1.3 ADC/TDC 信号处理:从物理量到数字化¶

1. 目的¶

  1. 掌握模拟电信号(时间、幅度)如何进行数字化(保存为整数道值)。
  2. 理解基线偏移(Pedestal)、超界(Overflow)。
  3. 有效事件的选择(cut)

2. Digitization (数字化)¶

在模拟代码中,事件的变量(如 $q_L/q_R$, $t_L/t_R$)通常是无限精度的浮点数 (double)。但在真实实验中,探测器输出的连续模拟信号经过电子学模块(ADC / TDC / QDC)后,会被量化为离散的整数(Channel / 道值),这个过程就叫数字化。

A. ADC / QDC (模拟/电荷-数字转换器)¶

ADC / QDC 用于记录输入信号的大小(ADC 测电压幅度,QDC 测电荷积分)。

假设一个 12-bit 的 ADC,硬件输入量程为 0-4V。 它的转换公式可以直白地写为:

$$ \mathrm{Raw\_ADC} = \mathrm{Int}(\text{信号幅度} \times \mathrm{Gain} + \mathrm{Pedestal} + \text{噪声涨落}) $$

具体参数说明:¶

  • 信号幅度 (Input Signal): 实际进入 ADC 的模拟电压(例如 2.5V)。
  • Gain (增益/转换系数): 把电压映射到道值的比例。
    • 例如量程 0-4V 对应 0-4095 ch,那么 Gain 大约是 $4095 / 4\mathrm{mV} \approx 1.024 \text{ ch/mV}$。输入 2.5V 就会被放大/转换到 2560 ch。
  • Pedestal (基线/直流偏置):
    • 因为真实的零信号总带有电子学噪声,噪声有正有负。如果基线设在 0 ch,负向噪声就会被 ADC 丢弃(无法记录负数)。
    • 在硬件上给输入端叠加一个固定的直流电压,将“没有信号时的零点”推高(比如推到 140 ch)。这样噪声再怎么负向波动,也不会低于 0 ch。
    • Pedestal 并不是一个固定的数值,而是一个分布。即使没有物理信号输入(Signal=0),ADC 读数也会在某个基准值附近波动。这种波动主要来源于:探测器噪声以及电子学噪声。这使得 Pedestal 呈现为一个高斯分布,其宽度由标准差 $\sigma$ 描述。如果只扣除均值(Mean),那么噪声的正向涨落就会被误认为是微弱的物理信号。

1

  • Range (量程):
    • 12-bit: 0 ~ 4095 ch
    • 14-bit: 0 ~ 16383 ch
  • Overflow (上溢): 如果输入信号太大(比如 5V),算出来的道值超过了 4095,ADC 只能强制记录为最大值 4095。

B. TDC (时间-数字转换器)¶

TDC 用于记录 Start 和 Stop 两个信号之间的时间差。

假设这个 TDC 的时间测量量程是 0-100ns,精度是 12-bit (0-4095 ch)。 它的转换公式为:

$$ \mathrm{Raw\_TDC} = \mathrm{Int}\left( (T_{\mathrm{stop}} - T_{\mathrm{start}} + \mathrm{Delay}) \times \mathrm{转换系数} \right) $$

具体参数说明:¶

  • 转换系数: 把时间差换算成道值的系数。
    • 在这个例子中,100ns 对应 4096 个道址,转换系数就是 $4096 / 100\mathrm{ns} \approx 40.96 \text{ ch/ns}$。
  • Delay:
    • TDC 只能测正的时间差(0-100ns)。但在实际连线中,因为电缆长度或触发逻辑,Stop 信号有可能比 Start 信号先到(时间差变成负的,比如 -10ns),TDC 就无法记录。
    • 在硬件或逻辑上给信号强行加上一段固定的 Delay(比如 +30ns),把原本 -10ns 的时间差整体平移到 +20ns,让它稳稳地落在 0-100ns 的合法量程内。
  • Range (量程):
    • 12-bit: 0 ~ 4095 ch
    • 14-bit: 0 ~ 16383 ch
  • Overflow (上溢): 如果两个信号的时间差超过了 TDC 的最大量程(比如相差 150ns),超出部分无法记录,强制记录为满刻度 4095。

3. 物理过程¶

  • 束流轰击靶以产生带电粒子、n、$\gamma$等粒子,重带电粒子碎片被靶后 Dipole magnet偏走,而部分轻带电粒子(LP: light particles,主要为质子)没有被完全偏走,仍然进入中子探测器。

真实数据获取 (DAQ) 中,触发逻辑决定了我们记录什么事件:

  • 物理触发 (Trig_Phys):中子,Gamma或LP 击中探测器。(pid=0, 1,2)
  • 束流/时钟触发 (Trig_Clock):强制触发,用于监测电子学基线状态。在此类事件中,探测器没有物理信号,只有电子学噪声。(pid=3)

4. 代码:基于 1.1 代码进行修改¶

定义数字化参数与分支¶

// --- 新增变量 ---
Int_t iAL, iAR;  // QDC道值 (0-4095)
Int_t itL, itR;  // TDC道值 (0-4095)
Int_t pid;       // 0:G, 1:N, 2:LP, 3:Pedestal

// --- 数字化与电子学参数 ---
const Double_t ADC_Gain = 5.0;    // 增益
const Double_t TDC_Gain = 25.0;   // 转换系数 (如40ps/ch)
const Double_t Ped_L = 140.0, Ped_R = 130.0; // 基线
const Double_t Noise = 8.5;       // 电子学噪声
const Double_t Trig_Dly = 50.0;   // 延迟
const Int_t    Max_ADC = 4095;    // 12-bit
const Int_t    Threshold = 180;   // 触发阈值(道值)

// --- Branch 映射 (省略原有部分) ---
opt->Branch("pid", &pid, "pid/I");
opt->Branch("iAL", &iAL, "iAL/I"); // ... 其余同理

事件生成 ($E_n \to E_p \to E_{ee}$)¶

// 1. 抽样生成 pid
Double_t rnd = gr->Uniform();
if (rnd < 0.10)      pid = 3; // 空触发/时钟触发
else if (rnd < 0.20) pid = 2; // LP (质子)
else                 pid = (gr->Uniform() < 0.3) ? 0 : 1; 

// 2. 物理过程修改
... 
if (pid == 2) {
    Eee = gr->Gaus(50.0, 5.0);           // LP 假设能量全沉积
} 
if (pid == 3) {
    Eee = 0.0;                           // Pedestal 无能量
}

数字化 (Digitization) 与 触发逻辑 (Trigger)¶

...

// 1. ADC: 幅度 * 增益 + 基线 + 噪声
iAL = (Int_t)(AL* ADC_Gain + Ped_L + gr->Gaus(0, Noise));
iAR = (Int_t)(AR * ADC_Gain + Ped_R + gr->Gaus(0, Noise));

// 2. TDC: (时间 + 延迟) * 转换系数
if (pid == 3) {
    itL = Max_ADC; itR = Max_ADC; // 无物理信号,TDC默认溢出
} else {
    itL = (Int_t)((tL + Trig_Dly) * TDC_Gain );
    itR = (Int_t)((tR + Trig_Dly) * TDC_Gain );
}

// 3. 超界截断处理
if (iAL > Max_ADC) iAL = Max_ADC; if (iAL < 0) iAL = 0;
// ... iAR, itL, itR 同理 ...

// 4. DAQ 触发逻辑 (物理符合触发 OR 时钟触发)
bool Trig_Phys = (iAL > Threshold) && (iAR > Threshold);
bool Trig_Clock = (pid == 3);

if (Trig_Phys || Trig_Clock) {
    tree->Fill(); // 只有满足触发条件才存入 Tree
}

3. 数字化信号处理:筛选 (Cut) 与连续化 (Dithering)¶

从电子学插件(ADC/TDC)获取的原始数据是整数道值(Integers)。在将这些道值转换为物理量(如能量、时间)时,必须经过两个关键步骤:有效范围筛选与变量连续化。

3.1. 运算的前提:合理选择有效范围¶

在对原始变量进行任何数学运算(如求和、平均、开方)之前,必须确保参与运算的数据具有物理意义。

确定低能阈值¶

为了区分“纯噪声”和“真实微弱信号”,需要设定一个阈值(Threshold)。

  • 方法:对空触发(或无束流)数据绘制 ADC 谱,拟合 Pedestal 峰得到均值 $\mu_{ped}$ 和标准差 $\sigma_{ped}$。
  • 标准:通常选择 $\mu_{ped} + 3\sigma_{ped}$ 作为阈值。
    • 根据高斯分布性质,噪声涨落超过 $3\sigma$ 的概率仅为 0.13%。
    • 这意味着:凡是超过这个阈值的信号,有 99.87% 的把握不是噪声。

有效范围筛选 (Cut)¶

在进行任何物理计算(如 $A = k \cdot (ADC - Ped)$)之前,必须先剔除无效数据:

  1. 噪声区:$ADC < \mu_{ped} + 3\sigma_{ped}$
  2. 溢出区 (Overflow):$ADC \ge 4095$(12-bit 量程上限)

TDC (针对时间):通常关注溢出 (Overflow)。

  • 有效信号必须满足:itL > 0 且 itL < Max_TDC (通常为 4095)。
  • 说明:若任一端探测器未被击中,TDC 通常记录为 0 或 4095。

以计算平均时间 $T_{avg} = (itL + itR) / 2$ 为例:如果其中一端是无效值(如 4095),直接运算得到的结果将完全错误。

// 在 tree->Draw() 中应用合理范围条件
// 只有当左右两端都在有效量程内,计算平均值才有意义
TCut valid_tdc = "itL > 0 && itL < 4095 && itR > 0 && itR < 4095";
tree->Draw("(itL + itR)/2.0 >> h_avg", valid_tdc);

锯齿现象与连续化 (Dithering)¶

锯齿的成因

ADC/TDC 输出的是离散整数(1, 2, 3...)。当我们对这些整数进行非整数倍的缩放(例如 $Time = 0.5 \times Channel$)或数学运算(如取平均)时,数据点的间距会被拉伸或压缩。 如果直方图的 Bin 宽度与这种拉伸后的间距不匹配(Mismatched Binning),就会导致某些 Bin 收集的数据多,某些 Bin 收集的少,从而在平滑的物理谱上产生非物理的锯齿结构。

解决方案:加入随机抖动(Dithering)

原理:由于量子化误差,真实的物理值等概率分布在 $[N, N+1)$ 区间内。 操作:在每个整数道值上叠加一个 $[0, 1)$ 的随机数。

$$ Val_{cont} = Val_{int} + \text{Random}(0, 1) $$


实例演示:模拟锯齿与连续化¶

下列代码模拟产生一组均匀分布的整数数据,观察对其进行简单运算后的效果。

In [3]:
    // 1. 创建直方图
    // h_raw: 直接运算,观察锯齿
    // h_dither: 连续化后运算,观察平滑
    TH1D *h_raw    = new TH1D("h_raw",    "Raw Calculation;Val;Counts", 100, 40, 60);
    TH1D *h_dither = new TH1D("h_dither", "With Dithering;Val;Counts",  100, 40, 60);

    TRandom3 rnd(0);
    
    // 2. 模拟 100000 个事件
    for (int i = 0; i < 100000; i++) {
        // 模拟两个独立的测量值 (假设物理值是50附近的高斯分布,但被数字化成了整数)
        Int_t iL = (Int_t)rnd.Gaus(50, 5); 
        Int_t iR = (Int_t)rnd.Gaus(50, 5);
        
        // --- 场景:计算两个变量的平均值 ---
        
        // A. 错误做法:直接使用整数计算
        // 结果只能是 x.0 或 x.5,在直方图 Bin 宽不为 0.5 的倍数时会出现锯齿
        Double_t avg_raw = (iL + iR) / 2.0; 
        
        // B. 正确做法:先 Dithering 再计算
        // 给每个整数加上 [0,1) 的随机量,还原连续性
        Double_t iL_cont = iL + rnd.Uniform(0, 1);
        Double_t iR_cont = iR + rnd.Uniform(0, 1);
        Double_t avg_dither = (iL_cont + iR_cont) / 2.0;
        
        h_raw->Fill(avg_raw);
        h_dither->Fill(avg_dither);
    }

    // 3. 绘图对比
    TCanvas *c1 = new TCanvas("c1", "Dithering Demo", 800, 400);
    c1->Divide(2, 1);
    
    c1->cd(1); 
    h_raw->SetLineColor(kRed); 
    h_raw->Draw(); // 你会看到明显的梳齿状结构
    
    c1->cd(2); 
    h_dither->SetLineColor(kBlue); 
    h_dither->Draw(); // 平滑的高斯分布,反映真实物理
    c1->Draw();

结果分析¶

  • 左图 (Raw):由于 (int + int)/2 的结果只能是整数或半整数(如 50.0, 50.5, 51.0...),数据点在数轴上是离散跳跃的。当直方图的 Bin 划分(这里是 100 bins / 20 range = 0.2 width)与这些离散点不对齐时,就会出现剧烈的高低交替(锯齿)。
  • 右图 (Dither):加入随机数后,数据填补了整数间的空隙,恢复了物理量的连续性,直方图呈现出平滑高斯形态。

总结¶

对原始变量进行运算时:

  1. 筛选合理范围:排除噪声以及超界信号, 选择物理上合理的信号区间。
  2. 连续化:凡是对原始道值做非整数运算(除法、刻度、坐标变换),必须先连续化(叠加 $[0, 1)$ 随机数)。