从零推导一维卡尔曼滤波
卡尔曼滤波的公式看上去很密,但一维情况下的每一个式子,都可以从”两个不太准的数,该怎么合成一个更准的数”这个问题出发,一步步推出来。
本文不先给公式,而是沿着一串问题往下走。每一步都先凭直觉回答,再用极端情况或代码检验。最后得到的,就是一维卡尔曼滤波的全部公式。
只讨论一维:状态只有”距离”一个量,速度视为已知。速度如何一起估计,留到下一篇。
场景:雷达车跟踪前车
雷达车装有毫米波雷达,正在跟踪正前方的一辆车,雷达每 50 ms 出一帧。
假设此刻已经知道:前车距离雷达车 20.0 m,正以 10 m/s 的速度向雷达车靠近。
本文约定速度 \(v\) 是距离的变化率:负值表示靠近,正值表示远离。这里 \(v = -10\) m/s。
下一帧,也就是 50 ms 之后,前车离雷达车多远?
预测:下一帧它在哪
如果前车保持速度不变,50 ms 内距离会缩短 \(10 \times 0.05 = 0.5\) m:
\[20.0 + (-10) \times 0.05 = 19.5\ \text{m}\]用运动规律把当前状态推到下一时刻,这一步叫做预测。这里用的运动规律是匀速运动:
\[\hat{x}_{\text{预测}} = \hat{x} + v\,\Delta t\]\(\hat{x}\) 上的”帽子”表示这是一个估计值,而不是真值。由于 \(v\) 带符号,无论靠近还是远离,都用同一个公式。
但 19.5 m 只是”应该在那里”,并不精确:
- 当前的 20.0 m 和 10 m/s 本身就是估计值,可能有误差。
- 前车在这 50 ms 里不一定严格匀速,可能轻踩刹车,也可能加速。
所以预测值需要用新的观测来核对。
测量:雷达说它在哪
50 ms 后,雷达的新一帧到了,测得距离 19.8 m。
测量也不精确。雷达测距带有噪声,即使目标静止不动,每帧的读数也会有些抖动。
现在手上有两个数,都不完全可靠,而且相差 0.3 m:
| 来源 | 距离 | 不准的原因 |
|---|---|---|
| 预测 | 19.5 m | 初始估计有误差,前车不一定匀速 |
| 测量 | 19.8 m | 雷达测距噪声 |
这一帧应该输出多少米?
第一直觉:取平均
最直接的做法是取平均,得到 19.65 m。
这个做法其实已经具备了卡尔曼滤波的骨架:预测 → 测量 → 融合。问题在于,平均隐含了一个选择:两边各信一半。
设想两种极端情况:
- 情况 A:雷达误差只有 ±1 cm,前车却是新手,经常突然刹车加速。
- 情况 B:雷达测距经常跳动 ±1 m,前车开着定速巡航,速度非常稳定。
显然,情况 A 应该更信雷达,情况 B 应该更信预测。取平均在两种情况下都不对。
卡尔曼滤波的核心思想就在这里:
谁的不确定性小,就更相信谁。
谁更不靠谱,就少信谁
先把加权平均换一种写法:
\[\hat{x} = \hat{x}_{\text{预测}} + K\,(z - \hat{x}_{\text{预测}})\]- \(z\) 是雷达测量值。
- 括号里是测量和预测的差,这个例子里是 0.3 m。
- \(K\) 在 0 到 1 之间,表示这个差值采纳多少。取平均就是 \(K = 0.5\)。
再用两个数描述”有多不靠谱”:
- \(P\):预测的不确定度
- \(R\):测量的不确定度
数字越大越不靠谱。我们希望 \(K\) 满足:
| 情况 | 期望的 \(K\) | 含义 |
|---|---|---|
| \(R = 0\),雷达完美 | 1 | 完全相信测量 |
| \(P = 0\),预测完美 | 0 | 完全相信预测 |
| \(P = R\) | 0.5 | 退回平均 |
\(K\) 是一个比例。看一个数字例子:\(P = 3\),\(R = 1\),总共 4 份不确定性,预测占 3 份,雷达占 1 份。预测占得越多,说明预测越不靠谱,越该转向测量。所以 \(K\) 应该等于预测所占的比例:
\[K = \frac{P}{P + R}\]逐条代入上表,三个条件都满足。
这里最容易弄反的是分子。\(P\)、\(R\) 表示的是不靠谱程度,和”信任”正好相反。可以用一句话检查:
预测越不靠谱,就越听测量的。
如果写成 \(K = R/(P+R)\),代入 \(R = 0\) 会得到 \(K = 0\):雷达完美时反而完全不信雷达。用一个已知答案的极端情况代入,是自查公式最快的办法。
融合后的不确定度
雷达每 50 ms 来一帧,下一帧还要再融合一次。到那时需要知道当前估计有多不靠谱,所以要先算出融合后的不确定度。
误差和不确定度不是一回事
| 误差 | 不确定度 | |
|---|---|---|
| 指什么 | 这一次估计离真值差多少 | 很多次估计里,误差通常有多大 |
| 例子 | 这一帧读数 19.8 m,真值 19.75 m,误差 0.05 m | 这个雷达的误差通常在 ±10 cm 左右 |
| 能否知道 | 不能,真值永远未知 | 能,可以通过标定或统计得到 |
卡尔曼滤波中的 \(P\) 和 \(R\) 都是不确定度,具体用的是方差,也就是误差平方的平均值。
推导
融合公式可以改写成两个数的加权和:
\[\hat{x} = (1-K)\,\hat{x}_{\text{预测}} + K\,z\]因为 \((1-K) + K = 1\),两边同时减去真值 \(x\),误差也是同样的加权和:
\[\hat{x} - x = (1-K)\,(\hat{x}_{\text{预测}} - x) + K\,(z - x)\]右边两项分别是预测误差(方差 \(P\))和测量误差(方差 \(R\))。两者互相独立时,加权和的方差等于系数平方乘各自的方差:
\[P_{\text{新}} = (1-K)^2\,P + K^2\,R\]这个式子对任意 \(K\) 都成立。
一个熟悉的特例:两把精度相同、误差独立的尺子各量一次,取平均。\(K = 0.5\),\(P = R = \sigma^2\),得到 \(\tfrac14\sigma^2 + \tfrac14\sigma^2 = \tfrac12\sigma^2\),方差减半。所以取两次平均比只量一次更可靠,因为误差会部分抵消。
融合不一定更好
很容易由此得出”融合两份独立信息,一定比任何一份都准”。这需要一个前提:\(K\) 选得对。
取 \(P = 1\)(预测较准)、\(R = 4\)(雷达较差):
| \(K\) | \(P_{\text{新}}\) | 和只用预测比 |
|---|---|---|
| 0 | 1.00 | 一样,等于没用雷达 |
| 0.2 | 0.80 | 更好 |
| 0.5 | 1.25 | 更差 |
| 1 | 4.00 | 差很多,等于只用雷达 |
雷达较差时取平均,结果反而不如只用预测。误差独立只保证我们能写出 \(P_{\text{新}}\) 的公式,至于结果好不好,取决于 \(K\)。
为什么这个增益是最优的
上表里 \(K = 0.2\) 最好,而 \(P/(P+R) = 1/5\) 恰好就是 0.2。这不是巧合。
\(P_{\text{新}}\) 是关于 \(K\) 的开口向上的抛物线。对 \(K\) 求导并令其为 0:
\[\frac{dP_{\text{新}}}{dK} = -2(1-K)P + 2KR = 0\]整理得:
\[KR = (1-K)P \quad\Rightarrow\quad K = \frac{P}{P+R}\]中间那个等式的含义是:\(K\) 每增大一点,测量误差的贡献增加,预测误差的贡献减少;在最优点两者正好抵消。
这一步还说明了另一件事。前面那三个条件只能排除明显错误的公式,并不能唯一确定 \(K\)。例如 \(K = P^2/(P^2+R^2)\) 也同样满足那三个条件。真正确定 \(K = P/(P+R)\) 的,是它让融合后的方差最小。卡尔曼滤波被称为最优估计,指的就是这一点。严格来说,”最优”还依赖线性模型和高斯噪声等前提。
把最优 \(K\) 代回去:
\[P_{\text{新}} = \frac{R^2 P + P^2 R}{(P+R)^2} = \frac{PR}{P+R} = (1-K)\,P\]所以教材里常见的 \(P_{\text{新}} = (1-K)P\) 不是一条独立的规律,而是一般式在最优增益下的化简结果。如果 \(K\) 取了别的值,就要用一般式计算。
检验两个极端:
- \(P = R\):\(P_{\text{新}} = P/2\),和两把尺子的结论一致。
- \(R = 0\):\(P_{\text{新}} = 0\)。雷达完美时,融合结果就是真值,确实没有任何不确定性。注意 \(P\) 是融合之前预测的不确定度,它不会因为雷达好坏而改变;”完全不信预测”是靠 \(K = 1\) 实现的,而不是让 \(P\) 变成无穷大。
预测让不确定度变大
融合之后进入下一帧。测量到来之前,先用运动模型把估计往前推 50 ms。
运动模型假设前车匀速,但它实际上可能在这 50 ms 里轻微加速或减速。模型没考虑到的这部分变化会带来新的不确定性,用 \(Q\) 表示:
\[P_{\text{预测}} = P + Q\]\(Q\) 叫过程噪声,\(R\) 叫测量噪声。它们是使用卡尔曼滤波时最需要自己设定的两个参数:
| 因素 | \(Q\) 应该 |
|---|---|
| 目标经常急加速、急刹车 | 设大 |
| 目标稳定巡航 | 设小 |
| 帧周期更长,比如从 50 ms 变成 200 ms | 变大,因为预测跨度越长,偏离越多 |
完整的一维卡尔曼滤波
每一帧依次执行两步:
① 预测
\[\begin{aligned} \hat{x}_{\text{预测}} &= \hat{x} + v\,\Delta t \\ P_{\text{预测}} &= P + Q \end{aligned}\]② 更新
\[\begin{aligned} K &= \frac{P_{\text{预测}}}{P_{\text{预测}} + R} \\ \hat{x} &= \hat{x}_{\text{预测}} + K\,(z - \hat{x}_{\text{预测}}) \\ P &= (1-K)\,P_{\text{预测}} \end{aligned}\]预测让不确定度变大(加 \(Q\)),测量让它变小(乘 \(1-K\))。每一帧都在这一涨一缩之间达到平衡。
每个式子的来源:
| 式子 | 来源 |
|---|---|
| \(P_{\text{预测}} = P + Q\) | 模型没考虑到的变化带来新的不确定性 |
| \(P_{\text{新}} = (1-K)^2 P + K^2 R\) | 独立误差加权求和的方差 |
| \(K = P/(P+R)\) | 让上式最小 |
| \(P_{\text{新}} = (1-K)P\) | 代入最优 \(K\) 后的化简 |
初始值从哪里来
开头假设”已经知道前车距离 20.0 m、以 10 m/s 靠近”,这是为了讨论方便直接给出的。实际系统里,滤波器在第一帧之前没有任何估计,需要初始化。
距离:雷达第一次发现目标时,手上只有这一次测量,最自然的做法是
\[\hat{x}_0 = z_0, \qquad P_0 = R\]估计值就是测量值,它的不确定度就是测量的不确定度。配套实验就是这样初始化的。
如果拿不准,也可以把 \(P_0\) 设得比较大。\(P_0\) 越大,前几帧的 \(K\) 越接近 1,滤波器会主要听测量的。几帧之后,\(P\) 会被测量不断压小,初始值的影响就逐渐消失了。反过来,把 \(P_0\) 设得过小,等于一开始就过度相信一个随手给的初值,需要更多帧才能纠正。
速度:本文的一维模型把 \(v\) 当成已知常数,这只是为了先把一维的推导讲清楚。实际系统中有两种来源:
- 直接测量:毫米波雷达可以通过多普勒效应测量目标的径向速度。
- 由滤波器估计:把速度也作为状态,从连续几帧的距离变化中推断出来。这是下一篇的内容。
工程上,雷达跟踪还会先做航迹起始,例如连续若干帧都检测到同一个目标才确认建立航迹,用这几帧来给出初始距离和速度。本文不展开。
用实验检验
配套程序模拟了这样一个场景:
- 帧周期 50 ms,雷达测距的标准差 0.3 m,即 \(R = 0.09\ \text{m}^2\)。
- 滤波器假设前车始终以 10 m/s 匀速靠近,即 \(v = -10\) m/s。
- 前 100 帧确实如此;从第 100 帧起前车刹车,靠近得越来越快,\(v\) 每秒减小 2 m/s,滤波器并不知道。
融合方差与最优增益
取 \(P = 1\)、\(R = 4\),各生成 20 万个随机误差,直接统计融合结果的方差:
| \(K\) | 统计值 | 公式 \((1-K)^2 P + K^2 R\) |
|---|---|---|
| 0.0 | 1.002 | 1.000 |
| 0.1 | 0.850 | 0.850 |
| 0.2 | 0.799 | 0.800 |
| 0.3 | 0.848 | 0.850 |
| 0.5 | 1.247 | 1.250 |
| 1.0 | 4.000 | 4.000 |
统计值与公式吻合,最小值出现在 \(K = P/(P+R) = 0.2\)。
Q = 0 时,K 会怎样
先预测:如果认为前车绝对匀速,把 \(Q\) 设为 0,\(K\) 会如何变化?
| 帧 | \(K\)(\(Q = 0\)) | \(K\)(\(Q = 0.01\)) |
|---|---|---|
| 1 | 0.500 | 0.526 |
| 10 | 0.091 | 0.283 |
| 50 | 0.020 | 0.282 |
| 199 | 0.005 | 0.282 |
\(Q = 0\) 时,每一帧只有测量在压缩 \(P\),没有任何东西让它涨回来,\(K\) 按 \(1/(n+1)\) 一直趋近 0。滤波器越来越自信,也越来越不听雷达的。
\(Q = 0.01\) 时,\(K\) 很快稳定在 0.28 左右,这就是一涨一缩达到的平衡,称为稳态。
前车刹车之后
估计误差(估计值减真值,单位 m):
| 帧 | 雷达本身 | \(Q = 0\) | \(Q = 0.01\) |
|---|---|---|---|
| 90 | 0.03 | −0.01 | −0.00 |
| 120 | −0.02 | 1.07 | 0.15 |
| 160 | 0.11 | 8.23 | 0.95 |
| 199 | 0.34 | 20.97 | 1.40 |
均方根误差:
| 区间 | 雷达本身 | \(Q = 0\) | \(Q = 0.01\) |
|---|---|---|---|
| 匀速段 | 0.28 | 0.03 | 0.12 |
| 刹车段 | 0.30 | 9.70 | 0.76 |
直觉上可能会以为 \(Q = 0\) 的滤波器只是反应延迟,迟早能追上。实际上它发散了:到第 199 帧偏差达 21 m,雷达一直在给正确读数,滤波器却几乎完全不理会。
这组数据还显示了 \(Q\) 的取舍。匀速段里 \(Q = 0\) 的效果最好,因为那段时间模型恰好是对的。\(Q\) 设得小,平稳时更平滑,但目标一变化就反应迟钝甚至发散;\(Q\) 设得大,跟得快,但对噪声更敏感。
容易混淆的地方
| 混淆 | 区分 |
|---|---|
| 不确定度和信任 | 不确定度越大越不可信。\(K\) 的分子是预测的不确定度 \(P\) |
| 不确定度和误差 | 误差是某一次的具体偏差,无法得知;不确定度描述误差通常有多大,可以标定 |
| 误差独立和融合更好 | 独立让方差公式成立;只有 \(K\) 选得好,融合结果才会更好 |
| \((1-K)P\) 和一般式 | \((1-K)P\) 只在最优 \(K\) 下成立,一般情况用 \((1-K)^2P + K^2R\) |
| \(P\) 和 \(P_{\text{新}}\) | \(P\) 是融合前预测的不确定度,\(P_{\text{新}}\) 是融合后的 |
| \(Q = 0\) 和延迟 | \(Q = 0\) 会让 \(K \to 0\),模型一旦失配,滤波器会发散,而不只是延迟 |
这个模型缺了什么
再看刹车段的结果:即使 \(Q = 0.01\),均方根误差 0.76 m 仍然比直接用雷达读数(0.30 m)还差,而且误差在慢慢变大。
原因在预测公式 \(\hat{x}_{\text{预测}} = \hat{x} + v\,\Delta t\) 里:\(v\) 是写死的 −10 m/s。前车刹车后,真实的靠近速度越来越大,滤波器却每帧都按 −10 m/s 预测。雷达每帧把位置往回拉,下一帧预测又按错误的速度跑偏。调大 \(Q\) 只能让它更快被拉回来,不能解决根本问题。
根治的办法是让滤波器把速度也作为状态来估计。这会带来几个新问题:
- 雷达只测距离时,怎么修正从未被直接测量的速度?
- 速度的修正幅度应该由什么决定?
- 位置误差和速度误差是否有联系,怎么描述这种联系?
这些问题会引出协方差矩阵和多维卡尔曼滤波,留到下一篇。
配套程序见 examples/kalman-1d,只用 Python 标准库,随机种子固定,结果可复现。