非线性滤波——基于EKF的INS/GPS松组合算法的研究(间接法|EKF|欧拉角)

2023-10-12 06:59

本文主要是介绍非线性滤波——基于EKF的INS/GPS松组合算法的研究(间接法|EKF|欧拉角),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在之前的博文《非线性滤波——基于EKF的INS/GPS松组合算法的研究(直接法|EKF|欧拉角)》中,我们记录了直接形式的EKF实现INS/GPS松组合算法,并在《卡尔曼滤波——直接法VS间接法》中对比说明了直接法与间接法的优劣。本文,我们记录使用间接反馈校正形式的EKF算法实现INS/GPS松组合算法。

建立模型

本文的INS/GPS组合模型主要参考文献:
Barton, Jeffrey. (2012). Fundamentals of Small Unmanned Aircraft Flight. Johns Hopkins Apl Technical Digest. 31. 132-149.
实验数据来源于之前的博客:非线性滤波——INS/GPS组合导航仿真数据的生成

INS/GPS的松组合模型可以用状态方程和测量方程描述与《非线性滤波——基于EKF的INS/GPS松组合算法的研究(直接法|EKF|欧拉角)》中一致,此处将其简记为
x ˙ = f ( x ) + w ( t ) , w ( t ) ∼ N ( 0 , Q ) \dot{\bold{x}}=f(\bold{x})+\bold{w}(t), \mathbf{w}(t) \sim N(0, \mathbf{Q}) x˙=f(x)+w(t),w(t)N(0,Q)

z ˉ = h ( x ) + v ( t ) , v ( t ) ∼ N ( 0 , R ) \bar{\bold{z}}=h(\bold{x})+\bold{v}(t), \mathbf{v}(t) \sim N(0, \mathbf{R}) zˉ=h(x)+v(t),v(t)N(0,R)

假设在时刻 t t t的状态 x ( t ) \bold{x}(t) x(t)是未知的,但我们知道其大致范围,则可以选定一个值 x ∗ ( t ) \bold{x}^*(t) x(t),只要得到了 δ x ( t ) = x ( t ) − x ∗ ( t ) \bold{\delta x}(t)=\bold{x}(t)-\bold{x}^{*}(t) δx(t)=x(t)x(t)的估计,就可以修正 x ∗ ( t ) \bold{x}^*(t) x(t),从而得到对 x ( t ) \bold{x}(t) x(t)更准确的估计。
在选取 x ∗ ( t ) \bold{x}^*(t) x(t)时需要满足以下关系
x ∗ ( t ) = f ( x ∗ ( t ) ) \bold{x}^*(t) = f(\bold{x}^*(t)) x(t)=f(x(t))

z ∗ ( t ) = h ( x ∗ ( t ) ) \bold{z}^*(t)=h(\bold{x}^*(t)) z(t)=h(x(t))
将上面两个方程与模型本身相减,并用泰勒级数展开,略去高阶项,得到
δ x ˙ ( t ) = F ( t ) δ x ( t ) + w ( t ) \delta \dot {\bold{{x}}}(t)=\boldsymbol{F}(t) \delta \bold{x}(t)+\bold{w}(t) δx˙(t)=F(t)δx(t)+w(t)

δ z = H ( t ) δ x ( t ) + v ( t ) \delta{\bold{z}}=\boldsymbol{H}(t) \delta \bold{x}(t)+\bold{v}(t) δz=H(t)δx(t)+v(t)
其中
F ( t ) = ∂ f ∂ x ∣ x ∗ , H ( t ) = ∂ h ∂ x ∣ x ∗ \boldsymbol{F}(t)=\left.\frac{\partial f}{\partial x}\right|_{x^{*}}, \boldsymbol{H}(t)=\left.\frac{\partial \boldsymbol{h}}{\partial \boldsymbol{x}}\right|_{x^{*}} F(t)=xfx,H(t)=xhx
其余步骤与之前的博文《非线性滤波——基于EKF的INS/GPS松组合算法的研究(直接法|EKF|欧拉角)》相同。
特别注意: 在程序中对误差状态量进行一步预测时,与直接法不同,需要将误差状态的一步预测值置零。因为在最后一步状态修正中
x ^ k + 1 ∣ k + 1 = x ^ k + 1 ∣ k + δ x ^ k + 1 ∣ k + 1 \hat{\bold{x}}_{k+1 | k+1}=\hat{\bold{x}}_{k+1 | k}+\delta \hat{\bold{x}}_{k+1 | k+1} x^k+1k+1=x^k+1k+δx^k+1k+1
经过修正后有
x ^ k + 1 ∣ k + 1 = E { x ( t k + 1 ) } \widehat{\bold{x}}_{k+1 | k+1}=E\left\{\bold{x}\left(t_{k+1}\right)\right\} x k+1k+1=E{x(tk+1)}
所以 δ x ^ k + 1 ∣ k + 1 = 0 \delta \hat{\bold{x}}_{k+1 | k+1}=0 δx^k+1k+1=0,也就 δ x ^ k ∣ k = 0 \delta \hat{\bold{x}}_{k | k}=0 δx^kk=0

仿真实现

本文代码在github及gitee(国内镜像)中不定时维护,代码内容可能与本文有所出入,地址:
https://github.com/tsuibeyond/BasicEKF
https://gitee.com/tsuibeyond/BasicEKF

clc
clear % 生成仿真数据
generate_uav_sensors_structure;% 重力加速度常量,m/s^2
g_mps2 = 9.81;  % 定义directEKF算法相关变量
ekf = [];
% 磁强计和GPS测量噪声估计,用于构造 R 矩阵
ekf.sigmas.mag2D_meas_rad        = sqrt(uavSensors.sigmas.mag2D_yaw_noise_rad^2);
ekf.sigmas.pos_meas_m            = sqrt(uavSensors.sigmas.GPSpos_noise_m^2);
ekf.sigmas.vel_meas_mps          = sqrt(uavSensors.sigmas.GPSvel_noise_mps^2);
ekf.R_gps = diag([...[1 1 1]*ekf.sigmas.pos_meas_m ...            % North-East-Alt position measurement noise, m[1 1 1]*ekf.sigmas.vel_meas_mps ...          % NED velocity measurement noise, m/s].^2);
ekf.R_gps = max(ekf.R_gps,(1e-3)^2*eye(size(ekf.R_gps)));    
ekf.R_mag2d = ekf.sigmas.mag2D_meas_rad;
ekf.R_mag2d = max(ekf.R_mag2d,(1e-3)^2*eye(size(ekf.R_mag2d)));   % 陀螺仪和加速度计初始估计的不确定度,用于构造P矩阵(协方差矩阵)
ekf.sigmas.gyro_bias_rps         = uavSensors.sigmas.gyro_bias_rps;
ekf.sigmas.accel_bias_mps2       = uavSensors.sigmas.accel_bias_mps2;% EKF过程噪声估计,用于构造 Q 矩阵
% Q 矩阵需要根据经验调节。Q 值代表了我们对状态模型的置信程度
ekf.sigmas.attitude_process_noise_rad = 0.002;%0.002;% Euler angle process noise, rad
ekf.sigmas.pos_process_noise_m = 0.005;%0;           % Position process noise, m
ekf.sigmas.vel_process_noise_mps = 0.001;%2;         % Velocity process noise, m/s
ekf.sigmas.gyroBias_process_noise_rps = 1e-5;%1e-6; % Gyro bias process noise, rad/s
ekf.sigmas.accelBias_process_noise_mps2=1e-5;%1e-6; % Accel bias process noise, m/s^2
ekf.Q = diag([...[1 1 1]*ekf.sigmas.attitude_process_noise_rad ...   % Euler angle process noise, rad[1 1 1]*ekf.sigmas.pos_process_noise_m ...          % North-East-Alt position process noise, m[1 1 1]*ekf.sigmas.vel_process_noise_mps ...        % NED velocity process noise, m/s[1 1 1]*ekf.sigmas.gyroBias_process_noise_rps ...   % XYZ gyro bias process noise, rad/s[1 1 1]*ekf.sigmas.accelBias_process_noise_mps2 ... % XYZ accel bias process noise, m/s^2].^2);
ekf.Q = max(ekf.Q,(1e-3)^2*eye(size(ekf.Q)));    % 设定EKF状态误差向量初始值
err_euler_init = [ 0 0 0 ];   % 欧拉角误差初始值, rad
err_pos_init = [ 0 0 0 ];
err_vel_init = [ 0 0 0 ];
ekf.xhat_err = [ ...err_euler_init ...                              %   1-3:Euler angle (Roll, Pitch, Yaw) 状态进行初始化,raderr_pos_init ...                                %   4-6: 对 North-East-Alt 位置状态进行初始化, merr_vel_init ...                                %   7-9: 对 NED 速度状态初始化, m/s[0 0 0] ...                                 % 10-12: 对 XYZ 三轴陀螺仪的常值偏差进行初始化, rad/s[0 0 0] ...                                 % 13-15: 对 XYZ 三轴加速度计的长治偏差进行初始化, m/s^2]';
clear err_euler_init err_pos_init err_vel_init% 设定EKF状态向量初始值
phi = 0;                                   % 横滚角初始值,rad
theta=0;                                   % 俯仰角初始值,rad
psi = uavSensors.mag2D_yaw_deg(1)*pi/180;  % 偏航角初始值, rad
euler_init = [ phi theta psi ];   
pos_init = [ uavSensors.GPS_north_m(1) uavSensors.GPS_east_m(1) uavSensors.GPS_h_msl_m(1) ];
vel_init = uavSensors.GPS_v_ned_mps(1,:);
ekf.xhat_ins = [ ...euler_init ...                              %   1-3:Euler angle (Roll, Pitch, Yaw) 状态进行初始化,radpos_init ...                                %   4-6: 对 North-East-Alt 位置状态进行初始化, mvel_init ...                                %   7-9: 对 NED 速度状态初始化, m/s[0 0 0] ...                                 % 10-12: 对 XYZ 三轴陀螺仪的常值偏差进行初始化, rad/s[0 0 0] ...                                 % 13-15: 对 XYZ 三轴加速度计的长治偏差进行初始化, m/s^2]';
clear psi theta phi euler_init pos_init vel_init% 对初始的协方差矩阵(P矩阵)设定较大值,以便EKF算法在初始的几次滤波步骤中更多的相信测量方程
large_angle_uncertainty_rad = 30*pi/180;
large_pos_uncertainty_m = 100;
large_vel_uncertainty_mps = 10;
ekf.P = diag([...[1 1 1]*large_angle_uncertainty_rad ...     % init Euler angle (NED-to-body) uncertainties, rad[1 1 1]*large_pos_uncertainty_m ...         % init North-East-Alt position uncertainties, m[1 1 1]*large_vel_uncertainty_mps ...       % init NED velocity uncertainties, m/s[1 1 1]*ekf.sigmas.gyro_bias_rps ...        % init XYZ gyro bias uncertainties, rad/s[1 1 1]*ekf.sigmas.accel_bias_mps2 ...      % init XYZ accel bias uncertainties, m/s^2].^2);
ekf.P = max(ekf.P,(1e-3)^2*eye(size(ekf.P)));    % 为了避免gyro_bias_rps和accel_bias_mps2设定为0
clear large_angle_uncertainty_rad large_pos_uncertainty_m large_vel_uncertainty_mps% 定义uavEst结构体并分配内存空间,用于存储估计的中间结果
uavEst.xhat = zeros(length(uavTruth.time_s),length(ekf.xhat_ins));
uavEst.P = zeros(length(uavTruth.time_s),length(ekf.xhat_ins));for kTime = 1 : length(uavSensors.time_s)% 计算两次滤波的时间间隔time_s                  = uavSensors.time_s(kTime);if kTime == 1dt_s = uavSensors.time_s(2) - uavSensors.time_s(1);elsedt_s = time_s - uavSensors.time_s(kTime-1);end% 获取滤波器所估计的状态量phi=ekf.xhat_ins(1);    theta=ekf.xhat_ins(2);  psi=ekf.xhat_ins(3);	% Roll, Pitch, Yaw Euler angles, radPn=ekf.xhat_ins(4); Pe=ekf.xhat_ins(5); Alt=ekf.xhat_ins(6);            % Position, North/East/Altitude, metersVn=ekf.xhat_ins(7); Ve=ekf.xhat_ins(8); Vd=ekf.xhat_ins(9);             % Velocity, North/East/Down, m/sbwx=ekf.xhat_ins(10);   bwy=ekf.xhat_ins(11);   bwz=ekf.xhat_ins(12);	% Gyro biases, rad/sbax=ekf.xhat_ins(13);   bay=ekf.xhat_ins(14);   baz=ekf.xhat_ins(15);	% Accelerometer biases, m/s^2% IMU 更新gyro_wb_rps             = uavSensors.gyro_wb_rps(kTime,:)';                     % 3x1 vectoraccel_fb_mps2           = uavSensors.accel_fb_mps2(kTime,:)';                   % 3x1 vectorwx = gyro_wb_rps(1);    wy = gyro_wb_rps(2);    wz = gyro_wb_rps(3);            % rad/sfx = accel_fb_mps2(1);    fy = accel_fb_mps2(2);    fz = accel_fb_mps2(3);      % m/s^2% 计算 xdotC_bodyrate2eulerdot  = [1      sin(phi)*tan(theta)    cos(phi)*tan(theta); ...0           cos(phi)                -sin(phi)    ; ...0      sin(phi)*sec(theta)    cos(phi)*sec(theta)];C_ned2b  = [cos(theta)*cos(psi)                               cos(theta)*sin(psi)                             -sin(theta); ...sin(phi)*sin(theta)*cos(psi)-cos(phi)*sin(psi)    sin(phi)*sin(theta)*sin(psi)+cos(phi)*cos(psi)   sin(phi)*cos(theta); ...cos(phi)*sin(theta)*cos(psi)+sin(phi)*sin(psi)    cos(phi)*sin(theta)*sin(psi)-sin(phi)*cos(psi)   cos(phi)*cos(theta)];C_b2ned=transpose(C_ned2b);xdot = [ ...C_bodyrate2eulerdot*([wx;wy;wz]-[bwx;bwy;bwz]); ...  % Derivative of [roll; pitch; yaw][Vn; Ve; -Vd]; ...                                   % Derivative of [Pn; Pe; Alt]C_b2ned*([fx;fy;fz]-[bax;bay;baz])+[0;0;g_mps2]; ... % Derivative of [Vn; Ve; Vd][0;0;0]; ...                                         % Derivative of [bwx; bwy; bwz][0;0;0]; ...                                         % Derivative of [bax; bay; baz]];% 计算 F 矩阵F = [ ...[                                                                 sin(phi)*tan(theta)*(bwz - wz) - cos(phi)*tan(theta)*(bwy - wy),                                  - cos(phi)*(bwz - wz)*(tan(theta)^2 + 1) - sin(phi)*(bwy - wy)*(tan(theta)^2 + 1),                                                                                                                                                              0, 0, 0, 0, 0, 0,  0, -1, -sin(phi)*tan(theta), -cos(phi)*tan(theta),                    0,                                                  0,                                                  0][                                                                                       cos(phi)*(bwz - wz) + sin(phi)*(bwy - wy),                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,            -cos(phi),             sin(phi),                    0,                                                  0,                                                  0][                                                             (sin(phi)*(bwz - wz))/cos(theta) - (cos(phi)*(bwy - wy))/cos(theta),                    - (cos(phi)*sin(theta)*(bwz - wz))/cos(theta)^2 - (sin(phi)*sin(theta)*(bwy - wy))/cos(theta)^2,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0, -sin(phi)/cos(theta), -cos(phi)/cos(theta),                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 1, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 1,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0, -1,  0,                    0,                    0,                    0,                                                  0,                                                  0][ - (sin(phi)*sin(psi) + cos(phi)*cos(psi)*sin(theta))*(bay - fy) - (cos(phi)*sin(psi) - cos(psi)*sin(phi)*sin(theta))*(baz - fz), cos(psi)*sin(theta)*(bax - fx) - cos(phi)*cos(psi)*cos(theta)*(baz - fz) - cos(psi)*cos(theta)*sin(phi)*(bay - fy), (cos(phi)*cos(psi) + sin(phi)*sin(psi)*sin(theta))*(bay - fy) - (cos(psi)*sin(phi) - cos(phi)*sin(psi)*sin(theta))*(baz - fz) + cos(theta)*sin(psi)*(bax - fx), 0, 0, 0, 0, 0,  0,  0,                    0,                    0, -cos(psi)*cos(theta),   cos(phi)*sin(psi) - cos(psi)*sin(phi)*sin(theta), - sin(phi)*sin(psi) - cos(phi)*cos(psi)*sin(theta)][   (cos(psi)*sin(phi) - cos(phi)*sin(psi)*sin(theta))*(bay - fy) + (cos(phi)*cos(psi) + sin(phi)*sin(psi)*sin(theta))*(baz - fz), sin(psi)*sin(theta)*(bax - fx) - cos(phi)*cos(theta)*sin(psi)*(baz - fz) - cos(theta)*sin(phi)*sin(psi)*(bay - fy), (cos(phi)*sin(psi) - cos(psi)*sin(phi)*sin(theta))*(bay - fy) - (sin(phi)*sin(psi) + cos(phi)*cos(psi)*sin(theta))*(baz - fz) - cos(psi)*cos(theta)*(bax - fx), 0, 0, 0, 0, 0,  0,  0,                    0,                    0, -cos(theta)*sin(psi), - cos(phi)*cos(psi) - sin(phi)*sin(psi)*sin(theta),   cos(psi)*sin(phi) - cos(phi)*sin(psi)*sin(theta)][                                                                 cos(theta)*sin(phi)*(baz - fz) - cos(phi)*cos(theta)*(bay - fy),                            cos(theta)*(bax - fx) + cos(phi)*sin(theta)*(baz - fz) + sin(phi)*sin(theta)*(bay - fy),                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,           sin(theta),                               -cos(theta)*sin(phi),                               -cos(phi)*cos(theta)][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0][                                                                                                                               0,                                                                                                                  0,                                                                                                                                                              0, 0, 0, 0, 0, 0,  0,  0,                    0,                    0,                    0,                                                  0,                                                  0]];    % 计算 PHI_k & Q_k 矩阵(一步预测矩阵 和 离散形式的过程噪声矩阵)nStates = length(ekf.xhat_ins);AA = [-F ekf.Q; zeros(nStates,nStates) F']*dt_s;BB = expm(AA); % <- Matrix exponential!PHI_k = BB(nStates+1:2*nStates,nStates+1:2*nStates)';Q_k = PHI_k*BB(1:nStates,nStates+1:2*nStates);% 一步预测 & 更新协方差ekf.xhat_ins = ekf.xhat_ins + xdot*dt_s;ekf.xhat_err = 0*ekf.xhat_err;ekf.P = PHI_k*ekf.P*PHI_k' + Q_k;% 磁强计测量融合(更新频率与IMU一致)mag2D_yaw_rad           = uavSensors.mag2D_yaw_deg(kTime)*pi/180;ekf.H_mag2d = [ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];ekf.K_mag2d = (ekf.P*ekf.H_mag2d')/(ekf.H_mag2d*ekf.P*ekf.H_mag2d'+ekf.R_mag2d);% 消除yaw角的范围约束while mag2D_yaw_rad>ekf.xhat_ins(3)+pi, mag2D_yaw_rad=mag2D_yaw_rad-2*pi; endwhile mag2D_yaw_rad<ekf.xhat_ins(3)-pi, mag2D_yaw_rad=mag2D_yaw_rad+2*pi; end
%     ekf.Z_mag2d = mag2D_yaw_rad;ekf.Z_mag2d_err = mag2D_yaw_rad - ekf.H_mag2d*ekf.xhat_ins;ekf.xhat_err = ekf.xhat_err + ekf.K_mag2d*(ekf.Z_mag2d_err - ekf.H_mag2d*ekf.xhat_err);ekf.P = (eye(length(ekf.xhat_ins))-ekf.K_mag2d*ekf.H_mag2d)*ekf.P;ekf.xhat_ins = ekf.xhat_ins + ekf.xhat_err;% GPS 测量更新 (更新频率较低)GPS_east_m              = uavSensors.GPS_east_m(kTime);GPS_north_m             = uavSensors.GPS_north_m(kTime);GPS_h_msl_m             = uavSensors.GPS_h_msl_m(kTime);GPS_v_ned_mps           = uavSensors.GPS_v_ned_mps(kTime,:)';            % 3x1 vectorGPS_valid               = uavSensors.GPS_valid(kTime);if GPS_validekf.H_gps = [ ...[ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0][ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0][ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0][ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]];ekf.K_gps = (ekf.P*ekf.H_gps')/(ekf.H_gps*ekf.P*ekf.H_gps'+ekf.R_gps);ekf.Z_gps = [ ...[GPS_north_m; GPS_east_m; GPS_h_msl_m];GPS_v_ned_mps];ekf.Z_gps_err = ekf.Z_gps - ekf.H_gps*ekf.xhat_ins;ekf.xhat_err = ekf.xhat_err + ekf.K_gps*(ekf.Z_gps_err - ekf.H_gps*ekf.xhat_err);ekf.P = (eye(length(ekf.xhat_ins))-ekf.K_gps*ekf.H_gps)*ekf.P;ekf.xhat_ins = ekf.xhat_ins + ekf.xhat_err;end% uavEst.xhat(kTime,:) = ekf.xhat_ins';
enduavEst.time_s = uavSensors.time_s;
uavEst.north_m = uavEst.xhat(:,4);
uavEst.east_m = uavEst.xhat(:,5);
uavEst.h_msl_m = uavEst.xhat(:,6);
uavEst.v_ned_mps = uavEst.xhat(:,7:9);
uavEst.roll_deg = rad2deg(uavEst.xhat(:,1));
uavEst.pitch_deg = rad2deg(uavEst.xhat(:,2));
uavEst.yaw_deg = rad2deg(uavEst.xhat(:,3));% 估计结果可视化
figure(1)
clf;
% 绘图的线型和点型设置
truthLineType    = 'b-';
sensedLineType   = 'gd';
estimateLineType = 'r.';
markerSize       = 6;
linewidth        = 2;%-东方向的位置估计结果
subplot(4,2,[1 3])
plot(uavSensors.GPS_east_m, uavSensors.GPS_north_m, sensedLineType, ...uavEst.east_m,         uavEst.north_m,         estimateLineType, ...uavTruth.east_m,       uavTruth.north_m,       truthLineType, ...'markersize',markerSize, 'linewidth', linewidth);
hold on
plot(uavTruth.east_m(1),uavTruth.north_m(1),'co', ...'markersize',1.5*markerSize, 'linewidth', 2*linewidth);
hold off
axis equal
grid on
xlabel('East, m'); ylabel('North, m')
title('UAV Position')
legend('GPS Meas.','Est. Pos.','True Pos.','Start','location','best')% 海拔高度估计结果
subplot(4,2,5)
plot(uavSensors.time_s, uavSensors.GPS_h_msl_m, sensedLineType, ...uavEst.time_s,     uavEst.h_msl_m,         estimateLineType, ...uavTruth.time_s,   uavTruth.h_msl_m,       truthLineType, ...'markersize',markerSize, 'linewidth', linewidth);
grid on
xlabel('Time, s'); ylabel('Altitude, above MeanSeaLevel, m')
legend('GPS Meas.','Est. Alt','True Alt','location','best')%--地 速度估计结果
subplot(4,2,7)
mag = @(v)(sqrt(sum(v.^2,2))); % magnitude of each row
plot(uavSensors.time_s, mag(uavSensors.GPS_v_ned_mps), sensedLineType, ...uavEst.time_s,     mag(uavEst.v_ned_mps),         estimateLineType, ...uavTruth.time_s,   mag(uavTruth.v_ned_mps),       truthLineType, ...'markersize',markerSize, 'linewidth', linewidth);
grid on
xlabel('Time, s'); ylabel('Inertial Speed, m/s')
legend('GPS Meas.','Est. Speed','True Speed','location','best')% 横滚角估计结果
subplot(3,2,2); 
plot(uavEst.time_s,     uavEst.roll_deg,    estimateLineType, ...uavTruth.time_s,   uavTruth.roll_deg,  truthLineType, ...    'markersize',markerSize, 'linewidth', linewidth);
grid on
xlabel('Time, s'); ylabel('Roll Angle, deg')
title('UAV Attitude: Roll')
legend('Est. Roll','True Roll','location','best')% 俯仰角估计结果
subplot(3,2,4); 
plot(uavEst.time_s,     uavEst.pitch_deg,    estimateLineType, ...uavTruth.time_s,   uavTruth.pitch_deg,  truthLineType, ...     'markersize',markerSize, 'linewidth', linewidth);
grid on
xlabel('Time, s'); ylabel('Pitch Angle, deg')
title('UAV Attitude: Pitch')
legend('Est. Pitch','True Pitch','location','best')% 偏航角估计结果(-180,180subplot(3,2,6);
wrap = @(angleDeg)(mod(angleDeg+180,360)-180); % Wrap from -180deg to 180deg.
plot(uavSensors.time_s, wrap(uavSensors.mag2D_yaw_deg), sensedLineType, ...uavEst.time_s,     wrap(uavEst.yaw_deg),           estimateLineType, ...uavTruth.time_s,   wrap(uavTruth.yaw_deg),         truthLineType, ...     'markersize',markerSize, 'linewidth', linewidth);
grid on
xlabel('Time, s'); ylabel('Yaw Angle, deg')
title('UAV Attitude: Yaw')
legend('Magnetometer','Est. Yaw','True Yaw','location','best')

仿真结果

在这里插入图片描述

这篇关于非线性滤波——基于EKF的INS/GPS松组合算法的研究(间接法|EKF|欧拉角)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/194138

相关文章

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python中的随机森林算法与实战

《Python中的随机森林算法与实战》本文详细介绍了随机森林算法,包括其原理、实现步骤、分类和回归案例,并讨论了其优点和缺点,通过面向对象编程实现了一个简单的随机森林模型,并应用于鸢尾花分类和波士顿房... 目录1、随机森林算法概述2、随机森林的原理3、实现步骤4、分类案例:使用随机森林预测鸢尾花品种4.1

关于Java内存访问重排序的研究

《关于Java内存访问重排序的研究》文章主要介绍了重排序现象及其在多线程编程中的影响,包括内存可见性问题和Java内存模型中对重排序的规则... 目录什么是重排序重排序图解重排序实验as-if-serial语义内存访问重排序与内存可见性内存访问重排序与Java内存模型重排序示意表内存屏障内存屏障示意表Int

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系