C Function ブロックを使用した外部 C/C++ コードの Simulink への統合
C Function ブロックを使用して、外部 C コードを呼び出し、Simulink® モデルに統合することができます。C Function ブロックでは、外部 C コードを呼び出し、ブロック パラメーター ダイアログの [出力コード] ペイン、[開始コード] ペイン、[初期化条件コード] ペイン、および [終了コード] ペインを使用してコードの統合をカスタマイズできます。C Function ブロックを使用して以下のことを行います。
名前空間の下に定義されている関数を含む外部 C コードから関数を呼び出し、コードを Simulink モデル用にカスタマイズする。
C 関数を呼び出すためにデータを前処理し、関数呼び出し後にデータを後処理する。
シミュレーションとコード生成とで別のコードを指定する。
複数の関数を呼び出す。
ブロックにキャッシュされた永続データを初期化したり操作したりする。
メモリの割り当てと割り当て解除を行う。
変更する外部 C アルゴリズムを Simulink 内に呼び出すには、C Function ブロックを使用します。Simulink モデルから 1 つの C 関数を呼び出すには、C Caller ブロックを使用します。連続状態または状態の変化をもつ動的システムを統合するには、S-Function ブロックを使用します。
メモ
Simulink へのカスタム C コード統合でサポートされる C 言語の標準バージョンは C99 です。
以下の例では、C Function ブロックを使用して入力の合計と平均を計算します。
外部ソース ファイルの書き込み
まず、外部ソース ファイルを作成します。
data_array.h
という名前のヘッダー ファイルを作成します。/* Define a struct called DataArray */ typedef struct DataArray_tag { /* Define a pointer called pData */ const double* pData; /* Define the variable length */ int length; } DataArray; /* Function declaration */ double data_sum(DataArray data);
同じフォルダーで新しいファイル
data_array.c
を作成します。このファイルには、入力された数値の合計を計算する C 関数を記述します。#include "data_array.h" /* Define a function that takes in a struct */ double data_sum(DataArray data) { /* Define 2 local variables to use in the function */ double sum = 0.0; int i; /* Calculate the sum of values */ for (i = 0; i < data.length; i++) { sum = sum + data.pData[i]; } /* Return the result to the block */ return sum; }
Simulink への外部コードの入力
新しい空のモデルを作成し、C Function ブロックを追加します。C Function ブロックは、ライブラリ ブラウザーの [User-Defined Functions] ライブラリにあります。
C Function ブロックをダブルクリックしてブロック ダイアログを開きます。 をクリックして [モデル コンフィギュレーション パラメーター] ダイアログを開きます。[シミュレーション ターゲット] ペインの [コード情報] タブにある [インクルード ヘッダー] でヘッダー ファイルを定義します。
ヒント
次の手順で [ソース ファイル] の情報を入力した後、[ソース ファイルからのオートフィル] をクリックすると、ソース ファイルに含まれる情報を使用してヘッダー ファイルの名前を自動で入力できます。
[コード情報] タブにある [ソース ファイル] でソース ファイルを定義します。カスタム コードを正常に解析してビルドできることを確認するには、[カスタム コードの検証] をクリックします。
メモ
C Function ブロックを For Each Subsystem 内で使用する、または連続サンプル時間を指定して使用する、あるいは条件付き入力分岐実行でブロックの使用を最適化するには、ブロックによって呼び出されるすべてのカスタム コード関数が確定的、つまり同じ入力に対して常に同じ出力を生成しなければなりません。[シミュレーション ターゲット] ペインで [確定的な関数] および [関数別に指定] パラメーターを使用して、確定的なカスタム コード関数を特定します。ブロックでいずれかのカスタム コード グローバル変数を参照する場合は、For Each Subsystem または条件付き入力分岐実行で、あるいは連続サンプル時間を指定してブロックを使用するために、[確定的な関数] を
[すべて]
に設定しなければなりません。For Each Subsystem の C Function ブロックを示す例については、Use C Function Block Within For Each Subsystemを参照してください。
C Function ブロック パラメーター ダイアログの [出力コード] ペインに、ブロックがシミュレーション中に実行するコードを記述します。この例では、外部 C 関数で合計を計算します。[出力コード] ペインに関数
data_array.c
を呼び出すコードを記述して合計を計算し、その後、平均を計算します。/* declare the struct dataArr */ DataArray dataArr; /* store the length and data coming in from the input port */ dataArr.pData = &data[0]; dataArr.length = length; /* call the function from the external code to calculate sum */ sum = data_sum(dataArr); /* calculate the mean */ mean = sum / length;
シミュレーション開始時に実行するコードを [開始コード] ペインに、シミュレーション終了時に実行するコードを [終了コード] ペインに指定できます。
[シンボル] テーブルを使用して、ブロックのコードで使用されるシンボルを定義します。[追加] ボタンと [削除] ボタンを使用してシンボルを追加または削除します。端子を正しく表示するため、[出力コード]、[開始コード]、[初期化条件コード]、[終了コード] ペインで使用されるすべてのシンボルを定義します。
[シンボル] テーブルでは、ブロックのコードで使用される各シンボルについて、[名前]、[スコープ]、[ラベル]、[タイプ]、[サイズ]、および [端子] を適宜定義します。
[ブロック パラメーター] ダイアログを閉じます。テーブルへのデータ入力後、C Function ブロックには、テーブルに指定したラベルをもつ 1 つの入力端子と 2 つの出力端子が含まれます。
C Function ブロックへの入力となる Constant ブロックを Simulink キャンバスに追加します。Constant ブロック内に、100 の要素をもつランダムな行配列を作成します。結果を表示するため、C Function ブロックの出力に Display ブロックを付加します。
メモ
モデルにカスタム コードが含まれる場合、モデルが更新または実行されると、読み込まれたカスタム コードのシミュレーション実行可能ファイルが原因で slprj
フォルダーがロックされる場合があります。ロックされているフォルダーは削除できません。実行可能ファイルをアンロードして、slprj
フォルダーのロックを解除するには、clear mex
コマンドを使用します。clear
を参照してください。
シミュレーション用コードまたはコード生成用コードの指定
MATLAB_MEX_FILE
を定義すると、C Function ブロックに、シミュレーション用とコード生成用とで異なる [出力コード] を指定することができます。たとえば、モデルのシミュレーション中にのみ実行されるコードを指定するには、以下を使用します。
#ifdef MATLAB_MEX_FILE /* Enter simulation code */ #else /* Enter code generation code */ #endif
コード生成のためのターゲット固有関数の宣言の指定
コード生成のために、C Function ブロックから呼び出す関数 (ターゲット固有のデバイス ドライバーなど) の宣言を含む外部ヘッダー ファイルがない場合は、ブロックの [出力コード] ペインで適切なシグネチャをもつ宣言を含めることができます。この操作により、次の例のように、コードが生成されるときに必要な関数に対する関数呼び出しが作成されます。
#ifndef MATLAB_MEX_FILE extern void driverFcnCall(int16_T in, int16_T * out); driverFcnCall(blockIn, &blockOut); #endif