Kalman滤波在重力匹配中的应用

1. Kalma滤波学习笔记

卡尔曼滤波包括预测和量测更新两个部分。

以汽车运动为例分析,其运动模型为:

Xk=Fk-1Xk-1+Gk-1Uk-1+wk-1

U表示输入的控制量,w表示噪声。

量测模型为:

yk=HkXk+vk

噪声特性为wk~N(0,Qk), vk~N(0,Rk)。

预测部分:

量测更新部分:

2. 惯性导航系统

在惯性导航系统中,加速度计和陀螺仪分别测量载体的加速度和角速度,通过积分的方法解算得到载体的位置、速度和姿态信息。

考虑姿态误差角小、高度不变的情形,惯性导航系统的位置误差、速度误差和姿态误差微分方程分别为:

3. 扩展卡尔曼滤波

选择状态变量为:

 

系统滤波方程为:

 

其中连续时间的状态转移矩阵F由INS误差微分方程决定,W为系统过程噪声方差阵,考虑由加速度计和陀螺仪的随机误差组成。

选择系统的量测量为INS测量位置对应重力图上的重力异常值与实测重力异常值之差,

 

其中INS下标表示惯性导航系统测量的位置在重力图中对应的重力异常值,G下标表示实际重力仪测得的重力异常值,gg和m下标和分别表示重力图的误差和重力仪的测量误差,V代表系统观测噪声,由重力仪测量随机误差构成。

上式化简得到,

 

式中求偏导分别代表重力异常值在纬度和经度方向上的梯度,H代表系统量测矩阵。其中梯度可通过局部线性化方式求取,对重力图局部区域拟合为经度和纬度的二阶多项式曲面,并求梯度,得到量测矩阵。

将状态方程与量测方程的非线性部分进行离散化:

 

 其中T为卡尔曼滤波周期,Fk和Qk表示第k时刻的状态转移矩阵与系统过程噪声方差矩阵的取值。

(具体推导过程见:https://blog.csdn.net/l2014010671/article/details/91126676?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.nonecase)

得到卡尔曼滤波递推方程如第一节中所述。由于INS测量频率高于重力仪测量频率,因此当有重力仪的量测值时,卡尔曼滤波器进行量测更新;否则,仅进行时间更新。量测更新之后,对INS的位置、速度和姿态进行修正。

部分主程序MATLAB代码如下所示:

%% 惯性导航初始化
% 位置
delta_pos=gv.delta_pos/glv.nm/gv.weight;    % 初始位置误差(单位:弧度)
pos = location0 +delta_pos;%载体的初始位置【纬度;经度;高度】
H_ini = pos(3); %初始高度
pos_1 = pos; %前一时刻位置
pos_2 = pos; %前两个时刻位置
% 速度
vn = velocity0+gv.delta_velocity*ones(3,1);
vn_1 = vn;  %前一时刻速度
vn_2 = vn;  %前两个时刻速度
dRnm_1 = zeros(3,1); %前一时刻位置增量
dRnm_2 = zeros(3,1); %前两个时刻位置增量
% 姿态
att0=(angle0/glv.deg)';         % 初始姿态(单位:度)
delta_att=gv.delta_att;       % 初始姿态误差
att0=att0+delta_att';
qnb = AttToQuat(att0*pi/180);   %姿态矩阵
%% 滤波器初值    
% 状态变量为: 位置2个,速度2个,姿态3个,加速度计2个,陀螺3个,共12个
dpos0=delta_pos(1:2)';    % 位置初始误差
dvn0=gv.delta_velocity*[1;1];     % 速度误差初值,单位为m/s
datt0=gv.delta_att'*glv.deg;   % 姿态误差初值,单位为弧度
%IMU误差
db=gv.Fe_chang*ones(2,1)*glv.ug;    % 加速度计误差初值,单位为ug
eb=gv.We_chang*ones(3,1)*glv.dph;   % 陀螺误差初值
wdb=gv.Fe_randn*ones(2,1)*glv.ug;    % 加速度计随机误差,单位为ug
web=gv.We_randn*ones(3,1)*glv.dph;   % 陀螺随机误差
%滤波器初值
Pk=diag([dpos0';dvn0;datt0';db;eb])^2;    % 初始误差阵
Qt =diag([zeros(2,1);wdb;web;zeros(5,1)])^2;    % 系统状态误差方差阵
Xk =[dpos0,dvn0',datt0,db',eb']';   %状态变量初值,列
Rk=gv.g_noise^2;     % 系统观测误差方差阵(由重力仪测量随机误差构成)
Xkf=zeros(L/4,nn);
Hk=zeros(1,12);
%% -----------导航计算--------------------
hwait = waitbar(0,'Please wait...'); %进度条
kk=1;  % 解算标号
kkk=1;
km=1;
for k=1:n:L-n+1
    k1=k+n-1;
    fmm=fm(k:k1,:)';         %四子样数据,比力
    wmm=wm(k:k1,:)';       %角速度
    [qnb, vn, pos, dRnm] = sinsQuat(qnb, vn_1, vn_2, pos_1, pos_2, dRnm_1, dRnm_2, wmm, fmm, Ts); %导航程序
    Ft=get_F12(vn, pos, mean(fmm,2));   %获得INS状态转移矩阵
    [Phikk_1, Qk] =kfdis(Ft, Qt, T_Kalman, 12);      %   离散化得到一步转移矩阵和系统噪声矩阵
    if mod(kk,interval)==0   % 得到观测值
        % 观测模型
        [Hk(1:2),m,s]=get_H(3,pos(1),pos(2));                % 拟合范围,纬度,经度,得到量测矩阵H
        Hk(3:12)=zeros(1,10);    H_s(kkk)=s;   H_m(kkk)=m;   kkk=kkk+1;
        % 观测值
        pnum=find_num2(pos(1:2)*gv.weight);
        g_ins=z2(pnum(2),pnum(1));
        point=[Storedata.avp(k1,7) Storedata.avp(k1,8)]*gv.weight;
        pnum=find_num2(point);
        g_true=z2(pnum(2),pnum(1))+gv.g_noise*rand(1,1);
        Zk=g_ins-g_true;         %  背景图重力异常值减去测量值
        % Kalman
        [Xk, Pk] = kalman(Phikk_1, Qk, Xk, Pk, Hk, Rk, Zk);   %有测量,更新
        % -----------------------------闭环修正----------------------------
        if nn>1
            pos(1:2)=pos(1:2)-Xk(1:2);    %  位置反馈
        end
        if nn>3
            vn(1:2)=vn(1:2)-Xk(3:4);   %  速度反馈
        end
        if nn>4
            Cnb=(eye(3)+askew(Xk(5:7)))*QuatToAttMat(qnb); % 修正姿态矩阵
            Cnb=Cnb*(Cnb'*Cnb)^(-1/2);
            qnb = AttmatToQuat(Cnb);
        end
        Xk(1:nn)=zeros(nn,1);
    else
        [Xk, Pk] = kalman(Phikk_1, Qk, Xk, Pk);   %状态更新
    end
    %-----------------------   记录数据   ----------------------
    Xkf(kk,:)=Xk(1:nn);
    INS_data_k(kk,1)=pos(1);
    INS_data_k(kk,2)=pos(2);
    INS_data_k(kk,3)=vn(1);
    INS_data_k(kk,4)=vn(2);
    Att = QuatToAtt(qnb);     % 姿态输出
    INS_data_k(kk,5:7)= Att';
    kk=kk+1;
    vn(3) = 0;                     %  天向抑制
    pos(3) = H_ini;                %  抑制高度通道
    vn_2 = vn_1;
    vn_1 = vn;
    pos_2 = pos_1;
    pos_1 = pos;
    dRnm_2 = dRnm_1;
    dRnm_1 = dRnm;
    %-----------------------   记录数据   ---------------------------------
    waitbar(k/L);
end
close(hwait)

离散化卡尔曼滤波:

function [Fikk_1, Qk] = kfdis(Ft, Qt, Tkf, n)
Tkfi = Tkf;
facti = 1;
Fti = Ft;
Mi = Qt;
In = eye(size(Ft,1));
Fikk_1 = In + Tkf*Ft;
Qk = Qt*Tkf;
for i=2:1:n
    Tkfi = Tkfi*Tkf;
    facti = facti*i;
    Fti = Fti*Ft;
    Fikk_1 = Fikk_1 + Tkfi/facti*Fti;
    
    FtMi = Ft*Mi;
    Mi = FtMi + FtMi';
    Qk = Qk + Tkfi/facti*Mi;
end

卡尔曼滤波:

function [Xk, Pk] = kalman(Phikk_1, Qk, Xk_1, Pk_1, Hk, Rk, Zk)
if nargin<7     % 仅进行状态递推
    Xk = Phikk_1*Xk_1;
    Pk = Phikk_1*Pk_1*Phikk_1'+Qk;
else            % 有测量时滤波
    Xkk_1=Phikk_1*Xk_1;
    Pkk_1 = Phikk_1*Pk_1*Phikk_1' + Qk;
    Pxz = Pkk_1*Hk';
    Pzz = Hk*Pxz + Rk;
    Kk = Pxz*Pzz^-1;
    Xk = Xkk_1 + Kk*(Zk-Hk*Xkk_1);
    Pk = Pkk_1-Kk*Hk*Pkk_1;
end
end

获得量测矩阵(重力在经纬度方向上的梯度):

function [h,m,s]=get_H(n,fai,lamda)
h=zeros(1,2);
[h(1),h(2),m,s]=get_h1_h4(n,fai,lamda);
end

function [h1,h4,m,s]=get_h1_h4(n,fai,lamda) load x2; load y2; load z2; gvs; map_gvs; kk=1; % 一维 k=1; % 二维 x=zeros(2*n+1,2*n+1); y=zeros(2*n+1,2*n+1); xxxx=zeros(n*n,1); yyyy=zeros(n*n,1); zzzz=zeros(n*n,1); point=[fai*gv.weight lamda*gv.weight]; num=find_num2(point); for i=-n:n for j=-n:n if num(1)+i<1 || num(2)+j<1 || num(1)+i>length(x2) || num(2)+j>length(x2) else xxxx(kk)=x2(1,num(1)+i)/gv.weight; yyyy(kk)=y2(num(2)+j,1)/gv.weight; zzzz(kk)=z2(num(2)+j,num(1)+i); kk=kk+1; end end end xxx=xxxx(1:kk-1); %拟合区域所有点的位置和重力值 yyy=yyyy(1:kk-1); zzz=zzzz(1:kk-1); f=fit([xxx,yyy],zzz,'poly22'); %曲面线性拟合 x=x2(num(1)-n:num(1)+n,num(1)-n:num(1)+n)/gv.weight; y=y2(num(2)-n:num(2)+n,num(2)-n:num(2)+n)/gv.weight; z=z2(num(2)-n:num(2)+n,num(1)-n:num(1)+n); [h1,h4]=differentiate(f,fai,lamda); %求梯度 D=z-(h1*x+h4*y); D=D(:); m=mean(D); %拟合区域的误差 s=std(D); end

 

posted @ 2020-06-30 10:11  望舒L  阅读(927)  评论(1编辑  收藏  举报