4、数学基础(下):状态估计问题、最小二乘、非线性优化(高斯牛顿、LM算法)、概率论基础(贝叶斯滤波)
好,咱们接着聊数学。上一节我们把矩阵、坐标系这些“硬骨头”啃了一遍。这一节,咱们要碰一碰SLAM里最核心的“软实力”——状态估计和非线性优化。
说实话,这部分是很多人的拦路虎。我当年刚入行时,看到一堆公式也头疼。但后来我发现,只要理解了它要解决什么问题,公式其实没那么可怕。说白了,SLAM就是一个“猜”的过程——猜机器人在哪,猜地图长啥样。而数学,就是让这个“猜”变得靠谱的工具。
4.1 状态估计问题:我们到底在猜什么?
先问个问题:你拿着一个激光雷达,转了一圈,得到了很多点云。然后呢?
你要回答两个问题:
- 我在哪?——这就是机器人的位姿(位置+姿态)
- 周围有什么?——这就是地图(一堆特征点或栅格)
这两个问题合起来,就是状态估计。我们管“我在哪+地图长啥样”叫状态。
核心思想:状态估计,就是根据带噪声的观测数据,反推最可能的状态。
举个例子。你闭着眼睛往前走,每一步都只能靠脚底的感觉猜自己走了多远。这时候,你听到左边有水流声(观测),你猜那是条小河。于是你修正自己的位置——哦,我应该在河边。这就是一次状态估计。
在SLAM里,这个过程被数学化了。我们用运动方程描述“我下一步大概在哪”,用观测方程描述“我看到的东西应该长什么样”。然后,把这两个方程揉在一起,求解。
我的经验:我在做第一个激光SLAM项目时,总想着一步到位把状态算准。结果发现,噪声一多,直接算出来的结果根本没法用。后来才明白,状态估计的本质是“概率”,不是“确定值”。你得接受不确定性,然后用数学去管理它。
4.2 最小二乘:让误差尽可能小
好,状态估计问题有了。怎么解?
最常用的方法,就是最小二乘。
什么叫最小二乘?说白了就是:我有一堆观测数据,每个数据都对应一个“预测值”。预测值和真实值之间有个误差。我想找到一组状态,让所有误差的平方和最小。
为什么是平方?因为平方可以放大大的误差,让优化器更关注那些“离谱”的观测。同时,平方函数是光滑的,方便求导。
数学上长这样:
minimize Σ ||观测值 - 预测值(状态)||²
举个简单的例子。你测了三个点,想拟合一条直线。每个点到直线的距离就是误差。最小二乘就是找一条直线,让所有点到它的距离平方和最小。
注意:最小二乘假设误差服从高斯分布。如果你的传感器噪声不是高斯分布(比如有离群点),那最小二乘的效果会变差。这时候,你需要用鲁棒核函数(比如Huber核)来“压一压”那些大误差。
避坑指南:我曾经在一个项目中,直接用标准最小二乘处理激光雷达的匹配问题。结果发现,一旦遇到玻璃墙(反射率低,点云稀疏),优化结果就飞了。后来加了Huber核函数,才稳定下来。记住:真实世界的噪声,永远比你想象的复杂。
4.3 非线性优化:高斯牛顿法与LM算法
最小二乘问题建好了。但大多数情况下,我们的预测函数是非线性的(比如旋转矩阵、投影变换)。这时候,没法直接求解析解。怎么办?
迭代。一点点逼近。
这就是非线性优化。最常用的两个算法:高斯牛顿法和LM算法。
4.3.1 高斯牛顿法
高斯牛顿法的思路很简单:把非线性函数在当前状态附近做一阶泰勒展开(线性化),然后求解一个线性最小二乘问题,得到状态的更新量。然后重复这个过程,直到收敛。
步骤:
- 给定初始状态 x₀
- 对每个误差项,计算雅可比矩阵 J(一阶导数)
- 构建正规方程:JᵀJ · Δx = -Jᵀe
- 解出 Δx,更新状态:x ← x + Δx
- 重复直到 Δx 足够小
关键点:高斯牛顿法用 JᵀJ 近似海森矩阵。这省去了计算二阶导数的麻烦,但前提是 JᵀJ 必须可逆且正定。如果遇到奇异矩阵,算法就会崩溃。
我的习惯:在实际代码中,我一般不会直接用高斯牛顿法。因为JᵀJ很容易病态,尤其是当状态维度高、观测信息不足时。我会优先用LM算法,它更鲁棒。
4.3.2 LM算法(列文伯格-马夸尔特法)
LM算法是高斯牛顿法的“升级版”。它在高斯牛顿的基础上,加了一个阻尼因子 λ。
正规方程变成了:
(JᵀJ + λI) · Δx = -Jᵀe
当 λ 很大时,LM算法退化为梯度下降法(步长小,稳定但慢)。当 λ 很小时,LM算法接近高斯牛顿法(步长大,快但可能不稳定)。
LM算法会自动调整 λ。如果这次迭代后误差下降,就减小 λ(更激进)。如果误差上升,就增大 λ(更保守)。
实际效果:LM算法几乎总是能收敛,只是速度可能比高斯牛顿慢一点。但在SLAM这种“数据质量参差不齐”的场景下,稳定比速度更重要。
// 伪代码示例:LM算法核心步骤
while (not converged) {
// 计算雅可比 J 和误差 e
// 构建 H = JᵀJ + λI
// 解 H · Δx = -Jᵀe
// 计算新误差 e_new
if (e_new < e) {
λ = λ / 2; // 减小阻尼,更信任高斯牛顿
x = x + Δx;
} else {
λ = λ * 2; // 增大阻尼,更信任梯度下降
// 不更新 x,重新计算
}
}
避坑指南:我曾经在调试一个激光雷达与IMU联合标定的程序时,LM算法的阻尼因子初始值设得太小。结果前几次迭代直接发散,状态飞到了十万八千里外。后来我把 λ 初始值设为 1e-3,并加了状态边界约束,才稳定下来。记住:初始值很重要,阻尼因子也很重要。
4.4 概率论基础:贝叶斯滤波
好,优化讲完了。但SLAM还有一个更底层的视角——概率。
你想想看,传感器有噪声,运动有误差。我们永远无法知道“真实状态”,只能知道“状态的概率分布”。
这就是贝叶斯滤波的用武之地。
贝叶斯滤波的核心公式:
P(状态 | 观测) ∝ P(观测 | 状态) · P(状态)
翻译成人话:
- 先验 P(状态):在拿到新观测之前,我对状态的猜测(比如根据运动模型猜的)
- 似然 P(观测 | 状态):如果状态是某个值,我有多大可能看到当前的观测
- 后验 P(状态 | 观测):结合观测后,我对状态的修正
贝叶斯滤波是一个“预测-更新”的循环:
- 预测:根据运动模型,从上一时刻的后验,预测当前时刻的先验
- 更新:根据当前观测,用似然函数修正先验,得到后验
SLAM中的体现:经典的卡尔曼滤波(KF)就是贝叶斯滤波的一种特例——假设所有分布都是高斯分布。扩展卡尔曼滤波(EKF)则把非线性函数线性化后套用KF框架。而粒子滤波(PF)则用一堆粒子来近似任意分布。
我的看法:在激光SLAM中,纯贝叶斯滤波(如EKF)用得越来越少。因为激光雷达的点云数据量大,EKF的线性化误差在复杂环境中容易累积。现在主流是图优化(就是前面讲的最小二乘+非线性优化)。但贝叶斯滤波的思想依然贯穿始终——你做的每一次优化,本质上都是在最大化后验概率。
嗯,这一节内容不少。从状态估计到最小二乘,再到高斯牛顿和LM,最后回到贝叶斯滤波。你会发现,这些工具其实都在做同一件事:在不确定中寻找确定。
下一节,我们会把这些数学工具真正用到激光雷达数据上。到时候,你会看到点云配准、图优化这些“实战”内容。准备好了吗?