非バーチャル サブシステムのモジュラー関数コードの生成
非バーチャル サブシステムのコード生成について
既定では、非バーチャル サブシステムのコードを作成すると、コード ジェネレーターによって、非バーチャル サブシステムに関連付けられた内部データが親モデルの内部データと同じデータ構造体に配置されます。これにより、特に再利用できないサブシステムの場合は、コードをトレースおよびテストするのが困難になる場合があります。また、非バーチャル サブシステムを含む大規模なモデルでは、データ構造体が大きくなり、コンパイルが難しくなる可能性があります。
Atomic サブシステムや条件付き実行サブシステムを含む、非バーチャル サブシステムのモジュラー関数コードを生成するには、Subsystem ブロック パラメーターの [別々のデータをもつ関数] を使用します。このブロック パラメーターは、コード ジェネレーターに対し、親モデルのデータ構造体に依存しない非バーチャル サブシステム関数のブロック I/O と DWork データ構造体を生成するように指示します。その結果、サブシステムに対して生成されたコードは次のようになります。
簡単にトレースできる。
簡単にテストできる。
モデルのグローバル データ構造体のサイズが削減される。
[別々のデータをもつ関数] パラメーターを使用するには、次を実行します。
ERT ベースのシステム ターゲット ファイルを使用してモデルを設定する。
サブシステムが Atomic または条件付き実行になるように設定する。
Subsystem ブロック パラメーター [関数のパッケージ化] を
[再利用できない関数]
に設定する。
モジュラー関数コードを生成するためにサブシステムを構成するには、[Subsystem パラメーター] ダイアログ ボックスを開き、表示されている一連の選択を行い、[別々のデータをもつ関数] オプションを有効にします。詳細については、モジュラー関数コードを生成するためのサブシステムの設定と非バーチャル サブシステムのモジュラー関数コードを参照してください。適用される制限については、非バーチャル サブシステム モジュラー関数コードの制限を参照してください。
Atomic サブシステムのコードの生成の詳細については、サブシステム コードを別々の関数およびファイルとして生成および個別のサブシステムのコードと実行可能ファイルの生成を参照してください。
モジュラー関数コードを生成するためのサブシステムの設定
サブシステムを含むモデルが ERT ベースのシステム ターゲット ファイルを使用しているか確認します。
モジュラー関数コードを生成するサブシステムを選択し、[Subsystem パラメーター] ダイアログ ボックスを開きます。Atomic サブシステムのダイアログ ボックスを以下に示します (条件付き実行サブシステムのダイアログ ボックスでは、ダイアログ ボックス オプション [Atomic サブシステムとして扱う] がグレー表示になり、手順 3 を省略できます)。
ブロック パラメーター [Atomic サブシステムとして扱う] が選択可能であっても選択されていない場合、サブシステムは Atomic サブシステムにも条件付き実行サブシステムにもなりません。パラメーター [Atomic サブシステムとして扱う] を選択します。これにより、[コード生成] タブの [関数のパッケージ化] パラメーターが有効になります。[コード生成] タブを選択します。
[関数のパッケージ化] パラメーターの場合は、
[再利用できない関数]
を選択します。この選択を行った後、[別々のデータをもつ関数] パラメーターが表示されます。[別々のデータをもつ関数] パラメーターを選択して非バーチャル サブシステムのコードを生成する前に、このパラメーターをオフにして関数コードを生成し、後で比較できるように
.c
ファイルおよび.h
ファイルを別のディレクトリに保存しておくことを検討してください。[別々のデータをもつ関数] パラメーターを選択します。追加のパラメーターが表示されます。
生成されるサブシステム関数とサブシステム ファイルの命名を制御するために、サブシステム パラメーター [関数名オプション] と [ファイル名オプション] を変更します。
サブシステム パラメーターの変更を保存し、[OK] をクリックしてダイアログ ボックスを終了します。
サブシステムのコードを生成し、サブシステム パラメーターの指定に従って命名した関数
.c
ファイルおよび.h
ファイルを含む、生成されたファイルを調べます。
非バーチャル サブシステムのコード生成の詳細については、サブシステム コードを別々の関数およびファイルとして生成を参照してください。生成されたサブシステムの関数コードの例については、非バーチャル サブシステムのモジュラー関数コードを参照してください。
非バーチャル サブシステムのモジュラー関数コード
この例では、[別々のデータをもつ関数] パラメーターを無効および有効にして非バーチャル サブシステムの関数コードを生成し、その結果を比較する方法を示します。
モデル例
rtwdemo_atomic
を開きます。次に、Embedded Coder アプリを開きます。システム ターゲット ファイルをert.tlc
に変更します。このモデルでは、バーチャル サブシステムの境界を保持する方法を説明します。Subsystem ブロック パラメーター [Atomic サブシステムとして扱う] を選択すると、サブシステムのコード ジェネレーターによって生成されるコードは、Atomic サブシステムとして実行されます。Atomic として設定した場合、[コード生成] タブの [関数のパッケージ化] パラメーターを設定して、コード ジェネレーターでのサブシステムの表現方法を指定できます。サブシステムが次のいずれかの実装タイプに変換されることを指定できます。
インライン
: 呼び出しサイトでインライン化されたサブシステム コード。関数
: モデルのグローバル データ構造体に I/O および内部データをもつvoid/void
関数。再利用可能な関数
: データが関数の引数として渡される再呼び出し可能な関数。自動
: コードジェネレーターで、コンテキストに基づいて実装が最適化されます。
SS1 サブシステムをダブルクリックし、内容を確認します。
その後、サブシステム ウィンドウを閉じます。
SS1 サブシステムを右クリックし、コンテキスト メニューから [ブロック パラメーター (Subsystem)] を選択して、設定を調べます。サブシステム パラメーター [代数ループの発生の最小化] を使用してサブシステムを Atomic にしている場合、Simulink® およびコード ジェネレーターでは、"人為的な" 代数ループを避けることができます。
データの分離を "使用しない" 関数コードを示す
rtwdemo_atomic
のバリアントを作成します。[Subsystem パラメーター] ダイアログ ボックスで、次を行います。
[メイン] タブで、[Atomic サブシステムとして扱う] を選択します。
[コード生成] タブで、次を行います。
[関数のパッケージ化] を
[再利用可能な関数]
に設定します。[関数名オプション] を
[ユーザー指定]
に設定します。[関数名] を
myfun
に設定します。[ファイル名オプション] を
[関数名を使用]
に設定します。この設定はオプションですが、Atomic サブシステムの関数コードがファイルmyfun.c
とmyfun.h
に生成されるようにして、後からコード比較のタスクを簡略化することができます。
[別々のデータをもつ関数] パラメーターは "選択しない" でください。
[適用] をクリックして変更を適用し、[OK] をクリックしててダイアログ ボックスを閉じます。
モデル バリアントを一意のファイル名 (
rtwdemo_atomic1
など) で書き込み可能な場所に保存します。
データの分離を "使用" する関数コードを示す
rtwdemo_atomic
のバリアントを作成します。モデル
rtwdemo_atomic
を開きます。Embedded Coder アプリを開きます。システム ターゲット ファイルを
ert.tlc
に変更します。モデル キャンバスで、SS1 サブシステムを右クリックし、[ブロック パラメーター (Subsystem)] を選択します。[Subsystem パラメーター] ダイアログ ボックスで、次を行います。
[メイン] タブで、[Atomic サブシステムとして扱う] を選択します。
[コード生成] タブで、次を行います。
[関数のパッケージ化] を
[再利用可能な関数]
に設定します。[関数名オプション] を
[ユーザー指定]
に設定します。[関数名] を
myfun
に設定します。[ファイル名オプション] を
[関数名を使用]
に設定します。[別々のデータをもつ関数] を選択します。
[適用] をクリックして変更を適用し、[OK] をクリックしててダイアログ ボックスを閉じます。
モデル バリアントを一意のファイル名 (
rtwdemo_atomic2
など) で書き込み可能な場所に保存します。
各モデル (
rtwdemo_atomic1
やrtwdemo_atomic2
など) のコードを生成します。2 つのモデルから生成された
/model
.c.h
ファイルとmyfun.c
/.h
ファイルを比較します。コードの比較については、非バーチャル サブシステム関数のデータ分離での H ファイルの差および非バーチャル サブシステム関数のデータ分離での C ファイルの差を参照してください。この例では、
ert_main.c
、
、model
_private.h
、またはmodel
_types.hrtwtypes.h
の生成されたバリアントに有意差はありません。
非バーチャル サブシステム関数のデータ分離での H ファイルの差
[別々のデータをもつ関数] を選択すると、コード ジェネレーターによって、
rtwdemo_atomic2
のmyfun.h
ファイルにサブシステム データの型定義が配置されます。/* Block states (default storage) for system '<Root>/SS1' */ typedef struct { real_T Integrator_DSTATE; /* '<S1>/Integrator' */ } DW_myfun_T;
rtwdemo_atomic1
では、次のようにサブシステムの型定義はモデルに属し、rtwdemo_atomic1.h
に表示されます。/* Block signals (default storage) */ typedef struct { real_T Sum; /* '<Root>/Sum' */ } B_rtwdemo_atomic_1_T; /* Block states (default storage) for system '<Root>' */ typedef struct { real_T Integrator_DSTATE; /* '<S1>/Integrator' */ } DW_rtwdemo_atomic_1_T;
[別々のデータをもつ関数] を選択すると、
rtwdemo_atomic2
について、次の外部宣言がmyfun.h
ファイルに生成されます。/* Extern declarations of internal data for system '<Root>/SS1' */ extern DW_myfun_T myfun_DW; extern void myfun_Update(void); extern void myfun(void);
反対に、
rtwdemo_atomic1
の生成されたコードは、rtwdemo_atomic1.h
内にサブシステムBlockIO
およびD_Work
データのモデルレベルの外部宣言を含みます。/* Block signals (default storage) */ extern B_rtwdemo_atomic_1_T rtwdemo_atomic_1_B; /* Block states (default storage) */ extern DW_rtwdemo_atomic_1_T rtwdemo_atomic_1_DW;
非バーチャル サブシステム関数のデータ分離での C ファイルの差
[別々のデータをもつ関数] を選択すると、
rtwdemo_atomic2
について、別のサブシステム初期化関数myfun_initialize
がmyfun.c
ファイルに生成されます。void myfun_initialize(void) { { ((real_T*)&rtwdemo_atomic2_myfunB.Integrator)[0] = 0.0; } rtwdemo_atomic2_myfunDW.Integrator_DSTATE = 0.0; }
myfun.c
のサブシステム初期化関数は、rtwdemo_atomic2.c
のモデル初期化関数で呼び出されます。/* Model initialize function */ void rtwdemo_atomic2_initialize(void) { ... /* Initialize subsystem data */ myfun_initialize(); }
反対に、
rtwdemo_atomic1
の場合、サブシステムのデータはrtwdemo_atomic1.c
のモデル初期化関数で初期化されます。/* Model initialize function */ void rtwdemo_atomic1_initialize(void) { ... /* block I/O */ { ... ((real_T*)&rtwdemo_atomic1_B.Integrator)[0] = 0.0; } /* states (dwork) */ rtwdemo_atomic1_DWork.Integrator_DSTATE = 0.0; ... }
[別々のデータをもつ関数] を選択すると、次の宣言が
rtwdemo_atomic2
のmyfun.c
ファイルに生成されます。/* Declare variables for internal data of system '<Root>/SS1' */ DW_myfun_T myfun_DW;
反対に、
rtwdemo_atomic1
の生成されたコードは、rtwdemo_atomic1.c
内にサブシステムBlockIO
およびD_Work
データのモデルレベルの宣言を含みます。/* Block signals (default storage) */ B_rtwdemo_atomic_1_T rtwdemo_atomic_1_B; /* Block states (default storage) */ DW_rtwdemo_atomic_1_T rtwdemo_atomic_1_DW;
[別々のデータをもつ関数] を選択すると、データ項目のサブシステムの方向を反映する識別子の命名が生成されます。
myfun
やmyfun_update
など、サブシステム関数内のサブシステム データへの参照は、モデルの関数
内にあります。たとえば、model
_steprtwdemo_atomic2
のmyfun
にある次のコードを/* DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_atomic_2_Y.Out1 = myfun_DW.Integrator_DSTATE;
rtwdemo_atomic1
のmyfun
にある対応するコードと比較します。/* DiscreteIntegrator: '<S1>/Integrator' */ rtwdemo_atomic_1_Y.Out1 = rtwdemo_atomic_1_DW.Integrator_DSTATE;
生成コードの関数の分割
この例では、モデル内のサブシステムを関数名とファイルに関連付ける方法を示します。
以下の方法について説明します。
生成したコード内での関数名とファイル名の指定方法。
生成したコードの統合に必要な部分の特定方法。
Atomic サブシステムのコードの生成方法。
生成した関数の実行に必要なデータの特定方法。
モデル例とこのシリーズの他の例の詳細については、C コード生成のためのコントロール アルゴリズム モデルの準備を参照してください。
Atomic サブシステムとバーチャル サブシステム
C コード生成のためのコントロール アルゴリズム モデルの準備と生成コードのデータ インターフェイスの構成のモデル例では "バーチャル サブシステム" を使用します。バーチャル サブシステムは視覚的にブロックを整理しますが、モデルの機能には影響しません。"Atomic サブシステム" はモデルに含まれるブロックを 1 つの単位として評価します。Atomic サブシステムを使用して、付加的な関数分割情報を指定することができます。モデル内で、Atomic サブシステムは境界が太線で描かれます。
モデル アーキテクチャの変更内容の参照
モデル例 rtwdemo_PCG_Eval_P3 を開きます。
書き込み可能なフォルダーにモデルのコピーを保存します。
この例は、バーチャル サブシステムを Function-Call Subsystem に置き換える方法を示します。Function-Call Subsystem については次の通りです。
Atomic サブシステムである
サブシステムの実行順を制御できる
"関数呼び出し信号" がトリガーされたときに実行される
サブシステムの実行順の制御によって、特定の実行順をもつ既存のシステムにモデルを一致させることができます。
次の図は、関数呼び出しサブシステム (1) が PI_ctrl_1
、PI_ctrl_2
および Pos_Command_Arbitration
であることを示します。
モデルのこのバージョンには新しいサブシステム Execution_Order_Control
(2) があり、スケジューラの呼び出し機能をモデル化する Stateflow® チャートが含まれています。サブシステムは関数呼び出し信号 (3) を介して関数呼び出しサブシステムの実行順を制御します。この例の後半では、実行順の変更によってシミュレーション結果がどのように変化するかを調査します。
モデルのこのバージョンには新しい Signal Conversion ブロック (4) が PI コントローラーの出力に含まれています。これらの追加のブロックを配置することにより、コード ジェネレーターは PI コントローラーに 1 つの再呼び出し可能な関数を生成できます。
生成コード内の関数の場所とファイルの配置の制御
C コード生成のためのコントロール アルゴリズム モデルの準備と生成コードのデータ インターフェイスの構成では、コード ジェネレーターにより制御アルゴリズム コードが含まれる 1 つの関数 model
_step
が作成されます。しかし多くのアプリケーションでは、関数のファイル配置をより大きなレベルで制御することが必要になります。Atomic サブシステムのパラメーターを変更することにより、複数の関数を単一のモデル内で指定できます。
次の図は、PI_ctrl_1
のサブシステム パラメーターを示しています。
Atomic サブシステムとして扱う
その他のサブメニューを有効にします。Atomic サブシステムではこのパラメーターは自動的に選択および無効にされます。
サンプル時間
実行するサンプル時間を指定します。Function-Call Subsystem では使用できません。
[関数のパッケージ化] オプション
Auto
-- サブシステムが生成コードに表示される方法を決定します。これが既定値です。Inline
-- サブシステム コードを残りのモデル コードとインラインで配置します。Function
-- サブシステムのコードを関数として生成します。Reusable function
-- 再利用可能な (再呼び出し可能な) 関数をサブシステムから生成します。この関数は、すべての入力データおよび出力データを仮パラメーターを通じて渡します。この関数は、グローバル変数に直接アクセスしません。
関数名オプション
[関数のパッケージ化] に
Function
またはReusable function
を選択することで、関数名オプションが有効になります。Auto
-- 関数を決定します。Use subsystem name
-- サブシステム名に基づいて関数名を決定します。User specified
-- 指定されたファイル名を適用します。
ファイル名オプション
[関数のパッケージ化] に
Function
またはReusable function
を選択することで、ファイル名オプションが有効になります。Auto
-- 親システム用に生成されたモジュールに関数定義を配置します。あるいは、モデル ルートが親である場合は、model.c
に配置します。Use subsystem name
-- 個別のファイルを生成します。ファイルの名前は、サブシステムまたはライブラリ ブロックの名前です。Use function name
-- 個別のファイルを生成します。ファイルの名前は、[関数名オプション] で指定した名前です。User specified
-- 指定された一意のファイル名を適用します。
別々のデータをもつ関数
[関数のパッケージ化] を
Function
に設定すると有効になります。オンにすると、コード ジェネレーターはサブシステムの内部データ (信号など) を親モデルのデータから分離します。サブシステムはこの分離データを所有します。
再呼び出し可能なコードの生成
Embedded Coder® は "再呼び出し可能なコード" をサポートしています。再呼び出し可能なコードは複数のプログラムで同時に使用できる再利用可能なプログラミング ルーチンです。再呼び出し可能なコードは、オペレーティング システムや同時発生イベントを処理するマルチスレッドを使うその他のシステム ソフトウェアで使用されています。再呼び出し可能なコードは状態のデータを維持しません。つまり、関数内に永続変数はありません。呼び出し側のプログラムが状態変数を維持し、状態データを関数に渡さなければなりません。再呼び出し可能関数の 1 つのコピーを複数のユーザーやプロセスで共有できます。
再呼び出し可能なコードを生成するには、パラメーター [関数のパッケージ化] を設定し、最初にサブシステムを再利用可能として指定しなければなりません。
モデルのコンフィギュレーションにより再利用可能コードを利用できない場合もあります。次の表に、一般的な問題を示します。
Cause Solution
Subsystem output feeds global signal Add a Signal Conversion block between the data subsystem and the global signal.
Generated function receives data Select Configuration Parameters > (formal parameters) through pointers Model Referencing > Pass fixed-size scalar root inputs by value for code generation.
Subsystem uses global signal data Use a port to pass the global data in and out in internal algorithm of the subsystem.
マスクを使用してパラメーター値をライブラリ サブシステムに渡す
再利用可能なライブラリ ブロックまたはサブシステムのスコープ外でアルゴリズムを制御するパラメーター データ (ゲインや係数など) を定義するために、ブロックまたはサブシステムに "マスク" を適用し、マスク パラメーターを作成することができます。その後、ブロックまたはサブシステムの各インスタンスに対して異なるパラメーター値を指定できます。各マスク パラメーターは生成されたコード内で再呼び出し可能な関数の仮パラメーターとして表示されます。
モデルのこのバージョンで、サブシステム PI_ctrl_1
と PI_ctrl_2
はマスクされています。各マスクで P
および I
ゲインの値は I_Gain_2
や P_Gain_2
などのデータ オブジェクトで設定されます。
Atomic サブシステムのコード生成
C コード生成のためのコントロール アルゴリズム モデルの準備と生成コードのデータ インターフェイスの構成では、モデルのルート レベルでコードを生成します。あるいは、特定のサブシステムをビルドすることもできます。
サブシステムのビルドを開始するには、コンテキスト メニューを使用します。以下のオプションから選択できます。
このサブシステムをビルド: サブシステムは別のモードとして扱われ、ソース C ファイルとヘッダー ファイルのフル セットが作成されます。このオプションで Function-Call Subsystem はサポートされていません。
S-Function を生成: サブシステム用に C コードを生成し、S-Function ラッパーを作成します。そして元のモデル内でコードのシミュレーションを実行できます。このオプションで Function-Call Subsystem はサポートされていません。
関数のエクスポート: [このサブシステムをビルド] オプションと関連付けられているスケジューリング コードを使用せずに C コードを作成します。このオプションは、Function-Call Subsystem などトリガーを使用してサブシステムをビルドする場合に使用します。
あるいは、Embedded Coder アプリを開いてサブシステムを選択し、[C コード] タブで [ビルド] をクリックします。
生成されたコードの検証
次の例は、フル システム ビルド用に生成したファイルとエクスポート関数用に生成したファイルとを比較します。また、マスクされたデータのコード内での表示方法も確認します。
これらの 3 つのオプションについてビルド スクリプトを実行します。次に、ハイパーリンクをクリックして生成されたファイルを検証します。
rtwdemo_PCG_Eval_P3.c
フル ビルド: はい、ステップ関数
PI_ctrl_1: いいえ
Pos_Command_Arbitration: いいえ
PI_ctrl_1.c
フル ビルド: いいえ
PI_ctrl_1: はい、トリガー関数
Pos_Command_Arbitration: いいえ
Pos_Command_Arbitration.c
フル ビルド: いいえ
PI_ctrl_1: いいえ
Pos_Command_Arbitration: はい、Init および関数
PI_Ctrl_Reusable.c
ert_main.c
eval_data.c
(1) eval_data.c
のコンテンツは完全なビルドとエクスポート関数のビルドでは異なります。完全なビルドにはモデルで使用されるすべてのパラメーターが含まれます。エクスポート関数にはサブシステムで使用される変数だけが含まれます。
生成したコードのマスクされたデータ
ファイル rtwdemo_PCG_Eval_P3.c
で、再呼び出し可能な関数の呼び出しサイトは、データ オブジェクト P_Gain
、I_Gain
、P_Gain_2
、I_Gain_2
を引数として使用します。
シミュレーション結果への実行順の影響
既定では、Simulink® は次の順序でサブシステムを実行します。
PI_ctrl_1
PI_ctrl_2
Pos_Command_Arbitration
この例では、2 つの代替順序のいずれかを指定することができます。その後、テスト ハーネスを使用してシミュレーション結果に対する実行順の影響を確認できます。サブシステム Execution_Order_Control
は実行順を制御する 2 つの設定値をもっています。設定値を選択するには、サブシステムのコンテキスト メニューを使用します。
実行順を変更し、結果を確認します。
シミュレーション結果 (時間経過に対するスロットル位置) は実行順に応じてわずかに変化します。スロットルの要求が変化するときに差異が最も顕著になることがわかります。
このシリーズの次の例については、モデルおよび生成コードからの外部 C コードの呼び出しを参照してください。
非バーチャル サブシステム モジュラー関数コードの制限
非バーチャル サブシステム ブロック パラメーター [別々のデータをもつ関数] には次の制限があります。
パラメーターは、ERT ベースのシステム ターゲット ファイルで設定されたモデルで利用できる。
パラメーターが適用される非バーチャル サブシステムは複数のサンプル時間または連続サンプル時間をもつことができない。つまり、サブシステムは、離散サンプル時間をもつシングルレートでなければならない。
非バーチャル サブシステムに連続状態を含めることはできない。
非バーチャル サブシステムは、関数呼び出し信号を出力できない。
非バーチャル サブシステムにインラインでない S-Function を含めることはできない。
非バーチャル サブシステムの生成されたファイルは、
やmodel
.h
などのモデル全体のヘッダー ファイルを参照する。model
_private.hパラメーターは、[クラシック コール インターフェイス] パラメーターと互換性がない。両方のパラメーターを選択すると、エラーが発生する。
パラメーターは、モデル コンフィギュレーション パラメーター
[コード インターフェイスのパッケージ化]
の [再利用可能な関数] と互換性がない。両方のパラメーターを選択すると、エラーが発生する。
サブシステムのパラメーターを選択した場合、サブシステムを含むモデルには、[モデル インスタンス間で共有する] が選択されている Data Store Memory ブロックを含めることができない。Data Store Memory を参照してください。