このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。
mdlRTW ルーチンでの完全インライン化 S-Function の記述
S-Function mdlRTW
ルーチンを使用することで、より複雑な S-Function をインライン化できます。mdlRTW
ルーチンにより、TLC ファイルで使用する調整できないパラメーターのパラメーター レコードを作成することによって、S-Function のインライン方法に関する詳細情報をコード生成プロセスに対して提供します。mdlRTW
ルーチンは情報を
ファイルに配置します。関数 model
.rtwmdlRTW
は、テキスト ファイル
に記述されます。matlabroot
/simulink/src/sfuntmpl_doc.c
関数 mdlRTW
を使用するには、直接インデックス ルックアップ S-Function を作成する手順に従います。ルックアップ テーブルとは、順序付けられた関数データ点の集まりです。通常、これらのテーブルでは、いくつかの内挿法を用いて既知のデータ点間にある関連した関数の近似値が求められます。ルックアップ テーブル アルゴリズムの例を Simulink® モデルに組み込むために、まず、関数 mdlOutputs
でアルゴリズムを実行する S-Function を記述します。最も効率的なコードを生成するために、次に、対応する TLC ファイルを作成して計算オーバーヘッドを取り除き、ルックアップの計算速度を高めます。
Simulink 製品は、1 次元、2 次元、および n 次元の汎用のルックアップ アルゴリズムに対するサポートを提供します。これらのアルゴリズムをそのまま使用することも、必要に応じてカスタムのルックアップ テーブル S-Function を作成することもできます。1 次元のルックアップ S-Function sfun_directlook.c
と、これに対応するインライン化 sfun_directlook.tlc
ファイルを作成できます (詳細については、Target Language Compilerを参照)。次のことが可能です。
S-Function パラメーターのエラーをチェックする。
モデルの実行中に変更されない S-Function の情報をキャッシュする。
関数
mdlRTW
を使用してコード ジェネレーターをカスタマイズし、指定された一連のブロック パラメーターに最適なコードを生成する。ルックアップ テーブルのコードの完全インライン化、または、ルックアップ テーブル アルゴリズムのラッパー関数の呼び出しのいずれかの S-Function 用に
TLC
ファイルを作成する。
S-Function RTWdata
RTWdata
はブロックのプロパティで、S-Function のインライン化時に Target Language Compiler で使用できます。RTWdata
はブロックに接続できる文字ベクトルの構造体です。RTWdata
はモデルと共に保存され、コードの生成時に
ファイルに配置されます。たとえば、この一連の MATLAB® コマンドは次のとおりです。model
.rtw
mydata.field1 = 'information for field1'; mydata.field2 = 'information for field2'; set_param(gcb,'RTWdata',mydata) get_param(gcb,'RTWdata')
次の結果が生成されます。
ans = field1: 'information for field1' field2: 'information for field2'
ファイル内で関連付けられている S-Function ブロックの情報は次のとおりです。model
.rtw
Block { Type "S-Function" RTWdata { field1 "information for field1" field2 "information for field2" }
メモ
RTWdata
は、ライブラリにリンクされていない S-Function のモデル ファイルに保存されます。ただし、RTWdata
は、ライブラリにリンクされている S-Function ブロックでは保持されません。
直接インデックス ルックアップ テーブル アルゴリズム
Simulink ライブラリで提供される 1 次元のルックアップ テーブル ブロックでは、出力の計算時に内挿や外挿が使用されます。次の例では、現在の入力 (x データ) 点に基づいて出力ベクトル (y データ ベクトル) に直接インデックスを付けるルックアップ テーブルを作成します。
この直接 1 次元ルックアップの例では、x データ ベクトルと y データ ベクトルの形式でデータ点のペア (x,y) が指定され、x=x0 における部分的に既知の関数 f(x) の近似解 p(x) を計算します。指定されるデータ ペア (i'th のペアなど) では、y_i = f(x_i) です。x データの値は単調増加することとします。x0 が x データ ベクトルの範囲外にあると、最初または最後の点が返されます。
S-Function のパラメーターは次のようになります。
XData, YData, XEvenlySpaced
XData
と YData
は未知の関数の値を表す同じ長さの倍精度ベクトルです。XDataEvenlySpaced
はスカラーであり、false の場合は 0.0
、true の場合は 1.0
です。XData
ベクトルが等間隔である場合、XDataEvenlySpaced
は 1.0
となり、より効率的なコードが生成されます。
このグラフでは、パラメーター XData=[1:6]
と YData=[1,2,7,4,5,9]
の処理方法を説明します。たとえば、S-Function ブロックの入力 (x 値) が 3 の場合、出力 (y 値) は 7 になります。
直接インデックス ルックアップ テーブルの例
TLC ファイルで直接インデックス S-Function をインライン化することによって、ルックアップ テーブルを向上させます。この直接インデックス ルックアップ テーブル S-Function で TLC ファイルは必要ありません。次の例では、直接インデックス ルックアップ テーブル S-Function に TLC ファイルを使用して、コード サイズを縮小して生成コードの効率を上げます。
インライン化された TLC ファイルで直接インデックス アルゴリズムを実装するには、S-Function メイン モジュール、sfun_directlook.c
と対応する lookup_index.c
モジュールが必要です。lookup_index.c
モジュールには関数 GetDirectLookupIndex
が含まれています。この関数は、XData
が等間隔ではないときに現在の x
入力値に対する XData
のインデックスを求めるために使用されます。GetDirectLookupIndex
ルーチンは、S-Function と生成コードから呼び出されます。この例では、Simulink MEX ファイルと生成コードで C/C++ コードを共有するためにラッパーの概念を使用します。
XData
が等間隔である場合、S-Function メイン モジュールと生成コードの両方には、指定された x 値の y 値を計算するためのルックアップ アルゴリズムが含まれます。これは、アルゴリズムが短いからです。
インライン化された TLC ファイルは sfun_directlook.tlc
で、ラッパーの呼び出しを実行するか、S-Function の最適な C/C++ コードを組み込むために使用されます (mdlRTW の使用の例を参照してください)。
エラーの処理
sfun_directlook.tlc
では、mdlCheckParameters
ルーチンは次の内容を検証します。
新しいパラメーター設定は有効である。
XData
とYData
は有限実数を含んでいる同じ長さのベクトルである。XDataEvenlySpaced
はスカラー値である。XData
ベクトルは単調増加のベクトルであり、等間隔に分布している。
関数 mdlInitializeSizes
は、S-Function に渡されるパラメーターの数を確認すると、明示的に mdlCheckParameters
を呼び出します。Simulink エンジンは mdlInitializeSizes
を呼び出した後、パラメーターの変更やその再評価のたびに mdlCheckParameters
を呼び出します。
ユーザー データのキャッシュ
sfun_directlook.tlc
では、mdlStart
ルーチンは、シミュレーション中 (または生成コードの実行中) にも変わらない情報をキャッシュする方法を示します。例では、SimStruct
のフィールドである UserData
の XDataEvenlySpaced
パラメーターの値をキャッシュします。以下の mdlInitializeSizes
の行によって、XDataEvenlySpaced
への変更は認められないということが Simulink エンジンに指示されます。
ssSetSFcnParamTunable(S, iParam, SS_PRM_NOT_TUNABLE);
実行中、mdlOutputs
は mxGetPr
MATLAB API 関数を呼び出さずに UserData
から XDataEvenlySpaced
の値にアクセスします。
mdlRTW の使用
コード ジェネレーターは、
ファイルの生成中にルーチン model
.rtwmdlRTW
を呼び出します。Simulink に最適なコードを生成するために、S-Function ブロックが動作するモードに関する情報を
ファイルに追加することができます。model
.rtw
この例では、パラメーターの設定を
ファイルに追加します。パラメーターの設定内容が実行中に変化することはありません。今回、model
.rtwXDataEvenlySpaced
S-Function パラメーターは実行中に変化しません (ssSetSFcnParamTunable
は、mdlInitializeSizes
のパラメーターで false (0
) として指定されました)。パラメーター設定 (XSpacing
) は関数 ssWriteRTWParamSettings
を使用します。
xData
と yData
は mdlSetWorkWidths
でランタイム パラメーターとして登録されているため、コード ジェネレーターは自動的に
ファイルに書き込みます。model
.rtw
S-Function およびインライン化 TLC ファイルを調査する前に、このモデルの生成コードを検討してください。
モデルは、上部の S-Function ブロックでは等間隔の XData
を使用し、下部の S-Function ブロックでは等間隔ではない XData
を使用します。このモデルを作成するときは、各 S-Function ブロックに次のコマンドを指定します。
set_param('sfun_directlook_ex/S-Function','SFunctionModules','lookup_index') set_param('sfun_directlook_ex/S-Function1','SFunctionModules','lookup_index')
このビルド プロセスでは実行可能ファイルの作成時にモジュール lookup_index.c
を使用します。
このモデルのコードを生成する際、コード ジェネレーターは S-Function mdlRTW
メソッドを使用して
ファイルを生成します。このとき、上部 S-Function ブロックの model
.rtwXSpacing
パラメーターには値 EvenlySpaced
が、下部 S-Function ブロックの XSpacing
パラメーターには値 UnEvenlySpaced
が使用されます。TLC ファイルは、XSpacing
の値を使用して生成コードに含めるアルゴリズムを決定します。生成コードは XData
が等間隔であればルックアップ アルゴリズムを含みますが、XData
が等間隔でないときには GetDirectLookupIndex
ルーチンを呼び出します。ルックアップ テーブルのモデル例について生成される
または model
.c
コードは次のコードと同様です。model
.cpp
/* * sfun_directlook_ex.c * * Code generation for Simulink model * "sfun_directlook_ex.slx". * ... */ #include "sfun_directlook_ex.h" #include "sfun_directlook_ex_private.h" /* External outputs (root outports fed by signals with auto storage) */ ExtY_sfun_directlook_ex_T sfun_directlook_ex_Y; /* Real-time model */ RT_MODEL_sfun_directlook_ex_T sfun_directlook_ex_M_; RT_MODEL_sfun_directlook_ex_T *const sfun_directlook_ex_M = &sfun_directlook_ex_M_; /* Model output function */ void sfun_directlook_ex_output(void) { /* local block i/o variables */ real_T rtb_SFunction; real_T rtb_SFunction1; /* Sin: '<Root>/Sine Wave' */ rtb_SFunction1 = sin(sfun_directlook_ex_M->Timing.t[0]); /* Code that is inlined for the top S-function block in the * sfun_directlook_ex model */ /* S-Function (sfun_directlook): '<Root>/S-Function' */ { const real_T *xData = sfun_directlook_ex_ConstP.SFunction_XData; const real_T *yData = sfun_directlook_ex_ConstP.SFunction_YData; real_T spacing = xData[1] - xData[0]; if (rtb_SFunction1 <= xData[0] ) { rtb_SFunction = yData[0]; } else if (rtb_SFunction1 >= yData[20] ) { rtb_SFunction = yData[20]; } else { int_T idx = (int_T)( ( rtb_SFunction1 - xData[0] ) / spacing ); rtb_SFunction = yData[idx]; } } /* Outport: '<Root>/Out1' */ sfun_directlook_ex_Y.Out1 = rtb_SFunction; /* Code that is inlined for the bottom S-function block in the * sfun_directlook_ex model */ /* S-Function (sfun_directlook): '<Root>/S-Function1' */ { const real_T *xData = sfun_directlook_ex_ConstP.SFunction1_XData; const real_T *yData = sfun_directlook_ex_ConstP.SFunction1_YData; int_T idx; idx = GetDirectLookupIndex(xData, 5, rtb_SFunction1); rtb_SFunction1 = yData[idx]; } /* Outport: '<Root>/Out2' */ sfun_directlook_ex_Y.Out2 = rtb_SFunction1; } /* Model update function */ void sfun_directlook_ex_update(void) { /* signal main to stop simulation */ { /* Sample time: [0.0s, 0.0s] */ if ((rtmGetTFinal(sfun_directlook_ex_M)!=-1) && !((rtmGetTFinal(sfun_directlook_ex_M)-sfun_directlook_ex_M->Timing.t[0]) > sfun_directlook_ex_M->Timing.t[0] * (DBL_EPSILON))) { rtmSetErrorStatus(sfun_directlook_ex_M, "Simulation finished"); } } /* Update absolute time for base rate */ /* The "clockTick0" counts the number of times the code of this task has * been executed. The absolute time is the multiplication of "clockTick0" * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not * overflow during the application lifespan selected. * Timer of this task consists of two 32 bit unsigned integers. * The two integers represent the low bits Timing.clockTick0 and the high bits * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment. */ if (!(++sfun_directlook_ex_M->Timing.clockTick0)) { ++sfun_directlook_ex_M->Timing.clockTickH0; } sfun_directlook_ex_M->Timing.t[0] = sfun_directlook_ex_M->Timing.clockTick0 * sfun_directlook_ex_M->Timing.stepSize0 + sfun_directlook_ex_M->Timing.clockTickH0 * sfun_directlook_ex_M->Timing.stepSize0 * 4294967296.0; } ...