☰
卡尔曼滤波在GPS/INS组合导航中的建模与仿真实践
2026/10/24 1:37:34 网站建设 项目流程

做导航算法这行,大概率都绕不开一个问题:GPS数据明明在跳来跳去,IMU积分又越走越飘,两个传感器单独用都不靠谱,怎么才能拼出一个平滑、准确、连续的位姿输出?我的答案一直是卡尔曼滤波。卡尔曼滤波不是一个高大上的黑盒,它本质上是给两种带误差的信息做加权平均,只不过这个权重不是拍脑袋定的,而是根据模型的预测精度和传感器的量测精度实时算出来的。这篇文章从一个GPS与INS组合导航的滤波模型仿真出发,把卡尔曼滤波用于工程数据处理的思路、建模步骤、仿真实现和调试要点写清楚,适合刚入门组合导航、做机器人定位或者正在被传感器数据噪声折磨的工程师参考。

1. 为什么组合导航里必须有一个滤波器

1.1 GPS定位数据的噪声、跳变和延迟

GPS接收机输出的位置和速度看起来是一条连续轨迹,但如果放在高采样率下去看,静止状态下坐标也会在真值附近跳来跳去。卫星星历误差、电离层和对流层延迟、以及多路径效应,都会折算成定位误差。开阔环境下水平方向的定位误差大概在米级,城市里高楼玻璃幕墙反射一多,跳变能到十几米,甚至出现短暂丢星。

有人会说,那给GPS结果做一个低通滤波不就行了。低通滤波确实能把轨迹抹平,但它的代价是相位滞后:车已经转弯了,滤波后的轨迹还沿着之前的切线方向往外拖。动态场景下这种滞后非常致命。更重要的一点是,低通滤波只能平滑结果,它无法告诉你当前这个平滑结果到底比原始观测可靠多少。而卡尔曼滤波是从动力学模型出发做预测,传感器观测只用来修正预测,天然不会有这种固定相位滞后。

1.2 INS短时高精度,长时必然发散

INS这边的情况正好相反。惯性测量单元(IMU)输出的是加速度计测到的比力和陀螺仪测到的角速度,要想得到位置和速度,就要做积分。积分是这么个东西:小的常值误差在单步内几乎看不见,但积分一段时间后会被放大到不可接受。

我算过一笔很直观的账:假设加速度计有一个常值零偏,约等于0.01 m/s²。把它两次积分100秒,位置偏差大约是0.5 × 0.01 × 100² = 50米。也就是说,一个看起来性能还不错的加速度计,只要零偏没有被估计出来,100秒的纯惯导推算就能偏出去一个足球场的长度。陀螺仪零偏对姿态的影响同理,姿态歪了之后重力分量会混进水平加速度,误差还会进一步加速累积。

这就是为什么实际工程中没有人敢把INS单独当成长期定位手段。INS最大的优势是数据率高,典型IMU有100Hz到1000Hz,短时间内的轨迹非常平滑、连续。GPS恰好相反,数据率低但长期无漂移。两者在数学上是互补的,问题只在于怎么把互补信息揉到一起。

1.3 融合的本质是给两个估计做加权

我们换一种直观的理解方式。假设我对当前位置有两个信息来源:一个是根据惯导模型推出来的预测位置,一个是GPS直接测到的位置。如果这两个东西完全重合,那没什么好说,取谁都行。但它们通常不重合,而且各自的误差水平是变化的。

卡尔曼滤波的厉害之处在于,它不仅知道当前位置是多少,还知道当前位置估计的协方差有多大。预测一步会让协方差变大,观测更新会让协方差变小。更新时增益K会读出一个比例:预测可靠就多信预测,观测可靠就多信观测。这个增益不是人为给定的常数,而是每个时刻都重新计算一次,所以它能跟着运行状态实时变化。这比任何固定权重的加权平均都要合理。

2. 卡尔曼滤波建模里的关键选择

2.1 状态向量怎么定:够用、可观测、好解释

很多入门者第一次建模就想着把所有的量都放进状态向量里,位置、速度、姿态、陀螺零偏、加速度计零偏全都要,恨不得把传感器每一个误差源都列出来。真实工程里我见过不少这样的状态向量,动辄15维、21维甚至更多,结果滤波器调了一个月还在发散。

状态向量该怎么选?我总结三个词:够用、可观测、好解释。所谓够用,是指状态里面至少要把那些会被积分放大的误差源放进去。最简单二维水平定位模型常用7状态:平面位置误差2个、速度误差2个、航向误差1个、陀螺零偏1个、加速度计零偏1个。这个模型适合解释算法原理,跑通流程非常快。完整三维惯导组合通常用15状态:位置误差3个、速度误差3个、姿态失准角3个、陀螺零偏3个、加速度计零偏3个。姿态误差不直接观测,它是通过位置和速度误差间接被激发出来的。

状态维度过高的问题在于可观测性变差。GPS只能提供位置和速度观测,有些误差状态组合是观测不到的,强行估计出来不但没有效果,还会让协方差矩阵变得病态。所以我的习惯是:先从低维度建模跑通流程,确实践不了再往上加状态,而不是一开始就上满配。

2.2 过程噪声Q和量测噪声R的工程理解

卡尔曼滤波有两个噪声参数被讨论得最多:过程噪声协方差Q和量测噪声协方差R。Q描述的是动力学模型本身的不确定性,包括IMU随机噪声、外界扰动、模型简化误差;R描述的是传感器观测的噪声水平。

不少初学者把Q和R当成玄学参数,其实它们的相对大小决定了滤波器的行为。Q相对R越大,滤波器越相信观测,轨迹跟着GPS跳动明显,平滑度差;Q相对R越小,滤波器越相信模型,轨迹平滑但响应迟钝,模型一旦出错就会发散。可以理解成滤波器内部有一个天平,Q是放在模型那端的砝码,R是放在观测那端的砝码。

R的初值最好别靠猜。拿GPS来说,把接收机静置几分钟,记录固定点上的定位结果,用统计学方法算一个标准偏差,这个值就是R的合理来源。IMU随机游走系数一般可以从传感器出厂手册里查到,没有手册也可以拿静止数据做Allan方差分析。Q和R的比值调好后,还要看新息序列是否接近白噪声:如果新息均值明显不为零,说明模型有系统误差;如果新息方差远大于理论值,说明Q给小了。

2.3 线性还是非线性:普通KF、EKF和UKF的选择

这里有一个经常把新人绕晕的选择题:组合导航到底该用普通卡尔曼滤波还是扩展卡尔曼滤波?答案取决于你的状态方程和观测方程是不是线性的。完整的惯导姿态更新里有旋转矩阵、四元数、三角函数,显然是强非线性,直接用线性KF做不了。

工程上真正常用的做法是误差状态卡尔曼滤波。不直接估计位置和姿态的绝对量,而是估计它们相对参考值的误差量。在小失准角假设下,误差状态方程可以线性化,于是又回到了成熟稳定的线性KF框架。这样一来,惯性导航的主流程仍然按机械编排跑,卡尔曼滤波只负责修正误差,模型简单、可靠、好调试。

只有当载体机动过于剧烈,姿态失准角大到线性近似撑不住的时候,才需要考虑EKF或UKF。UKF对非线性更强,但计算量大,调参也更复杂。我的建议是:松组合、小失准角场景先用误差状态线性KF,别一上来就上UKF。

3. GPS与INS组合导航的模型设计细节

3.1 松组合、紧组合、深组合怎么选

GPS与INS的组合方式通常分成松组合、紧组合和深组合。松组合是在导航解层面做融合:GPS接收机自己解算出位置和速度,把它当成观测喂给卡尔曼滤波器。紧组合用的是GPS接收机输出的原始伪距、伪距率,甚至载波相位观测,在观测方程里直接建立伪距与接收机位置的对应关系。深组合则更进一步,把惯性信息用来辅助接收机内部的跟踪环路。

从工程落地难度看,松组合最省事,因为GPS接收机已经替你完成了大部分工作,你只需要拿到位置和速度就行。现在绝大多数消费级、车载级组合导航产品都在松组合或紧组合层面。松组合的短板也很明显:如果GPS可见卫星太少,连一个完整的定位结果都解不出来,松组合就直接失去观测,而紧组合只要有4颗以上卫星的原始观测量就能继续工作。

如果你还处在算法研究阶段,我强烈建议从松组合开始。它把GPS定位部分隔离成黑盒,方便你集中精力理解卡尔曼滤波本身。先把位置和速度融合调通,再往紧组合推进,难度曲线会平缓很多。

3.2 简化模型的状态转移方程怎么建立

接下来直接进入本次仿真的核心模型。我用一个二维平面的简化模型来演示,目的是把卡尔曼滤波的预测和更新每个环节都讲清楚,同时避免三维姿态旋转带来的额外复杂度。状态向量取6维,定义如下:

x = [px, py, vx, vy, abx, aby]^T

前4个是水平位置和速度,后2个是加速度计的常值零偏。为什么要把加速度计零偏放到状态里?因为前面算过账,零偏积分后会引起很大的位置误差,它必须作为状态被估计出来,否则卡尔曼滤波没有办法在预测时把零偏从加速度计读数里扣掉。

离散状态转移方程写成矩阵形式,IMU的加速度计读数作为控制输入u,dt是积分步长:

F = [[1, 0, dt, 0, -0.5dt², 0], [0, 1, 0, dt, 0, -0.5dt²], [0, 0, 1, 0, -dt, 0], [0, 0, 0, 1, 0, -dt], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]

这个矩阵看着复杂,实际含义很好理解。位置等于旧位置加速度时间,加速度对位置的影响由-0.5*dt²项体现,因为状态里存的是ab,预测时要把它从控制输入里减掉。速度同理,零偏项前面对应的是-dt。

3.3 观测方程、坐标系统一和时间同步

GPS给卡尔曼滤波的观测是位置。观测方程z = Hx + v,H只有第一、二列是1,其余为0。如果我们能拿到GPS输出的速度,也可以把它加进观测向量,扩展H的行数,让滤波器在速度维度上也获得修正。R矩阵相应变成4乘4。

这里有一个每篇文章都会提但我还是想再强调的工程细节:坐标系必须统一。GPS输出的经纬度要先转换到局部平面坐标,一般用UTM或者以某点为原点的ENU直角坐标。IMU的数据定义在载体坐标系里,速度定义在导航系里,融合前要完成姿态转换和时间对齐。时间对齐更麻烦,GPS观测通常是整秒对齐,IMU是内部时钟计数,两边的时间戳如果不精确对应,观测就会出现滞后,卡尔曼滤波的新息序列会产生明显锯齿。

做仿真时不觉得这是问题,真机上GPS和IMU时钟不是同一颗晶振,滞后几十毫秒就可能让融合位置在转弯时偏出去一两米。解决思路是记录每个传感器的精确时间戳,在滤波前做线性插值或外推,把两者对齐到同一个参考时刻。

4. 仿真实现:从零搭建一个GPS/INS组合导航滤波模型

4.1 仿真场景与数据生成

仿真场景我设计成一段120秒的平面运动轨迹:前30秒匀速直线,中间30秒带一个缓慢的转弯和加速,后面一段重新进入直线,最后10秒停车。运动学上避免突变,让轨迹自然。IMU设置成100Hz输出,GPS设置成1Hz输出,这比较接近真实工程的比例。

IMU测量在真实轨迹加速度的基础上叠加了高斯白噪声和常值零偏,高斯白噪声标准差取0.05 m/s²,常值零偏取0.02 m/s²和-0.01 m/s²。GPS位置噪声标准差取5米。这些参数如下。

参数数值
IMU频率100 Hz
GPS频率1 Hz
IMU加速度白噪声标准差0.05 m/s²
加速度计常值零偏0.02 m/s², -0.01 m/s²
GPS位置噪声标准差5 m
仿真时长120 s

真值轨迹这一步一定要自己生成,因为最后评估卡尔曼滤波性能需要有“地面真值”。真实系统里不存在完美的地面真值,但仿真里你可以人为定义,这正是仿真最大的价值。

4.2 卡尔曼滤波主循环代码

核心代码我用Python和NumPy实现。状态转移矩阵F、控制矩阵B、观测矩阵H和噪声矩阵由前面模型推导得出。滤波主循环分成预测和更新两步:每个IMU周期都执行预测,每个GPS周期才执行更新,这种双频结构也是真实组合导航的标准写法。

import numpy as np fs = 100.0 dt = 1.0 / fs # 状态向量: [px, py, vx, vy, abx, aby] F = np.array([ [1, 0, dt, 0, -0.5*dt*dt, 0], [0, 1, 0, dt, 0, -0.5*dt*dt], [0, 0, 1, 0, -dt, 0], [0, 0, 0, 1, 0, -dt], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]) B = np.array([ [0.5*dt*dt, 0], [0, 0.5*dt*dt], [dt, 0], [0, dt], [0, 0], [0, 0]]) H = np.array([ [1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0]]) Q = np.diag([0.01, 0.01, 0.01, 0.01, 0.0001, 0.0001]) R = np.diag([25.0, 25.0]) # 5m标准差平方 x = np.zeros(6) P = np.eye(6) * 100.0 history = [] gps_idx = 0 for k in range(len(imu_acc)): # 预测:IMU加速度计读数作为控制输入 u = imu_acc[k] x = F @ x + B @ u P = F @ P @ F.T + Q # 更新:只有到达GPS历元才执行 if gps_idx < len(gps_times) and k == gps_times[gps_idx]: z = np.array(gps_meas[gps_idx]) S = H @ P @ H.T + R K = P @ H.T @ np.linalg.inv(S) innovation = z - H @ x x = x + K @ innovation P = (np.eye(6) - K @ H) @ P gps_idx += 1 history.append(x.copy())

这段代码里有一个容易被忽略的点:imu_acc数组已经在生成时叠加了常值零偏,但卡尔曼滤波里状态ab的初值是0。第一次预测时,滤波器不知道零偏存在,位置和速度会被带偏,直到第一个GPS观测到达,它才从新息里反推误差,把ab修正到接近真值。这个由观测修正不可观测状态的过程,正是组合导航能抑制INS零偏的原理。

4.3 运行结果分析和参数敏感性

跑完这段仿真,你会看到三种曲线。纯GPS的位置轨迹噪声明显,每秒钟跳几下,静态误差在5米量级。纯INS积分轨迹在前30秒看起来不错,但到仿真末尾会偏出几十米。而卡尔曼滤波融合结果的位置误差在第一个GPS更新后就快速收敛,稳态误差在2米以内,轨迹平滑度接近INS,长期准确性接近GPS。

我拿到结果之后还会顺手做一件事:把历史位置误差列表打印出来,检查有没有持续增大的趋势。如果融合误差随时间缓慢上升,那通常不是卡尔曼滤波的锅,而是真值轨迹和IMU模型之间不一致,比如零偏设置方式或者状态转移矩阵的符号写错了。

参数敏感性方面,比较值得亲自动手试的是把R从25改成250。此时滤波器不再信任GPS,融合轨迹会变得非常平滑,但在转弯处会明显跟不上真值,稳态误差变大。把Q从0.01改成0.1则相反,轨迹毛糙得像原始GPS,卡尔曼滤波基本失效,因为预测已经不被信任。所谓调参,本质就是在平滑度和动态响应之间找一个折中点。

5. 实际工程中的坑与排查技巧实录

5.1 滤波发散:看起来稳如老狗,其实已经飘掉

工程中最可怕的状态不是滤波结果乱跳,而是看起来一路平滑但已经缓慢飘走。发散初期很难察觉,往往等载体回到已知区域才发现位置偏出几十米。卡尔曼滤波发散最常见的原因是模型错误和Q设置过小。模型错误包括状态转移矩阵漏项、坐标系用错、时间戳对不齐;Q设置过小则会让滤波器盲目自信,长期忽略观测修正。

排查发散问题我有一个固定的流程。第一步打印新息序列,也就是每一时刻的观测减预测,理论上它的均值应该接近零。如果新息均值稳定偏正或偏负,说明预测模型存在系统偏差。第二步计算新息的实际方差和理论方差S做对比,实际方差比理论方差大很多,说明Q矩阵给得过于乐观,需要调大。第三步检查协方差矩阵P有没有异常收缩,P值变得特别小往往意味着滤波已经失去对观测变化的响应能力。

5.2 时间同步和坐标系问题

这个问题单独拿出来讲,因为我在实际项目中至少见过三次调试了一周最后发现是坐标系写反。GPS位置输出是在水平直角坐标系里的,IMU的加速度定义在载体坐标系里。如果载体有姿态角,IMU的加速度必须经过姿态矩阵转到导航系才能参与位置预测,否则转弯时横向加速度会被当成纵向加速度估计。

仿真里我刻意把载体简化成二维平面、姿态始终为0,就是为了跳过这个环节。真实工程里,姿态失准角估计、重力矢量分解、地球自转补偿这些都会出现在状态方程里,一个小数点符号错误就能毁掉整次试验。建议落地上车之前先用固定支架的静止数据做离线调试,确认坐标系全部对齐后再跑动态。

5.3 观测粗差处理:卡方检验和时变R

GPS在城市峡谷环境里偶尔会产生远大于正常噪声的跳变,这些粗差如果直接进入卡尔曼更新,会把整个状态一下拉飞。粗差处理不能只靠调大R,因为R是固定值,对单点粗差没有判别能力。

常规做法是先做新息卡方检验。每一时刻算一次新息马氏距离γ = innovation^T * S^{-1} * innovation,这个量理想情况下服从卡方分布,自由度等于观测维数。如果γ超过某个阈值,比如取0.99置信水平对应的卡方值,就认为观测不可信,跳过这次更新或者把它的R放大成原来的几十倍。工程演示中这个技巧能明显提升系统的抗干扰能力。

5.4 常见问题速查表

现象可能原因处理建议
轨迹毛糙,融合结果接近GPSQ过大或R过小减小Q或增大R
轨迹过于平滑,转弯跟不上Q过小或R过大增大Q或减小R
新息均值长期不为零模型系统误差、观测时间戳滞后检查状态转移和坐标转换
稳态误差缓慢增大零偏估计未收敛、模型输入符号错检查IMU读数方向、零偏初值
某个状态长时间不收敛状态不可观测降维或增加观测类型
粗差导致位置跳变GPS多路径卡方粗差检测、增大R

这张表不用背,我的建议是把它贴在工位上。遇到问题先看现象归类,再决定从模型还是参数下手,不要一上来就乱试Q和R。

6. 我对卡尔曼滤波建模的几点思考

6.1 先有问题,再有滤波器

做工程时间久了,我越来越觉得卡尔曼滤波本身不是重点,重点是建模的人对这个系统的理解。状态怎么选、过程噪声怎么设、坐标系怎么对齐,每一条都体现了工程师对物理过程的理解程度。如果理解不到位,再好的滤波算法也救不回来。

6.2 从简单模型开始,逐级加状态

我几乎所有的项目都是先用一个最小化模型跑通全流程,确认数据通路无误,再逐步加入姿态误差、陀螺零偏、杆臂效应等更加精确的状态。这样每一步都有清晰的验收指标,不会在15维状态空间里迷失方向。

6.3 滤波器是工具,不是万金油

卡尔曼滤波并不能创造信息,它只是把两个传感器的误差特征融合起来。如果传感器本身性能太差,融合结果也不会好到哪里去。有些场景下,把GPS换一个好的接收机、把IMU换一个低零偏的型号,比花三个月调滤波参数有效得多。先优化传感器,再谈算法,这个顺序不能颠倒。

6.4 一个值得养成的调试习惯

最后分享一个我自己的习惯:每次跑完试验,我都会把新息序列、P矩阵对角线、状态估计值这三个量保存成文件,画在同一张图上。看似额外花了五分钟,但在现场调试时,这套日志能帮你快速定位问题是出在传感器、模型还是参数上。滤波器这种系统,最怕的就是看不到中间变量,只看最后输出的位置。让中间过程透明化,是工程调试最重要的一步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询