自适应算法基础:LMS、RLS在DFE中的应用

DFE(判决反馈均衡器)的核心在于系数更新。固定系数只能应付静态信道,一旦信道变化——比如温度漂移、线缆长度不同——均衡就崩了。这时候自适应算法就得登场了。

我个人习惯把自适应算法看作“一个不断猜、不断修正的闭环”。猜错了没关系,下次调整方向就行。你想想看,DFE的前馈和反馈抽头系数,其实就是在找一组最优值来抵消码间串扰(ISI)。

LMS:最简单的“梯度下降”

LMS(最小均方)算法,说白了就是沿着误差下降最快的方向迈一小步。数学上不复杂:

e(n) = d(n) - y(n)          // 误差,期望值减去均衡器输出
w(n+1) = w(n) + μ * e(n) * x(n)  // μ 是步长,x(n) 是输入向量

每一拍都用瞬时误差来更新系数,计算量极低。我在项目中遇到过用LMS做10Gbps DFE的场景,硬件上只需要加法器和乘法器,延迟可控。但步长μ的选取很关键。

我的经验:μ太小,收敛慢,信道突变时反应不过来;μ太大,收敛快但稳态抖动大,眼图睁不开。常用的做法是先给一个较大μ(比如2^(-6))快速收敛,再切换到小μ(2^(-10))精调。

不过LMS有个毛病——噪声放大。输入噪声大时,瞬态误差抖动厉害,系数不稳。这时候RLS更有优势。

RLS:昂贵的“精确制导”

RLS(递归最小二乘)用所有历史数据做加权最小二乘估计,每次更新都算一个“遗忘因子”λ。它收敛快,稳态误差小,但代价是计算量大约O(N²)——N是抽头数。

k(n) = P(n-1) * x(n) / (λ + x^T(n) * P(n-1) * x(n))
ε(n) = d(n) - w^T(n-1) * x(n)
w(n) = w(n-1) + k(n) * ε(n)
P(n) = (P(n-1) - k(n) * x^T(n) * P(n-1)) / λ

你看,除了矩阵P的维护和逆运算。在FPGA里实现RLS,吞吐很难做高。我记得有一次客户要求25Gbps的链路,LMS死活收敛不到目标误码率,后来换成片外ARM跑RLS,每次训练后下发系数,才解决问题。

注意:RLS的递归矩阵P容易在定点计算中出现数值发散。我在调试时吃过亏——所有数据都变成了NaN。后来强制给P做对角线重置,damp系数加到1e-6才稳住。

LMS vs RLS:怎么选?

对比项 LMS RLS
计算复杂度 O(N),极低 O(N²),较高
收敛速度 慢,依赖特征值散布 快,10倍左右
稳态误差 较大,随机抖动 接近维纳最优
数值稳定性 好,定点友好 差,需要防发散
硬件资源 加法器 + 乘法器 矩阵乘法 + 除法器
适用信道 平稳、低SNR 快变、高SNR

实际产品中,我见过大多数商用PHY芯片用LMS做在线跟踪,RLS只在上电训练阶段用。为什么?你看看硬件代价:一个16抽头的LMS用几百个LUT,RLS得几千。功耗、面积都架不住。

变种算法:NLMS、符号LMS、泄漏LMS

基础LMS有两个改进点:归一化和符号化。

  • NLMS(归一化LMS):步长除以输入功率的估计值。收敛速度不随输入幅度变化。我在调试串行链路时常用这个方法——输入信号时大时小,固定步长容易过度调节。
  • 符号LMS(Sign-Error / Sign-Data):只取误差或输入的符号(±1)。硬件实现可以省掉乘法器。我曾做过一个低功耗DFE,用符号LMS,整个更新模块只用了一个异或门和累加器。
  • 泄漏LMS:在更新时加一个衰减项,防止系数漂移。适合信道稀疏、反馈抽头长时间没有有效信号的场景。
# 伪代码:泄漏LMS更新
leak = 0.99
w(n+1) = leak * w(n) + μ * e(n) * x(n)

选择哪个变种,其实看硬件允许的位宽和流水级。

DFE自适应算法选型决策逻辑 系统约束 & 信道特征 硬件资源是否有限? LMS 系列 NLMS / 符号LMS 在线跟踪/收敛 RLS 系列 训练/初始化阶段 快速收敛 & 高精度 定点实现 + 防发散 工程建议:硬件受限+平稳信道→LMS;可接受高算力+快变信道→RLS

实现中的避坑实践

我曾经在一个40nm芯片里同时集成LMS和RLS。LMS跑在线,RLS做后台校准。说几个容易踩的坑:

坑1:定点溢出

误差e(n)可能非常大——比如链路刚上电时,均衡器输出完全错误。如果不做饱和截位,累加器直接溢出,后面系数全乱。我习惯在每一拍更新前都把乘积结果限幅到[-1, +1)之间。

坑2:收敛状态检测

怎么知道算法收敛了?看均方误差(MSE)的变化率。硬件上算MSE也不贵——对误差平方做指数平均。如果连续N个周期MSE变化小于阈值,就认为训练完成,切换步长或冻结系数。

坑3:梯度噪声耦合

LMS的更新量e(n)*x(n)会产生高频谱能量,耦合到模拟前端。我有一版设计,均衡器一启动,PLL就抖动——源头是更新模块的乘法器没有做输出滤波。解决办法:在误差通路上加一个低通,或者用时钟门控让更新只在特定相位发生。

实战代码片段(Verilog风格)

// LMS 系数更新(定点,16位有符号)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        wf[0] <= 16'h1000; // 初始值,防止全零
        // 其他抽头...
    end else if (update_en) begin
        // error = expected - y
        // 限幅到[-1, 1)
        error_sat <= (error > 16'h3FFF) ? 16'h3FFF :
                     (error < 16'hC001) ? 16'hC001 : error;
        // w_new = w + mu * error * x (mu=2^(-8))
        product <= (error_sat * x_in) >>> 8;
        wf[0] <= wf[0] + product;
    end
end

注意这里用的是有符号右移(>>>),确保负数正确。移位代替乘法实现步长,节省资源。

总结一下要点

  • LMS适合在线、硬件紧张场景,但稳态精度有限。
  • RLS适合训练、高精度场景,但注意数值发散。
  • 改进变种如NLMS、符号LMS、泄漏LMS可以弥补原生LMS的不足。
  • 工程实现必须处理定点溢出、收敛检测和噪声耦合。

回到你手头的项目——如果信道变化不快,我建议先用LMS跑起来,眼图能睁开再考虑加RLS。别一上来就上复杂算法,调试周期会很长。