UKF介绍
预测
- 首先得到初始sigma点,并计算权重w:
χ = sigma-function ( x , P ) W m , W c = weight-function ( n , p a r a m e t e r s ) \begin{aligned}\boldsymbol\chi &= \text{sigma-function}(\mathbf x, \mathbf P) \\ W^m, W^c &= \text{weight-function}(\mathtt{n, parameters})\end{aligned} χWm,Wc=sigma-function(x,P)=weight-function(n,parameters)
λ = α 2 ( n + κ ) − n W 0 m = λ n + λ W 0 c = λ n + λ + 1 − α 2 + β W i m = W i c = 1 2 ( n + λ ) i = 1..2 n \begin{aligned} \lambda&=\alpha^2(n+\kappa)-n \\ W^m_0 &= \frac{\lambda}{n+\lambda} \\ W^c_0 &= \frac{\lambda}{n+\lambda} + 1 -\alpha^2 + \beta \\ W^m_i = W^c_i &= \frac{1}{2(n+\lambda)}\;\;\;i=1..2n \end{aligned} λW0mW0cWim=Wic=α2(n+κ)−n=n+λλ=n+λλ+1−α2+β=2(n+λ)1i=1..2n
{ X 0 = μ X i = μ + [ ( n + λ ) Σ ] i , i = 1... n X i = μ − [ ( n + λ ) Σ ] i − n i = ( n + 1 ) . . . 2 n \begin{cases} \mathcal{X}_0 = \mu \\ \mathcal{X}_i = \mu + \left[\sqrt{(n+\lambda)\Sigma} \right]_i, & i=1...n \\ \mathcal{X}_i = \mu - \left[\sqrt{(n+\lambda)\Sigma}\right]_{i-n} & i=(n+1)...2n \end{cases} ⎩ ⎨ ⎧X0=μXi=μ+[(n+λ)Σ]i,Xi=μ−[(n+λ)Σ]i−ni=1...ni=(n+1)...2n
对于获取Sigma点中矩阵求根,使用便于计算的定义: Σ = S S T \Sigma = \mathbf{SS}^\mathsf T Σ=SST, S \mathbf{S} S即为 Σ \Sigma Σ的根,通常用scipy.linalg.cholesky()
计算,返回上三角矩阵,因此选用每1行为1个Sigma点.
代码:
# 初始化权重:
def calc_weight(n, alpha, beta, kappa):
lambda_ = alpha ** 2 * (n + kappa) - n
Wc = np.full(2 * n + 1, 1. / (2 * (n + lambda_))) # np.full 可以避免循环
Wm = np.full(2 * n + 1, 1. / (2 * (n + lambda_)))
Wc[0] = lambda_ / (n + lambda_) + (1. - alpha ** 2 + beta)
Wm[0] = lambda_ / (n + lambda_)
return Wc, Wm
# 获取Sigma点:
def get_sigma_pnt(n, X, P, lambda_):
sigmas = np.zeros((2 * n + 1, n))
U = scipy.linalg.cholesky((n + lambda_) * P) # sqrt
sigmas[0] = X
for k in range(n):
sigmas[k + 1] = X + U[k]
sigmas[n + k + 1] = X - U[k]
- 计算先验预测: UT变换
Y = f ( χ , Δ t ) x ˉ = ∑ i = 0 2 n w i m Y i P ˉ = ∑ i = 0 2 n w i c ( Y i − x ˉ ) ( Y i − x ˉ ) T + Q \begin{aligned} \boldsymbol{\mathcal{Y}} = f(\boldsymbol{\chi}, \Delta t)\\ \mathbf{\bar x} &= \sum_{i=0}^{2n} w^m_i\boldsymbol{\mathcal Y}_i\\ \mathbf{\bar P} &= \sum_{i=0}^{2n} w^c_i({\boldsymbol{\mathcal Y}_i - \mathbf{\bar x})(\boldsymbol{\mathcal Y}_i-\mathbf{\bar x})^\mathsf{T}} + \mathbf Q \end{aligned} Y=f(χ,Δt)xˉPˉ=i=0∑2nwimYi=i=0∑2nwic(Yi−xˉ)(Yi−xˉ)T+Q
代码:
def ukf_predict(Wm, Wc, sigmas, Q): # ukf的预测也就是UT变换
# 状态预测:
x = np.dot(Wm, sigmas) # sigmas应该是传参前投影
# 协方差预测
kmax, n = sigmas.shape
P = np.zeros((n, n))
for k in range(kmax):
y = sigmas[k] - x
P += Wc[k] * np.outer(y, y) # numpy不区分一维矩阵的转置,所以调用此函数
P += Q
return x, P
def sigma_project(sigmas, fx, dt): # get的sigma点集,需要投影到的空间函数,dt
sigmas_f = sigmas
for i in sigmas.shape[0]:
sigmas_f[i] = fx(sigmas[i], dt) # 可能需要改
return sigmas_f
KF与UKF先验预测对比:
Kalman
Unscented
Y
=
f
(
χ
)
x
ˉ
=
F
x
x
ˉ
=
∑
w
m
Y
P
ˉ
=
F
P
F
T
+
Q
P
ˉ
=
∑
w
c
(
Y
−
x
ˉ
)
(
Y
−
x
ˉ
)
T
+
Q
\begin{array}{l|l} \text{Kalman} & \text{Unscented} \\ \hline & \boldsymbol{\mathcal Y} = f(\boldsymbol\chi) \\ \mathbf{\bar x} = \mathbf{Fx} & \mathbf{\bar x} = \sum w^m\boldsymbol{\mathcal Y} \\ \mathbf{\bar P} = \mathbf{FPF}^\mathsf T + \mathbf Q & \mathbf{\bar P} = \sum w^c({\boldsymbol{\mathcal Y} - \mathbf{\bar x})(\boldsymbol{\mathcal Y} - \mathbf{\bar x})^\mathsf T}+\mathbf Q \end{array}
Kalmanxˉ=FxPˉ=FPFT+QUnscentedY=f(χ)xˉ=∑wmYPˉ=∑wc(Y−xˉ)(Y−xˉ)T+Q
更新
- 所有卡尔曼都是在测量空间更新,所以需要将预测Sigma点投影到测量空间: Z = h ( Y ) \boldsymbol{\mathcal{Z}} = h(\boldsymbol{\mathcal{Y}}) Z=h(Y) (调用sigma_project函数)
- 对于测量空间中的先验进行UT变换:(直接调用预测函数即可)
μ z , P z = U T ( Z , w m , w c , R ) μ z = ∑ i = 0 2 n w i m Z i P z = ∑ i = 0 2 n w i c ( Z i − μ z ) ( Z i − μ z ) T + R \begin{aligned} \boldsymbol\mu_z, \mathbf P_z &= UT(\boldsymbol{\mathcal Z}, w_m, w_c, \mathbf R) \\ \boldsymbol\mu_z &= \sum_{i=0}^{2n} w^m_i\boldsymbol{\mathcal Z}_i \\ \mathbf P_z &= \sum_{i=0}^{2n} w^c_i{(\boldsymbol{\mathcal Z}_i-\boldsymbol{\mu}_z)(\boldsymbol{\mathcal Z}_i-\boldsymbol{\mu}_z)^\mathsf T} + \mathbf R \end{aligned} μz,PzμzPz=UT(Z,wm,wc,R)=i=0∑2nwimZi=i=0∑2nwic(Zi−μz)(Zi−μz)T+R - 计算实际观测值与预测投影到观测空间的差值得到y(结合卡尔曼增益来更新预测):
y = z − μ z \mathbf y = \mathbf z - \boldsymbol\mu_z y=z−μz - 计算卡尔曼增益:(1. 状态与测量的协方差;2. 结合预测协方差得到增益)
P x z = ∑ i = 0 2 n w i c ( Y i − x ˉ ) ( Z i − μ z ) T \mathbf P_{xz} =\sum_{i=0}^{2n} w^c_i(\boldsymbol{\mathcal Y}_i-\mathbf{\bar x})(\boldsymbol{\mathcal Z}_i-\boldsymbol\mu_z)^\mathsf T Pxz=i=0∑2nwic(Yi−xˉ)(Zi−μz)T
卡尔曼增益:(其实就是状态置信度与测量空间置信度之比)
K = P x z P z − 1 \mathbf{K} = \mathbf P_{xz} \mathbf P_z^{-1} K=PxzPz−1 - 最后得到后验:
状态: x = x ˉ + K y ;方差: P = P ˉ − K P z K T 状态:\mathbf x = \bar{\mathbf x} + \mathbf{Ky};方差: \mathbf P = \mathbf{\bar P} - \mathbf{KP_z}\mathbf{K}^\mathsf{T} 状态:x=xˉ+Ky;方差:P=Pˉ−KPzKT
代码:
def ukf_update(sigmas_f, xp, Pp, hx, z, Wm, Wc, R, dt):
# 1 投影
sigmas_h = sigma_project(sigmas_f, hx, dt)
# 2 投影后的预测值进行UT变换
zp, Pz = ut_ukf_predict(sigmas_h, Wm, Wc, R)
# 3 求差值
y = z - zp
# 4 状态与测量的交叉方差 与 卡尔曼增益
Pxz = np.zeros((X_dim, Z_dim))
for i in range(sigmas_f.shape[0]):
Pxz += Wc[i] * np.outer(sigmas_f[i] - xp, sigmas_h[i] - zp)
K = np.dot(Pxz, np.linalg.inv(Pz)) # Kalman 增益
# 5 计算后验
x_post = xp + np.dot(K, y)
P_post = Pp - np.dot(K, Pz).dot(K.T)
return x_post, P_post
后验对比:
Kalman Filter
Unscented Kalman Filter
Y
=
f
(
χ
)
x
ˉ
=
F
x
x
ˉ
=
∑
w
m
Y
P
ˉ
=
F
P
F
T
+
Q
P
ˉ
=
∑
w
c
(
Y
−
x
ˉ
)
(
Y
−
x
ˉ
)
T
+
Q
Z
=
h
(
Y
)
μ
z
=
∑
w
m
Z
y
=
z
−
H
x
y
=
z
−
μ
z
S
=
H
P
ˉ
H
T
+
R
P
z
=
∑
w
c
(
Z
−
μ
z
)
(
Z
−
μ
z
)
T
+
R
K
=
P
ˉ
H
T
S
−
1
K
=
[
∑
w
c
(
Y
−
x
ˉ
)
(
Z
−
μ
z
)
T
]
P
z
−
1
x
=
x
ˉ
+
K
y
x
=
x
ˉ
+
K
y
P
=
(
I
−
K
H
)
P
ˉ
P
=
P
ˉ
−
K
P
z
K
T
\begin{array}{l|l} \textrm{Kalman Filter} & \textrm{Unscented Kalman Filter} \\ \hline & \boldsymbol{\mathcal Y} = f(\boldsymbol\chi) \\ \mathbf{\bar x} = \mathbf{Fx} & \mathbf{\bar x} = \sum w^m\boldsymbol{\mathcal Y} \\ \mathbf{\bar P} = \mathbf{FPF}^\mathsf T+\mathbf Q & \mathbf{\bar P} = \sum w^c({\boldsymbol{\mathcal Y} - \mathbf{\bar x})(\boldsymbol{\mathcal Y} - \mathbf{\bar x})^\mathsf T}+\mathbf Q \\ \hline & \boldsymbol{\mathcal Z} = h(\boldsymbol{\mathcal{Y}}) \\ & \boldsymbol\mu_z = \sum w^m\boldsymbol{\mathcal{Z}} \\ \mathbf y = \mathbf z - \mathbf{Hx} & \mathbf y = \mathbf z - \boldsymbol\mu_z \\ \mathbf S = \mathbf{H\bar PH}^\mathsf{T} + \mathbf R & \mathbf P_z = \sum w^c{(\boldsymbol{\mathcal Z}-\boldsymbol\mu_z)(\boldsymbol{\mathcal{Z}}-\boldsymbol\mu_z)^\mathsf{T}} + \mathbf R \\ \mathbf K = \mathbf{\bar PH}^\mathsf T \mathbf S^{-1} & \mathbf K = \left[\sum w^c(\boldsymbol{\mathcal Y}-\bar{\mathbf x})(\boldsymbol{\mathcal{Z}}-\boldsymbol\mu_z)^\mathsf{T}\right] \mathbf P_z^{-1} \\ \mathbf x = \mathbf{\bar x} + \mathbf{Ky} & \mathbf x = \mathbf{\bar x} + \mathbf{Ky}\\ \mathbf P = (\mathbf{I}-\mathbf{KH})\mathbf{\bar P} & \mathbf P = \bar{\mathbf P} - \mathbf{KP_z}\mathbf{K}^\mathsf{T} \end{array}
Kalman Filterxˉ=FxPˉ=FPFT+Qy=z−HxS=HPˉHT+RK=PˉHTS−1x=xˉ+KyP=(I−KH)PˉUnscented Kalman FilterY=f(χ)xˉ=∑wmYPˉ=∑wc(Y−xˉ)(Y−xˉ)T+QZ=h(Y)μz=∑wmZy=z−μzPz=∑wc(Z−μz)(Z−μz)T+RK=[∑wc(Y−xˉ)(Z−μz)T]Pz−1x=xˉ+KyP=Pˉ−KPzKT