眼图测量与算法深入分析

眼图测量与算法深入分析

眼图基础文章已经讲清楚了"切片 + 对齐 + 叠加"的主线,但真正开发眼图功能时,最容易卡住的不是绘图,而是三个前置问题:

(1) 怎么得到 UI:没有正确的码元周期,眼图折叠就会漂移。

(2) 怎么做 CDR:很多高速串行信号没有独立时钟,必须从数据边沿恢复时钟。

(3) 怎么检测边沿:实际波形有噪声、振铃、毛刺和过冲,不能只用一个阈值粗暴判断。

这篇文章重点分析这三个问题的技术原理和实现方法。

1. UI 来源

UIUnit Interval,表示一个码元周期。眼图横轴本质上是按 UI 折叠,所以 UI 一旦错了,后面的相位映射、眼宽测量、抖动统计都会错。

如果已知码元速率 RsR_sRs,则:

UI=1Rs UI = \frac{1}{R_s} UI=Rs1

对 NRZ 信号,通常一个码元承载 1 bit,所以:

Rs=Rb R_s = R_b Rs=Rb

对 PAM4 信号,一个码元承载 2 bit,所以:

Rs=Rb2 R_s = \frac{R_b}{2} Rs=2Rb

因此 10Gbps NRZ 的 UI 是:

UI=110 Gbps=100 ps UI = \frac{1}{10\,\mathrm{Gbps}} = 100\,\mathrm{ps} UI=10Gbps1=100ps

10Gbps PAM4 的码元速率是 5GBaud,UI 是:

UI=15 GBaud=200 ps UI = \frac{1}{5\,\mathrm{GBaud}} = 200\,\mathrm{ps} UI=5GBaud1=200ps

这也是为什么开发眼图功能时不能只问"比特率是多少",还要知道信号调制方式。眼图按码元折叠,不是按 bit 折叠。

2. 码率估计

实际示波器软件中,UI 可以来自三类输入:

(1) 用户手动输入码率。

(2) 协议解析模块给出码率。

(3) 软件从波形中估计码率。

手动输入最简单,但用户输错时眼图会马上失真。自动估计更复杂,常见方法有边沿间隔统计、自相关、频域估计和协议辅助。

边沿间隔

先检测所有有效边沿时间:

t0,t1,t2,⋯ ,tN−1 t_0,t_1,t_2,\cdots,t_{N-1} t0,t1,t2,⋯,tN−1

再计算相邻边沿间隔:

Δti=ti+1−ti \Delta t_i = t_{i+1} - t_i Δti=ti+1−ti

对于 NRZ 数据,连续相同 bit 不会产生边沿,所以边沿间隔可能是:

UI, 2UI, 3UI,⋯ UI,\ 2UI,\ 3UI,\cdots UI, 2UI, 3UI,⋯

也就是说,相邻边沿间隔不一定等于 UI,而是 UI 的整数倍。因此不能简单用所有 Δti\Delta t_iΔti 的平均值当作 UI。更合理的做法是找这些间隔的基本周期。

常用实现流程:

(1) 对 Δti\Delta t_iΔti 做直方图。

(2) 找到最小且稳定的主峰,作为 UI 的候选值。

(3) 检查其他峰是否接近 2UI,3UI,4UI2UI,3UI,4UI2UI,3UI,4UI。

(4) 如果多个峰满足整数倍关系,则确认 UI。

例如间隔峰值集中在 1ns2ns3ns,则 UI 大概率是 1ns。如果只看到 2ns4ns,可能是数据模式缺少频繁跳变,此时不能直接判断 UI 为 2ns,还需要结合频域或协议信息。

最大公约周期

边沿间隔存在抖动,不能直接做整数最大公约数,但可以做"近似最大公约周期"。假设候选 UI 为 TTT,每个边沿间隔 Δti\Delta t_iΔti 应该接近某个整数倍:

Δti≈kiT \Delta t_i \approx k_i T Δti≈kiT

可以定义误差:

E(T)=∑i(Δti−round⁡(ΔtiT)T)2 E(T) = \sum_i \left(\Delta t_i - \operatorname{round}\left(\frac{\Delta t_i}{T}\right)T\right)^2 E(T)=i∑(Δti−round(TΔti)T)2

让 E(T)E(T)E(T) 最小的 TTT,就是一个候选 UI。这个方法适合对已有边沿做离线估计,但要限制 TTT 的搜索范围,否则容易把 UI/2UI/2UI/2 或 2UI2UI2UI 误判为基准周期。

自相关

自相关用于从波形中寻找重复时间尺度。对采样波形 vnvnvn,自相关可以写成:

Rk=∑nvnvn+k Rk = \sum_n vnvn+k Rk=n∑vnvn+k

如果信号有明显码元周期或数据跳变规律,RkRkRk 会在某些延迟位置出现峰值。采样间隔为 TsT_sTs 时,延迟 kkk 对应时间:

T=kTs T = kT_s T=kTs

自相关的好处是不用先精确检测每个边沿;缺点是随机数据的周期性不强,长串相同比特、编码扰码、均衡和噪声都会影响峰值。

频域估计

也可以对波形或边沿序列做频谱分析。若在频谱中观察到与码元速率相关的能量峰,可以反推:

UI=1Rs UI = \frac{1}{R_s} UI=Rs1

但数字信号频谱受编码、数据随机性、通道带宽和预加重影响,不一定有很尖锐的基频峰。因此频域估计通常只作为辅助,不应作为唯一依据。

3. UI 边界

求出 UI 还不够,还要知道每个 UI 的边界在哪里。眼图折叠用的是:

ϕi=(ti−t0) mod UI \phi_i = (t_i - t_0) \bmod UI ϕi=(ti−t0)modUI

这里 t0t_0t0 就是相位参考。如果 UIUIUI 正确但 t0t_0t0 不稳定,眼图也会变宽。

最简单的固定码率方式是:

tboundary,n=t0+nUI t_{\text{boundary},n} = t_0 + nUI tboundary,n=t0+nUI

这种方法假设发送端时钟理想稳定。实际链路中,发送端可能有频率偏差、低频漂移、扩频时钟和抖动。固定 UI 折叠会把这些变化全部显示到眼图里,眼图可能越来越宽。

CDR 的作用就是动态调整 t0t_0t0 和 UI,使本地恢复时钟尽量跟随接收到的数据边沿。

4. CDR 本质

CDRClock Data Recovery,时钟数据恢复。它不是从数据里"找出一根真实时钟线",而是在软件中维护一个本地时钟模型,让这个本地时钟和数据边沿尽量对齐。

可以把 CDR 理解成一个反馈控制系统:

text 复制代码
边沿检测 -> 相位误差 -> 环路滤波 -> 本地时钟/NCO -> UI 边界

核心目标是让预测边沿和实际边沿的误差尽量小:

en=tedge,n−tpredict,n e_n = t_{\text{edge},n} - t_{\text{predict},n} en=tedge,n−tpredict,n

其中:

(1) tedge,nt_{\text{edge},n}tedge,n 是检测到的实际边沿时间。

(2) tpredict,nt_{\text{predict},n}tpredict,n 是本地时钟预测的边沿时间。

(3) ene_nen 是相位误差。

如果 en>0e_n > 0en>0,说明实际边沿比预测边沿晚,本地时钟可能偏快或相位超前;如果 en<0e_n < 0en<0,说明实际边沿比预测边沿早,本地时钟可能偏慢或相位滞后。

5. 软件 PLL

软件 CDR 最常见的实现是数字 PLL。它维护两个状态:

(1) 相位 ϕ\phiϕ:当前 UI 边界位置。

(2) 周期 TTT:当前估计的 UI。

每检测到一个边沿,就计算相位误差,然后修正相位和周期。

一个简化的二阶环路可以写成:

Tn+1=Tn+Kien T_{n+1} = T_n + K_i e_n Tn+1=Tn+Kien

ϕn+1=ϕn+Tn+1+Kpen \phi_{n+1} = \phi_n + T_{n+1} + K_p e_n ϕn+1=ϕn+Tn+1+Kpen

其中:

(1) KpK_pKp 控制相位修正速度。

(2) KiK_iKi 控制频率修正速度。

(3) KpK_pKp 越大,恢复时钟越快跟随边沿抖动。

(4) KiK_iKi 越大,恢复时钟越快跟踪频率偏差。

这两个参数决定 CDR 环路带宽。带宽高,CDR 会跟随更多低频和中频抖动,眼图看起来可能更开;带宽低,更多抖动会留在眼图里,眼图看起来更宽更差。专业一致性测试通常会规定 CDR 模型和带宽,就是为了保证不同仪器测得的眼图可比。

工程级 CDR

前面的二阶 PLL 公式适合理解原理,但工程实现通常会拆成四个模块:

text 复制代码
边沿检测 -> 相位检测器 -> 环路滤波器 -> NCO -> UI 边界

(1) 边沿检测器 :输出有效边沿时间 tedget_{\text{edge}}tedge。

(2) 相位检测器 :计算实际边沿和预测边沿之间的相位误差 ene_nen。

(3) 环路滤波器:决定哪些误差被 CDR 跟踪,哪些误差保留为抖动。

(4) NCO:根据当前频率控制字生成连续 UI 边界。

这里的 NCONumerically Controlled Oscillator,数控振荡器。软件里它不是硬件振荡器,而是一个相位累加器。每前进一个采样点,就让相位增加:

θi+1=θi+W \theta_{i+1} = \theta_i + W θi+1=θi+W

其中 WWW 是频率控制字。若用采样周期 TsT_sTs 和当前 UI 估计 TUIT_{UI}TUI 表示,则:

W=TsTUI W = \frac{T_s}{T_{UI}} W=TUITs

当 θ\thetaθ 从小于 1 增加到大于等于 1 时,就说明跨过了一个 UI 边界:

θ≥1⇒emit UI boundary \theta \ge 1 \Rightarrow \text{emit UI boundary} θ≥1⇒emit UI boundary

随后:

θ←θ−1 \theta \leftarrow \theta - 1 θ←θ−1

如果使用时间戳离线处理,也可以不用逐点 NCO,而是维护 next_boundary

c 复制代码
next_boundary += ui_period;

但本质相同:都在用一个本地时钟模型产生 UI 边界。

相位检测器

相位检测器要解决的问题是:一个实际边沿应该对应本地 NCO 的哪一个 UI 边界。

设实际边沿为 tedget_{\text{edge}}tedge,离它最近的预测边界为 tclkt_{\text{clk}}tclk,相位误差为:

e=tedge−tclk e = t_{\text{edge}} - t_{\text{clk}} e=tedge−tclk

为了避免误差跨 UI 跳变,通常把误差限制在:

−UI2<e≤UI2 -\frac{UI}{2} < e \le \frac{UI}{2} −2UI<e≤2UI

如果 ∣e∣>UI/2|e| > UI/2∣e∣>UI/2,说明本地时钟可能已经滑过一个 UI,需要做 cycle slip 处理,而不是直接把这个巨大误差送进环路滤波器。

工程中还会对误差做门限限制:

eclip=clip⁡(e,−emax⁡,emax⁡) e_{\text{clip}} = \operatorname{clip}(e,-e_{\max},e_{\max}) eclip=clip(e,−emax,emax)

这样可以避免毛刺边沿或误检测边沿把 CDR 拉飞。

环路滤波器

软件 CDR 常用 PI 环路滤波器,也就是比例项加积分项:

fn+1=fn+Kien f_{n+1} = f_n + K_i e_n fn+1=fn+Kien

Δϕn=Kpen+fn+1 \Delta\phi_n = K_p e_n + f_{n+1} Δϕn=Kpen+fn+1

其中:

(1) KpenK_p e_nKpen 是快速相位修正。

(2) fnf_nfn 是频率修正量,也就是积分器状态。

(3) KienK_i e_nKien 用于慢慢修正频率偏差。

对应到 NCO,可以写成:

Wn+1=W0+fn+1 W_{n+1} = W_0 + f_{n+1} Wn+1=W0+fn+1

θn+1=θn+Wn+1+Kpen \theta_{n+1} = \theta_n + W_{n+1} + K_p e_n θn+1=θn+Wn+1+Kpen

实际实现时要注意三件事:

(1) 积分限幅 :fnf_nfn 要限制最大最小值,避免误边沿造成频率控制字失控。

(2) 误差限幅 :ene_nen 要 clip,避免毛刺破坏锁定。

(3) 无边沿保持 :没有有效边沿时,只让 NCO 自由运行,不更新 KpK_pKp 和 KiK_iKi。

伪代码如下:

c 复制代码
if edge_valid:
    edge_ref = nearest_nco_boundary(edge_time)
    error = edge_time - edge_ref
    error = wrap_to_half_ui(error)
    error = clamp(error, -error_limit, error_limit)

    freq_corr += Ki * error
    freq_corr = clamp(freq_corr, -freq_limit, freq_limit)

    phase_corr = Kp * error + freq_corr
    nco_phase += phase_inc + phase_corr
else:
    nco_phase += phase_inc + freq_corr

参数设计

环路参数决定 CDR 的抖动传递特性。直观理解:

(1) KpK_pKp 大,CDR 快速修正相位,能跟随较快的抖动。

(2) KiK_iKi 大,CDR 快速修正频率偏差,但更容易被低频漂移和误边沿影响。

(3) 环路带宽高,眼图中低频抖动会被 CDR 跟踪掉。

(4) 环路带宽低,更多抖动会保留在 TIE 和眼图里。

如果把误差单位归一化为 UI,把更新周期按"每个有效边沿"计,工程上可以用下面的二阶环路形式作为起点:

Kp≈2ζωn K_p \approx 2\zeta\omega_n Kp≈2ζωn

Ki≈ωn2 K_i \approx \omega_n^2 Ki≈ωn2

其中:

(1) ζ\zetaζ 是阻尼系数,常取 0.7070.7070.707 左右。

(2) ωn\omega_nωn 是归一化自然频率,和目标环路带宽相关。

这只是离散实现的近似起点,不是所有协议的标准公式。真正用于一致性测试时,应按照协议规定的 CDR 带宽、阶数和抖动传递函数实现。

开发调试时可以这样调:

(1) 先设很小的 KiK_iKi,只验证相位能否稳定跟踪。

(2) 再逐步增加 KiK_iKi,让频率偏差能收敛。

(3) 观察锁定后的 TIE RMS,防止环路过度跟随高频抖动。

(4) 用已知抖动注入信号验证 CDR 的抖动传递特性。

锁定检测

CDR 不能默认永远锁定。工程实现需要输出锁定状态,否则错误的 UI 边界会污染眼图和 BER 外推。

常用锁定判断条件:

(1) 相位误差均值接近 0

∣e‾∣<Emean |\overline{e}| < E_{\text{mean}} ∣e∣<Emean

(2) 相位误差 RMS 足够小

1N∑en2<Erms \sqrt{\frac{1}{N}\sum e_n^2} < E_{\text{rms}} N1∑en2 <Erms

(3) 频率修正量稳定

∣fn−fn−M∣<Fstable |f_n-f_{n-M}| < F_{\text{stable}} ∣fn−fn−M∣<Fstable

(4) 连续有效边沿数量足够:至少观察到一定数量的有效边沿。

(5) 无 cycle slip :最近一段时间没有出现 ∣e∣>UI/2|e|>UI/2∣e∣>UI/2 的情况。

可以用锁定计数器实现:

c 复制代码
if error_rms_ok && freq_stable && no_cycle_slip:
    lock_counter++
else:
    lock_counter = 0

locked = lock_counter > lock_threshold

失锁条件通常包括:

(1) 长时间没有有效边沿。

(2) 连续出现过大相位误差。

(3) 频率修正量达到限幅。

(4) 眼图折叠后相位持续漂移。

只有 locked = true 后,才建议输出高可信度的眼图测量、TIE、BER 外推和 Mask Test。

6. 缺失边沿

NRZ 数据不是每个 UI 都有边沿。例如连续 11110000 中,只有从 10 的位置有跳变。因此 CDR 不能要求每个 UI 都更新误差。

工程实现中通常这样处理:

(1) 本地时钟每个 UI 都按当前 TTT 自由运行。

(2) 只有检测到有效边沿时,才计算 ene_nen 并更新 PLL。

(3) 长时间没有边沿时,保持当前频率和相位预测。

(4) 如果无边沿时间过长,可以降低置信度或提示 CDR 失锁。

伪代码如下:

c 复制代码
for each UI:
    clock_phase += ui_period

    if valid_edge_detected:
        error = edge_time - nearest_clock_edge(clock_phase)
        ui_period += Ki * error
        clock_phase += Kp * error

这里的 nearest_clock_edge() 很关键。因为一个边沿可能对应本地时钟的某个整数 UI 边界,需要先找到离实际边沿最近的预测边界,再计算误差。

7. Bang-Bang CDR

有些 CDR 不使用连续误差大小,而只判断边沿是早了还是晚了,这叫 Bang-Bang CDR。它的相位检测结果只有三种:

en={+1,edge late−1,edge early0,no edge e_n = \begin{cases} +1, & \text{edge late} \\ -1, & \text{edge early} \\ 0, & \text{no edge} \end{cases} en=⎩ ⎨ ⎧+1,−1,0,edge lateedge earlyno edge

然后用这个方向信号调整本地时钟:

ϕn+1=ϕn+T+Ken \phi_{n+1} = \phi_n + T + K e_n ϕn+1=ϕn+T+Ken

这种方法对噪声和幅度误差不那么敏感,硬件接收机中很常见;缺点是不能直接得到边沿偏差的真实时间大小,收敛和抖动特性依赖环路设计。

软件示波器如果要做测量,通常更喜欢保留实际边沿时间误差,因为这样可以直接计算 TIE、RJ、DJ 和眼宽。

8. CDR 输出

CDR 最终要输出的不是一条可视波形,而是一组 UI 边界:

tboundary,0,tboundary,1,⋯ ,tboundary,N t_{\text{boundary},0},t_{\text{boundary},1},\cdots,t_{\text{boundary},N} tboundary,0,tboundary,1,⋯,tboundary,N

有了这些边界,眼图折叠就不再使用固定取模:

ϕi=(ti−t0) mod UI \phi_i = (t_i - t_0) \bmod UI ϕi=(ti−t0)modUI

而是先找到采样点 tit_iti 属于哪一个 UI 区间:

tboundary,n≤ti<tboundary,n+1 t_{\text{boundary},n} \le t_i < t_{\text{boundary},n+1} tboundary,n≤ti<tboundary,n+1

再计算相对相位:

ϕi=ti−tboundary,ntboundary,n+1−tboundary,n \phi_i = \frac{t_i - t_{\text{boundary},n}}{t_{\text{boundary},n+1}-t_{\text{boundary},n}} ϕi=tboundary,n+1−tboundary,nti−tboundary,n

这样得到的是归一化相位,范围为 0∼1UI0 \sim 1UI0∼1UI。如果要显示成时间单位,再乘以平均 UI。

这种做法比固定 UI 取模更接近真实接收端,因为接收端本身也是用恢复时钟来决定采样位置。

9. 边沿检测

边沿检测看似简单:电压跨过阈值就算一个边沿。但实际波形存在噪声、振铃、毛刺和过冲,如果只判断:

(V1−Vth)(V2−Vth)<0 (V_1 - V_{\text{th}})(V_2 - V_{\text{th}}) < 0 (V1−Vth)(V2−Vth)<0

会出现很多误判。

常见问题:

(1) 噪声在阈值附近来回抖动,导致一个真实边沿被检测成多个边沿。

(2) 振铃跨过阈值,导致边沿后面又出现伪边沿。

(3) 毛刺很窄,但也穿过阈值,被误认为数据跳变。

(4) 过冲和下冲导致电平短暂越界,干扰阈值判断。

(5) 码间干扰让边沿斜率很小,交叉时间容易被噪声拉动。

因此工程中的边沿检测通常不是单一阈值,而是一套判定规则。

10. 阈值选择

NRZ 信号的基本阈值可以取高低电平中点:

Vth=Vhigh+Vlow2 V_{\text{th}} = \frac{V_{\text{high}} + V_{\text{low}}}{2} Vth=2Vhigh+Vlow

但 VhighV_{\text{high}}Vhigh 和 VlowV_{\text{low}}Vlow 不应该简单取最大值和最小值,因为过冲、下冲和毛刺会污染极值。更稳妥的做法是用电压直方图找两个电平峰值。

流程如下:

(1) 对波形电压做直方图。

(2) 找低电平峰和高电平峰。

(3) 取两个峰值之间的中点作为初始阈值。

(4) 如果协议规定阈值,则优先使用协议阈值。

对 PAM4,需要找四个电平峰,并生成三个阈值:

Vth1,Vth2,Vth3 V_{\text{th1}},V_{\text{th2}},V_{\text{th3}} Vth1,Vth2,Vth3

每个阈值对应一个眼孔。

11. 迟滞检测

迟滞的作用是避免噪声在阈值附近造成多次触发。定义两个阈值:

Vhigh-th=Vth+H V_{\text{high-th}} = V_{\text{th}} + H Vhigh-th=Vth+H

Vlow-th=Vth−H V_{\text{low-th}} = V_{\text{th}} - H Vlow-th=Vth−H

其中 HHH 是迟滞宽度。只有信号从低于 Vlow-thV_{\text{low-th}}Vlow-th 上升并超过 Vhigh-thV_{\text{high-th}}Vhigh-th,才判定为上升沿;只有信号从高于 Vhigh-thV_{\text{high-th}}Vhigh-th 下降并低于 Vlow-thV_{\text{low-th}}Vlow-th,才判定为下降沿。

状态机可以写成:

text 复制代码
LOW 状态:等待电压超过 V_high-th -> 上升沿
HIGH 状态:等待电压低于 V_low-th -> 下降沿

迟滞宽度通常和噪声有关:

H≈kσnoise H \approx k\sigma_{\text{noise}} H≈kσnoise

噪声越大,迟滞越需要加宽;但迟滞太宽会让边沿检测位置偏移,所以检测到边沿后仍应使用原始判决阈值 VthV_{\text{th}}Vth 做插值,迟滞只用于确认边沿是否有效。

12. 死区时间

死区时间用于抑制振铃造成的重复边沿。检测到一个边沿后,在一段时间内不允许再次触发:

Tdead=αUI T_{\text{dead}} = \alpha UI Tdead=αUI

常见取值可以是:

0.2UI∼0.5UI 0.2UI \sim 0.5UI 0.2UI∼0.5UI

如果 TdeadT_{\text{dead}}Tdead 太短,振铃可能被当成多个边沿;如果太长,又可能漏掉真实的连续跳变。对 NRZ 信号,相邻真实边沿理论上不会短于 1UI1UI1UI,所以死区时间可以小于 1UI1UI1UI,但应足够覆盖边沿后的主要振铃区。

13. 斜率约束

真实数据边沿应该有足够斜率。毛刺和噪声虽然可能跨过阈值,但持续时间短、形态不稳定。可以在阈值附近计算局部斜率:

S=V2−V1t2−t1 S = \frac{V_2 - V_1}{t_2 - t_1} S=t2−t1V2−V1

只有满足:

∣S∣>Smin⁡ |S| > S_{\min} ∣S∣>Smin

才认为是有效边沿。

斜率约束的意义是:低速漂移、电源噪声和阈值附近的小幅扰动不应该触发边沿。但斜率门限不能设得太高,否则带宽受限或长线损耗后的真实慢边沿会被误删。

14. 脉宽约束

毛刺通常持续时间很短。可以要求跨越阈值后,信号必须在新状态保持一段最小时间:

Thold>βUI T_{\text{hold}} > \beta UI Thold>βUI

例如检测到上升沿后,如果信号很快又跌回低电平,并且高电平持续时间远小于合理 UI,就可以认为这是毛刺而不是真实数据边沿。

这一步本质上是在利用数字通信的物理约束:合法码元不应该短到明显小于 UI。

15. 插值定位

边沿检测先判断"有没有边沿",插值定位再计算"边沿准确发生在什么时候"。假设边沿跨过阈值的两个采样点为 (t1,V1)(t_1,V_1)(t1,V1) 和 (t2,V2)(t_2,V_2)(t2,V2),则交叉时间为:

tcross=t1+Vth−V1V2−V1(t2−t1) t_{\text{cross}} = t_1 + \frac{V_{\text{th}} - V_1}{V_2 - V_1}(t_2 - t_1) tcross=t1+V2−V1Vth−V1(t2−t1)

线性插值成立的前提是阈值附近波形近似线性。对于采样率足够高、阈值窗口较窄的情况,这个近似通常可用。

如果采样率较低或边沿弯曲明显,可以使用多点拟合:

(1) 取阈值附近多个点。

(2) 用直线或低阶多项式拟合。

(3) 求拟合曲线与 VthV_{\text{th}}Vth 的交点。

多点拟合可以降低噪声影响,但也可能被振铃和非线性边沿污染。实际实现中,常用线性插值作为基础版本,再提供可选的滤波或拟合模式。

16. 抗噪流程

一个较稳妥的边沿检测流程如下:

(1) 估计高低电平和噪声标准差。

(2) 计算判决阈值 VthV_{\text{th}}Vth。

(3) 设置迟滞阈值 Vhigh-thV_{\text{high-th}}Vhigh-th 和 Vlow-thV_{\text{low-th}}Vlow-th。

(4) 用状态机寻找候选边沿。

(5) 对候选边沿检查死区时间。

(6) 检查阈值附近斜率是否足够。

(7) 检查新状态保持时间,排除毛刺。

(8) 用原始阈值 VthV_{\text{th}}Vth 插值得到精确 tcrosst_{\text{cross}}tcross。

(9) 把有效边沿送入码率估计或 CDR。

伪代码如下:

c 复制代码
for each sample i:
    update_state_by_hysteresis(v[i])

    if state_changed:
        if t[i] - last_edge_time < dead_time:
            reject_edge()
            continue

        if abs(local_slope(i)) < slope_min:
            reject_edge()
            continue

        if not hold_time_ok(i):
            reject_edge()
            continue

        edge_time = interpolate_crossing(i, Vth)
        accept_edge(edge_time)

17. BER 外推

眼图可以显示已经采集到的数据分布,但很多高速接口要求在极低误码率下评估眼高、眼宽,例如:

BER=10−9, 10−12, 10−15 BER = 10^{-9},\ 10^{-12},\ 10^{-15} BER=10−9, 10−12, 10−15

如果直接靠真实采样统计 10−1210^{-12}10−12 的事件,理论上至少要观察 101210^{12}1012 个 bit 量级的数据,测试时间和存储量都很大。因此示波器和分析软件通常会做 BER 外推:先测量有限样本中的抖动、噪声分布,再用统计模型估算更低 BER 下眼图会闭合到什么程度。

BER 外推要解决的问题是:

(1) 已采到的数据只覆盖了概率较高的中心区域。

(2) 真正影响低 BER 的往往是分布尾部。

(3) 分布尾部样本很少,必须用模型拟合。

(4) 外推结果依赖模型假设,不能无条件等同真实误码率测试。

18. 浴缸曲线

浴缸曲线是 BER 外推最常见的表达方式。它描述采样时刻在 UI 内移动时,对应的误码率如何变化:

BER=f(tsample) BER = f(t_{\text{sample}}) BER=f(tsample)

在眼图中心采样时,距离左右边沿最远,误码率最低;采样点靠近边沿时,边沿抖动更容易侵入采样点,误码率升高。曲线两侧向上抬起,中间较低,形状类似浴缸。

从 TIE 角度看,左边沿和右边沿都有自己的时间分布。假设左边沿分布为 PL(t)P_L(t)PL(t),右边沿分布为 PR(t)P_R(t)PR(t),当采样时刻为 tst_sts 时:

(1) 左边沿如果抖到 tst_sts 右侧,可能导致采样过早。

(2) 右边沿如果抖到 tst_sts 左侧,可能导致采样过晚。

因此 BER 可以近似看成左右尾部概率之和:

BER(ts)≈P(tL>ts)+P(tR<ts) BER(t_s) \approx P(t_L > t_s) + P(t_R < t_s) BER(ts)≈P(tL>ts)+P(tR<ts)

这个公式不是严格协议定义,而是帮助理解:浴缸曲线本质上是在看边沿时间分布尾部侵入采样点的概率。

给定目标误码率 BER0BER_0BER0,左右浴缸曲线之间的水平距离就是该 BER 下的眼宽:

EyeWidth(BER0)=tR(BER0)−tL(BER0) EyeWidth(BER_0) = t_R(BER_0) - t_L(BER_0) EyeWidth(BER0)=tR(BER0)−tL(BER0)

所以"某 BER 下的眼宽"不是简单从当前眼图空白区量出来的,而是由抖动分布尾部推算出来的。

19. Dual-Dirac

Dual-Dirac 是高速链路抖动分析里常用的简化模型。它把总抖动分成两类:

(1) 随机抖动 RJ:近似高斯分布,理论上无界。

(2) 确定性抖动 DJ:有界,可以理解为两个主要边界之间的固定展开量。

Dual-Dirac 模型把复杂的确定性抖动等效成两个冲激位置,再在每个冲激上叠加相同的高斯随机抖动:

p(t)=12G(t−μ1,σ)+12G(t−μ2,σ) p(t) = \frac{1}{2}G(t-\mu_1,\sigma) + \frac{1}{2}G(t-\mu_2,\sigma) p(t)=21G(t−μ1,σ)+21G(t−μ2,σ)

其中:

(1) G(t,σ)G(t,\sigma)G(t,σ) 是高斯分布。

(2) σ\sigmaσ 表示随机抖动 RMS。

(3) μ1\mu_1μ1 和 μ2\mu_2μ2 是两个等效 Dirac 位置。

(4) 两个 Dirac 之间的距离表示确定性抖动:

DJδδ=μ2−μ1 DJ_{\delta\delta} = \mu_2 - \mu_1 DJδδ=μ2−μ1

在这个模型下,目标 BER 下的总抖动可以写成:

TJ(BER)=DJδδ+2Q(BER)σRJ TJ(BER) = DJ_{\delta\delta} + 2Q(BER)\sigma_{RJ} TJ(BER)=DJδδ+2Q(BER)σRJ

这个公式非常重要。它说明低 BER 下的总抖动由两部分组成:

(1) DJδδDJ_{\delta\delta}DJδδ:确定性部分,近似固定。

(2) 2Q(BER)σRJ2Q(BER)\sigma_{RJ}2Q(BER)σRJ:随机抖动尾部,BER 越低,Q(BER)Q(BER)Q(BER) 越大。

为什么是 2Qσ2Q\sigma2Qσ?因为眼图左右两侧边沿都可能侵入采样窗口,左尾和右尾各贡献一个 QσQ\sigmaQσ 的裕量。

Dual-Dirac 的意义不是说真实抖动真的只有两个冲激,而是用一个简单模型把复杂分布转成可以外推的形式。它适合工程估算和一致性测试中的标准化计算,但如果实际抖动分布明显非高斯、强多峰或非平稳,外推结果会有风险。

参数提取

从实测数据中使用 Dual-Dirac,核心是估计两个参数:

(1) 随机抖动标准差 σRJ\sigma_{RJ}σRJ。

(2) 等效确定性抖动 DJδδDJ_{\delta\delta}DJδδ。

常见做法不是直接从整个 TIE 直方图求标准差,因为整个分布同时包含 RJ 和 DJ。整个 TIE 标准差会把数据相关抖动、周期性抖动、占空比失真等确定性成分也算进去,导致 RJ 被高估。更合理的是看分布左右尾部。若尾部由高斯 RJ 主导,则在 Q-scale 上尾部斜率对应 σRJ\sigma_{RJ}σRJ。

从 TIE 提取 RJ 和 DJ 的基本步骤如下。

(1) 先得到 TIE 数组:

TIEn=tcross,n−tideal,n TIE_n = t_{\text{cross},n} - t_{\text{ideal},n} TIEn=tcross,n−tideal,n

(2) 将 TIE 从小到大排序:

x0≤x1≤⋯≤xN−1 x_0 \le x_1 \le \cdots \le x_{N-1} x0≤x1≤⋯≤xN−1

(3) 对右尾样本估算尾部概率:

pR,i=N−iN+1 p_{R,i} = \frac{N-i}{N+1} pR,i=N+1N−i

(4) 转换成 Q 坐标:

qR,i=Q(pR,i) q_{R,i} = Q(p_{R,i}) qR,i=Q(pR,i)

(5) 在右尾选择一段近似线性的区域,拟合:

xi≈aRqR,i+bR x_i \approx a_R q_{R,i} + b_R xi≈aRqR,i+bR

如果右尾近似高斯,则斜率 aRa_RaR 就是右尾随机抖动标准差:

σRJ,R≈aR \sigma_{RJ,R} \approx a_R σRJ,R≈aR

左尾类似,只是尾部概率为:

pL,i=i+1N+1 p_{L,i} = \frac{i+1}{N+1} pL,i=N+1i+1

并拟合:

xi≈aLqL,i+bL x_i \approx a_L q_{L,i} + b_L xi≈aLqL,i+bL

由于左尾方向和右尾方向相反,实际实现中常取斜率绝对值:

σRJ,L≈∣aL∣ \sigma_{RJ,L} \approx |a_L| σRJ,L≈∣aL∣

最终 RJ 可以取左右尾平均:

σRJ=σRJ,L+σRJ,R2 \sigma_{RJ} = \frac{\sigma_{RJ,L}+\sigma_{RJ,R}}{2} σRJ=2σRJ,L+σRJ,R

如果左右尾差异很大,说明抖动分布不对称,应该分别报告左右尾结果,或者提示 Dual-Dirac 模型拟合质量不足。

得到 σRJ\sigma_{RJ}σRJ 后,可以利用某个已测总抖动点反推 DJδδDJ_{\delta\delta}DJδδ。例如在某个概率 ppp 下,从实测分布得到总抖动 TJ(p)TJ(p)TJ(p),则:

DJδδ=TJ(p)−2Q(p)σRJ DJ_{\delta\delta} = TJ(p) - 2Q(p)\sigma_{RJ} DJδδ=TJ(p)−2Q(p)σRJ

这里的 TJ(p)TJ(p)TJ(p) 可以由实测分布在该概率处的左右边界得到:

TJ(p)=xR(p)−xL(p) TJ(p) = x_R(p) - x_L(p) TJ(p)=xR(p)−xL(p)

其中 xR(p)x_R(p)xR(p) 是右尾概率为 ppp 的时间位置,xL(p)x_L(p)xL(p) 是左尾概率为 ppp 的时间位置。

然后再外推到目标 BER:

TJ(BER0)=DJδδ+2Q(BER0)σRJ TJ(BER_0) = DJ_{\delta\delta} + 2Q(BER_0)\sigma_{RJ} TJ(BER0)=DJδδ+2Q(BER0)σRJ

这个过程的关键假设是:分布尾部主要由高斯随机抖动决定,而确定性抖动只负责把左右边界拉开。如果实际尾部由周期性干扰、串扰突发或非高斯噪声主导,使用这个模型会低估或高估低 BER 下的总抖动。

实现时通常还会输出:

(1) RJrms=σRJRJ_{\text{rms}} = \sigma_{RJ}RJrms=σRJ。

(2) DJδδDJ_{\delta\delta}DJδδ。

(3) TJ(BER0)TJ(BER_0)TJ(BER0)。

(4) 左右尾拟合残差。

(5) 左右尾斜率差异。

其中拟合残差和左右尾斜率差异很重要,它们用于判断"这个 BER 外推可信不可信"。如果尾部在 Q-scale 上不是直线,或者左右尾斜率差异过大,说明不能简单相信外推到 10−1210^{-12}10−12 或 10−1510^{-15}10−15 的结果。

实际分离算法

Dual-Dirac 给出了外推模型,但工程软件通常还会进一步把 DJ 分成若干可解释成分:

(1) DCDDuty Cycle Distortion,占空比失真,上升沿和下降沿平均位置不同。

(2) DDJData Dependent Jitter,数据相关抖动,不同前后码型导致边沿位置不同。

(3) PJPeriodic Jitter,周期性抖动,通常来自电源、时钟串扰或调制干扰。

(4) BUJBounded Uncorrelated Jitter,有界但和数据不强相关的抖动。

(5) RJ:随机抖动,通常以高斯尾部建模。

所以可以把 TIE 近似写成:

TIE=RJ+DCD+DDJ+PJ+BUJ TIE = RJ + DCD + DDJ + PJ + BUJ TIE=RJ+DCD+DDJ+PJ+BUJ

实际分离不是完美数学分解,而是按"可解释、可估计"的顺序逐步剥离。

预处理

先计算原始 TIE:

TIEn=tedge,n−tideal,n TIE_n = t_{\text{edge},n}-t_{\text{ideal},n} TIEn=tedge,n−tideal,n

然后去掉均值:

TIEn′=TIEn−TIE‾ TIE'_n = TIE_n - \overline{TIE} TIEn′=TIEn−TIE

如果存在明显频率偏差或慢漂移,还需要先用 CDR 或线性拟合去掉趋势,否则这些低频漂移会被误算成 DJ 或 RJ。

DCD

DCD 来自上升沿和下降沿平均位置不同。分别统计上升沿 TIE 和下降沿 TIE 的均值:

μrise=mean⁡(TIErise) \mu_{\text{rise}} = \operatorname{mean}(TIE_{\text{rise}}) μrise=mean(TIErise)

μfall=mean⁡(TIEfall) \mu_{\text{fall}} = \operatorname{mean}(TIE_{\text{fall}}) μfall=mean(TIEfall)

DCD 可以估算为:

DCD=∣μrise−μfall∣ DCD = |\mu_{\text{rise}}-\mu_{\text{fall}}| DCD=∣μrise−μfall∣

计算 DCD 后,可以从对应边沿中减去各自均值,得到去 DCD 后的残差:

rn=TIEn−μedge type r_n = TIE_n - \mu_{\text{edge type}} rn=TIEn−μedge type

这样做的原因是:如果不先去掉 DCD,上升沿和下降沿两个分布中心会分开,TIE 直方图可能出现双峰,导致 RJ 估计被放大。

DDJ

DDJ 来自数据模式。例如当前边沿之前有几个连续相同码元,通道的 ISI 会不同,导致边沿到达时间不同。

实现时需要给每个边沿附加码型上下文,例如前后若干 bit:

patternn=bn−m,⋯ ,bn,⋯ ,bn+k pattern_n = b_{n-m},\\cdots,b_n,\\cdots,b_{n+k} patternn=bn−m,⋯,bn,⋯,bn+k

对每一种 pattern,计算该组边沿的平均 TIE:

μp=mean⁡(TIE∣pattern=p) \mu_p = \operatorname{mean}(TIE \mid pattern=p) μp=mean(TIE∣pattern=p)

DDJ 峰峰值可以估算为:

DDJpp=max⁡p(μp)−min⁡p(μp) DDJ_{pp} = \max_p(\mu_p)-\min_p(\mu_p) DDJpp=pmax(μp)−pmin(μp)

去除 DDJ 时,从每个边沿的 TIE 中减去对应 pattern 的均值:

rn=TIEn−μpatternn r_n = TIE_n - \mu_{pattern_n} rn=TIEn−μpatternn

这样做的意义是:数据相关的平均偏移属于确定性抖动,不应混入随机抖动尾部。否则某些码型边沿偏早、某些码型边沿偏晚,会让整体直方图变宽,从而高估 RJ。

如果没有解码数据,也可以用边沿间隔或前后电平轨迹近似分类。例如把边沿按前一个跳变距离分成 1UI,2UI,3UI1UI,2UI,3UI1UI,2UI,3UI 等类别,粗略估计 ISI 引起的 DDJ。

PJ

PJ 是周期性抖动,通常表现为 TIE 残差中的频谱尖峰。去除 DCD 和 DDJ 后,对残差 rnr_nrn 做频谱分析:

Rk=FFT⁡(rn) Rk = \operatorname{FFT}(r_n) Rk=FFT(rn)

若某些频率点明显高于噪声底,可以认为存在周期性抖动。对每个显著频率分量,可以估计幅度和相位,重构周期抖动:

PJn=∑mAmsin⁡(2πfmn+φm) PJ_n = \sum_m A_m \sin(2\pi f_m n + \varphi_m) PJn=m∑Amsin(2πfmn+φm)

然后从残差中减去:

rn′=rn−PJn r'_n = r_n - PJ_n rn′=rn−PJn

PJ 的峰峰值可以由重构波形估算:

PJpp=max⁡(PJn)−min⁡(PJn) PJ_{pp} = \max(PJ_n)-\min(PJ_n) PJpp=max(PJn)−min(PJn)

频谱阈值不能太低,否则会把随机噪声的偶然峰当成 PJ;也不能太高,否则会漏掉真实周期干扰。工程上通常需要最小峰值门限、最小持续时间和频率稳定性检查。

RJ

去除 DCD、DDJ、显著 PJ 后,剩下的残差更接近随机抖动:

rRJ,n=TIEn−DCDn−DDJn−PJn r_{\text{RJ},n} = TIE_n - DCD_n - DDJ_n - PJ_n rRJ,n=TIEn−DCDn−DDJn−PJn

这时可以计算:

RJrms=std⁡(rRJ) RJ_{\text{rms}} = \operatorname{std}(r_{\text{RJ}}) RJrms=std(rRJ)

但更推荐仍然使用 Q-scale 尾部斜率估计 RJ,因为低 BER 外推关心的是尾部,而不是中间主体。若残差直方图接近高斯,且 Q-scale 左右尾近似直线,则 RJ 估计较可信。

总 DJ

工程报告里的 DJ 可以用多个分量组合:

DJpp≈DCD+DDJpp+PJpp+BUJpp DJ_{pp} \approx DCD + DDJ_{pp} + PJ_{pp} + BUJ_{pp} DJpp≈DCD+DDJpp+PJpp+BUJpp

也可以使用 Dual-Dirac 等效 DJ:

DJδδ=TJ(p)−2Q(p)RJrms DJ_{\delta\delta} = TJ(p) - 2Q(p)RJ_{\text{rms}} DJδδ=TJ(p)−2Q(p)RJrms

两者含义不同:

(1) 分量法 DJ 更适合定位问题来源。

(2) Dual-Dirac DJ 更适合 BER 外推。

因此开发软件时可以同时输出"分量分解"和"等效 Dual-Dirac 参数"。前者帮助调试硬件问题,后者用于计算 TJ(BER)TJ(BER)TJ(BER) 和浴缸曲线。

分离流程

完整流程可以写成:

(1) 边沿检测,得到 tedget_{\text{edge}}tedge。

(2) CDR 生成 tidealt_{\text{ideal}}tideal。

(3) 计算 TIE。

(4) 去均值和慢趋势。

(5) 按上升沿/下降沿提取 DCD。

(6) 按码型分组提取 DDJ。

(7) 对残差做 FFT,提取显著 PJ。

(8) 剩余残差估计 RJ。

(9) 用 Q-scale 和 Tail Fitting 校验 RJ 尾部。

(10) 输出 RJ、DCD、DDJ、PJ、DJ 和 TJ(BER)TJ(BER)TJ(BER)。

需要注意,RJ/DJ 分离没有唯一答案,不同仪器和标准可能使用不同算法。文章中的流程适合理解和开发基础分析功能;如果用于一致性测试,应以协议和仪器标准定义为准。

20. Q-Scale

Q-scale 是把概率尾部转换成"等效高斯标准差倍数"的坐标。对标准正态分布,尾部概率和 QQQ 的关系为:

P(x>Qσ)=12erfc⁡(Q2) P(x > Q\sigma) = \frac{1}{2}\operatorname{erfc}\left(\frac{Q}{\sqrt{2}}\right) P(x>Qσ)=21erfc(2 Q)

反过来:

Q(p)=2erfc⁡−1(2p) Q(p) = \sqrt{2}\operatorname{erfc}^{-1}(2p) Q(p)=2 erfc−1(2p)

其中 ppp 是单侧尾部概率。常见近似关系如下:

单侧尾部概率 ppp QQQ 约等于
10−310^{-3}10−3 3.093.093.09
10−610^{-6}10−6 4.754.754.75
10−910^{-9}10−9 6.006.006.00
10−1210^{-12}10−12 7.037.037.03
10−1510^{-15}10−15 7.947.947.94

Q-scale 的核心作用是把高斯尾部变成近似直线。若随机抖动是高斯分布,边沿分布的尾部在 Q-scale 上应接近直线。这样就可以用有限样本中可见的尾部去拟合直线,再向更低 BER 外推。

对眼图来说,Q-scale 常用于:

(1) 把 TIE 直方图的累积分布转换为 Q 坐标。

(2) 判断尾部是否接近高斯。

(3) 估计随机抖动 RMS。

(4) 外推 10−1210^{-12}10−12、10−1510^{-15}10−15 等低 BER 位置。

需要注意,BER 通常是双侧问题,而 Q 表中常见的是单侧尾部概率。具体实现时要确认软件使用的是单侧 BER、双侧 BER,还是每个边沿各分配一半概率。例如目标总 BER 为 10−1210^{-12}10−12 时,左右边沿可能各按 5×10−135 \times 10^{-13}5×10−13 分配。

21. Tail Fitting

Tail Fitting 是 BER 外推的关键步骤。它不是拟合整个抖动分布,而是专门拟合分布尾部,因为低 BER 对应的就是极小概率尾部事件。

基本流程如下:

(1) 从边沿检测得到大量 TIE:

TIE0,TIE1,⋯ ,TIEN−1 TIE_0,TIE_1,\cdots,TIE_{N-1} TIE0,TIE1,⋯,TIEN−1

(2) 对 TIE 排序,得到经验累积分布 CDF。

(3) 左尾使用 P(TIE<t)P(TIE < t)P(TIE<t),右尾使用 P(TIE>t)P(TIE > t)P(TIE>t)。

(4) 把尾部概率转换到 Q-scale。

(5) 对尾部点做线性拟合。

(6) 将拟合直线延伸到目标 BER。

以右尾为例,经验尾部概率为:

pR(t)=P(TIE>t) p_R(t) = P(TIE > t) pR(t)=P(TIE>t)

转换为 Q 坐标:

QR(t)=Q(pR(t)) Q_R(t) = Q(p_R(t)) QR(t)=Q(pR(t))

如果尾部近似高斯,则:

t≈μR+σRQR t \approx \mu_R + \sigma_R Q_R t≈μR+σRQR

因此在 ttt 与 QRQ_RQR 的坐标中,尾部应近似为一条直线:

t=aQ+b t = aQ + b t=aQ+b

其中:

(1) 斜率 aaa 对应随机抖动标准差 σ\sigmaσ。

(2) 截距 bbb 对应等效确定性边界位置。

外推到目标概率 p0p_0p0 时:

t(p0)=aQ(p0)+b t(p_0) = aQ(p_0) + b t(p0)=aQ(p0)+b

左尾和右尾分别拟合,可以得到目标 BER 下左右边沿的位置。两者之间的距离就是外推后的眼宽。

Tail Fitting 的难点在于选择尾部拟合区间:

(1) 区间太靠中心,会混入分布主体,低估尾部风险。

(2) 区间太靠尾端,样本太少,拟合不稳定。

(3) 分布若有多峰、周期性抖动或强数据相关抖动,尾部可能不是一条直线。

工程实现中常用策略是选择若干个尾部百分位点,例如从 10−310^{-3}10−3 到 10−610^{-6}10−6 的范围拟合,并检查线性相关性。如果左右尾拟合斜率差异很大,或残差明显弯曲,说明高斯尾部假设可能不成立。

实现细节

右尾拟合可以按下面方式实现。先将 TIE 从小到大排序:

x0≤x1≤⋯≤xN−1 x_0 \le x_1 \le \cdots \le x_{N-1} x0≤x1≤⋯≤xN−1

对第 iii 个样本,右尾概率可近似为:

pi=N−iN+1 p_i = \frac{N-i}{N+1} pi=N+1N−i

再转换成 Q 值:

qi=Q(pi) q_i = Q(p_i) qi=Q(pi)

选择尾部区间 i∈i1,i2i \in i_1,i_2i∈i1,i2,对点集 (qi,xi)(q_i,x_i)(qi,xi) 做线性拟合:

xi≈aqi+b x_i \approx aq_i+b xi≈aqi+b

目标尾部概率为 p0p_0p0 时:

xright(p0)=aQ(p0)+b x_{\text{right}}(p_0)=aQ(p_0)+b xright(p0)=aQ(p0)+b

左尾类似,只是使用:

pi=i+1N+1 p_i = \frac{i+1}{N+1} pi=N+1i+1

并对左侧样本做拟合。最后得到:

TJ(p0)=xright(p0)−xleft(p0) TJ(p_0)=x_{\text{right}}(p_0)-x_{\text{left}}(p_0) TJ(p0)=xright(p0)−xleft(p0)

这套算法能从有限样本推到更低概率,但前提是拟合区间真的呈线性。如果拟合残差很大,说明尾部不是简单高斯,不应继续盲目外推。

22. Eye Contour

浴缸曲线只看水平方向,也就是固定电压阈值附近的时间裕量。Eye Contour 则把 BER 外推扩展到二维眼图上,估算不同 BER 下的眼孔轮廓。

可以把 Eye Contour 理解成:

(1) 在眼图中选取多个方向或多个截面。

(2) 对每个截面上的统计分布做尾部拟合。

(3) 求出目标 BER 下的边界点。

(4) 把这些边界点连接成轮廓线。

如果只沿水平阈值方向做外推,就得到浴缸曲线;如果在多个方向都做外推,就得到二维 BER 轮廓。

Eye Contour 的意义是:它不只告诉你某个阈值下眼宽是多少,还能显示在目标 BER 下整个眼孔会缩到哪里。对 PAM4 或多电平信号尤其有用,因为每个眼孔都有不同的垂直噪声和水平抖动特性。

23. PAM4 测量

NRZ 只有两个电平,一个主要眼孔;PAM4 有四个电平,三个眼孔。PAM4 的码元可以表示 2 bit,因此在相同符号速率下吞吐量更高,但每个眼孔的垂直裕量明显变小。

PAM4 的四个电平通常记为:

L0,L1,L2,L3 L_0,L_1,L_2,L_3 L0,L1,L2,L3

三个眼孔分别位于:

(1) Eye1 :L0L_0L0 与 L1L_1L1 之间。

(2) Eye2 :L1L_1L1 与 L2L_2L2 之间。

(3) Eye3 :L2L_2L2 与 L3L_3L3 之间。

三个判决阈值为:

Vth1=μ0+μ12 V_{\text{th1}} = \frac{\mu_0+\mu_1}{2} Vth1=2μ0+μ1

Vth2=μ1+μ22 V_{\text{th2}} = \frac{\mu_1+\mu_2}{2} Vth2=2μ1+μ2

Vth3=μ2+μ32 V_{\text{th3}} = \frac{\mu_2+\mu_3}{2} Vth3=2μ2+μ3

其中 μ0,μ1,μ2,μ3\mu_0,\mu_1,\mu_2,\mu_3μ0,μ1,μ2,μ3 是四个电平在采样相位附近的均值。实际协议可能规定不同阈值或经过归一化的电平位置,开发时应优先按协议定义。

24. PAM4 电平提取

PAM4 测量第一步是从采样相位附近提取四个电平分布,而不是直接对全波形做最大最小值。

先在采样相位 ϕs\phi_sϕs 附近取电压样本:

Vs={vi∣ϕi∈ϕs−Δϕ,ϕs+Δϕ} V_s = \{v_i \mid \phi_i \in \\phi_s-\\Delta\\phi,\\phi_s+\\Delta\\phi\} Vs={vi∣ϕi∈ϕs−Δϕ,ϕs+Δϕ}

然后对 VsV_sVs 做直方图或聚类,得到四个电平簇:

C0,C1,C2,C3 C_0,C_1,C_2,C_3 C0,C1,C2,C3

每个电平的均值和标准差为:

μk=1Nk∑vi∈Ckvi \mu_k = \frac{1}{N_k}\sum_{v_i \in C_k} v_i μk=Nk1vi∈Ck∑vi

σk=1Nk∑vi∈Ck(vi−μk)2 \sigma_k = \sqrt{\frac{1}{N_k}\sum_{v_i \in C_k}(v_i-\mu_k)^2} σk=Nk1vi∈Ck∑(vi−μk)2

其中 k=0,1,2,3k=0,1,2,3k=0,1,2,3。

为什么必须在采样相位附近取样?因为 PAM4 的电平判断发生在采样点,边沿过渡区域不能代表稳定电平。如果把整个 UI 的样本都拿来聚类,边沿轨迹会把四个电平拖宽,导致电平均值和噪声估计失真。

实际实现中,电平聚类可以用:

(1) 电压直方图找四个峰。

(2) K-means 聚类,K=4K=4K=4。

(3) 协议给定电平范围时,按阈值分箱。

电平峰值排序后,最低为 L0L_0L0,最高为 L3L_3L3。

25. Level Separation

Level Separation 表示相邻两个 PAM4 电平之间的距离。它反映了接收端把相邻电平区分开的垂直空间。

相邻电平间隔为:

LS1=μ1−μ0 LS_1 = \mu_1-\mu_0 LS1=μ1−μ0

LS2=μ2−μ1 LS_2 = \mu_2-\mu_1 LS2=μ2−μ1

LS3=μ3−μ2 LS_3 = \mu_3-\mu_2 LS3=μ3−μ2

也可以计算平均电平间隔:

LSavg=LS1+LS2+LS33 LS_{\text{avg}} = \frac{LS_1+LS_2+LS_3}{3} LSavg=3LS1+LS2+LS3

理想 PAM4 电平应近似等间隔,即:

LS1≈LS2≈LS3 LS_1 \approx LS_2 \approx LS_3 LS1≈LS2≈LS3

如果 LS1,LS2,LS3LS_1,LS_2,LS_3LS1,LS2,LS3 差异很大,说明 PAM4 线性度不好,可能来自驱动器非线性、均衡设置不合理、通道压缩、接收端增益误差或电平校准问题。

为了量化电平间隔是否均匀,可以定义线性度误差:

ELS,k=LSk−LSavgLSavg E_{LS,k} = \frac{LS_k - LS_{\text{avg}}}{LS_{\text{avg}}} ELS,k=LSavgLSk−LSavg

这个值越接近 0,说明相邻电平间隔越一致。

26. PAM4 眼高

PAM4 有三个眼孔,所以眼高也要分别计算:

EyeHeight1=(μ1−kσ1)−(μ0+kσ0) EyeHeight_1 = (\mu_1-k\sigma_1)-(\mu_0+k\sigma_0) EyeHeight1=(μ1−kσ1)−(μ0+kσ0)

EyeHeight2=(μ2−kσ2)−(μ1+kσ1) EyeHeight_2 = (\mu_2-k\sigma_2)-(\mu_1+k\sigma_1) EyeHeight2=(μ2−kσ2)−(μ1+kσ1)

EyeHeight3=(μ3−kσ3)−(μ2+kσ2) EyeHeight_3 = (\mu_3-k\sigma_3)-(\mu_2+k\sigma_2) EyeHeight3=(μ3−kσ3)−(μ2+kσ2)

这里的 kσk\sigmakσ 和 NRZ 中的含义一样,用于扣除噪声尾部。以 Eye2 为例,L1L_1L1 的上噪声边界是 μ1+kσ1\mu_1+k\sigma_1μ1+kσ1,L2L_2L2 的下噪声边界是 μ2−kσ2\mu_2-k\sigma_2μ2−kσ2,两者之间的距离才是扣除噪声后的中间眼孔高度。

如果某一个眼孔高度明显小于其他眼孔,说明对应相邻电平更容易误判。例如 Eye2 变小,通常意味着 L1L_1L1 和 L2L_2L2 更难区分,即使 Eye1 和 Eye3 看起来正常,整体 PAM4 链路仍可能受中间眼孔限制。

工程上常取三个眼孔中的最小值作为最保守指标:

EyeHeightmin⁡=min⁡(EyeHeight1,EyeHeight2,EyeHeight3) EyeHeight_{\min} = \min(EyeHeight_1,EyeHeight_2,EyeHeight_3) EyeHeightmin=min(EyeHeight1,EyeHeight2,EyeHeight3)

27. PAM4 SNR

PAM4 的 SNR 不能只用全幅度除以整体噪声,因为误判发生在相邻电平之间。更有意义的是计算相邻电平的局部 SNR。

对第 kkk 个眼孔,相邻电平为 Lk−1L_{k-1}Lk−1 和 LkL_kLk,电平间隔为:

LSk=μk−μk−1 LS_k = \mu_k-\mu_{k-1} LSk=μk−μk−1

如果两个电平的噪声标准差分别为 σk−1\sigma_{k-1}σk−1 和 σk\sigma_kσk,可以定义合成噪声:

σeff,k=σk−12+σk2 \sigma_{\text{eff},k} = \sqrt{\sigma_{k-1}^2+\sigma_k^2} σeff,k=σk−12+σk2

则该眼孔的 SNR 可以写成:

SNRk=LSkσeff,k SNR_k = \frac{LS_k}{\sigma_{\text{eff},k}} SNRk=σeff,kLSk

也可以用 dB 表示:

SNRk,dB=20log⁡10(SNRk) SNR_{k,\mathrm{dB}} = 20\log_{10}(SNR_k) SNRk,dB=20log10(SNRk)

为什么噪声要平方相加?因为相邻两个电平都在抖动,判决错误取决于两个分布是否相互靠近。如果两个噪声源近似独立,其差值分布的方差为两者方差之和:

σΔ,k2=σk−12+σk2 \sigma_{\Delta,k}^2 = \sigma_{k-1}^2+\sigma_k^2 σΔ,k2=σk−12+σk2

所以相邻电平间距除以合成噪声,更能反映该眼孔的真实判决难度。

28. Eye1 Eye2 Eye3

PAM4 的三个眼孔需要分别测量,不应只给一个总眼高。

眼孔 下电平 上电平 阈值
Eye1 L0L_0L0 L1L_1L1 Vth1V_{\text{th1}}Vth1
Eye2 L1L_1L1 L2L_2L2 Vth2V_{\text{th2}}Vth2
Eye3 L2L_2L2 L3L_3L3 Vth3V_{\text{th3}}Vth3

每个眼孔都可以计算:

(1) 眼高 EyeHeightkEyeHeight_kEyeHeightk。

(2) 眼宽 EyeWidthkEyeWidth_kEyeWidthk。

(3) SNR SNRkSNR_kSNRk。

(4) 阈值交叉抖动。

(5) Mask Hit。

对眼宽来说,Eye1、Eye2、Eye3 使用不同判决阈值。以 Eye2 为例,要找穿越 Vth2V_{\text{th2}}Vth2 的边沿,再统计左右边沿交叉时间分布:

EyeWidth2=(μR,2−kσR,2)−(μL,2+kσL,2) EyeWidth_2 = (\mu_{R,2}-k\sigma_{R,2})-(\mu_{L,2}+k\sigma_{L,2}) EyeWidth2=(μR,2−kσR,2)−(μL,2+kσL,2)

Eye1 和 Eye3 同理,只是阈值分别换成 Vth1V_{\text{th1}}Vth1 和 Vth3V_{\text{th3}}Vth3。

这也是 PAM4 测量比 NRZ 复杂的原因:NRZ 只有一个阈值、一组边沿分布;PAM4 有三个阈值,三个眼孔的噪声和抖动情况可能完全不同。

29. PAM4 误判概率

PAM4 相邻电平误判可以用两个高斯分布重叠来理解。以 Eye2 为例,L1L_1L1 和 L2L_2L2 的判决阈值为 Vth2V_{\text{th2}}Vth2。

当实际发送 L1L_1L1 时,如果噪声把电压推到阈值上方,就可能被误判为 L2L_2L2 或更高:

P1→2=P(V>Vth2∣L1) P_{1\rightarrow2} = P(V > V_{\text{th2}} \mid L_1) P1→2=P(V>Vth2∣L1)

当实际发送 L2L_2L2 时,如果噪声把电压推到阈值下方,就可能被误判为 L1L_1L1 或更低:

P2→1=P(V<Vth2∣L2) P_{2\rightarrow1} = P(V < V_{\text{th2}} \mid L_2) P2→1=P(V<Vth2∣L2)

如果假设两个电平噪声近似高斯,可以写成:

P1→2≈Q(Vth2−μ1σ1) P_{1\rightarrow2} \approx Q\left(\frac{V_{\text{th2}}-\mu_1}{\sigma_1}\right) P1→2≈Q(σ1Vth2−μ1)

P2→1≈Q(μ2−Vth2σ2) P_{2\rightarrow1} \approx Q\left(\frac{\mu_2-V_{\text{th2}}}{\sigma_2}\right) P2→1≈Q(σ2μ2−Vth2)

这个公式说明,PAM4 的误码风险取决于每个电平到对应阈值的距离,以及该电平自身的噪声大小。阈值不一定总是简单中点;如果两个电平噪声不同,最优阈值会向噪声更大的那一侧偏移,以平衡误判概率。

30. PAM4 实现流程

PAM4 眼图测量可以按下面流程实现:

(1) 用 CDR 得到 UI 边界和采样相位。

(2) 在采样相位附近提取电压样本。

(3) 用直方图或聚类找到四个电平 L0,L1,L2,L3L_0,L_1,L_2,L_3L0,L1,L2,L3。

(4) 计算每个电平的 μk\mu_kμk 和 σk\sigma_kσk。

(5) 计算三个阈值 Vth1,Vth2,Vth3V_{\text{th1}},V_{\text{th2}},V_{\text{th3}}Vth1,Vth2,Vth3。

(6) 计算 LS1,LS2,LS3LS_1,LS_2,LS_3LS1,LS2,LS3 和 Level Separation 线性度。

(7) 分别计算 EyeHeight1,EyeHeight2,EyeHeight3EyeHeight_1,EyeHeight_2,EyeHeight_3EyeHeight1,EyeHeight2,EyeHeight3。

(8) 分别用三个阈值检测边沿,计算 EyeWidth1,EyeWidth2,EyeWidth3EyeWidth_1,EyeWidth_2,EyeWidth_3EyeWidth1,EyeWidth2,EyeWidth3。

(9) 计算 SNR1,SNR2,SNR3SNR_1,SNR_2,SNR_3SNR1,SNR2,SNR3。

(10) 根据协议要求做 PAM4 Mask 或 Eye Contour。

PAM4 测量结果最好按三个眼孔分别显示。只显示一个总 SNR 或总眼高,会掩盖局部最差眼孔,而系统误码往往由最差眼孔决定。

31. 外推限制

BER 外推很有用,但它依赖模型,必须知道限制:

(1) 如果随机抖动不是高斯分布,Q-scale 直线外推会出错。

(2) 如果确定性抖动不是有界稳定的,Dual-Dirac 会低估风险。

(3) 如果采样样本太少,尾部拟合不可靠。

(4) 如果 CDR 参数不符合协议,TIE 分布会改变,外推 BER 也会改变。

(5) 如果存在突发噪声、串扰事件、供电扰动,短时间采样可能完全看不到这些低概率事件。

因此外推 BER 应该被理解为"基于当前采样和模型的预测",不是绝对真实误码率。真正严格的 BER 仍需要误码仪或协议规定的一致性测试条件。

32. 实现流程

一个简化的软件实现流程如下:

(1) 用边沿检测得到 tcrosst_{\text{cross}}tcross。

(2) 用 CDR 得到理想边沿 tidealt_{\text{ideal}}tideal。

(3) 计算 TIE:

TIEn=tcross,n−tideal,n TIE_n = t_{\text{cross},n} - t_{\text{ideal},n} TIEn=tcross,n−tideal,n

(4) 分离左边沿和右边沿,分别建立 TIE 分布。

(5) 计算经验 CDF 和左右尾部概率。

(6) 转换到 Q-scale。

(7) 对左右尾部分别做线性拟合。

(8) 外推到目标 BER。

(9) 得到 TJ(BER)TJ(BER)TJ(BER)、EyeWidth(BER)EyeWidth(BER)EyeWidth(BER) 或 Eye Contour。

开发入门时可以先实现浴缸曲线外推,再扩展到二维 Eye Contour。因为浴缸曲线只需要处理时间方向的 TIE 分布,而 Eye Contour 还要处理不同电压截面和方向上的二维统计。

33. 眼图开发路径

如果从零开发眼图功能,建议按下面顺序实现:

(1) 固定码率眼图 :用户输入码率,直接得到 UI=1/RsUI=1/R_sUI=1/Rs,完成基础折叠和直方图显示。

(2) 边沿检测:实现阈值、迟滞、死区、斜率、脉宽过滤和插值。

(3) 码率估计:基于边沿间隔直方图或近似最大公约周期估计 UI。

(4) 软件 CDR:实现简化二阶 PLL,输出动态 UI 边界。

(5) 测量功能:基于 CDR 边界计算眼高、眼宽、TIE、抖动和 Mask Hit。

(6) 协议适配:根据 NRZ、PAM4、差分信号、参考时钟和标准 CDR 要求调整算法。

不要一开始就追求完整 CDR 和一致性测试。更稳妥的路线是先做固定码率版本,确认相位映射和直方图正确,再逐步替换为边沿检测、码率估计和 CDR。

34. 总结

(1) UI 的本质是码元周期,不同调制方式下比特率和码元速率不一定相等。

(2) 自动求 UI 不能简单平均边沿间隔,因为边沿间隔可能是 UIUIUI 的整数倍。

(3) 软件 CDR 是一个反馈控制系统,通过边沿相位误差不断修正本地时钟。

(4) CDR 输出的是 UI 边界,眼图应按这些边界计算相对相位。

(5) 边沿检测不能只靠单阈值,需要迟滞、死区、斜率、脉宽和插值共同保证可靠性。

(6) BER 外推通过 Dual-Dirac、Q-scale 和 Tail Fitting,把有限样本中的抖动尾部外推到更低误码率。

(7) PAM4 需要分别测量 Eye1、Eye2、Eye3,并计算 Level Separation、每个眼孔的 SNR 和最差眼孔裕量。

(8) 眼图开发的关键不是"把波形叠起来",而是先建立可信的时间基准,再把采样点映射到正确的 UI 相位中。