简介:这是一份用C语言实现的惯性导航轨迹发生器程序,面向航空、航海、航天及地面车辆领域的开发者,用于模拟IMU数据、生成运动轨迹,解决实际惯导算法研究中的测试数据不足问题,适合学习惯导原理、传感器建模或进行算法仿真的人员使用。资源以rar压缩包形式提供,共2个文件:核心C源文件负责模拟陀螺仪与加速度计数据,并通过微分方程求解载体姿态、速度和位置;另含一个TXT说明文件,可帮助快速了解程序背景与运行环境。资源包约4KB。程序虽小,但完整展示了IMU数据生成的典型流程,涵盖牛顿运动方程、四阶龙格-库塔法、传感器误差模型及低通/卡尔曼滤波处理等关键知识点,适合在航姿参考、组合导航或自动驾驶等场景中作为研究起点。已有814人浏览学习,是了解惯性导航轨迹生成实现细节的入门参考。
1. 惯性导航轨迹发生器程序:为什么我会在硬件还没到手时先造一份仿真数据
惯性导航轨迹发生器程序,说白了一点都不玄:它把你预先设计好的一段载体运动轨迹,反算成陀螺仪和加速度计应该输出的原始测量序列,相当于在真实传感器还没上电之前,先把惯导算法整条链路用仿真数据跑通。我做组合导航调试时最头疼的不是滤波器发散,而是拿到一段真实 IMU 数据后根本不知道载体当时真实的运动轨迹——解算偏差了,你分不清是算法的问题还是数据的问题。轨迹发生器把“真值”握在自己手里,轨迹是你定义的,误差是你注入的,所以算法哪里出错可以被精确定位。这篇文章适合三类人:正在做捷联解算或组合导航验证的工程师、需要为滤波器调参构造标准数据集的测试人员,以及刚接触惯导想搞懂 IMU 数据从哪来、又该怎么仿真的学习者和研究者。
2. 轨迹定义与建模:航迹点怎么变成一条可解算的运动曲线
轨迹发生器的第一步不是写代码,而是把“轨迹”这个词在数学上定义清楚。很多初学者以为给一串航迹点坐标就行,但 IMU 反解需要用到位置对时间的二阶导、姿态对时间的一阶导,所以轨迹必须至少二阶可微,姿态必须连续可微;同时还要满足载体本身的运动学约束,你不能让一辆地面车从静止瞬间跳到 20 m/s。我在生成轨迹时一般分三层来处理:坐标系约定、航迹点之间的运动学插值、以及按场景选择轨迹模板。
2.1 坐标系统一:仿真里的“第一颗扣子”
坐标系约定决定了后面所有公式的符号方向,这一层没做统一,后面反解出的 IMU 数据会成批出错。我统一采用 NED 导航坐标系:x 轴指向北、y 轴指向东、z 轴指向地,重力矢量表示为 g = [0, 0, 9.81] m/s²。载体坐标系则用“前右下”,即 x 轴朝载体前方,y 轴朝右,z 轴朝下,这样车辆水平静止时载体系和 NED 系完全对齐。
选 NED 的原因很实际:大部分惯导解算框架、滤波器的状态定义、以及公开的测试数据集都默认用 NED,你按别的地球坐标系约定生成数据,后面做算法对比时要额外做坐标转换,增加排错难度。另一个容易忽略的点是姿态表示:我统一用归一化四元数,避免欧拉角的万向锁问题。四元数在轨迹定义、反解、误差注入三个阶段都保持一致,不出现在某一环节偷偷换成欧拉角的情况。
一个具体的坑:很多人会把“惯性系”和“导航系”混着用。轨迹定义在 NED 导航系下,而 IMU 测量的是载体相对惯性空间的量在载体系下的投影。正因为有地球自转和重力差异,这两个系之间才需要比力方程和角速度补偿。在轨迹发生器这个场景里,我们通常忽略地球自转(低成本惯导本身也测不准 15°/h 的地速分量),但重力补偿绝对不能省,否则加速度计反解全部错位。
2.2 航迹点插值与运动学约束:轨迹不是画线,是服从物理规律
拿到一串离散航迹点之后,常见做法是直接线性插值,或者用三次样条插值。线性插值的问题很直观:位置连续但速度在每两个插值点之间是阶梯跳变的,一阶导不连续,算出来的加速度脉冲完全不像真实运动。三次样条对位置插值虽然光滑,但样条的曲率不受控,经常在转弯处出现远超载体能力的加速度尖峰。所以我的做法是:放弃“对位置插值”,改成先设计运动学参数,再积分出位置。
分段设计速度、加速度等运动参数,再积分得到位置和姿态序列,这在工程上叫“运动学合成”。例如一段直线运动,可以先定义加加速度、最大加速度、巡航速度和匀速时长,按“匀加速—匀速—匀减速”三段拼出来。这样速度天然连续、加速度有界、位置二阶可微,后面反解 IMU 时不会出现数值毛刺。
import numpy as np def linear_segment(v0, v1, a_max, dt): # 速度从 v0 过渡到 v1,限制最大加速度 a_max # 返回该段的速度曲线(等间隔 dt 采样) dv = v1 - v0 if abs(dv) < 1e-6: n = 1 return v0 * np.ones(n) # 加速到目标速度所需时间和距离 t_acc = abs(dv) / a_max n_acc = int(np.ceil(t_acc / dt)) v = np.linspace(v0, v1, n_acc + 1) # 线性变速段,加速度为常量 return v def synthesize_trajectory(v_waypoints, a_max, dt): # v_waypoints: 每个控制点的目标速度列表 # 依次生成各段,拼接成完整的速度曲线 segs = [] for i in range(len(v_waypoints) - 1): seg = linear_segment(v_waypoints[i], v_waypoints[i + 1], a_max, dt) segs.append(seg) v_total = np.concatenate(segs) # 位置由速度积分得到,x 方向示例 pos = np.cumsum(v_total) * dt return pos, v_total这段代码的逻辑是:每个控制点只给出速度和位置,实际轨迹由控制点之间的加减速段拼接而成。a_max是载体能承受的最大加速度,它把运动约束直接写进轨迹生成过程,而不是在插值之后再去检查加速度是否超限。dt是采样步长,也是后面 IMU 输出的节拍,全程固定。参数调整上我一般把a_max设为车辆实际动力性能的上限再乘一个 0.8 的安全系数,防止仿真轨迹在极限工况下出现加速度阶跃。如果当选段数多,可以把这个函数扩展到每个控制点同时指定速度和航向角,再把航向角也按同样的加减速逻辑生成,就能得到带转弯的平面轨迹。
2.3 轨迹参数化与场景贴合:三条常用的设计模板
不同算法验证任务需要的轨迹特征完全不同。轨迹发生器最好内置几套模板,按场景选,而不是每次都从零设计。我常用三套:直线往返段适合做陀螺零偏的标定验证,因为匀速直线运动段理论上只会激励加速度计零偏,陀螺只要在段内保持角速率恒定,辨识结果不受轨迹形状干扰;“8 字”轨迹适合做姿态解算的连续性验证,轨迹会遍历多个航向角变化,姿态解算的累积误差可以被显著激励出来;圆形轨迹则适合做离心力与姿态耦合的验证,因为恒定向心加速度会持续作用在加速度计横向轴上。
| 轨迹模板 | 典型用途 | 需要重点检查的指标 |
|---|---|---|
| 直线往返加速减速 | 加计零偏辨识、速度估计验证 | 加速度峰值、往返段位置闭合误差 |
| “8 字”或“S 形”连续转向 | 姿态解算长期稳定性、航向漂移 | 航向角累积误差、姿态欧拉角连续性 |
| 圆周运动 | 离心力补偿、比力方程验证 | 向心加速度幅值、半径漂移 |
| 静止 + 短时运动交替 | 零速修正(ZUPT)算法验证 | 静止段数据是否有漏零偏 |
模板选择伴随一个参数确认过程。我在生成每一条轨迹前都会打印几个关键约束:最大速度、最大加速度、最大角速率、轨迹总时长、总航向变化量。这些数值要和载体物理能力对齐,否则仿真跑出来的“高动态”轨迹实际上在现实中根本无法实现,算法验证完也无法迁移到真实场景。轨迹设计完成后保存成带时间戳的原始曲线文件,再进入下一步 IMU 反解——这条数据链路上,前一步的输出就是后一步的输入,任何一步坐标系错了,后面全错,所以轨迹定义阶段宁可多花时间核对也不要图快。
3. IMU 数据反解:把平滑轨迹翻译成陀螺与加计读数
轨迹生成之后,接下来就是核心转换:把位置序列和姿态序列变成 IMU 测量值。这个环节有两个高频错误:一是把位置序列直接做二阶差分当加速度计输出,完全忽略了比力方程;二是把欧拉角序列做差分当陀螺角速率,忽略了姿态增量与角速度之间的非线性关系。正确反解思路是:加速度计输出的是“比力”,等于载体加速度减去重力矢量,再投影到载体坐标系;陀螺输出的是姿态增量对应的等效旋转矢量除以时间。
3.1 姿态反解:用四元数差分恢复陀螺角速度
姿态序列给定之后,陀螺反解的本质是计算相邻两个姿态之间的小角度旋转。四元数表示下,从 t_i 时刻姿态 q_i 到 t_{i+1} 时刻姿态 q_{i+1} 的增量四元数可以写成 dq = q_{i+1} ⊗ q_i^{-1}。当采样时间 dt 很短、姿态增量足够小,等效旋转矢量的模近似等于 2 倍的 dq 虚部,于是角速度 ω ≈ 2/dt * dq_vec。这个近似在 dt 为毫秒级、单步姿态变化角度小于几度时误差可以忽略,MEMS 仿真场景基本够用。
这段反解代码我放在一个固定函数里,输入姿态四元数序列和采样间隔,输出陀螺角速度序列,保证可复用。
def quat_mult(q0, q1): # 四元数乘法,q0, q1 均为 (w, x, y, z) 数组 w0, x0, y0, z0 = q0 w1, x1, y1, z1 = q1 return np.array([ w0*w1 - x0*x1 - y0*y1 - z0*z1, w0*x1 + x0*w1 + y0*z1 - z0*y1, w0*y1 - x0*z1 + y0*w1 + z0*x1, w0*z1 + x0*y1 - y0*x1 + z0*w1 ]) def quat_conj(q): return np.array([q[0], -q[1], -q[2], -q[3]]) def pose_to_gyro(quat, dt): # quat: (N, 4) 姿态四元数序列,NED 系到载体系 # dt: 固定采样间隔 gyro = np.zeros((len(quat) - 1, 3)) for i in range(len(quat) - 1): q0 = quat[i] / np.linalg.norm(quat[i]) q1 = quat[i + 1] / np.linalg.norm(quat[i + 1]) dq = quat_mult(q1, quat_conj(q0)) dq /= np.linalg.norm(dq) # 提取增量角速率,小角度近似:ω ≈ 2/dt * dq_vec gyro[i] = 2.0 / dt * np.array([dq[1], dq[2], dq[3]]) return gyro代码里的quat_conj表示逆旋转,dq的实部接近 1 时虚部乘以 2/dt 就是角速率。这里有个参数要注意:dt必须是 IMU 输出周期,和后续误差注入、滤波器更新周期保持一致,别用轨迹定义的粗采样率来算陀螺。如果姿态变化较大(单步超过 5°),小角度近似会引入明显误差,需要换用四元数对数映射:ω = log(q) / dt,但一般 IMU 仿真很少遇到这种情况。
3.2 加速度计反解:比力方程里的重力补偿
加速度计反解是轨迹发生器里翻车率最高的环节。加速度计测量的不是运动加速度 a,而是比力 f = a - g。直观理解是:加速度计内部有一个检测质量,静止时支撑力抵消重力,所以读数应为 −g 在载体系下的投影;而运动时测到的是使检测质量产生加速度的惯性力。反解时先对位置序列取二阶差分得到加速度,再减去重力矢量,最后投影到载体坐标系。
def pose_to_imu(pos, quat, dt): # pos: (N, 3) NED 系下位置;quat: (N, 4) 姿态四元数 # 返回: acc_body (N,3) 比力, gyro (N-1,3) 角速率 g = np.array([0.0, 0.0, 9.81]) # 位置二阶中心差分求运动加速度 acc = np.zeros_like(pos) acc[1:-1] = (pos[2:] - 2 * pos[1:-1] + pos[:-2]) / (dt * dt) acc[0] = acc[1] acc[-1] = acc[-2] # 比力 = 加速度 - 重力,再转到载体系 acc_body = np.zeros_like(pos) for i in range(len(pos)): q = quat[i] / np.linalg.norm(quat[i]) # 由四元数构建旋转矩阵(导航系->载体系) w, x, y, z = q R_nb = np.array([ [1 - 2*(y*y + z*z), 2*(x*y - w*z), 2*(x*z + w*y)], [2*(x*y + w*z), 1 - 2*(x*x + z*z), 2*(y*z - w*x)], [2*(x*z - w*y), 2*(y*z + w*x), 1 - 2*(x*x + y*y)] ]) f_ned = acc[i] - g acc_body[i] = R_nb @ f_ned gyro = pose_to_gyro(quat, dt) return acc_body, gyro注意这里acc_body的 z 轴在水平静止时约为 −9.81 m/s²,而不是 +9.81,这是 NED 系下比力定义的自然结果。如果某个下游滤波器里加速度计输入约定是“正向上”,需要在这里统一翻转,别等数据灌进去才发现符号反了。边界点的加速度用单侧差分填值,仿真一般前后留一段静止过渡带,边界误差不会影响核心段落。位置序列如果来自样条插值,最好在插值阶段直接解析求二阶导,不要用差分,数值噪声会小很多。
3.3 时间同步与采样频率对齐:仿真数据的“隐形水印”
轨迹发生器里最容易埋下隐患的是时间轴。轨迹定义频率、IMU 输出频率、滤波器更新频率三者如果不一致,仿真数据看起来波形正常,但一进滤波器就发散。我的做法是:统一用 IMU 频率作为整个仿真的基准时钟,轨迹曲线先在基准时钟上插值重采样,再参与反解。反解得到的 IMU 数据自带时间戳数组,时间戳用整数计数 + 基准时间偏移,避免浮点累加误差造成的时间抖动。
频率对齐要关注数值化的细节。位置曲线在粗采样时是平滑的,重采样到高频 IMU 时钟后,如果直接用线性插值会在加速度上引入高频台阶,所以我的习惯是在轨迹定义阶段就把时间步长设成 IMU 周期,不做二次插值;如果必须插值,用三阶样条并对加速度项做平滑滤波。时间同步的验证指标很简单:检查 IMU 时间戳差分序列是否恒定等于 dt,以及反解出的角速率曲线在静止段是否严格为零。这两项过了,数据的时间轴才合格。
4. 误差注入:让仿真数据带着 MEMS 器件该有的噪声与零偏
理想反解出的 IMU 数据只能用来验证算法框架,不能用来验证滤波器鲁棒性,因为真实传感器输出的不是光滑曲线,而是带着白噪声、零偏、随机游走和温漂的“脏数据”。误差注入是轨迹发生器的另一大价值:你可以精确控制噪声大小,然后在滤波调试时观察算法对每类误差的响应。误差模型按复杂度可以拆成三层:加性白噪声、常值零偏与随机游走、以及更精细的标度因数和安装误差。
4.1 噪声模型:白噪声、零偏、随机游走怎么加
最基本也最常用的是加性白噪声加常值零偏。白噪声用高斯随机数生成,标准差由传感器白噪声功率谱密度换算而来;常值零偏则直接加在理想数据上。随机游走项用于模拟零偏的慢变漂移,实现方式是把白噪声序列做累积和——这样陀螺的角速率输出就会出现典型的“低频漂移”特征。三个误差叠加后的数据用于滤波调参,能基本覆盖 MEMS 惯性传感器的主要误差形态。
def add_sensor_errors(data, dt, sigma_w, bias, sigma_rw=0.0): # data: (N, 3) 理想陀螺或加计数据 # sigma_w: 白噪声标准差,单位与 data 一致 # bias: 常值零偏向量,如 [0.01, 0.01, 0.02] # sigma_rw: 随机游走噪声标准差(可选),0 表示不注入 n = len(data) # 白噪声项:每个通道独立高斯噪声 wnoise = np.random.randn(n, 3) * sigma_w # 随机游走项:白噪声积分,模拟零偏缓慢漂移 rw = np.zeros((n, 3)) if sigma_rw > 0.0: steps = np.random.randn(n, 3) * sigma_rw * np.sqrt(dt) np.cumsum(steps, axis=0, out=rw) return data + wnoise + rw + bias注入逻辑要说明两个关键点:一是sigma_w的单位和数据本身一致,陀螺是 °/s,加计是 m/s²,换算关系要从器件手册的白噪声功率谱密度出发,不要拿“随机游走”参数直接当白噪声标准差用;二是sigma_rw乘以sqrt(dt)是为了保证随机游走的方差随时间线性增长,这一步很多人漏掉,导致漂移速度与采样频率有关,换了采样率数据行为就变了。随机游走累积之后还要做一次零均值强迫,否则长期运行会叠加出一个整体偏置,不利于滤波器对比。
4.2 标度因数与安装误差:高精度仿真才考虑的事
标度因数误差指传感器输出的比例因子与真实值之间有一个偏差,比如真实角速率 10°/s 输出 9.95°/s;安装误差则是三个敏感轴之间不完全正交,造成轴间串扰。这两个误差在低精度算法验证阶段可以先不管,但当你要验证组合导航里的标定算法或者评估传感器选型时,就很有必要注入。实现方式也很简单:把理想量先乘一个标度因数矩阵,再叠加上轴间串扰矩阵,最后才加噪声。
我一般把误差注入的链路顺序固定为:标度因数与安装误差 → 零偏 → 白噪声 → 随机游走。这个顺序有讲究,如果先加噪声再乘标度因数,噪声幅度也会被错误地放大或缩小;反过来先乘标度因数,再叠加零偏,符合传感器的物理结构模型。后面调滤波器参数时,每个误差项的注入幅度要单独记录在配置表里,方便复现每一次仿真的数据。
4.3 误差参数调试:按器件手册设置,不是拍脑袋
误差参数设置是仿真数据能否迁移到真实场景的分水岭。我见过不少仿真数据做得非常漂亮,但用的是拍脑袋的噪声参数,最后算法到真机上完全失效。标准做法是参考所选 MEMS 器件手册给出的典型值,再结合实际标定结果微调。下面给出我常用的一组量级参考,具体数值必须以实际器件手册为准。
| 误差项 | 典型量级 | 说明 |
|---|---|---|
| 陀螺白噪声 | 0.001 ~ 0.01 °/s/√Hz | 对应角度随机游走约 0.06 ~ 0.6 °/√h |
| 陀螺常值零偏 | 0.01 ~ 0.1 °/s | MEMS 级,开机后基本不变 |
| 陀螺零偏随机游走 | 0.001 ~ 0.01 °/s² | 模拟温度漂移导致的慢变 |
| 加计白噪声 | 0.01 ~ 0.1 m/s²/√Hz | 对应速度随机游走几十到几百 μg/√Hz |
| 加计零偏 | 0.01 ~ 0.1 m/s² | 工程上叫几个 mg 到几十个 mg |
| 标度因数误差 | 0.1% ~ 1% | 出厂校准后残差 |
参数调整有一个技巧:先把零偏和噪声都设成零,跑一遍理想数据,确认轨迹发生器本身没有误差;然后只加白噪声,观察滤波器估计的噪声方差是否与注入值匹配;最后逐步加零偏和随机游走,验证滤波器能否把零偏估计出来。用这种“分步注入”的方式调试,任何一个环节出错都能快速定位,不会出现多个误差混在一起互相掩盖的情况。
提示:误差注入不是让数据“看起来更乱”,而是让数据具备某种确定的统计特征。每注入一个误差项,就应该用相应的统计工具去验证——白噪声看功率谱密度,零偏看长时间平均值,随机游走看 Allan 方差的斜率。验证不过,参数就是错的。
5. 避坑实战:轨迹发生器调试中的五个高频翻车点
轨迹发生器自己出问题时,症状经常被误认为算法的问题。下面这五条是我在调试中反复踩过的坑,照着检查能省下大量排查时间。
5.1 轨迹不闭合,解算结果却“自洽”
现象:生成的轨迹起点和终点不重合,明显不合理,但把 IMU 数据灌进纯惯导解算器后,解算轨迹却能回到起点附近,看起来“自洽”。
原因:反解时比力方程里的重力符号搞反了,或旋转矩阵转置错误。这种双重错误会让加速段和减速段的误差相互抵消,解算结果看似合理,但中间过程每一个中间时刻的状态都是错的。
解决:先不急着看解算结果,直接检查反解出的加速度计比力序列。取一段水平静止段,比力 z 轴应当严格等于 −9.81 m/s²;再取一段匀加速段,对比比力 x 轴是否等于理论加速度减去重力后的投影。符号错了立刻能暴露。
5.2 加速度计数据里混入重力分量
现象:静止段加计输出不是约 −9.81 m/s²,而是 0 或者 +9.81 m/s²。整个轨迹数据拿到滤波器里,加计零偏估计出来等于 1g。
原因:反解时直接对位置做了二次差分,忘了减掉重力矢量。位置加速度和比力是两个概念,二次差分得到的是运动加速度,不是 IMU 的输出。
解决:反解函数里把比力方程写成独立一行f_ned = acc - g,不要把它和加速度计算揉在一起。同时加一个单元测试:输入一个完全静止的位置序列,断言加计输出等于 −g 在载体系下的投影。
5.3 陀螺数据在静止段“纹丝不动”
现象:静止段陀螺输出严格为零,但惯导解算的姿态在静止段却缓慢漂移,而且漂移方向看起来很诡异。
原因:理想轨迹反解出的陀螺本来就应该是零,问题出在误差注入时没加零偏和随机游走。真实 MEMS 陀螺静止时输出带有零偏,这个零偏正是姿态漂移的主要来源;完全“干净”的数据反而让滤波器无法真实评估。
解决:在误差注入阶段至少加一项常值零偏,然后检查静止段陀螺输出的均值是否等于设定的 bias 值。如果滤波器算法里有零偏估计功能,零偏值应当能被逐步估计并收敛。
5.4 插值轨迹出现负速度或超速
现象:轨迹的位置曲线看起来平滑,但导出的速度曲线在某些区间出现负值,或者最大加速度远超设定值。
原因:轨迹用样条直接插值航迹点,样条过冲导致的局部超调在速度和加速度上被放大。位置曲线看不出问题,但速度是位置的一阶导,加速度是二阶导,微小过冲会被放大到不可接受。
解决:放弃样条直接插值,改回“先设计速度或加速度曲线再积分”的方式。如果必须用样条,就检查速度曲线的最小值不能为负(对于单向行驶场景),并且对加速度曲线做峰值统计,超过设定a_max直接报错。
5.5 采样率不匹配导致滤波器发散
现象:轨迹数据的 IMU 输出频率和滤波器更新时间Auß不符,仿真跑不过几秒滤波器就发散,发散前明显看到观测更新频率异常。
原因:轨迹定义时用了 1 Hz 的控制点频率,反解 IMU 用了 10 Hz,但滤波器的惯导解算以 100 Hz 运行,时间轴对不上,观测量的时间戳一乱,协方差更新全部错位。
解决:在轨迹发生器里把 IMU 频率设成单一基准,所有轨迹曲线先重采样到这个基准频率,再参与反解。生成的数据文件里必须带一列时间戳,后续管道代码用时间戳对齐,而不是靠“第几个数组”推断。
6. 进阶:用回环一致性检查轨迹发生器的数据质量
轨迹发生器的数据质量可以用一个“回环测试”来整体验证:把理想反解出来的 IMU 数据(不含任何误差)重新灌入捷联解算器,解算结果应当和原始轨迹完全一致。这个测试通过,说明轨迹定义、反解、坐标转换整条链路没有系统性错误。如果回环测试有偏差,偏差会随着积分时间线性增大,那就先不要谈误差注入和滤波,回去查反解链路。
回环测试可以做成一个自动检查脚本,我平时会在生成每一条仿真轨迹后都跑一遍。
def roundtrip_check_horizontal(pos, acc_body, dt): # 仅适用于水平直线运动场景的快速回环检查 # 输入:原始位置 pos,(N,3);反解加计 acc_body,(N,3) # 输出:解算位置与原始位置的最大偏差 g = np.array([0.0, 0.0, 9.81]) vel = np.zeros((len(pos), 3)) pos_est = np.zeros((len(pos), 3)) for i in range(len(pos) - 1): # 比力加回重力得到运动加速度,这里假设载体水平 acc_ned = acc_body[i] + g vel[i + 1] = vel[i] + acc_ned * dt pos_est[i + 1] = pos_est[i] + vel[i] * dt err = np.max(np.linalg.norm(pos_est - pos, axis=1)) return err这个脚本里最关键的一步是acc_ned = acc_body[i] + g,它把反解时减掉的重力加回来,恢复成运动加速度,再做二重积分。姿态变化大的场景这个脚本会失效,完整做法是用四元数姿态积分和比力方程做正向解算。验证通过标准我习惯设为:10 分钟仿真轨迹回环误差小于 0.1 m,超过这个量说明反解链路的数值精度不够,需要检查差分方式和 dt 设定。回环测试通过之后,再跑一遍加误差的完整流程,得到的解算结果与真值之间的差值,就应当基本等于误差注入的影响——这正是轨迹发生器用于算法调试的最终形态。
我现在的习惯是每个仿真工程先跑回环自查,再进入算法调试。这个习惯帮我把“轨迹生成问题”和“算法问题”彻底分开,省掉大量两头排查的时间。做惯导仿真的日子久了你会发现,轨迹发生器的质量几乎决定了算法验证的可信度,数据源头错了,后边所有努力都会白费。希望帮到你。
本文还有配套的精品资源,点击获取