简介:本资源面向本硕博等教研学习人群,提供基于UKF(无迹卡尔曼滤波)的6自由度火箭飞行预测跟踪与状态估计完整MATLAB实现,解决如何利用加速计、陀螺仪和GPS多源数据融合,完成火箭位置、速度与姿态估计的问题,适合导航制导、状态估计方向的中高级学习者。压缩包共8个文件,约188KB,包含6个m脚本文件、1个txt说明文档和1个avi操作录像,脚本覆盖主运行入口、仿真、估计、动力学方程及误差与真值绘图等模块,txt用于辅助说明,视频则演示完整操作流程。目前已有399人学习下载。读者可借助该资源掌握UKF在非线性飞行状态估计中的建模思路与代码组织方式,通过运行主脚本复现仿真结果,对照误差曲线与真值曲线评估滤波性能,并跟随录屏排查运行问题,快速搭建可复用的火箭跟踪估计实验框架。
1. 从一条加速度计读数说起:UKF 在 6 自由度火箭状态估计里到底解决什么问题
火箭飞行过程中,加速度计测的是比力,陀螺仪测的是角速度,GPS 给的是位置和速度,但三者都带噪声、都有延迟、都有各自的坐标系。单独用任何一个传感器,都推不出完整的 6 自由度状态——位置、速度、姿态、角速度、加速度偏置。工程上真正要做的,是把这些异构观测塞进一个滤波器里,让它在火箭高速、大机动、GPS 偶尔丢星的条件下,仍然稳定输出可用的状态估计。UKF(Unscented Kalman Filter,无迹卡尔曼滤波)就是干这个的:它不做雅可比线性化,而是用一组 sigma 点穿过非线性动力学,再统计均值和协方差。对火箭这种姿态用四元数、动力学强非线性的对象,UKF 比 EKF 更省心,也比粒子滤波更适合嵌入式实时跑。下面这套方案,从状态定义、动力学建模、观测模型到代码落地,按能复现的顺序讲清楚。
2. 6 自由度状态定义与 UKF 预测跟踪的建模细节
2.1 状态向量怎么选:15 维还是 16 维
火箭 6 自由度通常指三轴位置、三轴速度、三轴姿态、三轴角速度。但 UKF 要估计的不只是运动量,还要把传感器偏置一起估出来,否则加速度计零偏会直接积分成位置漂移。常见做法是 15 维状态:
| 分量 | 维度 | 含义 | 单位 |
|---|---|---|---|
| p | 3 | 位置(NED) | m |
| v | 3 | 速度(NED) | m/s |
| q | 4 | 姿态四元数 | 无量纲 |
| ω | 3 | 机体角速度 | rad/s |
| b_a | 2 | 加速度计偏置(简化) | m/s² |
如果偏置按三轴全估,就是 16 维。四元数有模长约束,UKF 里要么在 sigma 点生成后归一化,要么用误差四元数做局部参数化。我一般用 15 维加归一化,代码简单,数值也稳。
2.2 连续动力学与离散化
机体坐标系下的平动和转动方程:
import numpy as np def dynamics(x, u, dt): """ x: [p(3), v(3), q(4), w(3), ba(2)] u: [a_m(3), w_m(3)] 加速度计和陀螺仪测量 dt: 采样周期 """ p = x[0:3]; v = x[3:6]; q = x[6:10]; w = x[10:13]; ba = x[13:15] a_m = u[0:3]; w_m = u[3:6] # 加速度计去偏置,机体系转导航系 a_b = a_m - np.array([ba[0], ba[1], 0.0]) R = quat_to_rot(q) a_n = R @ a_b + np.array([0, 0, -9.81]) # 重力补偿 # 四元数微分 q_dot = 0.5 * quat_mult(q, np.array([0, w[0], w[1], w[2]])) # 欧拉积分 p_new = p + v * dt v_new = v + a_n * dt q_new = q + q_dot * dt q_new = q_new / np.linalg.norm(q_new) w_new = w_m # 陀螺仪直接作为角速度观测 ba_new = ba return np.concatenate([p_new, v_new, q_new, w_new, ba_new])这段代码里,quat_to_rot把四元数转旋转矩阵,quat_mult是四元数乘法。重力补偿项[0,0,-9.81]按 NED 坐标系写,如果用的是 ENU,符号要改。dt一般取 0.01 s 对应 100 Hz IMU,GPS 通常 5~10 Hz,中间用预测步补齐。
2.3 UKF 的 sigma 点生成与权重
UKF 的核心是 UT 变换。给定均值x和协方差P,生成2n+1个 sigma 点:
def sigma_points(x, P, alpha=1e-3, beta=2.0, kappa=0.0): n = len(x) lam = alpha**2 * (n + kappa) - n P_sqrt = np.linalg.cholesky((n + lam) * P) X = np.zeros((2*n+1, n)) X[0] = x for i in range(n): X[i+1] = x + P_sqrt[:, i] X[n+i+1] = x - P_sqrt[:, i] Wm = np.full(2*n+1, 1/(2*(n+lam))) Wc = Wm.copy() Wm[0] = lam/(n+lam) Wc[0] = lam/(n+lam) + (1 - alpha**2 + beta) return X, Wm, Wcalpha控制 sigma 点散布,通常 1e-3 到 1;beta=2对高斯分布最优;kappa一般取 0 或3-n。P必须对称正定,Cholesky 分解失败时加对角小量1e-9。
2.4 观测模型:GPS 位置速度与 IMU 偏置
GPS 给导航系下的位置和速度,观测方程线性:
def h_gps(x): return x[0:6] # p 和 v H_gps = np.zeros((6, 15)) H_gps[0:6, 0:6] = np.eye(6)如果 GPS 还输出航向,可以加一维姿态观测,但航向在火箭低速段噪声大,我一般只用位置速度。观测噪声R_gps按 GPS 手册给,位置 2~5 m,速度 0.1~0.5 m/s,实际再乘 2 倍留余量。
3. 用 Python 跑通 UKF 预测跟踪的最小可复现代码
3.1 预测步:sigma 点传播与协方差重构
def ukf_predict(x, P, u, dt, Q): X, Wm, Wc = sigma_points(x, P) X_pred = np.array([dynamics(X[i], u, dt) for i in range(len(X))]) x_pred = np.sum(Wm[:, None] * X_pred, axis=0) P_pred = Q.copy() for i in range(len(X)): dx = X_pred[i] - x_pred P_pred += Wc[i] * np.outer(dx, dx) return x_pred, P_predQ是过程噪声协方差,按 IMU 噪声密度和dt算。加速度计噪声密度 0.01 m/s²/√Hz,对应Q里速度项约(0.01)^2 * dt。Q太小滤波器跟不上机动,太大输出抖,我一般先按传感器手册设,再乘 1.5 倍。
3.2 更新步:GPS 到达时的卡尔曼增益
def ukf_update(x, P, z, R, h_func): X, Wm, Wc = sigma_points(x, P) Z = np.array([h_func(X[i]) for i in range(len(X))]) z_pred = np.sum(Wm[:, None] * Z, axis=0) S = R.copy() Pxz = np.zeros((len(x), len(z))) for i in range(len(X)): dz = Z[i] - z_pred dx = X[i] - x S += Wc[i] * np.outer(dz, dz) Pxz += Wc[i] * np.outer(dx, dz) K = Pxz @ np.linalg.inv(S) x_new = x + K @ (z - z_pred) P_new = P - K @ S @ K.T return x_new, P_newS是新息协方差,K是增益。P_new用标准形式,数值不稳时改用 Joseph 形式。GPS 更新频率低,每次到达才调用,中间只跑预测。
3.3 主循环与数据对齐
dt_imu = 0.01 x = np.zeros(15); x[6] = 1.0 # 四元数初始为单位 P = np.eye(15) * 1.0 Q = np.diag([1e-6]*3 + [1e-4]*3 + [1e-8]*4 + [1e-6]*3 + [1e-8]*2) R_gps = np.diag([4.0]*3 + [0.25]*3) for k in range(len(imu_data)): u = np.concatenate([imu_data[k][0:3], imu_data[k][3:6]]) x, P = ukf_predict(x, P, u, dt_imu, Q) if gps_available[k]: z = np.concatenate([gps_data[k][0:3], gps_data[k][3:6]]) x, P = ukf_update(x, P, z, R_gps, h_gps)IMU 和 GPS 时间戳要对齐,GPS 到达时刻插值到最近 IMU 步。P初始给大一点,让滤波器快速收敛。
4. 参数调优与常见发散问题的排查路径
4.1 Q 和 R 的整定顺序
先调R,再调Q。R反映观测可信度,GPS 位置噪声实测比手册大,用静态数据算标准差。Q反映模型可信度,火箭推力段加速度变化快,Q速度项要放大。一个实用做法:用一段已知轨迹的仿真数据,网格搜Q的缩放因子,看位置 RMSE 最低点。
4.2 四元数归一化与协方差正定
每次预测后归一化四元数,但协方差里四元数部分会因此失去一致性。常见做法是只对误差四元数维护 3 维协方差,或者归一化后把P对应块投影到切空间。如果 Cholesky 报错,检查P是否对称,加1e-9 * np.eye(15)。
4.3 GPS 丢星时的处理
GPS 丢星超过 1 s,位置协方差会快速膨胀。此时不要继续用旧观测,只跑预测,并把Q位置项临时放大。如果丢星超过 10 s,速度误差会积分成几十米位置误差,需要靠气压高度或地磁辅助。代码里加一个计数器:
if gps_available[k]: gps_lost = 0 else: gps_lost += 1 if gps_lost > 100: Q[0:3, 0:3] *= 104.4 姿态估计的验证方法
没有真值姿态时,用静止段重力方向反算 roll 和 pitch,和 UKF 输出对比。动态段看四元数是否平滑,角速度积分和陀螺仪原始读数是否一致。如果姿态发散,先查陀螺仪零偏是否被估进去,再看Q角速度项是否太小。
5. 从仿真到半实物:UKF 火箭跟踪的进阶技巧
5.1 用仿真数据做闭环验证
先写一个真值动力学生成轨迹,加噪声当观测,跑 UKF 看估计误差。真值动力学和滤波器动力学可以故意不一致,比如真值用 RK4,滤波器用欧拉,看鲁棒性。位置 RMSE 在 5 m 以内、姿态误差 2° 以内算合格。
5.2 自适应 UKF 的简化实现
固定Q和R在机动段容易滞后。一个低成本自适应:用新息z - z_pred的滑动方差调整R。新息方差大于S时,说明观测异常或模型失配,临时放大R:
innov = z - z_pred if np.linalg.norm(innov) > 3 * np.sqrt(np.diag(S)): R_adapt = R * 4 else: R_adapt = R5.3 代码操作视频里值得暂停看的三个点
第一,sigma 点生成后检查P_sqrt是否实数,出现复数说明P非正定。第二,更新步里S求逆前看条件数,大于 1e12 就加对角正则。第三,主循环里打印gps_lost和np.trace(P),协方差爆炸前会有明显上升趋势。把这三处日志打开,比事后调参省一半时间。
本文还有配套的精品资源,点击获取