8.卡尔曼滤波之平方根滤波


       上一篇文章,我们提到了卡尔曼滤波的发散问题,并说明了,导致卡尔曼滤波发散的原因一般有两种,一种是由于模型建立不够准确,导致的发散,另一种是计算过程由于累计误差效应,导致增益矩阵P失去对称性或正定性而造成的发散。
       而且,上一篇文章对第一种情况提出了一些解决措施,主要思路就是认为近期的观测量更可靠一些,并逐渐忘记之间的观测对滤波的影响,也就是衰减记忆法和限定记忆法。
       在这篇文章,我们讨论针对滤波器发散另一种原因可以采取的抑制措施。这里先介绍一种,也就是平方根滤波。不过在介绍这种滤波之前,我们需要先介绍一种对滤波器的处理方法:序贯处理。

一. 序贯处理

       先解释一下为什么要有序贯处理。还记得卡尔曼滤波的基本方程吧。当中求解增益矩阵的那个方程长这个样子: K k = P k / k − 1 H k T ( H k P k / k − 1 H k T + R k ) − 1 K_k=P_{k/k-1}H_k^T(H_kP_{k/k-1}H_k^T+R_k)^{-1} Kk=Pk/k1HkT(HkPk/k1HkT+Rk)1
       里面涉及了矩阵求逆的计算,要知道矩阵求逆的计算量是相当大的,观察这个方程,当 Z k Z_k Zk的维数很大时,矩阵求逆的计算量会极具增加,一般来讲,求逆的计算量与矩阵阶数的三次方成正比。而序贯处理就可以理解将高阶矩阵求逆转化为低阶矩阵求逆的算法。
       当然,这是有条件的。序贯处理的条件是观测量 Z k Z_k Zk的方差矩阵 R k R_k Rk是对角矩阵。而这一条件在几乎绝大多数情况下卡尔曼滤波都是满足的。
       下面可以说明一下什么是序贯处理了。首先想一下,为什么绝大多数系统的 R k R_k Rk是对角矩阵呢,那是因为 Z k Z_k Zk里的量测值之间都是不相关的。那么好了,如果我们把每个量测值单独看成一次量测,那么,对应的 K k = P k / k − 1 H k T ( H k P k / k − 1 H k T + R k ) − 1 K_k=P_{k/k-1}H_k^T(H_kP_{k/k-1}H_k^T+R_k)^{-1} Kk=Pk/k1HkT(HkPk/k1HkT+Rk)1这个方程里的求逆就会变成除法,这样不就避免了高阶矩阵求逆了吗。就是这个道理。于是我们就有了下面这套算法。
       先定义量测向量 Z k Z_k Zk是个r维的向量, Z k i Z_k^i Zki是它的第i个量测值, H k i H_k^i Hki H k H_k Hk的第i行, R k i R_k^i Rki Z k i Z_k^i Zki的方差。
K k i = P k i − 1 H k i T ( H k i P k i − 1 H k i T + R k i ) − 1 K_k^i=P_k^{i-1}H_k^{iT}(H_k^iP_k^{i-1}H_k^{iT}+R_k^i)^{-1} Kki=Pki1HkiT(HkiPki1HkiT+Rki)1 X ^ k i = X ^ k i − 1 + K k i ( Z k i − H k i X ^ k i − 1 ) \hat X_k^i=\hat X_k^{i-1}+K_k^i(Z_k^i-H_k^i\hat X_k^{i-1}) X^ki=X^ki1+Kki(ZkiHkiX^ki1) P k i = ( I − K k i H k i ) P k i − 1 P_k^i=(I-K_k^iH_k^i)P_k^{i-1} Pki=(IKkiHki)Pki1
       当然, i = 1 , 2 , . . . r i=1,2,...r i=1,2,...r。而且 X ^ k 0 = Φ k , k − 1 X ^ k − 1 \hat X_k^0=\Phi_{k,k-1}\hat X_{k-1} X^k0=Φk,k1X^k1 P k 0 = P k / k − 1 P_k^0=P_{k/k-1} Pk0=Pk/k1
       看到了吧,这套算法当中矩阵求逆其实是除法,因为那是一个标量。当然这套算法是有代价的,代价就是把每个滤波周期又细分成了r个滤波周期。但是当量测向量的维数比较长的时候,这种处理对降低计算量的效果是十分明显的。而如果量测向量维数很短,那也就没必要这么处理了。

二. 平方根滤波

       先解释一下为什么在介绍平方根滤波之前要介绍序贯处理。这是没办法的事,因为实用的平方根滤波是假设量测量是标量形式的。所以,对于矢量形式的量测,需要利用序贯处理,对每个量测值进行处理才能实现这套算法。
       为啥平方根滤波是针对矩阵计算累计误差导致非负定有效果呢?先来理解一下,为啥卡尔曼滤波方程的方差矩阵计算过程会有累计误差吧。还记得P阵的定义吧,它是状态量X的方差矩阵,描述状态量X的精度的。而我们知道,状态量X里面可以包含各种量,有的精度高些,有的精度低些,可能对于X中的某一个元素,差个100到200都不算大,可对于X中的另外一个元素,差个0.001都算是大的。在这种情况下,描述X精度的P阵内部就可能导致元素之间的数量级差别非常大。这种矩阵有一个名称,叫做病态矩阵。通过计算机对病态矩阵进行处理,就极可能由于舍入等因素导致的误差会越来越大。
       有什么办法没有呢。其实根治的办法没有,不过有办法可以减轻病态矩阵病的程度。就是开平方。其实道理也很简单,比如10000和0.0001之间数量级差8个,但是开平方后,100和0.01的数量级就只差4个了。数量级只差越小,舍入误差影响就会越小。这就是平方根滤波的思想来源。
       所以,我们需要对卡尔曼滤波方程种的 P k P_k Pk阵和 P k / k − 1 P_{k/k-1} Pk/k1阵进行开平方。一个数的开平方好办,矩阵的开平方是怎么回事?定义是这样的,拿 P k P_k Pk为例,如果 P k P_k Pk的平方根是矩阵 Δ k \Delta_k Δk,那么 P k P_k Pk就可以写成 P k = Δ k Δ k T P_k=\Delta_k\Delta_k^T Pk=ΔkΔkT。而且,当 P k P_k Pk可以写成这种形式的时候, P k P_k Pk一定是非负定的,就像一个数的平方一定不小于零是一个道理。
       而且,矩阵理论中有一条定理,任何矩阵,如果是正定的,那么它一定可以分解成两个三角矩阵的乘积,这两个三角矩阵互为转置。也就是说对于 P k = Δ k Δ k T P_k=\Delta_k\Delta_k^T Pk=ΔkΔkT Δ k \Delta_k Δk一定可以写成下三角矩阵的形式。于是,对 P k P_k Pk矩阵开平方的问题,就变成了对它进行三角分解的问题了。这种矩阵分解算法很多人都研究过,最常用的是乔莱斯基分解法。有机会我把这些通用算法单独写一篇文章来介绍,总之这里,大家记住: P k P_k Pk可以分解成 Δ k Δ k T \Delta_k\Delta_k^T ΔkΔkT,而 Δ k \Delta_k Δk是一个下三角矩阵。同理, P k / k − 1 = Δ k / k − 1 Δ k / k − 1 T P_{k/k-1}=\Delta_{k/k-1}\Delta_{k/k-1}^T Pk/k1=Δk/k1Δk/k1T,这里的 Δ k / k − 1 \Delta_{k/k-1} Δk/k1也是下三角矩阵。
       那么好了,我们的目的就是把卡尔曼滤波方程里的 P k P_k Pk Δ k \Delta_k Δk代替。也就是,我们不想知道 P k P_k Pk的递推方程了,而是想知道 Δ k \Delta_k Δk的递推方程是什么样的。这就要用到之前说的假设了,量测是标量。当量测是标量时: a k = Δ k / k − 1 T H k T a_k=\Delta_{k/k-1}^TH_k^T ak=Δk/k1THkT b k = ( a k T a k + R k ) − 1 b_k=(a_k^Ta_k+R_k)^{-1} bk=(akTak+Rk)1 γ k = ( 1 + b k R k ) − 1 \gamma_k=(1+\sqrt {b_kR_k})^{-1} γk=(1+bkRk )1 K k = b k Δ k / k − 1 a k K_k=b_k\Delta_{k/k-1}a_k Kk=bkΔk/k1ak X ^ k = X ^ k / k − 1 + K k ( Z k − H k X ^ k / k − 1 ) \hat X_k=\hat X_{k/k-1}+K_k(Z_k-H_k\hat X_{k/k-1}) X^k=X^k/k1+Kk(ZkHkX^k/k1) Δ k = Δ k / k − 1 − γ k K k a k T \Delta_k=\Delta_{k/k-1}-\gamma_kK_ka_k^T Δk=Δk/k1γkKkakT
       注意哦,由于量测 Z k Z_k Zk是标量,所以上面方程里的 b k , γ k , R k b_k,\gamma_k,R_k bk,γk,Rk可都是标量。如果量测是矢量,就要用到序贯处理了。比如量测矢量是m维的,
       取 X ^ k 0 = X ^ k / k − 1 \hat X_k^0=\hat X_{k/k-1} X^k0=X^k/k1 Δ k 0 = Δ k / k − 1 \Delta_k^0=\Delta_{k/k-1} Δk0=Δk/k1
       对于m维的量测,则有如下递推: a k j = ( H k j Δ k j − 1 ) T a_k^j=(H_k^j\Delta_k^{j-1})^T akj=(HkjΔkj1)T b k j = ( a k j T a k j + R k j ) − 1 b_k^j=(a_k^{jT}a_k^j+R_k^j)^{-1} bkj=(akjTakj+Rkj)1 γ k j = ( 1 + b k j R k j ) − 1 \gamma_k^j=(1+\sqrt {b_k^jR_k^j})^{-1} γkj=(1+bkjRkj )1 K k j = b k j Δ k / k − 1 j − 1 a k j K_k^j=b_k^j\Delta_{k/k-1}^{j-1}a_k^j Kkj=bkjΔk/k1j1akj X ^ k j = X ^ k j − 1 + K k j ( Z k j − H k j X ^ k j − 1 ) \hat X_k^j=\hat X_k^{j-1}+K_k^j(Z_k^j-H_k^j\hat X_k^{j-1}) X^kj=X^kj1+Kkj(ZkjHkjX^kj1) Δ k j = Δ k j − 1 − γ k j K k j a k j T \Delta_k^j=\Delta_k^{j-1}-\gamma_k^jK_k^ja_k^{jT} Δkj=Δkj1γkjKkjakjT j = 1 , 2 , . . . m j=1,2,...m j=1,2,...m
       当计算到 j = m j=m j=m X ^ k = X ^ k m \hat X_k=\hat X_k^m X^k=X^km Δ k = Δ k m \Delta_k=\Delta_k^m Δk=Δkm
       以上方程的获得都是基于卡尔曼滤波基本方程中的 P k = ( I − K k H k ) P k / k − 1 P_k=(I-K_kH_k)P_{k/k-1} Pk=(IKkHk)Pk/k1进行推导获得的,是卡尔曼滤波方程的量测更新部分,所以上面这些也叫做平方根滤波的量测更新步骤。
       来看这些方程,我们发现,只要知道 Δ k / k − 1 \Delta_{k/k-1} Δk/k1就可以计算 Δ k \Delta_k Δk,进而计算出 X ^ k \hat X_k X^k,就像卡尔曼滤波方程中,知道 P k / k − 1 P_{k/k-1} Pk/k1就可以知道 P k P_k Pk一样。
       但是 Δ k / k − 1 \Delta_{k/k-1} Δk/k1是怎么知道的呢?有同学说是把 P k / k − 1 P_{k/k-1} Pk/k1进行三角分解得到的。那 P k / k − 1 P_{k/k-1} Pk/k1又怎么才能知道呢。哦,根据卡尔曼滤波基本方程中的 P k / k − 1 = Φ k , k − 1 P k − 1 Φ k , k − 1 T + Γ k − 1 Q k − 1 Γ k − 1 T P_{k/k-1}=\Phi_{k,k-1}P_{k-1}\Phi_{k,k-1}^T+\Gamma_{k-1}Q_{k-1}\Gamma_{k-1}^T Pk/k1=Φk,k1Pk1Φk,k1T+Γk1Qk1Γk1T P k − 1 P_{k-1} Pk1计算得到,继续提问, P k − 1 P_{k-1} Pk1怎么知道的?由上一步平方根滤波中的 Δ k − 1 \Delta_{k-1} Δk1跟自己的转置相乘得到。大家有没有发现,我们转了一圈还是要计算 P k P_k Pk,因为下一步平方根滤波需要用。有没有方法可以直接从 Δ k − 1 \Delta_{k-1} Δk1计算到 Δ k / k − 1 \Delta_{k/k-1} Δk/k1的方法呢,就像从 P k − 1 P_{k-1} Pk1计算到 P k / k − 1 P_{k/k-1} Pk/k1一样?有的。这就是平方根滤波的时间更新步骤。
       我们需要构造一个矩阵A。 A = ( Δ k − 1 T Φ k , k − 1 T ( Γ k − 1 Q k − 1 1 2 ) ) ( n + l ) ∗ n A=\begin {pmatrix}\Delta_{k-1}^T\Phi_{k,k-1}^T\\(\Gamma_{k-1}Q_{k-1}^{\frac{1}2})\end {pmatrix}_{(n+l)*n} A=(Δk1TΦk,k1T(Γk1Qk121))(n+l)n
       这个A阵可不是方的哦。把这个A阵变换成上三角矩阵,也就是通过变换A阵变换成 ( D 0 ) ( n + l ) ∗ n \begin{pmatrix}D\\0\end{pmatrix}_{(n+l)*n} (D0)(n+l)n       D是上三角矩阵,则 Δ k / k − 1 T = D \Delta_{k/k-1}^T=D Δk/k1T=D,常用的变换方法有两种,Householder变换法或者改进的Gram-Schmidt(MGS)法。具体方法有机会讲,总之这里只需要明白,平方根的时间更新就是通过 Δ k − 1 \Delta_{k-1} Δk1计算出 Δ k / k − 1 \Delta_{k/k-1} Δk/k1
       重新审视上面这些公式,我们发现,已经看不到 P k P_k Pk P k / k − 1 P_{k/k-1} Pk/k1的影子了,全程都是这两个矩阵的平方根矩阵,也就是两个下三角矩阵在来回折腾。而如果 P k P_k Pk P k / k − 1 P_{k/k-1} Pk/k1是病的很严重的病态矩阵,那么 Δ k − 1 \Delta_{k-1} Δk1计算出 Δ k / k − 1 \Delta_{k/k-1} Δk/k1病的程度就明显减轻了很多,也就减少了由于计算舍入误差造成发散的可能了。
       上面这套平方根算法是基于下三角分解后的 Δ \Delta Δ进行的。当然也可以采用同样的思路使用上三角分解进行。有些文献中描述,采用下三角分解进行的平方根滤波叫做平方根滤波的Potter算法,而采用上三角分解的平方根滤波叫做平方根滤波的Carlson算法。其实本质没有区别的。

  • 23
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: 卡尔曼滤波(Kalman Filter)和平方根容积卡尔曼滤波(Square Root Cubature Kalman Filter)是常用的估计滤波算法,主要应用于状态估计和系统辨识问题。下面我将分别介绍其Matlab实验代码。 卡尔曼滤波的Matlab实验代码如下所示: ```matlab % 定义系统模型 A = [1 0.1; 0 1]; % 状态转移矩阵 B = [0.005; 0.1]; % 控制输入矩阵 H = [1 0]; % 观测矩阵 Q = [0.01 0; 0 0.01]; % 过程噪声协方差矩阵 R = 1; % 观测噪声方差 % 初始化滤波器状态 x_k = [0; 0]; % 状态向量 P_k = [1 0; 0 1]; % 状态协方差矩阵 % 初始化观测数据 y_k = [10; 8]; % 观测向量 % 迭代更新滤波器 for i = 1:length(y_k) % 预测步骤 x_k1 = A * x_k; P_k1 = A * P_k * A' + B * Q * B'; % 更新步骤 K_k = P_k1 * H' / (H * P_k1 * H' + R); x_k = x_k1 + K_k * (y_k(i) - H * x_k1); P_k = (eye(2) - K_k * H) * P_k1; end % 输出滤波结果 disp(x_k) ``` 平方根容积卡尔曼滤波的Matlab实验代码如下所示: ```matlab % 定义系统模型 A = [1 0.1; 0 1]; % 状态转移矩阵 B = [0.005; 0.1]; % 控制输入矩阵 H = [1 0]; % 观测矩阵 Q = [0.01 0; 0 0.01]; % 过程噪声协方差矩阵 R = 1; % 观测噪声方差 % 初始化滤波器状态 x_k = [0; 0]; % 状态向量 P_k = [1 0; 0 1]; % 状态协方差矩阵 % 初始化观测数据 y_k = [10; 8]; % 观测向量 % 迭代更新滤波器 for i = 1:length(y_k) % 预测步骤 x_k1 = A * x_k; P_k1 = A * P_k * A' + B * Q * B'; % 更新步骤 K_k = P_k1 * H' / (H * P_k1 * H' + R); x_k = x_k1 + K_k * (y_k(i) - H * x_k1); P_k = (eye(2) - K_k * H) * P_k1; % 平方根容积卡尔曼滤波的特殊步骤 [U, S, V] = svd(P_k); S_sqrt = sqrtm(S); P_k = U * S_sqrt * V'; end % 输出滤波结果 disp(x_k) ``` 这是一个简单的卡尔曼滤波平方根容积卡尔曼滤波的Matlab实验代码,用于对给定观测数据进行状态估计。根据实际需求,你可以对系统模型和参数进行相应的调整和修改。 ### 回答2: 卡尔曼滤波(Kalman Filter)和平方根容积卡尔曼滤波 (Square Root Cubature Kalman Filter)是两种常见的滤波算法。以下是一个使用MATLAB实现的简单示例代码。 卡尔曼滤波的MATLAB实验代码: ```matlab % 定义系统模型 A = [1 1; 0 1]; % 状态转移矩阵 B = [0.5; 1]; % 输入转移矩阵 C = [1 0]; % 观测矩阵 Q = [0.01 0; 0 0.01]; % 状态过程噪声协方差矩阵 R = 1; % 观测噪声协方差矩阵 % 初始化滤波器 x = [0; 0]; % 状态估计初始值 P = [1 0; 0 1]; % 状态估计误差协方差矩阵 % 定义观测数据 Y = [1.2; 2.1; 3.7; 4.3]; % 观测数据 % 开始滤波 for i = 1:length(Y) % 预测状态 x = A * x + B * 0; % 无输入 P = A * P * A' + Q; % 更新状态 K = P * C' / (C * P * C' + R); x = x + K * (Y(i) - C * x); P = (eye(size(A)) - K * C) * P; % 输出状态估计值 disp(['第', num2str(i), '次观测的状态估计值为:']); disp(x); end ``` 平方根容积卡尔曼滤波的MATLAB实验代码: ```matlab % 定义系统模型 A = [1 1; 0 1]; % 状态转移矩阵 B = [0.5; 1]; % 输入转移矩阵 C = [1 0]; % 观测矩阵 Q = [0.01 0; 0 0.01]; % 状态过程噪声协方差矩阵 R = 1; % 观测噪声协方差矩阵 % 初始化滤波器 x = [0; 0]; % 状态估计初始值 P = [1 0; 0 1]; % 状态估计误差协方差矩阵 % 定义观测数据 Y = [1.2; 2.1; 3.7; 4.3]; % 观测数据 % 开始滤波 for i = 1:length(Y) % 预测状态 x = A * x + B * 0; % 无输入 P = sqrtm(A * P * A' + Q); % 更新状态 G = P * C' / (C * P * C' + R); x = x + G * (Y(i) - C * x); P = sqrtm((eye(size(A)) - G * C) * P * (eye(size(A)) - G * C)' + G * R * G'); % 输出状态估计值 disp(['第', num2str(i), '次观测的状态估计值为:']); disp(x); end ``` 以上是一个简单的卡尔曼滤波平方根容积卡尔曼滤波的MATLAB实验代码示例。这些代码用于实现两种滤波算法,并使用预定义的系统模型和观测数据进行状态估计。实际应用中,需要根据具体问题进行参数调整和适应性修改。 ### 回答3: 卡尔曼滤波(Kalman Filter)和平方根容积卡尔曼滤波(Square Root Cubature Kalman Filter)都是常用于状态估计的滤波算法卡尔曼滤波是一种最优线性估计算法,基于状态空间模型,在系统的观测和模型误差服从高斯分布的条件下,通过使用先验信息和测量更新,来估计系统的状态。卡尔曼滤波的基本原理是通过不断地对先验状态和先验协方差进行更新和修正,得到最优估计。 平方根容积卡尔曼滤波是对传统卡尔曼滤波的改进算法之一,主要用于解决非线性系统的状态估计问题。相比于传统的卡尔曼滤波平方根容积卡尔曼滤波使用了卡尔曼滤波的根协方差表示,通过对根协方差进行传输和修正,避免了传统卡尔曼滤波中协方差矩阵计算的数值不稳定问题,提供了更好的数值精度和计算效率。 以下是MATLAB实验代码的伪代码示例: ``` % 卡尔曼滤波 % 初始化状态和观测噪声的协方差矩阵 Q = ... % 状态噪声的协方差矩阵 R = ... % 观测噪声的协方差矩阵 % 初始化状态和协方差矩阵 x = ... % 状态向量 P = ... % 状态协方差矩阵 for k = 1:N % 预测步骤 x_hat = ... % 先验状态估计 P_hat = ... % 先验协方差估计 % 更新步骤 K = P_hat * C' / (C * P_hat * C' + R) % 卡尔曼增益 x = x_hat + K * (z - C * x_hat) % 后验状态估计 P = (eye(size(K,1)) - K * C) * P_hat % 后验协方差估计 end % 平方根容积卡尔曼滤波 % 初始化状态和观测噪声的协方差矩阵 Q = ... % 状态噪声的协方差矩阵 R = ... % 观测噪声的协方差矩阵 % 初始化状态和根协方差矩阵 x = ... % 状态向量 S = ... % 根协方差矩阵 for k = 1:N % 预测步骤 x_hat = ... % 先验状态估计 S_hat = ... % 先验根协方差估计 % 更新步骤 y = z - H * x_hat % 观测残差 K = S_hat * H' / (H * S_hat * H' + R) % 平方根卡尔曼增益 x = x_hat + K * y % 后验状态估计 S = (eye(size(K,1)) - K * H) * S_hat % 后验根协方差估计 end ``` 注意,在实际应用中,需要根据具体问题的状态模型和观测模型进行相应的参数设置和代码实现。以上代码仅为伪代码示例,具体的实现方式可能有所不同。可根据实际需求和问题进行算法选择和代码编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值