4. 降噪滤波器基础

自适应滤波,说白了就是让滤波器自己学会怎么干活。你不需要事先知道噪声的统计特性,算法会一边处理一边调整系数。我最早接触这玩意儿是在一个车载通话降噪项目里,那时候天真地以为随便找个算法就能搞定,结果被现实狠狠教育了一顿。

今天咱们就聊聊三种最常用的自适应算法:LMS、NLMS 和 RLS。它们各有脾气,选对了事半功倍,选错了……嗯,你会浪费不少调试时间。

核心观点: 没有最好的算法,只有最合适的场景。收敛速度、计算量、稳定性,这三者你永远只能选两个。
自适应滤波算法选型框架 输入信号 x(n) + 期望 d(n) LMS 算法 梯度下降,计算量 O(N) NLMS 算法 归一化步长,抗波动 RLS 算法 递归最小二乘,O(N²) 收敛速度:慢 稳态误差:中等 收敛速度:中等 稳态误差:中等 收敛速度:快 稳态误差:低 适用:资源受限 实时性要求高 噪声平稳场景 适用:输入波动大 需要稳定收敛 工程首选方案 适用:快速跟踪 非平稳噪声 算力充足

4.1 LMS 算法:最朴素的梯度下降

LMS(最小均方)算法是自适应滤波的入门课。它的思想特别直白:每次迭代都沿着误差曲面的负梯度方向走一小步,让均方误差越来越小。

数学上长这样:

// LMS 算法核心更新公式
// 滤波器系数向量 w(n),输入向量 x(n),期望信号 d(n)
// 步长因子 μ,滤波器阶数 N

y(n) = w^T(n) * x(n);          // 滤波器输出
e(n) = d(n) - y(n);            // 误差信号
w(n+1) = w(n) + 2 * μ * e(n) * x(n);  // 系数更新

这里有个关键参数 μ(步长因子)。它决定了算法收敛的快慢和稳定性。

μ 取值 收敛速度 稳定性 稳态误差
μ 太小(如 0.001) 极慢,可能需要数万次迭代 非常稳定 低
μ 适中(如 0.01) 较快,几百次迭代可收敛 良好 中等
μ 太大(如 0.1) 可能不收敛 发散风险高 高
避坑指南: 我曾经在一个 ANC 耳机项目中把 μ 设成了 0.05,结果滤波器直接炸了——输出噪声比原始噪声还大 10 dB。后来才意识到,μ 的上限是 1/λ_max(输入信号自相关矩阵的最大特征值)。别凭感觉调,先算算特征值。

LMS 最大的优点是 计算量小——每次迭代只需要 O(N) 次乘加运算。在 DSP 或者低功耗 MCU 上跑起来毫无压力。但它的缺点也很明显:收敛速度对输入信号的功率非常敏感。如果输入信号忽大忽小,步长就不好选了。

4.2 NLMS 算法:给步长加个归一化

NLMS(归一化 LMS)就是来解决上面那个问题的。它把步长除以输入信号的功率,让更新步长自动适应信号的强弱变化。

// NLMS 算法核心更新公式
// 相比 LMS,多了一个归一化因子

e(n) = d(n) - w^T(n) * x(n);
// 归一化步长:μ / (||x(n)||² + δ)
// δ 是一个很小的正数,防止分母为零
w(n+1) = w(n) + (μ / (x^T(n)*x(n) + δ)) * e(n) * x(n);

你看,分母是输入向量的能量(L2 范数的平方)。当输入信号突然变大时,分母变大,步长自动缩小;信号变小时,步长自动放大。这样一来,收敛速度就稳定多了。

工程经验: 我个人习惯把 μ 设在 0.1 到 0.5 之间。δ 取 0.001 到 0.01 就够了,别太大,否则归一化就失效了。NLMS 是我在大多数降噪项目中的首选——它比 LMS 稳定,又比 RLS 省资源。

NLMS 的收敛速度比 LMS 快不少,尤其是在输入信号动态范围大的场景。比如在通话降噪中,说话声音大小变化很大,NLMS 能自动适应,不会因为突然的大声导致滤波器发散。

4.3 RLS 算法:用遗忘因子换速度

RLS(递归最小二乘)走的是另一条路。它不搞梯度下降,而是直接最小化从开始到现在所有误差的加权平方和。每次迭代都利用之前的信息,所以收敛速度极快。

// RLS 算法核心步骤(简化版)
// 遗忘因子 λ(通常 0.95 ~ 0.9995)
// 逆相关矩阵 P(n)

// 增益向量
k(n) = (P(n-1) * x(n)) / (λ + x^T(n) * P(n-1) * x(n));

// 先验误差
e(n) = d(n) - w^T(n-1) * x(n);

// 系数更新
w(n) = w(n-1) + k(n) * e(n);

// 逆相关矩阵更新
P(n) = (1/λ) * (P(n-1) - k(n) * x^T(n) * P(n-1));

RLS 的收敛速度通常比 LMS 快一个数量级。你想想看,LMS 可能需要 1000 次迭代才能收敛,RLS 可能 100 次就搞定了。这在跟踪快速变化的噪声时特别有用。

但代价也很明显:计算量是 O(N²)。N=64 时,RLS 每次迭代需要 4000 多次乘加,而 LMS 只要 64 次。在嵌入式系统上,这个差距是致命的。

对比项 LMS NLMS RLS
每次迭代计算量 O(N) O(N) O(N²)
收敛速度 慢 中等 快
对输入功率敏感度 高 低 低
稳态误差 中等 中等 低
数值稳定性 好 好 较差(需正则化)
适用硬件 MCU, DSP MCU, DSP ARM Cortex-A, FPGA
我的建议: 如果算力够,RLS 在非平稳噪声场景下效果最好。但如果你在做一个量产产品,NLMS 往往是更稳妥的选择——它够用、稳定、好调试。RLS 的数值问题(P 矩阵发散)在定点数平台上特别头疼,我吃过这个亏。

4.4 收敛速度与稳定性的博弈

这三个算法本质上都在做同一件事:在收敛速度和稳态误差之间找平衡。你想想看,步长越大收敛越快,但到了稳态之后,滤波器系数会在最优值附近来回晃,稳态误差就大。步长小了,稳态误差小,但收敛慢得像蜗牛。

RLS 之所以快,是因为它用了遗忘因子 λ。λ 越接近 1,算法记忆越长,收敛越慢但稳态误差越小;λ 越小(比如 0.95),算法能快速跟踪变化,但稳态误差会变大。

数值稳定性警告: RLS 的 P 矩阵在理论上是对称正定的,但在有限精度下很容易失去正定性。我曾经在 16 位定点 DSP 上跑 RLS,跑了 10 万次迭代后 P 矩阵变成了负定,滤波器直接崩溃。解决方案:定期重置 P 矩阵,或者用 QR-RLS 等数值更稳定的变体。

最后说一句:别迷信算法复杂度。我在一个主动降噪耳机项目里,一开始用 RLS 觉得高大上,结果功耗超标、延迟过大。后来换成 NLMS,把阶数从 128 降到 64,收敛速度虽然慢了点,但整体效果反而更好——因为延迟低了,系统稳定性提升了。

选算法,先看你的硬件能承受多少 MIPS,再看噪声是平稳还是突变,最后才决定用哪个。这个顺序别搞反了。