误差状态卡尔曼滤波ESKF理论拆解:从四元数约束到协方差传播

发布时间:2026/10/14 4:55:21
误差状态卡尔曼滤波ESKF理论拆解:从四元数约束到协方差传播 误差状态卡尔曼滤波Error-State Kalman FilterESKF做惯性导航这两年在组合导航、视觉惯性里程计、自动驾驶多传感器融合里几乎成了默认方案。我刚开始啃这套理论的时候最大的障碍不是公式本身而是资料普遍两种走极端要么纯学术、满屏流形和李代数要么直接丢给你一坨代码完全不给“误差状态到底处理了什么本质问题”的解释。这篇先把ESKF的理论骨架按我自己的理解完整拆一遍属于整个学习笔记系列的第一篇后续会结合具体实现和实测数据持续更新。文章适合刚接触组合导航、读过一点卡尔曼滤波但被四元数、姿态误差、协方差传播这些概念绕晕的读者。1. 为什么非得用误差状态全状态EKF的三个坑1.1 四元数均值与单位约束的尴尬如果你直接把常规EKF套到惯性导航上状态里会有位置、速度、姿态四元数、陀螺零偏、加速度计零偏姿态用四元数表示。四元数是个单位约束的四维向量真实姿态是在四维空间的一个球面上叫SO(3)流形。问题就出在这EKF的核心假设是状态服从高斯分布均值加协方差就能完整描述不确定性但这个假设在四元数上天然不成立。你可以做个试验取两个姿态四元数做算术平均结果大概率不是单位四元数。就算你强行归一化那是在“球外”做的投影不是统计意义上的最优均值。更麻烦的是四元数本身的维度是4但有效自由度只有3对应的协方差矩阵是4×4但本质上是奇异的约束关系让协方差变成病态矩阵。为了维持单位约束不少人会在每步更新后手动归一化这属于打补丁不是从根本上解决问题而且归一化会悄悄改变概率分布的形状。误差状态方案就绕开了这个问题姿态误差用三维旋转向量 (\delta\theta) 表示直接定义在SO(3)的切空间上协方差天然是3×3的不涉及多余维度也没有约束要维护。1.2 线性化误差的控制EKF对非线性系统做一阶泰勒展开线性化在“当前估计处”展开展开点离真实状态越远近似误差越大。全状态EKF里如果某个状态估计偏了比如姿态误差达到10度状态转移和观测模型的一阶近似就会引入明显偏差滤波器容易越跑越偏。误差状态的思路完全不同把状态拆成“标称状态”和“误差状态”标称状态用精确的非线性运动学传播误差状态被定义为标称状态与真实状态之间的小偏差。只要滤波器不发散误差状态始终维持在零附近哪怕姿态有30度的初始偏差经过几次观测修正后误差也会被压到很小。在一个小误差附近做线性化一阶近似的精度就高得多这是ESKF在工程上能稳定工作的核心原因。简单说全状态EKF是在大范围区域内强行用直线近似曲线ESKF是确保你始终在小邻域内用直线近似后者的近似代价低得多。1.3 双时间尺度带来的工程红利IMU的频率通常是100Hz到1000Hz而GPS、视觉里程计这类外部观测往往只有10Hz到50Hz。ESKF天然匹配这种频率差高频的标称状态传播只做运动学积分不涉及协方差更新计算量很小低频的误差状态更新才做矩阵运算。等于把“贵”的操作从高频路径挪到了低频路径实时性压力一下就小了。更重要的是误差状态更新完会立刻“归零重置”误差状态量级一直很小意味着卡尔曼增益和协方差的数值都保持在舒适区不容易出现数值不稳定。后面我会详细展开这个“重置”操作它看着简单实际是整个ESKF里最容易出暗病的环节。2. ESKF的状态定义与IMU运动学先把符号约定讲清楚2.1 真实状态、标称状态与误差状态的嵌套关系ESKF里同时维护三个层次的状态概念。真实状态 (x_t) 代表物理世界的真值永远得不到标称状态 (\hat{x}) 是滤波器实时维护的主体用来做运动学积分和输出导航结果误差状态 (\delta x) 是滤波器的“暗账”记录标称状态与真实状态之间的偏差卡尔曼滤波更新的是它。具体到惯性导航状态向量包含位置 (p)、速度 (v)、姿态四元数 (q)、陀螺仪零偏 (b_g)、加速度计零偏 (b_a)。三者的关系定义为[ p_t \hat{p} \delta p,\qquad v_t \hat{v} \delta v,\qquad q_t \hat{q} \otimes \delta q,\qquad b_{g,t} \hat{b}g \delta b_g,\qquad b{a,t} \hat{b}_a \delta b_a ]位置和速度、零偏都是加性关系只有姿态特殊用的是四元数乘法。这里有个必须事先统一的关键约定姿态误差到底在左侧乘还是右侧乘。本文采用右扰动约定即 (\delta q \approx [1, \frac{1}{2}\delta\theta]^T)(\delta\theta) 是三维旋转向量。不同文献可能用左扰动公式里会差一个正负号或者转置对照代码时务必先确认这一点否则移植公式过去全是坑。2.2 IMU测量模型与连续运动学方程先写IMU测量模型。陀螺仪测的是载体角速度加偏置再加噪声[ \omega_m \omega b_g n_g ]加速度计测的是比力注意它测不到重力反而把重力等效为反向加速度。测量方程写作[ a_m R^T(a - g) b_a n_a ]或者反过来写成真实加速度的表达式(a R(a_m - b_a - n_a) g)。这里的 (R) 是载体系到世界系的旋转矩阵(g) 是世界系下的重力向量(n_g)、(n_a) 是陀螺和加速度计的白噪声。模型里默认零偏都是缓变随机游走这个后面会体现在误差状态的噪声项里。标称状态的连续时间运动学写成[ \dot{\hat{p}} \hat{v} ][ \dot{\hat{v}} \hat{R}(a_m - \hat{b}_a) g ][ \dot{\hat{q}} \frac{1}{2} \hat{q} \otimes (\omega_m - \hat{b}_g) ]为什么直接用测量值减去当前零偏估计作为输入因为我们没有真值信号只能把测量当作“带噪声的系统输入”。IMU噪声和零偏估计误差不在这里处理而是全部放进误差状态的动态方程里。这种“明账”和“暗账”分离的思路贯穿整个ESKF。2.3 误差状态连续方程是怎么推出来的把真实状态关系代入真实运动学方程减去标称运动学方程忽略二阶以上小量就得到误差状态微分方程。这个过程我自己手推过一遍非常值得做能帮你彻底摆脱“背公式”的状态。关键结果是[ \delta\dot{p} \delta v ][ \delta\dot{v} -\hat{R}[a_m - \hat{b}a]{\times}\delta\theta\hat{R}\delta b_a - \hat{R}n_a ][ \delta\dot{\theta} -[\omega_m - \hat{b}g]{\times}\delta\theta\delta b_g - n_g ][ \delta\dot{b}g w{bg},\qquad \delta\dot{b}a w{ba} ]速度误差项里的 (-\hat{R}[a_m - \hat{b}a]{\times}\delta\theta) 是姿态误差引起的比力方向偏差(-\hat{R}\delta b_a) 是加速度计零偏误差姿态误差项里的 (-[\omega_m - \hat{b}g]{\times}\delta\theta) 是角速度测量误差引起的姿态变化率偏差(-\delta b_g) 是陀螺零偏误差。([]_\times) 表示三维向量的反对称矩阵它把叉积变成了矩阵乘法。这里要特别强调(\delta v) 里那个负号很容易在推导时搞错最好自己从 (q_t \hat{q}\otimes\delta q) 出发推一遍搞清楚旋转顺序。我当时对着讲义看三遍都没发现问题手推一遍才发现之前符号抄反了。3. 离散化与协方差传播从连续方程到可执行代码3.1 标称状态的离散更新连续方程要落到代码里第一步是离散化。标称状态的更新频率跟着IMU走通常用欧拉积分或者中点法。最朴素的欧拉积分写出来是[ \hat{p}_{k1} \hat{p}_k \hat{v}_k \Delta t\frac{1}{2}\left(\hat{R}k(a{m,k} - \hat{b}_a) g\right)\Delta t^2 ][ \hat{v}_{k1} \hat{v}_k \left(\hat{R}k(a{m,k} - \hat{b}_a) g\right)\Delta t ][ \hat{q}_{k1} \hat{q}k \otimes \exp\left((\omega{m,k} - \hat{b}_g)\Delta t\right) ](\exp(\cdot)) 在这里是旋转向量到四元数的指数映射小角度时可近似成 ([\omega\Delta t]) 对应的四元数。工程上更推荐用中点法甚至四阶龙格库塔处理姿态和速度积分尤其在车辆高动态场景下欧拉积分在高频响应时误差累积会比较明显。但不管是哪种积分标称状态的计算路径都是确定的、可复现的这也方便你先单独跑通这一层再上完整滤波器。3.2 误差状态转移矩阵的组装误差状态是线性时变系统可以写成 (\delta\dot{x} F\delta x Gn)。把上面的误差方程整理成矩阵形式连续时间的 (F) 矩阵是15×15的块矩阵[ F \begin{bmatrix} 0 I 0 0 0\ 0 0 -\hat{R}[a_m - \hat{b}a]{\times} -\hat{R} 0\ 0 0 -[\omega_m - \hat{b}g]{\times} 0 -I\ 0 0 0 0 0\ 0 0 0 0 0 \end{bmatrix} ]噪声输入矩阵 (G) 对应的是速度项里的 (-\hat{R}n_a)、姿态项里的 (-n_g)、零偏项里的 (w_{bg}, w_{ba})[ G \begin{bmatrix} 0 0 0 0\ -\hat{R} 0 0 0\ 0 -I 0 0\ 0 0 I 0\ 0 0 0 I \end{bmatrix} ]离散化的误差状态转移矩阵写成[ \Phi_k \exp(F\Delta t) \approx I F\Delta t ]一阶近似在工程上通常够用因为误差状态本身很小加上姿态误差的交叉项影响有限。如果你比较谨慎可以取二阶展开代价是代码量和计算量略增。我一开始用的一阶近似实测下来没遇到因为这一步导致的精度问题。3.3 噪声协方差的离散化连续时间噪声的协方差矩阵定义为[ Q_c \mathrm{diag}\left(\sigma_a^2 I_3,\ \sigma_g^2 I_3,\ \sigma_{bg}^2 I_3,\ \sigma_{ba}^2 I_3\right) ]离散化后的噪声协方差用一个近似公式[ Q_d \approx \Phi_k G Q_c G^T \Phi_k^T \Delta t ]这个公式把连续白噪声在积分步长内近似为离散等效噪声。如果追求更高精度可以用积分形式 (Q_d \int_0^{\Delta t}\Phi(\tau)GQ_cG^T\Phi^T(\tau)d\tau) 数值求解理论上更合理但实际中一阶近似已经能满足多数组合导航需求。还有一个实用小点协方差矩阵在每步传播后理论上是对称的但浮点运算可能破坏对称性做一些对称化处理 (P (P P^T)/2) 能避免后续卡尔曼增益计算出现病态。4. 观测更新与误差注入修正不是直接加到状态上4.1 观测模型、残差与卡尔曼增益外部观测的通用形式是 (z h(x_t) v)(v) 是观测噪声。把 (x_t \hat{x} \oplus \delta x) 代入在标称状态附近线性化残差就变成关于误差状态的线性函数[ y z - h(\hat{x}) H\delta x v ]这里的 (H) 是观测对误差状态的雅可比矩阵。举几个常见例子GPS位置观测对应 (H [I_3, 0, 0, 0, 0])轮速或视觉测速对应的速度观测是 (H [0, I_3, 0, 0, 0])磁力计或航向观测则对应姿态块上的特定组合。卡尔曼增益照公式算[ K P H^T \left(H P H^T R\right)^{-1} ]更新后的误差状态均值是[ \delta x K y ]注意这里没有减去预测的误差状态因为预测阶段误差状态的均值始终是零。协方差更新用标准式[ P (I - KH)P ]4.2 状态注入四元数用乘法其余用加法拿到 (\delta x [\delta p, \delta v, \delta\theta, \delta b_g, \delta b_a]) 之后把它修正回标称状态。位置、速度、零偏直接加[ \hat{p} \mathrel{} \delta p,\quad \hat{v} \mathrel{} \delta v,\quad \hat{b}_g \mathrel{} \delta b_g,\quad \hat{b}_a \mathrel{} \delta b_a ]姿态必须用四元数乘法[ \hat{q} \hat{q} \otimes \exp(\delta\theta) ]为什么要绕这一下因为如果直接把 (\delta\theta) 加到四元数上四元数马上失去单位约束状态就“掉出流形”了。乘法形式保证 (\hat{q}) 更新后仍是合法四元数。这也是ESKF的核心优雅之处标称状态的姿态始终在流形上走只有误差状态在切空间里做线性操作。4.3 必须做的误差重置与协方差G变换误差状态更新完下一步是把 (\delta x) 清零为下一轮做准备。但这里有个非常隐蔽的坑清零之前当前协方差 (P) 描述的是“旧误差状态”的不确定性清零之后误差状态的定义基准变了协方差必须同步变换到“新误差状态”的坐标系下。这个变换矩阵 (G) 定义为[ G \begin{bmatrix} I_3 0 0 0 0\ 0 I_3 0 0 0\ 0 0 I_3 - [\frac{1}{2}\delta\theta]_{\times} 0 0\ 0 0 0 I_3 0\ 0 0 0 0 I_3 \end{bmatrix} ]然后做[ P \leftarrow G P G^T ]位置、速度、零偏块的雅可比是单位阵只有姿态块因为旋转误差与真实误差之间的雅可比不为单位阵才需要这个修正。当 (\delta\theta) 很小时 (G) 非常接近单位阵所以很多简化实现直接忽略这一步也能跑但长期看协方差会对不上真实误差可能出现“滤波器很自信但实际误差很大”的假收敛状态。我在某个项目里就遇到过这种问题现象是定位结果看起来平滑一对比真实轨迹才发现误差已经悄悄涨到十几米排查下来就是重置G矩阵丢失造成的。5. 工程实现要点与参数调优5.1 初始化流程ESKF对初始化比全状态EKF更敏感因为误差状态方程依赖“误差很小”这个前提。如果初始姿态都差着30度线性化近似会非常吃力。常规做法是先在静止状态下采集几秒IMU数据陀螺仪输出均值作为陀螺零偏初值 (\hat{b}_g)加速度计输出均值除以重力模长得到重力方向算出横滚角和俯仰角初值航向角在没有磁力计或外部航向时可先置0加速度计零偏初值如果无法精确标定可以先设0但要把初值协方差设得比较大让滤波器自己去估计陀螺零偏的初始协方差根据传感器指标设一般设到对应角速率误差的平方级别。我在实际项目里的做法还要加一步“静止检测”用滑动窗口计算IMU输出的方差方差低于阈值才允许进入初始化。初始化期间必须保证设备完全静止否则重力对齐和零偏估计都会被污染后面ESKF就算能收敛也要花很长一段路才能把错误掰回来。5.2 过程噪声怎么定别拍脑袋ESKF调试中最影响手感的就是四个噪声参数加速度计白噪声 (\sigma_a)、陀螺白噪声 (\sigma_g)、陀螺零偏随机游走 (\sigma_{bg})、加速度计零偏随机游走 (\sigma_{ba})。这几个参数如果不匹配会导致滤波器要么过度信任IMU、输出漂得离谱要么过度信任外部观测、输出跟着观测噪声乱抖。参数物理含义典型量级参考(\sigma_a)加速度计噪声密度(10^{-3} \sim 10^{-2} \ \text{m/s}^2/\sqrt{\text{Hz}})(\sigma_g)陀螺噪声密度(10^{-4} \sim 10^{-3} \ \text{rad/s}/\sqrt{\text{Hz}})(\sigma_{bg})陀螺零偏随机游走(10^{-6} \sim 10^{-5} \ \text{rad/s}^2/\sqrt{\text{Hz}})(\sigma_{ba})加速度计零偏随机游走(10^{-5} \sim 10^{-4} \ \text{m/s}^3/\sqrt{\text{Hz}})这些参数最靠谱的来源是 Allan 方差分析或者用转台做离线标定。没有标定条件时先按数据手册给的值设一个初值然后做一组简单实验静止状态下看滤波输出的姿态是否稳定匀速直行看速度反馈是否平滑。过程噪声设小了残差序列会长期偏离零均值设大了协方差会偏大、滤波结果抖动明显。调参不是玄学核心诊断工具就是看 innovation 序列的统计特性。5.3 可观测性视角下的传感器组合搞ESKF不能只会套公式还得理解哪些状态到底能不能被观测到。以IMUGPS这个常见组合为例水平姿态横滚角、俯仰角可以通过加速度计“观测”重力方向来估计所以长时间不漂航向角则完全不可观测纯惯性下会随陀螺零偏和积分误差缓慢漂移要靠磁力计或外部航向观测约束。陀螺零偏在持续转动激励时估计得比较准长时间匀速直线运动时几乎不可观测零偏估计会“冻结”。这个结论直接决定系统设计纯IMU不加外部观测ESKF只能用统计最优的方式把IMU积分误差描述清楚并不能根治漂移。加速度计零偏更是难兄难弟它和姿态误差存在耦合只有车辆有纵向加速度激励的时候才更可观测。理解了这层你就能明白为什么视觉惯性系统里一定要有足够的加速度和角速度激励纯悬停状态对零偏估计完全不友好。5.4 实现避坑清单以下每一条都是我踩过或者看别人踩过的坑整理成清单坐标系约定要统一。IMU加速度计输出的比力方向世界系下重力向量取正值还是负值不同代码库的表达不一样必须先搞清楚。IMU和外部传感器的时间戳必须对齐。哪怕只有几十毫秒的固定延迟都会在残差里引入系统性偏差表现的信号是“滤波器始终有固定大小的innovation”。四元数乘法的左右顺序要和误差定义一致。右扰动下是 (\hat{q}\otimes\exp(\delta\theta))别在某个环节混成左乘。全程用双精度运算。单精度浮点在长时间积分下的累积误差会让姿态精度明显下降。每步对 (P) 做对称化必要时做特征值裁剪确保正定性。加速度计读数如果被归一化成重力倍数要通过数据手册或离线测试确认别稀里糊涂把 (g) 写成9.8又乘一遍。6. 调试经验与常见问题速查6.1 典型故障现象与解决方向调试ESKF时我总结了一套“现象→原因→排查方向”的速查表实际用起来比硬看公式高效得多。现象可能原因排查方向静止时姿态缓慢漂移陀螺零偏初值不准或 (\sigma_{bg}) 设得过大、零偏没被约束住重新做静止初始化调小 (\sigma_{bg})位置发散非常快加速度计零偏未估计或初始姿态误差偏大检查重力方向是否对齐引入速度/位置观测有外部观测但P持续变小且状态不修正更新后忘了把误差状态注入到标称状态只剩协方差变化检查注入代码打印注入前后的位置差值协方差不对称或出现负特征值长期未对称化或重置G矩阵缺失补对称化补G变换四元数模长偏离1标称状态更新时用了加性修正而非乘法修正姿态更新逻辑残差均值始终不为零时间戳对齐有问题或观测模型偏差做延迟标定检查H矩阵6.2 我的标准调试流程我调试ESKF不会直接拿真机数据硬啃而是按下面这个顺序来基本能快速定位问题。第一步先做仿真。用一段已知轨迹生成带噪声的IMU数据先只跑标称状态的前向积分看位置姿态的漂移幅度是否符合理论预测。如果前向积分这一步就不对滤波器再怎么调也没用。第二步在仿真环境里跑完整ESKF逐步加入外部观测。先只加GPS位置看水平姿态和位置能否稳定再加入测速观测看能否进一步压住速度漂移最后加航向观测检查航向收敛情况。每加一种观测都停下来看对应的innovation序列是否满足零均值。第三步切换到真实数据后先做静止数据测试。静止时加速度计均值应该大致等于重力陀螺均值应该接近零偏附近这个阶段发现的异常十有八九是标定问题而不是滤波算法问题。第四步看协方差的收敛情况。仿真中对真实误差归一化统计误差落在3σ以内的比例超过95%就说明协方差标定基本靠谱。真实场景没有真值但可以对比高精度参考系统看滤波输出的不确定度是否和实际误差匹配。6.3 几个真正提升效率的习惯最后分享几个调试中非常管用的习惯。一个是把误差状态的各个分量拆出来单独画曲线不要只盯着总的位置误差这样可以快速看出漂移主要来自姿态误差还是零偏误差。另一个是在代码里把每个环节的中间量都留log接口尤其是 (K y) 的值和注入后的状态增量调试时直接对比这些量能省很多时间。再一个是调参时保持只改一个参数的纪律一次动两三个参数会把问题搅在一起反而更难判断是哪个环节出了问题。这篇文章是我对整个ESKF理论框架的一次系统梳理属于持续更新系列的起点。后续我计划补三块内容一是GNSS、视觉、磁力计等不同观测模型的紧耦合细节二是IMU标定与Allan方差分析的实际操作三是ESKF在视觉惯性里程计里对外参和延迟的估计方法。我自己在协方差重置那个G矩阵上栽过大跟头那次教训让我把所有公式重新手推了一遍所以这篇里凡是涉及符号约定的地方我都尽量写清楚了。如果你在实现中也遇到类似“看着收敛但实际误差不小”的情况大概率也要回头检查一下误差状态定义和重置步骤。先记到这下次更新见。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询