Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

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

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

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

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

要件の特定

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

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

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

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

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

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

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

モデルの作成

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

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

top_model_gen_reentrant_code_simFuncBlk.png

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

dinteg_expansion.png

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

func_calc_expansion.png

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

multiinstfunc_expansion.png

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

functioncallsubsys_expansion.png

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

Simulink Function ブロックの設定

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

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

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

multiinstfunc_triggerport.png

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

関数の呼び出し元の設定

Simulink Function ブロックを呼び出すようにブロックを構成します。Simulink Function ブロックは、Function Caller ブロック、Stateflow® Chart ブロックまたは MATLAB Function ブロックから呼び出すことができます。この例では、Function Caller ブロックを使用します。それぞれのブロックで、ブロック パラメーター [関数プロトタイプ] の値を設定します。プロトタイプの入力を開始します。たとえば、y と入力します。モデルの関数定義に基づくプロトタイプ オプションが選択リストに表示されます。各関数呼び出しに対応するプロトタイプを選択します。

functioncaller_prototype.png

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

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

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

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

サブシステムの構成

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

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

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

参照モデルの構成

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

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

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

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

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

最上位モデルの設定

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

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

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

オプションで、モデルのエントリポイント関数インターフェイスをカスタマイズできます。エントリポイント関数名を指定できます。実行 (ステップ) エントリポイント関数の場合、関数名と引数を設定できます。カスタムのエントリポイント関数インターフェイスでは、生成コードと統合する既存の外部コードに対する変更を最小にできます。この例では、既定の関数インターフェイスを使用します。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/DiscreteIntegratorFunction/DiscreteIntegratorFunction.c に配置します。

real_T DiscreteIntegratorFunction_multiinstfunc(DiscreteIntegratorFunc_RT_MODEL * const
const DiscreteIntegratorFunctionrtM, const real_T rtu_u)
{
    real_T rty_y_0;
    real_T rtb_TmpLatchAtIn2Outport1;
    real_T rtb_TmpLatchAtInOutport1;
    
    rtb_TmpLatchAtInOutport1 =
    *DiscreteIntegratorFunctionrtM->DiscreteIntegratorFurtextInport.rtu_In1;
    
    rtb_TmpLatchAtIn2Outport1 =
    *DiscreteIntegratorFunctionrtM->DiscreteIntegratorFurtextInport.rtu_In2;
    
    *DiscreteIntegratorFunctionrtM->DiscreteIntegratorFrtextOutport.rty_Out2 = 2.0
    * rtb_TmpLatchAtInOutport1;
    
    DiscreteIntegratorFun_func_calc(DiscreteIntegratorFunctionrtM,
    rtb_TmpLatchAtIn2Outport1,
    DiscreteIntegratorFunctionrtM->DiscreteIntegratorFrtextOutport.rty_Out1);
    
    rty_y_0 = DiscreteIntegratorFunctionrtM->dwork.DiscreteIntegrator_DSTATE;
    
    DiscreteIntegratorFunctionrtM->dwork.DiscreteIntegrator_DSTATE += 0.1 * rtu_u;
    return rty_y_0;
}

サブシステムで定義された Simulink Function ブロックの関数コード

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

void DiscreteIntegratorFun_func_calc(DiscreteIntegratorFunc_RT_MODEL * const
DiscreteIntegratorFunctionrtM, real_T rtu_u, real_T *rty_y)
{
    DiscreteIntegratorFunctionrtM->dwork.calcMem =
    DiscreteIntegratorFunctionrtM->dwork.UnitDelay_DSTATE;
    
    *rty_y = DiscreteIntegratorFunctionrtM->dwork.calcMem;
    
    DiscreteIntegratorFunctionrtM->dwork.UnitDelay_DSTATE = rtu_u * 0.07;
    }

再利用可能な関数のマルチインスタンス データを格納する構造体

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

typedef struct DiscreteIntegratorFunct_tag_RTM DiscreteIntegratorFunc_RT_MODEL;

マルチインスタンス参照モデルの初期化コード

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

void DiscreteIntegratorFunctio_Start(DiscreteIntegratorFunc_RT_MODEL *const
  DiscreteIntegratorFunctionrtM, const real_T *rtu_In1, const real_T *rtu_In2,
  real_T *rty_Out2, real_T *rty_Out1)
{
  DiscreteIntegratorFunctionrtM->DiscreteIntegratorFurtextInport.rtu_In1 =
    rtu_In1;
  DiscreteIntegratorFunctionrtM->DiscreteIntegratorFurtextInport.rtu_In2 =
    rtu_In2;
  DiscreteIntegratorFunctionrtM->DiscreteIntegratorFrtextOutport.rty_Out2 =
    rty_Out2;
  DiscreteIntegratorFunctionrtM->DiscreteIntegratorFrtextOutport.rty_Out1 =
    rty_Out1;
}
void DiscreteIntegratorFu_initialize(const char_T **rt_errorStatus,
  DiscreteIntegratorFunc_RT_MODEL *const DiscreteIntegratorFunctionrtM)
{
  {
    rtmSetErrorStatusPointer(DiscreteIntegratorFunctionrtM, rt_errorStatus);
  }
}

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

 ...
  DiscreteIntegratorFu_initialize(rtmGetErrorStatusPointer(rtM),
    (&(rtM->Instance1)));

  DiscreteIntegratorFu_initialize(rtmGetErrorStatusPointer(rtM),
    (&(rtM->Instance2)));

  DiscreteIntegratorFunctio_Start((&(rtM->Instance1)), &rtU->In2, &rtU->In3,
    &rtY->Out2, &rtY->Out3);

  DiscreteIntegratorFunctio_Start((&(rtM->Instance2)), &rtU->In4, &rtU->In5,
    &rtY->Out4, &rtY->Out5);
...

最上位モデルのエントリポイント関数宣言

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

extern void ClientServerCommunication_initialize(RT_MODEL *const rtM);

extern void Run(RT_MODEL *const rtM);

参照モデルのエントリポイント関数宣言

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

extern void DiscreteIntegratorFu_initialize(const char_T **rt_errorStatus,
  DiscreteIntegratorFunc_RT_MODEL *const DiscreteIntegratorFunctionrtM);

extern real_T DiscreteIntegratorFunction_multiinstfunc
  (DiscreteIntegratorFunc_RT_MODEL * const DiscreteIntegratorFunctionrtM, const
   real_T rtu_u);

extern void DiscreteIntegratorFunctio_Start(DiscreteIntegratorFunc_RT_MODEL *
  const DiscreteIntegratorFunctionrtM, const real_T *rtu_In1, const real_T
  *rtu_In2, real_T *rty_Out2, real_T *rty_Out1);

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

Embedded Coder を使用している場合、モデル コードの C++ クラス インターフェイスを生成できます。この例では、モデル CppComponent. を使用します。

reentrantCodeSimFuncBlk_top_cppmodel2.png

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

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

void FuncDintegCPP::multiinstfunc(const real_T rtu_u, real_T *rty_y)
{
  real_T rtb_TmpLatchAtIn2Outport1;
  real_T rtb_TmpLatchAtInOutport1;

  rtb_TmpLatchAtInOutport1 = *FuncDintegCPPrtrtu_In1;

  rtb_TmpLatchAtIn2Outport1 = *FuncDintegCPPrtrtu_In2;

  *FuncDintegCPPrtrty_Out2 = 2.0 * rtb_TmpLatchAtInOutport1;

  FuncDintegCPP_func_calc(rtb_TmpLatchAtIn2Outport1, FuncDintegCPPrtrty_Out1);

  *rty_y = FuncDintegCPPrtDW.DiscreteIntegrator_DSTATE;

  FuncDintegCPPrtDW.DiscreteIntegrator_DSTATE += 0.1 * rtu_u;
}

サブシステムで定義された Simulink Function ブロックの関数コード

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

void FuncDintegCPP::FuncDintegCPP_func_calc(real_T rtu_u, real_T *rty_y)
{
  FuncDintegCPPrtDW.calcMem = FuncDintegCPPrtDW.UnitDelay_DSTATE;

  *rty_y = FuncDintegCPPrtDW.calcMem;

  FuncDintegCPPrtDW.UnitDelay_DSTATE = rtu_u * 0.07;
}

再利用可能な関数のマルチインスタンス データを格納する構造体

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

typedef struct FuncDintegCPP_tag_RTM FuncDintegCPP_RT_MODEL;

マルチインスタンス参照モデルの初期化コード

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

void FuncDintegCPP::start(const real_T *rtu_In1, const real_T *rtu_In2, real_T
  *rty_Out2, real_T *rty_Out1)
{
  FuncDintegCPPrtrtu_In1 = rtu_In1;
  FuncDintegCPPrtrtu_In2 = rtu_In2;
  FuncDintegCPPrtrty_Out2 = rty_Out2;
  FuncDintegCPPrtrty_Out1 = rty_Out1;
}
...

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

void CppComponent::initialize()
{
  Instance1MDLOBJ0.setErrorStatusPointer(rtmGetErrorStatusPointer((&rtM)));
  Instance2MDLOBJ1.setErrorStatusPointer(rtmGetErrorStatusPointer((&rtM)));

  Instance1MDLOBJ0.start(&rtU.In2, &rtU.In3, &rtY.Out2, &rtY.Out3);
  Instance2MDLOBJ1.start(&rtU.In4, &rtU.In5, &rtY.Out4, &rtY.Out5);
}

最上位モデルのクラス宣言

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

class CppComponent
{
 public:
  RT_MODEL * getRTM();

  ExtU rtU;
  ExtY rtY;

  void initialize();
  void Run();

  // Constructor
  CppComponent();

  // Destructor
  ~CppComponent();

 private:
  FuncDintegCPP Instance1MDLOBJ0;
  FuncDintegCPP Instance2MDLOBJ1;

  RT_MODEL rtM;
};

参照モデルのクラス宣言

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

class FuncDintegCPP
{
 public:
  void start(const real_T *rtu_In1, const real_T *rtu_In2, real_T *rty_Out2,
             real_T *rty_Out1);

  void multiinstfunc(const real_T rtu_u, real_T *rty_y);

  FuncDintegCPP_RT_MODEL * getRTM();

  void setErrorStatusPointer(const char_T **rt_errorStatus);

  // Constructor
  FuncDintegCPP();

  // Destructor
  ~FuncDintegCPP();

 private:
  FuncDintegCPP_DW FuncDintegCPPrtDW;

  const real_T *FuncDintegCPPrtrtu_In1;// '<Root>/In1'
  const real_T *FuncDintegCPPrtrtu_In2;// '<Root>/In2'
  real_T *FuncDintegCPPrtrty_Out2;     // '<Root>/Out2'
  real_T *FuncDintegCPPrtrty_Out1;     // '<Root>/Out1'

  void FuncDintegCPP_func_calc(real_T rtu_u, real_T *rty_y);

  FuncDintegCPP_RT_MODEL FuncDintegCPPrtM;
};

制限

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

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

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

以下は実行できない:

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

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

関連するトピック