HILシミュレーションに動的な系を埋め込む
はじめに
HIL(ハードウェアインザループ)シミュレーションは,物理系の数学モデルを使った実時間環境のシミュレーションである.これは費用や安全性の理由で物理系が利用できない場合に特に便利である.シミュレーションが実時間であるため,数学モデルの忠実度が十分であるなら,制御器または人が実質的に物理系とインタラクトすることになる.HILシミュレーションの一般的な適用先としては,実際の物理系を制御する制御器の配備前の検証,物理系の解析,訓練等が挙げられる.
このプロジェクトでは,Arduino Microマイクロコントローラボードに2槽タンク系非線形モデルを配備する.系の入力は上のタンクへの流入流量である.これは液面レベルを制御し,これを出力と考える.流量の調整にはポテンショメータが使われ,液面レベルはSerial Over USB信号として出力される.これはデバイスフレームワークを使って読み取ることができる.これで2槽タンク系の動作が実時間でシミュレーション,解析できるのである.
電気配線
ポテンショメータのワイパーターミナルをピンA0に,ターミナルの一つをGNDに,もう一つを5Vに接続する.
Arduino Microはmicro USBケーブルでコンピュータにも接続しなければならない.
数学モデル
2槽タンク系において,上のタンクへの流入は,両方のタンクの液面レベルの制御に使用される.
系の物理パラメータ.
pars = {𝒸 -> 0.7, ℊ -> 9.8, Subscript[𝒜, 1] -> π 4^2, Subscript[𝒶, 1] -> π 0.25^2, Subscript[𝒜, 2] -> π 3^2, Subscript[𝒶, 2] -> π 0.25^2, 𝓆 -> 1};ベルヌーイ(Bernoulli)の定理と物質収支を使って結果の微分方程式を求める
eqs = {Subscript[𝒜, 1]Subscript[𝒽, 1]'[t] == 𝒬[t] - 𝒸 Subscript[𝒶, 1]Sqrt[2ℊ Subscript[𝒽, 1][t]], Subscript[𝒜, 2]Subscript[𝒽, 2]'[t] == 𝒸 Subscript[𝒶, 1]Sqrt[2ℊ Subscript[𝒽, 1][t]] - 𝒸 Subscript[𝒶, 2]Sqrt[2ℊ Subscript[𝒽, 2][t]]};定常状態の動作値
を使う.
Simplify[eqs /. {Subscript[𝒽, 1][t] -> (𝓆^2/2 𝒸^2 ℊ Subsuperscript[𝒶, 1, 2]), Subscript[𝒽, 2][t] -> (𝓆^2/2 𝒸^2 ℊ Subsuperscript[𝒶, 2, 2]), 𝒬[t] -> 𝓆}, Subscript[𝒜, 1] > 0 && Subscript[𝒜, 2] > 0 && Subscript[𝒶, 1] > 0 && Subscript[𝒶, 2] > 0 && 𝒸 > 0 && 𝓆 > 0]対応する非線形系を入力
および出力
,
で定義する.
dtank = NonlinearStateSpaceModel[eqs, {{Subscript[𝒽, 1][t], (𝓆^2/2 𝒸^2 ℊ Subsuperscript[𝒶, 1, 2])}, {Subscript[𝒽, 2][t], (𝓆^2/2 𝒸^2 ℊ Subsuperscript[𝒶, 2, 2])}}, {{𝒬[t], 𝓆}}, {Subscript[𝒽, 1][t], Subscript[𝒽, 2][t]}, t] /. parsモデルの埋込み
モデルをサンプリング周期0.25秒で離散化する:
τ = 0.25;ddtank = ToDiscreteTimeModel[dtank, τ]入力流量はポテンショメータで制御し,流量は1から2の間で変化するようにスケールされる.
pscaler = NonlinearStateSpaceModel[{{}, {1 + (𝓊/5)}}, {}, {𝓊}, {Automatic}, Automatic, SamplingPeriod -> τ];モデルが流入流量と2つのタンク内の液面の高さを返すように設定する.
sys = SystemsConnectionsModel[{pscaler, ddtank}, {{1, 1}{2, 1}}, {{1, 1}}, {{1, 1}, {2, 1}, {2, 2}}]パッケージをロードする.
Needs["MicrocontrollerKit`"]モデルを埋め込む:
ℳ = MicrocontrollerEmbedCode[sys, <|"Target" -> "ArduinoMicro", "Inputs" -> "A0" -> "Analog", "Outputs" -> Table["SerialOverUSB", 3]|>, "/dev/tty.usbmodem1411"]シミュレーションで得られた信号の読取り
目的デバイスへのシリアル接続を開く:
y = {};
dv = DeviceOpen["Serial", "/dev/tty.usbmodem1411"]開始,区切り,終了バイト.
{sb, db, eb} = Lookup[ℳ["SerialOverUSB"], {"StartByte", "DelimiterByte", "EndByte"}]シリアル接続から入ってくるデータを解釈する関数:
parseData[{sb, flow__, db, h1__, db, h2__}] := ToExpression@FromCharacterCode@#& /@ {{flow}, {h1}, {h2}}
parseData[___] := Sequence[]毎秒値を読み込む(そしてポテンショメータを使ってステップ入力を適用する)タスクを設定する:
task = SessionSubmit@ScheduledTask[
If[DeviceExecute[dv, "SerialReadyQ"],
AppendTo[y, DeviceReadBuffer[dv, "ReadTerminator" -> eb]];DeviceExecute[dv, "ReadFlush"];
],
1
];30分ほどしたら,タスクを削除し,デバイス接続を終了する:
TaskRemove[task];
DeviceClose[dv];ポテンシャメータのステップ入力に対する2つのタンクの液面の高さ.
p1 = ListLinePlot[Transpose[parseData /@ y][[2 ;; 3]], PlotRange -> All]系に適用されたステップ入力を取り出す:
allu = (parseData /@ y)[[All, 1]];
u = UnitStep[t] + UnitStep[t - FirstPosition[allu, _ ? (# != 1.&)][[1]]] (allu[[-1]] - allu[[1]]);Plot[Evaluate@u, {t, 0, Length@allu}]実時間とシミュレーションの結果を比較する:
OutputResponse[dtank, u, {t, 0, Length@allu}];
Show[p1, Plot[%, {t, 0, Length@allu}, PlotStyle -> Dashed]]実時間シミュレーションの結果はWolframシステムでのシミュレーション結果と同等であった.しかし,実時間シミュレーションでは,流入流量が1
から1.11
に増加したときに,液面レベルが2.7メートルから3.3メートルになるのに約30分かかった.
発展
- 別の方法で液面レベルの可視化する.
- 他のチャンネルを使って出力信号を送る.
- 液面レベルへの外乱のシミュレーションを行う.
- 液面レベルを制御する制御器を設計し,HILシミュレーションを行う.
- 単振り子やDCモータ等,他の系のHILシミュレーションを行う.