接收端均衡:CTLE 与 DFE 技术详解

信号从发端经过信道跑到接收端,早就被 PCB 走线、连接器、过孔折腾得不成样子了。衰减、反射、串扰,全都混在一起。

这时候接收端要是不做点什么,眼图根本睁不开。
说白了,接收端均衡就是一把手术刀,专门修复被信道搞坏了的信号。

我刚开始做 Gen3 调优时,以为只要调发端就够。后来发现,链路跑上 8GT/s 甚至 16GT/s,发端很多问题根本救不回来,得靠接收端来兜底。

这一章我们就深入看看两个核心模块:CTLE 和 DFE。

核心观点:CTLE 负责高通滤波去高频衰减,DFE 负责消除码间干扰。两者缺一不可。

接收端均衡技术架构 接收信号输入 CTLE 连续时间线性 均衡器 DFE 判决反馈 均衡器 恢复数据 固定高频增益 不放大噪声 自适应消除 ISI 抽头数决定能力

CTLE 是什么?为什么需要它?

CTLE,全称是连续时间线性均衡器。
它是一个模拟高通滤波器。

信道对高频信号的损耗远大于低频。结果就是,信号的上升沿、下降沿变缓,眼高变小。
CTLE 做的就是补偿这个高频损耗。

你想想看,一根长长的走线就像低通滤波器。高频分量被吃掉太多,波形早就不是方波了。CTLE 在高频段给增益,把那些被削弱的边沿再拉起来。

频段 信道衰减 CTLE 补偿 结果
低频 (DC ~ 1GHz) 小 (0 ~ 3dB) 低增益 (0 ~ 2dB) 直流电平保持
中频 (1 ~ 5GHz) 中等 (3 ~ 10dB) 中增益 (2 ~ 6dB) 部分补偿
高频 (5 ~ 16GHz) 大 (10 ~ 30dB+) 高增益 (6 ~ 12dB) 边沿恢复

CTLE 一般有好几个可编程的增益档位和零点频率。实际工程中,我们通过 PRBS 测试码进行扫描,找到眼高最大的那组设置。

实战技巧:CTLE 开太高也不是好事。高频增益同时会放大噪声。我见过一些板子,CTLE 打到最大档,眼图反而变差——因为噪声被放到失真之上了。

CTLE 的自适应控制

很多 Gen3/Gen4 的 PHY 都支持 CTLE 自适应。什么意思?

  • 接收端根据检测到的信号幅度或眼图张开度,自动调整增益档位。
  • 目的是让信号幅度和信噪比达到平衡。
  • 自适应开启后,我一般会先看收敛速度。太慢的话,链路训练会超时。

但我个人习惯,在实验室调优阶段还是先用手动模式。固定一组 CTLE 系数,看眼图和 BER 表现。确定最优值后,再开启自适应让芯片跟踪温度或电压漂移。

DFE:后发制人的非线性均衡

CTLE 搞不定所有事。

信道中的反射、不连续阻抗,会产生长时间拖尾的码间干扰。CTLE 是线性滤波器,对这种后标干扰 (post-cursor ISI) 补偿能力有限。

这时候 DFE 就登场了。

DFE 的核心思路很简单:
既然已经知道前面几个 bit 是 1 还是 0,那就可以预测它们对当前 bit 的干扰量,然后减掉。

说白了,DFE 用一个反馈滤波器,消除已知的码间干扰。

DFE 工作原理示意:
输入信号 -> 采样判决 -> 判出当前 bit (dk)
                                |
                    反馈滤波器 (系数 c1, c2, ..., cn)
                                |
                    从下一输入中减去: r(k+1) - c1*dk - c2*d(k-1) - ...

这个反馈滤波器的系数数量,就是 DFE 的抽头数。抽头数越多,能消除的 ISI 范围越广。

Gen 标准 典型 DFE 抽头数 消除 ISI 的符号间隔 复杂度
Gen3 (8GT/s) 3 ~ 5 tap 3 ~ 5 UI 低
Gen4 (16GT/s) 5 ~ 8 tap 5 ~ 8 UI 中等
Gen5 (32GT/s) 8 ~ 12 tap 8 ~ 12 UI 高

DFE 的自适应算法

DFE 系数的搜索是个技术活。不能瞎调。

  • LMS 算法:最常用。自适应地最小化误差信号的均方值。
    每次更新:c_new = c_old + μ * e * d,其中 μ 是步长,e 是误差,d 是判决数据。
  • Sign-Sign LMS:工程实现的简化版。只取误差和数据的符号位。硬件成本低。
  • Zero-Forcing:直接根据信道冲击响应对抽头系数进行强制归零。

我自己在项目里多用 Sign-Sign LMS。简单,够用,收敛还不错。

避坑指南:我曾经调一块 Gen4 显卡的链路,DFE 自适应一直不收敛。查了三天,发现是 CTLE 的增益设错了。CTLE 输出信号幅度太小,DFE 的误差检测器根本没法分辨是 0 还是 1。先调好 CTLE,再开 DFE 自适应——这个顺序特别重要。

CTLE + DFE 的联合调优策略

CTLE 和 DFE 不是各干各的。它们需要配合。

CTLE 负责把信号拉回到一个合理的幅度范围内,把高频补偿到位。
DFE 负责收拾 CTLE 剩下的尾巴——那些长拖尾的码间干扰。

  1. 第一步:固定一组 DFE 系数(或者关闭 DFE),扫描 CTLE 档位。
    找一个眼高最大、眼宽合理的 CTLE 值。
  2. 第二步:CTLE 固定在这个最优档位,开启 DFE 自适应训练。
    监测 BER 是否下降,以及 DFE 系数的收敛曲线是否平稳。
  3. 第三步:如果 BER 仍达不到要求(一般 Gen4 要求 BER < 1e-12),微调 CTLE 档位后再跑一次自适应。

这个流程,说白了就是一个 CTLE -> DFE -> 联合优化 的迭代过程。

经验口:做完联合调优后,建议做一个温度扫描。从 0°C 到 85°C,看看眼图裕量会不会崩。我遇到过高温下 DFE 系数漂移导致链路断连的案例。解决方法是把 DFE 自适应一直保留开启状态。

实战:CTLE + DFE 的配置示例

下面是一段基于某个常见 SerDes IP 的配置示例。具体寄存器地址各家不同,但逻辑是相通的。

// Step 1: 初始化 PHY
phy_init();

// Step 2: 关闭 DFE,固定为低增益模式
dfe_disable();
dfe_set_coeffs(0, 0, 0);  // 清空所有抽头

// Step 3: 扫描 CTLE 档位
for (ctle_gain = 0; ctle_gain < 16; ctle_gain++) {
    ctle_set_gain(ctle_gain);
    delay(1);  // 等待稳定
    eye_height = measure_eye_height();
    // 记录
    results[ctle_gain] = eye_height;
}

// Step 4: 选择最优 CTLE 档位
int best_ctle = find_best(results);  // 眼高最大的档位
ctle_set_gain(best_ctle);

// Step 5: 开启 DFE 并开始自适应训练
dfe_enable();
dfe_lms_start(ALGORITHM_SIGN_SIGN_LMS);

// Step 6: 等待收敛或超时
while (!dfe_converged() && (timeout_ms < 500)) {
    delay(10);
}

// Step 7: 检查 BER
uint64_t ber = measure_ber();
if (ber > BER_THRESHOLD_1E_12) {
    // 微调 CTLE 后重试
    ctle_set_gain(best_ctle + 1);
    dfe_lms_restart();
}

这个流程看起来简单,但实际跑起来有很多坑。比如眼高测量本身就有噪声,你得多次采样平均。再比如 DFE 收敛后,你要读回抽头系数,看看是不是合理的值——如果某个抽头系数异常大,往往说明 CTLE 的频响出了问题。

调试技巧:测试环境中用 real-time scope 观察 DFE 的误差信号。如果误差信号分布太宽或者有明显偏置,就应该调整 DFE 的 DC 消除环路。有些 PHY 支持手动注入 DC offset 补偿。

CTLE 与 DFE 核心差异

维度 CTLE DFE
技术本质 线性模拟滤波器 非线性数字反馈
主要作用 补偿高频衰减 消除后标码间干扰 (post-cursor ISI)
噪声影响 放大噪声(不可避免) 不放大噪声(错误传播风险)
自适应速度 快(模拟环路) 较慢(数字自适应)
硬件开销 低(几个电阻电容 + 差分对) 较高(抽头越多越贵)
错误传播 无 有,单个误码可能诱发后续误码

所以我也常说一句话,CTLE 和 DFE 是黄金搭档。CTLE 打好基础,DFE 打扫战场。一项没做好,另一项再努力也白费。