Main Content

変数名およびループ ローリングの探索

timesN ループ チュートリアルの概要

目的: この例では、生成コードのループ動作を変更する方法について説明します。

次の例を開きます。

openExample('simulinkcoder/AdviceAboutTLCTutorialsExample')
cd('tlctutorial/timesN')

tlctutorial/timesN でモデル sfun_xN を操作します。1 つのソース (Sine Wave ジェネレーター ブロック)、times N ゲイン ブロック、Out ブロック、および Scope ブロックがあります。

このチュートリアルでは、以下の手順を順を追って説明します。

  1. 入門 — 演習を設定してモデルを実行

  2. モデルの変更 — 入力幅を変更して結果を確認

  3. ループ ローリングしきい値の変更 — しきい値を変更して結果を確認

  4. TLC ループ ローリングの詳細 — ループ動作をパラメーター化

入門

  1. tlctutorial/timesN を現在のフォルダーにし、提供されているファイルを使用できるようにします。

  2. MATLAB® コマンド ウィンドウで、S-Function の MEX ファイルを作成します。

    mex timesN.c

    これにより、Simulink® に付属しているバージョンが選択されなくなります。

    メモ

    まだ mex -setup を実行していない場合は、エラーが発生することがあります。

  3. モデル ファイル sfun_xN を開きます。

  4. sfun_xN_grt_rtw/sfun_xN.c にある以前に生成されたコードを表示します。ループがコードに存在していないことに注意します。これは、入出力信号がスカラーであるためです。

モデルの変更

  1. Sine Wave ブロックを Constant ブロックに置き換えます。

  2. Constant ブロックのパラメーターを 1:4 に設定し、上のラベル model: sfun_xNmodel: sfun_vec に変更します。

  3. 編集したモデルを (tlctutorial/timesN 内の) sfun_vec として保存します。これで、モデルは次のようになります。

  4. Constant ブロックで値のベクトルが生成されるため、これはベクトル化モデルです。モデルのコードを生成し、エディターで sfun_vec.c/*Model output function */ セクションを表示して、変数および for ループがどのように処理されるのかを観察します。この関数は以下のように表示されます。

    /* Model output function */
    static void sfun_vec_output(int_T tid)
    {
      /* S-Function Block: <Root>/S-Function */
      /* Multiply input by 3.0 */
      sfun_vec_B.timesN_output[0] = sfun_vec_P.Constant_Value[0] * 3.0;
      sfun_vec_B.timesN_output[1] = sfun_vec_P.Constant_Value[1] * 3.0;
      sfun_vec_B.timesN_output[2] = sfun_vec_P.Constant_Value[2] * 3.0;
      sfun_vec_B.timesN_output[3] = sfun_vec_P.Constant_Value[3] * 3.0;
    
      /* Outport: '<Root>/Out' */
      sfun_vec_Y.Out[0] = sfun_vec_B.timesN_output[0];
      sfun_vec_Y.Out[1] = sfun_vec_B.timesN_output[1];
      sfun_vec_Y.Out[2] = sfun_vec_B.timesN_output[2];
      sfun_vec_Y.Out[3] = sfun_vec_B.timesN_output[3];
      UNUSED_PARAMETER(tid);
    }

    モデル出力を生成するコードのインスタンスが 4 つあり、4 回の反復に対応していることに注意します。

  5. Constant ブロックのパラメーターを 1:10 に設定し、モデルを保存します。

  6. モデルのコードを生成し、エディターで sfun_vec.c/*Model output function */ セクションを表示して、変数および for ループがどのように処理されるのかを観察します。この関数は以下のように表示されます。

    /* Model output function */
    static void sfun_vec_output(int_T tid)
    {
      /* S-Function Block: <Root>/S-Function */
      /* Multiply input by 3.0 */
      {
        int_T i1;
        const real_T *u0 = &sfun_vec_P.Constant_Value[0];
        real_T *y0 = sfun_vec_B.timesN_output;
        for (i1=0; i1 < 10; i1++) {
          y0[i1] = u0[i1] * 3.0;
        }
      }
    
      {
        int32_T i;
        for (i = 0; i < 10; i++) {
          /* Outport: '<Root>/Out' */
          sfun_vec_Y.Out[i] = sfun_vec_B.timesN_output[i];
        }
      }
    
      UNUSED_PARAMETER(tid);
    }

次の点に注意してください。

  • モデル出力を生成するコードがループに "ロール" されます。既定では、これは反復回数が 5 回を超えると行われます。

  • ループのインデックス i1 は 0 から 9 までです。

  • ポインター *y0 が使用され、出力信号配列に初期化されます。

ループ ローリングしきい値の変更

コード ジェネレーターは、[ループ展開のしきい値] パラメーターの現在の値に応じて反復またはループを作成します。

[ループ展開のしきい値] の既定値は 5 です。モデル内のブロックのループ動作を変更するには、以下のようにします。

  1. [コンフィギュレーション パラメーター] ダイアログ ボックスの [最適化] ペインで、[ループ展開のしきい値]12 に設定し、Apply をクリックします。

    パラメーター RollThreshold12 になりました。ループが生成されるのは、ブロックを通過する信号の幅が 12 を超えている場合のみです。

    メモ

    [コンフィギュレーション パラメーター] ダイアログ ボックスから特定のブロックの RollThreshold を変更することはできません。

  2. Ctrl+B を押して出力を再生成します。

  3. sfun_vec.c を検査します。次のようになります。

    /* Model output function */
    static void sfun_vec_output(int_T tid)
    {
      /* S-Function Block: <Root>/S-Function */
      /* Multiply input by 3.0 */
      sfun_vec_B.timesN_output[0] = sfun_vec_P.Constant_Value[0] * 3.0;
      sfun_vec_B.timesN_output[1] = sfun_vec_P.Constant_Value[1] * 3.0;
      sfun_vec_B.timesN_output[2] = sfun_vec_P.Constant_Value[2] * 3.0;
      sfun_vec_B.timesN_output[3] = sfun_vec_P.Constant_Value[3] * 3.0;
      sfun_vec_B.timesN_output[4] = sfun_vec_P.Constant_Value[4] * 3.0;
      sfun_vec_B.timesN_output[5] = sfun_vec_P.Constant_Value[5] * 3.0;
      sfun_vec_B.timesN_output[6] = sfun_vec_P.Constant_Value[6] * 3.0;
      sfun_vec_B.timesN_output[7] = sfun_vec_P.Constant_Value[7] * 3.0;
      sfun_vec_B.timesN_output[8] = sfun_vec_P.Constant_Value[8] * 3.0;
      sfun_vec_B.timesN_output[9] = sfun_vec_P.Constant_Value[9] * 3.0;
    
      /* Outport: '<Root>/Out' */
      sfun_vec_Y.Out[0] = sfun_vec_B.timesN_output[0];
      sfun_vec_Y.Out[1] = sfun_vec_B.timesN_output[1];
      sfun_vec_Y.Out[2] = sfun_vec_B.timesN_output[2];
      sfun_vec_Y.Out[3] = sfun_vec_B.timesN_output[3];
      sfun_vec_Y.Out[4] = sfun_vec_B.timesN_output[4];
      sfun_vec_Y.Out[5] = sfun_vec_B.timesN_output[5];
      sfun_vec_Y.Out[6] = sfun_vec_B.timesN_output[6];
      sfun_vec_Y.Out[7] = sfun_vec_B.timesN_output[7];
      sfun_vec_Y.Out[8] = sfun_vec_B.timesN_output[8];
      sfun_vec_Y.Out[9] = sfun_vec_B.timesN_output[9];
      UNUSED_PARAMETER(tid);
    }
  4. ループ ローリングを再度有効にするには、[最適化] ペインで [ループ展開のしきい値] を 10 以下に変更します。

ループ ローリングは、生成コードを最適化するための重要な TLC 機能です。時間をとってその影響を調査、探索してから、量産要件向けのコードを生成してください。

TLC ループ ローリングの詳細

次の TLC %roll コードは timesN.tlc の関数 Outputs です。

%function Outputs(block, system) Output
  /* %<Type> Block: %<Name> */
  %%
  /* Multiply input by %<gain> */
  %assign rollVars = ["U", "Y"]
  %roll idx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars
     %<LibBlockOutputSignal(0, "", lcv, idx)> = \
    %<LibBlockInputSignal(0, "", lcv, idx)> * %<gain>;
  %endroll
%endfunction %% Outputs

%roll の引数

%roll と %endroll の間の行は繰り返すか、ループにすることができます。%roll 命令の理解の鍵は、その引数にあります。

%roll sigIdx = RollRegions, lcv = RollThreshold, block, "Roller", rollVars
引数説明
sigIdx

生成コードで使用される (信号) ベクトルのインデックスを指定します。信号がスカラーの場合、model.rtw ファイルの該当するブロックの解析時に、TLC はコード行が 1 行のみ必要であると判断します。この場合、ベクトルの 1 番目の要素にのみアクセスするために sigIdx0 に設定され、ループは作成されません。

lcv

%roll 命令で lcv = RollThreshold として一般的に指定される制御変数。RollThreshold はグローバル (モデル全体の) しきい値であり、既定値は 5 です。したがって、ブロックに 5 個を超える連続したロール可能変数が含まれている場合には常に、TLC は %roll%endroll の間に入れ子にされた行を 1 つのループに折り畳みます。連続したロール可能変数が 5 個を下回っている場合には、%roll はループを作成せず、個別のコード行を生成します。

block

これは、ブロック オブジェクトに対して操作するように TLC に指示します。S-Function 用の TLC コードはこの引数を使用します。

"Roller"

これは rtw/c/tlc/roller.tlc で指定され、ループの形式を設定します。通常、これはそのまま渡しますが、高度な用途では他のループ制御構成も可能です (入力信号関数LibBlockInputSignal を参照)。

rollVars

ロールする項目のタイプ (入力信号、出力信号、またはパラメーター、あるいはその組み合わせ) を TLC に指示します。すべてを使用する必要はありません。前の行で、%assign を使用して rollVars が定義されています。

%assign rollVars = ["U", "Y"]
このリストは、入力信号 (U) および出力信号 (Y) をロールすることを TLC に指示します。ブロックでスカラー パラメーターではなくパラメーターの配列が指定される場合は、rollvars は以下のように指定されます。
%assign rollVars = ["U", "Y", "P"]

入力信号、出力信号、およびパラメーター

%roll%endroll の間にある行を見てみましょう。

%<LibBlockOutputSignal(0, "", lcv, idx)> = \
%<LibBlockInputSignal (0, "", lcv, idx)> * 2.0;

TLC ライブラリ関数 LibBlockInputSignal および LibBlockOutputSignal が展開され、名前とインデックスが付けられたスカラーまたはベクトル識別子が生成されます。LibBlockInputSignalLibBlockOutputSignal、および多くの関連 TLC 関数には以下の 4 つの正準引数が渡されます。

引数説明

最初の引数 — 0

所定のブロックの入力端子インデックスに対応しています。最初の入力端子のインデックスは 0 です。2 番目の入力端子のインデックスは 1 で、以下同様に続きます。

2 番目の引数 — " "

高度な用途のために予約されているインデックス変数。ここでは、2 番目の引数は空 string として指定します。高度な用途では、%roll を指定してインデックスとして使用する独自の変数名を定義できます。そのような場合には、TLC は生成コード内の場所に整数としてこの変数を宣言します。

3 番目の引数 — lcv

前述のとおり、lcv = RollThreshold%roll で設定され、RollThreshold (既定値 5) を超えている場合に常にループを作成することを指示します。

4 番目の引数 — sigIdx

TLC で特殊ケースを処理できるようにします。RollThreshold を超えて "いない" 場合 (たとえば、ブロックがスカラー入力信号にのみ接続されている場合)、TLC はループにロールしません。そうではなく、TLC は "インライン" コードの対応する行のインデックス変数に整数値を提供します。RollThreshold を超えている場合は常に、TLC は for ループを作成し、インデックス変数を使用してループ内の入力、出力、およびパラメーターにアクセスします。

関連するトピック