Main Content

マルチレート マルチタスク環境での S-Function

マルチレート マルチタスク環境での S-Function について

S-Function は複数のサンプル レートがあるモデルで使用したり、マルチタスク ターゲット環境で展開することができます。同様に、S-Function が動作するレートを S-Function 自体が複数指定することもできます。コード ジェネレーターは、"レート グルーピング" と呼ばれる方法を使って、マルチレート マルチタスク モデルのコードを生成します。ERT ベースのターゲット用に生成されるコードでは、レート グルーピングによって、モデル内の基本レート タスクと各サブレート タスクに対し、個別に関数 model_step が生成されます。レート グルーピングは ERT ターゲットのみで使用されるコード生成機能ですが、以下に記載されているように S-Function をコード化すると、S-Function がその他のコンテキストでレート グルーピングを使用できるようになります。

S-Function でのレート グルーピングのサポート

レート グルーピングを利用するには、マルチレートの S-Function のインライン化が済んでいなければそれを実行しなければなりません。レート グルーピングを使用するには、Target Language Compiler の特定のプロトコルに従う必要があります。レート グルーピングを使用するために TLC をコード化しても、インライン化 S-Function が GRT で適切に機能しなくなることはありません。同様に、レート グルーピングに準拠させなくても、インライン化 S-Function によって有効な ERT コードが生成されます。ただし、マルチレートのモデルでより効率的なコードが生成されます。

S-Function を作成および更新してレート グルーピングに準拠したコードを生成する方法を示す Target Language Compiler コードの説明と例については、Rate Grouping Compliance and Compatibility Issuesを参照してください。

レート グルーピングに準拠しないマルチレート S-Function については、それぞれ、作成時にコード ジェネレーターから次の警告が発せられます。

Warning:  Simulink Coder: Code of output function for multirate block
'<Root>/S-Function' is guarded by sample hit checks rather than being rate
grouped. This will generate the same code for all rates used by the block,
possibly generating dead code. To avoid dead code, you must update the TLC
file for the block.

準拠していない S-Function のそれぞれに対して生成されるコードには、次のようなコメントもあります。

/* Because the output function of multirate block
   <Root>/S-Function is not rate grouped,
   the following code might contain unreachable blocks of code.
   To avoid this, you must update your block TLC file. */

これらの警告では、"update function" という語句が "output function" の代わりに使用されます。

マルチタスクで、マルチレートの、端子ベースのサンプル時間 S-Function の作成

次に、マルチレート S-Function でデータの確定性とデータの整合性の両方をサポートする方法を説明します。確定性も完全性も存在しない場合については説明しません。フレームベースの処理のサポートは、要件に影響を及ぼしません。

メモ

遅いレートは最速レートの倍数でなければなりません。相互に作用する 2 つのレートが倍数でない場合やレートが周期的なものでない場合、ここに記載されていることは適用されません。

高速から低速への転移を適切に処理するための規則

次に、マルチレート S-Function が入力を観測するときの規則を示します。

  • 入力は、入力端子のサンプル時間に関連付けられているレートでのみ読み取られる。

  • 通常、入力データは DWork に書き込まれ、DWork は遅い (下流) レートで関連付けられる。

入力は入力レートのサンプル ヒットごとに読み取り、DWork メモリに書き込むことができますが、この DWork メモリに遅いレートで直接アクセスすることはできません。遅いレートで読み取られる DWork メモリは、"特別なサンプル ヒット" があるときに速いレートのみで書き込まなければなりません。特別なサンプル ヒットは、入力端子のレートと、そのレートと相互に作用するレートにヒットがあるときに発生します。要件と設計に基づいて、アルゴリズムは複数の位置でデータを処理することができます。

次に、マルチレート S-Function が出力を観測するときの規則を示します。

  • 以下に説明される最適化の事例を除いて、出力端子に割り当てられているレートと異なるレートで、出力が書き込まれることはありません。

  • 出力端子のサンプル レートにヒットがあるときには必ず出力が書き込まれます。

これらの条件を満たせば、S-Function ブロックは、入出力端子がローカルで再利用可能になるように指定することができます。

処理のほとんどまたはすべてをデータで実行する必要がなければ、最適化を含めることができます。このような場合、特別なサンプル ヒットがあると、入力レート コードは (DWork を使用する代わりに) 出力に直接書き込まれます。ただし、これを実行する場合、出力端子が "グローバル" で "再利用不可" になるように宣言しなければなりません。この最適化によって memcpy が 1 つ減りますが、速いレートでの一様ではない処理要件が導入されます。

この最適化を使用してもしなくても、遅いレートで見られるように、最新の入力データは速いレートと遅いレートにそれぞれヒット (さらにアルゴリズムによっては、できるだけ前の入力データも) があるときの値になります。速いレートでの続きのステップと関連付けられている入力データの更新は、遅いレートの次のヒットが現れるまで遅いレートでは行われません。

速いレートから遅いレートに遷移する疑似コードの例

以下の疑似コードでは、C MEX コードを記述して速いレートから遅いレートへ遷移する方法を示し、出力レートを 1 秒にする入力レート 0.1 秒で説明します。同様の方法は、コードをインライン化するときに使用できます。ブロックには次の特性があります。

  • ファイル: sfun_multirate_zoh.c、式: y = u(tslow)

  • 入力: ローカルで再利用可能

  • 出力: ローカルで再利用可能

  • DirectFeedthrough: あり

    OutputFcn
    if (ssIsSampleHit(".1")) {
        if (ssIsSepcialSampleHit("1")) {
            DWork = u;
        }
    }
    if (ssIsSampleHit("1")) {
        y = DWork;
    }

単純なアルゴリズム向けにわずかに最適化されている代替方法:

  • 入力: ローカルで再利用可能

  • 出力: 特別なサンプル ヒット間で保持する必要があるためグローバルかつ再利用不可

  • DirectFeedthrough: あり

    OutputFcn
    if (ssIsSampleHit(".1")) {
        if (ssIsSpecialSampleHit("1")) {
            y = u;
        }
    }

単純なアルゴリズムを追加する例:

  • ファイル: sfun_multirate_avg.c、式: y = average(u)

  • 入力: ローカルで再利用可能

  • 出力: ローカルで再利用可能

  • DirectFeedthrough: あり

    (DWork[0:10]DWork[mycounter] はゼロに初期化されると仮定)

    OutputFcn
    if (ssIsSampleHit(".1")) {
        /* In general, processing on 'u' could be done here,
            it runs on every hit of the fast rate. */
        DWork[DWork[mycounter]++] = u;
        if (ssIsSpecialSampleHit("1")) {
        /* In general, processing on DWork[0:10] can be done 
           here, but it does cause the faster rate to have 
           nonuniform processing requirements (every 10th hit, 
           more code needs to be run).*/
            DWork[10] = sum(DWork[0:9])/10;
            DWork[mycounter] = 0;
        }
    }
    if (ssIsSampleHit("1")) {
        /* Processing on DWork[10] can be done here before
           outputing. This code runs on every hit of the 
           slower task. */
        y = DWork[10];
    }

低速から高速への転移を適切に処理するための規則

出力レートが入力レートよりも早い場合、入力は、次の規則に従って、入力端子のサンプル時間に関連付けられているレートでのみ読み取らなければなりません。

  • 入力を常に更新関数から読み取る。

  • 入力の読み取り時に特別なサンプル ヒットを使用しない。

  • 入力を DWork に書き込む。

  • レート間に特別なサンプル ヒットがある場合は、出力関数の 2 番目の DWork に DWork をコピーする。

  • 出力サンプル レートのヒットごとに、2 番目の DWork を出力に書き込む。

ブロックは、入力端子をローカルにしても利用不可に設定しないように要求できます。出力端子は、ローカルで再利用可能に設定することができます。

高速から低速への遷移のように、入力は、入力端子に割り当てられたレート以外のレートでは読み取られません。同様に、出力は、出力端子に割り当てられているレート以外のレートでは書き込まれません。

最適化は、実装されるアルゴリズムを低速で実行する必要があるときのみ行われます。このような場合は、1 つの DWork のみを使用します。入力は、更新関数の DWork に書き込まれます。レート間に特別なサンプル ヒットが存在する場合、出力関数は同じ DWork を直接出力にコピーします。この場合、出力端子がグローバルで再利用不可能になるように設定しなければなりません。この最適化によって、特別なサンプル ヒットごとに memcpy が 1 つ減ります。

いずれにしても、高速レートでの計算が行われるデータでは常に遅延が発生します。つまり、データは前のステップの低速レート コードからのものだということです。

遅いレートから速いレートに遷移する疑似コードの例

以下の疑似コードでは、遅いレートから速いレートへの遷移を処理するために S-Function が実行する内容を示し、出力レートを 1 秒にする入力レート 0.1 秒で説明します。ブロックには次の特性があります。

  • ファイル: sfun_multirate_delay.c、式: y = u(tslow-1)

  • 入力: 出力/更新が組み合わされている場合はローカル (ERT)、それ以外の場合はグローバル。更新関数が実行されるまで入力は保持されなければならないため、再利用不可に設定。

  • 出力: ローカルで再利用可能

  • DirectFeedthrough: なし

    OutputFcn
    if (ssIsSampleHit(".1") {
        if (ssIsSpecialSampleHit("1") {
            DWork[1] = DWork[0];
        }
        y = DWork[1];
    }
    UpdateFcn
    if (ssIsSampleHit("1")) {
        DWork[0] = u;
    }

いくつかのアルゴリズムで使用できる代替の最適化方法:

  • 入力: 出力/更新が組み合わされている場合はローカル (ERT)、それ以外の場合はグローバル。更新関数が実行されるまで入力は保持されなければならないため、再利用不可に設定。

  • 出力: 特別なサンプル ヒット間で保持する必要があるためグローバルかつ再利用不可。

  • DirectFeedthrough: なし

    OutputFcn
    if (ssIsSampleHit(".1") {
        if (ssIsSpecialSampleHit("1") {
            y = DWork;
        }
    }
    UpdateFcn
    if (ssIsSampleHit("1")) {
        DWork = u;
    }

単純なアルゴリズムを追加する例:

  • ファイル:sfun_multirate_modulate.c、式: y = sin(tfast) + u(tslow-1)

  • 入力: 出力/更新が組み合わされている場合はローカル (ERT 機能)、それ以外の場合はグローバル。更新関数が実行されるまで入力は保持されなければならないため、再利用不可に設定。

  • 出力: ローカルで再利用可能

  • DirectFeedthrough: なし

    OutputFcn
    if (ssIsSampleHit(".1") {
        if (ssIsSpecialSampleHit("1") {
        /* Processing not likely to be done here. It causes 
         * the faster rate to have nonuniform processing 
         * requirements (every 10th hit, more code needs to 
         * be run).*/
            DWork[1] = DWork[0];
        }
        /* Processing done at fast rate */
        y = sin(ssGetTaskTime(".1")) + DWork[1];
    }
    UpdateFcn
    if (ssIsSampleHit("1")) {
        /* Processing on 'u' can be done here. There is a delay of
           one slow rate period before the fast rate sees it.*/
        DWork[0] = u;}