在EKF中我们使用泰勒级数近似非线性函数是为了利用Gaussian的线性性质进行期望(均值)和方差的传递,但在线性化过程中,由于线性化点的选择和高阶项的舍弃,将不可避免的存在线性化误差。如果我们能找到一种方法直接获得非线性变换之后的期望和方差,就可以避免由线性化带来的算法误差,而无迹变换(Unscented Transform,UT)正是这样一种方法。
无迹变换的基本思路是通过确定性地选取一定数量的Sigma点,这些Sigma点的分布和原分布式一致的(即期望和方差相同),采用这一类策略的滤波器通常成为Sigma点Kalman滤波器(Sigma Point Kalman Filter,SPKF)。随后将这些Sigma点逐个按照非线性模型传播,再统计传播之后所有Sigma点的分布以获得非线性变换之后的分布。所以从本质上来说,UT是一种蒙特卡洛估计(Monte Carlo estimation),但其采用策略是确定性,而另一种蒙特卡洛估计方法——粒子滤波(Partical Filter),其采样策略是随机性。
对于Gaussian分布 x ∼ N ( μ , P ) \bm{x}\sim N(\bm{\mu},\bm{P}) x∼N(μ,P)和非线性函数 y = g ( x ) \bm{y}=g(\bm{x}) y=g(x),UT的步骤如下:
其中 [ ⋅ ] i [\cdot]_i [⋅]i表示矩阵的第 i i i列,缩放参数 λ \lambda λ由算法由UT变换参数 α \alpha α和 κ \kappa κ决定:
λ = α 2 ( n + κ ) − n (2) \lambda=\alpha^2\left(n+\kappa\right)-n \tag{2} λ=α2(n+κ)−n(2)
将1中构建的 2 n + 1 2n+1 2n+1个Sigma点按照非线性函数 g g g进行传播以获得传播后的Sigma点:
y ( i ) = g ( x ( i ) ) (3) y^{(i)}=g(x^{(i)}) \tag{3} y(i)=g(x(i))(3)
统计传播后的Sigma点的均值和方差:
E [ g ( x ) ] ≃ μ U = ∑ i = 0 2 n w i ( m ) y ( i ) C o v [ g ( x ) ] ≃ Σ U = ∑ i = 0 2 n w i ( s ) ( y ( i ) − μ U ) ( y ( i ) − μ U ) T (4) \begin{aligned} E\left[g(\bm{x})\right]&\simeq\bm{\mu}_U=\sum\limits_{i=0}^{2n}w_i^{(m)}y^{(i)}\\ Cov\left[g(\bm{x})\right]&\simeq\bm{\Sigma}_U=\sum\limits_{i=0}^{2n}w_i^{(s)}(y^{(i)}-\bm{\mu}_U)(y^{(i)}-\bm{\mu}_U)^T \end{aligned} \tag{4} E[g(x)]Cov[g(x)]≃μU=i=0∑2nwi(m)y(i)≃ΣU=i=0∑2nwi(s)(y(i)−μU)(y(i)−μU)T(4)
其中权值 w i ( s ) w_i^{(s)} wi(s)和 w i ( s ) w_i^{(s)} wi(s)按照如下方法获取:
w 0 ( m ) = λ n + λ w 0 ( s ) = λ n + λ + ( 1 − α 2 + β ) w i ( m ) = 1 2 ( n + λ ) w i ( s ) = 1 2 ( n + λ ) (5) \begin{aligned} w_0^{(m)}&=\frac{\lambda}{n+\lambda}\\ w_0^{(s)}&=\frac{\lambda}{n+\lambda}+\left(1-\alpha^2+\beta\right)\\ w_i^{(m)}&=\frac{1}{2(n+\lambda)}\\ w_i^{(s)}&=\frac{1}{2(n+\lambda)} \end{aligned} \tag{5} w0(m)w0(s)wi(m)wi(s)=n+λλ=n+λλ+(1−α2+β)=2(n+λ)1=2(n+λ)1(5)
其中 β \beta β亦为UT变换的第三个参数。
可以看出,使用UT不需要对函数 g ( x ) g(\bm{x}) g(x)进行任何的线性化,直接通过一定数量的例子对传播后的高斯分布进行近似,可有效避免在强线性化条件下一阶线性化过程带来的误差。
在了解UT的原理之后,我们很容易就可写出UKF的变换过程。与EKF的推导一样,根据噪声的特性(加性还是非加性),UKF的形式略有不同,由于加性噪声模型在应用中最为广泛,这里我们首先来看加性噪声的情况。
加性噪声下的系统状态空间方程为:
{ x k + 1 = f ( x k ) + w k , x k ∼ N ( μ k , Σ k ) , w k ∼ N ( 0 , Q k ) y k + 1 = h ( x k + 1 ) + v k , v k ∼ N ( 0 , R k + 1 ) (6) \left\{ \begin{aligned} \bm{x}_{k+1}&=f(\bm{x}_k)+\bm{w}_k,\quad\bm{x}_{k}\sim\mathcal{N}(\bm{\mu}_k,\bm{\Sigma}_{k}),\quad\bm{w}_k\sim\mathcal{N}(\bm{0},\bm{Q}_k)\\ \bm{y}_{k+1}&=h(\bm{x}_{k+1})+\bm{v}_k,\quad\bm{v}_k\sim\mathcal{N}(\bm{0},\bm{R}_{k+1}) \end{aligned} \right. \tag{6} {xk+1yk+1=f(xk)+wk,xk∼N(μk,Σk),wk∼N(0,Qk)=h(xk+1)+vk,vk∼N(0,Rk+1)(6)
由于系统的状态传播函数 f ( x ) f(\bm{x}) f(x)和量测函数 h ( x ) h(\bm{x}) h(x)均为非线性,我们可以分别对其进行两次UT操作。
构造Sigma点:
x k ( 0 ) = μ k x k ( i ) = μ k + n + λ [ P k ] i x k ( i + n ) = μ k − n + λ [ P k ] i , i = 1 , 2 , ⋯ , n (7) \begin{aligned} \bm{x}^{(0)}_{k}&=\bm{\mu}_k\\ \bm{x}^{(i)}_{k}&=\bm{\mu}_k+\sqrt{n+\lambda}[\sqrt{\bm{P}_k}]_i\\ \bm{x}^{(i+n)}_{k}&=\bm{\mu}_k-\sqrt{n+\lambda}[\sqrt{\bm{P}_k}]_i,\quad i=1,2,\cdots,n\\ \end{aligned} \tag{7} xk(0)xk(i)xk(i+n)=μk=μk+n+λ[Pk]i=μk−n+λ[Pk]i,i=1,2,⋯,n(7)
基于状态传播函数递推Sigma点:
x ^ k + 1 ( i ) = f ( x k ( i ) ) , i = 0 , 1 , ⋯ , 2 n \hat{\bm{x}}_{k+1}^{(i)}=f(\bm{x}_k^{(i)}),\quad i=0,1,\cdots,2n x^k+1(i)=f(xk(i)),i=0,1,⋯,2n
统计传播后Sigma点的均值和方差:
μ ^ k + 1 = ∑ i = 0 2 n w i ( m ) x ^ k + 1 ( i ) Σ ^ k + 1 = ∑ i = 0 2 n w i ( s ) ( x ^ k + 1 ( i ) − μ ^ k + 1 ) ( x ^ k + 1 ( i ) − μ ^ k + 1 ) T + Q k (8) \begin{aligned} \hat{\bm{\mu}}_{k+1}&=\sum\limits_{i=0}^{2n}w_i^{(m)}\hat{\bm{x}}_{k+1}^{(i)}\\ \hat{\bm{\Sigma}}_{k+1}&=\sum\limits_{i=0}^{2n}w_i^{(s)}(\hat{\bm{x}}_{k+1}^{(i)}-\hat{\bm{\mu}}_{k+1})(\hat{\bm{x}}_{k+1}^{(i)}-\hat{\bm{\mu}}_{k+1})^T+\bm{Q}_k \end{aligned} \tag{8} μ^k+1Σ^k+1=i=0∑2nwi(m)x^k+1(i)=i=0∑2nwi(s)(x^k+1(i)−μ^k+1)(x^k+1(i)−μ^k+1)T+Qk(8)
可以看出,由于加性噪声的影响,在统计变换后的均值和方差时,需要加上对应的均值和噪声项(此处噪声均值为0)。
构造Sigma点:
x ^ k + 1 ( 0 ) = μ ^ k + 1 x ^ k + 1 ( i ) = μ ^ k + 1 + n + λ [ P k ] i x ^ k + 1 ( i + n ) = μ ^ k + 1 − n + λ [ P k ] i , i = 1 , 2 , ⋯ , n (9) \begin{aligned} \hat{\bm{x}}^{(0)}_{k+1}&=\hat{\bm{\mu}}_{k+1}\\ \hat{\bm{x}}^{(i)}_{k+1}&=\hat{\bm{\mu}}_{k+1}+\sqrt{n+\lambda}[\sqrt{\bm{P}_k}]_i\\ \hat{\bm{x}}^{(i+n)}_{k+1}&=\hat{\bm{\mu}}_{k+1}-\sqrt{n+\lambda}[\sqrt{\bm{P}_k}]_i,\quad i=1,2,\cdots,n\\ \end{aligned} \tag{9} x^k+1(0)x^k+1(i)x^k+1(i+n)=μ^k+1=μ^k+1+n+λ[Pk]i=μ^k+1−n+λ[Pk]i,i=1,2,⋯,n(9)
基于状态传播函数递推Sigma点:
x ‾ k + 1 ( i ) = h ( x ^ k + 1 ( i ) ) , i = 0 , 1 , ⋯ , 2 n \overline{\bm{x}}_{k+1}^{(i)}=h(\hat{\bm{x}}_{k+1}^{(i)}),\quad i=0,1,\cdots,2n xk+1(i)=h(x^k+1(i)),i=0,1,⋯,2n
统计传播后Sigma点的均值,方差以及互协方差:
μ ‾ k + 1 = ∑ i = 0 2 n w i ( m ) x ‾ k + 1 ( i ) Σ ‾ k + 1 = ∑ i = 0 2 n w i ( s ) ( x ‾ k + 1 ( i ) − μ ‾ k + 1 ) ( x ‾ k + 1 ( i ) − μ ‾ k + 1 ) T + R k + 1 C k + 1 = ∑ i = 0 2 n w i ( s ) ( x ^ k + 1 ( i ) − μ ^ k + 1 ) ( x ‾ k + 1 ( i ) − μ ‾ k + 1 ) T (10) \begin{aligned} \overline{\bm{\mu}}_{k+1}&=\sum\limits_{i=0}^{2n}w_i^{(m)}\overline{\bm{x}}_{k+1}^{(i)}\\ \overline{\bm{\Sigma}}_{k+1}&=\sum\limits_{i=0}^{2n}w_i^{(s)}(\overline{\bm{x}}_{k+1}^{(i)}-\overline{\bm{\mu}}_{k+1})(\overline{\bm{x}}_{k+1}^{(i)}-\overline{\bm{\mu}}_{k+1})^T+\bm{R}_{k+1}\\ \bm{C}_{k+1}&=\sum\limits_{i=0}^{2n}w_i^{(s)}(\hat{\bm{x}}_{k+1}^{(i)}-\hat{\bm{\mu}}_{k+1})(\overline{\bm{x}}_{k+1}^{(i)}-\overline{\bm{\mu}}_{k+1})^T \end{aligned} \tag{10} μk+1Σk+1Ck+1=i=0∑2nwi(m)xk+1(i)=i=0∑2nwi(s)(xk+1(i)−μk+1)(xk+1(i)−μk+1)T+Rk+1=i=0∑2nwi(s)(x^k+1(i)−μ^k+1)(xk+1(i)−μk+1)T(10)
回顾Kalman滤波的推导过程可以发现,式(10)同样相当于给出了如下形式的联合分布:
[ x k + 1 z k + 1 ] ∼ N ( [ μ ^ k + 1 μ ‾ k + 1 ] , [ Σ ^ k + 1 C k + 1 C k + 1 T Σ ‾ k + 1 ] ) \begin{bmatrix} \bm{x}_{k+1} \\ \bm{z}_{k+1} \end{bmatrix}\sim\mathcal{N} \left(\begin{bmatrix} \hat{\bm{\mu}}_{k+1} \\ \overline{\bm{\mu}}_{k+1} \end{bmatrix}, \begin{bmatrix} \hat{\bm{\Sigma}}_{k+1} & \bm{C}_{k+1}\\ \bm{C}_{k+1}^T & \overline{\bm{\Sigma}}_{k+1} \end{bmatrix} \right) [xk+1zk+1]∼N([μ^k+1μk+1],[Σ^k+1Ck+1TCk+1Σk+1])
从联合分布 p ( x k + 1 , z k + 1 ) p(\bm{x}_{k+1},\bm{z}_{k+1}) p(xk+1,zk+1)中求解条件分布 p ( x k + 1 ∣ z k + 1 ) p(\bm{x}_{k+1}|\bm{z}_{k+1}) p(xk+1∣zk+1)则是我们再熟悉不过的了,利用高斯分布的联合分布->条件分布公式(参见Kalman滤波)有:
K k + 1 = C k + 1 Σ ‾ k + 1 − 1 μ ^ k + 1 = μ ^ k + 1 + K k + 1 [ z k + 1 − μ ‾ k + 1 ] Σ ^ k + 1 = Σ ^ k + 1 + C k + 1 Σ ‾ k + 1 − 1 C k + 1 T = C k + 1 Σ ‾ k + 1 − 1 Σ ‾ k + 1 Σ ‾ k + 1 − 1 C k + 1 T = K k + 1 Σ ‾ k + 1 K k + 1 T (11) \begin{aligned} \bm{K}_{k+1}&=\bm{C}_{k+1}\overline{\bm{\Sigma}}_{k+1}^{-1}\\ \hat{\bm{\mu}}_{k+1}& = \hat{\bm{\mu}}_{k+1} + \bm{K}_{k+1}\left[\bm{z}_{k+1} - \overline{\bm{\mu}}_{k+1}\right] \\ \hat{\bm{\Sigma}}_{k+1}&=\hat{\bm{\Sigma}}_{k+1}+\bm{C}_{k+1}\overline{\bm{\Sigma}}_{k+1}^{-1}\bm{C}_{k+1}^T=\bm{C}_{k+1}\overline{\bm{\Sigma}}_{k+1}^{-1}\overline{\bm{\Sigma}}_{k+1}\overline{\bm{\Sigma}}_{k+1}^{-1}\bm{C}_{k+1}^T\\ &=\bm{K}_{k+1}\overline{\bm{\Sigma}}_{k+1}\bm{K}_{k+1}^T \end{aligned} \tag{11} Kk+1μ^k+1Σ^k+1=Ck+1Σk+1−1=μ^k+1+Kk+1[zk+1−μk+1]=Σ^k+1+Ck+1Σk+1−1Ck+1T=Ck+1Σk+1−1Σk+1Σk+1−1Ck+1T=Kk+1Σk+1Kk+1T(11)
非加性噪声下的UKF算法相比加性噪声下的UKF更为简单,对于如下的非加性噪声模型:
{ x k + 1 = f ( x k , w k ) , x k ∼ N ( μ k , Σ k ) , w k ∼ N ( 0 , Q k ) y k + 1 = h ( x k + 1 , v k ) , v k ∼ N ( 0 , R k + 1 ) (12) \left\{ \begin{aligned} \bm{x}_{k+1}&=f(\bm{x}_k,\bm{w}_k),\quad\bm{x}_{k}\sim\mathcal{N}(\bm{\mu}_k,\bm{\Sigma}_{k}),\quad\bm{w}_k\sim\mathcal{N}(\bm{0},\bm{Q}_k)\\ \bm{y}_{k+1}&=h(\bm{x}_{k+1},\bm{v}_k),\quad\bm{v}_k\sim\mathcal{N}(\bm{0},\bm{R}_{k+1}) \end{aligned} \right. \tag{12} {xk+1yk+1=f(xk,wk),xk∼N(μk,Σk),wk∼N(0,Qk)=h(xk+1,vk),vk∼N(0,Rk+1)(12)
我们只需要做一个如下式所示简单的变换就可将其转化为无噪声问题,随后按照式(1)~式(5)进行更新即可。
x k ′ = [ x w k ] , Σ k ′ = [ Σ k Q k ] \bm{x}_k'=\begin{bmatrix}\bm{x}\\\bm{w}_k\end{bmatrix},\quad\bm{\Sigma}_k'=\begin{bmatrix}\bm{\Sigma}_k &\\ &\bm{Q}_k\end{bmatrix} xk′=[xwk],Σk′=[ΣkQk]
对于量测更新过程,我们同样可以如此简化,这里不再赘述。
这里我们来看一个简单的一维例子,假设我们需要随一个常值进行估计,系统的状态空间方程为:
{ x t + 1 = x t + w t z t + 1 = x t + 1 + v t + 1 \left\{ \begin{aligned} x_{t+1} &= x_{t}+w_{t}\\ z_{t+1} &= \sqrt{x_{t+1}} + v_{t+1} \end{aligned} \right. {xt+1zt+1=xt+wt=xt+1+vt+1
完整的代码参见github主页(Bayesian Filter),代码由一个UKF
基类及UKF_1D
派生类组成,Sigma Points的生成,状态及量测的传递均在基类实现如下:
void UKF::generateSigmaPoints(){
VecXd tmp = VecXd::Zero(x_dim_);
MatXd S_sqrt;
// Cholsky分解
S_sqrt = curSigma_.llt().matrixL();
// 生成Sigma Points
tmp = curMu_;
sPointsX_.emplace_back(tmp);
// 1 ~ n & n+1 ~ 2n
for(int i = 0; i < x_dim_; i++){
tmp = curMu_ + sqrt(x_dim_ + lambda_) * S_sqrt.col(i);
sPointsX_.emplace_back(tmp);
}
for(int i = 0; i < x_dim_; i++){
tmp = curMu_ - sqrt(x_dim_ + lambda_) * S_sqrt.col(i);
sPointsX_.emplace_back(tmp);
}
}
void UKF::oneStepPrediction(){
if(!flag_initiated_){
cerr << "Please call init() to initiate filter first !\n";
return;
}
// clear containers
sPointsX_.clear();
sPointsY_.clear();
// generate sigma points
generateSigmaPoints();
// propogate sigma points by f(x)
propagateFcn();
// compute predicted mean and covariance
curMu_ = calcMean(sPointsY_);
// cout << "MU_P: " << curMu_.transpose() << endl;
curSigma_ = calcCov(sPointsY_) + Q_;
}
void UKF::oneStepUpdate(VecXd &Z){
if(!flag_initiated_){
cerr << "Please call init() to initiate filter first !\n";
return;
}
// clear containers
sPointsX_.clear();
sPointsY_.clear();
// generate sigma points
generateSigmaPoints();
// propagate sigma points by h(x)
updateFcn();
// compute tmp predicted mean and covariance
VecXd M_tmp = calcMean(sPointsY_); // mu_k
MatXd S_tmp = calcCov(sPointsY_) + R_; // S_k
MatXd C_tmp = calcCrossCov(sPointsX_, sPointsY_); // C_k
// compute estimation state
MatXd K = C_tmp * S_tmp.inverse();
curMu_ += K * (Z - M_tmp);
curSigma_ -= K * S_tmp * K.transpose();
// cout << "MU_U: " << curMu_.transpose() << endl;
}
派生类UKF_1D
中则主要实现不同的状态传递和量测模型,针对本例,对应的函数如下:
namespace myFilter{
UKF_1D::UKF_1D(double alpha, double beta, double kappa){
alpha_ = alpha;
beta_ = beta;
kappa_ = kappa;
}
void UKF_1D::propagateFcn(){
VecXd tmp = VecXd::Zero(x_dim_);
for(auto it : sPointsX_){
tmp = it;
sPointsY_.emplace_back(tmp);
}
}
void UKF_1D::updateFcn(){
VecXd tmp = VecXd::Zero(x_dim_);
for(auto it: sPointsX_){
tmp(0) = sqrt(it(0));
sPointsY_.emplace_back(tmp);
}
}
}
这里我们取 x x x的真值为 25 25 25,量测噪声 v t + 1 ∼ N ( 0 , 2.5 ) v_{t+1}\sim\mathcal{N}(0, 2.5) vt+1∼N(0,2.5),共进行500次测量,得到的结果如下,其中蓝线为真值,绿线为量测值,红线为UKF的估计值: