尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

RLS递推最小二乘滤波:原理、参数整定与嵌入式C移植实战

RLS递推最小二乘滤波:原理、参数整定与嵌入式C移植实战 简介面向信号处理、控制工程与通信系统等需要在线参数估计的学习者提供基于递归最小二乘RLS算法的自适应滤波MATLAB实现可用于非平稳信号滤波与动态系统建模相较LMS拥有更快收敛与更高精度。压缩包仅40KB共含2个文件RLS.m为核心算法脚本完成权重迭代更新、遗忘因子调节及误差计算RLS.fig为可视化图形界面便于调整参数、观察滤波效果。目前已有239人学习下载适合正在学习自适应滤波理论、希望快速获得可运行代码的学生或工程师直接参考。读者下载后可运行脚本对照公式理解RLS更新过程中预测向量、误差项与遗忘因子的作用也可通过界面文件修改参数对比不同遗忘因子下的收敛速度与稳态误差为后续系统辨识、噪声抵消等应用提供可复用的代码框架。1. 从 RLS.zip 开始RLS 滤波解决的是自适应估计问题RLS.zip 解压后通常是一两个 .c、.m 或 .py 文件函数名里写着 rls 滤波。直接搬进工程大概率会撞上输出发散、权系数震荡、结果和卡尔曼滤波拉不开差距这类问题。RLS递推最小二乘滤波算法属于自适应滤波家族解决的不是把毛刺拉平而是在线估计一个线性模型系数每来一个新样本就修正一次权值。它比 LMS 收敛快一个数量级代价是每步 O(N²) 的矩阵运算和更苛刻的数值稳定性。遗忘因子、初始协方差矩阵、更新方程里那一次除法比复制代码重要得多。这套思路适合用过 LMS 或滑动平均滤波、觉得收敛太慢想换 RLS 的工程师也覆盖从仿真到嵌入式 C 移植的完整路径。2. RLS 滤波的递推原理与最小化 Python 实现2.1 最小二乘目标函数与递推更新公式批量最小二乘的做法是给一组输入向量 u(i) 和期望值 d(i)求权向量 w 使误差平方和最小标准解是 w (UᵀU)⁻¹Uᵀd。问题在于矩阵求逆每次都要重算不适合逐样本在线更新。RLS 把目标函数改成带遗忘因子的形式J(n) Σ(i0..n) λ^(n-i) e²(i)λ 是 0 到 1 之间的遗忘因子越早的误差权重越小。记 R(n) Σ λ^(n-i) u(i)uᵀ(i)P(n) R⁻¹(n)用矩阵求逆引理可以得到免显式求逆的递推式。每来一个样本先算增益向量k(n) P(n-1)u(n) / (λ uᵀ(n)P(n-1)u(n))再更新权系数和协方差矩阵w(n) w(n-1) k(n)e(n) P(n) (P(n-1) - k(n)uᵀ(n)P(n-1)) / λ其中 e(n) d(n) - wᵀ(n-1)u(n) 是先验误差。整个递推每步 O(N²)N 是滤波器阶数LMS 每步只有 O(N)这就是 RLS 收敛快但计算量大的根本原因。2.2 RLS 滤波的 3 个核心参数及其作用RLS 滤波可调参数不多但每个都直接决定行为。实际调试时我按下面表格设初值再根据信号特征微调参数含义常见取值影响λ遗忘因子0.980.999越接近 1 跟踪越慢、稳态误差越小越小对突变响应越快、噪声放大越明显δ正则化初始协方差倒数0.0110控制 P(0) 大小防止启动阶段增益过大导致权值乱跳N阶数回归向量长度464阶数不足时模型失配过高时计算量与稳态波动同步上升初始协方差取 P(0) I/δ。δ 取 1 表示初始置信度中等δ 很小相当于初始 P 很大启动阶段权值跳动明显。λ 没有万能值只能结合信号变化速度来整定方法放到第 4 章展开。2.3 Python 最小实现rls_filter 函数逐行拆解import numpy as np def rls_filter(x, d, order4, lam0.99, delta1.0): 标准 RLS 滤波逐样本在线更新。 x: 参考输入信号 d: 期望信号 order: 滤波器阶数 lam: 遗忘因子 delta: 正则化参数P(0) I / delta n len(x) w np.zeros(order) # 权系数向量 P np.eye(order) / delta # 初始协方差矩阵 y np.zeros(n) # 滤波器输出 e np.zeros(n) # 先验误差 for i in range(order, n): u x[i - order:i 1][::-1] # 取最新 order1 个点并反序 Pi P u denom lam u Pi k Pi / denom # 增益向量 k(n) y[i] w u # 输出 e[i] d[i] - y[i] # 期望与输出之差 w w k * e[i] # 权系数更新 P (P - np.outer(k, u P)) / lam # 协方差递推 return y, e, w这段代码与上一节公式一一对应。u 取x[i-order:i1][::-1]是为了让最新样本排在向量最前符合数字滤波器的卷积习惯顺序取窗会让权系数和真实滤波器系数反转辨识结果对不上。denom 是标量除法不涉及矩阵求逆这是 RLS 的核心。P 的更新先减后除浮点运算下 P 会缓慢失去对称性正式工程里通常每几十步强制对称化一次P (P P.T) / 2这一行能避免大量隐蔽的数值问题。3. 用 RLS 滤波跑通噪声对消与系统辨识3.1 噪声对消实验参考信号与期望信号怎么接RLS 滤波最典型的场景是自适应噪声对消。一个麦克风拾取语音加干扰另一个参考传感器拾取与干扰相关、与语音无关的噪声。参考噪声作为 x主麦克风信号作为 dRLS 估计的是干扰从参考点到主麦克风之间的传递路径输出 y 拟合干扰分量误差 e 就是滤除干扰后的信号。下面这段模拟完整过程import numpy as np rng np.random.default_rng(42) n 4000 t np.arange(n) / 100.0 clean np.sin(2 * np.pi * 3 * t) # 待保留的信号 ref_noise rng.standard_normal(n) # 参考噪声 path np.array([0.3, -0.5, 0.2, -0.1]) # 干扰传播路径 interf np.convolve(ref_noise, path)[:n] # 与参考相关的干扰 d clean interf # 主通道期望信号 y, e, w rls_filter(ref_noise, d, order4, lam0.995, delta1.0) snr_in 10 * np.log10(np.var(clean) / np.var(interf)) snr_out 10 * np.log10(np.var(clean) / np.var(e - clean)) print(f输入SNR{snr_in:.1f}dB 输出SNR{snr_out:.1f}dB)这里的关键是参考信号与干扰必须高度相关且与有用信号不相关。参考通道一旦混进语音成分RLS 会把有用信号一起消掉输出 SNR 反而变差。工程上遇到“滤波结果发闷”时先检查参考信号怎么接的再调 λ多数问题不在算法而在通道接法。3.2 系统辨识实验权系数收敛到真实冲激响应第二种常见用法是系统辨识。给未知系统输入白噪声把系统输出作为 d输入作为 x收敛后 w 就是系统冲激响应的估计。与批处理最小二乘不同RLS 可以边采数据边输出估计适合信道估计、回声消除这类在线场景。判断收敛的方法很直接把权向量轨迹画出来看是否逼近真实系数。rng np.random.default_rng(42) true_w np.array([0.5, -0.3, 0.2]) # 待辨识的真实系统 x rng.standard_normal(2000) d np.convolve(x, true_w)[:2000] 0.01 * rng.standard_normal(2000) y, e, w rls_filter(x, d, order3, lam0.99, delta1.0) print(估计系数:, np.round(w, 3))对 3 阶系统收敛后 w 会稳定在 [0.5, -0.3, 0.2] 附近误差 e 的功率降到接近加性噪声功率。阶数低于真实系统时残差明显变大阶数给高时多余权值不会完全归零而是保留小幅波动。选阶数的原则是宁高勿低同时接受多一点计算量。3.3 和滑动窗口滤波、卡尔曼滤波相比 RLS 赢在哪RLS 滤波经常被拿来和滑动窗口滤波、滑动平均滤波、卡尔曼滤波比较。滑动平均和滑动窗口滤波本质上是固定系数低通适合 ADC 采样去毛刺这类频率分离明确的场景不需要参考信号但应对不了相关性随时间变化的干扰。卡尔曼滤波是状态空间方法需要过程噪声 Q 和观测噪声 R模型准确时误差最优RLS 可以看作状态向量恒定时卡尔曼滤波的简化版少调两个噪声协方差矩阵代价是没有状态预测能力。方法每步计算量需要模型典型场景滑动平均滤波O(N)无ADC 平滑、毛刺抑制LMS 自适应滤波O(N)参考信号收敛要求不高的初版方案RLS 滤波O(N²)参考信号回声消除、信道估计、振动对消卡尔曼滤波O(N²)O(N³)状态转移与噪声统计组合导航、目标跟踪选型判断标准我一般这么定干扰和有用信号频带重叠但存在相关参考源用 RLS没有参考源、只做平滑滑动平均更划算系统有明确动态方程用卡尔曼滤波。互补滤波在姿态解算里融合加速度计和陀螺仪两个异源信号与 RLS 没有直接替代关系。4. RLS 滤波参数整定遗忘因子、发散处置与嵌入式移植4.1 遗忘因子 λ 的整定跟踪速度与稳态波动的权衡λ 是 RLS 滤波里唯一需要反复试的参数。λ 0.99 时算法大约记住前 1/(1-λ) ≈ 100 个样本λ 0.999 时约 1000 个样本。有效记忆越长稳态误差越小但对系统突变响应越慢。要直观验证可以在数据中间点突然改变真实权系数观察权向量重新收敛需要多少步λ 大时要几百步λ 小时几十步追上但稳态波动也更大。实际整定流程我一般走三步。先固定 order 和 delta把 λ 从 0.999 逐步往 0.95 试观察误差 e 的均方值出现明显噪声放大就回退一档再叠加一次人为跳变确认重新收敛时长满足系统响应要求最后用第 5 章的 Monte Carlo 方法确认稳态失调量可接受。不要同时改两个参数RLS 的响应是参数耦合的一次只动一个才能定位问题。提示改动输入信号幅值后先做归一化再调 λ否则两个变量互相干扰调出来的参数换一段数据就失效。4.2 P 矩阵发散、数值下溢与正则化手段RLS 滤波最典型的故障是 P 矩阵发散。症状是前几十步正常之后权系数突然跳变、误差震荡。原因通常是输入幅值过小导致 P 数值膨胀或者 P 在递推中失去对称正定性。处置手段按优先级排列先把输入归一化让 x 的方差落在 0.11 之间P 的更新对尺度非常敏感每步递推后执行P (P P.T) / 2强制对称仍然发散就改用平方根 RLS递推里更新 P 的 Cholesky 因子本质等价但对舍入误差不敏感。P 出现负对角元是数值退化的明确信号应该当作错误标志处理。正则化 δ 的本质是约束初始协方差。δ 取 0.01 相当于 P(0) 100I前期权值调整幅度大适合信噪比低的启动阶段δ 取 10 相当于 P(0) 0.1I收敛慢但稳定。固定信号场景下 δ 在 1 附近通常不需要大改。下面表格是现场排错时对照用的现象原因处置权系数突然跳变P 矩阵失去正定性强制对称化 输入归一化启动阶段输出过大δ 太小P(0) 太大δ 提到 110收敛后噪声偏大λ 太小或阶数过高λ 回退到 0.99 以上降低阶数突变跟踪跟不上λ 过于接近 1λ 调到 0.950.984.3 C 语言移植固定数组与单步更新函数到嵌入式端RLS 滤波的移植重点是去掉动态内存、把矩阵运算摊平。下面阶数固定为 4 的单步函数可以直接放进定时中断按采样率逐点调用#define RLS_ORDER 4 typedef struct { float lam; float w[RLS_ORDER]; // 权系数 float P[RLS_ORDER][RLS_ORDER]; // 协方差矩阵 float buf[RLS_ORDER]; // 窗缓存buf[0] 为最新样本 } rls_t; float rls_step(rls_t *rls, float x, float d) { int i, j; float u[RLS_ORDER], k[RLS_ORDER], Pu[RLS_ORDER]; float denom, y, e; for (i RLS_ORDER - 1; i 0; i--) // 窗口右移腾出最新位 rls-buf[i] rls-buf[i - 1]; rls-buf[0] x; for (i 0; i RLS_ORDER; i) u[i] rls-buf[i]; for (i 0; i RLS_ORDER; i) { // Pu P * u float s 0.0f; for (j 0; j RLS_ORDER; j) s rls-P[i][j] * u[j]; Pu[i] s; } denom rls-lam; // 标量分母 for (i 0; i RLS_ORDER; i) denom u[i] * Pu[i]; for (i 0; i RLS_ORDER; i) // 增益向量 k k[i] Pu[i] / denom; y 0.0f; for (i 0; i RLS_ORDER; i) y rls-w[i] * u[i]; e d - y; // 先验误差 for (i 0; i RLS_ORDER; i) // 权系数更新 rls-w[i] k[i] * e; for (i 0; i RLS_ORDER; i) // 协方差递推 for (j 0; j RLS_ORDER; j) rls-P[i][j] (rls-P[i][j] - k[i] * Pu[j]) / rls-lam; return e; }这段代码把协方差更新展开成一维循环Pu 复用了两次计算结果避免重复乘算。和单片机低通滤波里用左移右移代替乘除的做法不同RLS 的分母除法没法省float 精度在连续运行数万步后误差会累积资源允许时建议 P 用 doublew 和 u 用 float。与 MCU 上常见的“C 语言 ADC 值滤波函数”相比RLS 的接口多了参考输入和期望输入两个参数移植后最常见的错误是通道接反参考信号接成被滤波信号本身RLS 就退化成一个意义不大的预测器。5. 用 Monte Carlo 数据验证 RLS 滤波的收敛与跟踪5.1 多次独立实验的误差均方与失调量单次运行看到权系数“差不多收敛”不足以证明滤波器可靠RLS 单次实现的方差不小。常见做法是跑 50 次独立实验每次重新生成输入和噪声统计误差功率的平均trials 50 mses np.zeros(trials) for t in range(trials): x rng.standard_normal(2000) d np.convolve(x, true_w)[:2000] 0.01 * rng.standard_normal(2000) y, e, w rls_filter(x, d, order3, lam0.99, delta1.0) mses[t] np.mean(e[1000:] ** 2) # 只统计收敛后的后 1000 点 misadjustment np.mean(mses) / 0.0001 # 除以噪声功率 0.01^2 print(f失调量 ≈ {misadjustment:.2f})失调量是稳态额外误差与最小误差之比RLS 在 λ 0.99 时通常小于 0.1同样数据长度下 LMS 很难达到这个水平。统计时前 1000 点属于收敛期必须从均值里剔除否则结果会被启动阶段拉高得出滤波器“性能差”的错误结论。5.2 阶跃突变下的跟踪验证在线滤波场景里最重要的验证项是跟踪能力在数据中点把真实权系数乘以 -1观察误差均方是否出现一个高峰后又回落。回落时间大约等于有效记忆长度 1/(1-λ)如果超过系统允许的响应时间说明 λ 偏大需要回到第 4 章重新整定。把 RLS 的稳态误差和卡尔曼滤波放在同一组数据上对比是很好的交叉验证卡尔曼在状态模型准确时给出理论最优结果RLS 若明显差于卡尔曼多半是 λ 或 order 设置不合理而不是算法本身的问题。验证通过后再把第 4 章的 C 代码移植到目标板用同一份数据回放测试对比嵌入式端和 Python 端的误差曲线确认字节级一致后这套 RLS 滤波才算真正落地。本文还有配套的精品资源点击获取
返回列表