多传感器融合基础:从卡尔曼到粒子滤波

做导航这么多年,我越来越觉得——传感器融合不是选择题,而是必答题。你想想看,单个传感器总有掉链子的时候:GPS被高楼遮挡、IMU随时间漂移、激光雷达在雨雪天失效。怎么办?

答案就是:把多个传感器的数据揉在一起,取长补短。而这背后最核心的工具,就是今天我们要聊的这四种滤波方法。

核心观点:滤波的本质不是“消除噪声”,而是“在不确定性中做最优估计”。

多传感器融合滤波方法演进 传感器融合 卡尔曼滤波 (KF) 线性系统 + 高斯噪声 扩展卡尔曼 (EKF) 一阶泰勒展开线性化 无迹卡尔曼 (UKF) 无迹变换 + Sigma点 粒子滤波 (PF) 蒙特卡洛 + 重要性采样 复杂度与非线性处理能力:KF < EKF < UKF < PF

1. 卡尔曼滤波:一切的基础

先说卡尔曼滤波。说实话,我第一次接触它是在研究生做无人机定位的时候。当时觉得这公式怎么这么绕?后来做多了才发现——它本质上就是个“预测-修正”的循环

核心思想就两句话:

  • 预测:根据上一时刻的状态,猜一下当前时刻的状态
  • 更新:用当前时刻的观测值,修正这个猜测

我习惯用一个比喻来理解:你闭着眼睛走路,每走一步你大概知道自己在哪(预测),但偶尔睁开眼看到路标(观测),你就调整一下位置估计。卡尔曼滤波干的就是这个事。

关键公式(离散形式):

预测步:
  x̂ₖ|ₖ₋₁ = A·x̂ₖ₋₁|ₖ₋₁ + B·uₖ
  Pₖ|ₖ₋₁ = A·Pₖ₋₁|ₖ₋₁·Aᵀ + Q

更新步:
  Kₖ = Pₖ|ₖ₋₁·Hᵀ·(H·Pₖ|ₖ₋₁·Hᵀ + R)⁻¹
  x̂ₖ|ₖ = x̂ₖ|ₖ₋₁ + Kₖ·(zₖ - H·x̂ₖ|ₖ₋₁)
  Pₖ|ₖ = (I - Kₖ·H)·Pₖ|ₖ₋₁

这里面的A、H、Q、R,说白了就是你对系统和传感器的建模精度。我在项目中踩过最大的坑就是——Q和R调不好,滤波效果还不如不用

个人经验:调Q和R矩阵时,我一般先让系统跑一段开环,统计一下预测误差的方差作为Q的初值。R则直接看传感器数据手册的噪声指标,再乘以1.5~2倍作为安全余量。

2. 扩展卡尔曼滤波:对付非线性

卡尔曼滤波有个硬伤——它假设系统是线性的。但现实世界哪有那么多线性?你想想看,无人机做姿态估计,旋转矩阵是非线性的;车辆做转弯,运动模型也是非线性的。

EKF的思路很直接:既然非线性不好处理,那我就把它近似成线性的。怎么近似?用泰勒展开,取一阶项。

具体做法:

  1. 在估计点附近,对非线性函数f(x)做一阶泰勒展开
  2. 用展开后的雅可比矩阵代替原来的A和H
  3. 剩下的步骤和标准卡尔曼滤波一模一样

注意:EKF的线性化误差会随着非线性程度增加而急剧增大。我曾经在一个强非线性系统上硬套EKF,结果滤波直接发散。后来换成UKF才解决问题。

EKF的代码实现其实不复杂,核心就是求雅可比矩阵:

def ekf_predict(x, P, f, F, Q):
    # f: 状态转移函数(非线性)
    # F: f的雅可比矩阵
    x_pred = f(x)
    P_pred = F @ P @ F.T + Q
    return x_pred, P_pred

def ekf_update(x_pred, P_pred, z, h, H, R):
    # h: 观测函数(非线性)
    # H: h的雅可比矩阵
    y = z - h(x_pred)          # 残差
    S = H @ P_pred @ H.T + R   # 残差协方差
    K = P_pred @ H.T @ np.linalg.inv(S)  # 卡尔曼增益
    x_upd = x_pred + K @ y
    P_upd = (np.eye(len(x)) - K @ H) @ P_pred
    return x_upd, P_upd

3. 无迹卡尔曼滤波:不线性化也能行

EKF的线性化近似让我一直不太放心。你想想,一阶泰勒展开相当于用切线代替曲线,如果曲率大,误差就大了。

UKF换了个思路——我不去近似函数,而是去近似概率分布。具体来说:

  • 在状态估计点周围,选取一组确定的采样点(称为Sigma点)
  • 把这些Sigma点通过非线性函数传播
  • 用传播后的点重新计算均值和协方差

这就是所谓的无迹变换。它不需要求导,也不需要雅可比矩阵,而且对非线性函数的近似精度能达到三阶泰勒展开的水平。

Sigma点的选取(n维状态,2n+1个点):

χ⁰ = x̄
χⁱ = x̄ + (√((n+λ)P))ᵢ,  i=1,...,n
χⁱ = x̄ - (√((n+λ)P))ᵢ₋ₙ,  i=n+1,...,2n

我在做车辆定位时对比过EKF和UKF。同样的非线性系统,UKF的定位精度比EKF高了约15%,而且没有出现发散的情况。代价就是计算量稍微大一点——但现在的嵌入式处理器完全扛得住。

我的建议:如果你的系统非线性程度不高,EKF够用。但如果系统强非线性(比如大角度姿态估计、带回环的SLAM),直接上UKF,省心。

4. 粒子滤波:不假设任何分布

前面三种方法都有一个共同假设——噪声是高斯分布的。但现实中有很多情况不满足这个假设。比如:

  • 多模态分布(机器人可能在走廊的多个位置)
  • 非高斯噪声(传感器受突发干扰)
  • 高度非线性的状态空间

这时候,粒子滤波就派上用场了。

粒子滤波的核心思想是:用一堆带权重的随机样本(粒子)来近似后验概率分布。粒子越多,近似越精确。

基本流程:

  1. 初始化:在状态空间撒一批粒子,权重均匀
  2. 预测:每个粒子根据系统模型向前传播
  3. 更新:根据观测值更新每个粒子的权重
  4. 重采样:权重高的粒子多复制,权重低的粒子淘汰
  5. 回到步骤2,循环

注意:粒子滤波的计算量跟粒子数成正比。我做过一个项目,用1000个粒子做室内定位,在树莓派上只能跑到10Hz。后来优化到500个粒子,勉强到20Hz。所以粒子数不是越多越好,够用就行

重采样是粒子滤波的关键。我见过很多新手直接复制高权重粒子,结果所有粒子很快坍缩到同一个点——这叫粒子贫化。解决办法是加入少量随机扰动,保持粒子的多样性。

四种方法的对比

方法 适用场景 优点 缺点 我推荐的使用场景
KF 线性系统,高斯噪声 计算快,实现简单 不能处理非线性 GPS+IMU松耦合
EKF 弱非线性系统 成熟,应用广泛 线性化误差,需要雅可比 视觉SLAM前端
UKF 强非线性系统 精度高,无需求导 计算量稍大 车辆状态估计
PF 非高斯,多模态 任意分布都能近似 计算量大,粒子贫化 全局定位,绑架恢复

选型口诀:线性用KF,弱非线性用EKF,强非线性用UKF,非高斯多模态用PF。别一上来就上粒子滤波,杀鸡焉用牛刀。

好了,这一章的内容就到这里。四种滤波方法各有各的脾气,关键是要理解它们的核心假设和适用边界。我在实际项目中,经常是先用KF搭个基线,然后根据系统表现逐步升级到EKF或UKF。至于粒子滤波——嗯,那是最后的大招,轻易不用,用了就要确保计算资源够用。


公众号:蓝海资料掘金营,微信deep3321