mdlRTW ルーチンでの完全インライン化 S-Function の記述
S-Function mdlRTW ルーチンを使用することで、より複雑な S-Function をインライン化できます。mdlRTW ルーチンにより、TLC ファイルで使用する調整できないパラメーターのパラメーター レコードを作成することによって、S-Function のインライン方法に関する詳細情報をコード生成プロセスに対して提供します。mdlRTW ルーチンは情報を ファイルに配置します。関数 model.rtwmdlRTW は、テキスト ファイル に記述されます。matlabroot/toolbox/simulink/blocks/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;
}
...