Main Content

コード再利用のための S-Function

モデルの内部とすべての参照モデルの全域に複数のインスタンスとして存在する同一のサブシステムに対しては、生成コードを再利用できます。コードを再利用するためのサブシステムのコード生成の詳細については、サブシステム コードを別々の関数およびファイルとして生成を参照してください。

S-Function でのコード再利用の要件

サブシステムのコード再利用に S-Function を使用するには、その S-Function が次の要件を満たす必要があります。

  • インライン化されている。

  • S-Function から生成されたコードでは静的変数を使用しない。

  • S-Function は mdlStart でのみポインター作業ベクトルを初期化する。あらかじめ行っておく必要はない。

  • ワークスペースにデータのログを作成するシンクではない。

  • S-Function のパラメーターを mdlSetWorkWidths でランタイム パラメーターとして登録する (このために、S-Function は関数 mdlRTWssWriteRTWParameters を使用してはならない)。

  • デバイス ドライバーではない。

S-Function はSS_OPTION_WORKS_WITH_CODE_REUSEフラグを関数ssSetOptionsで設定する必要があります。このフラグは、サブシステムのコード再利用のための要件を S-Function が満たしていることを示します。フラグが設定されており、S-Function が要件を満たさない場合、コード ジェネレーターによって再利用可能な関数が生成されず、警告が表示されます。

モデル間で再利用される S-Function

S-Function は再利用可能なライブラリ サブシステム内に配置できます。S-Function ファイルで次の両方のフラグを設定します。

legacy_codeツールを使用して S-Function を生成する場合は、S-Function のオプション supportCodeReuseAcrossModels を使用して、S-Function を含むサブシステムのモデル間でのコード再利用を指定することができます。

S-Function がモデル固有のデータ構造体にアクセスしない場合にのみ、モデル間でコードを再利用するための S-Function の設定を行います。_sharedutils フォルダー内に生成されるコードが model_ert_rtw folder 内に生成されるコードから個別にコンパイルされるため、この設定が必要です。_sharedutils フォルダーに生成される再利用可能なライブラリ サブシステム コードでは、model.h で宣言されたタイプおよびマクロにアクセスできません。再利用可能なライブラリ サブシステム コードは独立していなければなりません。詳細については、モデル間で共有されるライブラリ サブシステムからの再利用可能なコードの生成を参照してください。

外部ヘッダー ファイルで定義されるカスタム関数を S-Function で使用する場合は、関数LibAddtoSystemCustomIncludes(system, incFileName)を S-Function の TLC ファイルに追加します。たとえば、.tlc ファイルに LibAddtoSystemCustomIncludes("company_math.h") を追加すると、_sharedutils フォルダー内の再利用可能なライブラリ サブシステム コードに #company_math.h ヘッダー ファイルが含まれます。

1. モデル例 SFunctionForCodeReuse を開きます。このモデル例では、再利用可能なライブラリ サブシステム SFunctionForCodeReuseLibrary の 2 つのインスタンスを使用します。再利用可能なライブラリ サブシステム内の S-Function sfun_mySrc では、外部ファイル doubleIt.cdoubleIt.h を使用します。

SFunctionForCodeReuse;

2. レガシ コード ツールを使用して S-Function コードを生成します。MATLAB コマンド ウィンドウで次のコマンドを使用します。

def = legacy_code('initialize');
def.SFunctionName = 'sfun_mySrc';
def.SourceFiles = {'doubleIt.c'};
def.HeaderFiles = {'doubleIt.h'};
def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';

3. S-Function でコード再利用のための指定を次のように行います。

def.Options.supportCodeReuseAcrossModels = true;

4. S-Function コードの TLC ブロック ファイルを生成します。次に、S-Function をコンパイルします。

legacy_code('sfcn_tlc_generate',def);
legacy_code('sfcn_cmex_generate', def);
legacy_code('compile', def);
### Start Compiling sfun_mySrc
    mex('-I/tmp/Bdoc23b_2369753_864902/tp6de1e44d/simulinkcoder-ex43633418', '-c', '-outdir', '/tmp/Bdoc23b_2369753_864902/tpba7860ea_4c77_4291_9e9a_6251010bc75b', '/tmp/Bdoc23b_2369753_864902/tp6de1e44d/simulinkcoder-ex43633418/doubleIt.c')
Building with 'gcc'.
MEX completed successfully.
    mex('sfun_mySrc.c', '-I/tmp/Bdoc23b_2369753_864902/tp6de1e44d/simulinkcoder-ex43633418', '/tmp/Bdoc23b_2369753_864902/tpba7860ea_4c77_4291_9e9a_6251010bc75b/doubleIt.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling sfun_mySrc
### Exit

5. コード ジェネレーターによって、MATLAB 作業フォルダーに S-Function ファイル sfun_mySrc.c およびその TLC ファイル sfun_mySrc.tlc が作成されます。sfun_mySrc.c ファイルでは、コード ジェネレーターによって以下の仕様が追加されます。

file = fullfile('sfun_mySrc.c');
coder.example.extractLines(file,'* All options have the form SS_OPTION_<name>', ...
    'ssSetSupportedForCodeReuseAcrossModels(S, 1);',1,1);
     * All options have the form SS_OPTION_<name> and are documented in
     * matlabroot/simulink/include/simstruc.h. The options should be
     * bitwise or'd together as in
     *    ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2))
     */
    ssSetOptions(S,
        SS_OPTION_USE_TLC_WITH_ACCELERATOR |
        SS_OPTION_CAN_BE_CALLED_CONDITIONALLY |
        SS_OPTION_EXCEPTION_FREE_CODE |
        SS_OPTION_WORKS_WITH_CODE_REUSE |
        SS_OPTION_SFUNCTION_INLINED_FOR_RTW |
        SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME
    );
    ssSetSupportedForCodeReuseAcrossModels(S, 1);

sfun_mySrc.c で、SS_OPTION_WORKS_WITH_CODE_REUSE フラグが関数 ssSetOptions で設定され、ssSetSupportedForCodeReuseAcrossModels が true に設定されます。

6. Simulink® ツールストリップで、"Embedded Coder" アプリまたは "Simulink Coder" アプリを開きます。

7. モデルのコードを生成します。[C コード] タブで、[ビルド] をクリックします。

evalc('slbuild(''SFunctionForCodeReuse'')');

コード ジェネレーターは、モデル間で再利用できる再利用可能関数を _sharedutils フォルダーに生成します。モデル参照階層内のモデルでは、この _sharedutils フォルダーを共有し、コードを再利用します。次の例では、再利用可能関数が slprj/grt/_sharedutils/sfunc.c ファイルに生成されます。

file = fullfile('slprj','grt','_sharedutils','sfunc.c');
coder.example.extractLines(file,'Output and update for atomic system', ...
    'rtb_sfun_mySrc',1,1);
%
 * Output and update for atomic system:
 *    'ReusableSubsystem' ('SFunctionForCodeReuseLibrary:60')
 *    'ReusableSubsystem' ('SFunctionForCodeReuseLibrary:60')
 */
void sfunc(real_T rtu_In1, B_sfunc_T *localB, DW_sfunc_T *localDW)
{
  /* local block i/o variables */
  real_T rtb_sfun_mySrc;

モデル内で再利用される S-Function

既定では、サブシステム内の S-Function にモデル内でコードを再利用するための設定は行われません。サブシステム内の S-Function は、モデル内でコードを再利用するために指定できます。S-Function ファイルの関数 ssSetOptionsSS_OPTION_WORKS_WITH_CODE_REUSE フラグを設定します。このフラグは、S-Function がサブシステムのコード再利用のための要件を満たし、コード再利用のために設定されていることを示します。フラグが設定されており、S-Function が要件を満たさない場合、コード ジェネレーターによって再利用可能な関数が生成されず、警告が表示されます。

1. モデル例 SFunctionForCodeReuse の場合は、レガシ コード ツールを使用して S-Function コードを生成します。S-Function のオプション supportCodeReuseAcrossModels は含めないでください。MATLAB コマンド ウィンドウで次のコマンドを使用します。

def = legacy_code('initialize');
def.SFunctionName = 'sfun_mySrc';
def.SourceFiles = {'doubleIt.c'};
def.HeaderFiles = {'doubleIt.h'};
def.OutputFcnSpec = 'double y1 = doubleIt(double u1)';

2. S-Function コードの TLC ブロック ファイルを生成します。次に、S-Function をコンパイルします。

legacy_code('sfcn_tlc_generate',def);
legacy_code('sfcn_cmex_generate', def);
legacy_code('compile', def);
### Start Compiling sfun_mySrc
    mex('-I/tmp/Bdoc23b_2369753_864902/tp6de1e44d/simulinkcoder-ex69241103', '-c', '-outdir', '/tmp/Bdoc23b_2369753_864902/tpb22371ad_8e29_4226_9b6a_6cd8bf6a5862', '/tmp/Bdoc23b_2369753_864902/tp6de1e44d/simulinkcoder-ex69241103/doubleIt.c')
Building with 'gcc'.
MEX completed successfully.
    mex('sfun_mySrc.c', '-I/tmp/Bdoc23b_2369753_864902/tp6de1e44d/simulinkcoder-ex69241103', '/tmp/Bdoc23b_2369753_864902/tpb22371ad_8e29_4226_9b6a_6cd8bf6a5862/doubleIt.o')
Building with 'gcc'.
MEX completed successfully.
### Finish Compiling sfun_mySrc
### Exit

3. コード ジェネレーターによって、MATLAB 作業フォルダーに S-Function ファイル sfun_mySrc.c およびその TLC ファイル sfun_mySrc.tlc が作成されます。

file = fullfile('sfun_mySrc.c');
coder.example.extractLines(file,'* All options have the form SS_OPTION_<name>', ...
    'SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME',1,1);
     * All options have the form SS_OPTION_<name> and are documented in
     * matlabroot/simulink/include/simstruc.h. The options should be
     * bitwise or'd together as in
     *    ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2))
     */
    ssSetOptions(S,
        SS_OPTION_USE_TLC_WITH_ACCELERATOR |
        SS_OPTION_CAN_BE_CALLED_CONDITIONALLY |
        SS_OPTION_EXCEPTION_FREE_CODE |
        SS_OPTION_WORKS_WITH_CODE_REUSE |
        SS_OPTION_SFUNCTION_INLINED_FOR_RTW |
        SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME

sfun_mySrc.c ファイルにはコード ジェネレーターによって既定で、関数 ssSetOptionsSS_OPTION_WORKS_WITH_CODE_REUSE フラグが追加されますが、S-Function がモデル間で再利用されることを妨げる ssSetSupportedForCodeReuseAcrossModels の仕様は含められません。

4. Simulink ツールストリップで、"Embedded Coder" アプリまたは "Simulink Coder" アプリを開きます。

5. モデルのコードを生成します。[C コード] タブで、[ビルド] をクリックします。

evalc('slbuild(''SFunctionForCodeReuse'')');

コード ジェネレーターは、サブシステムに対して再利用可能な関数を SFunctionForCodeReuse.c ファイルに生成します。このファイルは _sharedutils フォルダーの外にあります。以下のコードはモデル内で再利用可能ですが、モデル参照階層全体では再利用できません。

file = fullfile('SFunctionForCodeReuse_grt_rtw','SFunctionForCodeReuse.c');
coder.example.extractLines(file,'void sfunc', ...
    'localDW->UnitDelay_DSTATE = rtb_sfun_mySrc;',1,1);
%
void sfunc_Init(DW_sfunc_T *localDW)
{
  /* InitializeConditions for UnitDelay: '<S1>/Unit Delay' */
  localDW->UnitDelay_DSTATE = 0.0;
}

/*
 * Output and update for atomic system:
 *    '<Root>/ReusableSubsystem'
 *    '<Root>/ReusableSubsystem1'
 */
void sfunc(real_T rtu_In1, B_sfunc_T *localB, DW_sfunc_T *localDW)
{
  /* local block i/o variables */
  real_T rtb_sfun_mySrc;

  /* UnitDelay: '<S1>/Unit Delay' */
  localB->UnitDelay = localDW->UnitDelay_DSTATE;

  /* S-Function (sfun_mySrc): '<S1>/sfun_mySrc' */
  rtb_sfun_mySrc = doubleIt(rtu_In1);

  /* Update for UnitDelay: '<S1>/Unit Delay' */
  localDW->UnitDelay_DSTATE = rtb_sfun_mySrc;

関連するトピック