4. 原始时间戳数据预处理

在光子二阶关联测量中,时间符合计数设备(如时间数字转换器 TDC 或时间标记记录仪)输出的原始数据,通常是一串按到达顺序排列的时间戳记录。每条记录包含通道号与到达时刻,例如 ch1, 123456789.0 ps。这些原始记录并不能直接用于计算 g²(τ),因为其中混杂着通道间的时间基准偏移、探测器死时间造成的丢失、以及噪声或串扰产生的无效事件。本节的任务,就是把这批"生数据"清洗成"可用于关联运算的干净事件流",并用事件计数的一致性来验证清洗过程没有引入系统性错误。

原始数据的典型形态与读取

常见的原始文件有两种组织方式:一种是每行一条事件(通道 + 时间戳),另一种是硬件导出的二进制流,需要按固定字节长度解析。以文本格式为例,一个简化的读取脚本需要完成三件事:跳过文件头注释、按分隔符拆分字段、把时间戳统一转换为同一时间单位(建议统一为皮秒或纳秒,全文保持一致)。下面是一段可直接参考的 Python 读取与规范化示例:

import numpy as np

def load_timestamps(path, unit_scale=1.0):
    ch, ts = [], []
    with open(path, "r") as f:
        for line in f:
            line = line.strip()
            if not line or line.startswith("#"):
                continue
            c, t = line.split(",")
            ch.append(int(c))
            ts.append(float(t) * unit_scale)   # 统一到 ps
    return np.array(ch, dtype=np.int32), np.array(ts, dtype=np.float64)

读取完成后,务必先做一次基本检查:时间戳是否单调不减、通道号是否落在预期集合内(例如只有 1 和 2 两个通道)、是否存在明显超出量程的异常值。这一步能及早暴露文件截断或格式错位的问题。

通道对齐:消除固定时延偏移

两个探测通道的信号经过不同长度的光纤、电缆和电子学链路,到达 TDC 时会存在一个固定的相对时延 Δt₀。若不对齐,互相关峰会被平移到非零延迟处,直接导致 g²(τ) 峰值位置判读错误。对齐的常用做法是:先计算两通道事件的互相关直方图,找到峰值所在的延迟 bin,再将该偏移量从其中一个通道的时间戳中扣除。需要强调的是,对齐只消除固定偏移,不改变事件之间的相对间隔结构,因此不会影响二阶关联的物理信息。

死时间校正与无效事件剔除

探测器与 TDC 都存在死时间:一次事件被记录后,在死时间窗口内到达的后续光子无法被记录。这会造成计数率偏高时的事件丢失,使测得的 g²(0) 偏低。工程上通常采用两种处理:一是对相邻事件间隔小于死时间 τ_d 的记录进行标记,保留首个事件、剔除紧随其后的"死时间内事件";二是在数据分析阶段用非瘫痪模型(non-paralyzable)做计数率修正。清洗脚本中应显式记录被剔除的事件数,便于后续评估丢失比例。

无效事件剔除则针对另一类问题:暗计数、串扰、以及时间戳重复或倒序的记录。判断条件可以写成:同一通道内时间戳严格递增;相邻事件间隔不小于一个最小物理间隔;通道号属于有效集合。下面给出一个整合了死时间过滤与无效事件剔除的清洗函数:

def clean_events(ch, ts, dead_time_ps=50.0, valid_ch=(1, 2)):
    order = np.argsort(ts, kind="stable")
    ch, ts = ch[order], ts[order]
    keep = np.ones(len(ts), dtype=bool)
    last_t = {c: -np.inf for c in valid_ch}
    for i in range(len(ts)):
        c, t = ch[i], ts[i]
        if c not in valid_ch:
            keep[i] = False
            continue
        if t - last_t[c] < dead_time_ps:   # 死时间窗口内
            keep[i] = False
            continue
        last_t[c] = t
    return ch[keep], ts[keep]

注意 dead_time_ps=50.0 只是示例参数,实际取值应来自探测器数据手册或标定结果,不能随意套用。

清洗前后事件计数的一致性验证

清洗是否"只删该删的",需要用计数账本核对。核心恒等式是:原始事件数 = 保留事件数 + 无效事件数 + 死时间剔除数。若三者之和与原始总数不符,说明脚本存在漏判或重复计数。此外还应检查:保留事件的时间戳仍严格递增、两通道保留比例大致相当(若差异过大,往往意味着某通道存在系统性噪声)、以及清洗前后互相关峰位置未发生非预期移动。

原始时间戳数据预处理流程与计数账本 原始记录 通道 + 时间戳 读取与规范化 统一时间单位 通道对齐 扣除固定时延 Δt₀ 死时间与无效剔除 τ_d 窗口过滤 计数一致性账本 N_原始 = N_保留 + N_无效 + N_死时间剔除 示例:100000 = 98240 + 620 + 1140(合理假设数据) 干净事件流 用于 g²(τ) 计算 校验通过? 递增性 / 比例 / 峰位

上图把预处理链路与计数账本放在同一视图中:左侧是数据形态的演进,右侧是必须闭合的计数恒等式。实际脚本运行时,建议把每个阶段的计数打印成日志,例如 raw=100000, kept=98240, invalid=620, deadtime=1140,并断言 kept + invalid + deadtime == raw。一旦断言失败,就应回到剔除逻辑逐条排查,而不是继续往下做关联计算。

建议把清洗参数(死时间、有效通道、时间单位换算系数)与清洗日志一起保存为元数据文件,与清洗后的事件流同目录存放。这样后续复算 g²(τ) 时,任何一次结果差异都能追溯到具体的预处理参数,而不是靠记忆复现。

完成上述步骤后,得到的干净事件流才具备进入下一步关联运算的资格。判断清洗是否成功的最终标准不是"删了多少",而是"留下的数据在物理上自洽":时间戳单调、通道比例合理、互相关峰位于对齐后的零延迟附近、计数账本严格闭合。这四条同时满足,才可以认为预处理阶段没有引入新的系统偏差。