バックナンバーはこちら。
https://www.simulationroom999.com/blog/model-based-of-minimum-2-backnumber/
はじめに
必要なタイマハンドラは2つ。
- FMU_handler:FMUシミュレーション用(短周期呼び出し)
- plot_handler:matplotlibリアルタイム更新用(長周期呼び出し)
これらの実装について考えていく。
(今回はFMU_handler)
登場人物
博識フクロウのフクさん
イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1
エンジニア歴8年の太郎くん
イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1
FMU_handler
じゃ、まずはFMU_handlerことFMUシミュレーション用の処理だ。
コードにすると以下になる。
def FMU_handler():
global start_tick
global currenttime
current_tick = time.perf_counter()
delta_tick = current_tick - start_tick;
start_tick = current_tick
delta_simulate = delta_tick
res = master.simulate(start_time=currenttime, final_time=currenttime+delta_simulate-step_size/100, options=opts)
opts["initialize"] = 0
currenttime = currenttime + delta_simulate
deque_voltage.extend(res[model_sub2]['voltage'])
deque_current.extend(res[model_sub2]['current'])
deque_speed.extend(res[model_sub2]['speed'])
deque_loadTorqueStep_tau.extend(res[model_sub2]['loadTorqueStep.tau'])
deque_target.extend(res[model_sub1]['target'])
deque_time.extend(res[model_sub2]['time'])
deque_cpuload.extend(np.ones(len(res[model_sub2]['time']))*delta_simulate*1000)
root.after(1, FMU_handler)
FMU_handler詳細
先頭の方にglobalで定義された変数があるね?
これは何?
グローバル変数が存在していることを明示した書き方だな。
Pythonはスコープがネストしている場合、
特に明示しなくても参照できるのだが、
start_tick = current_tick
のような行があると、
ここで変数が新たに作られる場合とそうでない場合が区別つかないんだよね。
よって、この場合、グローバル変数が先に存在することを明示してあげる必要がある。
よくわからんが、
ローカル変数なのか、外側のスコープに別の変数がいるのかが分からなくなる場合があるからちゃんと指示して上げないといけない局面があるってことかな?
そして今回のstart_tickとcurrenttimeがそれに該当すると。
正解だ。
あとは実時間の進んだ時間をstart_tickとcurrenttimeを使って求めて、
その時間分をシミュレーション時間として進めてる感じか。
ちょっと気になるところはmaster.simulateメソッドの
final_time=currenttime+delta_simulate-step_size/100
ってところかな?
currenttime+delta_simulate
は、終了時間を示しているのは察せるけど、
-step_size/100
は何を示してるんだろう?
ここはちょっと苦肉の策みたいな部分はあるねー。
FMUのシミュレーションとして
final_time=currenttime+delta_simulate
とすると、
今回の最後のstepと次の最初のstepが重複しちゃうんだよね。
それを回避しようと
final_time=currenttime+delta_simulate-step_size
にすると、
今回の最後のstepと次の最初のstepの間に1step分の隙間が生まれて
キレイにシミュレーションしてくれない。
よって、微妙に次の先頭stepに係らない程度の時間を指定して、
演算としては辻褄が合うようにしている。
何を言ってるのか全く分からん。
まぁ図にしてみるとこんな感じだな。
ほう。
こんなことが起きているのか。
まぁ欠落微小で影響ないならOKだよね。
事前実験では問題なく動いていたことは確認しているので、
おそらく問題はないだろう。
まとめ
まとめだよ。
- FMU_handlerことFMUシミュレーション用処理のコードを提示。
- 外部の変数を使用するためにglobal定義している変数あり。
- 実時間の経過を元にFMUシミュレーション時間を決定している。
- 実時間にシミュレーション時間を追いつかせる方式。
- ただし、開始と終了のstepが重複したり欠落したりするので微小時間の調整が必要。
バックナンバーはこちら。
コメント