SimscapeでPWMモデルを作りたい

はい。この記事もマニアックですよ。完全にオタクのひとり語りです。いいんですね？　

はい！ありがとうございます！お付き合いくださいね！

# PWMとは
パルスワイドモジュレーション、すなわちパルス幅変調のことで、一般的には固定周波数で駆動する矩形波のパルス幅を変更する変調方式である。

今回はSimscapeでPWMを作りたい

# 既存のライブラリがあるのでは？

ある。が。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/318bff62-f557-5f51-e933-df1aa599ee65.png)

PWMは使用するマイコンのペリフェラル性能によっても色々違ってくるし、PWMキャリアに同期した処理実行をしたりしたいといった細やかな設定をしたい場合標準のPWMライブラリはシンプルすぎることもある。個人的には。
とくにパワエレはペリフェラルで結構振る舞いが決まるところもあるので大切だ。

とくにキャリアと同期したADCはとっても重要で・・・
というのは前回[こちら](https://qiita.com/griffin921/items/a04de4a4b380091ddf15)で語ってるので省略する。

あとモデルはこちらを参考にした。

https://github.com/mathworks/adc-synchronized-with-pwm

# いろんなPWMモデル

まず最初に結構抽象度が高い、けっこう重そうなモデルを作ってみた。

## Simulinkでゴリゴリ細かくモデリング

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/a972f4af-27cd-b192-d642-674dc9285ade.png)


大体マイコンはPWMを作るときにタイマと呼ばれるモジュールを使う。タイマーはクロック周期を分周したりして作ったカウントタイマ周期で１つずつ値を増やし、ある値でカウントリセット（アップカウンタ）、もしくは１つずつ減らす（アップダウンカウンタ）という振る舞いに切り替える。

このモデルでは左下の黄色いサブシステムが　クロックをもとにアップダウンカウンタを実装している。

左上のほうではDuty値をタイマカウント値に変換している。そのあとで、タイマカウント値としてデットタイムを挿入している。
そして、Duty比に相当するタイマカウント値と、黄色いサブシステムが作るキャリアに相当するカウント値を比較して、大小関係が反転した地点で切り替えている。

この辺もマイコンの中身で表現されるふるまいとなるべく一致させるようにしている。

### なぜここまで表現する必要がある？

PWMモジュールの入力としてDuty比(0~1のdouble)がはいってくるようになっている。しかし現実のマイコンはDoubleの0~1の値を投げたらいい感じにパルス作ってくれるようなやつではない。
（ここらへんは各社が用意しているAPIにもよるきがするが、世界中のマイコンについて知ってるわけではないので嘘ついてたらご勘弁いただきたい）

基本Intでタイマカウントアップをしてるし、何ビットのタイマであるかによってPWMの分解能が決まってくる。
その辺がずれているとMILで動かした挙動とRCPの挙動が違ってくる。

まぁそこまで細かく一致させる必要ないよねって場合でも、マイコンのAPIがPWMを”タイマカウント値”を引数とする場合、結局Dutyをそのマイコンのタイマビット数に合わせた変換をしないとだめになる。

もし、モデルからコード生成をする場合でも、モデルの最終値をDuty比にしてしまうと、ハンドコードでDuty→タイマカウント変換演算を書くハメになる。なので細かくモデルで書いておいた方がいい。そうするとその後モデル→コード生成をするときに生成されたコードの最終出力をPWMタイマのAPIにそのまま渡すだけでハンドコード部とリンクができる。

### 絶対ここまでやらないとだめですか

「タイマカウント周りの変換はハンドコードで書けばいい」と割り切るならここまでやらなくても問題ない。
ハンドコードで設定されているペリフェラル性能と、MILのPWMモジュールモデルの性能にずれがあると挙動の一致性に問題が出てくる可能性があるが、タイマクロック水準までモデルで作り込んでしまうとめちゃくちゃシミュレーションが遅くなる。

ここらへんは一長一短なので必要に応じて切り替えが要ると思う。

## Simulinkでライトに書く

タイマカウント周りは厳密にはIntで書くのが妥当だが、まぁそこらへんの細かいパルス分解能精度は気にしなくていいというのならこんな感じで書いても差し支えないだろう。基本的にほぼ全部Doubleで演算している。
Data Type Convertionが入ってるのは　比較器の出力がBooleanであるため、Doubleに変換した後15を乗じることで15VのPWM信号を作ってるというだけである。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/0d711437-5bf8-5fa0-c5fe-9a04a3ce496e.png)

こちらのほうが見た目わかりやすい。
キャリアの山と谷を検知してパルスを出してくれる機能もある（モデル下側）

これを使えばキャリアの山、谷のタイミングでS&Hして欲しいと言ったモデルも下記の通り簡単に作れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/feaa24f1-c506-4a77-6b60-3e6bac36e96b.png)

### ライトなSimulink PWMモデルの欠点
ではこのSimulinkで作ったライトなPWMモデルでバックコンバータを動かしてみよう。

バックコンバータは入力と出力の電圧を電圧源で固定し、電流制御している。スイッチング周波数は40kHz。さでどうか。

![B53CEBCF-E245-4C64-8C67-8A06BC3F6539.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/1ca5f015-b1be-e827-6020-a2463b35b0c4.gif)

ま、まぁまぁ速いのでいいが、キャリアの波形が歪んでいるのがすごく気になる。（真ん中　紫のグラフがきれいな三角波形になってない）
これは可変ステップソルバが「ここ、ステップ幅荒くてもシミュレーション結果あんま変わらないからこんぐらいの精度でOKでしょ！」と判断しているためである。ちなみにこのときはode23tを使用した。

ちなみにode15sにしてみるとこうなった。なんじゃこりゃ。簡略化しすぎだ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/9aa620e4-7c27-20a2-4abd-98a53c02128e.png)


せめて多少実行速度が遅くなってもキャリアはちゃんと表現してほしい。

このキャリアが歪まれると正確なPWM幅を表現できない。
じゃあキャリア変調せずにDuty幅から直接パルスを作ればよいだろうということになるが、そうなるとキャリアと同期したADCタイミングを実装しにくくなる。

## SimscapeでPWMモデルを作れば？

そこで筆者はひらめいた。Simscapeで作ればどうなる？
なんか変わるのだろうか？　
根拠はない。
思いつきだがやってみた。

これがそのモデルである。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/66edf3fb-f733-1e25-1dd8-d3a51b207fe6.png)

あまり知られていないが、Simscapeには「物理信号モデル」というなんか基本の数値演算をするSimulink的なブロックが備わっている。

https://www.mathworks.com/help/simscape/physical-signal-manipulation.html;jsessionid=7aad48e54f65310be80133821c93

四則演算はもちろん積分器もある。Simulinkの基本ブロックのラインナップと完全互換とは言えないが大体基本的なブロックはそろっている。
ライトのSimulinkPWMモジュールは結構Simulinkの基本ブロックのみで作ったので　ほぼ写経する形でSimcaspe 版が作れた。

さっき簡略化されすぎてだめだったode15sで動かしてみよう。

![1A0528A3-37E3-4A8B-8B7D-54DE626EF900.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331637/f134500a-8383-7042-157e-2de0bcabcedf.gif)

お、さっきより遅いがキャリアはちゃんと表現されている。

# なんでこんな結果になるんだろう

正直分からない。ただ、SimscapeはSimulinkと違って非因果モデリングという手法を取っている。因果系と非因果系のちがいはGoogle先生に教えてもらったこの記事とかを参考にしても良いかと思う。

https://otepipi.hatenablog.com/entry/2021/05/16/210855

同じソルバーでといたとしてもモデルとしての定義が異なるとソルバー側の解釈が変わるのだろう。
また、因果系のSimulinkはあくまで式演算をしているため、PWMのキャリア表現が荒くなったときの物理モデルに対する影響度といような意味的なところまで考えてステップを切ってくれない。

SimscapeでPWMモデルを作ると、Simscape　Electricalで構築された回路モデルと合わせて「非因果モデルとして」演算がされるのでちゃんと回路への影響度を含めてステップを切ってくれるかなと思ってる。

これにちゃんとした回答をつけるには結構調査が必要な気がするので今回はこの程度でとどめて　もしなにかわかったら（かつ気が向いたら）続きを投稿しようと思います！

# おわり