ちょっと高度なカスタムブロック、「MATLAB System ブロック」を使いこなせ!
皆さんこんにちは。トレーニングエンジニアの遠藤と申します。
このブログでは、「Simulink と MATLAB をつなぐ」をコンセプトとして、主に技術的な内容について書いています。
先日ついに MATLAB R2021b がリリースされましたね!Simulink と MATLAB をつなぐような新機能もあるようで、今回のブログ記事でもそれについて書こうかなとも考えたのですが、さすがにもう少し自分で使ってから紹介したいなという部分があり、新機能紹介はまた次の機会にしようかなと思います。
ということで、今回は「MATLAB System ブロック」にフォーカスを当てていきたいと思います。Simulink で MATLAB コードを使う機能としては、以前のブログ記事でも紹介した「MATLAB Function ブロック」が有名で、MATLAB System ブロックは少しマイナーな部類に入るかと思います。しかし、実装したい処理によっては MATLAB System ブロックの方が適している場面も少なくありません。
特に、以下のような方は MATLAB System ブロックを使いこなすことでより効率的にモデルを作れるようになるかもしれませんので、必見です!
- MATLAB Function ブロックで永続変数をよく使う
- MATLAB Function ブロック内でコード生成対応外の関数を使う機会が多い
- MATLAB Function ブロックのコード内のパラメータを調整することが多い
目次:
MATLAB System ブロックとは?
まずは MATLAB System ブロックについて簡単に説明したいと思います。MATLAB System ブロックは、System object を用いて動作をカスタマイズできるブロックです。System object はあまり馴染みのない方もいるかもしれませんが、簡単に言うとシミュレーションやストリーミング処理用につくられた、変数や関数を内部に持つことのできるオブジェクトです(詳しく知りたい方はリンク先のドキュメントを参照ください)。
実際に MATLAB System ブロックを使ってみましょう。まずはモデル上に MATLAB System ブロックを置いてみます。
最初は System object が何も紐づいていないので赤いエラーが表示されています。ダブルクリックしてブロックダイアログを開くと、既存の System object を指定、または新規で System object を作成することができます。新規作成の際には「標準」「詳細設定」「Simulink 拡張」の3つのテンプレートから作成することができますが、この記事では一番簡単な「標準」テンプレートの使い方を説明していきたいと思います。
標準テンプレートのコードが自動で開きました。MATLAB Function ブロックの関数に比べると少し複雑で抵抗感を感じる方もいるかもしれませんが、1つ1つの役割さえ覚えてしまえばそこまで難しくはありません、
まず最も重要なのが、テンプレートコードの下部にある stepImpl 関数です。この関数は、各タイムステップで MATLAB System ブロックの出力を計算する際に実行される関数です。MATLAB Function ブロックで作る関数と基本的には同じ役割ですね。この関数の中に出力の計算処理を書いていきます。
function y = stepImpl(obj,u)
% Implement algorithm. Calculate y as a function of input u and
% discrete states.
y = 2*u; % 入力を 2 倍して出力する
end
その他、MATLAB Function ブロックとは違い、以下のようなものもテンプレートに用意されています。
- properties
ここではブロックダイアログから変更できる変数を定義することができます(後述)。 - properties(DiscreteState)
ここでは離散状態用の変数を定義できます。少し上級者向けですのでこの記事では説明は割愛しますが、詳しく知りたい方はこちらのドキュメントをご確認ください。 - properties(Access = private)
ここでは System Object の関数内から値を変更可能な変数を定義することができます(後述)。 - setupImpl 関数
シミュレーション開始時に1度だけ実行される関数です。変数の読み込みなど1度だけ実行すればよい処理はここに記載します。 - resetImpl 関数
DiscreteState 属性のプロパティを初期化、リセットするための関数です。DiscreteState を使っていない場合は特に何も書く必要はありません。
これらをうまく使うと、MATLAB Function ブロックで実装するのが面倒臭い処理、難しい処理を簡単に実装することができます。早速 MATLAB System ブロックのメリットを具体的に見ていきましょう。
MATLAB System ブロックのメリット
1. ブロックダイアログからパラメータを設定できる
MATLAB System ブロックは、コード内で使用するパラメータの値をブロックダイアログから設定することができます。
やり方はとても簡単、設定したいパラメータを properties の部分で定義するだけです。
properties
k = 10; % パラメータ用の変数を定義
end
このように、properties で変数を定義すると、MATLAB System ブロックをダブルクリックしたときに開くダイアログにこの変数が表示され、値が変更できるようになります。
Gain ブロックなどと同様、エディットボックスで変数名を指定すれば、MATLAB のワークスペース上の変数の値を使うこともできます。
ただし、この変数をコード内で使用する場合、コードの書き方に注意が必要です。properties に定義した変数は、変数名だけではアクセスできません。”obj.変数名” という表記が必要です。
function y = stepImpl(obj,u)
% Implement algorithm. Calculate y as a function of input u and
% discrete states.
y = obj.k * u; % obj.k という表記で、定義したパラメータ k にアクセス
end
また、properties に定義した変数の値はコード中で変更できない点にも注意です。
2. 内部状態を持つことができる
ブロックの処理を MATLAB のコードで実装していると、「変数の値を次のタイムステップの計算に使うために残しておきたい」という状況にしばしば遭遇します。MATLAB Function ブロックでは「永続変数」を使うことで変数の値がリセットされるのを防ぐことができますが、シミュレーション後に Clear する必要がある、条件分岐などの追加コードが必要になりコードが見づらくなる、といった点で少し使いづらいです。これに対し、MATLAB System ブロックでは、properties(Access = private) を使うことで、簡単に値を保存、使用することができます。
例えば今の入力と1つ前のタイムステップの入力を足し算する処理を作ってみましょう。まずは1つ前の入力を保存するための変数を properties(Access = private) に定義します。
properties(Access = private)
uOld = 0;
end
ここで定義した変数の値は、シミュレーションが終わるまでリセットされません。そのため、過去の値を保存しておくことができます。この変数を使えば出力の計算も簡単に作れますね。
function y = stepImpl(obj,u)
% Implement algorithm. Calculate y as a function of input u and
% discrete states.
y = u + obj.uOld; % 現在の入力と1つ前の入力を加算
obj.uOld = u; % 次のタイムステップのために入力を保存
end
前述の properties 同様、こちらも “obj.” をつけなくてはいけない点に注意です。
3. シミュレーション開始時に1度だけ実行したい処理を簡単に実装できる
データの読み込みや初期設定など、シミュレーション開始時に1回だけ実行したい処理が必要な場合、MATLAB Function ブロックでは永続変数などと組み合わせて初回実行かどうかの判定を行う必要があります。
これに対し、MATLAB System ブロックは stepImpl 関数を使うことで初回実行処理を簡単に実装することができます。例えば、シミュレーション開始時に .mat ファイルからパラメータを読み込みたい場合は以下のようになります。
properties(Access = private)
a;
b; % パラメータ保存用の変数を用意
end
function setupImpl(obj)
% Perform one-time calculations, such as computing constants
data = load('myData.mat');
obj.a = data.a;
obj.b = data.b; % 初回のみデータファイルからパラメータを読み込む
end
function y = stepImpl(obj,u)
% Implement algorithm. Calculate y as a function of input u and
% discrete states.
y = obj.a * u + obj.b; % 初回に読み込んだ a と b を使って出力を計算
end
前述した properties(Access = private)と組み合わせ、初回時のみデータファイルからパラメータを読み込み、それを使って出力を計算する処理の例です。実行されるタイミングによって関数が分かれている分コードも見やすいですね。
4. コード生成に対応していない関数もそのまま使用可能
MATLAB Function ブロックはコード生成対応していない関数を使いたい場合は coder.extrinsic 関数でコード生成対象外にしなければいけませんでした。これに対し、MATLAB System ブロックはコード生成を行ってシミュレーションを実行する「コード生成」モードと、コード生成を行わずシミュレーションを行う「インタープリター型実行」モードを切り替えることができます。
そのため、インタープリター型実行を選択すれば、コード生成に対応していない関数を自由に使うことができます。コード生成に対応していない関数を使いたいだけなら Interpreted MATLAB Function ブロックもありますが、こちらは状況に応じてコード生成もインタープリター実行も行えるのが大きなメリットですね。
ただし、インタープリター型実行モードに設定した場合、MATLAB System 内の処理はすべて MATLAB 側で行われることになります。そのため、MATLAB と Simulink の間でやり取りが発生し、シミュレーションが遅くなる可能性があることには注意しましょう。
おわりに
今回は MATLAB System ブロックの簡単な使い方とメリットについての内容でした。Simulink を使っていると、ついつい「ブロックのカスタマイズ = MATLAB Function ブロック」となってしまいがちですが、MATLAB System ブロックだけに限らず、カスタムブロックにはそれぞれ適した場面があります(こちらも参照)ので、自分が実装したい処理にはどのブロックが最適なのかを一度見直してみると、モデルやコードをさらにシンプルにわかりやすくできるかもしれませんよ!
- Category:
- Simulink General,
- 機能と使い方
Comments
To leave a comment, please click here to sign in to your MathWorks Account or create a new one.