跳转至

拆解 PSINS 第 0 篇:读码地基——数据结构、六大约定、主循环骨架

拆解 PSINS 系列的"地基"篇。正式逐行拆解前,先把读懂 PSINS 代码所需的全部"通用前置"一次性立起来:代码长什么样、数据结构怎么存、有哪些反直觉的约定、主循环怎么转。读完它,再看 P1–P4 和后续逐行注释篇,不需要任何额外上下文。

本篇也是 Mini-INS 参考实现库(见 00 内化蓝图)的文档入口——文中的数据结构速查表,就是库里 data_classes.m 的字段定义来源。

一、代码地图:demo 是"薄壳",肉在 base/

PSINS 的源码分两层,读懂这个结构就成功了一半:

PSINS/
├── demos/          # 薄壳:每个 demo 只"点菜",几乎不干活(19~40 行)
│     test_SINS_trj.m / test_SINS.m / test_DR.m / test_SINS_DR.m / test_SINS_GPS_153.m …
└── base/           # 肉:库函数,按职能分目录
      ├── base1/    # 轨迹与机械编排:trjsegment / trjsimu / insupdate / cnscl / earth / qupdt2 …
      ├── base2/    # 框架与误差:inspure / avperrset / avpadderr / poserrset / avpcmpplot …
      ├── kf/       # 卡尔曼:kfinit / kfupdate / kffk / kffeedback / kfplot …
      ├── imu/      # 传感器误差:imuerrset / imuadderr / odsimu …
      └── plot/     # 画图闭包:insplot / imuplot / myfigure …

demo 的正确读法 = 把它当"数据流入口":每一行调用都是一扇门,推开门(读库函数)才是拆解。三个薄壳消费同一份数据母版:

demo 行数 调用 消费
test_SINS_trj.m 31 trjsegment/trjsimu 无(造数据母版 trj10ms.mat
test_SINS.m 19 inspure(内含 insupdate 母版
test_DR.m 29 odsimu/drinit/drupdate 母版
test_SINS_DR.m 40 etm/kffk/kfupdate/kffeedback 母版

二、六大约定(全系列统一字典)

PSINS 有 6 个反直觉的约定,每一个都踩过坑。先记熟,读代码时处处用到:

# 约定 内容 踩坑后果(如果不注意)
1 global glv 全局量 每个函数第一行几乎都是 global glv,地球模型常量全在 glvs.m 装的 glv 里(glv.Re/glv.wie/glv.g0/glv.deg…) 单独拎一段代码出来跑会报"glv 未定义"——PSINS 代码不能脱离全局量单独读
2 att 顺序 [pitch;roll;yaw] 姿态向量是 [俯仰; 横滚; 航向](欧拉角顺序 p-r-y) 和很多输出习惯(yaw-pitch-roll)不同,对拍前要先重排
3 pos 顺序 [lat;lon;h],弧度+米混用 纬度/经度是弧度,高度是 poserrset 的位置误差要按 /Re 转弧度(P4 坑 3 填错直接发散 NaN)
4 MATLAB 列主序 矩阵按列存储,M(2) 是第 (2,1) 格,不是 (1,2) 照搬 etm.m 线性索引时读反符号(P4 坑 2)→ 滤波器归因反了
5 rad 单位贯穿 角速度/角度全用弧度,换算靠 glv.deg/glv.min inst=[3;60;6]*glv.min 这类写法,漏乘 glv.min 单位差 60 倍
6 avp 大列向量 [att;vn;pos] 导航状态拼成 9×1(或 12×1 含初始)列向量,ins.avp 是它的便捷形式 结构体 ⇄ 列向量互转时维数对不上

📌 第 0 篇的重点提醒:约定 2/3/4 是"坐标系与存储"层面,约定 1/5/6 是"代码风格"层面。前三个影响数学,后三个影响读码——它们共同构成了"PSINS 风味"。

三、数据结构速查表(本篇最大交付)

⚠️ 字段名/顺序以实际 PSINS 源码为准,本表是阅读速查(若与你的 PSINS 版本有出入,以源码为准)。这是 Mini-INS 库 data_classes.m 的设计蓝本。

3.1 trjtrjsimu 产出,数据母版)

字段 维度 含义
avp0 12×1 初始状态 [att(3); vn(3); pos(3)]
avp N×10 每拍真值:[att(3) vn(3) pos(3) t](att rad、vn m/s、pos 弧度+米)
imu N×7 每拍 IMU 增量:[wm(3) vm(3) t]增量,rad / m/s,不是速率)
od N×2 每拍里程增量:[S t](P3/P4 用,dS 单位 m)
ts 1×1 采样间隔(0.01 s = 100 Hz)
len 1×1 总拍数(96600)

3.2 insinsinit 建立,解算状态)

字段 维度 含义 谁读写
qnb 4×1 姿态四元数(体→导航,[w;x;y;z] insupdate 姿态更新
vn 3×1 速度 [vE;vN;vU](ENU) 速度更新
pos 3×1 位置 [lat;lon;h] 位置更新
eb / db 3×1 陀螺 / 加计零偏(rad/s、m/s²) 标定步
wib 3×1 陀螺测量角速度(含地球自转) 姿态更新
wnb 3×1 体轴相对导航系角速度 姿态更新
eth struct 地球参数:RMh/RNh/wnie/wnin/gcc 每一步
Kg / Ka 3×3 刻度 / 安装误差阵(单位阵 = 无误差) 标定步
t 1×1 当前时间 循环

3.3 kfkfinit 建立,卡尔曼状态)

字段 维度 含义
Phikk_1 n×n 离散状态转移阵(每步由 kffk 刷新)
Ft n×n 连续状态阵(etm.m 生成)
Hk m×n 量测阵
Rk m×m 量测噪声协方差
Pk n×n 状态协方差
xk n×1 状态估计(误差状态,如 22 维)
Qk / Gk 过程噪声(离散/连续)

3.4 drdrinit 建立,航位推算状态)

字段 维度 含义
qnb 4×1 姿态四元数(P4 里直接抄 ins.qnb
pos 3×1 位置
vn 3×1 速度(DR 由里程 dS 推速度)
Kg 1×1 里程计刻度系数(≈1)
att 2×1 安装角(俯仰/航向,P4 的 dinst)

3.5 一句话记忆

  • trj = 剧本(真值 + 读数),ins = 演员(解算状态),kf = 教练(误差修正),dr = 另一个演员(独立定位链)。
  • 所有"状态"都是列向量,所有"时间序列"都是矩阵(每行一拍,最后一列 t)。

四、主循环骨架:P2 / P3 / P4 其实同构

四个 demo 的主循环是同一个骨架换零件:

for k = 1:nn:len-nn+1          % 每 nn 拍(双子样 nn=2)推进一次
    wvm = imu(k:k1, 1:6);      % 取本双子样的角增量 + 速度增量
    [解算核心]                   % ← 换零件的位置(下表)
    ...
end
demo 解算核心(每双子样) 附加动作 输出
test_SINS.m insupdate(ins, wvm) 高度阻尼 'Z'(钉 trj.bh 纯惯导 avp
test_DR.m drupdate(dr, wvm(:,1:3), dS) DR 位置
test_SINS_DR.m insupdatedr.qnb=ins.qnbdrupdatekffkkfupdate 每 10 拍(0.1 s)量测 + kffeedback 'v' 速度闭环 组合 avp

读法:P2 的循环是"SINS 单机",P4 的循环是"SINS + DR + KF 三机"——多出来的每一步都是往骨架里加零件。理解了这个骨架,任何 PSINS demo 拿到手都能 10 秒定位它在哪个零件上做了文章。

五、三本"字典"的分工

文档 管什么 什么时候翻
本篇(00 读码地基) 代码约定 + 数据结构 + 主循环 看不懂任何一行 PSINS 代码时
00 内化蓝图 Mini-INS 库的路线图 + 写作规范 想知道"拆完怎么变成自己的库"时
附录 · 绘图函数与 MATLAB 惯用法 MATLAB 语法词典(nargin/subplot/interp1…) 看不懂某句 MATLAB 语法时

一句话:迷路了先回这三处——约定不懂回本篇,语法不懂回附录,方向不懂回蓝图。

六、自测题

  1. trj.imu 每行 7 列,前 6 列是什么?为什么叫"增量"而不是"速率"?
  2. ins.qnbdr.qnb 在 P4 里是什么关系?为什么?
  3. 为什么 poserrset 的位置误差要按 /Re 转弧度?
  4. MATLAB 列主序下,M(2) 是矩阵的哪个元素?这和 P4 坑 2 有什么关系?
  5. test_SINS.mtest_SINS_DR.m 的主循环,每双子样各做了几步?差在哪?
📐 参考答案
  1. [wm(3) vm(3)] = 角增量(rad)+ 速度增量(m/s),是每个采样间隔内积出来的量;陀螺/加计输出本来就是增量(脉冲/积分结果),注入误差、标定补偿都要乘 ts。
  2. P4 里 dr.qnb = ins.qnb(DR 姿态硬抄 SINS)——车辆 DR 没有独立航向源,陀螺是唯一方向源,抄 SINS 保证 DR 方向一致;KF 只靠位置差修正。
  3. 因为 ins.pos 的 lat/lon 单位是弧度(约定 3),位置误差若用米表示必须先除地球半径转弧度,否则数量级差 6×10⁶ 倍直接发散。
  4. M(2) = 第 (2,1) 格(第 2 行第 1 列)。etm.m 用线性索引填 F 矩阵时,读错行/列顺序会把符号写反(如 Mva 变 -askew),滤波器归因反转 → 组合发散。
  5. test_SINS:1 步(insupdate)+ 高度阻尼;test_SINS_DR:4 步(insupdate → 锚 DR → drupdate → kf 预测)+ 每 0.1 s 量测反馈。多出的 3 步都是往骨架里加 DR 和 KF 零件。

参考体系:PSINS demos/base/;本系列 P1P400 内化蓝图(下一篇阅读建议)。