リアプノフ安定をスライディングモード制御経由で理解する

# はじめに
制御工学において安定性を判別する方法はいくつかあります。
線形制御における安定性判別の１手法としては「状態方程式の極」による方法が挙げられ、具体的には下記のように求められます。

```math
\begin{align} 
\dot{x}&= Ax+Bu　ラプラス変換した上で式変形し　\\　x &= (sI-A)^{-1}Bu\\
det(sI-A)&=0 を満たすsが極
\end{align} 
```
ラプラス変換を(なんとなくで良いので)理解した上で、「極で安定性を見る」と言った考え方さえ押さえれば割と簡単に安定性を理解できると思われます。

これに対し、非線形制御における安定性判別の方法は非常に煩雑です。具体的には表題にある通り、<b>リアプノフ関数によって安定性の判別(以降、リアプノフ安定と呼称)</b>を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/4c461ed6-af8e-1efd-9cd7-820b24304e63.png)

リアプノフ安定の厳密な考え方については、下記の記事にて丁寧に解説されており非常に勉強になります。
[難しい，けど面白い，非線形制御（CLFによるアプローチ）](https://qiita.com/dro_ota/items/b080d16d8f53dce74772)

しかしながら現代制御に慣れ親しんでいない人にとって、リアプノフ安定はなんだかんだで理解に苦労するものと思います。

実際問題、私（古典制御屋さん）にとってリアプノフ安定はずっと前から<b>「単語は知っているが理解できないもの」</b>という認識でした。しかしながら、あることをきっかけにすんなりと理解できました。それが標題にある、<b>スライディングモード制御</b>経由で理解するという方法です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/d3a4d69e-3431-268a-2f8d-987fc21ecab7.png)



いきなり登場したスライディングモード制御ですが、これまた現代制御に慣れ親しんでいないと理解に苦しむものと思います。（詳細は記事 [「スライディングモード制御」](qiita.com/HppyCtrlEngnrng/items/0b8d6a31e5123ac71e01)を参照）

難しそうなものを２つも持ち出して大丈夫？　と思われるかも知れませんが、下記の理由からこのほうが却ってスムーズに理解できるようになるというのが本記事での主張となります。

<b>・スライディングモード制御とリアプノフ安定が密接な関係にあるため</b>

<b>・スライディングモード制御適用時はリアプノフ関数の候補が簡単に見つかる
　(というかほとんど一意に決まる)</b>

<b>・スライディングモード制御を経由することで、現代制御の入門（状態変数xの定義）からリアプノフ安定までが話の飛躍なく繋がるため</b>

なお本投稿における話の流れは下記となります、何気に大事。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/1867588c-2145-eda9-16db-1dd145c6315e.png)

また本記事の執筆に当たり下記の本を大いに参考にしております。
[森北出版　倒立振子で学ぶ制御工学](https://www.morikita.co.jp/books/book/3110)

…というか、この本のスライディングモード制御の章を読んでリアプノフ安定を理解できたので記事を書いた、というのが正直なところ。本当にオススメの１冊。


# 1. 状態変数x,および状態方程式を定義する

現代制御においては制御対象の入出力関係を１階の微分方程式にて表現、これを状態方程式と呼びます。（詳細は各自、制御工学の教科書を参照）
状態変数`x`はであって、一般に下記のように表わされます。

```math
x(t)=\begin{bmatrix}
x_1(t) \\
x_2(t) \\
\vdots 
\end{bmatrix}
\tag{1}
```
<b>ただし下記では、説明の容易性のため状態量`x`は２変数から成るものします。</b>

```math
x(t)=\begin{bmatrix}
x_1(t) \\
x_2(t) \\
\end{bmatrix}
\tag{2}
```
状態方程式についても本章にて定義しておきますが、４章まで殆ど言及しないのでここでは参考までに。
制御対象が線形の場合、状態方程式は一般に下記のように表されます。

```math
\dot{x}(t)=\begin{bmatrix}
\dot{x}_1(t) \\
\dot{x}_2(t) \\
\end{bmatrix}
=Ax(t) + Bu(t)
\tag{3}
```
ここで`A`,`B`はそれぞれ行列であり、`u`は制御入力です。
制御対象が非線形の場合の状態方程式は下記のように表されます。

```math
\dot{x}(t)=f(x(t)) + g(x(t))u(t) \tag{4}
```


# 2. スライディング制御の切替面𝜎(𝑥)=0を定義する

急に切替面の話が出てきて困惑すると思いますが、順を追って説明していきましょう。
まずはじめに、横軸を`x1`、縦軸を`x2`とした相平面を考えます。この相平面は<b>ベクトルである`x`を投影するための2次元平面</b>とも言えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/74cf085c-d75b-1247-7835-568b9ad943f0.png)


次に、状態変数`x`を入力とする任意の関数`𝜎(𝑥)`を下記のように定義します。
（切替面のための関数というより<b>一種の評価関数</b>と捉えたほうが理解しやすいです）

```math
\sigma(x(t)) = S^{T}x(t) \tag{5}
```

ここで`S`は下記にて定義するものとします。

```math
S=\begin{bmatrix}
S_1 \\
S_2 \\
\end{bmatrix}
\tag{6}
```

上記だとなんだかよく分からんので、`S1=1`、`S2=2`として`𝜎(𝑥)`を求めてみましょう。

```math
\sigma(x(t)) = x_1 + 2x_2 \tag{7}
```


スライディング制御における切替面は`𝜎(𝑥)=0`の条件となります。これを相平面に書くと下記。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/96bbe6cc-c087-f3f2-3199-01fe082c9136.png)



ここでの切替面`𝜎(𝑥)=0`は、状態量`x`が２変数であるため<b>『切替線』</b>になります。

なお切替線より上の領域では`𝜎(𝑥)>0`となり、下の領域では`𝜎(𝑥)<0`となります。このことを視覚的に表現するため、<b>相平面を２次元→3次元に拡張</b>、評価関数`𝜎(𝑥)`の結果を追加した１次元に示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/43d5ca55-e22d-2219-f85a-1c0a27213b56.png)

上記３次元図をZ軸方向から見た場合は下記。こちらのほうが話の流れとしては分かり易いかも。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/1f61fc4c-37cd-3e47-f711-4f91d05bc206.png)

状態方程式の段階では状態量`x`はただのベクトルでしたが、相平面および関数`𝜎(𝑥)`の定義を経て3次元空間での出来事として捉えられるようになりました。

# 3. リアプノフ関数V(x)=V(σ(x))を定義する

リアプノフ関数で躓く最大のポイントって、恐らく下記だとおもうのです。

>システムに対するリアプノフ関数を見つけることができれば，そのシステムの原点は安定である
（[リアプノフの安定性理論](http://www.gifu-nct.ac.jp/elcon/labo/endo-n/endo/lecture/syscon/node24.html)より）

<b>見つけることが出来れば</b>って、そう言われましてもどうすれば？と思いませんか。
実際問題、googleさんで「リアプノフ関数」を調べようとするとサジェスションの１番目に「作り方」が出たりするので、誰もが悩むところだと思うのです。

しかしながら冒頭でも記載した通り、<b>スライディングモード制御適用時はリアプノフ関数の候補が簡単に見つかる、というかほとんど一意に決まります。</b>

具体的にはリアプノフ関数`V(x)`として下記を用います。

```math
V(x(t))=V(\sigma(x(t)))=\frac{\sigma(x(t))^2}{2} \tag{8}
```

なぜ式(8)を用いるかというと、これにより<b>リアプノフ安定条件とスライディングモード制御の成立条件を一致させるため</b>です。詳しく見て行きましょう。

リアプノフ安定条件は下記式によって定義されます。

```math
\dot{V}(x(t)) < 0　(x\neq 0)  \tag{9}
```

では、実際に式(8)を微分してみるとどうなるでしょうか。

```math
\begin{align}
\dot{V}(x(t)) &= \frac{d}{dt}V(x(t)) = \frac{d}{dt} \frac{\sigma(x(t))^{2}}{2}  \\
&= \frac{1}{2} \frac{d\sigma(x(t))^{2}}{d\sigma(x(t))} \frac{d\sigma(x(t))}{dt} \\
&= \sigma(x(t)) \dot\sigma(x(t))  \tag{10}
\end{align}
```

一方で、スライディングモード制御において、状態変数xが切替面へと近づくための条件（スライディング条件）は下記式によって定義されます。詳細は [倒立振子で学ぶ制御工学](https://www.morikita.co.jp/books/book/3110) を参照

```math
\sigma(x(t)) \dot\sigma(x(t)) < 0 \tag{11}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/fe82b5f9-ea17-6721-62b2-229ca047bac5.png)


<b>式(9)、(10)および(11)より、スライディングモード制御におけるスライディング条件成立のための式とリアプノフ安定条件の式は一致します。</b>
冒頭で「スライディングモード制御とリアプノフ安定が密接な関係にある」と書いたのはこのためです。
上記からすると、スライディングモード制御＝リアプノフ安定を得るための手段と理解するほうが腹落ちが良いです。（あくまで主観、間違ってたらすいません）

次に`V(x)`を３次元空間に表現してみるとどうなるでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/17555f96-1c07-d3ca-0f70-016cb3f7baab.png)

<b>`σ(x)`が板状だったのに対し、`V(x)`は`σ(x)=0`の線を一番下にした状態で`σ(x)`を折り曲げたような形</b>になります。式(8)からすると当たり前の結果ですが、可視化すると非常に分かり易くなりますね。

念のためZ軸方向から見た場合は下記。`x`が相平面上のどこにいても`σ(x)=0`へと移動していきそうな感じがしますね！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/68fbde30-62db-56ea-f8e8-2875bb77be99.png)

ここまで来れば、後はおまけみたいなもんです。

# 4. リアプノフ安定条件を満足する制御入力を決定する

式(4)、(5)より下記を得ます。


```math
\begin{align}
\dot{\sigma}(x(t)) &= S^{T}\dot{x}(t)\\
&= S^{T}( f(x(t))+g(x(t))u(t) )
\end{align} \tag{13}
```

式(11)に代入した上で、少し式変形します。

```math
\begin{align}
\sigma(x(t))\dot{\sigma}(x(t)) &= \sigma(x(t)) S^{T}( f(x(t))+g(x(t))u(t) ) \\
&= \sigma(x(t)) [ S^{T}f(x(t))+S^{T}g(x(t))u(t) ]<0 \\
\end{align}  \tag{14}
```
`σ(x)`の正負によらずに上記満足する制御入力`u`を考えます。
まず、`u`が下記式の場合において式(14)の大カッコ[ ]内を0にすることが出来ます。

```math
u(t) = \frac{-S^{T}f(x(t))}{S^{T}g(x(t))} \tag{15}
```
分子にaを足してみましょう。

```math
u(t) = \frac{-S^{T}f(x(t)) + a}{S^{T}g(x(t))} \tag{16}
```

式(14)に代入すると…

```math
\sigma(x(t))a<0 \tag{17}
```
σの正負によらずに上記条件式を満たすためのaは下記となります。

```math
a = - K\mathrm{sgn}(\sigma(x(t)))　\tag{18}
```
`K`は`K>0`を満たす任意のゲイン、`sgn`は符号関数です。
改めて、式(11)を満足する制御入力`u`についてまとめると

```math
\begin{align}
u(t) &= \frac{-S^{T}f(x(t)) - K\mathrm{sgn}(\sigma(x(t))) }{S^{T}g(x(t))} \\
&= -\frac{S^{T}f(x(t))}{S^{T}g(x(t))} -\frac{ K\mathrm{sgn}(\sigma(x(t)))}{S^{T}g(x(t))}
\end{align} \tag{19}
```

式(19)を制御器として実装することで、スライディングモード制御が実現されます。

# おまけ　単振子のスライディングモード制御による立ち上げ
twitterに先行に貼ったものの流用になるので本当におまけですが。
別途記事作成するか悩み中。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">反時計回りを正として+2rad/sの初期速度を与えているのだけれど、この場合半時計周り→時計回りの軌跡で振り挙がる。一見すると妙な動きなのだが、リアプノフ関数V(x)は常に低下する方向に状態量が動いているという…<br>久々に「制御めっちゃ面白い！」と感じました。 <a href="https://t.co/hSTmxcKqQQ">pic.twitter.com/hSTmxcKqQQ</a></p>&mdash; モータ制御マン (@motorcontrolman) <a href="https://twitter.com/motorcontrolman/status/1345032809841270789?ref_src=twsrc%5Etfw">January 1, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

状態xが切替線上を動いて、最終的に上死点(x1=θ=0)に到達することが下図にて確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/8d487ab9-32a6-af99-c745-d9c6e40b3397.png)

下死点(x1=θ=π)を２回通ることは下記図のほうが確認しやすいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/302506/d7a00b2f-c9fc-3c3a-52df-85f6c8bf1400.png)



# おわりに

2020年の年末休み中に、せっかくの長期休暇だから勉強しよう！と思い立ち「[倒立振子で学ぶ制御工学](https://www.morikita.co.jp/books/book/3110)」を読んでみたところ、長年の個人的課題であったリアプノフ安定の理解を実現できました。

その感動を表現することを目的に本記事を書き始めましたが、記事化してみるとちゃんと説明できない部分がどんどん出てきて、その結果年末休みのほとんどをリアプノフ安定とスライディングモード制御の事を考えて過ごすことになりました。

<b>うん、我ながらいい年の過ごし方をしたな！</b>
ということで、本年もよろしくお願いします。