【SUPER HIGH LEVEL SIMULINK LESSON】SimulinkとStateflowをFusionさせてみた

![ezgif-3-1743b34d6be6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/da43b870-87fc-86a8-20bb-94e367d8ba47.gif)
#やあ （´・ω・｀)
ようこそ、バーボンハウスへ。
このテキーラはサービスだから、まず飲んで落ち着いて欲しい。

うん、「また」なんだ。済まない。
仏の顔もって言うしね、謝って許してもらおうとも思っていない。

でも、この項目を見たとき、君は、きっと言葉では言い表せない「ときめき」みたいなものを感じてくれたと思う。
殺伐とした世の中で、そういう気持ちを忘れないで欲しい
そう思って、この記事を作ったんだ。

じゃあ、注文を聞こうか。

## と見せかけて釣りではないです☆
この出だしで歳がバレますね！

SimulinkとStateflow組み合わせるとスッキリしたモデルがかけちゃったぜ！という記事です。
でもこの内容がSUPER HIGH LEVELかどうかは人によりますよね。すみません。そこは釣りと捉えられても仕方ないかもしれません。

SUPER HIGH LEVELはTikTokerのケビンさんがよく使ってるワードなので
ノリで使ってしまいました。

https://www.tiktok.com/@kevinthepepperoni/video/7013015403349675266?lang=ja-JP

## ノリかよ・・・なんだそれ・・・帰る
ま、まって！いやごめんて！でも、でもまぁ見ていってくださいよ。

# モデル説明
このモデルは2つの全く同じ動きをするサブシステムを持ちます。片方はsimulink、もう片方はsimulinkとstateflowを組み合わせて作ってあります(サブシステムの画像が違ってるのがわかると思います)。

それぞれのサブシステム内部にはCntModeの値に応じてPI・P制御を切り替える離散コントローラーと
超シンプルな１次遅れPlantモデルが入っていてループが組まれています。

scopeをみてみましょう。
正弦波指令値に追従させたいのですが、上段のグラフに示されているCntModeが０のとき、すなわち各サブシステム内部の制御構成がP制御のときには両方とも指令値に追従できていません。サブシステム間ではその挙動すら一致してます。

動き、ビヘイビアという面ではそれぞれのサブシステムはほぼ等価といえると思います。

![スクリーンショット 2021-12-01 15.32.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/55410bac-6331-6a7a-f4b8-0b7c423fd239.png)

## Simulink側のモデル中身
![スクリーンショット 2021-12-01 15.34.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/27995f14-2e41-68fe-a220-4c815b4c1f2a.png)

こんなのです。
なるほどCntModeでPIとPの出力を切り替えてますね。
でPIにはなんかフィードバックがついてますが、これは切り替えが有効になった際の積分値をリセットしているんでしょうね。

確かにP制御側が動いているときにPIの積分に蓄積される値はちょっと変な値になってる可能性があるので、
現在の制御量でリセットするのがまぁ無難な方法だと思います。

**でも僕思うんです。
確かに動いているがぱっとみその設計意図や切り替えシーケンスのイメージが掴めますかね？
ちょっとわかりにくいと思いませんか？**

## SimulinkとStateflowをフュージョンさせてみた

![ezgif-3-128625389e94.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/d7fcea53-8482-07be-5177-ef13ec9a1a6c.gif)

一方SimulinkとStateflow両方使った方は？おや何か一つのChartにまとまってますね。
そしてStateflowのステートの中にSimulinkモデルが入ってます。
これはだいぶSimulinkとStateflowがフュージョンしてるぞ！

# 解説
フュージョンしてるほうはStateflowのSimulink StateとSimuink Functionという機能を使ってモデリングしています。

そして、状態をUpdateするのにState Writerブロックを使っています。

実は、これらの機能を使ったHelpドキュメントとサンプルがあるので、
皆さんこちらでこれらの機能をためすことができます。

https://jp.mathworks.com/help/stateflow/ug/about-simulink-states.html

## Simulink State
![スクリーンショット 2021-12-01 16.05.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/5e849238-b11b-b800-923e-9cc232b3effa.png)
Stateflowの編集画面の左側、パレットと呼ばれる部分のSimulink ステートボタンを押すと作ることができます。

で上の図の左側にある2つの丸みを帯びた四角。これがSimulink ステートです。


通常Stateflowの各状態はMATLABもしくはC言語を用いて処理を記述しますが、
なんとSimulinkブロックで処理をかけるんです。
このブロックではPI、PそれぞれのロジックをSimulinkで書いています。

PIなどはMATLABでもかけますが、「時間応答に対する処理はSimulinkで書きたい！」という人もいるんじゃないでしょうか？そういうとき便利ですね。

## Simulink Function(Simulink関数)
![スクリーンショット 2021-12-01 16.08.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/591ddec9-e96a-650d-7750-6c2582714c45.png)

Stateflowの編集画面の左側、パレットと呼ばれる部分のSimulink 関数ボタンを押すと作ることができます。

この上の図の右側の四角いやつがSimulink関数です。

このStateflowブロックを見るとP_Controllerから PI_ControllerまでのPathに
Reset_State(CntOut)という処理が記述されています。

実はSimulink Functionは関数としてSimulinkの処理を記述できる機能なのです。
そして引数として指定しているCntOutはこのブロックの出力値になっています。
はい、Stateflowで使用できる変数、（入力、出力ポートの変数含めて）利用ができるんです。

これで、Simulink側では出力値をフィードバックする記述をもっと簡潔にかけています。
CntOutを引数にして　Simulink関数内部に値を渡して、PI_Controllerの状態を上書きするという処理を書いているのです。stateflow内部の四角いブロックがsimulink関数です。

この処理がP制御からPI制御に切り替わるタイミングで実行されることがわかります。
状態遷移のタイミングで実行される処理をSimulinkでかけるのも良いですね。

## State Writer
https://jp.mathworks.com/help/simulink/slref/statewriter.html

こちらのHelpに記述があるのですが、なんと状態を上書きするための入力ブロックになってます。
これ、Simulink ステートとSimulink関数ブロックをまたいでも有効なんです。

このブロックの作り方はとってもかんたん。
**状態を持ってるブロック（積分ブロックとかUnitDelayとか）を右クリックドラッグするだけ**

![ezgif-3-f830eab18ad2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/02355351-bfeb-2f2e-00b2-cf5327a4210f.gif)
通常のドラッグと違い右クリックでドラッグしてくださいね。
そうするとState Reader / State Writerの選択肢がでますのでお好きなものを選んでください。

お察しの通りState Readerは状態を引っ張り出してくれるブロックです。
このブロックを使えば好きなタイミングで指定したブロックの状態値を取り出したり、上書きしたりできます。


## 使うことのメリット
なんといっても設計意図、動作のイメージをモデリングの図からイメージしやすいというところがあるのではないかと思います。
ちょっとここは人によって意見が別れますが、Stateflowは切り替わる状態をStateで表現できるので
ぱっとみたとき、「あーこのブロックは条件によって２つの状態にきりかわるのだな」ということがすぐわかります。

また、状態の上書きなどの処理は大体遷移のタイミングで実行したいことがあるのでそういう時にはsimulink関数とstateflowのフュージョンが便利です。

そして切替条件はStateflowで書いて、処理はSimulinkで書きたいというわがままを叶えてくれるのがこの書き方です。
![ezgif-3-1743b34d6be6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/696bd4e2-2090-217a-e79b-aa3a664157c9.gif)

#まとめ

みんなもこのモデリングを試してみてSUPER HIGH　LEVELになろう！