Main Content

Simulink Function ブロックからの再呼び出し可能なコードの生成

Embedded Coder® を使用している場合は、アルゴリズムをスコープが設定された Simulink Function ブロックとして表すことで、再利用可能な、再呼び出し可能コードを生成できます。Simulink Function ブロックから再呼び出し可能コードを生成する例として、モデル内の関数の呼び出し元間またはクライアント/サーバー アプリケーションで関数が状態を共有する場合があります。エクスポート関数モデルで共有されている Simulink Function ブロックの複数のインスタンスを使用して、高度にモジュール化されたコードを生成できます。コード ジェネレーターは関数コードを生成し、関数の各使用または呼び出しをインスタンス固有のデータに関連付けます。関数のスコープは、モデルのルート レベルまたはサブシステム内のどちらに関数を置くかによって異なります。

以下を設定するときに、コード ジェネレーターによって再呼び出し可能な関数コードが生成されます。

関数定義の 1 つ上のレベル、同じレベル、または 1 つ下のレベルからスコープが設定された Simulink Function ブロックで表される関数を呼び出します。Atomic サブシステムまたは非バーチャル サブシステムで関数のスコープを設定できますが、関数呼び出しのアクセスは、階層の同一以下のレベルに制限されます。関数名を一意にする必要はありません。

要件の特定

モデルの設計前また設計中に、以下の点を考慮してください。

  • 必要な各関数のインスタンス数

  • 関数の呼び出しサイトを関数定義を含むモデルに制限する必要があるかどうか

  • 関数をローカル環境内の信号と連動させても、呼び出し元にはそれらの信号を非表示にする必要があるかどうか

  • 関数が直接相互にやりとりする必要があるかどうか

  • 関数が外部 I/O に接続する必要があるかどうか

  • 関数の出力をログに記録する必要があるかどうか

モデルの作成

モデル コンポーネントの例 rtwdemo_comp を使用して、Simulink Function ブロックを使って再呼び出し可能な C コードを生成する方法を示します。C++ コードを生成する場合は、モデル例 rtwdemo_comp_cpp を使用します。モデルを開いて、モデルの階層構造を調べます。

モデルの最上位レベルには、1 つの Function-Call Subsystem と参照モデルの 2 つのインスタンスが含まれます。

参照モデル rtwdemo_func_dinteg は、関数 multiinstfunc を定義する 1 つの Simulink Function ブロックとサブシステム subsys_calc で構成されています。

サブシステムは Simulink Function ブロックで構成されています。この Simulink Function ブロックの使用は、ブロックが定義する関数のスコープをサブシステムを含むモデルに制限できることを示します。コード ジェネレーターは、func_calc の関数コードを生成し、関数の各呼び出しをインスタンス固有のデータに関連付けます。データには、メモリに格納されているデータなどの状態が含まれます。

関数 multiinstfunc を定義する Simulink Function ブロックは、Function Caller ブロックを使用して関数 func_calc を呼び出します。その Simulink Function ブロックは、Inport ブロックと Outport ブロックを通じてブロックのローカル環境内の信号と連携できることも示します。

モデル rtwdemo_comp の最上位レベルで、Function-Call Subsystem は Function Caller ブロックを使用して関数 multiinstfunc の 2 つのインスタンスを呼び出します。コード ジェネレーターは関数コードを生成し、各呼び出しをインスタンス固有のデータに関連付けます。

モデルとモデル要素の設定

Simulink Function ブロックの設定

関数の Trigger Port ブロックのパラメーターを設定して Simulink Function を設定します。コード ジェネレーターで Simulink Function ブロックから再呼び出し可能なコードを生成するには、次を実行します。

  • 同じ関数名のブロック インスタンスを設定する。

  • ブロック パラメーター [関数の可視性][スコープ内] に設定する。

この例では、参照モデル rtwdemo_func_dinteg の 2 つのインスタンスにある Simulink Function ブロックの関数名が multiinstfunc として指定されています。

Function Caller ブロックの設定

Function Caller ブロックを設定します。ブロックごとに、ブロック パラメーター [関数プロトタイプ] を設定します。プロトタイプの入力を開始します。たとえば、y と入力します。モデルの関数定義に基づくプロトタイプ オプションが選択リストに表示されます。各関数呼び出しに対応するプロトタイプを選択します。

この例では、プロトタイプが以下のように設定されています。

  • Function-Call Subsystem については、関数の呼び出し元のプロトタイプが y = Instance1.multiinstfunc(u) および y = Instance2.multiinstfunc(u) として設定される。Instancen 接頭辞は各関数の呼び出しを一意に識別し、呼び出しを独自のデータセットと関連付けます。

  • 関数 multiinstfunc の関数の呼び出し元は、プロトタイプ y = subsys_calc.func_calc(u) で設定される。接頭辞 subsys_calc は、関数定義を含むサブシステムを識別します。

この例では、入力引数と出力引数の指定とサンプル時間で既定の設定が保持されます。

サブシステムの構成

モデル例のサブシステムでは構成の変更は不要です。サブシステムに Simulink Function ブロックを含めると、コード ジェネレーターは以下を実行します。

  • 関数のスコープをサブシステムが含まれるモデルに設定する。

  • サブシステムを Atomic サブシステムとして扱う

参照モデルの構成

次の方法で、Simulink Function ブロックを含む参照モデルを構成します。

  • [ブロック パラメーター] ダイアログ ボックスで、パラメーター [モデル名] を参照モデル ファイル名に設定する。この例では、モデル名は rtwdemo_func_dinteg.slx です。

  • モデル コンフィギュレーション パラメーター [最上位モデルごとに可能なインスタンスの総数][複数] に設定します。

  • 参照モデルの C++ クラス インターフェイスを生成するには、モデル コンフィギュレーション パラメーター [言語][C++] に設定し、パラメーター [コード インターフェイスのパッケージ化][C++ クラス] に設定する。

オプションで、モデルのエントリポイント関数インターフェイスをカスタマイズできます。エントリポイント関数名を指定できます。実行 (ステップ) エントリポイント関数の場合、関数名と引数を設定できます。カスタムのエントリポイント関数インターフェイスでは、生成コードと統合する既存の外部コードに対する変更を最小にできます。この例では、既定の関数インターフェイスを使用します。Configure Entry-Point Function Interfaces for Simulink Function and Function Caller Blocks (Embedded Coder)を参照してください。

最上位モデルの設定

モデル コンポーネントの最上位モデルを設定します。モデル コンポーネント (最上位モデル) を再利用可能にする場合は、モデル コンフィギュレーション パラメーター [コード インターフェイスのパッケージ化][再利用可能な関数] に設定します。C++ コードを生成している場合は、このパラメーターを [C++ クラス] に設定できます。いずれかの場合、以下も実行します。

  • モデル コンフィギュレーション パラメーター [マルチインスタンス コードのエラーの診断][エラー] に設定する。

  • モデル コンフィギュレーション パラメーター [ルートレベル I/O を以下として渡す][モデル データ構造体の一部] に設定する。

オプションで、モデルのエントリポイント関数インターフェイスをカスタマイズできます。エントリポイント関数名を指定できます。実行 (ステップ) エントリポイント関数の場合、関数名と引数を設定できます。カスタムのエントリポイント関数インターフェイスでは、生成コードと統合する既存の外部コードに対する変更を最小にできます。この例では、既定の関数インターフェイスを使用します。Configure Entry-Point Function Interfaces for Simulink Function and Function Caller Blocks (Embedded Coder)を参照してください。

C コードの生成と検査

モデルの C コードを生成します。

  • マルチインスタンス Simulink Function ブロックに対する関数コード

    別のモデルで複数回使用するスコープが設定された Simulink Function ブロックを参照モデルに配置すると、コード ジェネレーターは参照モデルの model.c ファイルに関数コードを配置します。この例では、コード ジェネレーターは multiinstfunc の関数コードを slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.c に配置します。

    real_T rtwdemo_func_dinteg_multiinstfunc(RT_MODEL_rtwdemo_func_dinteg_T * const
      rtwdemo_func_dinteg_M, const real_T rtu_u)
    {
      real_T rtb_TmpLatchAtInOutport1;
      real_T rtb_TmpLatchAtIn2Outport1;
      real_T rty_y_0;
    
      rtb_TmpLatchAtInOutport1 =
        *rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In1;
    
      rtb_TmpLatchAtIn2Outport1 =
        *rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In2;
    
      *rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out2 = 2.0 *
        rtb_TmpLatchAtInOutport1;
      
      rtwdemo_func_dinteg_func_calc(rtwdemo_func_dinteg_M, rtb_TmpLatchAtIn2Outport1,
        rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out1);
    
      rty_y_0 = rtwdemo_func_dinteg_M->dwork.DiscreteIntegrator_DSTATE;
    
      rtwdemo_func_dinteg_M->dwork.DiscreteIntegrator_DSTATE += 0.1 * rtu_u;
      return rty_y_0;
    }
    
  • サブシステムで定義された Simulink Function ブロックの関数コード

    コード ジェネレーターは、サブシステムを含むモデルの model.c ファイルにサブシステムで定義した Simulink Function ブロックの関数コードを配置します。この例では、コード ジェネレーターは func_calc の関数コードを slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.c に配置します。

    void rtwdemo_func_dinteg_func_calc(RT_MODEL_rtwdemo_func_dinteg_T * const
      rtwdemo_func_dinteg_M, real_T rtu_u, real_T *rty_y)
    {
      rtwdemo_func_dinteg_M->dwork.calcMem =
        rtwdemo_func_dinteg_M->dwork.UnitDelay_DSTATE;
    
      *rty_y = rtwdemo_func_dinteg_M->dwork.UnitDelay_DSTATE;
    
      rtwdemo_func_dinteg_M->dwork.UnitDelay_DSTATE = rtu_u * 0.07;
    }
    
  • 再利用可能な関数のマルチインスタンス データを格納する構造体

    コード ジェネレーターはリアルタイム モデル (RT_MODEL) データ構造体に似た構造体を使用して、再利用可能な関数に関連付けられたマルチインスタンス データを格納します。コード ジェネレーターはこの構造体を slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.h で定義します。

    typedef struct rtwdemo_func_dinteg_tag_RTM RT_MODEL_rtwdemo_func_dinteg_T;
    
  • マルチインスタンス参照モデルの初期化コード

    同じスコープが設定された Simulink Function ブロックを含む参照モデルの各インスタンスで、コード ジェネレーターは初期化および起動関数コードを生成します。初期化コードの 1 つのコピーが slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.c で定義されます。

    void rtwdemo_func_dinteg_Start(RT_MODEL_rtwdemo_func_dinteg_T *const
      rtwdemo_func_dinteg_M, const real_T *rtu_In1, const real_T *rtu_In2, real_T
      *rty_Out2, real_T *rty_Out1)
    {
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In1 = rtu_In1;
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextInport.rtu_In2 = rtu_In2;
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out2 = rty_Out2;
      rtwdemo_func_dinteg_M->rtwdemo_func_dintegrtextOutport.rty_Out1 = rty_Out1;
    }
    
    void rtwdemo_func_dinteg_initialize(const char_T **rt_errorStatus,
      RT_MODEL_rtwdemo_func_dinteg_T *const rtwdemo_func_dinteg_M)
    {
      {
        rtmSetErrorStatusPointer(rtwdemo_func_dinteg_M, rt_errorStatus);
      }
    }
    

    初期化コードは、同じ Simulink Function ブロックを含む参照モデルの各インスタンスで呼び出されます。このコードはビルド フォルダーのファイル rtwdemo_comp.c にあります。

    .
    .
    .
    rtwdemo_func_dinteg_initialize(rtmGetErrorStatusPointer(rtwdemo_comp_M),
      (&(rtwdemo_comp_M->Instance1)));
      
    rtwdemo_func_dinteg_initialize(rtmGetErrorStatusPointer(rtwdemo_comp_M),
      (&(rtwdemo_comp_M->Instance2)));
    
    rtwdemo_func_dinteg_Start((&(rtwdemo_comp_M->Instance1)), &rtU->In2, &rtU->In3,
      &rtY->Out2, &rtY->Out3);
      
    rtwdemo_func_dinteg_Start((&(rtwdemo_comp_M->Instance2)), &rtU->In4, &rtU->In5,
      &rtY->Out4, &rtY->Out5);
    }
    
  • 最上位モデルのエントリポイント関数宣言

    モデル ヘッダー ファイル rtwdemo_comp.h には、最上位モデルの初期化、終了、実行 (run) エントリポイント関数の extern 宣言が含まれます。

    extern void rtwdemo_comp_initialize(RT_MODEL_rtwdemo_comp_T *const
      rtwdemo_comp_M);
    
    extern void Run(RT_MODEL_rtwdemo_comp_T *const rtwdemo_comp_M);
    
  • 参照モデルのエントリポイント関数宣言

    ヘッダー ファイル slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg.h には、参照モデルのエントリポイント関数の extern 宣言が含まれます。

    extern void rtwdemo_func_dinteg_initialize(const char_T **rt_errorStatus,
      RT_MODEL_rtwdemo_func_dinteg_T *const rtwdemo_func_dinteg_M);
    extern real_T rtwdemo_func_dinteg_multiinstfunc(RT_MODEL_rtwdemo_func_dinteg_T * 
      const rtwdemo_func_dinteg_M, const real_T rtu_u);
    extern void rtwdemo_func_dinteg_Start(RT_MODEL_rtwdemo_func_dinteg_T *const 
      rtwdemo_func_dinteg_M, const real_T *rtu_In1, const real_T *rtu_In2, real_T
      *rty_Out2, real_T *rty_Out1);
    

C++ コードの生成と検査

モデルの C++ コードを生成します。

  • マルチインスタンス Simulink Function ブロックに対する関数コード

    別のモデルで複数回使用するスコープが設定された Simulink Function ブロックを参照モデルに配置すると、コード ジェネレーターは参照モデルの model.cpp ファイルに関数コードを配置します。この例では、コード ジェネレーターは multiinstfunc の関数コードを slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.cpp に配置します。

    real_T rtwdemo_func_dintegModelClass::multiinstfunc(const real_T rtu_u)
    {
      real_T rtb_TmpLatchAtInOutport1;
      real_T rtb_TmpLatchAtIn2Outport1;
      real_T rty_y_0;
    
      rtb_TmpLatchAtInOutport1 = *rtwdemo_func_dinteg_cprtrtu_In1;
    
      rtb_TmpLatchAtIn2Outport1 = *rtwdemo_func_dinteg_cprtrtu_In2;
    
      *rtwdemo_func_dinteg_crtrty_Out2 = 2.0 * rtb_TmpLatchAtInOutport1;
    
      rtwdemo_func_dinteg_c_func_calc(rtb_TmpLatchAtIn2Outport1,
        rtwdemo_func_dinteg_crtrty_Out1);
    
      rty_y_0 = rtwdemo_func_dinteg_cpprtDW.DiscreteIntegrator_DSTATE;
    
      rtwdemo_func_dinteg_cpprtDW.DiscreteIntegrator_DSTATE += 0.1 * rtu_u;
      return rty_y_0;
    }
  • サブシステムで定義された Simulink Function ブロックの関数コード

    コード ジェネレーターは、サブシステムで定義された Simulink Function ブロックの関数コードを、サブシステムを含むモデルの model.cpp に配置します。この例では、コード ジェネレーターは func_calc の関数コードを slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.cpp に配置します。

    void rtwdemo_func_dintegModelClass::rtwdemo_func_dinteg_c_func_calc(real_T rtu_u,
      real_T *rty_y)
    {
      rtwdemo_func_dinteg_cpprtDW.calcMem =
        rtwdemo_func_dinteg_cpprtDW.UnitDelay_DSTATE;
    
      *rty_y = rtwdemo_func_dinteg_cpprtDW.UnitDelay_DSTATE;
    
      rtwdemo_func_dinteg_cpprtDW.UnitDelay_DSTATE = rtu_u * 0.07;
    }
    
  • 再利用可能な関数のマルチインスタンス データを格納する構造体

    コード ジェネレーターはリアルタイム モデル (RT_MODEL) データ構造体に似た構造体を使用して、[再利用可能な関数] に関連付けられたマルチインスタンス データを格納します。コード ジェネレーターはこの構造体を slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.h で定義します。

    typedef struct rtwdemo_func_dinteg_cpp_tag_RTM rtwdemo_func_dinteg_cp_RT_MODEL;
    
  • マルチインスタンス参照モデルの初期化コード

    同じスコープが設定された Simulink Function ブロックを含む参照モデルの各インスタンスで、コード ジェネレーターは初期化および起動関数コードを生成します。初期化コードの 1 つのコピーが slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.cpp で定義されます。

    void rtwdemo_func_dintegModelClass::start(real_T *rtu_In1, real_T *rtu_In2,
      real_T *rty_Out2, real_T *rty_Out1)
    {
      rtwdemo_func_dinteg_cprtrtu_In1 = rtu_In1;
      rtwdemo_func_dinteg_cprtrtu_In2 = rtu_In2;
      rtwdemo_func_dinteg_crtrty_Out2 = rty_Out2;
      rtwdemo_func_dinteg_crtrty_Out1 = rty_Out1;
    }
    .
    .
    .
    void rtwdemo_func_dintegModelClass::initializeRTM()
    {
      (void) memset((void *)((&rtwdemo_func_dinteg_cpprtM)), 0,
                    sizeof(rtwdemo_func_dinteg_cp_RT_MODEL));
    }
    

    初期化コードは、同じ Simulink Function ブロックを含む参照モデルの各インスタンスで呼び出されます。このコードはビルド フォルダーのファイル rtwdemo_comp_cpp.cpp にあります。

    .
    .
    .
    
    Instance1MDLOBJ0.initializeRTM();
    
    Instance1MDLOBJ0.setErrorStatusPointer(rtmGetErrorStatusPointer((&rtM)));
    Instance1MDLOBJ0.initialize();
    
    Instance2MDLOBJ1.initializeRTM();
    
    Instance2MDLOBJ1.setErrorStatusPointer(rtmGetErrorStatusPointer((&rtM)));
    	
    Instance1MDLOBJ0.start(&rtU.In2, &rtU.In3, &rtY.Out2, &rtY.Out3);
    
    Instance2MDLOBJ1.start(&rtwU.In4, &rtwU.In5, &rtY.Out4, &rtY.Out5);
    }
  • 最上位モデルのクラス宣言

    モデル ヘッダー ファイル rtwdemo_comp_cpp.h には、最上位モデルのクラス宣言が含まれます。

    class rtwdemo_compModelClass {
     public:
      ExtU rtU;
    
      ExtY rtY;
    
      void initialize();
    
      void Run();
    
      rtwdemo_compModelClass();
    
      ~rtwdemo_compModelClass();
    
      RT_MODEL * getRTM();
    
     private:
      RT_MODEL rtM;
    
      rtwdemo_func_dintegModelClass Instance1MDLOBJ0;
    
      rtwdemo_func_dintegModelClass Instance2MDLOBJ1;
    };
    
  • 参照モデルのクラス宣言

    ヘッダー ファイル slprj/ert/rtwdemo_func_dinteg/rtwdemo_func_dinteg_cpp.h には、参照モデルのクラス宣言が含まれます。

    class rtwdemo_func_dintegModelClass {
     public:
      real_T multiinstfunc(const real_T rtu_u);
    
      void start(real_T *rtu_In1, real_T *rtu_In2, real_T *rty_Out2, real_T
    	            *rty_Out1);
    
      rtwdemo_func_dintegModelClass();
    	
      ~rtwdemo_func_dintegModelClass();
    
      rtwdemo_func_dinteg_cp_RT_MODEL * getRTM();
    
      void initializeRTM();
    
      void setErrorStatusPointer(const char_T **rt_errorStatus);
    
     private:
      rtwdemo_func_dinteg_cpp_DW rtwdemo_func_dinteg_cpprtDW;
    
      const real_T *rtwdemo_func_dinteg_cprtrtu_In1;
      const real_T *rtwdemo_func_dinteg_cprtrtu_In2;
      real_T *rtwdemo_func_dinteg_crtrty_Out2;
      real_T *rtwdemo_func_dinteg_crtrty_Out1;
    
      rtwdemo_func_dinteg_cp_RT_MODEL rtwdemo_func_dinteg_cpprtM;
    
      void rtwdemo_func_dinteg_c_func_calc(real_T rtu_u, real_T *rty_y);
    };

制限

コード生成に関する以下の制限は、Simulink Function ブロックの複数のインスタンスを含むエクスポート関数モデルに適用されます。

  • モデル コンフィギュレーション パラメーター [ルートレベル I/O を以下として渡す][Part of model data structure] に設定しなければならない。

  • 生成コードはシングルスレッド実行のみと互換する。共有信号データの競合状態を回避するには、同じ実行スレッドから関数コードのインスタンスを呼び出します。

  • 以下は実行できない:

    • エクスポート関数モデルにモデル バリアントが含まれる場合にコードを生成する。

    • Stateflow® チャートから生成コードを呼び出す。

    • エクスターナル モードのデータ交換インターフェイスを有効にする。

関連するトピック