2.2 PPAC 信号处理-II¶
1. Tracking¶
利用多个 PPAC 的位置 (x,y,z) 信息进行 tracking 的原理如下图所示。由于 PPAC 的探测效率通常小于 100%,因此对于每个入射粒子,往往只有部分 PPAC 能够在 x 或 y 方向给出有效的位置信息。
假设对于某一入射粒子,有两个或两个以上探测器给出了有效的测量位置信息(如图中的红点所示,例如 1Ax, 2Ax 等),入射粒子在 x-z 或 y-z 平面上的飞行径迹即可由这些有效点进行线性拟合得到。
得到径迹的线性方程后,束流线上其他任意位置 (z) 处的 (x,y) 坐标,均可利用上述方程通过内插或外推计算得出。图中黑点即代表由线性方程计算/拟合得到的位置(它代表了我们所能推测出的粒子实际飞行路径)。
![]()
本实验中采用的重建策略¶
在实际实验中,若强制要求单层探测器必须同时给出 $(x,y)$ 二维有效信号才参与拟合,会导致严重的整体探测效率损失。因此实际上$x$ 方向与 $y$ 方向的径迹重建是完全独立进行的。即:只要某层探测器测得了有效的 $x$ 坐标,即便其 $y$ 信号缺失,该点仍独立参与 $x-z$ 平面的径迹拟合。
2. 径迹有效条件 对于 $x$ 或 $y$ 径迹,必须满足以下逻辑条件之一才被视为有效重建:
情况一: 最靠近下游的 F8PPAC3 具有有效信号
- 同时要求上游的 F8PPAC1 和 F8PPAC2 中,至少有 1 层 PPAC 提供有效信号。
情况二: 最靠近下游的 F8PPAC3 无有效信号
- 则完全依赖上游探测器,需满足以下 a) 或 b):
- a) F8PPAC1 和 F8PPAC2 中,合计有 3 层或 3 层以上的 PPAC 提供有效信号。
- b) 若合计仅有 2 层 PPAC 提供有效信号,则要求这两层必须分别来自 F8PPAC1 和 F8PPAC2。 (若仅有的2层信号来自同一位置(如都在 F8PPAC1 内),因两点间距过近,向靶点外推时会产生巨大的角度误差)
- 则完全依赖上游探测器,需满足以下 a) 或 b):
束流径迹重建结果(所有PPAC的信息都有x/y位置信息)¶

2. ROOT 文件中 TTree 的 Branch 说明¶
本实验使用的ROOT文件中,已完成位置刻度的 PPAC 数据存储在二维数组 PPACF8[i][j] 中。
- $z$ 坐标:代表各探测器平面在束流线上的绝对 $z$ 方向位置,由实验室几何测量事先给定。
- $x/y/z$坐标:单位mm。
- 当出现位置计算超界、信号堆积 (Pile-up) 或缺失时,数据统一用
-999或-1000填充。
数据映射关系表(从原始数据到物理分析变量):
| 探测器层级 | 原始 Branch | 物理意义 (已刻度) | 讲义代码对应变量 |
|---|---|---|---|
| PPAC 1 Layer A | PPACF8[0][0]PPACF8[0][1]PPACF8[0][2]PPACF8[0][3] |
$X$ 坐标 (mm) $Y$ 坐标 (mm) $X$ 平面对应的 $Z$ 坐标 $Y$ 平面对应的 $Z$ 坐标 |
xx[0]yy[0]xz[0]yz[0] |
| PPAC 1 Layer B | PPACF8[1][0~4] |
(同上结构,含 Anode 时间) | (本示例暂未使用) |
| PPAC 2 Layer A | PPACF8[2][0~4] |
(同上结构) | xx[1], yy[1]xz[1], yz[1] |
| PPAC 2 Layer B (作为待测层 DUT) |
PPACF8[3][0~4] |
(同上结构) | xx2b[0], yy2b[0]xz2b, yz2banode2b |
| PPAC 3 | PPACF8[4][0~4] |
(同上结构) | xx[2], yy[2]xz[2], yz[2] |
3. 径迹重建 (Tracking) 事例代码¶
下面示例代码 假设 1A, 2A, 3 这三个探测器均给出了有效位置信息,利用这三点进行直线拟合,并将径迹外推,用来评估 2B 探测器的各项探测效率及系统分辨率。
算法步骤如下:
- 1. 空间独立直线拟合:
- $x-z$ 平面拟合直线方程 $x = f_x(z)$,使用已知数据点:
(xx[0],xz[0]), (xx[1],xz[1]), (xx[2],xz[2]) - $y-z$ 平面拟合直线方程 $y = f_y(z)$,使用已知数据点:
(yy[0],yz[0]), (yy[1],yz[1]), (yy[2],yz[2])
- $x-z$ 平面拟合直线方程 $x = f_x(z)$,使用已知数据点:
- 2. 残差 (Residual) 计算(用于评估位置分辨率):
- 测量值与拟合值的差:$dx[i] = xx[i] - f_x(xz[i])$ ; $dy[i] = yy[i] - f_y(yz[i])$ $(i=0,1,2)$
- 3. 待测层 F8PPAC2_B (2B) 的对比:
- 实验测量坐标:
(xx2b[0], xz2b)和(yy2b[0], yz2b) - 外推预期坐标: 利用拟合直线算得
(xx2b[1], xz2b)和(yy2b[1], yz2b) - 阳极触发信号:
anode2b(用于求阳极本征效率)
- 实验测量坐标:
- 4. 物理靶位坐标外推:
- 利用拟合直线外推至靶点平面(假设靶位于 $z=0$),求得靶上坐标
(tx, ty)。
- 利用拟合直线外推至靶点平面(假设靶位于 $z=0$),求得靶上坐标
靶点坐标 $(t_x, t_y)$ 与出射角 $\theta$ 的误差评估¶
1. 物理动机:为什么要逐事件评估追踪误差?¶
在真实的物理实验中,分析中会采用不同的径迹重建(Tracking)策略。例如:
- 策略 A: 3 层探测器完美击中 $\to$ 杠杆臂长,拟合精度极高。
- 策略 B: 仅有 2 层探测器击中 $\to$ 勉强定迹,拟合误差巨大。
当我们为每一个事件计算出专属的物理误差($\sigma_{t_x}, \sigma_\theta$)并存入 TTree 后,在后续的物理分析中,可以通过以下 三种具体的编程手段 来统一处理这些质量参差不齐的数据:
用法一:Quality Cut¶
有了误差后,不同 tracking 策略的好坏被统一量化。在 ROOT 中画图或提取数据时,通过TCut选择不同误差的事件:
// 只要外推到靶上的误差小于 1.5 mm 的事件
TCut good_track_cut = "sigma_tx < 1.5 && sigma_theta < 0.05";
tree->Draw("tx >> h1", good_track_cut);
用法二:Inverse-Variance Weighting¶
如果物理目标是测量一个确定的中心值(例如:寻找束流打在靶上的绝对中心位置,或者拟合某个共振态的确定散射角),不能对所有事件取简单的算术平均。 应该使用逆方差(误差的平方倒数)作为每个事件的权重 $w_i$: $$ w_i = \frac{1}{\sigma_i^2} $$ 数学原理实现:
double sum_weight = 0;
double sum_value = 0;
for (int i=0; i<nentries; i++) {
tree->GetEntry(i);
if (sigma_tx <= 0) continue; // 排除无效点
double weight = 1.0 / (sigma_tx * sigma_tx); // 误差越小,权重呈指数级暴增
sum_value += tx * weight;
sum_weight += weight;
}
double final_tx_center = sum_value / sum_weight;
2. 协方差矩阵 (Covariance Matrix)¶
假设在 $X-Z$ 平面内用线性方程 $x(z) = p_0 + p_1 \cdot z$ 拟合粒子径迹。 最小二乘法在给出截距 $p_0$ 和斜率 $p_1$ 的同时,必然会给出一个 $2 \times 2$ 的协方差矩阵 $C$:
$$ C = \begin{pmatrix} \sigma_{p_0}^2 & Cov(p_0, p_1) \\ Cov(p_1, p_0) & \sigma_{p_1}^2 \end{pmatrix} $$
- 对角线元素: 分别是截距和斜率自身误差的平方(方差)。
- 非对角线元素 $Cov$: 极其重要!它代表了截距和斜率的相关性。在径迹拟合中,如果你稍微改变直线的倾角(斜率变大),直线在 $Z=0$ 处的截距必然会随之反向移动。因此 $p_0$ 和 $p_1$ 通常是强负相关的。忽略这个负的协方差,会导致最终外推误差被严重高估!
3. 原理推导:外推靶点 $(t_x)$ 与出射角 $(\theta)$ 的误差传递¶
假设物理靶位于 $z = z_{target}$ 处。
A. 靶上位置 $t_x$ 的误差推导(线性传递)¶
根据直线方程,外推点的计算公式为:$t_x = p_0 + p_1 \cdot z_{target}$。 利用多元函数误差传递公式: $$ \sigma_{f(p_0, p_1)}^2 = \left( \frac{\partial f}{\partial p_0} \right)^2 \sigma_{p_0}^2 + \left( \frac{\partial f}{\partial p_1} \right)^2 \sigma_{p_1}^2 + 2 \left( \frac{\partial f}{\partial p_0} \right) \left( \frac{\partial f}{\partial p_1} \right) Cov(p_0, p_1) $$
代入偏导数($\frac{\partial t_x}{\partial p_0} = 1$, $\frac{\partial t_x}{\partial p_1} = z_{target}$),得到靶点位置的真实方差: $$ \mathbf{\sigma_{t_x}^2 = \sigma_{p_0}^2 + (z_{target})^2 \cdot \sigma_{p_1}^2 + 2 \cdot z_{target} \cdot Cov(p_0, p_1)} $$ (注:Y 方向的 $t_y$ 误差推导与 X 方向完全相同,只需将 X 平面的拟合参数代入即可。)
B. 物理出射角 $\theta$ 的误差推导(非线性传递)¶
拟合出的斜率 $p_1$ 等于角度的正切值,真正的物理角度为:$\theta = \arctan(p_1)$。 利用一元非线性误差传递公式: $$ \sigma_\theta^2 = \left( \frac{d\theta}{dp_1} \right)^2 \sigma_{p_1}^2 $$ 根据微积分导数公式 $\frac{d}{dx}\arctan(x) = \frac{1}{1+x^2}$,得到角度的真实绝对误差: $$ \mathbf{\sigma_\theta = \frac{\sigma_{p_1}}{1 + p_1^2}} $$
4. 位置分辨率¶
在实验中,测定探测器的本征位置分辨率是评估径迹重建质量和动量/角度分辨率的前提。通常有两种测定方法:
2.1 准直束刻度方法(离线测试 / 放射源)¶

该方法通常在离线实验室中,利用低能放射源和准直狭缝(Collimator)进行。
- 理想高斯展宽模型: 通过准直孔将粒子准直后打入探测器。此时测得的表观位置分辨率 $\sigma$ 是探测器本征分辨率 $\sigma_0$ 与准直孔几何展宽 $\sigma_{geo}$ 的卷积(近似为高斯叠加): $$ \sigma^2 = \sigma_0^2 + \sigma_{geo}^2 $$ 其中,$\sigma_{geo}$ 由准直孔的物理孔径引入(见图 a)。通过反推即可得到 $\sigma_0$。
- 局限性一:源与真实束流的电离差异 气体探测器的本征分辨率 $\sigma_0$ 强烈依赖于入射粒子的比电离能损 ($dE/dx$)、原初电离统计涨落以及产生 $\delta$ 电子的射程。因此,用低能 $\alpha$ 放射源测出的 $\sigma_0$,只能证明探测器硬件完好,不能直接等同于高能重离子束流条件下的真实分辨率。
- 局限性二:高能束流的“边缘散射(Slit Scattering)” 如果在真实束流线上强行使用准直孔(图 b),高能粒子在穿过准直孔边缘时会发生严重的多重库仑散射(MCS)。这不仅会使得 $\sigma_{geo}$ 的几何关联失效,更会在位置谱上产生巨大的非高斯拖尾(Tail / Halo),彻底淹没探测器真实的 $\sigma_0$。
2.2 多探测器径迹残差法¶
鉴于准直方法的局限性,在真实的高能物理实验中,可靠的方法是利用多层探测器系统,在真实束流和真实数据获取条件下,通过径迹残差(Residuals)来逆推分辨率。
残差(Residual)的定义: 选择被全部 PPAC(如 5 层)同时探测到的“好事件”进行空间直线拟合。定义第 $i$ 层探测器的测量坐标 $x^i$ 与拟合径迹在该层的预期坐标 $x_{track}^i$ 之差为残差 $\Delta x^i$: $$ \Delta x^i = x^i - x_{track}^i $$
在 $z_i$ 位置观察到的残差 $\Delta x^i$,实际上是由两个独立成分叠加而成的:
- 探测器本身的测量涨落 $\sigma_0$,即位置分辨。
- 拟合直线的误差 $\sigma_{track}$:这正是通过上一节协方差矩阵在 $z_i$ 处算出的不确定度。
提取 $\sigma_0$,实验上常用“排除拟合法”:即在拟合直线时,不使用第 $i$ 层的数据,而只用其他层连成直线。
此时,由于第 $i$ 层的测量值与外推直线完全独立,残差的方差是两者方差的直接相加: $$\sigma_{residual}^2 = \sigma_0^2 + \sigma_{track}^2(z_i)$$
5. PPAC 探测效率¶

理想情况下,若有 $N$ 个粒子真实穿过了探测器的灵敏区域(Active Area),而探测器实际成功记录并解析出位置信息的事件数为 $N_{det}$,则该探测器的绝对探测效率定义为: $$\epsilon = \frac{N_{det}}{N}$$
在实际束流实验中,由于我们无法预知真实的 $N$,通常采用以下两种典型的数据分析方法来评估效率:
方法一:位置读出效率(基于内部信号符合,对应图 a)
- 物理意义: 评估当气体发生有效雪崩后,阴极成功读取出位置坐标的概率。
- 计算方法: 将 PPAC 的阳极 (Anode) 触发信号计数作为分母(代表测到粒子确实穿过探测器),将阴极 (Cathode) 具有位置信息的计数作为分子。
方法二:基于径迹外推的绝对探测效率(参考探测器法,对应图 b)
- 物理意义: 利用其他探测器作为基准,评估待测探测器的实际探测能力。
- 计算方法:
- 选择任意两层(或多层)具有位置信号的 PPAC 作为参考探测器(图b中的 i, j),拟合出粒子径迹。
- 分母 ($N_{ij}$): 将上述径迹外推至待测探测器(图b中的 k)的位置,统计预期穿过其灵敏面积的所有事件总数。
- 分子 ($N_{kij}$): 在上述 $N_{ij}$ 个事件的前提下,去检查待测探测器 k 是否确实给出了位置信号,记录成功探测的事件数。
- 计算公式: $\epsilon = \frac{N_{kij}}{N_{ij}}$
- 拓展:阳极探测效率评估
- 利用类似的径迹外推做法,也可以求得每个探测器阳极(Anode)的本征探测效率。只需保持分母(预期事件总数 $N_{ij}$)不变,将分子替换为:在上述事件中,待测探测器 k 的阳极成功产生触发信号的事件数即可。
维度独立性: 由于 PPAC 内部 $x$ 和 $y$ 方向的阴极读出结构通常是独立的,利用上述“径迹外推法”,可以分别独立评估该探测器单一维度的 $x$ 效率、$y$ 效率,以及要求两者同时有效的二维 $(x,y)$ 联合探测效率。
6. 分析代码框架¶
利用 ROOT 的 MakeClass 功能,生成用于遍历 TTree 的 C++ 框架代码:
# 在终端中启动 ROOT 并加载数据文件
root -l f8ppac001.root
root [1] tree->MakeClass("tracking");
root [2] .q
提示:执行后会生成 tracking.h 和 tracking.C,按照下文修改这两个文件。
修改后运行分析的命令:
root -l
root [1] .L tracking.C
root [2] tracking t;
root [3] t.Loop();
root [4] .q
运行结束后,生成 tracking.root 。
tracking.h¶
修改说明: 在 MakeClass 自动生成的基础上,补充了用于径迹外推分析的用户自定义变量与成员函数声明。
#ifndef tracking_h
#define tracking_h
#include <TROOT.h>
#include <TChain.h>
#include <TFile.h>
class tracking {
public :
TTree *fChain; //!pointer to the analyzed TTree or TChain
Int_t fCurrent; //!current Tree number in a TChain
// ================= 原始数据 Branch 变量 =================
Float_t PPACF8[5][5];
Float_t F8PPACRawData[5][5];
Int_t beamTrig;
Int_t must2Trig;
Float_t targetX, targetY;
// ================= 用户自定义物理分析变量 =================
Double_t xx[3], xz[3], yy[3], yz[3]; // 参考层 1A, 2A, 3 的位置坐标
Double_t xx2b[2], yy2b[2], xz2b, yz2b; // 待测层 2B: [0]实际测量值, [1]拟合外推值
Double_t anode2b; // 待测层 2B 阳极信号
Double_t dx[3], dy[3]; // 拟合残差 (Residual)
// 运动学物理量与本征误差
Double_t tx, ty; // 靶上外推坐标 (Target pos)
Double_t theta_x, theta_y; // 粒子出射角 (单位: rad)
Double_t sigma_tx, sigma_ty; // 靶上坐标的绝对物理误差
Double_t sigma_thetax, sigma_thetay; // 出射角的绝对物理误差
Double_t c2nx, c2ny; // 直线拟合质量评估 chi2/ndf
// 原始数据 Branch 指针
TBranch *b_PPACF8; //!
TBranch *b_F8PPACRawData; //!
TBranch *b_beamTrig; //!
TBranch *b_must2Trig; //!
TBranch *b_targetX; //!
TBranch *b_targetY; //!
// ================= 标准系统函数 =================
tracking(TTree *tree=0);
virtual ~tracking();
virtual Int_t Cut(Long64_t entry);
virtual Int_t GetEntry(Long64_t entry);
virtual Long64_t LoadTree(Long64_t entry);
virtual void Init(TTree *tree);
virtual void Loop();
virtual Bool_t Notify();
virtual void Show(Long64_t entry = -1);
// ================= 用户自定义成员函数 =================
virtual void SetBranch(TTree *tree);
virtual void TrackInit();
virtual void SetTrace(TH2D *h, Double_t k, Double_t b, Int_t min, Int_t max);
};
// ... (下方的 tracking_cxx 实现部分保持原样不变) ...
#endif
tracking.C¶
#define tracking_cxx
#include "tracking.h"
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <TF1.h>
#include <TGraphErrors.h> // 【修改】必须包含带有误差的图类
#include <TFitResult.h>
#include <TMatrixDSym.h> // 【新增】用于接收协方差矩阵
#include <iostream>
#include <cmath>
using namespace std;
void tracking::SetBranch(TTree *tree)
{
tree->Branch("xx", xx, "xx[3]/D");
tree->Branch("xz", xz, "xz[3]/D");
tree->Branch("yy", yy, "yy[3]/D");
tree->Branch("yz", yz, "yz[3]/D");
tree->Branch("dx", dx, "dx[3]/D");
tree->Branch("dy", dy, "dy[3]/D");
tree->Branch("xx2b", xx2b, "xx2b[2]/D");
tree->Branch("yy2b", yy2b, "yy2b[2]/D");
tree->Branch("anode2b", &anode2b, "anode2b/D");
// 【新增】注册所有运动学中心值及其物理误差
tree->Branch("tx", &tx, "tx/D");
tree->Branch("ty", &ty, "ty/D");
tree->Branch("theta_x", &theta_x, "theta_x/D");
tree->Branch("theta_y", &theta_y, "theta_y/D");
tree->Branch("sigma_tx", &sigma_tx, "sigma_tx/D");
tree->Branch("sigma_ty", &sigma_ty, "sigma_ty/D");
tree->Branch("sigma_thetax", &sigma_thetax, "sigma_thetax/D");
tree->Branch("sigma_thetay", &sigma_thetay, "sigma_thetay/D");
tree->Branch("c2nx", &c2nx, "c2nx/D");
tree->Branch("c2ny", &c2ny, "c2ny/D");
tree->Branch("beamTrig", &beamTrig, "beamTrig/I");
tree->Branch("must2Trig", &must2Trig, "must2Trig/I");
tree->Branch("targetX", &targetX, "targetX");
tree->Branch("targetY", &targetY, "targetY");
}
void tracking::TrackInit()
{
// 初始化所有计算变量为无效值,防止上一个事件的数据污染
tx = -999; ty = -999;
theta_x = -999; theta_y = -999;
sigma_tx = -1; sigma_ty = -1; // 误差初始化为负数代表无效
sigma_thetax = -1; sigma_thetay = -1;
xx[0] = PPACF8[0][0]; yy[0] = PPACF8[0][1]; xz[0] = PPACF8[0][2]; yz[0] = PPACF8[0][3];
xx[1] = PPACF8[2][0]; yy[1] = PPACF8[2][1]; xz[1] = PPACF8[2][2]; yz[1] = PPACF8[2][3];
xx[2] = PPACF8[4][0]; yy[2] = PPACF8[4][1]; xz[2] = PPACF8[4][2]; yz[2] = PPACF8[4][3];
xx2b[0] = PPACF8[3][0]; yy2b[0] = PPACF8[3][1];
xz2b = PPACF8[3][2]; yz2b = PPACF8[3][3];
anode2b = PPACF8[3][4];
xx2b[1] = -1000; yy2b[1] = -1000;
}
void tracking::SetTrace(TH2D *h, Double_t k, Double_t b, Int_t min, Int_t max){
if(h == 0 || min >= max) return;
for(int i = min; i < max; i++){
h->Fill(i, (Int_t)(i * k + b));
}
}
void tracking::Loop()
{
if (fChain == 0) return;
TFile *opf = new TFile("tracking.root", "RECREATE");
TTree *tree = new TTree("tree", "PPAC Tracking Data");
SetBranch(tree);
TH2D *htf8xz = new TH2D("htf8xz", "X-Z Plane Trace; Z (mm); X (mm)", 2200, -2000, 200, 300, -150, 150);
TH2D *htf8yz = new TH2D("htf8yz", "Y-Z Plane Trace; Z (mm); Y (mm)", 2200, -2000, 200, 300, -150, 150);
// 【核心修改】使用 TGraphErrors 替代 TGraph,赋予探测器真实的本征分辨率
TGraphErrors *grx = new TGraphErrors(3);
TGraphErrors *gry = new TGraphErrors(3);
TF1 *fx = new TF1("fx", "pol1", -2000, 0);
TF1 *fy = new TF1("fy", "pol1", -2000, 0);
// 假设:所有PPAC每层的本征位置分辨率为 1.0 mm
const double det_resolution = 1.0;
const double z_target = 0.0; // 物理靶所在Z坐标位置
Long64_t nentries = fChain->GetEntriesFast();
Long64_t nbytes = 0, nb = 0;
for (Long64_t jentry = 0; jentry < nentries; jentry++) {
Long64_t ientry = LoadTree(jentry);
if (ientry < 0) break;
nb = fChain->GetEntry(jentry); nbytes += nb;
TrackInit();
bool b1a = abs(xx[0]) < 150 && abs(yy[0]) < 150;
bool b2a = abs(xx[1]) < 150 && abs(yy[1]) < 150;
bool b3 = abs(xx[2]) < 100 && abs(yy[2]) < 100;
if(!b1a || !b2a || !b3) continue;
// ================= X-Z 平面径迹拟合与误差计算 =================
for(int i=0; i<3; i++) {
grx->SetPoint(i, xz[i], xx[i]);
grx->SetPointError(i, 0.0, det_resolution); // 关键:输入Z和X的误差
}
// 【核心修改】去除 "W" 选项。S=保存结果(以获取矩阵), Q=静默模式
TFitResultPtr rx = grx->Fit(fx, "SQ");
if (rx->IsValid()) {
double p0_x = fx->GetParameter(0);
double p1_x = fx->GetParameter(1);
// 提取中心值
xx2b[1] = fx->Eval(xz2b);
tx = p0_x + p1_x * z_target;
theta_x = atan(p1_x); // 物理出射角 (rad)
// 提取协方差矩阵并计算严谨物理误差
TMatrixDSym cov_x = rx->GetCovarianceMatrix();
double var_p0 = cov_x(0, 0);
double var_p1 = cov_x(1, 1);
double cov_p0_p1 = cov_x(0, 1);
// 外推位置误差传递公式
double err2_tx = var_p0 + (z_target * z_target * var_p1) + (2.0 * z_target * cov_p0_p1);
sigma_tx = sqrt(err2_tx);
// 角度非线性误差传递公式
sigma_thetax = sqrt(var_p1) / (1.0 + p1_x * p1_x);
c2nx = rx->Chi2() / rx->Ndf();
SetTrace(htf8xz, p1_x, p0_x, -1800, 0);
for(int i=0; i<3; i++) dx[i] = xx[i] - fx->Eval(xz[i]);
}
// ================= Y-Z 平面径迹拟合与误差计算 =================
for(int i=0; i<3; i++) {
gry->SetPoint(i, yz[i], yy[i]);
gry->SetPointError(i, 0.0, det_resolution);
}
TFitResultPtr ry = gry->Fit(fy, "SQ");
if (ry->IsValid()) {
double p0_y = fy->GetParameter(0);
double p1_y = fy->GetParameter(1);
yy2b[1] = fy->Eval(yz2b);
ty = p0_y + p1_y * z_target;
theta_y = atan(p1_y);
TMatrixDSym cov_y = ry->GetCovarianceMatrix();
double var_p0 = cov_y(0, 0);
double var_p1 = cov_y(1, 1);
double cov_p0_p1 = cov_y(0, 1);
double err2_ty = var_p0 + (z_target * z_target * var_p1) + (2.0 * z_target * cov_p0_p1);
sigma_ty = sqrt(err2_ty);
sigma_thetay = sqrt(var_p1) / (1.0 + p1_y * p1_y);
c2ny = ry->Chi2() / ry->Ndf();
SetTrace(htf8yz, p1_y, p0_y, -1800, 0);
for(int i=0; i<3; i++) dy[i] = yy[i] - fy->Eval(yz[i]);
}
// 将本事件结果写入 Tree (包括新算出的误差)
tree->Fill();
if(jentry % 10000 == 0) cout << "Processing Event: " << jentry << " / " << nentries << endl;
}
// 释放内存并保存结果
delete grx; delete gry;
delete fx; delete fy;
htf8xz->Write();
htf8yz->Write();
tree->Write();
opf->Close();
cout << "Tracking finished. Output saved to tracking.root" << endl;
}
//%jsroot on
TFile *ipf = new TFile("tracking.root");
TTree *tree = (TTree*) ipf->Get("tree");
TCanvas *c1 = new TCanvas("c1","c1");
束流径迹¶
TH2D *hxz = (TH2D*) ipf->Get("htf8xz");
hxz->Draw("colz");
c1->Draw();
TH2D *hyz = (TH2D*) ipf->Get("htf8yz");
hyz->Draw("colz");
c1->Draw();
束流在靶上投影¶
- 假设靶与束流线垂直。
tree->Draw("ty:tx>>htx(120,-60,60,120,-60,60)","must2Trig","colz");
c1->Draw();
tree->Draw("tx:ty>>htx(120,-60,60,120,-60,60)","beamTrig","colz");
c1->Draw();
$\chi^2/Ndf : tx$
残差,chi2/NDF¶
- 下图中呈现的残差分布并不是单一的gaus分布,有一个窄的gauss重叠在宽的gauss之上。这种现象在气体探测器中比较常见,其物理根源有:
- 多重库仑散射 (MCS): 高能束流穿过 PPAC 的镀铝Mylar或工作气体时,发生的卢瑟福散射天然具有非高斯的大角度拖尾。
- $\delta$ 电子 : 入射粒子打出的高能次级电子在气体中横向游走,使得雪崩电荷的重心偏离了粒子真实的穿透点。
- 电子学与束流本底: Pile-up 或电子学的噪声。
在实际的离线数据分析中,会使用 双高斯函数:窄核 + 宽尾对分布进行拟合。
- 宽尾(Tail): 吸收由上述多重散射和 $\delta$ 电子造成的物理本底。
- 窄核(Core): 剥离本底后,只有这个窄核的高斯宽度($\sigma_{core}$)才代表探测器真实的响应。
TF1 *total2 = new TF1("total2", "gaus(0)+gaus(3)");
TF1 *g1 = new TF1("g1", "gaus");
TF1 *g2 = new TF1("g2", "gaus");
TF1 *total = new TF1("total", "gaus(0) + gaus(3)");
TH1F *hdx;
Double_t sigma;
tree->Draw("dx[0]>>hdx(200,-5,5)");
hdx = (TH1F*)gROOT->FindObject("hdx");
hdx->Fit("g1","","",-0.5,0.5);
sigma = g1->GetParameter(2);
total->SetParameter(2,sigma);
total->SetParameter(5,7*sigma);//初始化,估计半宽为2*sigma;
hdx->Fit("total");
gPad->SetLogy(0);
c1->Draw();//residual
**************************************** Minimizer is Minuit2 / Migrad Chi2 = 1890.97 NDf = 17 Edm = 5.74935e-07 NCalls = 70 Constant = 16429.2 +/- 53.2958 Mean = -0.0644376 +/- 0.000586192 Sigma = 0.225004 +/- 0.000603074 (limited) **************************************** Minimizer is Minuit2 / Migrad Chi2 = 4054.38 NDf = 194 Edm = 8.03563e-06 NCalls = 327 p0 = 15539.3 +/- 54.0504 p1 = -0.0690443 +/- 0.000592113 p2 = 0.216952 +/- 0.000650672 p3 = 852.983 +/- 8.11293 p4 = -0.0868271 +/- 0.00572421 p5 = 1.36888 +/- 0.00718881
tree->Draw("c2ny:dy[0]>>hh(40,-10,10,200,0,1000)","","colz");
c1->SetLogy(0);
c1->Draw();//从chi2/ndf图上可看出,部分事件的径迹拟合误差很大,这部分要在后续数据处理中去掉。
tree->Draw("c2ny>>hh(200,0,1000)","","");
gPad->SetLogy();
c1->Draw();//从chi2/ndf图上可看出,部分事件的径迹拟合误差很大,这部分要在后续数据处理中去掉。
gPad->SetLogy(0);
tree->Draw("tx:ty>>(120,-60,60)","c2nx<10 && c2ny<10 && beamTrig ","colz");
c1->Draw();//
tree->Draw("tx:ty>>(120,-60,60,120,-60,60)","(c2nx>20 || c2ny>20) && beamTrig ","colz");
c1->Draw();//
PPAC2B x,y,x-y的探测效率¶
在 ROOT 中,利用 TCut(条件切割)和 TTree::GetEntries(selection) 来快速统计满足特定物理条件的事件数,从而计算效率。
0. 定义物理筛选条件 (TCut)¶
首先,将复杂的逻辑判断定义为直观的 TCut 变量:
// ================= 入射粒子 =================
// 1. 预期穿过:拟合径迹外推至 2B 平面,且落在 200x200 mm 的灵敏面积内
TCut c2btrack = "abs(xx2b[1])<100 && abs(yy2b[1])<100";
// 2. 2B 探测器的阳极 (Anode) 确实给出了有效的时间信号
TCut c2ba = "anode2b>-1000";
// ================= 探测数目 =================
// 测得有效位置:实际测量值落在正常范围内 (排除 -1000 等无效值)
TCut c2bx = "abs(xx2b[0])<100"; // X 有信号
TCut c2by = "abs(yy2b[0])<100"; // Y 信号
1. 计算穿过探测器灵敏面积的预期粒子数¶
利用刚才定义的 c2btrack,可以画出径迹在外推平面上的二维投影,并获取总入射事件数。
// 绘制外推位置的 2D 分布 (预期击中位置)
tree->Draw("yy2b[1]:xx2b[1]>>h_expected(200,-100,100,200,-100,100)", c2btrack, "colz");
c1->Draw();
// 统计预期穿过灵敏区域的总数
Long64_t N_track = tree->GetEntries(c2btrack);
cout << "预期穿过 PPAC2B 灵敏区的粒子总数 N_track = " << N_track << endl;
预期穿过 PPAC2B 灵敏区的粒子总数 N_track = 232296
2. 计算并对比两类探测效率¶
实际气态探测器的效率与入射粒子的种类 $(A, Z)$、能量以及击中位置均有关,示例代码求的是全局平均探测效率。
Long64_t Na;
Long64_t Nx, Ny, Nxy;
Double_t effa;
Double_t effx1, effy1, effxy1;
Double_t effx2, effy2, effxy2;
Long64_t Na, Nx, Ny, Nxy;
// 统计各项实际响应的事件数
Na = tree->GetEntries(c2ba && c2btrack); // 阳极触发数
Nx = tree->GetEntries(c2bx && c2btrack); // 仅要求 X
Ny = tree->GetEntries(c2by && c2btrack); // 仅要求 Y
Nxy = tree->GetEntries(c2bx && c2by && c2btrack); // 要求 X 和 Y
// ==========================================================
// 方法一:径迹外推的“绝对探测效率”
// ==========================================================
Double_t eff_a = Double_t(Na) / N_track; // 阳极本征效率
Double_t eff_x1 = Double_t(Nx) / N_track; // X 绝对效率
Double_t eff_y1 = Double_t(Ny) / N_track; // Y 绝对效率
Double_t eff_xy1 = Double_t(Nxy) / N_track; // (X,Y) 二维绝对效率
// ==========================================================
// 方法二:以探测器阳极信号为基准
// ==========================================================
Double_t eff_x2 = Double_t(Nx) / Na;
Double_t eff_y2 = Double_t(Ny) / Na;
Double_t eff_xy2 = Double_t(Nxy) / Na;
// 格式化输出结果
printf("\n--- PPAC2B 绝对探测效率 (基于 Tracking) ---\n");
printf("阳极触发效率 eff_a = %5.2f%%\n", eff_a * 100);
printf(" X 绝对效率 eff_x1 = %5.2f%%\n", eff_x1 * 100);
printf(" Y 绝对效率 eff_y1 = %5.2f%%\n", eff_y1 * 100);
printf(" X-Y 联合效率 eff_xy1 = %5.2f%%\n", eff_xy1 * 100);
printf("\n--- PPAC2B 位置读出效率 (基于 Anode) ---\n");
printf(" X 读出效率 eff_x2 = %5.2f%%\n", eff_x2 * 100);
printf(" Y 读出效率 eff_y2 = %5.2f%%\n", eff_y2 * 100);
printf(" X-Y 联合效率 eff_xy2 = %5.2f%%\n", eff_xy2 * 100);
c1->Draw();
--- PPAC2B 绝对探测效率 (基于 Tracking) --- 阳极触发效率 eff_a = 99.23% X 绝对效率 eff_x1 = 93.11% Y 绝对效率 eff_y1 = 92.98% X-Y 联合效率 eff_xy1 = 86.87% --- PPAC2B 位置读出效率 (基于 Anode) --- X 读出效率 eff_x2 = 93.84% Y 读出效率 eff_y2 = 93.70% X-Y 联合效率 eff_xy2 = 87.54%
讨论:¶
在实际的离线数据分析中,评估 PPAC 的位置探测效率是否引入“阳极(Anode)信号有效”作为符合条件,主要基于对本底抑制机制与物理统计量的权衡:
1. 不要求阳极符合 此方式客观反映了探测器提供可用空间坐标的概率,避免在后续计算截面时对效率进行过度扣除(Double Counting)。其劣势在于,阴极延迟线易受环境电磁干扰,仅依赖位置解算容易将纯电子学噪声误判为有效坐标。不过,在实际的多探测器径迹重建(Tracking)中,通常可依靠多层探测器之间的空间共线关联(通过拟合的 $\chi^2$ 判据)来自然剔除此类噪声影响。
2. 要求阳极符合 引入阳极符合能有效压制延迟线上的虚假噪声;同时,阳极的快时间信号在识别和剔除高束流下的多重击中(Pile-up)事件时不可或缺。当实验束流强度较高、Pile-up 影响显著时,必须引入此符合条件,其代价是整体探测效率会有所降低。
作业¶
Task A: 物理靶点外推与重建信息记录¶
示例代码演示了固定的 3 层探测器(1A, 2A, 3)拟合。但在实际物理分析中,为了最大化统计量,我们需要利用 F8PPAC1a, 1b, 2a, 2b, 3 这 5 层 的所有有效位置信息,进行动态径迹重建。
修改示例代码:
1. 径迹拟合与状态记录¶
- 筛选有效点: 对每一个事件,逐一检查 5 层 PPAC 是否给出了有效的位置坐标(排除 -999 或越界噪声)。
- 状态记录: 引入变量
Ndet_x和Ndet_y记录实际参与 $X$ 和 $Y$ 平面拟合的探测器层数(需满足 $N \ge 2$ 才可拟合);引入数组DetHit[5]记录具体是哪几层参与了拟合(1代表参与,0代表未参与)。
2. 靶位坐标¶
实验中,物理靶并非垂直放置,而是朝向望远镜倾斜了 $45^\circ$(靶的平面方程x+z=0 )。
求解靶上坐标: 请将空间直线方程 $x = f_x(z)$ 和 $y = f_y(z)$ 与倾斜的靶平面方程联立,解出束流打在靶面上的真实三维交点坐标
targetX, targetY, targetZ。计算出靶上交点坐标的物理误差 ,以及束流出射角误差 。
将上述所有拟合卡方值(
chi2/ndf)、残差(Residual)、交点坐标及物理误差作为新 Branch 存入 TTree。
3. 数据分析¶
- 传输效率计算: 在
beamTrig(束流触发)条件下,统计“重建的束流打在给定物理靶尺寸范围内”的事件数比例(即靶的几何接受度/传输效率 $\varepsilon_{target}$)。 - 分别画出不同策略下的事件在靶位上的位置以及散射角分布,以及各项的误差分布。
Task B: PPAC 探测效率的多重验证¶
计算位于最上游的 PPAC1a 和最下游的 PPAC3 的 $x$ 效率、$y$ 效率以及 $(x,y)$ 二维联合效率。
要求进行交叉验证:
- 对比效率类型: 分别计算它们的绝对探测效率(方法一:Tracking 外推作为分母)和位置读出效率(方法二:自身阳极信号作为分母)。
- 在使用 Tracking 方法时,尝试改变“参考探测器”的组合(例如:测 PPAC3 时,分别尝试用
1a+2a拟合,或用1b+2b拟合),验证在不同基准下求出的效率值是否具有自洽性(结果应相近)。