很多人第一次接触“递推最小二乘法”时脑子里冒出来的问题是最小二乘我熟线性回归嘛线性代数课上不知道解了多少遍为什么还搞一个“递推”版本尤其是做自适应滤波、系统辨识、在线参数估计的工程师迟早都会碰到RLS这个名字。其实RLS就是把批量最小二乘的求解过程改造成一条条数据流的迭代更新核心是三条递推式最难啃的也就是矩阵求逆引理那么一小块。下面直接围绕RLS公式的详细推导展开把“为什么这样递推、每一步在干什么”讲清楚顺带把初始化、调参与工程落地的经验一起交个底。这篇文章适合信号处理方向的学生、搞自适应算法的工程师以及所有需要在线更新模型而不是离线批量拟合的人。1. 递推最小二乘法到底在解决什么问题1.1 从批量最小二乘到在线递推先回到最基础的问题。假设我们要估计一个线性模型的权重向量 $w$每一时刻拿到输入向量 $u(i)$ 和期望输出 $d(i)$。批量最小二乘的做法是一次性收集 $n$ 组数据然后最小化误差平方和$$ J(w)\sum_{i1}^{n}\left[d(i)-w^{T}u(i)\right]^{2} $$把 $n$ 组输入排成矩阵 $U$期望值排成向量 $d$解就是熟知的法方程$$ \hat{w}(n)\left(U^{T}U\right)^{-1}U^{T}d $$这个写法很干净但工程上有个痛点数据是流式到达的每来一个新样本如果都重新组装矩阵、重新求逆计算量会越来越大而且旧数据未必还值得保留。系统的特性可能随时间缓慢变化越旧的数据越不该继续参与本次估计。这时候就需要一种“边到边算”的更新方式——RLS就是这个需求的产物。RLS的名字里“递推”两个字指的正是权重向量 $w(n)$ 可以由 $w(n-1)$ 加上某个修正量得到不重算历史数据。它的数学形式看起来复杂但思想其实和“记账”很像每次来一笔新账你只需要在余额上做一次增量更新不需要把过去所有账单重新加一遍。1.2 RLS能用在哪些场景RLS在工程里的出场频率非常高。凡是需要在线估计一个时变参数的线性模型基本都能看到它的身影。典型的应用包括自适应信道均衡通信接收端实时补偿信道失真权重必须跟随信道变化。系统辨识给未知系统输入激励信号在线估计系统的传递函数或脉冲响应系数。有源噪声控制用自适应滤波器生成反相信号抵消噪声要求算法快速收敛。自动控制中的在线参数估计控制器参数需要根据工况实时调整时用RLS估计模型参数。金融时间序列的在线预测用近期数据训练一个线性预测器跟踪市场状态变化。这些场景有一个共同特点数据非平稳模型不能一劳永逸。LMS最小均方算法也能做在线自适应但RLS的优势在收敛速度代价是更高的单步计算量。后面有一章会专门对比这两种算法先把RLS本身的推导啃下来。1.3 遗忘因子 $\lambda$ 的直觉RLS引入了一个关键参数 $\lambda$叫做遗忘因子取值范围通常在 $(0,1]$。它的作用是给历史样本的误差加上指数衰减的权$$ J(n)\sum_{i1}^{n}\lambda^{n-i}\left[d(i)-w^{T}u(i)\right]^{2} $$注意公式里的 $\lambda^{n-i}$$n$ 是当前时刻$i$ 是样本下标。当前样本的权重是 $\lambda^{0}1$越老的样本幂次越大、权重越小。$\lambda1$ 时所有历史样本权重一样退化成无限记忆的普通最小二乘$\lambda$ 越小旧样本被遗忘得越快算法跟踪变化的能力越强但受噪声影响也越大。很多人在推导公式前忽略了这个参数的意义导致后面初始化 $\lambda$ 时全靠蒙。我这里先挑明$\lambda$ 本质上是“时间常数”的离散版本。一个系数大约在 $1/(1-\lambda)$ 个样本后衰减到原始权重的 $1/e$ 左右。比如 $\lambda0.95$ 时有效记忆长度大约是20个样本$\lambda0.99$ 时大约是100个样本。这个直觉对于后面调参非常重要。2. RLS公式详细推导2.1 带遗忘因子的代价函数正式的RLS推导从加权代价函数出发。定义 $n$ 时刻的代价函数$$ J(n)\sum_{i1}^{n}\lambda^{n-i}e^{2}(i) $$其中瞬时误差$$ e(i)d(i)-w^{T}u(i) $$为了后面推导方便定义两个累加量$$ R(n)\sum_{i1}^{n}\lambda^{n-i}u(i)u^{T}(i) $$$$ r(n)\sum_{i1}^{n}\lambda^{n-i}u(i)d(i) $$你可以把 $R(n)$ 理解为“加权输入自相关矩阵”把 $r(n)$ 理解为“加权输入-期望互相关向量”。把 $J(n)$ 对 $w$ 求梯度并令其为零得到法方程$$ R(n)w(n)r(n) $$所以理论上最优解就是$$ w(n)R^{-1}(n)r(n) $$问题在于每来一个新样本$R(n)$ 变了如果直接求逆复杂度大概是 $O(N^{3})$其中 $N$ 是滤波器阶数。RLS的全部数学改造都是为了让这个求逆过程变成低成本的递推更新。2.2 加权法方程的递推形式先看 $R(n)$ 和 $r(n)$ 的递推关系。根据定义$$ R(n)\sum_{i1}^{n}\lambda^{n-i}u(i)u^{T}(i) \lambda\sum_{i1}^{n-1}\lambda^{n-1-i}u(i)u^{T}(i)u(n)u^{T}(n) $$于是得到$$ R(n)\lambda R(n-1)u(n)u^{T}(n) $$同理$$ r(n)\lambda r(n-1)u(n)d(n) $$这两个递推式本身很简单就是“旧值整体衰减 $\lambda$再加上当前样本贡献”。麻烦的是下一步已知 $R(n-1)$ 和 $r(n-1)$如何用它们快速得到 $w(n)$直接的想法是$$ w(n)R^{-1}(n)r(n) $$但需要解 $R^{-1}(n)$。如果能让 $P(n)R^{-1}(n)$ 也满足一个递推式整个问题就顺了。这就要用到矩阵求逆引理。2.3 矩阵求逆引理递推的数学支柱矩阵求逆引理也叫 Sherman-Morrison-Woodbury 公式它说的是$$ (ABCD)^{-1}A^{-1}-A^{-1}B\left(C^{-1}DA^{-1}B\right)^{-1}DA^{-1} $$看起来复杂但它的作用很直观已知一个矩阵 $A$ 的逆如果它加上一个低秩的扰动 $BCD$新矩阵的逆可以用 $A^{-1}$ 和几个矩阵乘除得到不需要重新做高斯消元或显式求逆。在RLS里我们要处理的是$$ R(n)\lambda R(n-1)u(n)u^{T}(n) $$对应引理中的$$ A\lambda R(n-1),\quad Bu(n),\quad C1,\quad Du^{T}(n) $$代入矩阵求逆引理令 $P(n)R^{-1}(n)$$P(n-1)R^{-1}(n-1)$$$ P(n)\frac{1}{\lambda}P(n-1)-\frac{\frac{1}{\lambda}P(n-1)u(n)u^{T}(n)\frac{1}{\lambda}P(n-1)}{1\frac{1}{\lambda}u^{T}(n)P(n-1)u(n)} $$整理分母得到$$ P(n)\frac{1}{\lambda}P(n-1)-\frac{P(n-1)u(n)u^{T}(n)P(n-1)}{\lambdau^{T}(n)P(n-1)u(n)} $$这个式子里分母 $\lambdau^{T}(n)P(n-1)u(n)$ 是一个标量整个第二项是一个秩为1的矩阵修正。它的复杂度是 $O(N^{2})$比直接求逆的 $O(N^{3})$ 低一个量级这正是RLS递推的核心优势。2.4 三个核心递推式的完整推演有了 $P(n)$ 的递推式剩下的推演就顺理成章了。先定义增益向量$$ K(n)\frac{P(n-1)u(n)}{\lambdau^{T}(n)P(n-1)u(n)} $$那么 $P(n)$ 可以写成更整洁的形式$$ P(n)\frac{1}{\lambda}\left[I-K(n)u^{T}(n)\right]P(n-1) $$这个形式在代码里非常常见。它等价于“先用增益向量修正再整体缩放”。接下来推导权重更新。由法方程 $R(n)w(n)r(n)$$$ R(n)w(n)\lambda r(n-1)u(n)d(n) $$另一方面用 $R(n)$ 的递推式去乘 $w(n-1)$$$ R(n)w(n-1)\left[\lambda R(n-1)u(n)u^{T}(n)\right]w(n-1) \lambda r(n-1)u(n)u^{T}(n)w(n-1) $$两式相减$$ R(n)\left[w(n)-w(n-1)\right]u(n)\left[d(n)-u^{T}(n)w(n-1)\right] $$令先验误差为$$ e(n)d(n)-u^{T}(n)w(n-1) $$于是$$ w(n)-w(n-1)R^{-1}(n)u(n)e(n)P(n)u(n)e(n) $$最后还需要证明 $P(n)u(n)K(n)$。从 $P(n)$ 的递推式左乘 $u(n)$$$ P(n)u(n)\frac{1}{\lambda}P(n-1)u(n)-\frac{1}{\lambda}K(n)u^{T}(n)P(n-1)u(n) $$令 $\alphau^{T}(n)P(n-1)u(n)$则$$ P(n)u(n)\frac{1}{\lambda}P(n-1)u(n)-\frac{1}{\lambda}K(n)\alpha $$注意 $K(n)\frac{P(n-1)u(n)}{\lambda\alpha}$代入后$$ P(n)u(n)\frac{1}{\lambda}P(n-1)u(n)-\frac{\alpha}{\lambda}\cdot\frac{P(n-1)u(n)}{\lambda\alpha} $$$$ \frac{1}{\lambda}P(n-1)u(n)\left(1-\frac{\alpha}{\lambda\alpha}\right) \frac{1}{\lambda}P(n-1)u(n)\cdot\frac{\lambda}{\lambda\alpha} T(n)u(n) $$等一下这里要小心符号。重新写一下$$ P(n)u(n)\frac{1}{\lambda}P(n-1)u(n)\left(1-\frac{\alpha}{\lambda\alpha}\right) $$括号里 $1-\frac{\alpha}{\lambda\alpha}\frac{\lambda}{\lambda\alpha}$所以$$ P(n)u(n)\frac{1}{\lambda}P(n-1)u(n)\cdot\frac{\lambda}{\lambda\alpha} \frac{P(n-1)u(n)}{\lambda\alpha}K(n) $$所以结论成立。这样权重更新就得到经典形式$$ w(n)w(n-1)K(n)e(n) $$完整的三条核心递推式汇总如下$$ e(n)d(n)-w^{T}(n-1)u(n) $$$$ K(n)\frac{P(n-1)u(n)}{\lambdau^{T}(n)P(n-1)u(n)} $$$$ w(n)w(n-1)K(n)e(n) $$$$ P(n)\frac{1}{\lambda}\left[I-K(n)u^{T}(n)\right]P(n-1) $$这个顺序就是工程实现RLS时每一轮迭代的执行顺序先算误差再算增益然后更新权重最后更新协方差矩阵。很多资料把 $P$ 更新放在权重前面本质上等价但按顺序记更好理解。2.5 先验误差与后验误差的关系RLS推导里还有一个容易被忽略的细节$e(n)$ 是用旧权重 $w(n-1)$ 计算出来的叫先验误差更新后的权重 $w(n)$ 对应的误差叫后验误差$$ \varepsilon(n)d(n)-w^{T}(n)u(n) $$代入 $w(n)w(n-1)K(n)e(n)$$$ \varepsilon(n)e(n)-e(n)u^{T}(n)K(n)e(n)\left[1-u^{T}(n)K(n)\right] $$而 $K(n)P(n)u(n)$所以$$ u^{T}(n)K(n)u^{T}(n)P(n)u(n) $$进一步可以得到$$ \varepsilon(n)e(n)\cdot\frac{\lambda}{\lambdau^{T}(n)P(n-1)u(n)} $$这个关系说明后验误差总是小于先验误差的绝对值因为分母中 $\lambdau^{T}(n)P(n-1)u(n)\lambda$。换句话说RLS每步更新都会利用新样本把预测误差降下来这也从误差层面解释了为什么RLS收敛快。这个恒等式在推导更高级的RLS变形时经常用到比如Exponentially Weighted RLS的稳定形式证明。3. 参数含义、工程初始化与可复现实操3.1 P(0)、λ、输入尺度到底怎么定公式推完了但直接上代码的人通常会懵在第一行$P(0)$ 到底设成什么$P(n)$ 是输入自相关矩阵逆矩阵的估计初始时刻没有数据最常用的做法是设为单位阵乘以一个常数$$ P(0)\delta I $$$\delta$ 的取值有讲究。如果 $\delta$ 很小比如 $10^{-6}$相当于初始时刻“假装”输入能量很大、协方差矩阵很满算法会非常不信任初始权重 $w(0)$ 的猜测前几步修正幅度会很大如果 $\delta$ 很大比如 $100$意味着初始协方差很大模型“有把握说不知道”前几步修正反而更大这里需要掰扯清楚。很多教材直接给“$\delta$取小正数”但没解释为什么。实际经验是$\delta$ 的选择要参照输入信号的功率。如果输入信号方差为 $\sigma_u^2$那么 $R$ 的初始估计大约应该和 $N$ 倍方差一个量级。一个稳妥的工程做法是$$ \delta \frac{1}{\sigma_u^{2}\cdot N} $$或者干脆观测一段数据后取 $R(0)$ 的迹作为估计。否则 $\delta$ 一旦比实际信号能量小太多$P$ 的初值会偏大早期增益 $K$ 异常大权重发生“假性剧震”看起来像发散实际只是初始化不当。$\lambda$ 的取值同样取决于应用。平稳环境中$\lambda$ 尽量接近1比如 $0.995\sim1$稳态误差小非平稳环境中需要跟踪参数变化$\lambda$ 要调低一些比如 $0.95\sim0.98$。$\lambda$ 越小算法越“神经质”跟随快但噪声放大$\lambda$ 越大算法越“迟钝”估计平稳平滑但跟不上突变。这个权衡没有万能解只能根据实际信号时间尺度试。3.2 一个可复现的在线系统辨识示例说了这么多不如跑一个最简单的例子看效果。假设有一个未知的4阶FIR系统真实系数为$$ w_{\text{true}}[0.5,,-1.2,,0.8,,0.3] $$我们给系统输入高斯白噪声观测值叠加少量噪声用RLS在线估计系统系数。用Python实现核心更新逻辑代码非常简洁import numpy as np def rls_update(w, P, x, d, lam0.98): alpha x P x K (P x) / (lam alpha) e d - x w w w K * e P (P - np.outer(K, x) P) / lam return w, P, e np.random.seed(42) N 4 w_true np.array([0.5, -1.2, 0.8, 0.3]) w np.zeros(N) P np.eye(N) * 0.1 lam 0.98 for n in range(2000): x np.random.randn(N) d w_true x 0.01 * np.random.randn() w, P, e rls_update(w, P, x, d, lam) if n in [0, 10, 50, 200, 1000]: print(fstep {n:5d}, w {np.round(w, 4)})运行之后你会看到第一步由于 $P(0)0.1I$增益不算太大权重只挪动一点大约10步左右四个系数已经很有轮廓到200步基本贴近真实值之后一直在真值附近小幅波动不再显著偏离。这个例子还暴露了一个容易被忽略的点输入信号必须是满秩激励。如果输入老是同一个值$R(n)$ 是奇异矩阵或者条件数极大RLS的表现会非常差。实际做系统辨识时一旦发现不收敛优先检查激励信号是否持续存在而不是急着调 $\lambda$。3.3 收敛速度与计算复杂度RLS为什么收敛快核心在于它用了输入的二阶统计量信息。增益向量 $K(n)$ 里的 $P(n-1)$ 本质上是对输入协方差的逆矩阵估计相当于对不同方向的自适应步长做了归一化处理。LMS只有单个步长参数 $\mu$输入信号特征值散布越大各方向收敛速度差异就越大而RLS相当于对输入做了“白化”各个方向收敛速度接近所以整体收敛快很多。代价是计算量。RLS每一步复杂度是 $O(N^{2})$主要来自 $P u$ 这个矩阵向量乘以及 $K u^{T}P$ 这个外积更新。LMS只需要 $O(N)$。在 $N$ 几百以上、采样率又很高的场景RLS的实时性压力会很大。这也是为什么很多工业场景中简单系统用LMS复杂系统才上RLS。选择不只取决于收敛要求还要看硬件算力。4. 使用中的常见问题、坑位与改进方向4.1 常见问题排查速查表接触RLS这几年周围同事问得最多的问题几乎都集中在这几类。我整理了一张速查表基本覆盖绝大多数现场故障现象可能原因排查与建议权重早期剧烈震荡甚至发散$P(0)$ 与输入能量不匹配检查输入信号方差调整 $\delta$或先用小批量数据初始化 $R(0),r(0)$收敛太慢、跟踪不上变化$\lambda$ 太接近1逐步降低 $\lambda$观察误差均方值变化稳态误差大、系数抖动明显$\lambda$ 太小适当增大 $\lambda$或用可变遗忘因子策略权重重现突然跳变输入信号出现共线性或短暂断激励检查激励质量考虑加入正则项或改用鲁棒版本数值结果出现NaN或Inf$P$ 矩阵失去正定性改用平方根RLS或QR-RLS检查是否有过大数值输入系统参数突变后恢复慢固定 $\lambda$ 导致记忆过长考虑误差门控的变遗忘因子机制4.2 数值稳定性RLS最容易被忽视的弱点标准RLS在理论上是漂亮的但在有限精度浮点运算下$P(n)$ 可能失去对称正定性。$P$ 一旦不再是对称正定增益方向就错了权重更新就会发散。这个问题在定点DSP实现上尤其严重因为量化误差会不断累积。工程上常用的改进思路有几条。第一条是平方根RLSSquare-Root RLS直接递推 $P$ 的Cholesky因子或QR因子不显式计算 $P$ 本身数值稳定性好很多。第二条是加正则化项在 $P$ 更新后强制对称化比如 $P(PP^{T})/2$虽然不彻底但能延后数值恶化。第三条是定期复位或监测 $P$ 的特征值发现异常就重建。如果你的系统需要7×24小时连续运行强烈建议不要裸用标准RLS至少要做对称化处理。还有一个容易踩的坑输入量级跨度太大时$u^{T}Pu$ 这个标量可能溢出。比如输入信号幅值达到 $10^{3}$$P$ 中某些元素又偏大中间结果很容易爆。解决办法是先对输入做归一化或者用对数增益的形式重写更新式。4.3 RLS与LMS选型对比很多新手会在RLS和LMS之间犹豫。两者都做在线自适应但思路完全不同。LMS基于随机梯度下降每次只沿瞬时误差梯度的反方向走一小步RLS基于最小二乘的解直接利用输入二阶统计量做一步最优修正。对比维度LMSRLS单步复杂度$O(N)$$O(N^{2})$收敛速度慢受输入特征值分布影响大快基本无特征值散布敏感问题稳态失调通常偏大可调 $\lambda$ 做到很小跟踪非平稳能力中等强但需要调 $\lambda$数值敏感性低高需维护 $P$ 正定性实现复杂度低高实际选型我给三条建议如果阶数很低且输入接近白噪声LMS完全够用没必要上RLS如果阶数高、输入相关性大、又要求快速收敛上RLS但优先考虑加固数值稳定性的改进版本如果硬件资源紧张、需要极大规模并行LMS类算法仍然是现实选择。4.4 工程落地心得最后分享一个这几年实打实攒下来的经验RLS调参的第一要务不是调 $\lambda$而是先调 $P(0)$。很多人一看到不收敛就猛调 $\lambda$把值越调越小结果系统越来越抖最后以为是算法不行。其实大多数前期发散问题都出在初始化不合理。先花时间搞清楚输入信号的功率、阶数 $N$把 $\delta$ 设到合理范围再动 $\lambda$问题往往解决一大半。另外一个心得是永远别在真实系统上直接跑标准的、没有任何防护的RLS。最少加三样东西输入限幅、$P$ 对称化、以及误差超限保护。这三行代码成本极低却能避免绝大多数灾难性故障。很多论文里RLS效果惊艳是因为仿真数据干净拿到现场噪声、断流、脉冲干扰全来了不加保护等于裸奔。懂了这些RLS对你来说就不再是一堆黑盒子公式而是一个可以按部就班上手的顺手工具。真要写代码时把三条核心递推式按顺序摆好再处理好 $P(0)$ 和数值细节整个系统就能稳定跑了。