卡尔曼滤波与扩展卡尔曼滤波实现
参考
How a Kalman filter works, in pictures
python Robotics
知乎-卡尔曼滤波
代码
1 | %matplotlib |
机器人有4个状态量,坐标x,坐标y,航向角yaw,速度v,记录为[x, y, yaw, v]
Q是没有被跟踪的干扰,通过协方差表示为噪声
$$
\boldsymbol{Q}=
\left[\begin{array}{c}
0.01 & 0 & 0 & 0 \\
0 & 0.01 & 0 & 0 \\
0 & 0 & 0.003 & 0 \\
0 & 0 & 0 & 1 \\
\end{array}\right] \quad
$$
R是传感器的不确定性,通过协方差表示为噪声
$$
\boldsymbol{R}=
\left[\begin{array}{c}
1 & 0 \\
0 & 4 \\
\end{array}\right] \quad
$$
速度传感器与陀螺仪的输入误差
$$
\boldsymbol{INPUT_{noise}}=
\left[\begin{array}{c}
1 & 0 \\
0 & 0.27 \\
\end{array}\right] \quad
$$
GPS传感器误差
$$
\boldsymbol{GPS_{noise}}=
\left[\begin{array}{c}
0.25 & 0 \\
0 & 0.25 \\
\end{array}\right] \quad
$$
1 | Q = np.diag([ |
机器人有一个速度传感器和一个陀螺仪传感器。所以该机器人的输入数据为速度m/s,角速度rad/s
$$
\boldsymbol{u}=
\left[\begin{array}{c}
v \\
ω \\
\end{array}\right] \quad
$$
1 | def sensor_input(): |
这里是给定一个初始值,并加入随机噪声,让其不断的进行更新,从而对xTrue进行追踪。
1 | def observation(xTrue, xd, u): |
这里需要了解一下协方差矩阵,相同状态量之间有关系,不同状态量之间就没有关系
下式中,a是1与1的一个关系,g是2与3的一个关系
4个状态量的话,就是4x4的矩阵
$$
\left[\begin{array}{c}
& 1 & 2 & 3\\
1 & a & b & c\\
2 & e & f & g\\
3 & h & i & j\\
\end{array}\right] \quad
$$
F为状态转换方程,将t时刻的状态转换至t+1时刻的状态; 代表的是当前状态量和未来状态量之间的关系,上面解释了为什么对角线之外为0
B是外部控制矩阵,将运动量测量值u的作用映射到状态向量上
u是运动测量值,如加速度,转向角等等(对于没有外部控制的简单系统来说,这部分可以忽略)
$$
x_{t+1} = F x_t + B u \\
P_{t+1} = F P_t F^{-1} \\
$$
$$
\boldsymbol{F}=
\left[\begin{array}{c}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 0 \\
\end{array}\right] \quad
\boldsymbol{B}=
\left[\begin{array}{c}
\cos(\varphi)\Delta t & 0 \\
\sin(\varphi)\Delta t & 0 \\
0 & \Delta t \\
1 & 0 \\
\end{array}\right] \quad
$$
但是这里,我们需要计算这个外部控制量。这是一个变化量,是当前状态量的变化量。
当前状态量有坐标x,坐标y,角速度,速度,所以变化量可以写为
$$
\cos(\varphi)\Delta t \cdot v_t \\
\sin(\varphi)\Delta t \cdot v_t \\
ω \cdot \Delta t \\
v_t\\
可以通过矩阵相乘计算获得=
\left[\begin{array}{c}
\cos(\varphi)\Delta t & 0 \\
\sin(\varphi)\Delta t & 0 \\
0 & \Delta t \\
1 & 0 \\
\end{array}\right] \quad
\cdot
\left[\begin{array}{c}
v \\
ω \\
\end{array}\right] \quad
$$
1 | def motion_model(x, u): |
H为转换矩阵。它将状态向量映射到测量值所在的空间中,代表的是GPS的传感器数据相关性,乘以现在的位置信息就是通过预测得到的新的位置信息
因为GPS只能获得位置信息,所以x,y以外都为0
1 | def observation_model(x): |
在卡尔曼滤波器中,位置信息成线性变化
$$
x_{t+1} = x_t + v cos(yaw) \Delta t \\
y_{t+1} = y_t + v sin(yaw) \Delta t \\
yaw_{t+1} = yaw_t + ω \Delta t \\
v_{t+1} = v_t \\
$$
$$
\boldsymbol{F}=
\left[\begin{array}{c}
1 & 0 & 0 & \Delta t \cos(\varphi) \\
0 & 1 & 0 & \Delta t \sin(\varphi) \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \\
\end{array}\right] \quad
$$
1 | def calc_F(x, u): |
在扩展卡尔曼滤波器中,位置信息成非线性变化,通过一次微分,表示为x与yaw的关系,x与v的关系,y与yaw的关系,y与v的关系
Jacobian记为
$$
\frac{dx}{dyaw} = -v sin(yaw) \Delta t \\
\frac{dx}{dv} = cos(yaw) \Delta t \\
\frac{dy}{dyaw} = v cos(yaw) \Delta t \\
\frac{dy}{dv} = sin(yaw) \Delta t \\
$$
$$
\boldsymbol{Jacobian_f}=
\left[\begin{array}{c}
1 & 0 & -v\sin(\varphi)\Delta t & \cos(\varphi)\Delta t \\
0 & 1 & v\cos(\varphi)\Delta t & \sin(\varphi)\Delta t \\
0 & 0 & 1 & 0 \\
0 & 0 & 0 & 1 \\
\end{array}\right] \quad
$$
1 | def jacob_f(x, u): |
协方差H的Jacobian不发生变化
$$
\boldsymbol{Jacobian_h}=
\left[\begin{array}{c}
1 & 0 & 0 & 0 \\
0 & 1 & 0 & 0 \\
\end{array}\right] \quad
$$
1 | def jacob_h(): |
扩展卡尔曼滤波预测流程
Predict
$$
x_{t+1} = Fx_t + Bu \\
P_{t+1} = J_fP_tJ_f^T + Q\\
$$
Update
$$
z_{t+1} = Hx_{t+1} \\
y = z_t - z_{t+1} \\
S=J_hP_{t+1}J_h^T + R \\
K=P_{t+1}J_h^TS^{-1} \\
x_{t+1} = x_t + Ky \\
P_{t+1} = (1 - KJ_h)P_{t+1}
$$
1 | def ekf_estimation(xEst, PEst, z, u): |
卡尔曼滤波预测流程
Predict
$$
x_{t+1} = Fx_t + Bu \\
P_{t+1} = FP_tF^T + Q\\
$$
Update
$$
z_{t+1} = Hx_{t+1} \\
y = z_t - z_{t+1} \\
S=HP_{t+1}H^T + R \\
K=P_{t+1}H^TS^{-1} \\
x_{t+1} = x_t + Ky \\
P_{t+1} = (1 - KH)P_{t+1}
$$
1 | def kf_estimation(xEst, PEst, z, u): |
封装了一个画图功能,用于画椭圆形
1 | def plot_covariance_ellipse(xEst, PEst, color): # pragma: no cover |
主函数
红色线为扩展卡尔曼滤波,黄色线为卡尔曼滤波
1 | def main(): |