自动驾驶面临的第一个问题:从哪里来,到哪里去?要解决这个问题,自动驾驶汽车首先需要准确的知道自己在地图上的位置。理所当然的我们可以想到通过GPS来进行定位,但获取GPS信号需要跟卫星进行通信,这就导致它的更新频率比较低,每次获取的位置是不连续的。换一个思路,我们高中都学过物理,当知道了一个小车的起点、速度和加速度之后,就可以通过直线运动公式预测接下来的位置,再结合小车偏向的角度、角速度和角加速度,完全可以通过运动学模型预测小车在二维道路上接下来的位置。此时我们有了两种定位的方式:直接通过GPS观测和间接通过运动模型预测,那该选择哪一种呢?小孩子才做选择,成年人表示我都要,这也是本节要介绍的——卡尔曼滤波。
卡尔曼滤波的应用非常广泛,尤其是在导航当中,而它的广泛应用主要是因为我们实际生活的世界中存在着大量的不确定性,当我们去描述一个系统的时候,不确定性主要体现在三个方面:① 不存在完美的数学模型,② 系统的扰动往往不可控也很难建模,③ 测量传感器本身存在误差。
让我们先从一个简单的例子开始。假如有一辆小车从原点出发,原点处有一个光学测距仪器,每一时刻测量光从原点传播到小车所需的时间,可以据此计算出小车与原点之间的距离。小车上还装了加速度传感器,为了简化任务,该传感器只会输出xxx方向上的加速度值,每隔Δt\Delta tΔt时间输出小车在ttt时刻的瞬时加速度。我们的最终目标是希望能够尽可能准确的估计小车在每一时刻的速度vtv_tvt和距离dtd_tdt。
理想情况下,我们当让希望加速度计的测量是完美的,那么直接对加速度做积分就能得到速度,对速度再做一次积分就得到距离。但是在实际应用中,无论什么样的传感器,它的输出都是带有噪声的,直接使用带有噪声的数据做计算会导致累计误差越来越大。
简化一下任务,假如我们现在只想要小车与原点的距离,并且只考虑光学测距仪,再假如小车在某一个位置保持静止,那么为了得到更加准确的距离,我们可以多次测距取平均值,或者用不同的光学测距仪进行测距。我们用zkz_kzk来表示测量的结果,下标kkk就表示第kkk次的测量结果。
如果我们采用同一仪器多次测量的方案,此时如果要估计真实结果,很自然的就可以想到取平均值,即z^k=1k(z1+z2+...+zk)\hat{z}_k = \frac{1}{k}(z_1+z_2+...+z_k)z^k=k1(z1+z2+...+zk),这里的^\hat{}^表示这是zkz_kzk的估计值,即期望。我们对z^k\hat{z}_kz^k的公式做一下变形:z^k=k−1k1k−1(z1+z2+...+zk−1)+1kzk=k−1kz^k−1+1kzk=z^k−1+1k(zk−z^k−1)\hat{z}_k =\frac{k-1}{k}\frac{1}{k-1}(z_1+z_2+...+z_{k-1}) + \frac{1}{k}z_k =\frac{k-1}{k}\hat{z}_{k-1} + \frac{1}{k}z_k =\hat{z}_{k-1}+\frac{1}{k}(z_{k} - \hat{z}_{k-1})z^k=kk−1k−11(z1+z2+...+zk−1)+k1zk=kk−1z^k−1+k1zk=z^k−1+k1(zk−z^k−1),即kkk时刻的估计值z^k\hat{z}_kz^k=上一次的估计值z^k−1\hat{z}_{k-1}z^k−1+系数1k\frac{1}{k}k1×(当前测量值zkz_kzk-上一次估计值z^k−1\hat{z}_{k-1}z^k−1)。
分析这个公式可以得出以下结论:
我们将上面的公式提炼一下,令系数为K\mathbf{K}K,则z^k=z^k−1+K(zk−z^k−1)\hat{z}_k = \hat{z}_{k-1} + \mathbf{K}(z_{k} - \hat{z}_{k-1})z^k=z^k−1+K(zk−z^k−1),这里的K\mathbf{K}K就是后面要推导的卡尔曼增益。为了初步理解卡尔曼增益,我们引入两个参数:
此时卡尔曼增益定义为Kk=eestimatek−1eestimatek−1+emeasurementk\mathbf{K}_k = \frac{e_{estimate_{k-1}}}{e_{estimate_{k-1}} + e_{measurement_{k}}}Kk=eestimatek−1+emeasurementkeestimatek−1(此公式后面给出推导过程)
讨论:
接下来我们看一个实际的例子,给出如下表所示的测量数据。因为光学测距仪本身就有误差,所以每次测量的结果也会不尽相同。由于我们使用同一个光学测距仪,其测量误差固定为emeasurement=2me_{measurement} = 2\text{m}emeasurement=2m,这个值一般由传感器厂商提供。
测量次数 | 测量值 |
---|---|
z1z_1z1 | 101m |
z2z_2z2 | 105m |
z3z_3z3 | 98m |
一个非常简单的用卡尔曼滤波解决这个问题的步骤:
由于卡尔曼滤波是通过递归的方式去估计一个非常接近真实值的估计值,因此开始的时候需要提供一个初始估计值x^0=95\hat{x}_{0} = 95x^0=95和初始估计值的误差eestimate0=5e_{estimate_0} = 5eestimate0=5。
kkk | zkz_kzk | emeasurementke_{measurement_k}emeasurementk | KkK_kKk | z^k\hat{z}_kz^k | eestimeateke_{estimeate_k}eestimeatek |
---|---|---|---|---|---|
0 | 100.00 | 5 | |||
1 | 103 | 2 | 0.71 | 102.13 | 1.45 |
2 | 101 | 2 | 0.42 | 101.65 | 0.84 |
3 | 98 | 2 | 0.3 | 100.56 | 0.59 |
可以发现,虽然测量值zkz_kzk是波动的,但是估计值z^k\hat{z}_kz^k逐渐收敛,经过多步迭代之后,估计值会越来越趋向于某一个值,我们就认为这个收敛的估计值跟真实值是比较接近的。这就是卡尔曼滤波的递归思想,随着测量数据的越来越多,更新的估计值也越来越靠近真实值。
卡尔曼滤波的公式推导需要一定的数学基础,本节主要讨论三个问题:数据融合、协方差矩阵和状态方程。
上面的最小例子中,我们通过光学测距仪多次测量取均值的方式得到了一个最优估计值,那么如果我们有多个光学测距仪,就可以将多个传感器的测量值融合起来。假如用两个光学测距仪进行测量,分别测出z1=30mz_1 = 30 mz1=30m、z2=32mz_2 = 32mz2=32m,两个传感器都有测量误差,并且误差服从正态分布,标准差σ12=2m\sigma_1^2 = 2mσ12=2m、σ22=4m\sigma_2^2 = 4mσ22=4m。
表现在图像上如下图所示:
import math
import numpy as np
import matplotlib.pyplot as pltdef normal_distribution(u, sig):x = np.linspace(u - 3 * sig, u + 3 * sig, 50)y = np.exp(-(x - u) ** 2 / (2 * sig ** 2)) / (math.sqrt(2 * math.pi) * sig)return x, yimport math
import numpy as np
import matplotlib.pyplot as pltdef normal_distribution(u, sig):x = np.linspace(u - 3 * sig, u + 3 * sig, 50)y = np.exp(-(x - u) ** 2 / (2 * sig ** 2)) / (math.sqrt(2 * math.pi) * sig)return x, yu1, sig1 = 30, 2
u2, sig2 = 32, 4
x1, y1 = normal_distribution(u1, sig1)
x2, y2 = normal_distribution(u2, sig2)plt.plot(x1, y1, "g", linewidth=2, label="z_1")
plt.plot(x2, y2, "r", linewidth=2, label="z_2")
plt.legend()
plt.show()
有了这两个结果之后,如果想要估计一个更加准确的值,自然而然的可以想到取平均,但是因为第一个传感器的误差更小一些,因此应该用加权平均,让结果更偏向第一个结果。
观察前面计算估计值的公式:z^k=z^k−1+Kk(zk−z^k−1)\hat{z}_k = \hat{z}_{k-1} + \mathbf{K}_k(z_{k} - \hat{z}_{k-1})z^k=z^k−1+Kk(zk−z^k−1),其实z^k\hat{z}_kz^k和z^k−1\hat{z}_{k-1}z^k−1不仅可以来自同一传感器不同时间的测量值,也可以来自不同传感器的测量值,即z^=z1+k(z2−z1)\hat{z} = z_{1} + k(z_{2} - z_{1})z^=z1+k(z2−z1)。此时我们的目标就变成了求解kkk使得估计值z^\hat{z}z^的标准差最小,也就是方差最小。
σz2=Var(z1+k(z2−z1))=Var(z1−kz1+kz2)=Var((1−k)z1+kz2)=Var((1−k)z1)+Var(kz2)=(1−k)2Var(z1)+k2Var(z2)=(1−k)2σ12+k2σ22\begin{aligned} \sigma_{z}^{2} &= \mathrm{Var}(z_{1}+k(z_{2}-z_{1})) = \mathrm{Var}(z_{1}-k z_{1}+k z_{2}) \\ & = \mathrm{Var}((1-k) z_{1}+k z_{2}) = \mathrm{Var}((1-k) z_{1}) + \mathrm{Var}(k z_{2}) \\ & = (1-k)^2\mathrm{Var}(z_{1}) + k^{2}\mathrm{Var}(z_{2}) = (1-k)^2\sigma_1^2 + k^{2}\sigma_2^2 \\ \end{aligned}σz2=Var(z1+k(z2−z1))=Var(z1−kz1+kz2)=Var((1−k)z1+kz2)=Var((1−k)z1)+Var(kz2)=(1−k)2Var(z1)+k2Var(z2)=(1−k)2σ12+k2σ22
dσz2dk=−2(1−k)σ12+2kσ22=0⇒k=σ12σ12+σ22\frac{d \sigma_{z}^{2}}{d k} = -2(1 - k)\sigma_1^2 + 2k\sigma_2^2 = 0 \Rightarrow k = \frac{\sigma_1^2}{\sigma_1^2 + \sigma_2^2}dkdσz2=−2(1−k)σ12+2kσ22=0⇒k=σ12+σ22σ12
然后我们把σ1\sigma_1σ1和σ2\sigma_2σ2带入进去即可计算出k=2222+42=0.2k = \frac{2^2}{2^2 + 4^2} = 0.2k=22+4222=0.2,进而计算出z^=z1+0.2(z2−z1)=30+0.2∗(32−30)=30.4\hat{z} = z_{1} + 0.2(z_{2} - z_{1}) = 30 + 0.2 * (32 - 30) = 30.4z^=z1+0.2(z2−z1)=30+0.2∗(32−30)=30.4,也就是说,根据两个传感器的测量值和它们相应的误差,可以得出最优的估计值为30.4米,此时的方差为σz2=(1−0.2)2∗22+0.22∗42=3.2\sigma_z^2 = (1 - 0.2)^2 * 2 ^2 + 0.2^2 * 4^2 = 3.2σz2=(1−0.2)2∗22+0.22∗42=3.2。
将两个测量值和计算出的最优估计值表现在图像上如下图所示:
以上这个过程就是卡尔曼滤波的数据融合。
方差我们都知道,它是各个样本与样本均值的差的平方和的均值,用来度量一组数据的分散程度。那什么是协方差呢?可以通俗的理解为:两个变量在变化过程中是同方向变化还是反方向变化?同向或反向的程度如何?你变大,同时我也变大,说明两个变量是同向变化的,这时协方差就是正的,你变大,同时我变小,说明两个变量是反向变化的,这时协方差就是负的。从数值来看,协方差的数值越大,两个变量同向程度也就越大,反之亦然。协方差矩阵可以将方差和协方差在一个矩阵中表现出来,体现了变量间的联动关系。
那么怎么用数学语言来表述协方差呢?首先方差我们都比较熟悉,若样本X:x1,x2,⋯,xmX: x_{1}, x_{2}, \cdots, x_{m}X:x1,x2,⋯,xm,期望为μ\muμ, 则方差为Var(X)=∑i=1m∣xi−μ∣2\mathrm{Var}(X) = \sum_{i=1}^{m} \left|x_{i} - \mu\right|^{2}Var(X)=∑i=1m∣xi−μ∣2。假设随机变量x=[x1x2]\mathbf{x} = \begin{bmatrix} x_1 \\ x_2 \end{bmatrix}x=[x1x2]服从正态分布x∼N(0,σ12)\mathbf{x} \sim N(0, \sigma_1^2)x∼N(0,σ12),根据方差公式Var(x)=E(x2)−[E(x)]2\mathrm{Var}(x) = \mathbb{E}(x^2) - [\mathbb{E}(x)]^2Var(x)=E(x2)−[E(x)]2,σ12=E(x2)−[E(x)]2=tr[xxT]=x12+x22\sigma_1^2 = \mathbb{E}(\mathbf{x}^2) - [\mathbb{E}(\mathbf{x})]^2 = tr[\mathbf{x} \mathbf{x}^T] = x_1^2 + x_2^2σ12=E(x2)−[E(x)]2=tr[xxT]=x12+x22。
类比一下,若样本X:x1,x2,⋯,xmX: x_{1}, x_{2}, \cdots, x_{m}X:x1,x2,⋯,xm期望为μ\muμ,样本Y:y1,y2,⋯,ymY: y_{1}, y_{2}, \cdots, y_{m}Y:y1,y2,⋯,ym,期望为ν\nuν,那么(X,Y)(X, Y)(X,Y)的取值可以为(x1,y1),(x2,y2),⋯,(xm,ym)(x_{1}, y_{1}), (x_{2}, y_{2}), \cdots, (x_{m}, y_{m})(x1,y1),(x2,y2),⋯,(xm,ym),则协方差为Cov(X,Y)=∑i=1m(x‾i−μ)(y‾i−ν)\mathrm{Cov}(X, Y) = \sum\limits_{i=1}^{m}(\overline{x}_{i} - \mu)(\overline{y}_{i} - \nu)Cov(X,Y)=i=1∑m(xi−μ)(yi−ν)。假设有两个随机变量x=[x1x2],y=[y1y2]\mathbf{x} = \begin{bmatrix} x_1 \\ x_2 \end{bmatrix}, \mathbf{y} = \begin{bmatrix} y_1 \\ y_2 \end{bmatrix}x=[x1x2],y=[y1y2],分别服从正态分布x∼N(0,σ12),y∼N(0,σ22)\mathbf{x} \sim N(0, \sigma_1^2), \mathbf{y} \sim N(0, \sigma_2^2)x∼N(0,σ12),y∼N(0,σ22),根据协方差公式Cov(X,Y)=E[(X−E(X))(Y−E(Y))]=E(XY)−E(X)E(Y)\mathrm{Cov}(X, Y) = \mathbb{E}[(X - \mathbb{E}(X))(Y - \mathbb{E}(Y))] = \mathbb{E}(XY) - \mathbb{E}(X)\mathbb{E}(Y)Cov(X,Y)=E[(X−E(X))(Y−E(Y))]=E(XY)−E(X)E(Y),协方差矩阵为Cov(X,Y)=E[xyT]=E[x1y1x1y2x2y1x2y2]\mathrm{Cov}(X, Y) = \mathbb{E}[\mathbf{xy^\mathbf{T}}] = \mathbb{E}\begin{bmatrix} x_1y_1 & x_1y_2\\ x_2y_1 & x_2y_2 \end{bmatrix}Cov(X,Y)=E[xyT]=E[x1y1x2y1x1y2x2y2]。
因此,方差其实是一种特殊的协方差,当x=yx=yx=y时,Cov(x,y)=Var(x)=Var(y)\mathrm{Cov}(x,y) = \mathrm{Var}(x) = \mathrm{Var}(y)Cov(x,y)=Var(x)=Var(y),方差的值就是协方差矩阵的迹。数据集中两两变量的协方差就组成了协方差矩阵,其中的每个元素就是各个向量元素之间的协方差,其对角线上的值就是方差。
我们将小车ttt时刻的速度和距离表示为一个状态向量xt=[dtvt]\mathbf{x}_t = \begin{bmatrix} d_t \\ v_t \end{bmatrix}xt=[dtvt],设ttt时刻加速度传感器的输出为ata_tat。根据直线运动公式,小车在ttt时刻的速度为vt=vt−1+atΔtv_{t}=v_{t-1}+a_{t} \Delta tvt=vt−1+atΔt,距离为dt=dt−1+vt−1Δt+12atΔt2d_{t}=d_{t-1}+v_{t-1} \Delta t+\frac{1}{2} a_{t} \Delta t^{2}dt=dt−1+vt−1Δt+21atΔt2,将其整理为矩阵相乘的形式:x^t=[dtvt]=[1Δt01][dt−1vt−1]+[Δt22Δt]at\mathbf{\hat{x}}_{t}=\left[\begin{array}{l} d_{t} \\ v_{t} \end{array}\right]=\left[\begin{array}{rr} 1 & \Delta t \\ 0 & 1 \end{array}\right]\left[\begin{array}{l} d_{t-1} \\ v_{t-1} \end{array}\right]+\left[\begin{array}{c} \frac{\Delta t^{2}}{2} \\ \Delta t \end{array}\right] a_{t}x^t=[dtvt]=[10Δt1][dt−1vt−1]+[2Δt2Δt]at。当然,这是在理想状态下的期望值,实际的状态向量应该再加上一项随机噪声向量wt−1\mathbf{w}_{t-1}wt−1,即xt=[1Δt01][dt−1vt−1]+[Δt22Δt]at+wt−1\mathbf{x}_{t}=\left[\begin{array}{rr}1 & \Delta t \\0 & 1\end{array}\right]\left[\begin{array}{l}d_{t-1} \\v_{t-1}\end{array}\right]+\left[\begin{array}{c}\frac{\Delta t^{2}}{2} \\\Delta t\end{array}\right] a_{t}+ \mathbf{w}_{t - 1}xt=[10Δt1][dt−1vt−1]+[2Δt2Δt]at+wt−1,此时我们得到的方程即为卡尔曼滤波算法中状态方程的特殊形式。
卡尔曼滤波算法假定系统在某一时刻的状态可以由上一时刻的状态根据一个线性方程变化而来,即状态方程:xt=Axt−1+But+wt−1\mathbf{x}_{t} =\mathbf{A} \mathbf{x}_{t-1}+\mathbf{B} \mathbf{u}_{t}+\mathbf{w}_{t-1}xt=Axt−1+But+wt−1
其中:
由于噪声是均值为0的正态噪声,那么上述状态方程的期望(最大概率对应的值)是x^t−=Ax^t−1++But\hat{\mathbf{x}}_{t}^{-}=\mathbf{A} \hat{\mathbf{x}}_{t-1}^{+}+\mathbf{B} \mathbf{u}_{t}x^t−=Ax^t−1++But
其中:
上式表示,当前时刻对状态向量的预测可以从上一时刻输出的系统状态向量乘以状态转换矩阵加上此时的控制输入向量乘以控制矩阵得出。
光学测距仪得到的测量值是光从原点移动到小车的时间,设光速为ccc,那么测量值zt=dtcz_t = \frac{d_t}{c}zt=cdt,将其写为与系统状态向量矩阵相乘的形式z^t=[1c,0][dtvt]\mathbf{\hat{z}}_t = \begin{bmatrix} \frac{1}{c},& 0 \end{bmatrix} \begin{bmatrix} d_t \\ v_t \end{bmatrix}z^t=[c1,0][dtvt]。当然,这也是在理想状态下的期望值,实际的测量向量应该再加上一项测量噪声向量vt\mathbf{v}_{t}vt,即zt=[1c,0][dtvt]+vt\mathbf{z_t} = \begin{bmatrix} \frac{1}{c},& 0 \end{bmatrix} \begin{bmatrix} d_t \\ v_t \end{bmatrix} + \mathbf{v}_{t}zt=[c1,0][dtvt]+vt。
接下来我们对测量向量状态方程进行抽象:zt=Hxt+vt\mathbf{z}_{t}=\mathbf{H} \mathbf{x}_{t}+\mathbf{v}_{t}zt=Hxt+vt,其中:
我们最终的目标其实是xt\mathbf{x}_txt,因此也可以将测量向量状态方程转换一下:x^t=H−1z^t\hat{\mathbf{x}}_t = \mathbf{H}^{-1}\hat{\mathbf{z}}_tx^t=H−1z^t,后面也会用到这种形式。
由于我们假设噪声服从正态分布,正态分布的均值为0,也就是值为0对应的概率最大。换句话说,状态向量和测量向量实际上是一个随机向量,等于什么值是一个概率问题。如下图,小车在时刻ttt的位置是一个满足图示的概率分布。
最后,我们就得出了卡尔曼滤波算法中重要的两个状态方程:xt=Axt−1+But−1+wt−1zt=Hxt+vt\begin{array}{l} \mathbf{x}_{t}=\mathbf{A} \mathbf{x}_{t-1}+\mathbf{B} \mathbf{u}_{t-1}+\mathbf{w}_{t-1} \\ \mathbf{z}_{t}=\mathbf{H} \mathbf{x}_{t}+\mathbf{v}_{t} \end{array}xt=Axt−1+But−1+wt−1zt=Hxt+vt。
在开始正式推导卡尔曼滤波的公式之前,先做一个符号说明,不需要完全记住,只需在后面推导的过程中如果发生混淆随时查阅即可。
xt\mathbf{x}_txt:t 时刻的状态向量
x^t−\mathbf{\hat{x}}_t^-x^t−:t 时刻预测的状态向量的先验估计(未优化)
x^t+\mathbf{\hat{x}}_t^+x^t+:t 时刻预测的状态向量的后验估计(优化后)
zt\mathbf{z}_tzt:t 时刻的测量向量
z^t−\mathbf{\hat{z}}_t^-z^t−:t 时刻预测的测量向量的先验估计(未优化)
z^t+\mathbf{\hat{z}}_t^+z^t+:t 时刻预测的测量向量的后验估计(优化后)
wt\mathbf{w}_twt:t 时刻的过程噪声,服从正态分布
vt\mathbf{v}_tvt:t 时刻的测量噪声,服从正态分布
ut\mathbf{u}_tut:t 时刻外界对系统的输入
A\mathbf{A}A:状态转移矩阵
B\mathbf{B}B:输入控制矩阵
H\mathbf{H}H:测量矩阵
Q\mathbf{Q}Q:过程噪声的协方差矩阵
R\mathbf{R}R:测量噪声的协方差矩阵
P\mathbf{P}P:误差的协方差矩阵
K\mathbf{K}K:卡尔曼增益
根据卡尔曼滤波的两个状态方程可以得到两个状态向量的期望表达式:x^t−=Ax^t−1++Butx^t=H−1z^t\begin{array}{l} \hat{\mathbf{x}}_{t}^{-}=\mathbf{A} \hat{\mathbf{x}}_{t-1}^{+}+\mathbf{B} \mathbf{u}_{t} \\ \hat{\mathbf{x}}_t = \mathbf{H}^{-1}\hat{\mathbf{z}}_t \end{array}x^t−=Ax^t−1++Butx^t=H−1z^t,然后根据前面得到的数据融合的公式:z^k=z^k−1+K(zk−z^k−1)\hat{z}_k = \hat{z}_{k-1} + \mathbf{K}(z_{k} - \hat{z}_{k-1})z^k=z^k−1+K(zk−z^k−1),扩展为将两个状态向量进行融合x^t+=x^t−+G(H−1zt−x^t−)\hat{\mathbf{x}}_{t}^{+} = \hat{\mathbf{x}}_{t}^{-} + \mathbf{G}(\mathbf{H}^{-1}\mathbf{z}_t - \hat{\mathbf{x}}_{t}^{-})x^t+=x^t−+G(H−1zt−x^t−),然后令G=KtH\mathbf{G} = \mathbf{K}_t\mathbf{H}G=KtH,则x^t+=x^t−+Kt(zt−Hx^t−)\hat{\mathbf{x}}_{t}^{+} = \hat{\mathbf{x}}_{t}^{-} + \mathbf{K}_t(\mathbf{z}_t - \mathbf{H}\hat{\mathbf{x}}_{t}^{-})x^t+=x^t−+Kt(zt−Hx^t−),这个就是卡尔曼滤波的核心公式。我们的目标就是找到一个合适的Kt\mathbf{K}_tKt使得估计值x^t+\hat{\mathbf{x}}_{t}^{+}x^t+的误差最小。
状态预测对系统的状态向量进行建模,由于传感器的输出是带噪声的,反映到对状态向量的估计就是状态预测方程中的wt\mathbf{w}_twt噪声项,我们假设噪声服从正态分布,即P(wt)∼N(0,Qt)P(\mathbf{w}_t) \sim N(0, \mathbf{Q}_t)P(wt)∼N(0,Qt),其中Qt=E[wtwtT]\mathbf{Q}_t = \mathbb{E}[\mathbf{w}_t\mathbf{w}_t^T]Qt=E[wtwtT]。
在实际建模的过程中,并不能直接获取到噪声,但是我们希望通过滤波让噪声造成的误差越小越好。可以用ttt时刻实际的状态向量xt\mathbf{x}_txt减去ttt时刻预测的状态向量x^t−\hat{\mathbf{x}}_{t}^{-}x^t−,即误差et=xt−x^te_{t} = \mathbf{x}_{t}-\hat{\mathbf{x}}_{t}et=xt−x^t。由于噪声服从正态分布,因此误差也服从正态分布,即P(et)∼N(0,Pt)P(e_t) \sim N(0, \mathbf{P}_t)P(et)∼N(0,Pt),其中Pt\mathbf{P}_tPt为误差的协方差矩阵。
Pt=E[etetT]=E[(xt−x^t)(xt−x^t)T]\mathbf{P}_{t} = \mathbb{E}[e_{t}e_{t}^{T}] = \mathbb{E}\left[(\mathbf{x}_t - \mathbf{\hat{x}}_{t})(\mathbf{x}_t - \mathbf{\hat{x}}_{t})^{T}\right]Pt=E[etetT]=E[(xt−x^t)(xt−x^t)T]
其中xt−x^t=xt−(x^t−+Kt(zt−Hx^t−))=xt−x^t−−Ktzt+KtHx^t−\begin{aligned} \mathbf{x}_t - \mathbf{\hat{x}}_{t} & = \mathbf{x}_t - \left(\hat{\mathbf{x}}_{t}^{-} + \mathbf{K}_t(\mathbf{z}_t - \mathbf{H}\hat{\mathbf{x}}_{t}^{-})\right) \\ & = \mathbf{x}_t - \hat{\mathbf{x}}_{t}^{-} - \mathbf{K}_t\mathbf{z}_t + \mathbf{K}_t\mathbf{H}\hat{\mathbf{x}}_{t}^{-} \end{aligned}xt−x^t=xt−(x^t−+Kt(zt−Hx^t−))=xt−x^t−−Ktzt+KtHx^t−
又zt=Hxt+vt\mathbf{z}_{t}=\mathbf{H} \mathbf{x}_{t}+\mathbf{v}_{t}zt=Hxt+vt
所以xt−x^t=xt−x^t−−Kt(Hxt+vt)+KtHx^t−=(xt−x^t−)−KtHxt+KtHx^t−−Ktvt=(E−KtH)(xt−x^t−)−Ktvt\begin{aligned} \mathbf{x}_{t} - \mathbf{\hat{x}}_{t} & = \mathbf{x}_{t} - \hat{\mathbf{x}}_{t}^{-} - \mathbf{K}_{t}(\mathbf{H}\mathbf{x}_{t} + \mathbf{v}_{t}) + \mathbf{K}_t\mathbf{H}\hat{\mathbf{x}}_{t}^{-} \\ & = (\mathbf{x}_t - \hat{\mathbf{x}}_{t}^{-}) - \mathbf{K}_t\mathbf{H}\mathbf{x}_{t} + \mathbf{K}_t\mathbf{H}\hat{\mathbf{x}}_{t}^{-} - \mathbf{K}_t\mathbf{v}_{t} \\ & = (\mathbf{E} - \mathbf{K}_t\mathbf{H})(\mathbf{x}_t - \hat{\mathbf{x}}_{t}^{-}) - \mathbf{K}_t\mathbf{v}_{t} \end{aligned}xt−x^t=xt−x^t−−Kt(Hxt+vt)+KtHx^t−=(xt−x^t−)−KtHxt+KtHx^t−−Ktvt=(E−KtH)(xt−x^t−)−Ktvt
误差et=xt−x^te_{t} = \mathbf{x}_{t}-\hat{\mathbf{x}}_{t}et=xt−x^t,所以先验误差即为et−=xt−x^t−e_t^- = \mathbf{x}_{t}-\hat{\mathbf{x}}_{t}^-et−=xt−x^t−,那么误差的方差:
Pt=E[(xt−x^t)(xt−x^t)T]=E[((E−KtH)et−−Ktvt)((E−KtH)et−−Ktvt)T]=E[((E−KtH)et−−Ktvt)(et−T(E−KtH)T−vtTKtT)]=E[(E−KtH)et−et−T(E−KtH)T−(E−KtH)et−vtTKtT−Ktvtet−T(E−KtH)T+KtvtvtTKtT]\begin{aligned} \mathbf{P}_{t} & = \mathbb{E}\left[(\mathbf{x}_t - \mathbf{\hat{x}}_t)(\mathbf{x}_t - \mathbf{\hat{x}}_t)^{\mathbf{T}}\right] \\ & = \mathbb{E}\left[ \left( (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^- - \mathbf{K}_t\mathbf{v}_{t} \right)\left( (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^- - \mathbf{K}_t\mathbf{v}_{t} \right)^{\mathbf{T}} \right] \\ & = \mathbb{E}\left[ \left( (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^- - \mathbf{K}_t\mathbf{v}_{t} \right)\left( {e_t^-}^{\mathbf{T}}(\mathbf{E} - \mathbf{K}_t\mathbf{H})^{\mathbf{T}} - \mathbf{v}_{t}^{\mathbf{T}}\mathbf{K}_t^{\mathbf{T}} \right) \right] \\ & = \mathbb{E}\left[ (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^- {e_t^-}^{\mathbf{T}}(\mathbf{E} - \mathbf{K}_t\mathbf{H})^{\mathbf{T}} - (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^-\mathbf{v}_{t}^{\mathbf{T}}\mathbf{K}_t^{\mathbf{T}} - \mathbf{K}_t\mathbf{v}_{t}{e_t^-}^{\mathbf{T}}(\mathbf{E} - \mathbf{K}_t\mathbf{H})^{\mathbf{T}} + \mathbf{K}_t\mathbf{v}_{t}\mathbf{v}_{t}^{\mathbf{T}}\mathbf{K}_t^{\mathbf{T}} \right] \end{aligned} Pt=E[(xt−x^t)(xt−x^t)T]=E[((E−KtH)et−−Ktvt)((E−KtH)et−−Ktvt)T]=E[((E−KtH)et−−Ktvt)(et−T(E−KtH)T−vtTKtT)]=E[(E−KtH)et−et−T(E−KtH)T−(E−KtH)et−vtTKtT−Ktvtet−T(E−KtH)T+KtvtvtTKtT]
由于先验误差et−e_t^-et−和测量噪声vt\mathbf{v}_tvt是相互独立的,两个相互独立的随机变量的乘积的期望等于两个随机变量期望的乘积,即E(x1⋅x2)=E(x1)⋅E(x2)\mathbb{E}\left(\mathrm{x}_{1} \cdot \mathrm{x}_{2}\right)=\mathbb{E}\left(\mathrm{x}_{1}\right) \cdot \mathbb{E}\left(\mathrm{x}_{2}\right)E(x1⋅x2)=E(x1)⋅E(x2),而测量噪声向量的期望为0,所以E[(E−KtH)et−vtTKtT]=E[Ktvtet−T(E−KtH)T]=0\mathbb{E} \left[ (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^-\mathbf{v}_{t}^{\mathrm{T}}\mathbf{K_t}^{\mathrm{T}} \right] = \mathbb{E} \left[ \mathbf{K}_t\mathbf{v}_{t}{e_t^-}^{\mathrm{T}}(\mathbf{E} - \mathbf{K}_t\mathbf{H})^{\mathrm{T}} \right] = 0E[(E−KtH)et−vtTKtT]=E[Ktvtet−T(E−KtH)T]=0。
误差的协方差矩阵简化为:Pt=E[(E−KtH)et−et−T(E−KtH)T+KtvtvtTKtT]=(E−KtH)E[et−et−T](E−KtH)T+KtE[vtvtT]KtT=(E−KtH)Pt−(E−HTKtT)+KtRKtT\begin{aligned} \mathbf{P}_{t} & = \mathbb{E}\left[ (\mathbf{E} - \mathbf{K}_t\mathbf{H})e_t^- {e_t^-}^{\mathbf{T}}(\mathbf{E} - \mathbf{K}_t\mathbf{H})^{\mathbf{T}} + \mathbf{K}_t\mathbf{v}_{t}\mathbf{v}_{t}^{\mathrm{T}}\mathbf{K}_t^{\mathrm{T}} \right] \\ & = (\mathbf{E} - \mathbf{K}_t\mathbf{H}) \ \mathbb{E} \left[ e_t^- {e_t^-}^{\mathbf{T}} \right](\mathbf{E} - \mathbf{K}_t\mathbf{H})^{\mathrm{T}} + \mathbf{K}_t \ \mathbb{E} \left[ \mathbf{v}_{t}\mathbf{v}_{t}^{\mathrm{T}} \right] \mathbf{K}_t^{\mathrm{T}} \\ & = (\mathbf{E} - \mathbf{K}_t\mathbf{H}) \ \mathbf{P}_{t}^{-} (\mathbf{E} - \mathbf{H}^{\mathrm{T}}\mathbf{K}_t^{\mathrm{T}}) + \mathbf{K}_t \ \mathbf{R} \mathbf{K}_t^{\mathrm{T}} \\ \end{aligned}Pt=E[(E−KtH)et−et−T(E−KtH)T+KtvtvtTKtT]=(E−KtH) E[et−et−T](E−KtH)T+Kt E[vtvtT]KtT=(E−KtH) Pt−(E−HTKtT)+Kt RKtT,回过头看,我们的目标是希望找到Kt\mathbf{K}_{t}Kt使误差ete_{t}et的方差越小越好,而方差其实就是协方差矩阵的迹,因此可以用tr(Pt)tr(\mathbf{P}_{t})tr(Pt)对Kt\mathbf{K}_{t}Kt求导,令导数值等于零,就可以找到tr(Pt)tr(\mathbf{P}_{t})tr(Pt)的极值点了,即方差最小的点。
为了方便计算,将Pt\mathbf{P}_{t}Pt的表达式展开然后求迹:tr(Pt)=tr(Pt−)−2tr(KtHPt−)+tr(KtHPt−HTKtT)+tr(KtRKtT)tr(\mathbf{P}_{t}) = tr(\mathbf{P}_{t}^{-}) - 2tr(\mathbf{K}_t\mathbf{H}\mathbf{P}_{t}^{-}) + tr(\mathbf{K}_t\mathbf{H}\mathbf{P}_{t}^{-}\mathbf{H}^{\mathbf{T}}\mathbf{K}_t^{\mathbf{T}}) + tr(\mathbf{K}_t \mathbf{R} \mathbf{K}_t^{\mathbf{T}})tr(Pt)=tr(Pt−)−2tr(KtHPt−)+tr(KtHPt−HTKtT)+tr(KtRKtT),然后每一项分别对Kt\mathbf{K}_{t}Kt求导:
所以dtr(Pt)d(Kt)=−2Pt−HT+2KtHPt−HT+2KtR\frac{\mathrm{d} \ tr(\mathbf{P}_{t})}{\mathrm{d} (\mathbf{K}_{t})} = -2\mathbf{P}_{t}^{-}\mathbf{H}^\mathrm{T} + 2\mathbf{K}_t\mathbf{H}\mathbf{P}_{t}^{-}\mathbf{H}^{\mathbf{T}} + 2\mathbf{K}_t \mathbf{R}d(Kt)d tr(Pt)=−2Pt−HT+2KtHPt−HT+2KtR,令其等于零,可解出Kt=Pt−HtTHtPt−HtT+Rt\mathbf{K}_{t} = \frac{\mathbf{P}_{t}^{-} \mathbf{H}_{t}^{\mathrm{T}}}{\mathbf{H}_{t} \mathbf{P}_{t}^{-} \mathbf{H}_{t}^{\mathrm{T}} + \mathbf{R}_{t}}Kt=HtPt−HtT+RtPt−HtT,这也就是我们想求的卡尔曼增益,它可以让误差的方差取极小值。
H\mathbf{H}H是已知的测量矩阵,R\mathbf{R}R是测量噪声向量的协方差矩阵,因此K\mathbf{K}K的表达式中只有P−\mathbf{P}^{-}P−是未知的,根据定义Pt−=E[et−et−T]\mathbf{P}_{t}^{-} = \mathbb{E}[e_{t}^{-}{e_{t}^{-}}^{\mathrm{T}}]Pt−=E[et−et−T],而et−=xt−x^t−e_t^- = \mathbf{x}_{t}-\hat{\mathbf{x}}_{t}^-et−=xt−x^t−,根据xt=Axt−1+But−1+wt−1x^t−=Ax^t−1++But−1\begin{matrix} \mathbf{x}_{t}=\mathbf{A} \mathbf{x}_{t-1}+\mathbf{B} \mathbf{u}_{t-1}+\mathbf{w}_{t-1} \\ \hat{\mathbf{x}}_{t}^{-}=\mathbf{A} \hat{\mathbf{x}}_{t-1}^{+}+\mathbf{B} \mathbf{u}_{t-1} \end{matrix}xt=Axt−1+But−1+wt−1x^t−=Ax^t−1++But−1,得et−=A(xt−1−x^t−1+)+wt−1e_t^- = \mathbf{A} (\mathbf{x}_{t-1} - \hat{\mathbf{x}}_{t-1}^{+}) + \mathbf{w}_{t-1}et−=A(xt−1−x^t−1+)+wt−1,因此
Pt−=E[et−et−T]=E[(Aet−1+wt−1)(et−1TAT+wt−1T)]=E[Aet−1et−1TAT+Aet−1wt−1T+wt−1et−1TAT+wt−1wt−1T]=E[Aet−1et−1TAT]+E[Aet−1wt−1T]+E[wt−1et−1TAT]+E[wt−1wt−1T]\begin{aligned} \mathbf{P}_{t}^{-} & = \mathbb{E}[e_{t}^{-}{e_{t}^{-}}^{\mathrm{T}}] \\ & = \mathbb{E}\left[ \left( \mathbf{A} e_{t-1} + \mathbf{w}_{t-1} \right)\left(e_{t-1}^{\mathrm{T}}\mathbf{A}^{\mathrm{T}} + \mathbf{w}_{t-1}^{\mathrm{T}} \right)\right] \\ & = \mathbb{E}\left[ \mathbf{A} e_{t-1}e_{t-1}^{\mathrm{T}}\mathbf{A}^{\mathrm{T}} + \mathbf{A}e_{t-1}\mathbf{w}_{t-1}^{\mathrm{T}} + \mathbf{w}_{t-1} e_{t-1}^{\mathrm{T}}\mathbf{A}^{\mathrm{T}} + \mathbf{w}_{t-1}\mathbf{w}_{t-1}^{\mathrm{T}} \right] \\ & = \mathbb{E}\left[ \mathbf{A} e_{t-1}e_{t-1}^{\mathrm{T}}\mathbf{A}^{\mathrm{T}} \right ] + \mathbb{E}\left[\mathbf{A}e_{t-1}\mathbf{w}_{t-1}^{\mathrm{T}}\right] + \mathbb{E}\left[\mathbf{w}_{t-1} e_{t-1}^{\mathrm{T}}\mathbf{A}^{\mathrm{T}}\right] + \mathbb{E}\left[\mathbf{w}_{t-1}\mathbf{w}_{t-1}^{\mathrm{T}} \right] \end{aligned}Pt−=E[et−et−T]=E[(Aet−1+wt−1)(et−1TAT+wt−1T)]=E[Aet−1et−1TAT+Aet−1wt−1T+wt−1et−1TAT+wt−1wt−1T]=E[Aet−1et−1TAT]+E[Aet−1wt−1T]+E[wt−1et−1TAT]+E[wt−1wt−1T]
注意et−=xt−x^t−xt=Axt−1+But−1+wt−1\begin{aligned} & e_t^- = \mathbf{x}_{t}-\hat{\mathbf{x}}_{t}^- \\ & \mathbf{x}_{t}=\mathbf{A} \mathbf{x}_{t-1}+\mathbf{B} \mathbf{u}_{t-1}+\mathbf{w}_{t-1} \end{aligned}et−=xt−x^t−xt=Axt−1+But−1+wt−1,wt−1\mathbf{w}_{t-1}wt−1作用与第ttt次xt\mathbf{x}_{t}xt,而et−1e_{t-1}et−1是第t−1t-1t−1次的误差,因此两个向量相互独立,E[Aet−1wt−1T]=E[wt−1et−1TAT]=0\mathbb{E}\left[\mathbf{A}e_{t-1}\mathbf{w}_{t-1}^{\mathrm{T}}\right] = \mathbb{E}\left[\mathbf{w}_{t-1} e_{t-1}^{\mathrm{T}}\mathbf{A}^{\mathrm{T}}\right] = 0E[Aet−1wt−1T]=E[wt−1et−1TAT]=0,最终简化为Pt−=AE[et−1et−1T]AT+E[wt−1wt−1T]=AtPt−1+AtT+Qt\mathbf{P}_{t}^{-} = \mathbf{A}\mathbb{E}\left[e_{t-1}e_{t-1}^{\mathrm{T}}\right]\mathbf{A}^{\mathrm{T}} + \mathbb{E}\left[\mathbf{w}_{t-1}\mathbf{w}_{t-1}^{\mathrm{T}} \right] = \mathbf{A}_{t} \mathbf{P}_{t-1}^{+} \mathbf{A}_{t}^{T} + \mathbf{Q}_{t}Pt−=AE[et−1et−1T]AT+E[wt−1wt−1T]=AtPt−1+AtT+Qt。
求出了先验估计Pt−\mathbf{P}_{t}^{-}Pt−,根据前面推导出的后验估计公式Pt=(E−KtH)Pt−(E−HTKtT)+KtRKtT\mathbf{P}_{t} = (\mathbf{E} - \mathbf{K}_t\mathbf{H}) \ \mathbf{P}_{t}^{-} (\mathbf{E} - \mathbf{H}^{\mathrm{T}}\mathbf{K}_t^{\mathrm{T}}) + \mathbf{K}_t \ \mathbf{R} \mathbf{K}_t^{\mathrm{T}}Pt=(E−KtH) Pt−(E−HTKtT)+Kt RKtT,带入Kt\mathbf{K}_tKt,即可将后验估计公式简化为:Pt+=(E−KtHt)Pt−\mathbf{P}_{t}^{+}=(\mathbf{E} - \mathbf{K}_{t} \mathbf{H}_{t}) \mathbf{P}_{t}^{-}Pt+=(E−KtHt)Pt−。
到此为止,卡尔曼滤波中所有的公式就已经推导完毕。
卡尔曼滤波给出了一种数据融合的方案,将以加速度传感器的输出建立的数学模型和光学测距仪的输出融合起来,取长补短,这样得出的结果才更加准确。那么具体怎么融合,卡尔曼滤波给出了步骤:首先通过数学模型预测,然后通过测量模型更新。所谓状态预测,就是前面提到的用数学模型根据加速度传感器的输出直接推导出小车此时的速度和距离,将其称为预测结果。所谓更新,就是先获取小车以外的传感器的测量结果,比如光学测距仪的结果,然后结合该测量结果对预测结果进行修正,因此也叫测量更新。
在自动驾驶中,我们并不知道自己的精确位置。卡尔曼滤波从k−1k - 1k−1时刻的概率估计开始,通过里程计或IMU的输出建立数学模型预测kkk时刻的状态,但由于传感器的精度、空气阻力和摩擦系数等不确定性因素,导致预测并不是很完美。然后通过GPS等传感器建立的测量模型更新kkk时刻的车辆位置,虽然GPS的精度不够准确,但是卡尔曼滤波可以将所有可用的信息都结合起来,根据其本身的噪声分配一定的权重,就能得到一个比任何单个方案更好的结果,这就是卡尔曼滤波的作用。
卡尔曼滤波包括下面5个步骤:
我们可以将卡尔曼滤波看作是融合不同传感器信息进行不确定性估计的技术,它的每一个组成部分,初始估计、预测状态和更新状态都是通过均值和方差确定的随机变量。由于它是一个递推的公式,要计算t=1t = 1t=1时刻误差的协方差矩阵P1−\mathbf{P}_{1}^{-}P1−,需要给出t=0t = 0t=0时刻的协方差矩阵P0+\mathbf{P}_{0}^{+}P0+,以及初始化一个Q0\mathbf{Q}_{0}Q0。
卡尔曼滤波对初始值并不是很敏感,在实际使用中,如果可以得到在一段初始时间内状态向量的简单计算结果,那么也就可以从这一段时间内计算出均值和方差。比如在上面这个例子中,起始阶段小车静止,速度和距离都是0,但是如果直接用加速度传感器的输出做一次积分得到速度,做二次积分得到距离,得到的速度和距离不是0的话,那么就可以据此简单估计出噪声的均值和方差。对于无法估计的系统,噪声的方差可以设为传感器的观测方差,一般可以通过测量实验或从传感器厂商那里直接获得。
接下来我们通过Python实现一个简单的卡尔曼滤波:
import numpy as np
import matplotlib.pyplot as pltdelta_t = 0.1 # 每秒钟采一次样
end_t = 7 # 时间长度
time_t = end_t * 10 # 采样次数
t = np.arange(0, end_t, delta_t) # 设置时间数组u = 1 # 定义外界对系统的作用 加速度
x = 1 / 2 * u * t ** 2 # 实际真实位置v_var = 1 # 测量噪声的方差
# 创建高斯噪声,精确到小数点后两位
v_noise = np.round(np.random.normal(0, v_var, time_t), 2)X = np.mat([[0], [0]]) # 定义预测优化值的初始状态
v = np.mat(v_noise) # 定义测量噪声
z = x + v # 定义测量值 = 实际状态值 + 噪声
A = np.mat([[1, delta_t], [0, 1]]) # 定义状态转移矩阵
B = [[delta_t ** 2 / 2], [delta_t]] # 定义输入控制矩阵
P = np.mat([[1, 0], [0, 1]]) # 定义初始状态协方差矩阵
Q = np.mat([[0.001, 0], [0, 0.001]]) # 定义预测噪声协方差矩阵
H = np.mat([1, 0]) # 定义观测矩阵
R = np.mat([1]) # 定义观测噪声协方差
X_mat = np.zeros(time_t) # 初始化记录系统预测优化值的列表for i in range(time_t):# 预测X_predict = A * X + np.dot(B, u) # 估算状态变量P_predict = A * P * A.T + Q # 估算状态误差协方差# 校正K = P_predict * H.T / (H * P_predict * H.T + R) # 更新卡尔曼增益X = X_predict + K * (z[0, i] - H * X_predict) # 更新预测优化值P = (np.eye(2) - K * H) * P_predict # 更新状态误差协方差# 记录系统的预测优化值X_mat[i] = X[0, 0]plt.plot(x, "b", label="ground truth") # 设置曲线数值
plt.plot(X_mat, "g", label="predict value")
plt.plot(z.T, "r--", label="measure value")
plt.xlabel("time") # 设置X轴的名字
plt.ylabel("distance") # 设置Y轴的名字
plt.title("Kalman Filter") # 设置标题
plt.legend() # 设置图例
plt.show() # 显示图表
可以看出,尽管测量值波动很大,但最终的预测优化值与实际状态值相差不大。