扩展卡尔曼滤波(EKF)作为非线性系统状态估计的经典方法,在无人机、机器人等载体的三维姿态估计中发挥着关键作用。与线性卡尔曼滤波不同,EKF通过局部线性化的方式处理非线性系统,这使得它能够有效应对姿态估计中固有的非线性特性。
在三维空间中,物体的姿态通常采用四元数或欧拉角表示。四元数因其计算效率和避免万向节锁等优点,成为工程实践中的首选表示方法。一个四元数q可以表示为q = [w, x, y, z],其中w为实部,x、y、z为虚部。四元数的单位长度特性(w²+x²+y²+z²=1)使其能够完整描述三维旋转。
典型的姿态估计状态向量包含姿态信息(四元数)和角速度信息:
x = [q; ω] = [w, x, y, z, ωx, ωy, ωz]ᵀ
运动模型描述姿态随时间的演化,核心是四元数微分方程:
dq/dt = 0.5 * q ⊗ [0; ω]
其中⊗表示四元数乘法运算。这个方程揭示了角速度与姿态变化率之间的数学关系。
在实际离散化实现时,我们通常采用一阶近似:
qₖ = qₖ₋₁ ⊗ exp(0.5 * [0; ωₖ₋₁] * Δt)
其中Δt为采样时间间隔,exp()为四元数指数映射。
观测数据主要来自IMU的加速度计和磁力计。加速度计测量重力方向(在静止状态下),磁力计测量地磁场方向。观测模型将这些物理量映射到状态空间:
加速度观测模型:
a_pred = R(q)ᵀ * g
其中R(q)是四元数对应的旋转矩阵,g是世界坐标系下的重力向量(通常取[0,0,1]ᵀ)。
磁力观测模型:
m_pred = R(q)ᵀ * h
h是世界坐标系下的地磁向量(通常归一化处理)。
这两个观测量为系统提供了绝对参考,弥补了陀螺仪积分导致的漂移问题。
预测步骤包含状态预测和协方差预测两个核心操作:
状态预测:
xₖ|ₖ₋₁ = f(xₖ₋₁, uₖ)
其中f(·)是非线性状态转移函数,uₖ是系统输入(通常为角速度测量值)。
协方差预测:
Pₖ|ₖ₋₁ = Fₖ Pₖ₋₁ Fₖᵀ + Qₖ
Fₖ是状态转移函数的雅可比矩阵,Qₖ是过程噪声协方差矩阵。
雅可比矩阵Fₖ的计算是EKF区别于KF的关键,它通过对非线性函数f(·)在当前状态估计处进行一阶泰勒展开得到。对于四元数姿态表示,这个雅可比矩阵需要考虑四元数乘法的特殊性质。
更新步骤将观测信息融入状态估计:
卡尔曼增益计算:
Kₖ = Pₖ|ₖ₋₁ Hₖᵀ (Hₖ Pₖ|ₖ₋₁ Hₖᵀ + Rₖ)⁻¹
其中Hₖ是观测模型的雅可比矩阵,Rₖ是观测噪声协方差矩阵。
状态更新:
xₖ = xₖ|ₖ₋₁ + Kₖ (zₖ - h(xₖ|ₖ₋₁))
h(·)是非线性观测函数,zₖ是实际观测值。
协方差更新:
Pₖ = (I - Kₖ Hₖ) Pₖ|ₖ₋₁
过程噪声Q和观测噪声R的设定对滤波器性能至关重要:
Q反映系统模型的不确定性,通常设置为对角矩阵,对角元素对应状态各分量的噪声强度。角速度噪声通常比姿态噪声大1-2个数量级。
R反映传感器测量噪声特性,可通过传感器静止时的数据统计得到。加速度计的R值通常比磁力计小,因为重力测量相对稳定。
实际调试时,可以采用"调参金字塔"方法:
在MATLAB实现中,四元数处理需要特别注意:
归一化处理:每次状态更新后必须执行q = q/‖q‖,保持四元数单位长度。忽略这步会导致滤波器发散。
四元数乘法:MATLAB提供了quatmultiply函数,但理解其底层实现很重要。自定义函数时注意乘法顺序:
function q = quatMultiply(q1, q2)
w = q1(1)*q2(1) - q1(2)*q2(2) - q1(3)*q2(3) - q1(4)*q2(4);
x = q1(1)*q2(2) + q1(2)*q2(1) + q1(3)*q2(4) - q1(4)*q2(3);
y = q1(1)*q2(3) - q1(2)*q2(4) + q1(3)*q2(1) + q1(4)*q2(2);
z = q1(1)*q2(4) + q1(2)*q2(3) - q1(3)*q2(2) + q1(4)*q2(1);
q = [w; x; y; z];
end
EKF性能很大程度上取决于雅可比矩阵计算的准确性。对于姿态估计系统,推荐采用符号计算预先推导雅可比表达式,而非数值差分:
状态转移雅可比F:
syms qw qx qy qz wx wy wz dt
q = [qw; qx; qy; qz];
omega = [wx; wy; wz];
q_dot = 0.5 * quatMultiply(q, [0; omega]);
F = jacobian([q + q_dot*dt; omega], [q; omega]);
观测雅可比H:
R = quat2rotm(q.');
g = [0; 0; 1];
h = [1; 0; 0];
a_pred = R.' * g;
m_pred = R.' * h;
H = jacobian([a_pred; m_pred], [q; omega]);
将生成的表达式转换为MATLAB代码可显著提高运行效率。
良好的初始化是滤波器快速收敛的关键:
静态初始化:当载体初始静止时,利用加速度计和磁力计数据计算初始姿态:
acc = acc_data/norm(acc_data);
mag = mag_data/norm(mag_data);
down = -acc;
east = cross(mag, down); east = east/norm(east);
north = cross(down, east);
R = [north, east, down].';
q0 = rotm2quat(R);
动态初始化:运动状态下,可采用短时间内的陀螺积分初步估计姿态,然后切换至EKF。
初始协方差P₀通常设为对角矩阵,姿态部分较小(1e-4),角速度部分较大(1e-2)。
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 滤波器发散 | 噪声协方差设置不当 | 重新调整Q/R,减小过程噪声 |
| 姿态估计漂移 | 磁力计干扰或未校准 | 校准磁力计,检测磁场干扰 |
| 响应迟缓 | 观测噪声R设置过大 | 减小R的对角元素值 |
| 高频抖动 | 过程噪声Q设置过小 | 增大Q的对角元素值 |
| 初始化异常 | 初始姿态计算错误 | 检查加速度计/磁力计数据质量 |
计算效率优化:
数值稳定性增强:
自适应调参:
典型的EKF姿态估计MATLAB实现包含以下模块:
初始化模块
主循环模块
工具函数
状态预测函数示例:
function [x_pred, F] = predict_state(x, gyro, dt, Q)
% 解包状态
q = x(1:4); omega = x(5:7);
% 四元数积分
omega_norm = norm(omega);
if omega_norm > eps
delta_q = [cos(omega_norm*dt/2);
sin(omega_norm*dt/2)*omega/omega_norm];
else
delta_q = [1; 0; 0; 0]; % 无旋转情况
end
q_pred = quatMultiply(q, delta_q);
% 状态转移雅可比
F = eye(7);
F(1:4,1:4) = quatJacobian(q, omega, dt);
F(1:4,5:7) = omegaJacobian(q, omega, dt);
% 预测状态
x_pred = [q_pred; omega];
P_pred = F * P * F' + Q;
end
观测更新函数示例:
function [x_updated, P_updated] = update_attitude(x_pred, P_pred, acc, mag, R)
% 解包状态
q = x_pred(1:4);
% 预测观测
Rq = quat2rotm(q');
z_pred = [Rq' * [0;0;1]; % 重力方向
Rq' * [1;0;0]]; % 地磁方向
% 观测残差
z = [acc/norm(acc); mag/norm(mag)];
y = z - z_pred;
% 观测雅可比
H = zeros(6,7);
H(1:3,1:4) = accJacobian(q);
H(4:6,1:4) = magJacobian(q);
% 卡尔曼增益
S = H * P_pred * H' + R;
K = P_pred * H' / S;
% 状态更新
x_updated = x_pred + K * y;
x_updated(1:4) = x_updated(1:4)/norm(x_updated(1:4)); % 归一化
% 协方差更新
P_updated = (eye(7) - K * H) * P_pred;
end
结果可视化通常包括:
性能评估指标:
在MATLAB中,可以使用animatedline函数实时显示姿态变化,或使用quiver3绘制3D坐标系演示姿态估计结果。