做RM电控的同学,十个里有九个第一次翻开卡尔曼滤波资料时,脑子里是空白的。明明“预测”和“更新”这两步用嘴讲都能懂,可一到公式,满屏的矩阵符号直接把你劝退。标题里的“卡尔曼滤波前瞻-矩阵分析基础”,其实就是干这件事的:在真正碰卡尔曼滤波之前,先把线性代数里那些和它强相关的矩阵分析工具啃下来。这篇文章不讲抽象的数学定理,而是从RM电控里真实会碰到的状态估计问题出发,把状态向量、转移矩阵、协方差矩阵、雅可比矩阵这些东西挨个拆开。适合谁看?适合已经会写一点C语言、准备上卡尔曼滤波但数学没底的同学,也适合被扩展卡尔曼滤波折磨过的老队员。
1. 为什么卡尔曼滤波会让电控人栽在数学上
1.1 一个真实场景:云台瞄准怎么调都“飘”
我以前调步兵云台,视觉识别给出一组带噪声的目标角度。直接把角度送给云台Yaw轴跟踪,瞄准线像喝醉了酒一样左右摆。换低通滤波,噪声是压住了,但滞后特别严重,对面装甲板一加速,弹丸全打在尾巴上。后来决定上卡尔曼滤波。按网上的教程写出状态方程和观测方程:
x_k = A x_{k-1} + B u_k + w_k
z_k = H x_k + v_k
然后就开始头疼了。A矩阵是什么?H矩阵怎么构造?P、Q、R四个矩阵的初始值给多少?这几个矩阵里任何一个理解不到位,滤波器要么发散,要么比低通还钝。这个场景我相信很多RM队员都经历过,尤其是电控刚入门、视觉那边又催着要落地的赛季中期。
1.2 卡尔曼的五个公式里,每一步都在做矩阵运算
标准卡尔曼滤波更新流程已经很固定了:
预测:
x̂_k⁻ = A x̂_{k-1} + B u_k
P_k⁻ = A P_{k-1} Aᵀ + Q
更新:
K_k = P_k⁻ Hᵀ (H P_k⁻ Hᵀ + R)⁻¹
x̂_k = x̂_k⁻ + K_k (z_k - H x̂_k⁻)
P_k = (I - K_k H) P_k⁻
如果不懂矩阵乘法、转置、逆矩阵,这里面每一个符号都是天书。其实逻辑本身不复杂:A把上一时刻的状态推到当前,P代表对状态信任程度的不确定性,Q是模型自己带的过程噪声,H把状态映射到传感器观测的空间,K则是“该信预测还是信测量的权重”。但矩阵不是数,乘法交换律不成立,求逆也不是简单除一下,这才是卡壳的地方。
1.3 学矩阵分析前你要先转换心态
很多同学问:“我是不是要把线性代数整本书学完才能看卡尔曼?”我的经验是:不需要。你只需要把矩阵当成“一组数按规则组织起来的容器”,然后掌握乘法、转置、逆、行列式、特征值、矩阵求导这些工具就够了。卡尔曼用到的矩阵分析是应用工具箱,不是数学系的抽象空间。重点是学会什么时候用哪个运算,而不是背证明。等你真的用滤波解决过几个问题,再回头补理论,效率会高非常多。
2. 矩阵分析第一课:把卡尔曼的“状态”装进矩阵
2.1 状态向量与状态转移矩阵:从坐标变换说起
RM里最常见的状态估计是云台角度。假设我们估计两个量:当前角度θ和角速度ω。状态向量可以写成:
x = [θ, ω]ᵀ
忽略控制输入时,匀速旋转模型的物理关系是:
θ_k = θ_{k-1} + ω_{k-1} · dt
ω_k = ω_{k-1}
把它们打包成矩阵形式就是 x_k = A x_{k-1},其中:
A = [[1, dt], [0, 1]]
如果认为电机有一个角加速度控制量 a,那么还需要一个控制输入项 B u_k,这里 B = [[0], [dt]],u = a。
这个例子想说明:A矩阵并不是什么神秘的东西,它就是把上一时刻的多路物理量线性组合到当前时刻。对RM电控来说,最常用的状态量是角度、角速度、加速度、位置、速度这些。建模时只要把“下一时刻等于什么”写清楚,矩阵自然就出来了。很多同学一上来就抄别人的A矩阵,抄完不知道每个元素代表什么,滤波效果差了也没法调。
2.2 向量与矩阵的维度:为什么乘法顺序不能乱
普通数乘法满足交换律,a乘b和b乘a结果一样。矩阵不满足。A B和B A大多数时候不但数值不同,连维度都可能不匹配。卡尔曼滤波里常用的符号维度是这样的:
| 符号 | 维度 | 说明 |
|---|---|---|
| x | n×1 | 状态向量 |
| A | n×n | 状态转移矩阵 |
| P | n×n | 协方差矩阵 |
| Q | n×n | 过程噪声协方差 |
| z | m×1 | 观测向量 |
| H | m×n | 观测矩阵 |
| R | m×m | 测量噪声协方差 |
| K | n×m | 卡尔曼增益 |
为什么预测协方差是 P_k⁻ = A P_{k-1} Aᵀ,而不是 Aᵀ P A?这里不光要维度对,物理意义也要对。P是状态空间里的不确定性,A从上一时刻的状态空间映射到当前时刻,所以左边乘A就不要了?不对,矩阵乘法不交换,P两边都要和A发生关系。A在左、Aᵀ在右,正好保证结果仍然是n×n,而且保留了状态演化对不确定性的影响。
另一个重点是H矩阵。假设用编码器测角度,但角速度不可直接观测,那么m=1,H = [[1, 0]]。K矩阵就是n×m,也就是2×1。这个维度匹配关系,写代码的时候最好用注释标出来:“此处矩阵乘法,左矩阵列数必须等于右矩阵行数”。在ARM上跑滤波,一不留神就会数组越界,轻则滤波乱跳,重则HardFault。
2.3 单位矩阵、转置和逆矩阵:卡尔曼公式中的“还原”操作
单位矩阵I是矩阵里的“1”,任何矩阵乘I不变。转置Aᵀ把行和列互换,很多公式里出现Aᵀ,是因为要把误差从观测空间映射回状态空间。逆矩阵A⁻¹相当于矩阵里的“除法”,用来解线性方程组。
卡尔曼增益里的这个组合 (H P⁻ Hᵀ + R) 是m×m矩阵。H P⁻ Hᵀ 把状态协方差变换到观测空间,R加上测量自身的噪声,整个矩阵描述了“预测测量值的不确定性”。对它求逆,就能把修正量折算回状态空间。多传感器融合时,R从标量变成矩阵,这个逆必须用矩阵求逆算法实现。大一大二学的线性代数里,2×2矩阵可以直接套公式,n>3的时候要写LU分解或者用现成矩阵库。RM比赛通常建议自己维护一套轻量矩阵库,把所有运算封装好,后期调LQR控制器也能复用。
这里有一个容易忽略的点:单位矩阵I的维度是n×n,但在P_k = (I - K_k H) P_k⁻ 里,K_k H 是n×n,I也必须取n×n,不是默认的2×2或者3×3。维度随状态向量数量变化,建议用宏定义。
3. 协方差矩阵:RM赛场上误差传播的数学账本
3.1 方差到协方差:单个量到多个量的不确定性
先回顾一个变量的方差σ²:它表示这个量自身波动的剧烈程度。两个量一起波动时,还需要知道它们是同向还是反向,这就是协方差。把所有状态量两两之间的协方差排成一个方阵,就是协方差矩阵P。
对角线是每个状态量自己的方差,非对角线是不同状态量之间的相关性。卡尔曼滤波每一步都在更新这个矩阵,因为它代表着我们对当前状态估计的“信任程度”。
Q和R不是随便填的。Q大,说明你觉得模型本身不靠谱,于是P会被冲大,滤波更愿意相信测量;R大,说明你觉得传感器噪声大,滤波会更平滑但反应迟钝。RM里常见错误是一律把Q和R设成0.01,结果滤波效果和普通低通差不多,白写一堆矩阵运算。正确做法是先估一下传感器噪声方差,编码器读数在静止时的抖动范围,再反推R;Q则结合模型误差设定,比如忽略摩擦阻尼时,Q可以稍微给大一点。
3.2 卡尔曼滤波里的P矩阵为什么要不断更新
预测步骤里,P_k⁻ = A P_{k-1} Aᵀ + Q,表示老的不确定性在状态演化中传播,再加上过程噪声带来的新不确定性。更新步骤里,P_k = (I - K H) P_k⁻,表示观测给了一部分信息后,不确定性缩小了。
有人为了省事,把P矩阵从头到尾设成一个固定对角矩阵,不更新。短期看也能工作,但一旦状态突然发生大幅度变化,比如云台被弹丸砸了一下,固定的P会让滤波反应不过来。P就像是滤波器的“自信心账本”,它一直在线,你才能真正自适应。
举一维弹丸测速的例子:摩擦轮速度传感器偶尔丢包,模型又有打滑扰动。如果P更新不及时,滤波对突变的响应会非常慢。一维还好办,到二维状态时,P的非对角线开始反映“角度估计误差”和“角速度估计误差”之间的相关程度。比如角度偏了,很可能角速度也偏了同一方向,这种相关性能在后续预测中自动传递给下个时刻。这是低通滤波永远做不到的。
3.3 对角化与相关性问题:IMU数据融合的一个例子
IMU姿态估计里,经常把状态设计成[姿态角,角速度,加速度计漂移]。加速度计和陀螺仪都有误差,它们对姿态角的影响会耦合在一起,P矩阵的非对角项就会非零。如果非对角项一直很大,说明系统状态之间存在强耦合,不能简单地拆开单独处理。
矩阵分析里的“对角化”概念可以帮助理解:通过特征向量变换,可以把一组耦合的变量旋转到一个新坐标系里,让它们的误差解耦。实际调试中你不必真的去对角化,但理解这个过程能帮你读懂论文里“白噪声化”“解耦”的说法。
有个新队员把协方差矩阵P的非对角项全部强制清零,理由是“我状态量看起来没关系”。结果滤波精度下降不少。除非状态量在物理上完全独立,否则不要手动删除非对角项。就算你在建模时觉得无关,数据里的相关性也可能来自控制耦合或者机械安装误差,P矩阵本来就应该把它们体现出来。
4. 矩阵求导与雅可比矩阵:非线性系统里的“线性化”工具
4.1 雅可比矩阵到底是什么
RM里很多模型不是线性的。云台转角到像素坐标的变换,里面有旋转矩阵和相机投影;弹道估计要考虑空气阻力,这些方程没法写成固定的A矩阵。这个时候要用扩展卡尔曼滤波(EKF),核心思想是把非线性函数在当前估计点附近做一阶泰勒展开,展开后的导数矩阵就是雅可比矩阵。
雅可比矩阵本质就是“多输入多输出函数对每个输入求偏导,然后排成一个表”。假设状态是[p, q]ᵀ,测量方程是两组非线性函数:
z₁ = f₁(p, q)
z₂ = f₂(p, q)
那么观测雅可比矩阵就是:
H = [[∂f₁/∂p, ∂f₁/∂q], [∂f₂/∂p, ∂f₂/∂q]]
举个RM里的直觉例子:镜头看到的装甲板像素位置与云台转角的关系。当目标在画面中心时,像素偏移和云台转角近似线性;当目标在画面边缘,畸变变大,非线性增强。EKF每一帧都在算一个局部的线性化近似,等于沿着一根弯曲的路径不断画切线,每走几步就画一条新的。
4.2 用雅可比矩阵做卡尔曼滤波的近似:EKF的思路
EKF的预测和更新与线性卡尔曼基本相同,只是把A和H替换为当前估计值处函数对应的雅可比矩阵 A_j 和 H_j。因为每次估计值都变,雅可比矩阵也要跟着更新。
这个近似只有在当前点附近才准。如果系统强非线性,比如云台在极限角度附近出现机械限位打滑,EKF可能发散。这时可以考虑无迹卡尔曼(UKF)或者粒子滤波,但计算量会上去。对RM大部分应用来说,EKF足够解决云台和底盘的问题。
写EKF时,矩阵求导结果要在嵌入式上实时计算。解析推导太复杂时,可以用数值差分近似。比如求∂f/∂x,就用(f(x+ε)-f(x-ε)) / (2ε)。ε不能太小,否则浮点截断误差会占主导;也不能太大,否则线性化误差太明显。实际调试时建议先用Python把解析式算出来,和数值差分结果对比,确认解析实现没有手滑。
4.3 实战:摩擦轮测速的温度漂移补偿中用得到的导数模型
RM电控里有一个容易被忽视的场景:超级电容放电时电压会持续下降,摩擦轮电机的响应会跟着变化。如果只把摩擦轮转速当成状态,电压变化对转速的影响就会被当成随机噪声滤掉。但如果你把电压也写进状态方程,那“电压变化对转速的影响系数”就是一个偏导数,它会出现在雅可比矩阵里。
例如状态里有转速v和电压U,状态方程写成:
v_k = v_{k-1} + c·U_k·dt
这里c是固定系数,但如果考虑摩擦阻力随温度变化,c会变成v和温度的函数,所以需要重新求导。链式法则是关键:复合函数求雅可比,等于中间雅可比矩阵相乘。矩阵乘法不满足交换律,所以推导的时候每一步顺序都要小心,最好在纸上画变量依赖图,再对照矩阵乘法顺序。
实际项目里,我不建议手推特别复杂的雅可比,容易错。先用MATLAB/Python写符号推导,再把结果整理成C代码,然后用一个真实的log数据离线跑一遍,看滤波值和原始传感器值是否贴合。这样能省一个赛季的调试时间。
5. 特征值与特征向量:判断系统收敛性的一扇窗
5.1 矩阵作用于向量时,方向不变意味着什么
矩阵A表示一个线性变换。如果有非零向量v满足 A v = λ v,那么v是A的特征向量,λ是特征值。意思是这个矩阵对向量v只做长度伸缩,不改变方向。
在卡尔曼滤波里,A矩阵的特征值能告诉我们系统开环的稳定性。比如云台匀速旋转模型A=[[1,dt],[0,1]],特征值是两个1,说明这个模型本身临界稳定——既不会自己收敛,也不会很快发散。角度和角速度会按照模型一直推算下去,真正让误差变小的是后面的测量更新,也就是“反馈”。
5.2 离散系统稳定性与卡尔曼滤波收敛的关系
对于离散系统 x_k = A x_{k-1},如果所有特征值的模都小于1,系统会收敛;大于1会发散;等于1刚好处在边界。卡尔曼滤波的预测步骤里,如果A本身不稳定,P矩阵会越来越大,更新步骤又会用测量修正把P拉回来。滤波能不能收敛,还和系统的可观测性有关,也就是H矩阵能不能通过测量把所有状态量都“看透”。
RM里的一个现象:滤波输出疯狂增长,很多人的第一反应是Q、R没调好。其实更快的方法是检查A矩阵的写法。比如把dt写成0.01,但实际控制周期是0.002,意味着每个周期里模型多推了5倍的角度和角速度,特征值自然会偏离真实。A矩阵写错时,特征值往往已经大于1,离线分析很容易抓出来。
5.3 用特征值分析避免滤波器发散
写代码实现卡尔曼滤波后,建议先做一件事:把测量更新禁用掉,只保留预测步骤,看P矩阵会不会发散。如果预测步骤里P越变越大,说明模型本身不可观测或者A取错了。然后再启用K更新,看P是否收敛到一个比较小的稳态值。
当P收敛到稳态后,卡尔曼增益K会趋于常数。这个稳态增益对应的是代数黎卡提方程的解。实际工程里,如果主控算力吃紧,可以先在线算一段时间,等P收敛到阈值后,切换成常数K,省掉每一步的矩阵求逆。RM主控资源有限,这个技巧很划算。但要注意,比赛过程中车速、射速、环境温度都会变,常数K并不总是最优。折中办法是每隔一段时间重新打开在线计算,或者用一组特征值变化很敏感的标志量触发重新初始化。
矩阵特征值还有一个用途:判断滤波器的响应速度。特征值模长越接近0,滤波衰减越快;接近1,滤波越“钝”。这和低通滤波器的截止频率在概念上很像,只不过卡尔曼的“截止频率”会随噪声环境自适应变化。
6. 从矩阵到卡尔曼:RM电控里最常见的五个数学坑
6.1 矩阵维度不匹配:运行时断言崩溃
C语言里没有运行时维度检查,矩阵乘法维度不对会访问越界,表现往往是滤波结果随机跳变或者程序卡死。解决办法是建立统一的矩阵结构体,比如:
typedef struct { uint8_t rows; uint8_t cols; float data[8][8]; } Matrix;在矩阵乘法函数里先检查左矩阵列数是否等于右矩阵行数,不相等就返回错误码。调试阶段打开断言,让程序在出错时立刻停在对应行,然后再定位是哪个矩阵的维度设计错了。这样能省下大量查数组越界的时间。
6.2 逆矩阵不存在:奇异问题
卡尔曼增益里要对 S = H P Hᵀ + R 求逆。如果R是全零矩阵,而H P Hᵀ又奇异,S就不可逆,程序直接算出无穷大。实际使用中R对角线要保证为正,也就是每个传感器都至少有一点噪声估计,这样S才是正定矩阵,逆一定存在。
有些同学把P0初始化成全零矩阵,这也不合适。P0全零代表“我完全相信初始状态”,滤波器在后续很长时间里不太敢修正,收敛很慢。建议P0对角线取比较大的值,比如角度方差给1,角速度方差给100,表示“我其实不确定初值”,这样滤波器会快速往真实值靠拢。
6.3 数值误差累积:P矩阵非对称
浮点运算经过大量迭代之后,P矩阵会因为舍入误差逐渐失去对称性,甚至出现对角线为负的“负方差”。负方差显然没有物理意义,会导致滤波发疯。解决办法很粗暴:每次更新完P之后,强制做一次对称化:
P = (P + Pᵀ) / 2
这个操作几乎不增加计算量,但对稳定性帮助很大。矩阵求逆和特征值计算之前尤其要保证P对称。很多标准库内部会默认输入是对称阵,如果你的P已经漂移得不对称,结果会不可预测。
6.4 初始化不当导致滤波收敛慢
卡尔曼滤波需要x0和P0。x0可以用第一帧传感器读数初始化,比如角度直接读编码器,角速度读陀螺仪。P0代表初值的置信度。如果P0设得特别小,滤波会长时间“迷信”x0,实际运动起来要几十毫秒才能跟上;如果P0设大一点,滤波器会快速修正。RM项目上电瞬间云台角度是确定的,但角速度往往未知,我习惯把角速度的方差给大一些,让滤波器初期更信任陀螺仪的数据来修正。
6.5 忘记时间戳:状态转移在不同频率下的问题
A矩阵里的dt必须和实际控制周期一致。有的同学在主循环里写死dt=0.002,但被视觉算法拖一下,实际循环变成0.003甚至0.005,模型和真实物理系统就错位了。更靠谱的做法是每一步读取系统时间,计算真实的dt,然后动态更新A矩阵。
这个坑听起来不算矩阵分析,但其实是矩阵应用里最要命的。因为A矩阵一旦和真实时间不匹配,特征值偏离,协方差的传播也不对,后面矩阵运算做得再漂亮都没用。这也是为什么卡尔曼滤波在RM赛场上“落地难”的常见原因之一。
7. 自测与建议的学习路径
7.1 五个小练习带你过一遍矩阵分析
与其看一堆理论,不如动手自测。这五个练习都是我带新人时用过的,难度递增,但都和卡尔曼相关:
- 给定A=[[1,0.01],[0,1]],P0=[[1,0],[0,4]],手算 A P0 Aᵀ,写出结果。
- 默写2×2矩阵[[a,b],[c,d]]的逆矩阵公式,并说明什么时候不存在。
- 用一组IMU静止数据,计算加速度计x、y两轴的方差和协方差,填进2×2协方差矩阵。
- 给定函数 f(θ,ω) = θ + ω·dt + 0.5·sin(θ)·dt²,对θ和ω求偏导,构造雅可比矩阵。
- 求矩阵A=[[0.9,0.1],[0,0.95]]的两个特征值,判断系统是否稳定。
做完这几个练习,再回头看卡尔曼五个公式,你会觉得流畅很多。
7.2 推荐资料与使用顺序
网上经常搜到“矩阵分析史荣昌pdf”这类资源,但我不建议一上来就啃教材正文。对RM电控来说,先建立几何直觉比刷证明重要。可以先看3Blue1Brown的线性代数本质系列,把“线性变换”“特征向量”“矩阵乘法”的几何意义搞清楚;然后找一份带例子的卡尔曼滤波教程,用Python跟着实现一遍;最后如果想去证明收敛性、推导EKF的雅可比矩阵,再去翻矩阵分析教材。按这个顺序走,效率最高。
7.3 我的个人经验:边写代码边补数学效果最好
我带新人最有效的办法不是先讲完线性代数再讲卡尔曼,而是直接给一套能跑的卡尔曼代码,把P和K的更新中间量打日志出来,每个矩阵用表格打印。让他们观察角度误差如何随P变化,增益如何根据噪声调整。矩阵运算在数值上的表现看得多了,再回头补理论,速度会快很多。
数学重要,但要带着问题学。比如“为什么K矩阵要乘一个Hᵀ?”,光看书可能记不牢。一旦你代码里预测值和观测值维度对不上,调试到半夜之后,这个问题会刻进DNA。RM电控的学习节奏本来就很紧,与其按部就班啃教材,不如直接从实际现象出发,把矩阵分析当成工具,用到哪学到哪。
最后分享一个我自己的习惯:每次在嵌入式上写一段矩阵运算,我都会先用电脑脚本跑一遍同样的运算,对比数值结果。卡尔曼滤波里的矩阵分析不是考试,是你手里的扳手。把这一课补完,后面再看LQR、状态观测器、IMU姿态解算,你会发现到处都有它的影子。祝各位在赛场上滤波不发散,调车不顺的时候少一点。