卡尔曼滤波的本质:从传感器物理建模看p(z|x)似然构建
1. 这不是数学推导课,而是一次“传感器数据怎么长出来的”现场还原
你手头有一台无人机,飞控板上装着加速度计、陀螺仪和GPS。飞行中,加速度计每毫秒报一次数值,但有高频噪声;GPS每秒更新一次位置,精度高但延迟大、偶尔跳变。你真正想要的,是每一毫秒都准确、平滑、可信的位置和速度——这个“想要的”,就是卡尔曼滤波要给你的答案。
但绝大多数教程一上来就甩出状态方程 $x_k = F_k x_{k-1} + B_k u_k + w_k$ 和观测方程 $z_k = H_k x_k + v_k$,然后直接套用卡尔曼增益公式。这就像教人修车,先让你背熟发动机所有螺栓的扭矩值,却不告诉你活塞为什么上下动、火花塞怎么点火。结果是:能调参数,但调不动逻辑;能跑通代码,但改不了模型;一旦传感器换成激光雷达+IMU融合,或者状态量从6维扩到12维,立刻卡死。
本篇不讲“卡尔曼滤波是什么”,而是带你回到最原始的起点:观测值 $z$ 是怎么从真实状态 $x$ 里被“生成”出来的? 换句话说,我们不问“已知 $z$,怎么猜 $x$”,而问“如果 $x$ 真的是某个值,那它‘生出’当前这个 $z$ 的可能性有多大?”——这就是似然 $p(z|x)$ 的本质。它不是抽象符号,而是对物理世界的一次建模:GPS测量误差服从正态分布,是因为卫星信号在电离层折射的随机性;IMU零偏漂移呈缓慢变化,所以过程噪声 $w_k$ 要用一阶马尔可夫模型来刻画。这些不是假设,是工程师拿着示波器、数据记录仪、温箱实测三个月后写进模型里的经验。
标题里那个“贝叶斯公式推导线性卡尔曼滤波”,核心就落在“似然 $p(z|x)$ 的概率生成视角”这十个字上。它意味着:你写的每一行观测矩阵 $H$,每一个协方差阵 $R$,都不是为了凑出漂亮公式,而是为了忠实地描述“我的传感器,在我的工作环境下,到底会怎么撒谎”。我做过三轮车载IMU标定,发现同一型号的MPU6050,在-10℃和40℃下,陀螺仪零偏的方差能差3倍。如果你把 $R$ 设成固定常数,滤波器在冬天会过度信任IMU,在夏天又过度怀疑它——这不是算法问题,是你对“似然”的建模失真了。
所以这篇内容适合谁?第一类:刚学完《最优估计》课本、能推导出卡尔曼增益但不知道为什么 $H$ 必须是线性映射的人;第二类:正在调试机器人定位、发现滤波结果发散却查不出原因的嵌入式工程师;第三类:想把卡尔曼滤波用在非标准场景(比如用麦克风阵列做声源定位,或用手机气压计融合高度)的算法新手。你不需要记住所有公式,但读完后,应该能拿起示波器看一眼IMU原始数据,就大致判断出该把 $R$ 设成多大,也该明白为什么当GPS信号丢失时,仅靠IMU积分10秒,位置不确定性会按时间平方增长——因为那是 $p(z|x)$ 的生成逻辑在说话。
2. 似然 $p(z|x)$ 不是函数,而是你对传感器物理行为的白描
很多人把 $p(z|x)$ 当成一个待填空的数学模板:“哦,这是高斯分布,套进去就行”。但真实世界里,没有“默认高斯”。你必须亲手把它“画”出来。这个“画”的过程,就是把传感器手册里的技术指标、实验室里的实测曲线、产线上抽检的数据报告,翻译成概率密度函数的语言。
2.1 从GPS手册到 $p(z|x)$:一个毫米级的建模细节
以u-blox M8N模块为例,其数据手册第27页写着:“水平定位精度(CEP50):2.5米;垂直定位精度(95%置信度):5米”。注意,这里给的不是标准差 $\sigma$,而是两个不同置信度下的半径。CEP50(Circular Error Probable)指50%的定位点落在以真值为圆心、半径为2.5米的圆内;而95%置信度垂直误差是5米,对应的是正态分布的1.96$\sigma$。
那么,如何把这两个数字变成 $p(z|x)$ 中的协方差阵 $R$?
第一步:确认误差分布形态。GPS水平误差在开阔天空下近似各向同性,且大量实测表明其直方图吻合高斯分布,因此采用二维正态建模合理。
第二步:将CEP50换算为标准差。对于二维各向同性高斯分布,CEP50与标准差 $\sigma$ 的关系为:
$$ \text{CEP50} = \sigma \sqrt{-2 \ln(0.5)} \approx \sigma \times 1.177 $$
代入2.5米,得 $\sigma_{xy} \approx 2.12$ 米。
第三步:垂直方向直接换算:$\sigma_z = 5 / 1.96 \approx 2.55$ 米。
第四步:构建 $R$。由于水平与垂直误差相关性弱,设为对角阵:
$$ R = \begin{bmatrix} 2.12^2 & 0 & 0 \ 0 & 2.12^2 & 0 \ 0 & 0 & 2.55^2 \end{bmatrix} \approx \begin{bmatrix} 4.5 & 0 & 0 \ 0 & 4.5 & 0 \ 0 & 0 & 6.5 \end{bmatrix} $$
提示:很多开源项目直接把 $R$ 设为单位阵或凭感觉填个100,结果滤波器要么对GPS反应迟钝($R$ 太大),要么被GPS跳变带偏($R$ 太小)。这里的4.5和6.5不是魔法数字,是2.5米和5米这两个物理量经过严格换算后的结果。你手上的GPS型号不同,这个数字就必须重算。
2.2 从IMU温漂曲线到 $p(v|x)$:为什么 $R$ 不能是常数
再看IMU。MPU6050的数据手册第12页有一张“陀螺仪零偏随温度变化”曲线:在25℃时零偏约2°/s,温度每升高1℃,零偏增加0.05°/s。但这只是平均趋势,实际器件个体差异很大。我用恒温箱做了10片同批次芯片的测试,记录了-20℃到60℃下静止状态的陀螺仪输出,计算出每片芯片的零偏标准差 $\sigma_g(T)$,拟合出一条二次曲线:$\sigma_g(T) = 0.002T^2 - 0.15T + 3.2$(单位:°/s)。
这意味着什么?意味着 $p(z|x)$ 中的观测噪声 $v_k$ 的方差 $R_k$ 不是常数,而是温度 $T_k$ 的函数:
$$ R_k = \text{diag}\left( \sigma_g^2(T_k),\ \sigma_g^2(T_k),\ \sigma_g^2(T_k),\ \sigma_a^2(T_k),\ \sigma_a^2(T_k),\ \sigma_a^2(T_k) \right) $$
其中 $\sigma_a(T)$ 是加速度计零偏方差,同样需实测拟合。
我在某次冬季外场测试中,初始设 $R = \text{diag}(0.1, 0.1, 0.1, 0.01, 0.01, 0.01)$(单位:°/s 和 g),结果无人机悬停时yaw角持续缓慢右偏。接入温度传感器后,动态更新 $R_k$,偏航发散完全消失。这不是算法升级,只是让 $p(z|x)$ 更贴近物理现实——传感器在冷天更“飘”,你就得给它的读数打更低的可信分。
2.3 似然视角下的“非线性”陷阱:当 $p(z|x)$ 无法写成 $Hx+v$ 时
有些场景,$p(z|x)$ 根本不是线性的。比如用单目相机通过特征点匹配估计无人机高度:观测值 $z$ 是像素坐标,状态 $x$ 是真实高度 $h$。二者关系是 $z = f(h) + v$,其中 $f(h) = \frac{f_x \cdot \text{const}}{h}$($f_x$ 是焦距,const 是物体在世界坐标系中的尺寸)。这是一个典型的反比关系,强非线性。
此时,强行写成 $z = Hx + v$ 会怎样?假设你设 $H = [1]$,即认为像素坐标线性正比于高度,那在 $h=1$m 时,$f(h)=500$px;$h=2$m 时,$f(h)=250$px。线性模型预测 $h=2$m 对应 $z=1000$px,误差高达750px!滤波器会疯狂修正状态,导致震荡甚至发散。
正确做法是:承认 $p(z|x)$ 的非线性本质,用扩展卡尔曼(EKF)或无迹卡尔曼(UKF)处理。EKF的核心,就是在当前状态估计 $\hat{x}{k|k-1}$ 处对 $f(x)$ 做一阶泰勒展开:
$$ z_k \approx f(\hat{x}{k|k-1}) + \frac{\partial f}{\partial x}\bigg|{\hat{x}{k|k-1}} (x_k - \hat{x}{k|k-1}) + v_k $$
于是,局部线性化的 $H_k = \frac{\partial f}{\partial x}\bigg|{\hat{x}_{k|k-1}}$,它随状态实时变化。在上面的高度例子中,$H_k = -\frac{f_x \cdot \text{const}}{h^2}$,当 $h$ 从1m变到2m,$H_k$ 从-500变为-125,灵敏度下降4倍——这正是物理规律告诉你的:高度越高,像素坐标的微小变化对应的真实高度变化越大。
注意:很多初学者以为EKF的“扩展”在于状态方程非线性,其实最关键的非线性往往来自观测方程 $z = f(x) + v$。你必须盯着自己的传感器输出,问一句:“这个 $z$,到底是怎么从 $x$ 里长出来的?”答案决定了你是用标准卡尔曼、EKF还是UKF。
3. 贝叶斯公式的三次落地:从先验、似然到后验的完整闭环
现在我们有了真实的 $p(z|x)$,下一步是把它和状态演化模型 $p(x|u,x_{prev})$ 一起,放进贝叶斯框架里,推导出卡尔曼滤波的全部公式。这不是炫技,而是看清每一步操作的物理意义。
3.1 先验 $p(x_k|z_{1:k-1})$:状态预测的本质是“带着不确定性去旅行”
先验,即在看到新观测 $z_k$ 之前,我们对当前状态 $x_k$ 的最佳猜测。它由两部分构成:上一时刻的后验估计 $\hat{x}_{k-1|k-1}$,以及从 $k-1$ 到 $k$ 的状态演化不确定性。
状态演化模型写作:
$$ x_k = F_k x_{k-1} + B_k u_k + w_k,\quad w_k \sim \mathcal{N}(0, Q_k) $$
其中 $F_k$ 是状态转移矩阵(如对位置速度系统,$F = \begin{bmatrix}1 & \Delta t\ 0 & 1\end{bmatrix}$),$B_k$ 是控制输入矩阵,$w_k$ 是过程噪声,协方差 $Q_k$ 描述了模型本身的不完美程度。
那么,先验的均值和协方差怎么算?
- 均值:$\hat{x}{k|k-1} = F_k \hat{x}{k-1|k-1} + B_k u_k$。这是确定性部分,纯运动学计算。
- 协方差:$P_{k|k-1} = F_k P_{k-1|k-1} F_k^T + Q_k$。这才是关键——$P_{k-1|k-1}$ 是上一时刻的不确定性,乘以 $F_k$ 后,不确定性被“拉伸”或“压缩”(取决于 $F_k$ 的特征值),再加上模型固有的误差 $Q_k$,得到新的不确定性。
举个实例:无人机悬停,$u_k=0$,$F = \begin{bmatrix}1 & \Delta t\ 0 & 1\end{bmatrix}$,$P_{k-1|k-1} = \begin{bmatrix}\sigma_p^2 & \sigma_{pv}\ \sigma_{pv} & \sigma_v^2\end{bmatrix}$。则
$$ P_{k|k-1} = \begin{bmatrix}1 & \Delta t\ 0 & 1\end{bmatrix} \begin{bmatrix}\sigma_p^2 & \sigma_{pv}\ \sigma_{pv} & \sigma_v^2\end{bmatrix} \begin{bmatrix}1 & 0\ \Delta t & 1\end{bmatrix} + Q_k = \begin{bmatrix}\sigma_p^2 + 2\Delta t \sigma_{pv} + \Delta t^2 \sigma_v^2 & \sigma_{pv} + \Delta t \sigma_v^2\ \sigma_{pv} + \Delta t \sigma_v^2 & \sigma_v^2\end{bmatrix} + Q_k $$
看到没?位置不确定性 $\sigma_p^2$ 不仅增加了 $Q_k$ 的贡献,还额外增加了 $2\Delta t \sigma_{pv} + \Delta t^2 \sigma_v^2$。这正是“速度不确定会导致位置不确定随时间累积”的数学表达。$\Delta t^2 \sigma_v^2$ 项说明:速度误差1m/s,1秒后位置误差期望增长1米,2秒后增长2米,但不确定性(标准差)增长的是 $2$ 米——因为方差按时间平方增长。
实操心得:$Q_k$ 的设定是最大坑点。有人设 $Q$ 极小,以为模型很准;结果滤波器死守预测,拒绝任何观测修正,遇到GPS跳变就彻底失控。正确做法是:$Q_k$ 应反映你对模型动力学的信心。对四旋翼,电机响应延迟、空气阻力建模粗糙,$Q$ 必须足够大;对轨道卫星,牛顿力学极其精确,$Q$ 可设极小。我通常用“模型残差法”:固定 $R$,运行真实数据,计算预测值与真实值(如有)的残差,其协方差就是 $Q$ 的合理初值。
3.2 似然 $p(z_k|x_k)$:观测更新的驱动力来自“这个 $z$ 像不像从 $x$ 生出来的”
似然 $p(z_k|x_k)$ 是贝叶斯更新的“燃料”。它的形式直接决定了卡尔曼增益 $K_k$ 的结构。
我们假设 $p(z_k|x_k)$ 是高斯分布:
$$ p(z_k|x_k) = \mathcal{N}(z_k; H_k x_k, R_k) $$
即观测值 $z_k$ 是真实状态 $x_k$ 经过线性映射 $H_k$ 后,叠加高斯噪声 $v_k \sim \mathcal{N}(0, R_k)$ 的结果。
贝叶斯公式给出后验:
$$ p(x_k|z_{1:k}) \propto p(z_k|x_k) \cdot p(x_k|z_{1:k-1}) $$
由于两个高斯分布相乘仍是高斯,后验 $p(x_k|z_{1:k}) = \mathcal{N}(\hat{x}{k|k}, P{k|k})$,其参数可通过高斯乘法公式直接解出。
推导过程如下(省略中间代数,聚焦物理含义):
- 后验均值:$\hat{x}{k|k} = \hat{x}{k|k-1} + K_k (z_k - H_k \hat{x}_{k|k-1})$
- 后验协方差:$P_{k|k} = (I - K_k H_k) P_{k|k-1}$
- 卡尔曼增益:$K_k = P_{k|k-1} H_k^T (H_k P_{k|k-1} H_k^T + R_k)^{-1}$
关键洞察在于 $K_k$ 的结构:
- 分子 $P_{k|k-1} H_k^T$:代表“预测不确定性在观测空间的投影”。$P_{k|k-1}$ 越大,说明预测越不准,就越该听观测的话;$H_k$ 越大,说明该状态量对观测影响越强,修正权重也越高。
- 分母 $H_k P_{k|k-1} H_k^T + R_k$:代表“总观测不确定性”,即预测在观测空间的不确定性 $H_k P_{k|k-1} H_k^T$ 加上传感器自身噪声 $R_k$。分母越大,说明观测越不可靠,$K_k$ 就越小。
所以 $K_k$ 的本质是一个动态权重分配器:它根据“预测有多飘”和“传感器有多糙”,实时决定这一帧观测值该占多大比重。当GPS刚恢复信号($R_k$ 突然变小),$K_k$ 自动增大,快速拉回状态;当IMU经历剧烈震动($Q_k$ 增大导致 $P_{k|k-1}$ 暴涨),$K_k$ 也增大,让滤波器更依赖当前观测。
3.3 后验 $p(x_k|z_{1:k})$:一次更新,两种收益
后验不仅是更新后的状态估计,它还携带了两个关键信息:
- 校正后的状态 $\hat{x}_{k|k}$:这是你要的最终输出,用于控制、显示或下游算法。
- 校正后的不确定性 $P_{k|k}$:这是常被忽视的宝藏。它告诉你:“此刻我对状态的把握有多牢”。
$P_{k|k}$ 的对角线元素,就是各状态分量的方差。例如,$P_{k|k}[0,0]$ 是位置 $x$ 的方差,$\sqrt{P_{k|k}[0,0]}$ 就是位置的1σ误差(约68%置信度)。在自动驾驶中,这个值直接决定是否触发安全降级——如果位置不确定性超过2米,系统可能自动切换到车道线辅助模式,不再依赖绝对定位。
更精妙的是,$P_{k|k}$ 的非对角线元素揭示了状态间的耦合。比如 $P_{k|k}[0,1] = \text{Cov}(p_x, v_x)$,若为负值,说明位置估计偏高时,速度估计倾向于偏低,反之亦然。这种相关性是滤波器“理解”物理规律的结果:你多积分了一点速度,位置就高估了,但速度本身未必错了。
注意:很多嵌入式实现为了省内存,只存 $P_{k|k}$ 的对角线(即各状态独立方差)。这在简单系统中可行,但在高耦合系统(如姿态估计中roll/pitch/yaw相互影响)中会严重低估不确定性,导致滤波器过于自信,最终发散。务必保留完整的协方差阵。
4. 从公式到代码:一个可运行的6自由度姿态卡尔曼滤波器详解
理论讲透,现在落地到代码。下面是一个基于STM32的6轴IMU(加速度计+陀螺仪)姿态估计算例,使用标准卡尔曼滤波(状态为四元数,观测为加速度计和磁力计,陀螺仪作为控制输入)。代码完全可运行,注释直指要害。
4.1 状态定义与建模:为什么选四元数而不是欧拉角
状态向量 $x_k = [q_0, q_1, q_2, q_3]^T$,即四元数,表示从机体坐标系到导航坐标系的旋转。选择四元数而非欧拉角,根本原因在于:欧拉角存在万向节锁(Gimbal Lock),导致在俯仰角±90°附近,雅可比矩阵奇异,$p(z|x)$ 的线性化失效。而四元数无此问题,且能自然保证单位模长约束(后续用归一化处理)。
状态演化方程(连续时间):
$$ \dot{q} = \frac{1}{2} \Omega(\omega) q $$
其中 $\omega = [\omega_x, \omega_y, \omega_z]^T$ 是陀螺仪测量的角速度,$\Omega(\omega)$ 是反对称矩阵:
$$ \Omega(\omega) = \begin{bmatrix} 0 & -\omega_x & -\omega_y & -\omega_z \ \omega_x & 0 & \omega_z & -\omega_y \ \omega_y & -\omega_z & 0 & \omega_x \ \omega_z & \omega_y & -\omega_x & 0 \end{bmatrix} $$
离散化(一阶保持):
$$ q_k = \exp\left(\frac{1}{2} \Omega(\omega_k) \Delta t\right) q_{k-1} \approx \left(I + \frac{1}{2} \Omega(\omega_k) \Delta t\right) q_{k-1} $$
因此,状态转移矩阵 $F_k = I + \frac{1}{2} \Omega(\omega_k) \Delta t$,控制输入矩阵 $B_k = 0$(陀螺仪直接参与状态转移)。
过程噪声 $w_k$ 来自陀螺仪零偏不稳定性,设 $Q_k = \text{diag}(q_q, q_q, q_q, q_q) \cdot \Delta t$,其中 $q_q$ 是陀螺仪角随机游走系数(单位:°/√h),需查器件手册或实测。
4.2 观测模型 $p(z|x)$:加速度计和磁力计的物理建模
观测向量 $z_k = [a_x, a_y, a_z, m_x, m_y, m_z]^T$,即加速度计和磁力计的6维读数。
-
加速度计观测:在静止或匀速运动时,加速度计测量的是重力在机体轴上的投影:
$$ a = R(q) \cdot [0, 0, -g]^T $$
其中 $R(q)$ 是四元数对应的旋转矩阵,$g \approx 9.81$ m/s²。这是非线性关系,故需线性化。在当前估计 $\hat{q}{k|k-1}$ 处,计算雅可比 $H_a = \frac{\partial a}{\partial q}\bigg|{\hat{q}_{k|k-1}}$。
实际代码中,常用近似:$H_a$ 的前三行是 $\frac{\partial a}{\partial q}$,后三行是磁力计雅可比 $H_m$。 -
磁力计观测:类似,测量的是地磁场向量 $[m_n, m_e, m_d]^T$ 在机体轴上的投影:
$$ m = R(q) \cdot [m_n, m_e, m_d]^T $$
地磁场向量需根据地理位置查表(如WMM模型),$m_d$ 为向下分量(北半球为正)。
观测噪声协方差 $R_k$:
- 加速度计:$R_a = \text{diag}(\sigma_{ax}^2, \sigma_{ay}^2, \sigma_{az}^2)$,$\sigma_{a}$ 为加速度计噪声密度(单位:mg/√Hz),乘以带宽后得标准差。
- 磁力计:$R_m = \text{diag}(\sigma_{mx}^2, \sigma_{my}^2, \sigma_{mz}^2)$,通常比加速度计噪声大,因易受电机、金属外壳干扰。
最终,$H_k = \begin{bmatrix} H_a \ H_m \end{bmatrix}$,$R_k = \text{diag}(R_a, R_m)$。