第三章 线性高斯估计(优化版)

Chapter 3   Linear-Gaussian Estimation (Optimized)


本章导航 / Chapter Navigator

一句话总结(TL;DR)

当运动和观测都是线性的、噪声都是高斯的时候,最优估计有闭式解。从”一次性算所有时刻”的批量方法,可以分解出”一步步往前算”的卡尔曼滤波器。

阅读路径建议:

  • 🟢 快速浏览:读完”直觉图解”即可把握核心思想
  • 🔵 理解算法:阅读”概念层”的公式和解释
  • 深度推导:展开”推导层”查看完整数学

3.1 批量估计:交卷前可以回头检查

🎯 直觉:为什么要”批量”?

想象你在做一道多步计算题:

  • 在线估计(滤波器):做完第3步就不能改了,继续往后做
  • 批量估计(平滑器):交卷前可以回头修改任何一步,因为你知道后面的答案也能帮助判断前面是否正确

关键洞察:如果允许使用”未来的测量”来修正”过去的估计”,精度会更高。


🔑 概念层:问题设置

我们有一个随时间移动的东西(比如机器人),用离散时刻 描述。

运动模型(即使没有观测,我们也大概知道它会怎么动):

观测模型(传感器告诉我们一些关于状态的信息):

符号速查: 是状态(位置/速度等), 是观测, 是状态转移矩阵, 是观测矩阵。波浪号 表示”大约等于”(因为有噪声)。

目标:给定所有观测 和初始猜测,估计所有时刻的状态


📐 推导层:最小二乘求解

展开:如何将问题转化为线性系统

把所有状态堆成一个大向量:

把所有方程(运动 + 观测)写成矩阵形式:

其中 包含所有观测和初始先验, 是稀疏矩阵。

MAP 估计等价于最小化:

求导并令为零:

这就是著名的正规方程(Normal Equations)。

关键观察 是块三对角矩阵(每个时刻只与相邻时刻耦合),这使得求解可以高效进行。


3.2 Cholesky 平滑器:稀疏性的力量

🎯 直觉:为什么批量估计可以很快?

个时刻,每个状态 维,总共有 个未知数。直接求逆矩阵的复杂度是 ——当 时根本算不完。

物理世界有个特性:时刻 只与 直接相关(马尔可夫性)。这导致 矩阵非常稀疏——大部分是零!

形象地说, 长这样(空白=零):

这叫做块三对角结构。


🔑 概念层:两步求解法

利用 Cholesky 分解 ,其中 是下三角矩阵。

第一步:前向传递(求

由于 是下三角,可以从上到下依次求解(像多米诺骨牌)。

第二步:后向传递(求

由于是上三角,可以从下到上依次求解。

复杂度 —— 与时刻数 成线性关系!比直接求逆快 倍。


📐 推导层:前向-后向算法

展开:块三对角系统的递归求解

的块三对角分解为:

前向传递(Forward Pass)

对每个

后向传递(Backward Pass)

这就是 Cholesky 平滑器的完整算法。


3.3 RTS 平滑器:协方差形式更直观

🎯 直觉:Cholesky 的”协方差版本”

Cholesky 平滑器工作在”信息域”(处理 )。

但更常见的是用协方差 思考——“我的估计误差有多大?”

RTS 平滑器与 Cholesky 平滑器数学等价,但全用协方差表示,更直观。


🔑 概念层:两步算法

第一步:前向滤波(卡尔曼滤波器)

,计算并存储:

  • 先验估计 :基于过去所有数据
  • 后验估计 :再加上当前观测

第二步:后向平滑(用未来数据修正过去)

直观理解:

  • :未来数据揭示的”预测误差”
  • :我们该相信这个误差多少?(如果运动模型很准,就别太信;如果运动模型不准,就多信)

🧮 数值示例:一维运动

假设一个物体沿直线运动,我们观测它的位置。

设置

  • 真实位置:时刻0在0,时刻1在10,时刻2在20(匀速运动)
  • 观测噪声:标准差 2
  • 运动模型假设:每步大约移动 10,但不确定(标准差 3)

前向滤波结果

时刻观测滤波估计滤波标准差
01.21.22.0
18.59.11.6
222.320.51.4

平滑后结果

时刻平滑估计平滑标准差
00.81.2
110.21.1
220.51.4

观察

  • 时刻0的估计从 1.2 修正到 0.8(更接近真实值0)
  • 时刻0的不确定性从 2.0 降到 1.2(用了未来信息)
  • 时刻2是终点,没有未来信息,所以不变

📐 推导层:从 Cholesky 到 RTS

展开:两种平滑器的等价性证明

RTS 平滑器的后向传递可以写成:

其中

这等价于 Cholesky 平滑器的后向传递:

通过 SMW(Sherman-Morrison-Woodbury)恒等式可以证明两者代数等价。

关键观察

  • Cholesky:工作在信息矩阵域,数值更稳定
  • RTS:工作在协方差域,更直观易懂
  • 两者给出完全相同的估计结果

3.4 卡尔曼滤波器:只往前看的在线估计

🎯 直觉:为什么需要”滤波器”?

前面的平滑器都需要”交卷后回头检查”——但在很多场景下,我们必须实时做决策:

  • 自动驾驶汽车:不能等到旅程结束才知道5秒前在哪里
  • 火箭导航:不能等到着陆后再修正轨道
  • 机器人避障:必须现在就知道当前位置

卡尔曼滤波器就是 RTS 平滑器的前向部分——只用过去和现在的数据,不用未来数据。


🔑 概念层:预测-校正循环

每个时刻,重复两个步骤:

1. 预测(Prediction)

根据运动模型,从上一时刻预测当前时刻:

直观:运动模型告诉我们”应该在哪里”,但不确定性会累积(

2. 校正(Correction)

拿到观测后,融合预测和观测:

直观:

  • :观测与预测的差距(新息 Innovation
  • (卡尔曼增益):该信预测还是信观测?如果观测噪声小( 小),就多信观测

🧮 数值示例:跟踪飞行中的球

假设你扔一个球,用摄像头观测它的位置。

状态(位置,速度)

运动模型(重力作用):

观测模型(只看到位置):

卡尔曼滤波的神奇之处

  • 即使只观测位置,滤波器也能自动估计出速度
  • 速度估计不需要显式微分(微分会放大噪声)
  • 这是通过运动模型的物理约束”隐式”估计的

📐 推导层:卡尔曼滤波器的五种等价形式

展开:不同形式的卡尔曼增益

形式1(信息形式)

形式2(协方差更新形式)

形式3(Joseph形式,数值稳定)

这些形式通过矩阵求逆引理相互等价。实际应用中根据维度和数值稳定性选择。


3.5 三种方法的统一视角

🎯 核心结论

方法信息使用计算复杂度应用场景
批量估计过去+未来离线分析、地图构建
RTS平滑器过去+未来需要协方差形式的离线分析
卡尔曼滤波器仅过去 每步实时估计、在线控制

关键洞察

  1. 它们都是同一个优化问题的解
  2. 区别只在于”能否用未来数据”
  3. 如果噪声是高斯的、模型是线性的,这些方法都是最优的(MVU:最小方差无偏)

本章自检清单

阅读完本章,你应该能回答:

  • 为什么批量估计比逐点估计更准?(因为用了未来信息)
  • 为什么 可以优化到 ?(利用块三对角稀疏性)
  • 卡尔曼增益 的直观意义是什么?(预测 vs 观测的信任分配)
  • 平滑器和滤波器的本质区别是什么?(能否用未来数据)

如果以上都清楚,恭喜你掌握了线性高斯估计的核心!


延伸阅读与代码

Python 实现(伪代码):

def kalman_filter(x0, P0, A, C, Q, R, measurements):
    """
    线性卡尔曼滤波器
    """
    x = x0  # 初始状态估计
    P = P0  # 初始协方差
    estimates = []
 
    for y in measurements:
        # 预测
        x_pred = A @ x
        P_pred = A @ P @ A.T + Q
 
        # 校正
        S = C @ P_pred @ C.T + R  # 新息协方差
        K = P_pred @ C.T @ np.linalg.inv(S)  # 卡尔曼增益
        x = x_pred + K @ (y - C @ x_pred)  # 状态更新
        P = (np.eye(len(x)) - K @ C) @ P_pred  # 协方差更新
 
        estimates.append(x)
 
    return estimates
 
 
def rts_smoother(filter_estimates, filter_covariances, A, Q):
    """
    RTS 后向平滑器
    """
    K = len(filter_estimates)
    x_smooth = [None] * K
    P_smooth = [None] * K
 
    # 从最后一个时刻开始
    x_smooth[-1] = filter_estimates[-1]
    P_smooth[-1] = filter_covariances[-1]
 
    # 后向传递
    for k in range(K-2, -1, -1):
        # 预测(前向滤波时存储的)
        x_pred = A @ filter_estimates[k]
        P_pred = A @ filter_covariances[k] @ A.T + Q
 
        # 平滑增益
        G = filter_covariances[k] @ A.T @ np.linalg.inv(P_pred)
 
        # 修正
        x_smooth[k] = filter_estimates[k] + G @ (x_smooth[k+1] - x_pred)
        P_smooth[k] = filter_covariances[k] + G @ (P_smooth[k+1] - P_pred) @ G.T
 
    return x_smooth, P_smooth

下一章将进入非线性非高斯世界,这些闭式解不再适用,需要近似方法。