了解卡尔曼滤波

本文介绍了卡尔曼滤波的基本概念和数学推导,包括状态方程和更新方程。通过示例展示了卡尔曼滤波在电动车BMS和自动驾驶中的应用。文中还提供了两个Python代码实现,分别模拟了车辆位置估计和温度测量的滤波过程,以加深理解。
摘要由CSDN通过智能技术生成

我们会经常看到或者听说卡尔曼滤波。在电动车的BMS(Battery manangemen system)里面,也会用到卡尔曼滤波,当然更多的可能是会用到AKF 自适应卡尔曼滤波。在自动驾驶中,也会用到自适应卡尔曼滤波。自适应卡尔曼滤波主要是使用历史固定帧的数据去更新R和Q矩阵,只更新R矩阵的做法比较多,并且只用了加权求和的方法,动态调节参数没有使用。

本文中以下的内容主要是了解卡尔曼滤波,没有涉及AKF 自适应卡尔曼滤波。我们可以在网上找到很多关于卡尔曼滤波的内容,但是可能自己把这些内容写一遍,能够做到对卡尔曼滤波的更深入一些的了解。

状态方程:

             

预测(时间更新):

更新(测量更新):

 

 

, 需要人为设置初始值 ,F,B和H为已知量,  和 也认为是已知量。得出预测值 ,有了P0- 可以得到更新值 ,进而得到 。那么 时刻的计算就完成了。

, 根据已经得到的 ,得出预测值 ,有了 可以得到更新值 ,进而得到 , 。那么 时刻的计算就完成了。

以此继续,

推导过程 :

把真实值和预测值的差叫做先验误差:

把真实值和估计值的差叫做后验误差:           

那么问题就转化为求解 ,使其最小化。可以通过MSE(mean square error),使得后验误差最小。

估计值 = 预测值 + 权重 x 观测误差,也就是说公式 是直接就定义好的,不需要再次推导了。公式 是输出的状态方程,也不需要再推导。

把公式 带入公式 :

得出:

分别定义先验误差和后验误差的协方差矩阵为-

在卡尔曼滤波中,都假定造成服从高斯分布。写成 是说明每行是一个特征,从而求得的协方差矩阵。

把公式 带入到公式 中,并且由于et-vt 不相关,Eet-vtT=E(vtet-T ,得到:

 

展开:

因为: ,并且 是自相关矩阵, ,所以:

根据MSE(mean square error),使得后验误差最小。可以看到, 对角线上的值就是 各个元素的方差。对角线上的和又称为矩阵的迹(Trace),用来做为损失函数,记作 . 根据迹的性质,一个方阵的迹和它的转置的迹相等,因此: 

             

把上式看成 的凸函数,导数为零的点就是最小值。求导:

得到:

根据公式 ,得出:

所以公式) 演变为

进而

即:

计算协方差,再利用 不相关的假设:

)

即:

 例1:假如有一辆无人驾驶汽车,里面装了gps来测量小车的位置,装了车速表来测量小车的车速,它沿着一条直路行驶,已知它在 时刻的位置是 , 速度是 , 加速度为 , 那么它在 时刻的 和速度 是多少呢?

其中 时刻的时间差。

写成状态方程的形式 :

定义小车的状态:

定义状态转移矩阵:

定义控制矩阵:

加入过程噪声 ,公式 变成:

其中 .

 定义gps测量的位置信息为

其中, 为测量噪声

虽然 都是实际上未知的,但是为了简化问题,我们假设过程噪声和测量噪声都是高斯白噪声,并假设他们是已知的。并他们的协方差矩阵分别为 , 即 ,记作:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
deltaT=1
time=range(0,100,deltaT) #时间序列,单位是s
vhlSpd=[5 for i in range(len(time))] #小车的初始速度为5m/s
gpsPos=[0 for i in range(len(time))] # 小车的初始位置为0

acc = 0.1 # 小车的加速度为0.1m/s^2
for i in range(1,len(time)):
    vhlSpd[i]=vhlSpd[i-1]+acc*deltaT
    gpsPos[i]=gpsPos[i-1]+vhlSpd[i-1]+0.5*acc*deltaT*deltaT

noise_vhlSpd = 0.01*np.random.randn(len(time)) #人为制造一些噪声数据
noise_gpsPos = 3*np.random.randn(len(time)) #人为制造一些噪声数据
vhlspd = vhlSpd+noise_vhlSpd     # 人为制造的, 车速表的测量数据, 相当于Zt
gpsPos = gpsPos + noise_gpsPos   # 认为制造的,gps的测量数据, 相当于Zt

#设置卡尔曼当中所需的已知量
Q = np.mat([[0.01, 0],[0, 0.01]]) # 过程噪声的协方差矩阵
R = np.mat([1])

#初始化
X = np.mat([[0],[0]]); #初始状态,[位置,速度]就是我们要估计的内容
P = np.mat([[1, 0],[0, 1]]) #先验误差协方差矩阵的初始值,根据经验给出

#已知的线性变换矩阵
F = np.mat([[1,deltaT],[0,1]])
B = np.mat([[0.5*deltaT*deltaT], [deltaT]])
H = np.mat([1,0])

#对每一时刻状态的记录
xlist=[]
for i in range(0, len(time)):
    X_ = F*X + B*acc
    P_ = F*P*F.T + Q
    K = P_*H.T/(H*P_*H.T + R)
    X = X_+K*(np.mat(gpsPos[i])-H*X_)
    P = (np.eye(2)-K*H)*P_
    xTurn = X[0].tolist()
    xTurn1 = xTurn[0]
    xlist.append(xTurn1[0])

fig, ax = plt.subplots(figsize=[10,5],facecolor='lightblue')

ax.set_facecolor('#eafff5')

ax.set_title('Estimated position vs Measured position', color='darkblue')
# 4) single letter color string
ax.set_xlabel('Time [s]',  color='darkblue',fontsize=12)
# 5) a named color:
ax.set_ylabel('gps postion', color='darkblue',fontsize=12)
# 6) a named xkcd color:
ax.plot(time, xlist, 'xkcd:crimson',label= 'Estimated gps postion')
# 7) Cn notation:
ax.plot(time, gpsPos, color='black', linestyle='--', label= 'Measured gps postion')
# 8) tab notation:
ax.tick_params(labelcolor='darkblue',color='darkblue',width=2)
ax.spines['left'].set_color('darkblue')
ax.spines['bottom'].set_color('darkblue')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.grid(axis='y')

labelss = ax.legend(loc=0, fontsize=12).get_texts()
[label.set_color('darkblue') for label in labelss]

 例2: 假设如下一个系统,房间内连续两个时刻温度差值的标准差为0.02度,温度计的测量值误差的标准差为0.5度,房间温度的真实值为24度,对温度的初始估计值为23.5度,误差的方差为1。

Python 代码实现:

# 假设如下一个系统:
# 房间内连续两个时刻温度差值的标准差为0.02度
# 温度计的测量值误差的标准差为0.5度
# 房间温度的真实值为24度
# 对温度的初始估计值为23.5度,误差的方差为1
# Kalman filter example of temperature measurement in Matlab, I use python to do it
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

n_iter=range(0,100,1) # 0,...99s,100 个时刻
z = 24+np.random.randn(len(n_iter)) # z是温度计的测量结果,在真实值(永远未知)24的基础上加上了方差为0.25的高斯噪声。

#设置卡尔曼当中所需的已知量
Q = np.mat([4e-4]) # 过程噪声的协方差矩阵
R = np.mat([0.25])

#初始化
X = np.mat([23.5]); #初始状态,
P = np.mat([1]) #先验误差协方差矩阵的初始值,根据经验给出
u=0
#已知的线性变换矩阵
F = np.mat([1])
B = np.mat([0])
H = np.mat([1])

#对每一时刻状态的记录
xlist=[]
for i in range(0, len(n_iter)):
    X_ = F*X + B*u
    P_ = F*P*F.T + Q
    K = P_*H.T/(H*P_*H.T + R)
    X = X_+K*(np.mat(z[i])-H*X_)
    P = (np.eye(1)-K*H)*P_
    xTurn = X[0].tolist()
    xTurn1 = xTurn[0]
    xlist.append(xTurn1[0])

fig, ax = plt.subplots(figsize=[10,5],facecolor='lightblue')

ax.set_facecolor('#eafff5')

ax.set_title('Estimated temperature vs Measured temperature', color='darkblue')
# 4) single letter color string
ax.set_xlabel('Time [s]',  color='darkblue',fontsize=12)
# 5) a named color:
ax.set_ylabel('temperature', color='darkblue',fontsize=12)
# 6) a named xkcd color:
ax.plot(n_iter, xlist, 'xkcd:crimson',label= 'Estimated temperature')
# 7) Cn notation:
ax.plot(n_iter, z, color='black', linestyle='--', label= 'Measured temperature')
# 8) tab notation:
ax.tick_params(labelcolor='darkblue',color='darkblue',width=2)
ax.spines['left'].set_color('darkblue')
ax.spines['bottom'].set_color('darkblue')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.grid(axis='y')

labelss = ax.legend(loc=0, fontsize=12).get_texts()
[label.set_color('darkblue') for label in labelss]

 

 引用:

一文看懂卡尔曼滤波(附全网最详细公式推导和Matlab代码) - 知乎 (zhihu.com)

(53条消息) kalman滤波理解三:协方差矩阵的计算_误差协方差矩阵_还差得远呢的博客-CSDN博客

如何求矩阵的协方差矩阵 - 知乎 (zhihu.com)

卡尔曼滤波算法原理(KF,EKF,AKF,UKF) - 知乎 (zhihu.com)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值