扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)「建议收藏」

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)「建议收藏」扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)文章目录扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)理论讲解KF和EKF模型对比雅可比矩阵计算计算实例应用实例线性模型CV模型:CA模型非线性模型CTRV模型:CTRV实例(python)smalldemo抛物线demo飞机高度demoC++实例参考文献我们上篇提到的卡尔曼滤波是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布

大家好,又见面了,我是你们的朋友全栈君。

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)

我们上篇提到的
卡尔曼滤波(参见我的另一篇文章:
卡尔曼滤波理论讲解与应用(matlab和python))是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布的系统中,但是现实中并不是所有的系统都符合这样 。另外高斯分布在非线性系统中的传递结果将不再是高斯分布。那如何解决这个问题呢?扩展卡尔曼滤波就是干这个事的。

理论讲解

扩展卡尔曼滤波(Extended Kalman Filter,EKF)通过局部线性来解决非线性的问题。将非线性的预测方程和观测方程进行求导,以切线代替的方式来线性化。其实就是在均值处进行一阶泰勒展开

数学中,泰勒公式是一个用函数在某点的信息描述其附近取值的公式( 一句话描述:就是用多项式函数去逼近光滑函数 )。如果函数足够平滑的话,在已知函数在某一点的各阶导数值的情况之下,泰勒公式可以用这些导数值做系数构建一个多项式来近似函数在这一点的邻域中的值。泰勒公式还给出了这个多项式和实际的函数值之间的偏差。
f ( x ) T a y l o r = ∑ n = 0 ∞ f ( n ) ( a ) n ! × ( x − a ) n = f ( a ) + f ′ ( a ) 1 ! ( x − a ) + f ( 2 ) ( a ) 2 ! ( x − a ) 2 + ⋯ + f ( n ) ( a ) n ! ( x − a ) n + R n ( x ) f(x)_{Taylor} = \sum_{n=0}^{\infty} \frac{f^{(n)}(a)}{n!} \times (x – a)^n\\ =f(a) + \frac{f'(a)}{1!}(x-a) + \frac{f^{(2)}(a)}{2!}(x-a)^2+ \cdots + \frac{f^{(n)}(a)}{n!}(x-a)^n + R_n(x) f(x)Taylor=n=0n!f(n)(a)×(xa)n=f(a)+1!f(a)(xa)+2!f(2)(a)(xa)2++n!f(n)(a)(xa)n+Rn(x)
f ( n ) ( a ) f^{(n)}(a) f(n)(a) 表示 f ( x ) f(x) f(x) 在第 n n n阶导数的表达式,带入一个值 a a a计算后得到的结果(注意,它是个值)
1 n ! \frac{1}{n!} n!1是一个系数(一个值),每一项都不同,第一项 1 1 \frac{1}{1} 11,第二项 1 2 \frac{1}{2} 21 …… 依此类推
( x − a ) n (x−a)^n (xa)n是一个以 x x x为自变量的表达式 R n ( x ) Rn(x) Rn(x)是泰勒公式的余项,是 ( x − a ) n (x−a)^n (xa)n 的高阶无穷小

在这里插入图片描述

KF和EKF模型对比

首先,让卡尔曼先和扩展卡尔曼滤波做一个对比。在对比过程中可以看出,扩展卡尔曼是一个简单的非线性近似滤波算法,指运动或观测方程不是线性的情况,在预测模型部分,扩展卡尔曼的预测模型和量测模型已经是非线性了。为了简化计算,EKF通过一阶泰勒分解线性化运动、观测方程。KFEKF具有相同的算法结构,都是以高斯形式描述后验概率密度的,通过计算贝叶斯递推公式得到的。最大的不同之处在于,计算方差时,EKF的状态转移矩阵(上一时刻的状态信息 k − 1 ∣ k − 1 k-1|k-1 k1k1)和观测矩阵(一步预测 k ∣ k − 1 k|k-1 kk1)都是状态信息的雅克比矩阵( 偏导数组成的矩阵)。 在预测公式部分,扩展卡尔曼滤波的 F k F_k Fk f f f的雅可比矩阵,在更新公式部分,扩展卡尔曼滤波的 H k H_k Hk h h h的雅可比矩阵。

预测模型:
K a l m a n F i l t e r E x t e n d e d K a l m a n F i l t e r x k = F x k − 1 + B u k + w k x k = f ( x k − 1 , u k ) + w k z k ⃗ = H x k + v k z k ⃗ = h ( x k ) + v k \quad Kalman \quad\quad Filter \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad Extended \quad Kalman \quad Filter\\ x_k=Fx_{k-1}+Bu_k+w_k \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad x_k=f(x_{k-1},u_k)+w_k\\ \vec{z_k}=Hx_k+v_k \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad \vec{z_k}=h(x_k)+v_k KalmanFilterExtendedKalmanFilterxk=Fxk1+Buk+wkxk=f(xk1,uk)+wkzk
=
Hxk+vkzk
=
h(xk)+vk

预测公式:

K a l m a n F i l t e r E x t e n d e d K a l m a n F i l t e r x ^ k = F k x ^ k − 1 + B k u ⃗ k x ^ k = f ( x k − 1 , u k ) P k = F k P k − 1 F k T + Q k P k = F k P k − 1 F k T + Q k \quad Kalman \quad\quad Filter \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad Extended \quad Kalman \quad Filter\\ \hat x_k=F_k \hat x_{k-1} + B_k \vec u_k \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad \hat x_k=f(x_{k-1},u_k)\\ P_k=F_kP_{k-1}F^T_k+Q_k \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad P_k=F_kP_{k-1}F^T_k+Q_k KalmanFilterExtendedKalmanFilterx^k=Fkx^k1+Bku
k
x^k=
f(xk1,uk)Pk=FkPk1FkT+QkPk=FkPk1FkT+Qk

更新公式:

K a l m a n F i l t e r E x t e n d e d K a l m a n F i l t e r K ′ = P k H k T ( H k P k H k T + R k ) − 1 K ′ = P k H k T ( H k P k H k T + R k ) − 1 x ^ k ′ = x ^ k + K ′ ( z k ⃗ − H k x ^ k ) x ^ k ′ = x ^ k + K ′ ( z k ⃗ − h ( x ^ k ) ) P k ′ = P k − K ′ H k P k P k ′ = P k − K ′ H k P k \quad Kalman \quad\quad Filter \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad Extended \quad Kalman \quad Filter \\ K’ = P_kH^T_k(H_kP_kH^T_k+R_k)^{-1} \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad K’ = P_kH^T_k(H_kP_kH^T_k+R_k)^{-1} \\ \hat x’_k = \hat x_k+K'(\vec {z_k}-H_k\hat x_k) \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad \hat x’_k = \hat x_k+K'(\vec {z_k}-h(\hat x_k)) \\ P’_k=P_k-K’H_kP_k \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad P’_k=P_k-K’H_kP_k KalmanFilterExtendedKalmanFilterK=PkHkT(HkPkHkT+Rk)1K=PkHkT(HkPkHkT+Rk)1x^k=x^k+K(zk
Hkx^k)x^k=x^k+K(zk
h(x^k))Pk=PkKHkPkPk=PkKHkPk

其中
x k ^ \hat{x_k} xk^ k k k时刻的状态向量;

F k F_k Fk为状态转移矩阵,表示将 k − 1 k-1 k1时刻的状态向量转移至t时刻的状态向量;

B k B_k Bk是输入控制矩阵,代表着将控制向量 u k ^ \hat{u_k} uk^映射到状态向量上,统一控制向量 u k ^ \hat{u_k} uk^和状态向量之间 x k ^ \hat{x_k} xk^的关系;

u k ^ \hat{u_k} uk^代表着控制向量,如加速度,角加速度等;

w k w_k wk为过程演化噪声;

v k v_k vk为量测噪声 ;

P k P_k Pk为状态向量的协方差矩阵,代表着状态向量每个元素之间的关系;

Q k Q_k Qk表示预测状态的高斯噪声的协方差阵,它用来衡量模型的准确度,模型越准确其值越小;

z k ⃗ \vec {z_k} zk
为传感器测量值的状态向量,也就是传感器的测量结果;

H k H_k Hk 为转换矩阵,他将状态向量 x k ^ \hat{x_k} xk^映射到测量值所在的向量空间 z k ⃗ \vec {z_k} zk

R k R_k Rk为测量值的高斯噪声的协方差阵,代表着传感器测量的误差。

图片示例:

在这里插入图片描述
J A , J H J_A,J_H JA,JH均为雅可比矩阵。
在这里插入图片描述

雅可比矩阵计算

雅可比矩阵(Jacobian matrix )是该函数 f ( x ) f(x) f(x) 的所有行数( m m m个)对状态向量 x ⃗ k \vec x_k x
k
的所有分量( n n n 个)的一阶偏导数组成的矩阵。雅可比矩阵 F k F_k Fk的计算如下,其中输入噪声为0。
x k = f ( x k − 1 , u k , w k ) ≈ f ( x ^ k − 1 , u k , 0 ) + ∂ f ∂ x k − 1 ∣ x ^ k − 1 , u k , 0 ⏟ F k − 1 ( x k − 1 − x ^ k − 1 ) + ∂ f ∂ w k − 1 ∣ x ^ k − 1 , u k , 0 ⏟ L k − 1 w k 令 k = k − 1 F k = d e f ∂ f ( x ) ∂ x = d e f [ ∂ f ∂ x 1 . . . ∂ f ∂ x n ] = d e f [ ∂ f 1 ∂ x 1 . . . ∂ f 1 ∂ x n ⋮ ⋮ ⋮ ∂ f m ∂ x 1 . . . ∂ f m ∂ x n ] = d e f J A . x_k=f(x_{k-1},u_k,w_k) \approx f(\hat x_{k-1},u_k,0)+ \underbrace{\left.\frac{\partial {f}}{\partial {x}_{k-1}}\right|_{\hat{
{x}}_{k-1}, {u}_{k},0} }_{\mathbf{F}_{k-1}} \left({x}_{k-1}-\hat{
{x}}_{k-1}\right) + \underbrace{\left.\frac{\partial {f}}{\partial {w}_{k-1}}\right|_{\hat{
{x}}_{k-1}, {u}_{k},0} }_{\mathbf{L}_{k-1}} w_k\\令k=k-1\\F_k\stackrel{def}{=}\frac{\partial f(x)}{\partial x}\stackrel{def}{=} \left[ \begin{array}{ccc} \frac{\partial f}{\partial x_1} & … & \frac{\partial f}{\partial x_n} \\ \end{array} \right] \stackrel{def}{=} \left[ \begin{array}{ccc} \frac{\partial f_1}{\partial x_1} & … & \frac{\partial f_1}{\partial x_n} \\ \vdots & \vdots & \vdots \\\frac{\partial f_m}{\partial x_1} & … & \frac{\partial f_m}{\partial x_n} \end{array} \right] \stackrel{def}{=} J_A.\\
xk=f(xk1,ukwk)f(x^k1,uk,0)+Fk1


xk1fx^k1,uk,0
(xk1x^k1)+
Lk1


wk1fx^k1,uk,0
wk
k=k1Fk=defxf(x)=def[x1f...xnf]=defx1f1x1fm......xnf1xnfm=defJA.

函数 f ( x k − 1 , u k , w k ) f(x_{k-1},u_k,w_k) f(xk1,uk,wk) f 1 , . . . , f m f_1,…,f_m f1,...,fm 行个分量,于是有 m m m行。状态向量 x ⃗ k \vec x_k x
k
x 1 , . . . , x n x_1,…,x_n x1,...,xn个分量,于是有 n n n列。

雅可比矩阵 H k H_k Hk的计算如下,其中输入噪声为0。
y k = h ( x k , v k ) ≈ h ( x ^ k , 0 ) + ∂ h ∂ x k ∣ x ^ k , 0 ⏟ H k ( x k − x ^ k ) + ∂ h ∂ v k ∣ x ^ k , 0 ⏟ M k v k H k = d e f ∂ h ( x ) ∂ x = d e f [ ∂ h ∂ x 1 . . . ∂ h ∂ x n ] = d e f [ ∂ h 1 ∂ x 1 . . . ∂ h 1 ∂ x n ⋮ ⋮ ⋮ ∂ h m ∂ x 1 . . . ∂ h m ∂ x n ] = d e f J H . y_k=h(x_{k},v_k) \approx h(\hat x_{k},0)+ \underbrace{\left.\frac{\partial {h}}{\partial {x}_{k}}\right|_{\hat{
{x}}_{k}, 0} }_{\mathbf{H}_{k}} \left({x}_{k}-\hat{
{x}}_{k}\right) + \underbrace{\left.\frac{\partial {h}}{\partial {v}_{k}}\right|_{\hat{
{x}}_{k}, 0} }_{\mathbf{M}_{k}} v_k \\H_k\stackrel{def}{=}\frac{\partial h(x)}{\partial x}\stackrel{def}{=} \left[ \begin{array}{ccc} \frac{\partial h}{\partial x_1} & … & \frac{\partial h}{\partial x_n} \\ \end{array} \right] \stackrel{def}{=} \left[ \begin{array}{ccc} \frac{\partial h_1}{\partial x_1} & … & \frac{\partial h_1}{\partial x_n} \\ \vdots & \vdots & \vdots \\ \frac{\partial h_m}{\partial x_1} & … & \frac{\partial h_m}{\partial x_n} \end{array} \right] \stackrel{def}{=} J_H.
yk=h(xk,vk)h(x^k,0)+Hk


xkhx^k,0
(xkx^k)+
Mk


vkhx^k,0
vk
Hk=defxh(x)=def[x1h...xnh]=defx1h1x1hm......xnh1xnhm=defJH.

函数 h ( x k , v k ) h(x_{k},v_k) h(xk,vk) h 1 , . . . , h m h_1,…,h_m h1,...,hm 行个分量,于是有 m m m行。状态向量 x ⃗ k \vec x_k x
k
x 1 , . . . , x n x_1,…,x_n x1,...,xn个分量,于是有 n n n列。

矩阵计算实例

举例说明: f ( x ) f(x) f(x) f 1 , f 2 f_1,f_2 f1,f2两个函数,状态向量 x ⃗ k \vec x_k x
k
x 1 , x 2 x_1,x_2 x1,x2两个分量,所以有
f ( x ) = [ f 1 f 2 ] = [ x 1 + x 2 x 1 2 ] ∂ f ∂ x = [ ∂ f 1 ∂ x 1 ∂ f 1 ∂ x 2 ∂ f 2 ∂ x 1 ∂ f 2 ∂ x 2 ] = [ 1 1 2 x 1 0 ] {f}({x})=\left[\begin{array}{l} f_{1} \\ f_{2} \end{array}\right]=\left[\begin{array}{c} x_{1}+x_{2} \\ x_{1}^{2} \end{array}\right] \quad \quad \frac{\partial {f}}{\partial {x}}=\left[\begin{array}{cc} \frac{\partial f_{1}}{\partial x_{1}} & \frac{\partial f_{1}}{\partial x_{2}} \\ \frac{\partial f_{2}}{\partial x_{1}} & \frac{\partial f_{2}}{\partial x_{2}} \end{array}\right]=\left[\begin{array}{cc} 1 & 1 \\ 2 x_{1} & 0 \end{array}\right] f(x)=[f1f2]=[x1+x2x12]xf=[x1f1x1f2x2f1x2f2]=[12x110]
又如:
在这里插入图片描述

应用实例

线性模型

常用的线性模型有

  • 恒定速度模型(Constant Velocity, CV)
  • 恒定加速度模型(Constant Acceleration, CA)

这些线性运动模型假定目标是直线运动的,并不考虑物体的转弯。

CV模型:

CV模型的状态空间可以表示为:
x → ( t ) = ( x y v x v y ) T \overrightarrow{x}(t) = (x \quad y \quad v_x \quad v_y)^T x
(t)=
(xyvxvy)T

那么转移函数为:
x → ( t + Δ t ) = ( x ( t ) + Δ t v x y ( t ) + Δ t v y v x v y ) \overrightarrow{x}(t+\Delta t) = \left( \begin{array}{c} x(t) + \Delta t v_x \\ y(t) + \Delta t v_y \\ v_x \\ v_y \end{array} \right) x
(t+
Δt)=x(t)+Δtvxy(t)+Δtvyvxvy

或者,CV模型的完整的状态空间还可以表示为:

x → ( t ) = ( x y v x v y a x a y ) T \overrightarrow{x}(t) = (x \quad y \quad v_x \quad v_y \quad a_x \quad a_y)^T x
(t)=
(xyvxvyaxay)T

矩阵表示为:
x 1 → = ( x 1 y 1 v x 1 v y 1 a x 1 a y 1 ) = F ⋅ x 0 → = ( 1 0 t 0 0 0 0 1 0 t 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) ⋅ ( x 0 y 0 v x 0 v y 0 a x 0 a y 0 ) = ( x 0 + v x 0 t y 0 + v y 0 t v x 0 v y 0 0 0 ) \overrightarrow{x1} =\left( \begin{array}{c} x_1\\ y_1\\ v_{x1}\\ v_{y1}\\ a_{x1}\\ a_{y1} \end{array} \right)= F \cdot \overrightarrow{x0}= \left( \begin{array}{c} 1 & 0 & t & 0 & 0 &0\\ 0 & 1 & 0 & t & 0 &0\\ 0 & 0 & 1 & 0 & 0 &0\\ 0 & 0 & 0 & 1 & 0 &0\\ 0 & 0 & 0 & 0 & 0 &0 \\ 0 & 0 & 0 & 0 & 0 &0 \end{array} \right) \cdot \left( \begin{array}{c} x_0\\ y_0\\ v_{x0}\\ v_{y0}\\ a_{x0}\\ a_{y0} \end{array} \right)= \left( \begin{array}{c} x_0+v_{x0}t\\ y_0+v_{y0}t\\ v_{x0}\\ v_{y0}\\ 0\\ 0 \end{array} \right) x1
=
x1y1vx1vy1ax1ay1=Fx0
=
100000010000t010000t0100000000000000x0y0vx0vy0ax0ay0=x0+vx0ty0+vy0tvx0vy000

CA模型

CA模型的状态空间可以表示为:

x → ( t ) = ( x y v x v y a x a y ) T \overrightarrow{x}(t) = (x \quad y \quad v_x \quad v_y \quad a_x \quad a_y)^T x
(t)=
(xyvxvyaxay)T

矩阵表示为:
x 1 → = ( x 1 y 1 v x 1 v y 1 a x 1 a y 1 ) = F ⋅ x 0 → = ( 1 0 t 0 1 2 t 2 0 0 1 0 t 0 1 2 t 2 0 0 1 0 t 0 0 0 0 1 0 t 0 0 0 0 1 0 0 0 0 0 0 1 ) ⋅ ( x 0 y 0 v x 0 v y 0 a x 0 a y 0 ) = ( x 0 + v x 0 t + 1 2 a x 0 t 2 y 0 + v y 0 t + 1 2 a y 0 t 2 v x 0 + a x 0 t v y 0 + a y 0 t a x 0 a y 0 ) \overrightarrow{x1} =\left( \begin{array}{c} x_1\\ y_1\\ v_{x1}\\ v_{y1}\\ a_{x1}\\ a_{y1} \end{array} \right)= F \cdot \overrightarrow{x0}= \left( \begin{array}{c} 1 & 0 & t & 0 & \frac{1}{2}t^2 &0\\ 0 & 1 & 0 & t & 0 &\frac{1}{2}t^2\\ 0 & 0 & 1 & 0 & t &0\\ 0 & 0 & 0 & 1 & 0 &t\\ 0 & 0 & 0 & 0 & 1 &0 \\ 0 & 0 & 0 & 0 & 0 &1 \end{array} \right) \cdot \left( \begin{array}{c} x_0\\ y_0\\ v_{x0}\\ v_{y0}\\ a_{x0}\\ a_{y0} \end{array} \right)= \left( \begin{array}{c} x_0+v_{x0}t+\frac{1}{2}a_{x0}t^2\\ y_0+v_{y0}t+\frac{1}{2}a_{y0}t^2\\ v_{x0}+a_{x0}t\\ v_{y0}+a_{y0}t\\ a_{x0}\\ a_{y0} \end{array} \right) x1
=
x1y1vx1vy1ax1ay1=Fx0
=
100000010000t010000t010021t20t010021t20t01x0y0vx0vy0ax0ay0=x0+vx0t+21ax0t2y0+vy0t+21ay0t2vx0+ax0tvy0+ay0tax0ay0

CA和CV的交互式多模型可以参考我的这篇博客:交互式多模型 IMM的原理及代码实现(matlab)

非线性模型

非线性模型包括:

  • 恒定转率和速度模型(Constant Turn Rate and Velocity,CTRV)
  • 恒定转率和加速度模型(Constant Turn Rate and Acceleration,CTRA)

CTRV目前多用于机载追踪系统(飞机),这些二次运动模型大多假定速度 v v v和 偏航角速度(yaw rate) ω ω ω没有关系,因此,在这类运动模型中,由于偏航角速度测量的扰动(不稳定),即使车辆没有移动,我们的运动模型下的角速度也会发生细微的变化。为了解决这个问题,速度 v v v 和 偏航角速度 ω ω ω 的关联可以通过设定转向角 Φ Φ Φ恒定来建立,这样就引出了 恒定转向角和速度模型(Constant Steering Angle and Velocity,CSAV), 另外,速度可以别假定为线性变化的,进而引出了常曲率和加速度模型(Constant Curvature and Acceleration,CCA)。

CTRV模型:

CA、CV模型并不能预测预测转弯,为了解决这个问题我们使用CTRV模型:
在这里插入图片描述
CTRV中,使用位置 p x , p y p_x,p_y px,py,速度 v v v,角度 ψ \psi ψ,及角速度 ψ ˙ \dot{\psi} ψ˙来作为目标的状态向量:
x → ( t ) = ( p x p y v ψ ψ ˙ ) T \overrightarrow{x}(t) = (p_x \quad p_y \quad v \quad \psi \quad \dot{\psi})^T x
(t)=
(pxpyvψψ˙)T

其中, ψ \psi ψ为偏航角,是追踪的目标车辆在当前车辆坐标系下与 x x x轴的夹角,逆时针方向为正,取值范围是 [ 0 , 2 π ) [0, 2π) [0,2π), ψ ˙ \dot{\psi} ψ˙是偏航角速度。
其推导过程为:
在这里插入图片描述
在这里插入图片描述
CTRV的状态向量也可以表示为:

x → ( t ) = ( x y v θ ω ) T \overrightarrow{x}(t) = (x \quad y \quad v \quad \theta \quad \omega)^T x
(t)=
(xyvθω)T

其中, θ θ θ为偏航角, ω ω ω是偏航角速度。
CTRV的状态转移函数为:
x → ( t + Δ t ) = ( v ω sin ⁡ ( ω Δ t + θ ) − v ω sin ⁡ ( θ ) + x ( t ) − v ω cos ⁡ ( ω Δ t + θ ) + v ω cos ⁡ ( θ ) + y ( t ) v ω Δ t + θ ω ) \overrightarrow{x}(t+\Delta t) = \left( \begin{array}{c} \frac{v}{\omega} \sin(\omega \Delta t + \theta) – \frac{v}{\omega}\sin(\theta) + x(t) \\ -\frac{v}{\omega} \cos(\omega \Delta t + \theta) + \frac{v}{\omega}\cos(\theta) + y(t) \\ v \\ \omega \Delta t + \theta \\ \omega \end{array} \right) x
(t+
Δt)=ωvsin(ωΔt+θ)ωvsin(θ)+x(t)ωvcos(ωΔt+θ)+ωvcos(θ)+y(t)vωΔt+θω

使用CTRV还存在一个问题,那就是 ω = 0 ω=0 ω=0 的情况,此时我们的状态转移函数公式中的 ( x , y ) (x,y) (x,y)将变成无穷大。为了解决这个问题,我们考察一下 ω = 0 ω=0 ω=0 的情况,此时我们追踪的车辆实际上是直线行驶的,所以我们的 ( x , y ) (x,y) (x,y)的计算公式就变成了:
x ( t + Δ t ) = v cos ⁡ ( θ ) Δ t + x ( t ) y ( t + Δ t ) = v sin ⁡ ( θ ) Δ t + y ( t ) x(t+\Delta t) = v \cos(\theta)\Delta t + x(t)\\ y(t+\Delta t) = v \sin(\theta)\Delta t + y(t) x(t+Δt)=vcos(θ)Δt+x(t)y(t+Δt)=vsin(θ)Δt+y(t)
那么现在问题来了,我们知道,卡尔曼滤波仅仅用于处理线性问题,那么很显然我们现在的处理模型是非线性的,这个时候我们就不能简单使用卡尔曼滤波进行预测和更新了,此时预测的第一步变成了如下非线性函数:
x k + 1 = f ( x k , u k ) x_{k+1} = f(x_k, u_k) xk+1=f(xk,uk)
其中, f ( x ) f(x) f(x)表示CTRV运动模型的状态转移函数, u k u_k uk 表示处理噪声。为了解决非线性系统下的问题,我们引入扩展卡尔曼滤波(Extended Kalman Filter,EKF)

CTRV示例

应用场景:

假设我们有激光雷达和雷达两个传感器,它们分别以一定的频率来测量如下数据:

  • 激光雷达:测量目标车辆的坐标 ( x , y ) (x,y) (x,y) 。这里的 x , y x,y x,y是相对于我们的车辆的坐标系的,即我们的车辆为坐标系的原点,我们的车头为 x x x轴,车的左侧为 y y y轴。
  • 雷达:测量目标车辆在我们车辆坐标系下与本车的距离 ρ ρ ρ,目标车辆与x轴的夹角 ψ ψ ψ,以及目标车辆与我们自己的相对距离变化率 ρ ˙ \dot ρ ρ˙(本质上就是目标车辆的实际速度在我们和目标车辆的连线上的分量)

前面的卡尔曼滤波器中,我们使用一个测量矩阵 H H H 将预测的结果映射到测量空间,那是因为这个映射本身就是线性的,现在,我们使用毫米波雷达和激光雷达来测量目标车辆(我们把这个过程称为传感器融合),这个时候会有两种情况,即:

  1. 激光雷达的测量模型仍然是线性的,其测量矩阵为:

H L = [ 1 0 0 0 0 0 1 0 0 0 ] H_L = \left[ \begin{array}{c} 1 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 \end{array} \right] HL=[1001000000]

将预测映射到激光雷达测量空间:
H L x → = ( x , y ) T H_L\overrightarrow{x} = (x, y)^T HLx
=
(x,y)T

  1. 雷达的预测映射到测量空间是非线性的,其表达式为:

( ρ ψ ρ ˙ ) = ( x 2 + y 2 a t a n 2 ⁡ ( y , x ) v x + v y x 2 + y 2 ) \left(\begin{matrix} \rho \\ \psi \\ \dot\rho \end{matrix}\right) = \left(\begin{matrix}\sqrt{x^{2} + y^{2}}\\\operatorname{atan_{2}}{\left (y,x \right )}\\\frac{v x + v y}{\sqrt{x^{2} + y^{2}}}\end{matrix}\right) ρψρ˙=x2+y2
atan2(y,x)x2+y2
vx+vy

此时我们使用 h ( x ) h(x) h(x)来表示这样一个非线性映射 ,下面就是对 h ( x ) h(x) h(x)求雅各比行列式,具体的算法见代码。
在这里插入图片描述

滤波效果:

在这里插入图片描述

具体的推导可以参考这篇博客:高级运动模型和扩展卡尔曼滤波

python代码

这里附上完整的python代码:python_EKF_CTRV 代码

C++代码

这里附上完整的C++代码:C++_EKF_CTRV 代码

matlab示例

下面举一些小的例子,便于我们理解应用

抛物线demo

在这里插入图片描述
在这里插入图片描述

matlab代码
close all;
clear all;
%%  真实轨迹模拟
kx = .01;   ky = .05;       % 阻尼系数
g = 9.8;                    % 重力
t = 15;                     % 仿真时间
Ts = 0.1;                   % 采样周期 
len = fix(t/Ts);            % 仿真步数
dax = 3; day = 3;       % 系统噪声
X = zeros(len,4); 
X(1,:) = [0, 50, 500, 0]; % 状态模拟的初值
for k=2:len
    x = X(k-1,1); vx = X(k-1,2); y = X(k-1,3); vy = X(k-1,4); 
    x = x + vx*Ts;
    vx = vx + (-kx*vx^2+dax*randn(1,1))*Ts;
    y = y + vy*Ts;
    vy = vy + (ky*vy^2-g+day*randn(1))*Ts;
    X(k,:) = [x, vx, y, vy];
end
%%  构造量测量
dr = 8;  dafa = 0.1;        % 量测噪声
for k=1:len
    r = sqrt(X(k,1)^2+X(k,3)^2) + dr*randn(1,1);
    a = atan(X(k,1)/X(k,3))*57.3 + dafa*randn(1,1);
    Z(k,:) = [r, a];
end
%% ekf 滤波
Qk = diag([0; dax/10; 0; day/10])^2;
Rk = diag([dr; dafa])^2;
Pk = 10*eye(4);
Pkk_1 = 10*eye(4);
x_hat = [0,40,400,0]';
X_est = zeros(len,4);
x_forecast = zeros(4,1);
z = zeros(4,1);
for k=1:len
    % 1 状态预测    
    x1 = x_hat(1) + x_hat(2)*Ts;
    vx1 = x_hat(2) + (-kx*x_hat(2)^2)*Ts;
    y1 = x_hat(3) + x_hat(4)*Ts;
    vy1 = x_hat(4) + (ky*x_hat(4)^2-g)*Ts;
    x_forecast = [x1; vx1; y1; vy1];        %预测值
    % 2  观测预测
    r = sqrt(x1*x1+y1*y1);
    alpha = atan(x1/y1)*57.3;
    y_yuce = [r,alpha]';
    %  状态矩阵
    vx = x_forecast(2);  vy = x_forecast(4);
    F = zeros(4,4);
    F(1,1) = 1;  F(1,2) = Ts;
    F(2,2) = 1-2*kx*vx*Ts;
    F(3,3) = 1;  F(3,4) = Ts;
    F(4,4) = 1+2*ky*vy*Ts;
    Pkk_1 = F*Pk*F'+Qk;
    % 观测矩阵
    x = x_forecast(1); y = x_forecast(3);
    H = zeros(2,4);
    r = sqrt(x^2+y^2);  xy2 = 1+(x/y)^2;
    H(1,1) = x/r;  H(1,3) = y/r;
    H(2,1) = (1/y)/xy2;  H(2,3) = (-x/y^2)/xy2;
    
    Kk = Pkk_1*H'*(H*Pkk_1*H'+Rk)^-1;       %计算增益
    x_hat = x_forecast+Kk*(Z(k,:)'-y_yuce);      %校正
    Pk = (eye(4)-Kk*H)*Pkk_1;
    X_est(k,:) = x_hat;
end
%% 
figure, hold on, grid on;
plot(X(:,1),X(:,3),'-b');
plot(Z(:,1).*sin(Z(:,2)*pi/180), Z(:,1).*cos(Z(:,2)*pi/180));
plot(X_est(:,1),X_est(:,3), 'r');
xlabel('X'); 
ylabel('Y'); 
title('EKF simulation');
legend('real', 'measurement', 'ekf estimated');
axis([-5,230,290,530]);

上例代码的效果图示:

在这里插入图片描述
可以看出一开始收敛的不快,下面一个代码完美解决了该问题
这里附上一个完整的matlab代码,效果超好。

在这里插入图片描述

C++示例

飞机高度demo1

假设一架飞机以恒定水平速度飞行(高度不变),地面上有一个雷达可以发射电磁波测量飞机到雷达的距离 r r r

在这里插入图片描述

从图中可以看出,有如下关系:
θ = a r c t a n ( y x ) r 2 = x 2 + y 2 \theta=arctan(\frac{y}{x})\\r^2=x^2+y^2 θ=arctan(xy)r2=x2+y2

我们想知道某一时刻飞机的水平位置和垂直高度,以水平位置、水平速度、垂直高度作为状态变量:
x = ( distance velocity altitude ) = ( x x ˙ y ) \mathbf{\textbf{x}}=\left(\begin{array}{c}\text{distance} \\\text{velocity} \\\text{altitude}\end{array}\right)=\left(\begin{array}{c}x \\\dot{x} \\y\end{array}\right) x=distancevelocityaltitude=xx˙y
则观测值与状态变量之间的关系为: h ( x ^ ) = x 2 + y 2 h\left(\hat{x}\right)=\sqrt{x^2+y^2} h(x^)=x2+y2
,可以看出这是一个非线性的表达式。对于这个问题来说,观测方程的雅克比矩阵为: J H = [ ∂ h ∂ x ∂ h ∂ x ˙ ∂ h ∂ y   ] J_H=\left[\frac{\partial h}{\partial x}\quad\frac{\partial h}{\partial \dot{x}}\quad\frac{\partial h}{\partial y}\text{ }\right] JH=[xhx˙hyh ],即
J H = [ x x 2 + y 2 0 y x 2 + y 2 ] J_H=\left[\frac{x}{\sqrt{x^2+y^2}} \quad 0 \quad \frac{y}{\sqrt{x^2+y^2}}\right] JH=[x2+y2
x
0x2+y2
y
]

状态转移方程的雅克比矩阵为:
J A = ( 1 Δ 0 0 1 0 0 0 1 ) J_A=\left( \begin{array}{c} 1 & \Delta & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end{array} \right) JA=100Δ10001
得到上述矩阵后我们就可以设定初值和噪声,然后根据流程图中的步骤进行迭代计算。

C++代码

代码

飞机高度demo2

飞机在2D空间中飞行,其中x轴是飞机行进的距离,y轴是飞机的高度。该系统可以由以下连续方程表示:

在这里插入图片描述

其中 m m m是飞机的重量(1000千克)

b x b_ {x} bx是阻力系数(0.35 N /平方米/秒²)

p p p是提升力(3.92 N /平方米/秒²)

g g g是重力加速度(9.8米/秒²)

u u u输入的电机的推力

在这里插入图片描述
计算雅各比矩阵:

在这里插入图片描述

即:

在这里插入图片描述

设置状态向量的初始估计之后,设置代表状态向量估计误差的协方差的协方差矩阵P。然后,设置协方差Q和R,分别代表过程噪声和测量噪声的协方差矩阵。

在这里插入图片描述

C++代码

代码

EKF的不足

EKF存在的主要问题如下:

  1. 运动及观察模型用泰勒级数的一阶或二阶展开近似成线性模型,忽略了高阶项,不可避免的引入线性误差,甚至导致滤波器发散。有如下误差补偿方法:

    泰勒近似使得状态预测必然存在误差:

    A) 补偿状态预测中的误差,附加“人为过程噪声”,即通过增大过程噪声协方差来实现这一点。
    B) 扩大状态预测协方差矩阵,用标量加权因子 φ > 1 φ>1 φ>1乘状态预测协方差矩阵
    C) 利用对角矩阵 φ = d i a g ( s q r t ( φ i ) ) , φ i > 1 φ=diag(sqrt(φ_i)), φ_i>1 φ=diag(sqrt(φi)),φi>1来乘以状态预测协方差矩阵

    其实无论增大过程噪声协方差还是状态预测协方差矩阵,都是为了增大kalman增益,即状态预测是不准的,我要减小一步状态预测在状态更新中的权重。

  2. 雅克比矩阵(一阶)及海塞矩阵(二阶)计算困难。二阶EKF的性能要好于一阶的,而二阶以上的性能相比于二阶并没有太大的提高,所以超过二阶以上的EKF一般不采用。但二阶EKF的性能虽好,但计算量大,一般情况下不用

为了解决这一问题,请参见下一期无损卡尔曼滤波~~

参考文献

由浅入深的扩展卡尔曼滤波器教程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/148835.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • idea DataGrip 使用图解教程[通俗易懂]

    自从使用上idea以后就没有使用过eclipse开发工具,现在有迷上了DataGrip下载地址https://www.jetbrains.com/datagrip/buy/#editio

  • 用户 不在 sudoers 文件中。此事将被报告。

    用户 不在 sudoers 文件中。此事将被报告。文章目录背景解决方案背景普通linux用户使用sudo命令执行只有root用户才可以执行的命令时出现了该错误,如下图示:简单说明一下操作。命令$ll/etc/sudoers表示查看文件的属性,属性包括有:文件拥有者、文件所属组以及其他用户组对该文件拥有的读写权限和文件的类型等,上图的/etc/sudoers文件表示拥有者和所属组都是root且只能读取,其他用户组的没有任何读写权限。命…

  • python自行实现支付宝证书签名&验签全流程[通俗易懂]

    python自行实现支付宝证书签名&验签全流程[通俗易懂]支付宝Pythonsdk只有密钥签名,没有证书签名,下面是本人自行实现签名全流程证书签名需要新加alipay_root_cert_sn和app_cert_sn两个参数,这两个参数需要解析支付宝根证书(alipay_root_cert_sn)和应用公钥证书(appCerPublicKey_”app_id”.crt)得到:defsn_string():root_file_li=open(alipayRootCert.crt’,’r’).read().split(‘\n\n’)

  • Android listView中的button点击事件[通俗易懂]

    Android listView中的button点击事件[通俗易懂]Android–listView中的button控件获取item的值在listview中的listitem设置事件响应,如果listitem中有button控件,这时候listitem就不会捕获到点击事件,而默认的是listitem中的button会捕获点击事件,这方面的介绍网上很多,我想大家应该很熟悉了,之前做项目开发的时候遇到了一个问题,就是如果我点击listitem中的button怎么才能这个button是在哪一个item中呢,换句话说,就是点击listitem中的button怎么获取该list

  • 逻辑漏洞之密码找回漏洞(semcms)「建议收藏」

    逻辑漏洞之密码找回漏洞(semcms)「建议收藏」目录什么是密码找回漏洞一般流程可能产生该漏洞的情况脑洞图1.用户凭证暴力破解2.返回凭证3.邮箱弱token4.用户凭证有效性5.重新绑定6.服务器验证7.用户身份验证8.找回步骤9.本地验证10.注入11.Token生成12.注册覆盖13.session覆盖演示暴破验证码找回密码更改id号修改admin密码靶场cms下载什么是密码找回漏洞利用漏洞修改他人帐号密码,甚至修改管理员的密码。一般流程1首先尝试正常找回密码流程,选择不同的找回方式,记录所有数据包2分析数据包,找到敏感部分3

  • ckeditor 在C#中使用

    ckeditor 在C#中使用

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号