PSINS工具箱卡尔曼滤波器

psins中一个15维状态量、3维位置观测量的卡尔曼滤波器示例:

% SINS/GPS intergrated navigation simulation using kalman filter.
% Please run 'test_SINS_trj.m' to generate 'trj10ms.mat' beforehand!!!
% See also test_SINS_trj, test_SINS, test_SINS_GPS_186, test_SINS_GPS_193.
% Copyright(c) 2009-2014, by Gongmin Yan, All rights reserved.
% Northwestern Polytechnical University, Xi An, P.R.China
% 17/06/2011
glvs
psinstypedef(153); %设定滤波器标识
trj = trjfile('trj10ms.mat');
% initial settings
[nn, ts, nts] = nnts(2, trj.ts);
imuerr = imuerrset(0.03, 100, 0.001, 5); % IMU误差设定
imu = imuadderr(trj.imu, imuerr); % 添加IMU误差
davp0 = avperrset([0.5;-0.5;20], 0.1, [1;1;3]); % 设定初始avp误差
ins = insinit(avpadderr(trj.avp0,davp0), ts); % 初始化INS
% KF filter
rk = poserrset([1;1;3]); % 设定Rk,位置观测误差
kf = kfinit(ins, davp0, imuerr, rk); % 初始化卡尔曼滤波器
kf.Pmin = [avperrset(0.01,1e-4,0.1); gabias(1e-3, [1,10])].^2; kf.pconstrain=1; % 设定P阵最小值
len = length(imu); [avp, xkpk] = prealloc(fix(len/nn), 10, 2*kf.n+1);
timebar(nn, len, '15-state SINS/GPS Simulation.');
ki = 1;
for k=1:nn:len-nn+1
k1 = k+nn-1;
wvm = imu(k:k1,1:6); t = imu(k1,end);
ins = insupdate(ins, wvm); % INS更新
kf.Phikk_1 = kffk(ins); % Phi阵更新
kf = kfupdate(kf); % 卡尔曼时间更新
if mod(t,1)==0
posGPS = trj.avp(k1,7:9)' + davp0(7:9).*randn(3,1); % GPS pos simulation with some white noise
kf = kfupdate(kf, ins.pos-posGPS, 'M'); % 卡尔曼观测更新
[kf, ins] = kffeedback(kf, ins, 1, 'avp'); % 状态反馈
avp(ki,:) = [ins.avp', t];
xkpk(ki,:) = [kf.xk; diag(kf.Pxk); t]'; ki = ki+1; % 构建状态量和状态方差数据
end
timebar;
end
avp(ki:end,:) = []; xkpk(ki:end,:) = [];
% show results
insplot(avp);
avperr = avpcmpplot(trj.avp, avp);
kfplot(xkpk, avperr, imuerr);

psinstypedef

该函数是一个标识器,主要用于设定全局结构体psinsdef,通过psinsdef中的kfinit、kffk、kfhk、kfplot四个字段来标记卡尔曼滤波模型和绘图参数。如153表示采用15维状态向量+3维位置观测模型,156表示采用18维状态向量+3维位置观测+3维速度观测模型。也可以对滤波模型进行修改和增加(需同时修改kfinit, kffk, kfhk, kfplot等函数)。

function psinstypedef(typestr, kffk, kfhk, kfplot)
......
psinsdef.kfinit = typestr;
psinsdef.kffk = fix(psinsdef.kfinit/10);
psinsdef.kfhk = psinsdef.kfinit;
psinsdef.kfplot = psinsdef.kffk;
......

kfinit

根据psinsdef中设定的类型,对卡尔曼滤波器进行初始化。主要流程为先根据滤波器模型设定Q阵、R阵、初始P阵、H阵,然后再调用kfinit0函数完成全部初始化工作,返回卡尔曼滤波器结构体kf。

function kf = kfinit(ins, varargin)
switch(psinsdef.kfinit)
case psinsdef.kfinit153,
psinsdef.kffk = 15; psinsdef.kfhk = 153; psinsdef.kfplot = 15;
[davp, imuerr, rk] = setvals(varargin);
kf.Qt = diag([imuerr.web; imuerr.wdb; zeros(9,1)])^2; % 连续域过程噪声矩阵
kf.Rk = diag(rk)^2; % 离散域观测噪声矩阵
kf.Pxk = diag([davp; imuerr.eb; imuerr.db]*1.0)^2; % 初始P阵
kf.Hk = kfhk(0); % 观测矩阵
......
kf = kfinit0(kf, nts);

kfinit0

卡尔曼滤波器结构体初始化函数,为各状态量、矩阵分配内存空间,包含Q阵、G阵、P阵、K阵、状态量、状态反馈量等(这里的Q、G为离散域矩阵)。同时设置滤波器配置参数,如观测量掩码、自适应滤波开关等。

function kf = kfinit0(kf, nts)
% Always called by kfinit and initialize the remaining fields of kf.
%
% See also kfinit, kfupdate, kffeedback, psinstypedef.
kf.nts = nts;
[kf.m, kf.n] = size(kf.Hk); % m,观测维数;n,状态维数
kf.I = eye(kf.n);
kf.Kk = zeros(kf.n, kf.m); % 卡尔曼增益矩阵
kf.measmask = []; % measurement mask for no update 20/11/2022
kf.measstop = zeros(kf.m,1); % measurement stop time
kf.measlost = zeros(kf.m,1); % measurement lost time
kf.measlog = 0; % measurement log flag
if ~isfield(kf, 'xk'), kf.xk = zeros(kf.n, 1); end % 状态向量
if ~isfield(kf, 'Qk'), kf.Qk = kf.Qt*kf.nts; end % 过程噪声矩阵
if ~isfield(kf, 'Gammak'), kf.Gammak = 1; kf.l = kf.n; end % 噪声传递矩阵
if ~isfield(kf, 'fading'), kf.fading = 1; end
if ~isfield(kf, 'adaptive'), kf.adaptive = 0; end
......
kf.Pmax = (diag(kf.Pxk)+1)*1.0e10;
kf.Pmin = kf.Pmax*0;
% kf.Pykk_1 = kf.Hk*kf.Pxk*kf.Hk'+kf.Rk;
kf.Pykk_1 = kf.Hk*kf.Pxk*kf.Hk'+0; % 计算卡尔曼增益的中间矩阵
kf.xfb = zeros(kf.n, 1); % 状态反馈量
% kf.coef_fb = (1.0-exp(-kf.T_fb./kf.xtau));
% kf.coef_fb = ar1coefs(kf.T_fb, kf.xtau);
xtau = kf.xtau;
xtau(kf.xtau<kf.T_fb) = kf.T_fb; kf.coef_fb = kf.T_fb./xtau;

kffk

根据滤波器模型调用etm函数更新F阵,并离散化为Phi阵。etm函数计算F阵的元素值。

function [Fk, Ft] = kffk(ins, varargin)
global psinsdef
%% get Ft
if isstruct(ins), nts = ins.nts;
else nts = ins;
end
switch(psinsdef.kffk)
case 15
Ft = etm(ins);
......
end
%% discretization,离散化
Fk = Ft*nts;
if nts>0.1 % for large time interval, this may be more accurate.
Fk = expm(Fk);
else % Fk = I + Ft*nts + 1/2*(Ft*nts)^2 , 2nd order expension
Fk = eye(size(Ft)) + Fk;% + Fk*Fk*0.5;
end

kfhk

设置观测矩阵H。

function Hk = kfhk(ins, varargin)
global psinsdef
switch(psinsdef.kfhk)
case 153,
Hk = [zeros(3,6), eye(3), zeros(3,6)];
end
......

kfupdate

卡尔曼更新函数。输入参数kf结构体、观测量yk(可选参数,执行观测更新时需传入)、更新标识TimeMeasBoth。TimeMeasBoth为T时只进行时间更新,为M时只进行观测更新,为B时执行完整的时间更新和观测更新。

function kf = kfupdate(kf, yk, TimeMeasBoth)
if nargin==1;
TimeMeasBoth = 'T';
elseif nargin==2
TimeMeasBoth = 'B';
end
if TimeMeasBoth=='T' % Time Updating
kf.xk = kf.Phikk_1*kf.xk;
kf.Pxk = kf.Phikk_1*kf.Pxk*kf.Phikk_1' + kf.Gammak*kf.Qk*kf.Gammak';
kf.measstop = kf.measstop - kf.nts; kf.measlost = kf.measlost + kf.nts;
else
if TimeMeasBoth=='M' % Meas Updating
kf.xkk_1 = kf.xk;
kf.Pxkk_1 = kf.Pxk;
elseif TimeMeasBoth=='B' % Time & Meas Updating
kf.xkk_1 = kf.Phikk_1*kf.xk;
kf.Pxkk_1 = kf.Phikk_1*kf.Pxk*kf.Phikk_1' + kf.Gammak*kf.Qk*kf.Gammak';
kf.measstop = kf.measstop - kf.nts; kf.measlost = kf.measlost + kf.nts;
else
error('TimeMeasBoth input error!');
end
......
end

kffeedback

状态反馈,psins中的状态量均为误差量。执行卡尔曼滤波后,可将状态量通过kffeedback函数反馈值全状态。

function [kf, ins, xfb] = kffeedback(kf, ins, T_fb, fbstr)
if nargin<4, fbstr=kf.fbstr; end
if nargin<3, T_fb=1; end
if kf.T_fb~=T_fb
kf.T_fb = T_fb;
idx = kf.T_fb>kf.xtau; % scale<vector
kf.coef_fb(idx) = 1; kf.coef_fb(~idx) = kf.T_fb./kf.xtau(~idx); %2022-6-25
kf.coef_fb(kf.xtau<0.001 & kf.T_fb~=inf) = 1;
end
xfb_tmp = kf.coef_fb.*kf.xk; xfb = xfb_tmp*0;
for k=1:length(fbstr)
switch fbstr(k)
case 'a',
idx = 1:3; ins.qnb = qdelphi(ins.qnb, xfb_tmp(idx));
case 'v',
idx = 4:6; ins.vn = ins.vn - xfb_tmp(idx);
case 'p',
idx = 7:9; ins.pos = ins.pos - xfb_tmp(idx);
......
end
kf.xk(idx) = kf.xk(idx) - xfb_tmp(idx); %
kf.xfb(idx) = kf.xfb(idx) + xfb_tmp(idx); % record total feedback
xfb(idx) = xfb_tmp(idx);
end
[ins.qnb, ins.att, ins.Cnb] = attsyn(ins.qnb);
ins.avp = [ins.att; ins.vn; ins.pos]; % 2015-2-22

posted on   RandWalker  阅读(315)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示