卡尔曼(Kalman)滤波(六)--卡尔曼滤波的应用: 四元数卡尔曼滤波(QKF)的C代码实现姿态解算

news/2024/11/24 5:41:17/

0 引言

在捷联惯导工程实践[6]中,我们希望陀螺仪能够非常精确的获取信息,或者说希望陀螺仪能非常准确的地反映观测量(加速度,磁场等)[6,7]的真实值,但是这个过程或多或少是受到噪声干扰的,导致测量的不准确;为了能够让陀螺仪在状态更新时做到准确,必须对状态变量和观测量进行数据融合和滤波,从而尽最大限度的降低噪声的干扰。

最常用也最有效的方法非卡尔曼滤波莫属,其在处理高斯模型的系统上效果颇佳;随着计算机技术的发展,Kalman滤波的计算要求和复杂性已不再成为其应用中的阻碍,并且越来越受到人们的青睐。卡尔曼滤波是线性系统的最小方差估值器,但在实际应用中,运用四元数表示的状态模型关于状态变量却是非线性的,一种办法是考虑使用扩展的Kalman滤波(EKF),但是其在求解四元数微分方程时需要求一个雅可比矩阵,计算量复杂,对于实际中的高维问题显得不切实际;另一种办法是考虑使用非线性滤波算法,如无迹的卡尔曼滤波[5],粒子滤波等,但他们极其复杂和繁琐的计算量,使其难以在工程实践中得到应用;因此利用汉密尔顿算子将四元数状态方程改写成线性形式,并在计算相关协方差矩阵时进行了改进。

另外,在姿态解算的两个更新过程中,将陀螺仪的原始输出角增量积分得到更新所需要的角度这一步骤显得举足轻重,如果能在陀螺的积分过程中降低噪声对原始输出的影响,那么在后续的迭代更新中无疑减小了噪声的逐级扩散和放大,因为角度和位移的积分均是对时间的积分,如果处理不当,很容易造成噪声随着时间的延续而逐步增大,可想而知难以达到实际应用精度。

1.四元数


2.基于三次样条插值的QKF

2.1状态更新



2.2观测更新




3.C代码实现

初始参数设置:

初始四元数为,



下面是C代码:

#define ROU_K       0.001
#define SIGAMA_1    0.5
#define SIGAMA_2    6
#define SIGAMA_3    0.01


float q_k_k[4]={1,0,0,0};
float p_k_k[7][7]={5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5};
float p_k_k_q[4][4]={5,0,0,0,0,5,0,0,0,0,5,0,0,0,0,5};float u_k_k[3]={0,0,0};
float exp_theta_x,exp_theta_y,exp_theta_z;const float I4[4][4]={1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1};const float I7[7][7]={1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1};float b_k1[3]={0};
float r_k1[3]={0};
float c_k1[3]={0};
float d_k1[3]={0};void QKF_update2(void)
{float X_k_k[4][3];float x_k_k[7];float x_k1_k[7]={0};float x_k1_k1[7]={0};float p_k1_k[7][7]={0};float p_k1_k_q[4][4];float p_k1_k1[7][7]={0};float p_k1_k_v[4][4]={0};float p_k_w[7][7]={0};float q_k1_k[4];float q_k1_k1[4]={0};float F_K_K[4][4];float F_K[4][4];float theta_k[3];float theta_k_k[3];float M_k_k[4][4];float M_k1_k[4][4];float H_k1[4][4]={0};float H_k1_2[4][7]={0};float B_k1[4][4]={0};float S_k1_k[4][4]={0};float K_k1[7][4]={0};float pusai[7][7]={0};float temp_77_1[7][7]={0};float temp_77_2[7][7]={0};float temp_77_3[7][7]={0};float temp_77_4[7][7]={0};float temp_44_1[4][4]={0};float temp_44_2[4][4]={0};float temp_44_3[4][4]={0};float temp_44_4[4][4]={0};float temp_74[7][4]={0};float temp_74_2[7][4]={0};float temp_47_1[4][7]={0};float tr;float temp; unsigned char i=0,j=0;for(i=0;i<3;i++){b_k1[i]=gyro[i];}/*下面为时间更新*/for(i=0;i<4;i++){x_k_k[i]=q_k_k[i];}for(i=0;i<3;i++){x_k_k[i+4]=u_k_k[i];}                             //对x_k_k赋值for(i=0;i<3;i++){theta_k[i]=theta[i];}                       //对theta_k赋值for(i=0;i<3;i++){theta_k_k[i]=theta_k[i]-TWO_TIM*u_k_k[i];}                                   //对theta_k_k赋值exp_theta_x=exp(0.5*theta_k_k[0]);exp_theta_y=exp(0.5*theta_k_k[1]);exp_theta_z=exp(0.5*theta_k_k[2]);F_K_K[0][0]=F_K_K[1][1]=F_K_K[2][2]=F_K_K[3][3]=1;F_K_K[0][1]=F_K_K[3][2]=1/exp_theta_x;F_K_K[0][2]=F_K_K[1][3]=1/exp_theta_y;F_K_K[0][3]=F_K_K[2][1]=1/exp_theta_z;F_K_K[1][0]=F_K_K[2][3]=exp_theta_x;F_K_K[2][0]=F_K_K[3][1]=exp_theta_y;F_K_K[3][0]=F_K_K[1][2]=exp_theta_z;                 //计算 F_k_kfor(i=0;i<7;i++){for(j=0;j<7;j++){temp_77_1[i][j]=0;}}                                                   //清空临时变量。temp_77_1[0][0]=temp_77_1[1][1]=temp_77_1[2][2]=1;for(i=0;i<4;i++){for(j=0;j<4;j++){temp_77_1[i+3][j+3]=F_K_K[i][j];}}                                  MatrixMul((float*)temp_77_1,(float*)x_k_k,(float*)x_k1_k,7,7,1);  //对x_k1_k赋值for(i=0;i<4;i++){q_k1_k[i]=x_k1_k[i];}                                    //从x_k1_k中提取q_k1_kexp_theta_x=exp(0.5*theta_k[0]);exp_theta_y=exp(0.5*theta_k[1]);exp_theta_z=exp(0.5*theta_k[2]);F_K[0][0]=F_K[1][1]=F_K[2][2]=F_K[3][3]=1;F_K[0][1]=F_K[3][2]=1/exp_theta_x;F_K[0][2]=F_K[1][3]=1/exp_theta_y;F_K[0][3]=F_K[2][1]=1/exp_theta_z;F_K[1][0]=F_K[2][3]=exp_theta_x;F_K[2][0]=F_K[3][1]=exp_theta_y;F_K[3][0]=F_K[1][2]=exp_theta_z;                 //计算 F_kX_k_k[0][0]=X_k_k[1][1]=X_k_k[2][2]=q_k_k[0];X_k_k[0][1]=X_k_k[3][2]=-1*q_k_k[2];X_k_k[0][2]=q_k_k[1];X_k_k[1][0]=q_k_k[2];X_k_k[1][2]=X_k_k[3][0]=-1*q_k_k[3];X_k_k[2][0]=X_k_k[3][1]=-1*q_k_k[1];X_k_k[2][1]=q_k_k[3];                            //对X_k_k赋值for(i=0;i<7;i++){for(j=0;j<7;j++){   pusai[i][j]=0;}}pusai[0][0]=pusai[1][1]=pusai[2][2]=1;for(i=0;i<4;i++){for(j=0;j<3;j++){pusai[i+3][j]=-0.5*TWO_TIM*X_k_k[i][j];}}                    for(i=0;i<4;i++){for(j=0;j<4;j++){pusai[i+3][j+3]=F_K[i][j];}}                                        //对pusai赋值MatrixMul((float*)q_k_k,(float*)q_k_k,(float*)temp_44_1,4,1,4);MatrixAdd((float*)temp_44_1,(float*)p_k_k_q,(float*)M_k_k,4,4);tr=M_k_k[0][0]+M_k_k[1][1]+M_k_k[2][2]+M_k_k[3][3];          //计算M_k_k 和  tr for(i=0;i<7;i++){for(j=0;j<7;j++){p_k_w[i][j]=0;}}                                              //清空p_k_wp_k_w[0][0]=p_k_w[1][1]=p_k_w[2][2]=SIGAMA_3*SIGAMA_3*TWO_TIM;for(i=0;i<4;i++){for(j=0;j<4;j++){temp_44_1[i][j]=tr*I4[i][j];}}MatrixMinus((float*)temp_44_1,(float*)M_k_k,(float*)temp_44_2,4,4);temp=0.25*(SIGAMA_1*SIGAMA_1+SIGAMA_2*SIGAMA_2*TWO_TIM);for(i=0;i<4;i++){for(j=0;j<4;j++){p_k_w[i+3][j+3]=temp*temp_44_2[i][j];}}                                               //对p_k_w赋值MatrixTrans((float*)pusai,(float*)temp_77_2,7,7);MatrixMul((float*)pusai,(float*)p_k_k,(float*)temp_77_1,7,7,7);MatrixMul((float*)temp_77_1,(float*)temp_77_2,(float*)temp_77_3,7,7,7);MatrixAdd((float*)temp_77_3,(float*)p_k_w,(float*)p_k1_k,7,7); //对p_k1_k赋值for(i=0;i<4;i++){for(j=0;j<4;j++){p_k1_k_q[i][j]=p_k1_k[i][j];}}                                               //从p_k1_k中提取p_k1_k_q/*r_k1产生随机序列。。。。*/for(i=0;i<3;i++){c_k1[i]=0.5*(b_k1[i]+r_k1[i]);d_k1[i]=0.5*(b_k1[i]-r_k1[i]);}H_k1[0][0]=H_k1[1][1]=H_k1[2][2]=H_k1[3][3]=0;for(i=0;i<3;i++){H_k1[0][i+1]=-1*d_k1[i];H_k1[i+1][0]=d_k1[i];}H_k1[1][2]=   c_k1[2];H_k1[1][3]=-1*c_k1[1];H_k1[2][1]=-1*c_k1[2];H_k1[2][3]=   c_k1[0];H_k1[3][1]=   c_k1[1];H_k1[3][2]=-1*c_k1[0];         //对 H_k1赋值for(i=0;i<4;i++){for(j=0;j<4;j++){H_k1_2[i][j+3]=H_k1[i][j];}}                              //对H_k1_2赋值MatrixMul((float*)q_k1_k,(float*)q_k1_k,(float*)temp_44_1,4,1,4);MatrixAdd((float*)temp_44_1,(float*)p_k1_k_q,(float*)M_k1_k,4,4);  //计算M_k1_ktr=M_k1_k[0][0]+M_k1_k[1][1]+M_k1_k[2][2]+M_k1_k[3][3];   //计算 trB_k1[0][0]=B_k1[1][1]=B_k1[2][2]=B_k1[3][3]=0;B_k1[0][1]=B_k1[3][2]=-1*b_k1[0];B_k1[0][2]=B_k1[1][3]=-1*b_k1[1];B_k1[0][3]=B_k1[2][1]=-1*b_k1[2];B_k1[1][0]=B_k1[2][3]=b_k1[0];B_k1[2][0]=B_k1[3][1]=b_k1[1];B_k1[3][0]=B_k1[1][2]=b_k1[2]; //对 B_k1 赋值 for(i=0;i<4;i++){for(j=0;j<4;j++){temp_44_1[i][j]=0;temp_44_2[i][j]=0;temp_44_3[i][j]=0;}}temp_44_1[0][0]=temp_44_1[1][1]=temp_44_1[2][2]=temp_44_1[3][3]=tr;MatrixMinus((float*)temp_44_1,(float*)M_k1_k,(float*)temp_44_2,4,4);MatrixTrans((float*)B_k1,(float*)temp_44_1,4,4);MatrixMul((float*)B_k1,(float*)M_k1_k,(float*)temp_44_3,4,4,4);MatrixMul((float*)temp_44_3,(float*)temp_44_1,(float*)temp_44_4,4,4,4);MatrixMinus((float*)temp_44_2,(float*)temp_44_4,(float*)temp_44_1,4,4);for(i=0;i<4;i++){for(j=0;j<4;j++){p_k1_k_v[i][j]=0.25*ROU_K*temp_44_1[i][j];}}                                                                 //计算p_k1_k_vfor(i=0;i<4;i++){for(j=0;j<4;j++){temp_44_1[i][j]=0;temp_44_2[i][j]=0;temp_44_3[i][j]=0;}}MatrixTrans((float*)H_k1,(float*)temp_44_4,4,4);MatrixMul((float*)H_k1,(float*)p_k1_k_q,(float*)temp_44_1,4,4,4);MatrixMul((float*)temp_44_1,(float*)temp_44_4,(float*)temp_44_2,4,4,4);MatrixAdd((float*)temp_44_2,(float*)p_k1_k_v,(float*)S_k1_k,4,4);   //计算S_k1_kMatrixTrans((float*)H_k1_2,(float*)temp_74,4,7);MatrixMul((float*)p_k1_k,(float*)temp_74,(float*)temp_74_2,7,7,4);for(i=0;i<4;i++){for(j=0;j<4;j++){temp_44_1[i][j]=S_k1_k[i][j];}}Gauss_Jordan((float*)temp_44_1,4);MatrixMul((float*)temp_74_2,(float*)temp_44_1,(float*)K_k1,7,4,4);      //计算K_k1MatrixMul((float*)K_k1,(float*)H_k1_2,(float*)temp_77_3,7,4,7);MatrixMinus((float*)I7,(float*)temp_77_3,(float*)temp_77_1,7,7);MatrixTrans((float*)temp_77_1,(float*)temp_77_2,7,7);MatrixMul((float*)temp_77_1,(float*)p_k1_k,(float*)temp_77_3,7,7,7);MatrixMul((float*)temp_77_3,(float*)temp_77_2,(float*)temp_77_4,7,7,7); MatrixMul((float*)K_k1,(float*)p_k1_k_v,(float*)temp_74,7,4,4);     MatrixTrans((float*)K_k1,(float*)temp_47_1,7,4);MatrixMul((float*)temp_74,(float*)temp_47_1,(float*)temp_77_3,7,4,7);MatrixAdd((float*)temp_77_4,(float*)temp_77_3,(float*)p_k1_k1,7,7);   //计算p_k1_k1for(i=0;i<7;i++){for(j=0;j<7;j++){p_k_k[i][j]=p_k1_k1[i][j];}}                                             //p_k1_k1保存为下一次的p_k_kfor(i=0;i<4;i++){for(j=0;j<4;j++){p_k_k_q[i][j]=p_k1_k1[i][j];}}                                            //从p_k1_k1中提取p_k_k_qMatrixMul((float*)temp_77_1,(float*)x_k1_k,(float*)x_k1_k1,7,7,1);   //计算x_k1_k1for(i=0;i<3;i++){u_k_k[i]=x_k1_k1[i+4];}                                                                    //从x_k1_k1中提取u_k_kfor(i=0;i<4;i++){q_k1_k1[i]=x_k1_k1[i];}temp=pow(q_k1_k1[0]*q_k1_k1[0]+q_k1_k1[1]*q_k1_k1[1]+q_k1_k1[2]*q_k1_k1[2]+q_k1_k1[3]*q_k1_k1[3],0.5);for(i=0;i<4;i++){q_k_k[i]=q_k1_k1[i]/temp;}                                                                    //从x_k1_k1中提取四元数归一化并保存为下一次的四元数
}


参考文献

[1]关治,陆金甫.数值分析基础[M].同济大学出版社.1998:75-80.

[2]关治,陆金甫.数值分析基础[M].同济大学出版社.1998:38-41.

[3]关治,陆金甫.数值分析基础[M].同济大学出版社.1998:59-60.

[4]杨丕文.四元数分析与偏微分方程[M].科学出版社.2009.

[5]秦永元,汪叔华.卡尔曼滤波与组合导航原理(第二版)[M].西北工业大学出版社.2012.

[6]邓正隆.惯性技术[M].西北工业大学出版社.2006.

[7]张天光,王秀萍.捷联惯导技术[M].国防工业出版社.2007.





http://www.ppmy.cn/news/661390.html

相关文章

一文读懂卡尔曼滤波——卡尔曼滤波融合IMU的陀螺仪和加速度计实践(一)

卡尔曼的基本原理以及公式网上有很多&#xff0c;可以参照大神博客&#xff1a; https://blog.csdn.net/m0_38089090/article/details/79523784?ops_request_misc%257B%2522request%255Fid%2522%253A%2522162147991616780271580764%2522%252C%2522scm%2522%253A%252220140713…

莱卡公司成立一周年

分享成为如意集团独立子公司一年以来的业绩亮点 特拉华州威尔明顿市--(美国商业资讯)--为纺织、服装和个人护理行业提供创新方案的全球领导者莱卡公司&#xff0c;将在1月31日迎来成为如意集团独立子公司的一周年纪念日。 本新闻稿包含多媒体。此处查看新闻稿全文&#xff1a…

卡尔曼滤波C++代码

卡尔曼滤波C代码 卡尔曼滤波预测和更新两部分&#xff0c;卡尔曼滤波主要实现预测过程个更新过程&#xff1b;因此在代码实现的时候需要完成四部分 变量定义 2&#xff09;变量形状设置(由构造函数实现) 3&#xff09; 初始化&#xff0c;送入初始的状态量和协方差 4&#xff…

用卡尔曼滤波处理轨迹

卡尔曼滤波这个词老是听到&#xff0c;一直也没有耐心看&#xff0c;最近准备看看轨迹挖掘相关的东西&#xff0c;第一步轨迹处理中卡尔曼滤波就又出现了&#xff0c;终于耐着性子研究了两天(一看一堆矩阵就脑壳痛&#xff09;&#xff0c;期间网上找了不少代码和博客&#xff…

卡尔曼滤波Q、R如何调节?

转载&#xff1a;作者&#xff1a;小心假设 链接&#xff1a;https://www.zhihu.com/question/30481204/answer/50092960 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 跑题一个&#xff0c;说几个准则吧。只是准则&…

string类学习

本篇将深入学习string类&#xff0c;通过各个测试函数玩遍cstring类&#xff0c;学到就是赚到&#xff01;&#xff01;&#xff01; 文章目录 1.头文件和源文件1.1源文件1.2头文件 2.构造函数3.赋值重载函数4.元素访问运算符5.迭代器5.1正向迭代器5.2反向迭代器 6.添加字符串…

模糊 (一)运动模糊失焦模糊 去卷积盲去卷积

&#xff08;一&#xff09;去空间不变的模糊核 1&#xff09;维纳滤波 一个理想点经过相机后成的像由点扩散函数PSF(Point Spread Function)来描述。 线性移不变的PSF导致的图像模糊&#xff1a;bc*xn n是噪声 例如衍射极限PSF 相机抖动模糊 直接去卷积会放大系统中高频部…

模糊集介绍

https://wenku.baidu.com/view/acb754583d1ec5da50e2524de518964bcf84d29a.html