简介:这份资源面向学习导航定位、信号处理与控制理论的学生和工程人员,提供GPS/INS组合导航的MATLAB实现方案,帮助理解两种导航方式互补融合的完整流程。压缩包共10个文件,约682KB,以m脚本和asv自动备份文件为主,另含doc说明文档、mat数据文件与txt程序说明,覆盖GPS信号模拟、INS动态模型、扩展卡尔曼滤波融合及结果可视化等环节。资源中既有位置组合主程序与卡尔曼滤波实现脚本,也附带组合结果文档和仿真数据,便于读者对照代码复现轨迹对比、误差分析与性能评估过程。目前已有3938人学习下载,适合希望从原理到代码系统掌握组合导航、并动手调试滤波参数的中高级学习者参考。
1. GPS/INS 组合导航 MATLAB 实现:从单点定位到卡尔曼滤波闭环
做车载定位或者无人机导航的朋友大概率遇到过这种场景:跑一段城市道路,纯 GPS 轨迹在楼宇遮挡处直接飘出去几十米,速度曲线像心电图;换成纯 INS 递推,半分钟不到位置就发散到没法看。GPS/INS 组合导航 MATLAB 实现这套东西,解决的就是这个——用卡尔曼滤波把 GPS 的长期稳定和 INS 的短期高动态捏在一起,让轨迹在丢星几秒内还能撑住。它适合已经懂一点状态空间、想在 MATLAB 里把整套松组合流程跑通的人,也适合做毕设或算法预研、需要一份能改能调的参考实现的人。下面按“数据怎么造 → 模型怎么搭 → 滤波怎么调 → 坑在哪”一路拆下去。
2. 组合导航的数学底子:状态量、误差模型与坐标系
2.1 为什么选 15 维误差状态而不是直接估位置
松组合里最常见的做法是间接法滤波:不直接估计位置速度姿态,而是估计它们的误差量,再把误差反馈回去修正惯导解算结果。原因是误差量是小量,线性化近似成立,卡尔曼滤波的线性假设不会被破坏得太狠。15 维状态的标准排布是:
| 序号 | 状态量 | 含义 | 单位 |
|---|---|---|---|
| 1-3 | δp | 位置误差(纬度、经度、高度) | m |
| 4-6 | δv | 速度误差(东北天三轴) | m/s |
| 7-9 | δφ | 姿态误差角 | rad |
| 10-12 | ε | 陀螺零偏 | rad/s |
| 13-15 | ∇ | 加速度计零偏 | m/s² |
选 15 维而不是 9 维,是因为陀螺和加计的零偏如果不建模,滤波会把零偏误当成姿态误差去修,时间一长姿态就被拉歪。把零偏放进状态里让它自己估,是性价比最高的一步。常见做法是零偏建模为一阶马尔可夫过程或随机游走,MATLAB 里用eye(3)*sigma_bias^2*dt近似离散噪声阵就够用。
2.2 坐标系与姿态表示:别在四元数和欧拉角之间反复横跳
惯导解算内部用四元数更新姿态,因为欧拉角在俯仰接近 ±90° 时有万向锁。但卡尔曼滤波的状态转移矩阵推导通常用欧拉角误差模型更直观,所以工程上常见的组合是:解算用四元数,滤波用误差角。两者之间靠方向余弦矩阵 C_b^n 转换。
% 四元数更新(简化版,仅示意核心逻辑) function q_new = quat_update(q, omega, dt) % q: 当前四元数 [w x y z] % omega: 机体角速度 [wx wy wz] rad/s % dt: 采样间隔 omega_norm = norm(omega); if omega_norm < 1e-12 q_new = q; return; end % 构造旋转四元数增量 dq = [cos(omega_norm*dt/2), ... sin(omega_norm*dt/2)*omega/omega_norm]; % 四元数乘法 q_new = q * dq q_new = quat_mult(q, dq); q_new = q_new / norm(q_new); % 强制归一化,防漂移 end这段的关键在最后一行归一化。四元数在数值积分下模长会缓慢偏离 1,不归一化的话姿态矩阵会逐渐失去正交性,表现为航向角缓慢漂移——这种漂移很隐蔽,跑短数据看不出来,跑十分钟就明显了。参数上dt必须和 IMU 实际采样率一致,常见 IMU 是 100Hz 或 200Hz,对应 dt 为 0.01 或 0.005 秒。
2.3 状态转移矩阵 F 的离散化
连续时间误差方程离散化,工程上一般用一阶近似Fd = I + F*dt,因为 dt 很小(0.01s 量级),高阶项贡献可以忽略。F 矩阵里比较容易被写错的是姿态误差对速度误差的耦合项,也就是比力反对称矩阵那一块。写错这一项,滤波在转弯或加速时会出现明显的速度估计滞后。
% 构造离散状态转移矩阵(15维,简化示意) I = eye(15); F = zeros(15,15); % 位置误差对速度误差:单位阵 F(1:3, 4:6) = eye(3); % 速度误差对姿态误差:比力反对称阵 fn = C_bn * acc_meas; % 比力投影到导航系 F(4:6, 7:9) = -skew(fn); % 速度误差对加计零偏 F(4:6, 13:15) = C_bn; % 姿态误差对陀螺零偏 F(7:9, 10:12) = -C_bn; Fd = I + F * dt; % 一阶离散化skew是反对称矩阵构造函数。这里acc_meas用的是加计原始测量值减去零偏估计,不是纯重力。很多新手直接把重力矢量代进去,结果静态下滤波收敛正常,一动态就发散,就是这里出的问题。
3. 松组合滤波实现:量测方程、噪声阵与闭环校正
3.1 量测方程:位置速度双观测量怎么配
松组合最直接的做法是把 GPS 输出的位置和速度与 INS 解算的位置速度作差,作为卡尔曼滤波的量测。量测矩阵 H 就是简单的选择矩阵:
% 量测方程:GPS位置速度 - INS位置速度 H = zeros(6,15); H(1:3, 1:3) = eye(3); % 位置误差观测 H(4:6, 4:6) = eye(3); % 速度误差观测 % 量测残差 z = [pos_gps - pos_ins; vel_gps - vel_ins]; % 卡尔曼增益 S = H * P * H' + R; K = P * H' / S; % 状态更新 dx = K * z; P = (eye(15) - K*H) * P;量测噪声阵 R 的取值直接决定滤波“信 GPS 还是信 INS”。经验值是 GPS 水平位置标准差取 2~5 米,速度取 0.1~0.3 m/s。如果用的是 RTK 固定解,位置可以收到厘米级,R 相应调小。R 给太大,滤波反应迟钝,GPS 修正拉不回来;R 给太小,GPS 一飘滤波就跟着跳。
3.2 噪声阵 Q 的调参逻辑
过程噪声 Q 反映的是你对 IMU 模型的信任程度。陀螺零偏噪声、加计零偏噪声、角度随机游走、速度随机游走,这几项要分开设。实操中我一般先按 IMU 数据手册里的噪声密度换算,再在这个基础上放大 2~5 倍作为初值,因为实际安装误差和振动会引入额外噪声。
% 过程噪声阵构造(简化) q_gyro = (0.5*pi/180/3600)^2; % 陀螺噪声,单位 rad^2/s^2 q_accel = (100e-6*9.8)^2; % 加计噪声 Q = zeros(15,15); Q(4:6, 4:6) = eye(3) * q_accel * dt; Q(7:9, 7:9) = eye(3) * q_gyro * dt; Q(10:12,10:12)= eye(3) * q_gyro * dt * 0.01; % 零偏噪声更小 Q(13:15,13:15)= eye(3) * q_accel * dt * 0.01;零偏项的噪声为什么要乘 0.01?因为零偏是缓变量,短时间内几乎不变,给它太小的过程噪声反而能让滤波更稳地估计它。这个系数不是死的,跑完看零偏估计曲线,如果曲线抖得厉害就再调小,如果收敛太慢就调大。
3.3 闭环校正:反馈时机决定滤波稳不稳
滤波估出误差状态后,有两种用法:开环输出(只从状态里减掉误差,不反馈到惯导)和闭环反馈(把误差直接修正到惯导解算结果里,状态清零)。工程上几乎都用闭环,因为开环下误差会越积越大,线性化假设很快失效。
% 闭环校正 pos_ins = pos_ins - dx(1:3); vel_ins = vel_ins - dx(4:6); % 姿态修正:用误差角构造修正四元数 dtheta = dx(7:9); dq_corr = [1, dtheta'/2]; q_ins = quat_mult(q_ins, dq_corr); q_ins = q_ins / norm(q_ins); % 零偏反馈 gyro_bias = gyro_bias + dx(10:12); accel_bias = accel_bias + dx(13:15); % 状态清零,准备下一轮 dx = zeros(15,1);注意姿态修正用的是小角度近似[1, dtheta/2],只在误差角很小的时候成立。如果某次 GPS 跳变导致误差角估计超过几度,这个近似就会引入二次误差。稳妥做法是加个限幅,误差角超过阈值时只修正一部分。
4. 避坑与排查:跑不通时先看这几处
4.1 现象:滤波初期轨迹剧烈抖动,几十秒后才收敛
原因通常是初始协方差阵 P0 给得太小,滤波对自己的初始状态过于自信,GPS 前几个量测被当成异常值压掉了。解决是把 P0 的位置和速度项放大到实际不确定度的平方,比如初始位置不确定 10 米,P0(1,1) 就设 100。姿态初始不确定度按 1~5 度设,零偏按数据手册最大值设。
4.2 现象:直线段正常,一转弯位置就偏出去
这是姿态误差和速度误差耦合项写错或符号搞反的典型表现。回头检查 F 矩阵里F(4:6,7:9)那一块,比力反对称阵的符号要和你的导航系定义一致。东北天坐标系下,比力在导航系的投影和姿态误差的叉乘顺序不能反。另一个可能是 GPS 速度量测的坐标系没对齐,GPS 给的是地速航向,INS 给的是机体系速度,中间差一个姿态旋转。
4.3 现象:零偏估计曲线一直往上爬不收敛
多半是 Q 阵里零偏项的过程噪声给太大,滤波把真实的姿态误差误判成零偏变化。把零偏对应的 Q 项调小一个量级再看。还有一种可能是 GPS 量测里存在系统性偏差(比如天线杆臂没补偿),滤波只能靠零偏去吸收这个偏差,表现出来就是零偏单调漂移。杆臂补偿在车载场景下不能省,天线到 IMU 的杆臂哪怕只有半米,转弯时也会引入可观的速度误差。
4.4 现象:丢星后轨迹还能撑,但重新捕获时跳变
这是闭环反馈的经典问题。丢星期间滤波只有预测没有更新,协方差 P 不断膨胀,一旦 GPS 回来,卡尔曼增益很大,一个量测就把状态拉过去一大截。解决思路是丢星超过一定时间后,把 P 限制在上限内,或者对量测残差做卡方检验,超限的量测直接丢弃。MATLAB 里实现卡方检验就是算z'*inv(S)*z和阈值比大小。
4.5 现象:整个轨迹整体平移,形状对但位置偏
检查 GPS 和 INS 的时间同步。如果 GPS 的 1PPS 和 IMU 采样没对齐,哪怕差 50 毫秒,高速下就是米级的位置偏差。常见做法是用 GPS 的秒脉冲做时间基准,对 IMU 数据做插值对齐。另一个可能是坐标框架没统一,GPS 给的是 WGS84 经纬高,INS 解算用的是当地东北天,转换时椭球参数用错也会造成系统性偏移。
5. 进阶技巧:用仿真数据验证滤波收敛性
真实数据不好搞的时候,自己造一段带真值的仿真轨迹是验证滤波最靠谱的办法。思路是:先设计一条已知的位置、速度、姿态曲线,反推出理想的陀螺和加计输出,再叠加噪声和零偏,最后把这份“假 IMU 数据”喂给滤波,看估计值和真值的差。
% 生成仿真IMU数据(简化示意) t = 0:0.01:60; % 60秒,100Hz N = length(t); % 设计真值轨迹:匀速直线 + 一段转弯 pos_true = zeros(3,N); vel_true = zeros(3,N); att_true = zeros(3,N); for k = 2:N if t(k) < 20 vel_true(:,k) = [10; 0; 0]; % 东向10m/s elseif t(k) < 40 omega = 0.05; % 转弯角速率 att_true(3,k) = att_true(3,k-1) + omega*0.01; vel_true(:,k) = [10*cos(att_true(3,k)); 10*sin(att_true(3,k)); 0]; else vel_true(:,k) = vel_true(:,k-1); end pos_true(:,k) = pos_true(:,k-1) + vel_true(:,k)*0.01; end % 反推理想IMU输出 + 叠加噪声和零偏 gyro_true = diff(att_true,1,2)/0.01; accel_true = diff(vel_true,1,2)/0.01 + [0;0;9.8]; % 加重力 gyro_meas = gyro_true + gyro_bias_true + randn(3,N-1)*gyro_noise; accel_meas = accel_true + accel_bias_true + randn(3,N-1)*accel_noise;这段代码的价值在于:真值已知,滤波估计的位置误差、速度误差、姿态误差都能直接算出来,收敛快慢、稳态精度一目了然。我一般会跑三组对比——纯 INS 递推、GPS 单独定位、组合导航——把三条误差曲线画在一张图上。如果组合导航的误差曲线没有明显低于另外两条,说明滤波参数或者模型有问题,不用怀疑数据。
验证时重点看三个指标:位置误差的稳态值是否收敛到 GPS 噪声水平以下,姿态误差是否在转弯段没有明显发散,零偏估计是否在 30 秒内基本稳定。这三个都过了,这套参数搬到真实数据上通常不会翻车。从那以后我每次调完滤波参数,都强制先跑一遍仿真真值对比,确认收敛再上实测数据,省下大量对着飘忽轨迹发呆的时间。希望帮到你。
本文还有配套的精品资源,点击获取