拡張カルマンフィルタによる自己位置推定動作の可視化

# はじめに
カルマンフィルタといったら一般的に線形カルマンフィルタのことを指すが、この線形カルマンフィルタは線形システムのモデルにしか適用できない。
そこで、この線形カルマンフィルタを非線形モデルに適用できるよう拡張されたのが拡張カルマンフィルタ(Extended Kalman Filter, EKF)となります。

# 拡張カルマンフィルタ(Extended Kalman Filter)

線形カルマンフィルタの場合、状態空間モデルは以下の式で表されていました。

- __状態空間モデル（線形）__

```math
\begin{align}
    \boldsymbol{x}(k+1) &= \boldsymbol{A} \boldsymbol{x}(k) + 
    \boldsymbol{B} \boldsymbol{u}(k) +  \boldsymbol{v}(k) \tag{1}\\
    \boldsymbol{y}(k) &= \boldsymbol{C} \boldsymbol{x}(k) + \boldsymbol{w}(k)  \tag{2}\\
\end{align}
```
なお、線形カルマンフィルタの詳細については前回の記事を参考にしてください。
・[SLAM(Simultaneous Localization and Mapping)と環境計測センサについて](http://qiita.com/Crafty_as_a_Fox/items/860aa3d467397432e060)

拡張カルマンフィルタの場合、状態空間モデルは以下の式で表わされます。

- __状態空間モデル（非線形）__

```math
\begin{align}
    \boldsymbol{x}(k+1) &= \boldsymbol{f}(\boldsymbol{x}(k), \boldsymbol{u}(k)) +  \boldsymbol{v}(k) \tag{3}\\
    \boldsymbol{y}(k) &= \boldsymbol{h}(\boldsymbol{x}(k)) + \boldsymbol{w}(k)  \tag{4}\\
\end{align}
```

但し、
$\boldsymbol{f}(\cdot)$：$\boldsymbol{x}(k)$及び、$\boldsymbol{u}(k)$の非線形関数
$\boldsymbol{h}(\cdot)$：$\boldsymbol{x}(k)$の非線形関数

$\boldsymbol{f}(\cdot)$と$\boldsymbol{h}(\cdot)$は、どちらの非線形関数であるため、直接共分散行列を計算することができません。しかし、これらの関数を線形近似することによって線形カルマンフィルタと同じ要領で解くことができます。線形システムと非線形システムは対立する関係ではなく、非線形システムの特殊な場合が線形システムであるととらえることが重要です。
拡張カルマンフィルタでは非線形の状態方程式と観測方程式の偏微分行列（ヤコビアン）を用います。

```math
\begin{align}
    \boldsymbol{A}(k) &= \left.\frac{\partial \boldsymbol{f}(\boldsymbol{x},    \boldsymbol{u})}{\partial \boldsymbol{x}}\right|_{\boldsymbol{x}=\boldsymbol{\hat{x}}(k), \boldsymbol{u}=\boldsymbol{u}(k)} \tag{5}\\
    \boldsymbol{C}(k) &= \left.\frac{\partial \boldsymbol{h}(\boldsymbol{x})}{\partial \boldsymbol{x}}\right|_{\boldsymbol{x}=\boldsymbol{\hat{x}}(k)} \tag{6}\\
\end{align}
```
この場合のカルマンフィルタの時間更新式は次のようになります。

- __予測ステップ__

```math
\begin{align}
事前状態推定値&：　\boldsymbol{\hat{x}}^-(k) = \boldsymbol{f}(\boldsymbol{\hat{x}}(k-1), \boldsymbol{u}(k-1)) \tag{7}\\
線形近似&：　\boldsymbol{A}(k-1) = \left.\frac{\partial \boldsymbol{f}(\boldsymbol{x}, \boldsymbol{u})}{\partial \boldsymbol{x}}\right|_{\boldsymbol{x}=\boldsymbol{\hat{x}}(k-1), \boldsymbol{u}=\boldsymbol{u}(k-1)} \tag{8}\\
&　　\boldsymbol{C}(k) = \left.\frac{\partial \boldsymbol{h}(\boldsymbol{x})}{\partial \boldsymbol{x}}\right|_{\boldsymbol{x}=\boldsymbol{\hat{x}}(k)} \tag{9}\\
事前誤差共分散行列&：　\boldsymbol{P}^-(k) = \boldsymbol{A}(k-1) \boldsymbol{P}(k-1) \boldsymbol{A}^T(k-1) + \boldsymbol{Q}(k-1) \tag{10}\\
\end{align}
```

- __フィルタリングステップ__

```math
\begin{align}
    カルマンゲイン行列&：　\boldsymbol{G}(k) = \boldsymbol{P}^-(k) \boldsymbol{C}^T(k) (\boldsymbol{C}(k) \boldsymbol{P}^-(k) \boldsymbol{C}^T(k) + \boldsymbol{R}(k))^{-1} \tag{11}\\
    状態推定値&：　\boldsymbol{\hat{x}}(k) = \boldsymbol{\hat{x}}^-(k) + \boldsymbol{G}(k)(\boldsymbol{y}(k) - \boldsymbol{h} (\boldsymbol{\hat{x}}^-(k)) \tag{12}\\
    事後誤差共分散行列&：　\boldsymbol{P}(k) = (\boldsymbol{I} - \boldsymbol{G}(k) \boldsymbol{C}) \boldsymbol{P}^-(k) \tag{13}\\
\end{align}
```

# 例題
2次元座標において、あるロボットが速度$v[m/s]$、角速度$\omega[deg/s]$で周回移動するものとします。このとき、ロボットの移動には誤差$\boldsymbol{v}(k)$を含みます。また、ロボットの位置を観測するセンサも誤差$\boldsymbol{w}(k)$を含みます。サンプリング周期は$\Delta t$とします。ここで、観測された軌跡から実際の軌跡を拡張カルマンフィルタによって推定します。
![例題.png](https://qiita-image-store.s3.amazonaws.com/0/153826/841b0ed7-2590-5d48-f128-b95f988fe9fd.png)

ここで、ロボットの姿勢を定義します。

![姿勢.PNG](https://qiita-image-store.s3.amazonaws.com/0/153826/065610b0-edfa-b4ad-eef7-68b858821c3f.png)

$x,y,\theta$はそれぞれ、ロボットの$X$座標、$Y$座標、姿勢角を表し、姿勢ベクトル$\boldsymbol{x}(k)$は以下のように定義されます。

```math
\boldsymbol{x}(k) = 
\begin{bmatrix}
x(k) \\
y(k) \\
\theta(k) \\
\end{bmatrix} \tag{14}\\
```
よって状態方程式は以下のようになります。

```math
\begin{align}
\boldsymbol{\hat{x}}^-(k+1) &= \boldsymbol{f}(\boldsymbol{\hat{x}}(k),\boldsymbol{u}(k)) \\
&=
\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
0 & 0 & 1 \\
\end{bmatrix}
\boldsymbol{\hat{x}}^-(k)
 + 
\begin{bmatrix}
v & 0 & 0 \\
0 & v & 0 \\
0 & 0 & \omega \\
\end{bmatrix}
\boldsymbol{u}(k) \\
\end{align} \tag{15}\\
```
但し、

```math
\boldsymbol{u}(k) = \begin{bmatrix}
\Delta t \cdot cos\theta(k) \\
\Delta t \cdot sin\theta(k) \\
\Delta t \\
\end{bmatrix} \tag{16}\\
```

するとヤコビアンは以下のように求められます。

```math
\frac{\partial \boldsymbol{f}(\boldsymbol{x},    \boldsymbol{u})}{\partial \boldsymbol{x}} = 
\begin{bmatrix}
1 & 0 & v \cdot \Delta t \cdot cos\theta(k) \\
0 & 1 & v \cdot \Delta t \cdot sin\theta(k) \\
0 & 0 & 1 \\
\end{bmatrix}
 \tag{17}\\
```

次は観測値$\boldsymbol{y}(k)$を定義します。
まず、観測ベクトル$\boldsymbol{y}(k)$を以下のように定義します。

```math
\boldsymbol{y}(k) = 
\begin{bmatrix}
x(k) \\
y(k) \\
\end{bmatrix} \tag{18}\\
```

$x,y$はそれぞれ、観測されたロボットの$X$座標、$Y$座標を表します。
次に、観測値$\boldsymbol{y}(k)$は「真の位置$\boldsymbol{x}_{gt}(k)$+観測雑音$\boldsymbol{w}(k)$」で与えられるものとします。そうすると、観測値は以下の式で算出されます。

```math
\boldsymbol{y}(k) = 
\begin{bmatrix}
1 & 0 & 0 \\
0 & 1 & 0 \\
\end{bmatrix}
\boldsymbol{x}_{gt}(k)
 + \boldsymbol{w}(k)
 \tag{19}\\
```

例題の説明は以上です。
上記例題を実装したスクリプトはGitHubで公開しています。
・[GitHub - extended_kalman_filter.py](https://github.com/takuyani/SLAM-Robot_Simu/blob/master/extended_kalman_filter.py)

また、スクリプトを実行した結果は以下のようになります。
（画像をクリックするとYouTubeへジャンプします。）
[![extended_kalman_filter](https://farm5.staticflickr.com/4451/37758218611_f5de350889_b.jpg)](http://www.youtube.com/watch?v=7Lxlnb39wtU)

青い点が拡張カルマンフィルタによる推定値になるのですが、その回りに見える黄色の薄い楕円は誤差楕円(Error Ellipse)となっています。

上記誤差楕円を含め、スクリプトを書く際は以下のサイトを参考にさせていただきました。
 ・[拡張カルマンフィルタを使用した自己位置推定MATLABサンプルプログラム](http://myenigma.hatenablog.com/entry/20130413/1365826157)
 ・[カルマンフィルタにおける誤差楕円の計算方法](http://myenigma.hatenablog.com/entry/20140621/1403336277)
先駆者に感謝します。

# おわりに
次はパーティクルフィルタやろうかな・・・

# 参考文献
1. ["確率ロボティクス (プレミアムブックス版)", マイナビ出版, 2005.](https://book.mynavi.jp/ec/products/detail/id=37337)
2. ["カルマンフィルタの基礎", 東京電機大学出版局, 2012.](http://www.tdupress.jp/books/isbn978-4-501-32890-0.html)