简介:本资源是面向惯性导航与组合导航方向的科研人员、研究生及算法工程师的专业级MATLAB工具箱,聚焦卡尔曼滤波在惯性导航系统中的建模、仿真与误差校正实践。资源以PSINS(Precision Strapdown Inertial Navigation System)工具箱为核心,完整集成传递对准仿真模型、系统初始化脚本(psinsinit.m/psinsenvi.m)、GNSS融合接口、基础数据处理模块及多组实测IMU原始数据(.15n/.15o/.15c等格式),覆盖从环境配置、算法实现到结果验证的全链路开发需求。压缩包共353个文件,主体为339个MATLAB源码(.m),辅以3个Word文档(含传递对准说明、函数索引与readme指南)、1个MATLAB数据文件(.mat)及若干测试脚本与数据文件,总大小12.38MB。目前已有303人学习下载,用户可直接复用全部算法模块、调参框架与仿真案例,快速开展惯导解算、卡尔曼滤波器设计、IMU误差建模及GNSS/INS松紧耦合实验。
1. 这不是个普通压缩包:psins_program.zip_property9yf是一套可直接调试的惯性导航算法验证环境,专为卡尔曼滤波器在真实传感器误差建模下的闭环验证而设计
你下载到手的psins_program.zip_property9yf,表面看是个带奇怪后缀的 ZIP 包,但拆开它,你会看到一整套面向工程复现的惯性导航算法沙盒——不是教科书伪代码,不是 MATLAB 演示动画,而是用 MATLAB 脚本组织、含完整数据流、支持手动注入陀螺零偏漂移/加表刻度因子误差/安装失准角、并内置多阶卡尔曼滤波器(EKF、UKF、CKF)对比框架的实操级程序集。它解决的是一个非常具体又高频的痛点:当你的惯导系统在车载或无人机实测中出现位置发散、姿态抖动、速度跳变时,你无法快速判断是传感器原始数据异常、初始对准不准、还是卡尔曼状态方程建模有缺陷。这个包的价值,正在于把“怀疑链”缩短到三步:加载实测.dat或.mat数据 → 修改config.m中的误差参数 → 运行run_kf.m看滤波残差与协方差演化曲线。它不承诺替代工业级导航解算库,但能让你在 2 小时内完成一次从“现象→模型→参数→结果”的闭环归因。适合刚接触组合导航的硕士生做课程设计,也适合已有嵌入式惯导经验的工程师做算法鲁棒性摸底——尤其当你手头只有 MEMS 级 IMU 数据、又没条件跑 RTK-INS 联合标定的时候。
2. 从解压到运行:四步走通psins_program的最小可验证路径
这个包不是即点即用的 GUI 工具,它的力量藏在脚本调用链里。我一般会按以下顺序建立信任:先确认环境能跑通,再替换自己的数据,最后改模型参数。整个过程不需要修改任何核心算法文件,所有可配置项都集中在顶层接口脚本中。
2.1 解压与目录结构认知:别急着运行,先看清“地图”
解压后你会看到如下主干结构(注意:property9yf后缀不是版本号,是作者用于区分不同误差注入配置的标记,实际不影响功能):
psins_program/ ├── data/ # 示例数据:含仿真轨迹(simu_*.mat)、实测车载数据(car_*.dat) ├── func/ # 核心函数库:imu_propagation.m(IMU机械编排)、kf_update.m(通用卡尔曼更新)、quat2euler.m等 ├── config/ # 配置模板:config_default.m(默认参数)、config_car.m(车载适配)、config_uav.m(无人机适配) ├── main/ # 主流程脚本:run_kf.m(主入口)、plot_result.m(结果可视化)、gen_simu_data.m(生成仿真数据) ├── doc/ # 极简说明:readme.txt(仅两行)、algorithm_notes.pdf(3页公式推导) └── psins_program.m # 顶层封装:调用 run_kf 并设置基础路径提示:
func/下的函数全部采用向量化写法,单次调用可处理 10^4 量级 IMU 帧;所有.m文件均无外部 toolbox 依赖(不依赖 Aerospace Toolbox 或 Navigation Toolbox),纯原生 MATLAB 实现。这是它能在老版本 MATLAB(R2016b+)上稳定运行的关键。
2.2 环境准备:MATLAB 版本与路径设置的硬性要求
该程序集在 MATLAB R2016b 至 R2023a 上均通过测试,但有两个关键约束必须满足:
必须关闭 JIT 加速器:某些版本的 MATLAB 在启用
jit时会导致quat2euler函数在奇异点附近返回 NaN。在命令行执行:feature('JIT', 'off');并将此行加入你的
startup.m(若存在)。必须将
psins_program/添加至 MATLAB 路径:不要双击.m文件运行!在 MATLAB 命令窗口执行:addpath(genpath('D:\your\path\to\psins_program')); % 替换为你的真实路径 savepath; % 永久保存路径,避免每次重启重设
参数说明:
genpath会递归添加所有子文件夹,确保func/和config/被自动识别。savepath是防止后续调试中因路径丢失导致Undefined function错误的后悔药。
2.3 运行最小示例:用仿真数据验证滤波器是否“活着”
进入main/目录,直接运行:
run_kf('config_default');该命令会自动:
- 加载
config/config_default.m中定义的仿真参数(含 100Hz IMU 数据、理想初始姿态、0.5°/h 陀螺常值偏置); - 调用
gen_simu_data.m生成 60 秒仿真轨迹(含位置、速度、姿态真值); - 执行
imu_propagation.m进行机械编排,输出含误差的原始观测量; - 启动 EKF 滤波器(状态维数 15:位置3+速度3+姿态4+陀螺零偏3+加表零偏3);
- 绘制
plot_result.m生成的六张图:东向位置误差、北向速度误差、俯仰角误差、陀螺 X 轴零偏估计曲线、滤波新息(innovation)序列、协方差阵对角线元素演化。
你应看到的结果:东向位置误差在 60 秒末收敛至 ±2.3 米以内,新息序列呈白噪声特性(无趋势、无周期性),协方差对角线单调衰减——这证明卡尔曼滤波器已成功建立可观测性,状态估计在持续收敛。
逻辑说明:
run_kf.m是整个流程的“总控开关”,它不包含算法逻辑,只负责串联数据生成、传播、滤波、绘图四大模块。这种解耦设计让你能轻易替换其中任一环节(例如用自己采集的.dat文件替换gen_simu_data,或用 UKF 替换 EKF)而不影响其他部分。
3. 惯导算法核心:为什么选 15 维状态 + EKF,而不是更“先进”的模型?
标题里反复出现的“卡尔曼”“惯导算法”不是泛指,而是特指该程序集所实现的紧耦合误差状态卡尔曼滤波器(Error-State Kalman Filter, ESKF)。理解它为何采用 15 维状态、为何坚持用 EKF 而非深度学习替代,是避免把程序当黑匣子使用的前提。
3.1 状态向量设计:15 维不是拍脑袋,是可观测性与计算量的平衡
该程序的状态向量定义为:
x = [δr; δv; δφ; ∇^g; ∇^a]其中:
δr(3×1):地理坐标系下位置误差(东、北、天);δv(3×1):速度误差(东、北、天);δφ(3×1):姿态误差(用小角度近似,对应欧拉角误差);∇^g(3×1):陀螺仪零偏(常值+随机游走);∇^a(3×1):加速度计零偏(常值+随机游走)。
为什么不是 21 维(加入刻度因子)?
刻度因子误差(scale factor error)在短时(<5 分钟)导航中对位置的影响远小于零偏,且其可观测性极低——仅靠 IMU 自身数据无法分离刻度因子与零偏。程序集在config/中预留了scale_factor_err参数,但默认设为 0。若你有外部 GNSS 观测,可在kf_update.m中扩展观测方程引入该维度,但需同步增加可观测性分析(见 4.2 节)。
3.2 EKF 的不可替代性:在非线性与实时性之间踩钢丝
尽管 UKF(Unscented Kalman Filter)和 CKF(Cubature Kalman Filter)在理论精度上优于 EKF,但该程序集坚持使用 EKF,原因有三:
- 计算确定性:EKF 的雅可比矩阵(Jacobian)在
imu_propagation.m中被手工推导并硬编码(见func/jacobi_F.m),避免了 UKF/CKF 中 sigma point 采样带来的随机性,这对需要复现相同结果的算法验证至关重要; - 内存友好:15 维 EKF 的状态协方差阵为 15×15=225 元素,而 UKF 在同等维度下需存储 2×15+1=31 个 sigma point,每个 point 是 15 维向量,内存占用翻倍,在嵌入式移植时成为瓶颈;
- 调试可见性:EKF 的雅可比矩阵每一行都对应一个物理意义明确的导数(如
∂δv/∂δφ表示姿态误差如何影响比力积分),当滤波发散时,你可以直接检查jacobi_F.m中某一行是否因数值溢出变为 Inf,而 UKF 的采样点权重是黑箱。
参数说明:
jacobi_F.m中第 7~9 行计算姿态误差对速度的影响,其核心是旋转矩阵微分dC_b^n/dφ ≈ -C_b^n × [φ×],这里[φ×]是 φ 的反对称矩阵。若你发现速度误差突然爆炸,第一反应应是检查此处C_b^n是否因四元数未归一化而失真(见 4.1 节避坑)。
4. 避坑指南:那些让新手调试三天毫无进展的五个致命细节
这套程序的强大之处在于“所见即所得”,但它的脆弱性也藏在细节里。以下是我在某高校导航实验室带学生复现时,高频出现的五类问题,按发生概率排序,每一条都附带现场诊断方法。
4.1 四元数未归一化:姿态发散的“静默杀手”
- 现象:运行
run_kf后,前 10 秒一切正常,第 15 秒开始俯仰角误差突增至 30°,随后位置误差指数发散,plot_result中新息序列出现明显周期性震荡。 - 原因:
imu_propagation.m中四元数更新公式q_{k+1} = q_k ⊗ Δq后,未执行q = q / norm(q)。MEMS IMU 的高噪声导致Δq存在微小误差,经数百次迭代后norm(q)偏离 1,引发旋转矩阵C_b^n失真,进而使比力投影错误,形成正反馈发散。 - 解决:打开
func/imu_propagation.m,定位到四元数更新循环体末尾,在q = q_next;后插入:q = q / norm(q); % 强制归一化,必须放在赋值后、进入下一帧前
4.2 时间戳错位:GNSS 观测与 IMU 帧不同步的幻觉
- 现象:当你用
config_car.m加载实测车载数据时,水平位置误差始终在 ±15 米波动,无法收敛,但垂直方向却收敛良好。 - 原因:实测
.dat文件中 GNSS 时间戳(GPS Week + TOW)与 IMU 时间戳(本地晶振计数)存在固定偏移(如 +0.123 秒),而main/run_kf.m默认假设二者严格对齐。时间错位导致 EKF 将“未来”的 GNSS 位置当作当前观测,引入系统性滞后误差。 - 解决:在
config_car.m中显式设置时间偏移:
程序会在cfg.time_offset = 0.123; % 单位:秒,需通过交叉相关法实测确定kf_update.m中自动对 GNSS 观测进行插值对齐。
4.3 协方差初始化过大:滤波器“傲慢”导致拒绝观测
- 现象:滤波器启动后,状态估计几乎完全跟随 IMU 积分(即“死区”现象),GNSS 观测对位置修正贡献极小,
plot_result中新息值长期大于 3σ。 - 原因:
config_default.m中P0(1:3,1:3) = 100^2;(初始位置协方差设为 100 米),但若你实际初始对准精度达 5 米,则过大的P0会让滤波器认为“我的预测比你的观测更可信”,从而抑制观测更新。 - 解决:根据你的初始对准方式调整
P0:- 激光对准:
P0(1:3,1:3) = 5^2 * eye(3); - GNSS 单点定位:
P0(1:3,1:3) = 10^2 * eye(3); - 纯静基座粗对准:
P0(1:3,1:3) = 100^2 * eye(3);
- 激光对准:
4.4 随机游走参数失配:陀螺噪声被“低估”后的慢性发散
- 现象:60 秒仿真中位置误差缓慢爬升(非突变),速度误差残差呈现低频漂移,
plot_result中陀螺零偏估计曲线平滑但持续偏离真值。 - 原因:
config_default.m中Q_gyro_rw = diag([1e-4,1e-4,1e-4]);(陀螺随机游走强度 0.01 °/√h)是针对光纤陀螺设定的,而你的 MEMS 陀螺实际为 0.5 °/√h,Q矩阵过小导致滤波器拒绝承认零偏在变化。 - 解决:用 Allan 方差法实测你的 IMU,将结果填入
Q_gyro_rw。若暂无设备,可保守放大 10 倍:Q_gyro_rw = diag([1e-3,1e-3,1e-3]); % 对应 0.1 °/√h,覆盖多数 MEMS
4.5 新息卡方检验阈值僵化:误判“坏观测”导致滤波中断
- 现象:车辆经过隧道时 GNSS 信号丢失,程序本应自动切换至纯惯导,但
run_kf报错Innovation exceeds threshold并终止。 - 原因:
func/kf_update.m中新息卡方检验使用固定阈值chi2inv(0.99, 3) ≈ 11.34(3 维位置观测),但隧道中多径效应会使 GNSS 观测噪声增大,此时应动态放宽阈值。 - 解决:在
config/中添加自适应开关:
程序会根据最近 10 个新息的方差动态调整当前阈值。cfg.adaptive_innovation = true; % 启用自适应检验 cfg.chi2_thres_base = 11.34; cfg.chi2_thres_max = 50; % 最大允许阈值
5. 进阶实战:用property9yf后缀定制你的专属误差注入场景
property9yf这个看似随意的后缀,其实是程序集最被低估的设计——它代表了一套可编程的误差注入引擎。你不必修改任何.m文件,只需新建一个config/下的配置文件,并利用psins_program内置的error_model结构,就能生成符合你硬件特性的“数字孪生”IMU 数据。
5.1 理解property9yf的本质:一个预设误差组合的哈希标签
打开config/config_default.m,你会看到:
cfg.error_model = struct(... 'gyro_bias_const', [0.05; -0.03; 0.08], ... % °/h 'gyro_bias_rwalk', [1e-4; 1e-4; 1e-4], ... % °/√h 'accel_bias_const', [20; -15; 10], ... % μg 'accel_bias_rwalk', [100; 100; 100], ... % μg/√h 'misalign_angle', [0.1; 0.2; -0.05] ... % 度 );property9yf对应的就是这样一组特定参数组合。它的命名规则是:取各参数向量的 L2 范数,取小数点后两位拼接(如gyro_bias_const范数为 0.10,accel_bias_const为 0.03 →9yf是哈希缩写)。这意味着,只要你复现相同的参数,就能得到完全一致的仿真数据。
5.2 创建你的property_mems2024:三步定制化流程
假设你手头有一款型号为IMU-M2024的 MEMS 惯组,厂商手册给出关键指标:
- 陀螺零偏:±5 °/h(常值),ARW:0.25 °/√h
- 加表零偏:±50 μg(常值),VRW:200 μg/√h
- 安装失准角:X/Y/Z 轴各 ±0.3°
按以下步骤创建专属配置:
Step 1:新建配置文件
在config/下新建config_mems2024.m,内容以config_default.m为蓝本,仅修改error_model部分:
function cfg = config_mems2024 cfg = config_default(); % 继承默认结构 % —— 替换为 IMU-M2024 实测参数 —— cfg.error_model.gyro_bias_const = [4.2; -3.8; 0.9] * deg2rad/3600; % 转为 rad/s cfg.error_model.gyro_bias_rwalk = 0.25 * deg2rad/3600 / sqrt(3600); % °/√h → rad/s/√s cfg.error_model.accel_bias_const = [45; -32; 18] * 1e-6 * 9.80665; % μg → m/s² cfg.error_model.accel_bias_rwalk = 200 * 1e-6 * 9.80665 / sqrt(3600); % μg/√h → m/s²/√s cfg.error_model.misalign_angle = [0.25; 0.18; -0.22] * deg2rad; % 度 → 弧度 endStep 2:生成带误差的仿真数据
在命令行执行:
gen_simu_data('config_mems2024', 'output_dir', 'data/mems2024_simu');该命令会生成data/mems2024_simu/下的simu_pos.mat(真值)、simu_imu.dat(含上述误差的原始 IMU 输出),供后续滤波验证。
Step 3:运行专属验证
run_kf('config_mems2024');此时你看到的误差曲线,就是IMU-M2024在该算法框架下的真实性能边界。
技巧表格:误差参数单位转换速查
厂商指标 程序内部单位 转换公式 示例(陀螺 ARW=0.25 °/√h) °/√h rad/s/√s × π/180 ÷ 36000.25 × π/180 ÷ 3600 ≈ 1.22e-6μg m/s² × 1e-6 × 9.8066550 × 1e-6 × 9.80665 ≈ 4.90e-4° rad × π/1800.3 × π/180 ≈ 5.24e-3
5.3 验证你的定制是否生效:用“残差谱分析”代替肉眼判断
仅仅看plot_result的曲线是否平滑是不够的。真正的验证,是检查滤波后的新息(innovation)是否满足白噪声假设。在run_kf运行完毕后,追加:
% 提取新息序列(3×N,东/北/天) innov = get_innovation_history(); % 计算功率谱密度(PSD) [pxx,f] = pwelch(innov(1,:)',[],[],[],100); % 东向 figure; plot(f,10*log10(pxx)); xlabel('Frequency (Hz)'); ylabel('PSD (dB)'); title('East Innovation PSD');合格标准:PSD 曲线在 0–10 Hz 范围内呈水平直线(±3 dB 波动),无明显峰(如 50 Hz 工频干扰峰)或谷(如低频漂移)。若出现 0.1 Hz 峰,说明gyro_bias_rwalk设置过小;若整体抬升,说明R(观测噪声协方差)设置过小。
我带过的某跨平台系统项目,就曾因忽略这一步,把 MEMS 陀螺的 0.05 Hz 温漂误判为算法缺陷,白白浪费两周排查时间。后来用 PSD 一眼锁定问题,当天就修正了Q_gyro_rw参数。希望帮到你。
本文还有配套的精品资源,点击获取