卡尔曼滤波算法——基本原理及举例(python实现radar数据滤波)
一、基本原理
卡尔曼滤波分为两大阶段:预测和更新。
1.1 预测
预测公式如下:
x
′
=
F
x
+
B
u
x^{\prime}=Fx+B u
x′=Fx+Bu
P
′
=
F
P
F
T
+
Q
P^{\prime}=F P F^{T}+Q
P′=FPFT+Q 其中,
x
′
x^{\prime}
x′ 表示当前估计值 ;
F
F
F 表示状态转移矩阵 ;
x
x
x 表示上一时刻的最优估计值 ;
B
B
B 表示外部输入矩阵 ;
U
U
U 表示外部状态矩阵 ;
P
′
P^{\prime}
P′ 表示当前的先验估计协方差矩阵 ;
P
P
P 表示上一时刻的最优估计协方差矩阵 ;
Q
Q
Q 表示过程的协方差矩阵 。
1.2 更新
1.2.1 写法一
更新公式如下:
K
=
P
′
H
T
(
H
P
′
H
T
+
R
)
?
1
K=P^{\prime} H^{T}\left(H P^{\prime} H^{T}+R\right)^{-1}
K=P′HT(HP′HT+R)?1
x
=
x
′
+
K
(
z
?
H
x
′
)
x=x^{\prime}+K\left(z-H x^{\prime}\right)
x=x′+K(z?Hx′)
P
=
(
I
?
K
H
)
P
′
P=(I-K H) P^{\prime}
P=(I?KH)P′ 其中,
K
K
K 表示当前时刻的卡尔曼增益 ;
H
H
H 表示观测矩阵 ;
x
x
x 表示根据当前时刻的估计值及观测值融合得到的当前时刻的最优估计值 ;
z
z
z 表示实际测量值 ;
P
P
P 表示当前时刻的协方差矩阵 ;
I
I
I 表示单位矩阵 。
1.2.2 写法二
更新公式如下:
y
=
z
?
H
x
′
y=z-H x^{\prime}
y=z?Hx′
S
=
H
P
′
H
T
+
R
S=H P^{\prime} H^{T}+R
S=HP′HT+R
K
=
P
′
H
T
S
?
1
K=P^{\prime} H^{T} S^{-1}
K=P′HTS?1
x
=
x
′
+
K
y
x=x^{\prime}+K y
x=x′+Ky
P
=
(
I
?
K
H
)
P
′
P=(I-K H) P^{\prime}
P=(I?KH)P′ 其中,
y
y
y 和
S
S
S 无实际含义 ,属于中间变量;
K
K
K 表示当前时刻的卡尔曼增益 ;
H
H
H 表示观测矩阵 ;
x
x
x 表示根据当前时刻的估计值及观测值融合得到的当前时刻的最优估计值 ;
z
z
z 表示实际测量值 ;
P
P
P 表示当前时刻的协方差矩阵 ;
I
I
I 表示单位矩阵 。
二、举例
本例子采用的是更新写法二 radar测量如下:
2.1 数据说明
2.2 代码
import numpy as np
import matplotlib.pyplot as plt
from math import sin,cos,sqrt
if __name__ == "__main__":
file = open('sample-laser-radar-measurement-data-2.txt')
position_rho_measure = []
position_theta_measure = []
position_velocity_measure = []
time_measure = []
position_x_true = []
position_y_true = []
speed_x_true = []
speed_y_true = []
position_x_measure = []
position_y_measure = []
speed_x_measure = []
speed_y_measure = []
position_x_prior_est = []
position_y_prior_est = []
speed_x_prior_est = []
speed_y_prior_est = []
position_x_posterior_est = []
position_y_posterior_est = []
speed_x_posterior_est = []
speed_y_posterior_est = []
for line in file.readlines():
curLine = line.strip().split(" ")
if curLine[0] == 'R':
position_rho_measure.append(float(curLine[1]))
position_theta_measure.append(float(curLine[2]))
position_velocity_measure.append(float(curLine[3]))
time_measure.append(float(curLine[4]))
position_x_true.append(float(curLine[5]))
position_x_true.append(float(curLine[6]))
speed_x_true.append(float(curLine[7]))
speed_y_true.append(float(curLine[8]))
position_x_measure.append(float(curLine[1])*cos(float(curLine[2])))
position_y_measure.append(float(curLine[1])*sin(float(curLine[2])))
speed_x_measure.append(float(curLine[3])*cos(float(curLine[2])))
speed_y_measure.append(float(curLine[3])*sin(float(curLine[2])))
X0 = np.array([[position_x_measure[1]],[position_y_measure[1]],[speed_x_measure[1]],[speed_y_measure[1]]])
last_timestamp_ = time_measure[1]
P = np.array([[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0]])
X_posterior = np.array(X0)
P_posterior = np.array(P)
for i in range(2,len(time_measure)):
delta_t = (time_measure[i] - last_timestamp_) / 1000000.0
last_timestamp_ = time_measure[i]
F = np.array([[1.0, 0.0, delta_t, 0.0],
[0.0, 1.0, 0.0, delta_t],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0]])
B = np.array([[delta_t*delta_t/2.0, 0.0],
[0.0, delta_t*delta_t/2.0],
[delta_t, 0.0],
[0.0, delta_t]])
if i == 2 or i == 3:
acceleration_x_posterior_est = 0
acceleration_y_posterior_est = 0
else:
acceleration_x_posterior_est = (speed_x_posterior_est[i-3] - speed_x_posterior_est[i-4])/delta_t
acceleration_y_posterior_est = (speed_y_posterior_est[i-3] - speed_y_posterior_est[i-4])/delta_t
U = np.array([[acceleration_x_posterior_est],[acceleration_y_posterior_est]])
print("acceleration_x_posterior_est",acceleration_x_posterior_est)
print("acceleration_y_posterior_est",acceleration_y_posterior_est)
X_prior = np.dot(F,X_posterior)
position_x_prior_est.append(X_prior[0,0])
position_y_prior_est.append(X_prior[1,0])
speed_x_prior_est.append(X_prior[2,0])
speed_y_prior_est.append(X_prior[3,0])
Q = np.array([[0.0001, 0.0, 0.0, 0.0],
[0.0, 0.00009, 0.0, 0.0],
[0.0, 0.0, 0.001, 0.0],
[0.0, 0.0, 0.0, 0.001]])
P_prior_1 = np.dot(F,P_posterior)
P_prior = np.dot(P_prior_1, F.T) + Q
R = np.array([[0.009, 0.0, 0.0, 0.0],
[0.0, 0.0009, 0.0, 0.0],
[0.0, 0.0, 9, 0.0],
[0.0, 0.0, 0, 9]])
H = np.array([[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]])
k1 = np.dot(P_prior, H.T)
k2 = np.dot(np.dot(H, P_prior), H.T) + R
K = np.dot(k1, np.linalg.inv(k2))
Z_measure = np.array([[position_x_measure[i]],[position_y_measure[i]],[speed_x_measure[i]],[speed_y_measure[i]]])
X_posterior_1 = Z_measure - np.dot(H, X_prior)
X_posterior = X_prior + np.dot(K, X_posterior_1)
position_x_posterior_est.append(X_posterior[0, 0])
position_y_posterior_est.append(X_posterior[1, 0])
speed_x_posterior_est.append(X_posterior[2, 0])
speed_y_posterior_est.append(X_posterior[3, 0])
P_posterior_1 = np.eye(4) - np.dot(K, H)
P_posterior = np.dot(P_posterior_1, P_prior)
if True:
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.xlabel("x")
plt.ylabel("y")
plt.plot(position_x_posterior_est, position_y_posterior_est, color='red', label="扩展卡尔曼滤波后的值")
plt.scatter(position_x_measure, position_y_measure, color='blue', label="测量值")
plt.legend()
plt.show()
2.3 实验结果
三、调参技巧
- 一般来说,上一时刻数据与这一时刻数据的间隔时间一般是已知的,若不已知,则需要想办法得到间隔时间。(不同的间隔时间,对后续的其他参数有影响)
- 调参主要调协方差矩阵P的初始值、过程的协方差矩阵Q、测量的协方差矩阵R。
- 先调好测量的协方差矩阵R,R一般是厂家给出的,其数值越小,代表测量精度越高。
- 再调调协方差矩阵P的初始值。
- 最后调过程的协方差矩阵Q。
四、小贴士
- 计算外部状态
U
U
U的时候,不能用预测值来计算,得用估计值。
参考资料
- 卡尔曼滤波简介
- 快速上手的Python版二维卡尔曼滤波解析
- 多传感器融合定位1(激光雷达+毫米波雷达)
- 使用卡尔曼滤波和扩展卡尔曼滤波进行毫米波雷达和激光雷达数据融合示例
|