简介:面向信号去噪与状态估计需求,该资源提供基于变分贝叶斯卡尔曼滤波器(VBKF)的Matlab实现方案,适合自动化、电子信息等专业本科及硕士阶段教研学习,也适用于滤波器算法对比与实验验证。压缩包共8个文件,其中4个.m源码文件涵盖变分贝叶斯卡尔曼滤波主程序、标准卡尔曼滤波对比程序及测试脚本,可直接运行复现;3个.png图片为运行结果图和仿真效果展示,便于直观检查滤波性能;1个.txt说明文件对代码结构和使用方式作简要提示,整体包体仅511KB,轻量易用。已有263人学习下载,说明该方案具有一定参考价值。通过阅读代码和运行示例,读者可快速理解变分贝叶斯卡尔曼滤波在非高斯噪声或时变噪声场景下的去噪原理,并基于现有工程脚本扩展应用到自己的信号处理任务中。
1. 变分贝叶斯卡尔曼滤波器:信号去噪的新思路
在做信号去噪时,大多数工程师的第一反应是平滑滤波、小波阈值或经典卡尔曼滤波。但有个场景会让这些方法集体失效:过程噪声和观测噪声的统计特性随时间缓慢变化,而真实信号又往往是一段带趋势的随机序列。固定噪声参数的卡尔曼滤波器一旦遇到“噪声变了”的情况,要么大幅滞后,要么滤波结果充满毛刺。变分贝叶斯卡尔曼滤波器(VBKF)解决的就是这个问题——它在标准卡尔曼框架内引入变分贝叶斯推断,在递归滤波的同时在线估计噪声协方差矩阵,不需要外部训练数据,也不要求噪声先验精确已知。对处理非平稳信号、传感器漂移、目标跟踪等场景,VBKF 是比自适应滤波更稳的替代方案。本文将用 MATLAB 代码把整套算法拉通,从原理到参数调整再到验证方法,适合有卡尔曼滤波基础但想进一步处理时变噪声的工程师阅读。
2. 从卡尔曼滤波到 VBKF:固定噪声方差为什么不够用
2.1 卡尔曼滤波的五大假设与失效场景
标准卡尔曼滤波(KF)的推导中有五个核心假设:状态转移矩阵已知、观测矩阵已知、过程噪声和观测噪声均为零均值高斯白噪声、两者方差已知、初始状态均值和协方差已知。前两条在多数工程系统中可以满足,但第四条约在是最大的隐患。实际采集的信号中,传感器受温度影响会缓慢漂移,测量电路增益变化会改变噪声幅值,甚至目标本身运动模式变化会带来过程噪声的起伏。一旦这些统计特性改变,固定噪声参数的 KF 会表现出两种典型症状:如果过程噪声设置偏小,滤波输出过度信任状态预测,造成明显的相位滞后;如果观测噪声设置偏小,滤波器过度信任观测值,去噪后输出依然包含大量高频毛刺。
从数学上看,KF 的增益矩阵计算依赖于两个噪声协方差矩阵的比例。比例一旦失真,滤波结果就不是最优估计,而是“一个带偏的最小方差解”。这时最直接的做法是引入自适应机制,让滤波器自己调整噪声参数。
2.2 变分贝叶斯推断如何嵌入滤波框架
变分贝叶斯(Variational Bayes)的核心思想是用一个简化的分布 q(θ) 去近似真实后验 p(θ|x),通过最小化二者之间的 KL 散度来获得近似解。在卡尔曼滤波的框架里,被估计的“额外参数”是观测噪声协方差 R 和过程噪声协方差 Q。VBKF 的做法并不复杂:在每一时刻的滤波更新中,将联合后验 p(x_k, R_k, Q_k | y_1:k) 近似为 q(x_k) q(R_k) q(Q_k),然后通过坐标上升法迭代求解。由于卡尔曼滤波本身给出状态的后验形式是高斯分布,而逆 Wishart 分布是高斯分布的共轭先验,这使 R 和 Q 的后验近似也落在逆 Wishart 分布族里,迭代公式可以用解析形式直接推导出来。
实际中并不需要对完整的联合后验都做推断——许多实现只在线估计观测噪声 R,过程噪声 Q 仍保留为预设值。原因在于过程噪声往往与系统模型无关,可以由用户根据物理模型的经验设定;而观测噪声则受环境干扰变化剧烈,是自适应最需要补偿的项。VBKF 的典型做法是给 R_k 设定一个逆 Wishart 先验,先验的均值由上一时刻的估计值确定,然后通过固定点迭代更新。
2.3 VBKF 单步迭代的核心更新式
设状态方程 x_k = F x_{k-1} + w_k,观测方程 y_k = H x_k + v_k。在标准滤波的预测步完成后,VBKF 进入一个可迭代的更新步。以估计观测噪声为例,其迭代流程为:
- 初始化 R_k 的逆 Wishart 尺度矩阵为上一时刻估计值,自由度参数 rho_k = rho_{k-1} + 1。
- 重复以下两步直至收敛或达到最大迭代次数:
- 使用当前的 R_k 估计值计算卡尔曼增益并更新状态均值与协方差;
- 利用状态后验的预测残差重新估计 R_k 的逆尺度矩阵。
其中第 2 步的新息协方差 S_k = H P_k H^T + R_k,残差项用于修正 R 的估计。整个过程与期望最大化相似,但这里是在线递归形式。
下面给出描述 VBKF 单步逻辑的伪码,便于理解后续 MATLAB 代码结构:
输入: 状态预测 x_p, P_p, 观测 y_k, 上一时刻噪声估计 invW_R, rho 输出: 更新后的状态 x_u, P_u, 噪声估计 invW_R, rho 初始化: R = invW_R / (rho - d - 1) m = 1 循环 (m <= max_iter): S = H * P_p * H^T + R K = P_p * H^T * inv(S) x_u = x_p + K * (y_k - H * x_p) P_u = (I - K * H) * P_p 计算新息误差 e = y_k - H * x_u invW_R = invW_R0 + e * e^T + H * P_u * H^T R = invW_R / (rho - d - 1) m = m + 1这个循环中的核心变量是逆 Wishart 分布的逆尺度矩阵 invW_R。它在迭代过程中累加残差信息,随时间的递推则反映噪声统计的缓慢时变。rho 参数控制忘记旧信息的速度,类似滑动窗口的长度。
3. MATLAB 实现 VBKF 信号去噪的关键代码与参数说明
3.1 最小可运行实现:一维信号滤波
下面用 MATLAB 写一个可直接运行的 VBKF 函数。它针对一维观测信号,状态为信号值及其变化率,观测为带噪的测量值。完整复制即可用测试信号验证。
function [x_hist, R_hist] = vb_kf_1d(y, F, H, Q, rho, max_iter) % VBKF 变分贝叶斯卡尔曼滤波器,一维观测 % 输入: % y 观测序列,N x 1 % F 状态转移矩阵,2 x 2 % H 观测矩阵,1 x 2 % Q 过程噪声协方差,2 x 2 % rho 逆WiShart分布自由度参数,建议0.9~1.0 % max_iter 单步迭代次数,建议5~10 % 输出: % x_hist 滤波状态序列,2 x N % R_hist 观测噪声方差估计序列,1 x N N = length(y); nx = size(F, 1); x = zeros(nx, 1); % 初始状态 P = eye(nx) * 0.1; % 初始协方差 invW_R = 1; % 逆尺度矩阵初始值 x_hist = zeros(nx, N); R_hist = zeros(1, N); for k = 1:N % 预测步 x_pred = F * x; P_pred = F * P * F' + Q; % VB 更新步 R = invW_R / (rho - 2); % 1维观测时自由度参数减2 for iter = 1:max_iter % 标准卡尔曼更新 S = H * P_pred * H' + R; K = P_pred * H' / S; innov = y(k) - H * x_pred; x_upd = x_pred + K * innov; P_upd = (eye(nx) - K * H) * P_pred; % 变分贝叶斯更新噪声估计 e = y(k) - H * x_upd; invW_R = (rho - 2) * R + e^2 + H * P_upd * H'; R = invW_R / (rho - 2); end % 写入历史 x = x_upd; P = P_upd; x_hist(:, k) = x; R_hist(k) = R; end end这段代码的核心逻辑是双重循环:外层对时间步递推,内层迭代更新状态与噪声估计。预测步与标准 KF 完全一致,差别完全体现在更新步中——每次卡尔曼更新完成后,额外计算残差 e 的平方和状态协方差在观测空间的映射,用这两项加权修正 invW_R。
参数说明中需要注意的是 rho 与 R 的换算关系。逆 Wishart 分布的均值在 d 维下为 scale_matrix / (rho - d - 1),一维时为 invW_R/(rho-2)。当 rho 接近 2 时,R 的估计对最新数据非常敏感,容易剧烈抖动;rho 设置在 3~5 之间更稳定。max_iter 一般取 5 即可收敛,取 10 会带来额外的计算开销但精度提升有限。Q 的取值需根据实际信号的导数幅度标定,如果信号变化缓慢,Q 对角线取 1e-4 量级即可。
3.2 代码逻辑与矩阵维度验证
很多读者会担心上述代码中 invW_R 的迭代公式是否量纲正确。这里拆开来看:e^2 的量纲是信号幅值的平方,HP_updH' 的量纲也是幅值的平方,而 (rho-2)*R 是上一轮估计的加权。因此 invW_R 始终保持在幅值平方量级,除以 (rho-2) 后又回到方差量级。这样就保证 R 的估计值不会漂移到负值或量级失控。
需要特别注意的是,上述实现是单输出通道的特例。如果观测是多维的,invW_R 变成矩阵,自由度参数 rho 的下界变为观测维度+1,更新公式需要把 e^2 换成 e*e'。对于惯性导航、多传感器融合等应用场景,这种矩阵化实现将直接决定系统能否在收敛速度和估计精度上取得平衡。
3.3 与标准 KF 和扩展 KF 的对比
要验证 VBKF 确实有效,需要在同一段信号上做对比。下面构造一个带时变观测噪声的信号:前半段噪声方差为 1,后半段方差跳到 10。
% 构造测试信号 fs = 100; t = (0:999) / fs; true_signal = sin(2*pi*1.5*t) + 0.3 * sin(2*pi*5*t); noise_std = [ones(1,500), sqrt(10)*ones(1,500)]; rng(42); y = true_signal + noise_std .* randn(1,1000); % 跑两种滤波器 F = [1 1/fs; 0 1]; H = [1 0]; Q = [1e-6 0; 0 1e-6]; % 标准KF x_kf = zeros(2,1000); P_kf = 0.1*eye(2); R_fixed = 1; for k = 1:1000 x_pred = F * x_kf(:,k); P_pred = F * P_kf * F' + Q; K = P_pred * H' / (H*P_pred*H' + R_fixed); x_kf(:,k) = x_pred + K*(y(k) - H*x_pred); P_kf = (eye(2)-K*H)*P_pred; end % 跑VBKF [x_vb, R_hist] = vb_kf_1d(y, F, H, Q, 3, 8); % 计算均方误差(排除前50个点的启动过程) mse_kf = mean((true_signal(51:end) - x_kf(1,51:end)).^2); mse_vb = mean((true_signal(51:end) - x_vb(1,51:end)).^2); fprintf('KF MSE: %.4f, VBKF MSE: %.4f\n', mse_kf, mse_vb);运行这段代码后,VBKF 的均方误差通常会比固定噪声参数的 KF 低一个数量级。原因并不复杂——标准 KF 的后半段在噪声变大后仍按原噪声方差计算增益,滤波结果过度平滑,真实信号的峰值被严重削幅;而 VBKF 检测到残差增大后自动调高 R 的估计值,卡尔曼增益降低,从而让滤波输出“知道”当前观测质量在退化,转而更多信任状态预测。
4. 参数调整、收敛性观察与常见误用陷阱
4.1 自由参数 rho 与先验记忆长度
VBKF 最需要手动调整的参数是 rho。一个常见的工程做法是令 rho 与时间相关:rho_k = rho_0 * (1 - 遗忘因子)^{k-1} + 1,其中遗忘因子取 0.9 到 0.99 之间。但更直接的做法是固定一个较小的值,如 rho = 3。理解 rho 对估计的影响需要看它在迭代公式中的双重作用:它既决定 R 的均值计算中的分母,又影响逆尺度矩阵更新时对旧估计的保留程度。
| 参数 | 推荐值范围 | 影响 | 说明 |
|---|---|---|---|
| rho | 3~5 | 越小响应越快,越大越平滑 | 小于等于 d+1 时均值公式失效 |
| max_iter | 5~10 | 5 次以内基本收敛 | 大于 10 时计算量线性增长 |
| Q | 1e-6~1e-3 | 状态跟踪的灵敏度 | 依据状态量纲和物理模型标定 |
| P0 | 0.1~1 | 启动阶段收敛速度 | 对稳态影响较小 |
上面表格中的参数对新手来说最容易被忽略的是 rho 的下界。在一维观测下自由度必须大于 2,否则逆 Wishart 分布不存在有限均值。调试中如果看到 R 估计输出 NaN 或负数,优先检查 rho 是否小于等于 2。
4.2 观测噪声初值对收敛的影响
初始的 invW_R 取值决定滤波器启动阶段对噪声的估计起点。一个常见做法是把 invW_R 设为系统标称噪声方差的 1 倍到 2 倍。如果初始值偏离真实值过大,滤波器会在前几十个时间步内出现较大的尖峰误差,但通常会在 50 个采样点内收敛。需要注意的是,VBKF 的收敛行为取决于持续的可观测激励——如果滤波过程中信号一直保持恒定,残差长期为零,R 的估计会缓慢趋向于保守值(偏大方向)。这种情况在工程中被称作“噪声不可辨识”,并不是算法错误而是系统信息不足。
4.3 常见误用陷阱
4.3.1 将 VBKF 应用于非线性系统的错误姿势
部分 MATLAB 使用者会把 VBKF 直接套到扩展卡尔曼滤波器的框架里,用状态转移矩阵的雅可比替换 F。这个做法在某些情况下可行,但不建议直接照搬。因为变分贝叶斯更新公式中的残差计算依赖线性化后的观测矩阵 H,如果非线性程度强,线性化误差会导致 R 的估计严重偏大。此时应优先采用无迹变换(UKF)框架内的 VB 扩展,或使用粒子滤波与 VB 结合的方案。
4.3.2 R 估计滞后于真实突变
当观测噪声在相邻两个时刻发生阶跃式变化时,VBKF 的估计会滞后若干步。可以从 R_hist 输出中看到明显的斜坡而不是瞬跳。对于雷达测距、GPS 信号中断恢复等场景,这种滞后会造成滤波输出在突变边缘出现可感知的误差峰。缓解方案是在 VB 更新循环中加入新息异常检测:当新息超过某个阈值(比如 3 倍标准差)时,主动缩小 rho 以加速响应。
4.3.3 误将 Q 也完全交给 VB 推断
有的实现会把 Q 和 R 同时纳入变分推断框架。这看似更完善,但在实际运行中 Q 和 R 存在耦合,两个矩阵同时自由更新往往导致结果发散或对初值极度敏感。业界成熟做法是:先通过离线数据标定 Q,在线只自适应 R。如果确实需要同时估计 Q 和 R,应当引入平滑器或更复杂的层次贝叶斯模型,而不应依赖单步 VB 迭代。
5. 进阶用法:用 VBKF 做在线噪声方差估计与性能验证
VBKF 的一个隐藏用途是作为实时噪声监测器。由于 R_hist 本身就是对观测噪声方差的在线估计,可以把它当作一个独立的噪声分析工具。如果收到的信号本身是已知的微弱目标信号,通过观察 R_hist 的波动就能判断噪声是否存在时变特征。
% 绘制噪声方差估计结果 figure; subplot(3,1,1); plot(t, y); title('观测信号'); xlabel('时间 (s)'); subplot(3,1,2); plot(t, x_vb(1,:), 'r-', 'LineWidth', 1.5); hold on; plot(t, true_signal, 'k--', 'LineWidth', 1); legend('VBKF滤波输出', '真实信号'); title('滤波结果对比'); subplot(3,1,3); plot(t, R_hist); title('观测噪声方差在线估计'); xlabel('时间 (s)'); ylabel('R 估计值');运行后可以从第三张子图中直观看到 R 从 1 附近逐步爬升到接近 10 的轨迹。这个轨迹具有明确的物理含义:后半段噪声增大时,R 的估计跟随上升,但存在约 10~20 个采样点的响应延迟。工程师可以利用这个延迟的统计特征来判断是否需要调整滤波频率或传感器的信号调理电路。
要定量评价 VBKF 的滤波质量,不能只看总体的 MSE,还需要关注频域评价。对去噪后的信号做 FFT 频谱分析,重点观察高频噪声底噪是否下降、目标频点幅值是否保持。MATLAB 中可用pwelch函数计算功率谱密度,对比滤波前后高频段的幅值变化。如果 VBKF 的参数设置合理,滤波后的高频段功率应比输入信号低 20 dB 以上,而信号本身的基波和主要谐波幅值衰减不超过 0.5 dB。这个验证方法比单纯看 MSE 更能说明滤波是否真正“去噪”而不是“削信号”。
对于 5 年以上经验的工程师,建议把 VBKF 做成一个通用函数库的组成部分,而不是一次性脚本。将状态转移矩阵、观测矩阵、控制输入和噪声估计策略封装成类,借助 MATLAB 的面向对象机制管理滤波器实例。这样在切换不同传感器、不同信号类型时,只需修改配置对象而不必重写主流程。对于批量信号处理场景,可以使用parfor并行处理多个 VBKF 实例,每个实例处理一个通道的信号,加速效果在线性系统下几乎按核数线性增长。测试时注意把启动阶段的数据从统计指标中剔除,否则初始收敛的暂态误差会占据较大比重,掩盖算法在稳定段的真实表现。
本文还有配套的精品资源,点击获取