Simulink® 物理モデル(water tank)とバルブ制御回路を Intel® FPGA に実装 "model in FPGA"

## はじめに
最近の Revision の **Simulink®** には watertank というサンプルモデルが用意されていて、非線形の制御対象に対する PI 制御の例として参照することができます。

https://jp.mathworks.com/help/slcontrol/gs/watertank-simulink-model.html

このサンプルモデルでは、PI(D) コントローラが制御機器を、Water-Tank が実際の物理現象を表しています。
構成ブロックはゲイン(定数乗算)、加減算、積分(1/s)、平方根で、連続時間積分を離散遅延(1/z)に置き換えると、HDL を生成する **モデルベースデザイン(MBD)** 環境で容易に HDL 化できる様な構成になっています。
物理モデルを制御回路と同様に HDL 化して同時に **FPGA** に実装することで、モデル全体のエミュレーション（感覚としては実機ハードウェアによるシミュレーション）を FPGA で行えるようになります。図にしてみると下記の様な形になります。
![001b_ModelInFPGA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/96547b8d-0897-2dbd-caf4-510ffbaa659b.png)

実際に FPGA で動作させるためには、フィードバックループによる問題など解決が必要な課題があります。
今回、**DSP Builder** for Intel® FPGA (以下 DSP Builder) でモデルを制御対象を含めてハードウェア化して動作させてみましたので内容を紹介します。

#### (背景)
筆者はディジタル回路の設計を Verilog HDL 記述や DSP Builder を使って行っています。
DSP Builder はややマイナーかもしれませんが、Mathworks® 社の HDL Coder(TM) の Intel 社 FPGA 専用版と考えて良く、Simulink モデルの形でモデルベース設計(MBD)を行うことができます。

なお筆者は直接には制御システムの担当ではありません。そちらの担当者から 2 年ほど前相談されて、試しに watertank モデルを題材に、DSP Builder で代理店の資料を参考にして作った結果が、今回の内容となります。
（ただし、今回は新しい version で試しています。）
その後の開発には採用されなかった為、実際の製品レベルでのチューニングや諸問題への対応はできていません。コンセプト的なサンプルにとどまる点はご了解ください。

（今回 Intel 社より Advent Calender 投稿のお誘いを受けましたので、問題ないか再確認して投稿させていただきました）

まず簡単なモデルでやってみて本質的な課題や DSP Builder の特性上工夫が必要な部分を提示することが本記事の主眼となります。（後半で少しその辺りの考察を試みてみます）

#### (作業のポイント)
作業の概略の流れとしては下記になります。

0.事前準備：ツールインストール、FPGA ボードの準備
1.Simulink モデル(watertank)の離散化と詳細化：連続時間モデルを離散時間モデルに変換、ブロックも HDL 化可能なレベルまで低レベルに分解
2.DSP Builder 移行：DSP Builder で HDL 化するためブロックを置き換え（＋固有の設定などのブロックを追加）
3.動作用調整：ループに関連する問題の対策、初期値設定機能の追加
4.実機動作確認：DSP Builder で FPGA HW 化し、実動作させて Signal Tap で信号を確認（デバッグを含む）

## 事前準備
今回使ったツールと version や Hardware 情報は下記になります。
- DSP Builder モデル作成作業
Mathworks® MATLAB®/Simulink® : Version R2020a
DSP Builder for Intel® FPGAs Pro Edition : Version 22.2
仮ターゲットデバイス：Cyclone IV E (speed grade -8)
- HDL compile 作業 （ DSP Builder から起動, QUARTUS_ROOTDIR に設定）
Intel® Quartus® II Subscription Edition : Version 13.0
ターゲットデバイス：Cyclone II EP2C20F484C7
- プログラミング＆Signal Tap 動作確認用
Intel® Quartus® Prime Standard Edition : Version 18.1
FPGA board :  Cyclone II Starter Board
![006h_Env_and_Flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/44ebc2a3-816e-e66c-c5c6-634cfa011ab6.png)

上記のツール、ボードが図の様なフローで連携して動作する様に準備、インストールしておきます。
DSP Builder から Quartus Prime (または Quartus II) をする為には、環境変数 QUARTUS_ROOTDIR に install パスを設定しておきます。

最近の Low Cost Device ならば普通に Quartus Prime Standard v21.1 で良いと思いますが、都合により Cyclone II Starter Board を利用する事になったので、DSP Builder (v22.2 pro) でサポートされている Cyclone IV E と、サポートされていない Cyclone II の両方を扱える Quartus II v13.0 を使用しています。
Cyclone IV E ターゲットでモデル・VHDL を作成し、Quartus 上でターゲットデバイスを Cyclone II に切り替えてコンパイルしています。10 年近く差が出ていますが少なくとも今回のデザインでは問題なく連携できています。（内部メモリが違うというデバイスの違いによる warning などは出ましたが、吸収してデザイン作成できています）
Board に接続して SOF を書き込み、Signal Tap で信号を見る作業は、別の PC 上の Quartus v18.1 で行いました。

#### (DSP Builder 対応 version について)
最近の version での DSP Builder の Low Cost Device サポートについて触れておきます。(なお Advanced Blockset の場合です）
- version 19.1 まで：Quartus Prime Standard で対応、DSP Builder をインストーラーに含む
- version 20.1 ～：Quartus Prime Standard には DSP Builder を含まない（非サポート）
- version 22.1 ～：Quartus Prime Pro 対応の DSP Builder で Low Cost Device (Cyclone IV E 等)もサポート
（Cyclone V は v21.4 Pro から対応）（HDL コンパイルは Quartus Prime Standard を呼び出し）

v20.1 から DSP Builder が Quartus Prime Standard Edition でサポートされなくなり Pro Edition のみとなった為、Low Cost Device に使えない状況が生じていました。困ったなと思っていましたが、最近の v22.1 で変則的ですが Low Cost Device が使える様になったという事になります。

Quartus Prime Pro Edition のライセンスを持っていなくても、DSP Builder をもっていれば、Pro Edition の installer のDSP Builder を使って Cyclone IV, V や MAX10 等の Low Cost デバイスをターゲットに VHDL が生成できます。そのコンパイルは QUARTUS_ROOTDIR で設定した Quartus Prime の Standard Edition でやる様になっています。

参照："DSP Builder for Intel® FPGAs (Advanced Blockset) Handbook" （以下 "Handbook"）

https://www.intel.com/content/www/us/en/docs/programmable/683337/22-2/faq.html

## Simulink モデル(watertank)の離散化と詳細化
watertank モデルは連続時間なので、FPGA 内で動かすために離散時間に変換します。誤差が生じる可能性はありますが今回は許容するものとして先に進みます。（連続時間のまま、ソルバをHDL 化する様な仕組みがあれば誤差がより少ない実装が可能と思いますが、特に無い様です）

Simulink のアプリ → モデルの離散化を実行するか、ブロックの設定やタイプを離散時間に変更してモデルを離散化します。
シミュレーション入力は Signal Builder で生成する様にしましたが、連続時間出力しか設定がない様ですので、ゼロ次ホールドを挿入して離散化します。
サンプル時間を変数 Ts で扱う事にして、各ブロックのパラメーターに設定します。

![007b_convert_discrete_w_Integrator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/e3987569-180e-000a-293f-2134fc1f6510.png)

離散化された PI コントローラーやプラントモデル内の積分ブロックは対応する DSP Builder ブロックは無いので、計算式を対応するブロックのあるもので置き換えます（詳細化）。

積分のゲインには Ts を含む(掛け算する)必要があるようですので注意してください。（代理店の資料ではこまごまと比較確認しながら少しずつ置き換えて行ってます）

## DSP Builder 移行
DSP Builder で HDL 化するためブロックを置き換え（＋固有の設定などのブロックを追加）をおこないます。

![008_PI_controller_DSPB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/1ad8dec0-a6d1-adb3-57ec-459d6e63b5ad.png)

例えば PI コントローラーは図の様に DSP Builder のブロックで置き換えます。Gain, Add, Delay はそのまま置き換える形ですが、フィードバックループについてはエラー防止の為の工夫が必要です。（次のセクションで触れます）
Water-Tank についても同様に行っています。

DSP Builder の場合パイプライン挿入を行って HDL 化しますので、その為の処理単位になる Primitive Subsystem を構成します。ChannelIn, ChannelOut (または GPIn, GPOut) ブロックを通して Subsystem から入出力する様にします。
（このあたりは DSP Builder Handbook を参照してください）

制御分野のキャリア周波数(例：1kHz)で動作させる為にイネーブル制御を行いますので、Delay は "latch_1L" ブロックを使用し、valid 信号を enable 端子に接続しています。

## 動作用調整
ループに関連する問題の対策、初期値設定機能の追加を行います。

今回 watertank モデルを詳細化まで行った段階で４つのループが見えてきます。全体のフィードバック制御の為のループ、Water-Tank モデル内の平方根を含むループ、２つの積分回路です。
ループでは下記の３つの問題が起こることがあるので、それぞれ配慮が必要です。

- 代数ループ(algebraic loop)エラー
遅延を含まないループを形成すると、このエラーが発生します。信号として直接ループになっていなくても、Subsystem の構造などで形式的にループになっていると疑似代数ループとされて生じる事もある様です。（詳細は下記 Mathworks のページで説明されています）
今回は遅延挿入で回避しています。

https://jp.mathworks.com/help/simulink/ug/algebraic-loops.html

- データ型不明（＋固定小数点数の場合 Bit Growth）
積分回路の様な構成で、入力とフィードバック値を加減算するブロックで、入力にデータ型を合わせる様に構成（型の伝播）ができない為に発生します。対策としては SameDT ブロックを使用して型を伝搬させて指定します。（SameDT を使いたくない場合は個々のブロックで設定するより無い様です）
Simulink にもありますが、DSP Builder ブロックの部分では DSP Builder のものを使用します。（下図参照）
なお今回データ型は単精度浮動小数点数(single)を使っていますので Bit Growth の問題は回避しています。
- 遅延時間（見積もり）不足
こちらは DSP Builder 固有の問題で、パイプライン挿入のための遅延時間見積もりに起因する様です。積分回路は Delay (1 clock) と加算器でループが形成されるので、追加のパイプライン挿入が出来ないところになり、遅延時間が足りないという判定になってしまう様です。
実際のクロックを 1kHz まで下げるとさすがに動作すると思われる場合も、加算器などに固定のレイテンシ(サイクル数)が設定されているのか、エラーとなる場合があります。（デバイスにもよる）
![008b_PI_controller_DSPB_loop_control.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/34a9fc70-eca7-4d2c-e05d-c8dd2cb83337.png)

こちらの対策は、ループに遅延を挿入する方法もありますがその場合計算の整合性をデータのフェーズ(channel, valid)で管理する必要があります。今回は下記の方法を取っています。

データの流れに配慮しつつループに遅延を追加する１つの方法としては、クロックより十分レートの低い valid 信号（間隔が長い、キャリア周波数相当）で主要な部分の動作を制御し、自動または手動で挿入した遅延は valid の間隔よりは十分短い様に作る事です。

全体のループにせよ、局所ループにせよ、valid 信号毎にループの前段から入ってくる入力に同期して正しいタイミングで更新できればよいので、実質的にはループに追加の遅延が無くとも動作するはずです。

上の図は PI コントローラ部分の調整結果ですが、図では赤で結んだ GPOut -> GPIn の接続で遅延時間見積もり上はループ扱いを避けています。Simulink 上はループとして扱われていると思いますが Delay が入っているので代数ループエラーにはなりません。
GPIn - GPOut 間のパスなどでレイテンシの挿入は行われますが今回は "0" つまり挿入なしで良いという判定になっています。

これで、クロックより周期の長い Ts 毎に1クロックの valid でイネーブルとなり計算結果が更新されていきます。
全ての部分の説明は省略しますが、全体および局所的に上記のループ対策と下記の初期値機能追加を行って、調整は完了です。

#### (初期値機能の追加)
Water-Tank の積分器は元のモデルでは初期値 (1.0) を持っていますが、DSP Builder の Sample Delay は初期値は 0 固定となっているので、初期値設定機能を用意しなければなりません。

DSP Builder の Latch 1L ブロックはマスクの中を覗くと sample delay と MUX のループでイネーブル機能を実現していますが、それを応用して初期値機能を持たせたカスタムブロックは下記の様になります。

![009_Initializable_Latch_1L.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/710df888-cac9-d89a-41d2-ed925839c4a0.png)

入力 d が伝わる mux, UnitDelay で構成された下段部分が元の Latch 1L 機能の部分です。
初期状態～最初のイネーブルが入力 e に入るまでは、出力 q は入力 init_value の方が選択される様になっています。

## 実機動作確認
調整完了した DSP Builder モデルから FPGA ターゲットの VHDL を生成し、FPGA デザインに取り込んで実動作させ、Signal Tap で信号を確認しました。下記の様なデザイン＆作業環境です。

（もちろん実際には調整不足の部分が有ったりしますので、値を確認しながらデバッグを進めていくことになります。）

![010_Board_and_Design.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/a84d1573-e84d-74f1-ffd1-ed791e4fc120.png)

Simulink の Signal Builder 部分は直接 DSP Builder モデルに移植しなかったので、同等の波形生成を Verilog HDL 記述で作成しています。またモデル部分は浮動小数点数(単精度)ですが、Signal Tap での表示もしづらいので確認用デザインでは固定小数点数で扱っています。（32bit, 小数部24bit なので指数レンジが狭いだけで精度は十分とっています）
![011_CompileResult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/65769b3a-0e3e-9432-65c2-f43db5a55686.png)

Cyclone II と古い世代ですので、さすがに内蔵メモリが少な目でそのままでは Signla Tap で十分な波形が取れないため、波形生成と並行して周期 Ts のさらに 10/100/1000 倍の周期のパルスを生成し、そのパルスの時だけデータを取得する様に Signal Tap の Strage Qualifier 機能を用いて間引きを行っています。これで確認としては十分な期間が確保できました。
コンパイル結果は上の図の様になっています。さすがにロジックも半分以上消費しています。動作クロックは、モデルでは 1MHz に設定しマージンを +9MHz 持たせて、実機では 10MHz となる様調整しています。（10倍速動作させるため）Timing は十分とれています。

動作させ波形確認したところ、Simulink の動作波形と一致する波形が得られました。
![003b_waves.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2270053/dfadda27-0f98-1a30-643a-92f0aa021c5c.png)

後で考察する土台となる、今回の watertank モデルとそれを DSP Builder モデル化し、実機で動作させた時間について確認結果を示します。
- シミュレーション対象時間：10 秒
（サンプル周期 Ts = 0.001 秒、 10,000 サンプル分）
- Simulink 実行時間（離散化したもの、詳細化前）：約 1.24 秒
- DSP Builder モデルの Simulink 実行時間：約 5700 秒 (1h35m)
（1MHz クロック動作ステップ x 10秒 = 10,000,000 サイクル分）
- 実機動作時間：1 秒
（10MHz で x10 の加速動作となる為）

今回の方法でどれだけ時間を加速/節約できたかを考えるのに、上記のどの２つを比較するかで話が異なってきます。
ここはシンプルに、DSP Builder モデルで 5700 秒かかっていた計算が実機で 1 秒で出来る、と考えると 5700 倍高速に処理できる、という事が出来ます。

## 考察
#### (モデルベースデザインについて）
モデルベース"開発" の MBD は、システムの開発・検証をモデル記述を骨格として行う手法で、V 字プロセス(フロー,モデル)と組み合わせて行われることが一般的になっています。
Simulink モデルを HDL 化するモデルベース"設計" はハードウェア化される部分を HDL Coder や DSP Builder を使用して実装する設計方法を指し、V 字プロセスでは主に開発工程の HW 化対象部分を指しています。

(V字プロセスの図、当たり障りのない英文ソフトウェア開発版)

https://en.wikipedia.org/wiki/V-Model_(software_development)

今回の記事の内容は、きっかけとしては water tank モデルを制御と物理モデルの２つに切り離して HW 化部分とテストベンチに分けるのがかえって面倒（複雑化）と考えて一緒に HW にしたことです。

発想としては、ディジタル回路の設計者ですので物理モデルを取り込むというより、本体（制御）部分の HDL の検証をするのに、シミュレーション用のテストベンチのテストベクタ部分をパターン生成回路にして合成・HW 化対象部分に取り込む感覚に近いです。
（テストベンチ、テストベクタを手作業で管理するのが面倒くさい場合に選択する方法です...）
実機で切り替えて動かす場合は BIST (Built In Self Test) になります。

モデルベース"開発" としては、開発工程側で制御対象の物理モデルも一緒に HW 化対象として FPGA 上で動作させることにより、モデルのシミュレーションを加速する手法になると思います。
用語の定義や微妙なニュアンス、検証工程との関係性で該当しないかもしれませんが、MILS・RP(Rapid Prototyping)・Virtual System・Digital Twin の一形態と考えて良いかもしれません。

メリット・デメリット（コスト）は、モデルシミュレーションを高速化できるが、物理モデルを HDL 化する作業は必要となり（DSP Builder を使う場合はさらに変換など必要）、また機材として FPGA ボードを使うという事です。
モデルの大きさや必要な精度によって、そこそこ高性能・大容量の FPGA が必要になるかもしれません。逆に言えば、今回元の Simulink シミュレーションも1秒程度で出来ていたので問題ありませんが、モデルの規模が 1000 倍になってしまうと同じ PC では 1000 秒で 10 数分もかかる様になってしまいます。
今回 10,000 LE 消費している様ですので、さすがに 1000 倍を直接収容する FPGA はまだ無いですが、ハイエンド FPGA で 100 倍は収容可能なものもありますので、並列に動作させて実行時間は 10秒で済むかもしれない、ということです。

今回、実際にやってみて、結構手間がかかったのは、入力のパターン生成や出力結果の観測方法も当然なにか自前で用意しなければならない事です。FPGA ですので、入力パターン生成も結局 DSP Builder モデルか HDL 記述でつくらないといけません。（または組み込みプロセッサ等を利用）
観測は Simulink 環境でのシミュレーションの様に Scope 等の GUI が無く、Signal Tap が１つの現実的な答えになりますが、やはり Scope 程気軽に使えない面もあります。自作部分はそれなりにデバッグも必要になります。

今回のアイデア自身は特に新しいものではなく、FPGA アクセラレータとして用意されている製品もありますし検索するとやはり似た様な発想の試みが 10 年近く前でも見られます。(論文など)
ただ、たまたまかもしれませんが、まだ身近で FPGA アクセラレータカードや開発キットでソフトが早くなった、という例を見たことがありません。調べるとスパコンとかデータセンターとか直接一般ユーザーが触らない様な分野向けが中心で、例えば手元の PC の Simulink が FPGA カードのおかげで早くなった、という様な例は、本気で調べていないだけかもしれませんが、見たことがありません。アプローチとして Soft の一部を高位合成で FPGA にオフロードする、という方法がとられると思いますが、まだ汎用的にうまくいく例は無いのかもしれません。

今回の試みはその辺り、例えば通信とかアクセラレータにオフロードする部分の分離、コーディングなどは考えることなしに、「すっとばして」モデルをほとんど丸ごと FPGA に入れてしまう様な方法になります。
最低限の環境「あるレベルでライブラリを絞った Simulink モデルに落とし込まれていれば、DSP Builder を使ってハードウェア化できる環境」、は用意できているという例です。
ただし上に述べたように、手軽に入出力を用意・観測するには環境が cheap で、その様なコンセプトの製品などが出てこない限りは、FPGA ハードウェア設計・デバッグ環境の応用で何とかするしかない様です。

#### （その他の考察）
時間的な制約で今回の考察はここまでですが、下記の発展性または追加の考察が出来ないか考えています。
また機会があれば掘り下げて見れたらと思っています。
- FPGA を使った「実機シミュレーション」の加速
（クロックアップ、無駄なリソースと待機時間の省略など）
- 今回の様なモデル構築のための便利なカスタムライブラリの作成
- FPGA を使ったアクセラレーションの１方法としての位置づけ
（物理モデルのエミュレーションや HILS 接続が FPGA 内部に取り込めるが、GUI など環境は cheap）
- 非因果モデル(マルチドメイン物理モデル)への対応
（因果モデルへの変換の話でかなり難しいかも）

## まとめ
watertank モデルを制御対象の物理モデルも含めて DSP Builder で HDL 化し、FPGA ボードで動作させることができました。

大規模なモデルに対し大規模な FPGA のボードを使用することで、Simulation 時間の削減が図れる可能性があります。

ご閲覧ありがとうございました。

（文中に記載されている会社名、商品名は各社の商標または、登録商標です。）