zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Java编辑PDF写入文字 插入图片
    Java图片压缩
    Java base64 图片编码转换
    JAVA操作字符串
    JAVA获取文件夹下所有的文件
    IntelliJ IDEA 注释模板设置
    IntelliJ IDEA 添加junit插件
    python操作mysql数据库系列-安装MySql
    python操作mysql数据库系列-安装MySQLdb
    软件测试工程师为什么要不断提高自身技能?
  • 原文地址:https://www.cnblogs.com/huangliu1111/p/13212196.html
Copyright © 2011-2022 走看看