卡尔曼滤波

在一些场景中,我们可以认为这一时刻的状态依赖于上一时刻的转态,即:
xt=Fxt1+ϵtx_t=F*x_{t - 1}+\epsilon_txt​=F∗xt−1​+ϵt​
其中,ϵt\epsilon_tϵt​为误差项,ϵN(0,Q)\epsilon\sim N(0, Q)ϵ∼N(0,Q)。
PtP_tPt​为协方差矩阵,那么P1=QP_1=QP1​=Q,且Pt=Fxt1F+QP_t = F * x_{t - 1} * F'+QPt​=F∗xt−1​∗F′+Q。
上面等式成立的原因为:cov(Ax)=Acos(x)Acov(Ax)=Acos(x)A'cov(Ax)=Acos(x)A′。


此时,我们预测的观测值应该是μt=Hxt,Σt=HPtH\mu_t=H*x_t,\Sigma_t=H*P_t*H'μt​=H∗xt​,Σt​=H∗Pt​∗H′,即服从N(Hxt,HPtH)N(H*x_t, H*P_t*H')N(H∗xt​,H∗Pt​∗H′)。这里的HHH为当前状态和观测的转态的关系矩阵。
这个和真实的观测值是不一样的,服从N(yk,Rk)N(y_k, R_k)N(yk​,Rk​)。
我们找的点就是,最大可能满足这两个分布的点。也就是两个高斯分布相乘的均值。
这里我没有推导,直说结论吧。
K=Σ0(Σ0+Σ1)1μ=μ0+K(μ1μ0)Σ=Σ0KΣ0K=\Sigma_0(\Sigma_0+\Sigma_1)^{-1}\\\mu'=\mu_0+K(\mu_1-\mu_0)\\\Sigma'=\Sigma_0-K\Sigma_0K=Σ0​(Σ0​+Σ1​)−1μ′=μ0​+K(μ1​−μ0​)Σ′=Σ0​−KΣ0​
那么我们的最优估计就是:
K=HPtH(HPtH+Rk)1Hx^t=Hxt+K(ykHxt)HP^tH=HPtHKHPtHK=HP_tH'(HP_tH'+R_k)^{-1}\\H\hat x_t=Hx_t+K(y_k-Hx_t)\\H\hat P_tH=HP_tH'-KHP_tH'K=HPt​H′(HPt​H′+Rk​)−1Hx^t​=Hxt​+K(yk​−Hxt​)HP^t​H=HPt​H′−KHPt​H′
化简一下就是:
K^=PtH(HPtH+Rt)1x^t=xt+K^(ytHxt)P^t=PtK^HPt\hat K=P_tH'(HP_tH'+R_t)^{-1}\\\hat x_t=x_t+\hat K(y_t-Hx_t)\\\hat P_t=P_t-\hat KHP_tK^=Pt​H′(HPt​H′+Rt​)−1x^t​=xt​+K^(yt​−Hxt​)P^t​=Pt​−K^HPt​
那么,卡尔曼滤波到这里就结束了。


下面是做了一个温度例子的仿真

先模拟得到温度的数据:

function [real_temperature, view_temperature] = get_kalman_data()
% 模拟温度变化的仿真

%% 参数设置
data_size = 120;

%% 空间申请
real_temperature = zeros(1, data_size);     % 真实的温度值
view_temperature = zeros(1, data_size);     % 观测的温度值
real_temperature(1) = 25.1;
view_temperature(1) = 24.9;

%% 噪声项
Q = 0.01;
R = 0.25;
real_guass = sqrt(Q) * randn(1, data_size);
view_guass = sqrt(R) * randn(1, data_size);

%% 模型数据变化
for t = 2:data_size
    real_temperature(t) = real_temperature(t - 1) + real_guass(t - 1);
    view_temperature(t) = real_temperature(t) + view_guass(t - 1);
end

end

然后根据观测值,做卡尔曼滤波:

%% 初始化
clear; close; clc;

%% 数据导入
[real_temperature, view_temperature] = get_kalman_data();
data_size = size(view_temperature);

%% 参数设置
Q = 0.01; R = 0.25;
P = zeros(data_size);
P(1) = Q;

%% 状态转移矩阵
% x_t = F_t * x_{t - 1} + B_t * u_t _ \epsilon_t
% p_t = F_t * p_{t - 1} * F_t' + Q_t
% 其中,\epsilon为误差项,\epsilon_t \sim N(0, Q_t)

F = 1;
H = 1;
I = eye(1);

%% 卡尔曼滤波
kf_temperature = zeros(data_size);
kf_temperature(1) = view_temperature(1);

for t = 2:data_size(2)
    X_t = F * kf_temperature(t - 1);    % 预测值
    P_t = F * P(t - 1) * F' + Q;        % 偏差
    e = view_temperature(t) - H * X_t;  % 误差值
    K = P_t * H' * inv(H * P_t * H'+ R);% 计算卡尔曼增量
    kf_temperature(t) = X_t + K * e;    % 卡尔曼滤波值 = 预测值 + 卡尔曼增量 * 误差值
    P(t) = (I - K * H) * P_t;
end

%% 数据可视化
t = 1:data_size(2);
plot(t, real_temperature, '-b', t, view_temperature, '-r', t, kf_temperature, '-ko');
legend('真实值', '观测值', '卡尔曼滤波值');
xlabel('采样时间/s'); ylabel('温度值/c');

figure;
plot(t, (view_temperature - real_temperature), '-b', t, (kf_temperature - real_temperature), '-r');
legend('测量偏差', '卡尔曼滤波偏差');
xlabel('采样时间/s'); ylabel('温度值/c');

效果如下:
卡尔曼滤波
卡尔曼滤波

上一篇:Centos 安装 helm3


下一篇:tp5 分页