Main Content

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

生成されたコードによる内部信号、状態、パラメーター データの保存方法

入力から出力を計算するには、生成されたコードは一部の "内部データ" をグローバル メモリに保存します。ルートレベルの入力または出力 (Inport ブロックまたは Outport ブロック) に接続しない信号は、内部データです。

内部データには、以下も含まれる場合があります。

  • Unit Delay ブロックの状態などのブロック状態。アルゴリズムには、実行サイクル間の状態値が維持されなければならないため、生成されたコードは通常、グローバル メモリに状態を保存します (たとえば、グローバル変数またはグローバル構造体変数のフィールドとして)。

  • コード ジェネレーターがコードでインライン化できない値をもつ Gain ブロックの [ゲイン] パラメーターなどのブロック パラメーター。たとえば、コード ジェネレーターは非スカラー パラメーターの値をインライン化できません。

  • Enabled Subsystem などの条件付きで実行されるサブシステムのステータス インジケーター。

より効率的なコードのため、[コンフィギュレーション パラメーター][既定のパラメーター動作] および [コンフィギュレーション パラメーター][信号ストレージの再利用] などで、内部データ向けのストレージの削減を試行する最適化を設定できます。ただし、最適化では生成されたコードでメモリを消費する、一部のデータのストレージを削除することはできません。

生成されたコードが内部データを保存する既定の形式を理解すると、次を行うことができます。

  • 既定で信号をアクセス可能にして、パラメーターを調整可能にします。すると、実行中にコードの操作と監視が可能になります。

  • 内部データのストレージを削除して、ハードウェアおよびビルド ツールチェーンに応じて、最適化により削除できないデータのメモリ内の配置を制御することで、効率的な量産コードを生成します。

  • 内部データの一部をモデル インターフェイスにプロモートし、コンポーネントおよびシステムがそのデータにアクセスできるようにします。

生成されたコードが呼び出し環境とインターフェイスを介してデータを交換する方法の詳細については、生成されたコードによる環境とのデータ交換方法を参照してください。

生成されたコードの内部データ

次の例は、生成されたコードがブロック状態などの内部データを保存する方法を示します。

モデル例の確認

モデル例 RollAxisAutopilot を開きます。

open_system('RollAxisAutopilot')

モデルには、ルートレベルの Inport ブロックまたは Outport ブロックに接続しない内部信号が含まれています。一部の信号には、phiCmd 信号などの名前があります。

またモデルには、状態データを維持する一部のブロックが含まれています。たとえば、BasicRollMode サブシステムの Integrator というラベルの Discrete-Time Integrator ブロックは状態を維持しています。

モデルで、[コンフィギュレーション パラメーター]、[コード生成]、[システム ターゲット ファイル]grt.tlc に設定します。

set_param('RollAxisAutopilot','SystemTargetFile','grt.tlc')

[コンフィギュレーション パラメーター]、[コード生成]、[インターフェイス]、[コード インターフェイスのパッケージ化] の設定を検査します。設定 Nonreusable function は、生成されたコードが再利用可能ではない (再呼び出し可能ではない) ことを意味します。

この例では、[コンフィギュレーション パラメーター]、[コード生成]、[インターフェイス]、[詳細設定パラメーター]、[MAT ファイルのログ] をクリアすることで、さらに簡単なコードを生成します。

set_param('RollAxisAutopilot','MatFileLogging','off')

再利用できないコードの生成

次のコンフィギュレーション パラメーターを設定します。

  • [既定のパラメーター動作] を [Tunable] に設定します。

  • [信号ストレージの再利用] をクリアします。

set_param('RollAxisAutopilot','DefaultParameterBehavior','Tunable',...
    'OptimizeBlockIOStorage','off')

モデルからコードを生成します。

slbuild('RollAxisAutopilot')
### Starting build procedure for: RollAxisAutopilot
### Successful completion of build procedure for: RollAxisAutopilot

Build Summary

Top model targets built:

Model              Action                        Rebuild Reason                                    
===================================================================================================
RollAxisAutopilot  Code generated and compiled.  Code generation information file does not exist.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 10.757s

ファイル RollAxisAutopilot.h は、内部データを表す複数の構造体型を定義します。たとえば、ブロック入力および出力構造体は、モデルの各内部信号の 1 つのフィールドを定義します。各フィールド名は、信号を生成するブロックの名前から派生するか、信号の名前を指定する場合は、信号の名前から派生します。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot.h');
coder.example.extractLines(file,...
    '/* Block signals (default storage) */','} B_RollAxisAutopilot_T;',1,1)
/* Block signals (default storage) */
typedef struct {
  real32_T phiCmd;                     /* '<Root>/ModeSwitch' */
  real32_T hdgError;                   /* '<S2>/Sum' */
  real32_T DispGain;                   /* '<S2>/DispGain' */
  real32_T Product;                    /* '<S2>/Product' */
  real32_T Abs;                        /* '<S3>/Abs' */
  real32_T FixPtUnitDelay1;            /* '<S4>/FixPt Unit Delay1' */
  real32_T Xnew;                       /* '<S4>/Enable' */
  real32_T TKSwitch;                   /* '<S3>/TKSwitch' */
  real32_T RefSwitch;                  /* '<S3>/RefSwitch' */
  real32_T Integrator;                 /* '<S1>/Integrator' */
  real32_T DispLimit;                  /* '<S1>/DispLimit' */
  real32_T Sum;                        /* '<S1>/Sum' */
  real32_T DispGain_f;                 /* '<S1>/DispGain' */
  real32_T RateLimit;                  /* '<S1>/RateLimit' */
  real32_T Sum1;                       /* '<S1>/Sum1' */
  real32_T RateGain;                   /* '<S1>/RateGain' */
  real32_T Sum2;                       /* '<S1>/Sum2' */
  real32_T CmdLimit;                   /* '<S1>/CmdLimit' */
  real32_T IntGain;                    /* '<S1>/IntGain' */
  boolean_T NotEngaged;                /* '<S3>/NotEngaged' */
  boolean_T TKThreshold;               /* '<S3>/TKThreshold' */
  boolean_T RefThreshold2;             /* '<S3>/RefThreshold2' */
  boolean_T RefThreshold1;             /* '<S3>/RefThreshold1' */
  boolean_T Or;                        /* '<S3>/Or' */
  boolean_T NotEngaged_e;              /* '<S1>/NotEngaged' */
} B_RollAxisAutopilot_T;

ファイルは、Discrete-Time Integrator ブロックの状態としてブロック状態を表す、構造体型の 1 つである DWork 構造体を定義します。

coder.example.extractLines(file,...
    '/* Block states (default storage) for system','} DW_RollAxisAutopilot_T;',1,1)
/* Block states (default storage) for system '<Root>' */
typedef struct {
  real32_T FixPtUnitDelay1_DSTATE;     /* '<S4>/FixPt Unit Delay1' */
  real32_T Integrator_DSTATE;          /* '<S1>/Integrator' */
  int8_T Integrator_PrevResetState;    /* '<S1>/Integrator' */
} DW_RollAxisAutopilot_T;

ファイルは、パラメーター データを表す構造体型を定義します。Gain ブロックの [ゲイン] パラメーターなどの、モデルの各調整可能なブロック パラメーターは、この構造体のフィールドとして表示されます。ブロック パラメーターが MATLAB® 変数または Simulink.Parameter オブジェクトから値を取得すると、この変数またはオブジェクトはブロック パラメーターではなくフィールドとして表示されます。

またファイルは、構造体型および生成されたコードで実行中にエラーが発生したかどうかの実行時指標を 1 つのフィールドで表す "リアルタイム モデル データ構造体" も定義します。

coder.example.extractLines(file,'/* Real-time Model Data Structure */',...
    '/* Block parameters (default storage) */',1,0)
/* Real-time Model Data Structure */
struct tag_RTM_RollAxisAutopilot_T {
  const char_T *errorStatus;
};

リアルタイム モデル データ構造体を表す構造体型の場合、ファイル RollAxisAutopilot_types.h は、生成されたコードで構造体にメモリを割り当てるために後で使用されるエイリアスを作成します。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot_types.h');
coder.example.extractLines(file,'/* Forward declaration for rtModel */',...
    'RT_MODEL_RollAxisAutopilot_T;',1,1)
/* Forward declaration for rtModel */
typedef struct tag_RTM_RollAxisAutopilot_T RT_MODEL_RollAxisAutopilot_T;

これらの構造体型を使用して、ファイル RollAxisAutopilot.c は生成されたアルゴリズムの内部データを保存するグローバル構造体変数の定義 (メモリの割り当て) を行います。またファイルは、リアルタイム モデル データ構造体を表す変数とその構造体を指すポインターも定義します。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot.c');
coder.example.extractLines(file,'/* Block signals (default storage) */',...
    '= &RollAxisAutopilot_M_;',1,1)
/* Block signals (default storage) */
B_RollAxisAutopilot_T RollAxisAutopilot_B;

/* Block states (default storage) */
DW_RollAxisAutopilot_T RollAxisAutopilot_DW;

/* External inputs (root inport signals with default storage) */
ExtU_RollAxisAutopilot_T RollAxisAutopilot_U;

/* External outputs (root outports fed by signals with default storage) */
ExtY_RollAxisAutopilot_T RollAxisAutopilot_Y;

/* Real-time model */
static RT_MODEL_RollAxisAutopilot_T RollAxisAutopilot_M_;
RT_MODEL_RollAxisAutopilot_T *const RollAxisAutopilot_M = &RollAxisAutopilot_M_;

プライマリ モデル アルゴリズムを表すモデルの関数 stepvoid void インターフェイス (引数なし) を使用します。

coder.example.extractLines(file,...
    '/* Model step function */','void RollAxisAutopilot_step(void)',1,1)
/* Model step function */
void RollAxisAutopilot_step(void)

関数定義では、アルゴリズムはグローバル変数に直接アクセスして、信号の中間結果および状態の構造体を計算して保存します。またアルゴリズムは、対応するグローバル変数からパラメーター データも読み取ります。たとえば、BasicRollMode サブシステムで、Integrator ブロック向けに生成されたコードは構造体からの信号、状態、およびパラメーター データの読み取りおよび書き込みを行います。

coder.example.extractLines(file,'/* DiscreteIntegrator: ''<S1>/Integrator'' *',...
    '/* End of DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
  /* DiscreteIntegrator: '<S1>/Integrator' */
  if (RollAxisAutopilot_B.NotEngaged_e ||
      (RollAxisAutopilot_DW.Integrator_PrevResetState != 0)) {
    RollAxisAutopilot_DW.Integrator_DSTATE = RollAxisAutopilot_P.Integrator_IC;
  }

  /* DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_B.Integrator = RollAxisAutopilot_DW.Integrator_DSTATE;

  /* Saturate: '<S1>/DispLimit' */
  u0 = RollAxisAutopilot_B.phiCmd;
  u1 = RollAxisAutopilot_P.DispLimit_LowerSat;
  u2 = RollAxisAutopilot_P.dispLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/DispLimit' */
    RollAxisAutopilot_B.DispLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/DispLimit' */
    RollAxisAutopilot_B.DispLimit = u1;
  } else {
    /* Saturate: '<S1>/DispLimit' */
    RollAxisAutopilot_B.DispLimit = u0;
  }

  /* End of Saturate: '<S1>/DispLimit' */

  /* Sum: '<S1>/Sum' incorporates:
   *  Inport: '<Root>/Phi'
   */
  RollAxisAutopilot_B.Sum = RollAxisAutopilot_B.DispLimit -
    RollAxisAutopilot_U.Phi;

  /* Gain: '<S1>/DispGain' */
  RollAxisAutopilot_B.DispGain_f = RollAxisAutopilot_P.dispGain *
    RollAxisAutopilot_B.Sum;

  /* Saturate: '<S1>/RateLimit' */
  u0 = RollAxisAutopilot_B.DispGain_f;
  u1 = RollAxisAutopilot_P.RateLimit_LowerSat;
  u2 = RollAxisAutopilot_P.rateLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/RateLimit' */
    RollAxisAutopilot_B.RateLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/RateLimit' */
    RollAxisAutopilot_B.RateLimit = u1;
  } else {
    /* Saturate: '<S1>/RateLimit' */
    RollAxisAutopilot_B.RateLimit = u0;
  }

  /* End of Saturate: '<S1>/RateLimit' */

  /* Sum: '<S1>/Sum1' incorporates:
   *  Inport: '<Root>/Rate_FB'
   */
  RollAxisAutopilot_B.Sum1 = RollAxisAutopilot_B.RateLimit -
    RollAxisAutopilot_U.Rate_FB;

  /* Gain: '<S1>/RateGain' */
  RollAxisAutopilot_B.RateGain = RollAxisAutopilot_P.rateGain *
    RollAxisAutopilot_B.Sum1;

  /* Sum: '<S1>/Sum2' */
  RollAxisAutopilot_B.Sum2 = RollAxisAutopilot_B.Integrator +
    RollAxisAutopilot_B.RateGain;

  /* Saturate: '<S1>/CmdLimit' */
  u0 = RollAxisAutopilot_B.Sum2;
  u1 = RollAxisAutopilot_P.CmdLimit_LowerSat;
  u2 = RollAxisAutopilot_P.cmdLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/CmdLimit' */
    RollAxisAutopilot_B.CmdLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/CmdLimit' */
    RollAxisAutopilot_B.CmdLimit = u1;
  } else {
    /* Saturate: '<S1>/CmdLimit' */
    RollAxisAutopilot_B.CmdLimit = u0;
  }

  /* End of Saturate: '<S1>/CmdLimit' */

  /* Gain: '<S1>/IntGain' */
  RollAxisAutopilot_B.IntGain = RollAxisAutopilot_P.intGain *
    RollAxisAutopilot_B.Sum1;

  /* Update for DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_DW.Integrator_DSTATE +=
    RollAxisAutopilot_P.Integrator_gainval * RollAxisAutopilot_B.IntGain;
  if (RollAxisAutopilot_DW.Integrator_DSTATE > RollAxisAutopilot_P.intLim) {
    RollAxisAutopilot_DW.Integrator_DSTATE = RollAxisAutopilot_P.intLim;
  } else if (RollAxisAutopilot_DW.Integrator_DSTATE <
             RollAxisAutopilot_P.Integrator_LowerSat) {
    RollAxisAutopilot_DW.Integrator_DSTATE =
      RollAxisAutopilot_P.Integrator_LowerSat;
  }

  RollAxisAutopilot_DW.Integrator_PrevResetState = (int8_T)
    RollAxisAutopilot_B.NotEngaged_e;

  /* End of Update for DiscreteIntegrator: '<S1>/Integrator' */
  /* End of Outputs for SubSystem: '<Root>/BasicRollMode' */

  /* Switch: '<Root>/EngSwitch' incorporates:
   *  Inport: '<Root>/AP_Eng'
   */
  if (RollAxisAutopilot_U.AP_Eng) {
    /* Outport: '<Root>/Ail_Cmd' */
    RollAxisAutopilot_Y.Ail_Cmd = RollAxisAutopilot_B.CmdLimit;
  } else {
    /* Outport: '<Root>/Ail_Cmd' incorporates:
     *  Constant: '<Root>/Zero'
     */
    RollAxisAutopilot_Y.Ail_Cmd = RollAxisAutopilot_P.Zero_Value_c;
  }

  /* End of Switch: '<Root>/EngSwitch' */
}

/* Model initialize function */
void RollAxisAutopilot_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(RollAxisAutopilot_M, (NULL));

  /* block I/O */
  (void) memset(((void *) &RollAxisAutopilot_B), 0,
                sizeof(B_RollAxisAutopilot_T));

  /* states (dwork) */
  (void) memset((void *)&RollAxisAutopilot_DW, 0,
                sizeof(DW_RollAxisAutopilot_T));

  /* external inputs */
  (void)memset(&RollAxisAutopilot_U, 0, sizeof(ExtU_RollAxisAutopilot_T));

  /* external outputs */
  RollAxisAutopilot_Y.Ail_Cmd = 0.0F;

  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  RollAxisAutopilot_DW.FixPtUnitDelay1_DSTATE =
    RollAxisAutopilot_P.LatchPhi_vinit;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_DW.Integrator_DSTATE = RollAxisAutopilot_P.Integrator_IC;
  RollAxisAutopilot_DW.Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

/* Model terminate function */
void RollAxisAutopilot_terminate(void)
{
  /* (no terminate code required) */
}

void void インターフェイスおよび直接データ アクセスのため、関数は再呼び出し可能ではありません。関数をアプリケーションで複数回呼び出す場合、各呼び出しはデータをグローバル構造体変数に書き込み、後続の呼び出しがそのデータを読み取ることがあるため、結果として呼び出し間の意図しない干渉が行われます。

モデル初期化関数 RollAxisAutopilot_initialize は、すべての内部データをゼロに初期化します。関数は特殊なマクロ関数を呼び出すことで、エラー ステータスも初期化します。初期化関数は、グローバル変数に直接アクセスします。これは、関数が再呼び出し可能ではないことを意味します。

coder.example.extractLines(file,'/* Model initialize function */',...
    'sizeof(DW_RollAxisAutopilot_T));',1,1)
/* Model initialize function */
void RollAxisAutopilot_initialize(void)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatus(RollAxisAutopilot_M, (NULL));

  /* block I/O */
  (void) memset(((void *) &RollAxisAutopilot_B), 0,
                sizeof(B_RollAxisAutopilot_T));

  /* states (dwork) */
  (void) memset((void *)&RollAxisAutopilot_DW, 0,
                sizeof(DW_RollAxisAutopilot_T));

次に、関数は DWork 構造体のブロック状態を、モデルのブロック パラメーターが指定する初期値に初期化します。モデルの 3 つの状態のうち 2 つが調整可能な初期値をもつため、コードはパラメーター構造体からデータを読み取ることで、それらを初期化します。

coder.example.extractLines(file,...
    '/* SystemInitialize for Atomic SubSystem: ''<Root>/RollAngleReference'' */',...
    '/* Model terminate function */',1,0)
  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  RollAxisAutopilot_DW.FixPtUnitDelay1_DSTATE =
    RollAxisAutopilot_P.LatchPhi_vinit;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_DW.Integrator_DSTATE = RollAxisAutopilot_P.Integrator_IC;
  RollAxisAutopilot_DW.Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

再利用可能なコードの生成

生成されたコードを再呼び出し可能に設定できます。これは、エントリポイント関数をアプリケーションで複数回呼び出すことができることを意味します。この設定では、エントリポイント関数はグローバル変数に直接アクセスせずに、仮パラメーター (ポインター引数) を介して内部データを受け入れます。これらのポインター引数を使用して、各呼び出しは内部データを別個のグローバル変数のセットで維持でき、呼び出し間での意図しない相互作用が行われないようにします。

モデルで、[コンフィギュレーション パラメーター]、[コード生成]、[インターフェイス]、[コード インターフェイスのパッケージ化]Reusable function に設定します。

set_param('RollAxisAutopilot','CodeInterfacePackaging','Reusable function')

モデルからコードを生成します。

slbuild('RollAxisAutopilot')
### Starting build procedure for: RollAxisAutopilot
### Successful completion of build procedure for: RollAxisAutopilot

Build Summary

Top model targets built:

Model              Action                        Rebuild Reason                   
==================================================================================
RollAxisAutopilot  Code generated and compiled.  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 9.3468s

これにより、RollAxisAutopilot.h のリアルタイム モデル データ構造体には、エラー指標、内部データ、および ExtUExtY のサブ構造体 (モデルのルート レベルにある Inport ブロックおよび Outport ブロックを表すフィールド) の形式をもつプライマリの入力データおよび出力データを指すポインターが含まれます。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot.h');
coder.example.extractLines(file,'/* Real-time Model Data Structure */',...
    '/* External data declarations for dependent source files */',1,0)
/* Real-time Model Data Structure */
struct tag_RTM_RollAxisAutopilot_T {
  const char_T *errorStatus;
  B_RollAxisAutopilot_T *blockIO;
  ExtU_RollAxisAutopilot_T *inputs;
  ExtY_RollAxisAutopilot_T *outputs;
  DW_RollAxisAutopilot_T *dwork;
};

/* Block parameters (default storage) */
extern P_RollAxisAutopilot_T RollAxisAutopilot_P;

生成されたコードをアプリケーションで複数回呼び出すには、コードで、リアルタイム モデル データ構造体に呼び出し単位でメモリを割り当てなければなりません。ファイル RollAxisAutopilot.c は、新しいリアルタイム モデル データ構造体にメモリを割り当ててポインターを構造体に返す特殊な関数を定義します。関数は、DWork 構造体などのモデル データ構造体のフィールドが指し示すサブ構造体へのメモリの割り当ても行います。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot.c');
coder.example.extractLines(file,'/* Model data allocation function */',...
    'RT_MODEL_RollAxisAutopilot_T *RollAxisAutopilot(void)',1,1)
/* Model data allocation function */
RT_MODEL_RollAxisAutopilot_T *RollAxisAutopilot(void)

モデルの関数 step は、リアルタイム モデル データ構造体を表す引数を受け入れます。

coder.example.extractLines(file,'/* Model step function */','void RollAxisAutopilot_step',1,1)
/* Model step function */
void RollAxisAutopilot_step(RT_MODEL_RollAxisAutopilot_T *const

関数定義では、アルゴリズムは最初にリアルタイム モデル データ構造体から各ポインターを抽出し、ローカル変数に渡します。

coder.example.extractLines(file,'*RollAxisAutopilot_B =','RollAxisAutopilot_M->outputs;',1,1)
  B_RollAxisAutopilot_T *RollAxisAutopilot_B = RollAxisAutopilot_M->blockIO;
  DW_RollAxisAutopilot_T *RollAxisAutopilot_DW = RollAxisAutopilot_M->dwork;
  ExtU_RollAxisAutopilot_T *RollAxisAutopilot_U = (ExtU_RollAxisAutopilot_T *)
    RollAxisAutopilot_M->inputs;
  ExtY_RollAxisAutopilot_T *RollAxisAutopilot_Y = (ExtY_RollAxisAutopilot_T *)
    RollAxisAutopilot_M->outputs;

次に、グローバル メモリに保存されている内部データにアクセスするために、アルゴリズムはこれらのローカル変数を操作します。

coder.example.extractLines(file,'/* DiscreteIntegrator: ''<S1>/Integrator'' */',...
    '/* End of DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
  /* DiscreteIntegrator: '<S1>/Integrator' */
  if (RollAxisAutopilot_B->NotEngaged_e ||
      (RollAxisAutopilot_DW->Integrator_PrevResetState != 0)) {
    RollAxisAutopilot_DW->Integrator_DSTATE = RollAxisAutopilot_P.Integrator_IC;
  }

  /* DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_B->Integrator = RollAxisAutopilot_DW->Integrator_DSTATE;

  /* Saturate: '<S1>/DispLimit' */
  u0 = RollAxisAutopilot_B->phiCmd;
  u1 = RollAxisAutopilot_P.DispLimit_LowerSat;
  u2 = RollAxisAutopilot_P.dispLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/DispLimit' */
    RollAxisAutopilot_B->DispLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/DispLimit' */
    RollAxisAutopilot_B->DispLimit = u1;
  } else {
    /* Saturate: '<S1>/DispLimit' */
    RollAxisAutopilot_B->DispLimit = u0;
  }

  /* End of Saturate: '<S1>/DispLimit' */

  /* Sum: '<S1>/Sum' */
  RollAxisAutopilot_B->Sum = RollAxisAutopilot_B->DispLimit -
    RollAxisAutopilot_U->Phi;

  /* Gain: '<S1>/DispGain' */
  RollAxisAutopilot_B->DispGain_f = RollAxisAutopilot_P.dispGain *
    RollAxisAutopilot_B->Sum;

  /* Saturate: '<S1>/RateLimit' */
  u0 = RollAxisAutopilot_B->DispGain_f;
  u1 = RollAxisAutopilot_P.RateLimit_LowerSat;
  u2 = RollAxisAutopilot_P.rateLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/RateLimit' */
    RollAxisAutopilot_B->RateLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/RateLimit' */
    RollAxisAutopilot_B->RateLimit = u1;
  } else {
    /* Saturate: '<S1>/RateLimit' */
    RollAxisAutopilot_B->RateLimit = u0;
  }

  /* End of Saturate: '<S1>/RateLimit' */

  /* Sum: '<S1>/Sum1' */
  RollAxisAutopilot_B->Sum1 = RollAxisAutopilot_B->RateLimit -
    RollAxisAutopilot_U->Rate_FB;

  /* Gain: '<S1>/RateGain' */
  RollAxisAutopilot_B->RateGain = RollAxisAutopilot_P.rateGain *
    RollAxisAutopilot_B->Sum1;

  /* Sum: '<S1>/Sum2' */
  RollAxisAutopilot_B->Sum2 = RollAxisAutopilot_B->Integrator +
    RollAxisAutopilot_B->RateGain;

  /* Saturate: '<S1>/CmdLimit' */
  u0 = RollAxisAutopilot_B->Sum2;
  u1 = RollAxisAutopilot_P.CmdLimit_LowerSat;
  u2 = RollAxisAutopilot_P.cmdLim;
  if (u0 > u2) {
    /* Saturate: '<S1>/CmdLimit' */
    RollAxisAutopilot_B->CmdLimit = u2;
  } else if (u0 < u1) {
    /* Saturate: '<S1>/CmdLimit' */
    RollAxisAutopilot_B->CmdLimit = u1;
  } else {
    /* Saturate: '<S1>/CmdLimit' */
    RollAxisAutopilot_B->CmdLimit = u0;
  }

  /* End of Saturate: '<S1>/CmdLimit' */

  /* Gain: '<S1>/IntGain' */
  RollAxisAutopilot_B->IntGain = RollAxisAutopilot_P.intGain *
    RollAxisAutopilot_B->Sum1;

  /* Update for DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_DW->Integrator_DSTATE +=
    RollAxisAutopilot_P.Integrator_gainval * RollAxisAutopilot_B->IntGain;
  if (RollAxisAutopilot_DW->Integrator_DSTATE > RollAxisAutopilot_P.intLim) {
    RollAxisAutopilot_DW->Integrator_DSTATE = RollAxisAutopilot_P.intLim;
  } else if (RollAxisAutopilot_DW->Integrator_DSTATE <
             RollAxisAutopilot_P.Integrator_LowerSat) {
    RollAxisAutopilot_DW->Integrator_DSTATE =
      RollAxisAutopilot_P.Integrator_LowerSat;
  }

  RollAxisAutopilot_DW->Integrator_PrevResetState = (int8_T)
    RollAxisAutopilot_B->NotEngaged_e;

  /* End of Update for DiscreteIntegrator: '<S1>/Integrator' */
  /* End of Outputs for SubSystem: '<Root>/BasicRollMode' */

  /* Switch: '<Root>/EngSwitch' */
  if (RollAxisAutopilot_U->AP_Eng) {
    /* Outport: '<Root>/Ail_Cmd' */
    RollAxisAutopilot_Y->Ail_Cmd = RollAxisAutopilot_B->CmdLimit;
  } else {
    /* Outport: '<Root>/Ail_Cmd' incorporates:
     *  Constant: '<Root>/Zero'
     */
    RollAxisAutopilot_Y->Ail_Cmd = RollAxisAutopilot_P.Zero_Value_c;
  }

  /* End of Switch: '<Root>/EngSwitch' */
}

/* Model initialize function */
void RollAxisAutopilot_initialize(RT_MODEL_RollAxisAutopilot_T *const
  RollAxisAutopilot_M)
{
  DW_RollAxisAutopilot_T *RollAxisAutopilot_DW = RollAxisAutopilot_M->dwork;

  /* SystemInitialize for Atomic SubSystem: '<Root>/RollAngleReference' */
  /* InitializeConditions for UnitDelay: '<S4>/FixPt Unit Delay1' */
  RollAxisAutopilot_DW->FixPtUnitDelay1_DSTATE =
    RollAxisAutopilot_P.LatchPhi_vinit;

  /* End of SystemInitialize for SubSystem: '<Root>/RollAngleReference' */

  /* SystemInitialize for Atomic SubSystem: '<Root>/BasicRollMode' */
  /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  RollAxisAutopilot_DW->Integrator_DSTATE = RollAxisAutopilot_P.Integrator_IC;
  RollAxisAutopilot_DW->Integrator_PrevResetState = 0;

  /* End of SystemInitialize for SubSystem: '<Root>/BasicRollMode' */
}

/* Model terminate function */
void RollAxisAutopilot_terminate(RT_MODEL_RollAxisAutopilot_T
  * RollAxisAutopilot_M)
{
  /* model code */
  rt_FREE(RollAxisAutopilot_M->blockIO);
  rt_FREE(RollAxisAutopilot_M->inputs);
  rt_FREE(RollAxisAutopilot_M->outputs);
  rt_FREE(RollAxisAutopilot_M->dwork);
  rt_FREE(RollAxisAutopilot_M);
}

/* Model data allocation function */
RT_MODEL_RollAxisAutopilot_T *RollAxisAutopilot(void)
{
  RT_MODEL_RollAxisAutopilot_T *RollAxisAutopilot_M;
  RollAxisAutopilot_M = (RT_MODEL_RollAxisAutopilot_T *) malloc(sizeof
    (RT_MODEL_RollAxisAutopilot_T));
  if (RollAxisAutopilot_M == (NULL)) {
    return (NULL);
  }

  (void) memset((char *)RollAxisAutopilot_M, 0,
                sizeof(RT_MODEL_RollAxisAutopilot_T));

  /* block I/O */
  {
    B_RollAxisAutopilot_T *b = (B_RollAxisAutopilot_T *) malloc(sizeof
      (B_RollAxisAutopilot_T));
    rt_VALIDATE_MEMORY(RollAxisAutopilot_M,b);
    RollAxisAutopilot_M->blockIO = (b);
  }

  /* states (dwork) */
  {
    DW_RollAxisAutopilot_T *dwork = (DW_RollAxisAutopilot_T *) malloc(sizeof
      (DW_RollAxisAutopilot_T));
    rt_VALIDATE_MEMORY(RollAxisAutopilot_M,dwork);
    RollAxisAutopilot_M->dwork = (dwork);
  }

  /* external inputs */
  {
    ExtU_RollAxisAutopilot_T *RollAxisAutopilot_U = (ExtU_RollAxisAutopilot_T *)
      malloc(sizeof(ExtU_RollAxisAutopilot_T));
    rt_VALIDATE_MEMORY(RollAxisAutopilot_M,RollAxisAutopilot_U);
    RollAxisAutopilot_M->inputs = (((ExtU_RollAxisAutopilot_T *)
      RollAxisAutopilot_U));
  }

  /* external outputs */
  {
    ExtY_RollAxisAutopilot_T *RollAxisAutopilot_Y = (ExtY_RollAxisAutopilot_T *)
      malloc(sizeof(ExtY_RollAxisAutopilot_T));
    rt_VALIDATE_MEMORY(RollAxisAutopilot_M,RollAxisAutopilot_Y);
    RollAxisAutopilot_M->outputs = (RollAxisAutopilot_Y);
  }

  {
    B_RollAxisAutopilot_T *RollAxisAutopilot_B = RollAxisAutopilot_M->blockIO;
    DW_RollAxisAutopilot_T *RollAxisAutopilot_DW = RollAxisAutopilot_M->dwork;
    ExtU_RollAxisAutopilot_T *RollAxisAutopilot_U = (ExtU_RollAxisAutopilot_T *)
      RollAxisAutopilot_M->inputs;
    ExtY_RollAxisAutopilot_T *RollAxisAutopilot_Y = (ExtY_RollAxisAutopilot_T *)
      RollAxisAutopilot_M->outputs;

    /* block I/O */
    (void) memset(((void *) RollAxisAutopilot_B), 0,
                  sizeof(B_RollAxisAutopilot_T));

    /* states (dwork) */
    (void) memset((void *)RollAxisAutopilot_DW, 0,
                  sizeof(DW_RollAxisAutopilot_T));

    /* external inputs */
    (void)memset(RollAxisAutopilot_U, 0, sizeof(ExtU_RollAxisAutopilot_T));

    /* external outputs */
    RollAxisAutopilot_Y->Ail_Cmd = 0.0F;
  }

  return RollAxisAutopilot_M;
}

同様に、モデル初期化関数はリアルタイム モデル データ構造体を引数として受け入れます。

coder.example.extractLines(file,...
    '/* Model initialize function */','void RollAxisAutopilot_initialize',1,1)
/* Model initialize function */
void RollAxisAutopilot_initialize(RT_MODEL_RollAxisAutopilot_T *const

エントリポイント関数に対して行う各呼び出しは、別個のリアルタイム モデル データ構造体を操作するため、呼び出し間での意図しない相互作用が行われません。

コード生成の最適化による内部データの消去

メモリの消費が少ない、さらに効率的なコードを作成するには、以前にクリアした [既定のパラメーター動作] などの最適化を選択します。

set_param('RollAxisAutopilot','DefaultParameterBehavior','Inlined',...
    'OptimizeBlockIOStorage','on',...
    'LocalBlockOutputs','on')

この例では、コードをさらに簡単にするために、[コード インターフェイスのパッケージ化]Nonreusable function に設定します。

set_param('RollAxisAutopilot','CodeInterfacePackaging','Nonreusable function')

モデルからコードを生成します。

slbuild('RollAxisAutopilot')
### Starting build procedure for: RollAxisAutopilot
### Successful completion of build procedure for: RollAxisAutopilot

Build Summary

Top model targets built:

Model              Action                        Rebuild Reason                   
==================================================================================
RollAxisAutopilot  Code generated and compiled.  Generated code was out of date.  

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 9.6174s

ここで、RollAxisAutopilot.h はブロックの入力および出力の構造体を定義していません。モデルのすべての内部信号について、最適化によりストレージが削除されるか、グローバル構造体フィールドではなくローカル関数変数が作成されました。

最適化により 3 つのブロック状態のストレージは削除されなかったため、ファイルは引き続き DWork 構造体型を定義します。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot.h');
coder.example.extractLines(file,...
    '/* Block states (default storage) for system','} DW_RollAxisAutopilot_T;',1,1)
/* Block states (default storage) for system '<Root>' */
typedef struct {
  real32_T FixPtUnitDelay1_DSTATE;     /* '<S4>/FixPt Unit Delay1' */
  real32_T Integrator_DSTATE;          /* '<S1>/Integrator' */
  int8_T Integrator_PrevResetState;    /* '<S1>/Integrator' */
} DW_RollAxisAutopilot_T;

Discrete-Time Integrator ブロックに対して生成されたコードは、状態および出力データを DWork 構造体のみに格納します。

file = fullfile('RollAxisAutopilot_grt_rtw','RollAxisAutopilot.c');
coder.example.extractLines(file,'/* Update for DiscreteIntegrator: ''<S1>/Integrator''',...
    '/* End of Update for DiscreteIntegrator: ''<S1>/Integrator'' */',1,1)
  /* Update for DiscreteIntegrator: '<S1>/Integrator' incorporates:
   *  Gain: '<S1>/IntGain'
   */
  RollAxisAutopilot_DW.Integrator_DSTATE += 0.5F * rtb_TKSwitch * 0.025F;
  if (RollAxisAutopilot_DW.Integrator_DSTATE > 5.0F) {
    RollAxisAutopilot_DW.Integrator_DSTATE = 5.0F;
  } else if (RollAxisAutopilot_DW.Integrator_DSTATE < -5.0F) {
    RollAxisAutopilot_DW.Integrator_DSTATE = -5.0F;
  }

  RollAxisAutopilot_DW.Integrator_PrevResetState = (int8_T)tmp;

また最適化によって、モデルのブロックパラメーターのストレージが削除されました。たとえば、Discrete-Time Integrator ブロックで、[飽和の上限] および [飽和の下限] パラメーターが intLim および -intLim に設定されます。intLim は、値 5 を格納する Simulink.Parameter オブジェクトです。Discrete-Time Integrator に対して生成されたコードでは、これらのブロック パラメーターおよび intLim はインライン化された数値リテラル 5.0F および -5.0F として表示されます。

モデルにコード ジェネレーターが直接インライン化できないパラメーター (たとえば、配列パラメーター) が含まれている場合、コードはデータを表す構造体型を定義します。この "定数パラメーター" 構造体は const ストレージ型修飾子を使用するため、一部のツールチェーンはアセンブリ コードをさらに最適化できます。

構造体の宣言 ConstParam_model は、次のように model.h に配置されます。

/* Constant parameters (auto storage) */
typedef struct {
   /* Expression: [1 2 3 4 5 6 7]
    * Referenced by: '<Root>/Constant'
    */
   real_T Constant_Value[7];
   
   /* Expression: [7 6 5 4 3 2 1]
    * Referenced by: '<Root>/Gain'
    */
   real_T Gain_Gain[7];
 } ConstParam_model;

定数パラメーターの宣言 model_ConstP は、既定では model_data.c に配置されます。

/* Constant parameters (auto storage) */
const ConstParam_model model_ConstP = {
   /* Expression: [1 2 3 4 5 6 7]
    * Referenced by: '<Root>/Constant'
    */
   { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 },

   /* Expression: [7 6 5 4 3 2 1]
    * Referenced by: '<Root>/Gain'
    */
   { 7.0, 6.0, 5.0, 4.0, 3.0, 2.0, 1.0 }
};

model_ConstP は、引数として参照モデルに渡されます。

生成コードのローカル変数

最適化の [コンフィギュレーション パラメーター][ローカルなブロックの出力を有効にする] を選択すると、コード ジェネレーターは、内部信号をグローバル構造体のフィールドではなくローカル変数として表すことで、より効果的なコードを生成しようとします。ローカル変数で消費されるメモリがターゲット ハードウェアで使用できるスタック領域を超えるリスクがある場合は、[コンフィギュレーション パラメーター][最大スタック サイズ (バイト)] を設定して最大スタック サイズを指定することを検討してください。詳細については、最大スタック サイズ (バイト)を参照してください。

生成コードでのテスト ポイントの外観

"テスト ポイント" は、固有のメモリ位置に格納される信号です。モデルにテスト ポイントを含める方法の詳細については、テスト ポイントとしての信号の設定を参照してください。

テスト ポイントを含むモデル用にコードを生成する時に、ビルド プロセスは各テスト ポイントに別個のメモリ バッファーを割り当てます。既定では、テスト ポイントは model_B などの標準データ構造体のメンバーとして格納されます。

Embedded Coder® を使用している場合は、以下を実行できます。

  • コード マッピング エディターでデータの [Internal data] カテゴリのコード生成設定を指定して、テスト ポイントの既定の表示を制御できる (Configure Default Code Generation for Dataを参照)。

  • Ignore test point signalsパラメーターを使用して、ビルド プロセスがモデル内のテスト ポイントを無視し、最適なバッファー割り当てを許可するように指定することができます。テスト ポイントを無視すると、プロトタイピングから展開への移行が容易になり、ワークフロー アーティファクトのせいで起こる生成コードの劣化が回避されます。Ignore test point signalsを参照してください。

バーチャル バスは、テスト ポイントに関連付けられている場合でも生成コードに表示されません。生成コードにバスを表示するには、非バーチャル バスまたは Signal Conversion ブロックを使用して非バーチャル バスに変換されたバーチャル バスを使用します。

生成コードでのワークスペース変数の外観

"ワークスペース変数" とは、モデル内でブロック パラメーター値を指定するために使用する変数です。ワークスペース変数には、ベース ワークスペースなどのワークスペースやデータ ディクショナリに格納する MATLAB® 数値変数と Simulink.Parameter オブジェクトが含まれます。

[既定のパラメーター動作][調整可能] に設定すると、既定で、ワークスペース変数が、グローバル パラメーター構造体の調整可能なフィールドとして生成されたコードに表示されます。この変数を使用して複数のブロック パラメーター値を指定すると、変数はグローバル パラメーター構造体の単一フィールドとしてに表示されます。このコードは、ブロック パラメーターを表すために複数のフィールドを作成しません。そのため、コードの実行時にフィールド値を調整すると、シミュレーション時に MATLAB 変数の値またはパラメーター オブジェクトを調整する場合と同じ方法でモデルの数学的動作が変更されます。

Embedded Coder を使用している場合は、コード マッピング エディターでパラメーター データのカテゴリにコード生成設定を指定して、ワークスペース変数の既定の表示を制御できます (Configure Default Code Generation for Dataを参照)。

  • [Model parameters] カテゴリは、モデル ワークスペースに保存する変数に適用されます。

  • [External parameters] カテゴリは、ベース ワークスペースまたはデータ ディクショナリに保存する変数に適用されます。

インターフェイスへの内部データのプロモート

既定では、コード ジェネレーターは、アプリケーションのその他のシステムおよびコンポーネントが内部データにアクセスする必要がないことを想定しています。たとえば、内部データは、生成されたコードから内部データを削除する最適化の対象です。プロトタイプおよびテストの目的で、最適化をクリアするか、テスト ポイントを構成してストレージ クラスを適用することで内部データにアクセスできます (生成コード内の変数の保持を参照)。最適化された量産コードの場合、個別のデータ項目がモデル インターフェイスの一部として生成コードに表示されるように設定します。

プロモート可能なデータ

生成されたコードが再呼び出し可能かどうかによって、つまり、[コード インターフェイスのパッケージ化] で選択した設定によって、モデルの各データ項目を次のエンティティのいずれかとしてコードに表示させることで、インターフェイスに参加するように設定できます。

  • グローバル変数または特殊な関数呼び出しなどのグローバル シンボル

  • 生成されたエントリポイント関数の仮パラメーター (引数)

次の表に、各データのカテゴリがインターフェイスに参加するために使用できるメカニズムを示します。

データのカテゴリグローバル シンボルとして表示エントリポイント関数の引数として表示
ルートレベルの Inport ブロックまたは Outport ブロック再呼び出し不可能なモデルの場合のみ。はい。
2 つのブロックに接続する信号再呼び出し不可能なモデルの場合のみ。

再呼び出し可能なモデルの場合のみであり、構造体のフィールドとしてのみ。

あるいは、信号をルートレベルの Outport ブロックに接続する。

ブロックの状態再呼び出し不可能なモデルの場合のみ。再呼び出し可能なモデルの場合のみであり、構造体のフィールドとしてのみ。
Data Store Memory ブロックなどのデータ ストアはい。再呼び出し可能なモデルの場合のみであり、構造体のフィールドとしてのみ。
Simulink.Parameter などのブロック パラメーターまたはブロック オブジェクトはい。構造体のフィールドとしてのみ。

単一インスタンスのアルゴリズム

単一インスタンスのアルゴリズム ([コード インターフェイスのパッケージ化][再利用できない関数] に設定している) の場合、モデル データ エディターまたはプロパティ インスペクターを使用してストレージ クラスを個別のデータ項目に直接適用します。直接適用されたストレージ クラスを使用すると、データ項目はグローバル変数などのグローバル シンボルとしてコードに表示されます。ストレージ クラスはまた、データ項目のストレージが最適化によって削除されないようにします。

ストレージ クラスを 1 つのブロック状態およびブロック パラメーターに適用できます (ブロック パラメーターの場合、ストレージクラスを Simulink.Parameter などのパラメーター オブジェクトを介して間接的に適用します)。ただし、信号については、モデルのルート レベルの Outport ブロックに信号を接続することを検討してください。オプションで、ストレージ クラスをブロックに適用できます。ブロック線図では、Outport ブロックは、信号がシステム出力を表すことを示します。

ストレージ クラスの詳細については、C Data Code Interface Configuration for Model Interface Elementsを参照してください。

再呼び出し可能なアルゴリズム

再呼び出し可能なアルゴリズムの場合 ([コード インターフェイスのパッケージ化][再利用可能な関数] に設定)、さまざまな手法を使用して、データ項目が生成されたエントリポイント関数の仮パラメーター (引数) としてコードに表示されるように設定します。

  • 内部信号の場合は、ストレージ クラス Model default を直接適用します (C Data Code Interface Configuration for Model Interface Elementsを参照)。Embedded Coder を使用している場合、コード マッピング エディターで、[Internal data] カテゴリに対して、既定のストレージ クラスを [Default] または Embedded Coder ディクショナリで定義した構造体化されたストレージ クラスに設定します (Create Code Definitions for Use in the Code Mappings Editorを参照)。または、信号をテスト ポイントとして設定します (生成コードでのテスト ポイントの外観を参照)。既定では、信号は標準のデータ構造体の 1 つのフィールドとして表示されます (生成されたコードによる内部信号、状態、パラメーター データの保存方法を参照)。信号を量産コードに表示させない場合、モデル コンフィギュレーション パラメーター [テスト ポイント信号を無視] を後で選択できるようにテスト ポイントを使用します。

    もしくは、モデルのルート レベルの Outport ブロックに信号を接続します。信号をルートレベルの Outport ブロックに接続することで、最適化によりコードから信号が削除されなくなります。大規模なモデルでの信号の経路指定を容易にするには、Goto ブロックおよび From ブロックを使用します。

  • ブロック パラメーターの場合は、Simulink.Parameter などのパラメーター オブジェクトを作成し、Auto 以外のストレージ クラスをオブジェクトに直接適用します。ストレージ クラスは、最適化によってコードのパラメーター値がインライン化されないようにします。

    ストレージ クラスでは、エントリポイント関数の呼び出しである、モデルのインスタンス間でパラメーターが共有されます。関数は、引数ではなく、グローバル シンボルとしてパラメーター データに直接アクセスします。モデルの各インスタンスでパラメーターに異なる値を使用できるようにするには、パラメーターをモデル引数として構成します。詳細については、再利用可能な参照モデルへのインスタンス固有パラメーター値の指定を参照してください。

    ストレージ クラスの適用の詳細については、C Data Code Interface Configuration for Model Interface Elementsを参照してください。

既定の内部データ表現の制御 (Embedded Coder)

既定では、コード ジェネレーターは、最適化で除去できない内部データ (大半の状態データなど) を DWork 構造体などの標準の構造体に集約します。Embedded Coder を使用して、生成コードでのこのデータの保存方法を制御できます。

プラグマの挿入によるメモリ内のデータの配置の制御

コード マッピング エディターを使用して、状態や信号などのデータ ([Internal data]) の各カテゴリに対して既定のメモリ セクションを指定します。生成されたコードでは、データ定義と宣言がカスタム プラグマまたはその他の装飾によって囲まれます。

また、サブルーチンおよびその他のアルゴリズムのサブコンポーネントのデータに異なる既定のメモリ セクションを指定できるようにするために、モデルの Atomic Subsystem に応じて構造体を分割できます。

詳細については、Control Data and Function Placement in Memory by Inserting Pragmasを参照してください。

標準のデータ構造体の型、フィールド、グローバル変数の名前の制御

標準のデータ構造体の特性を制御できます。詳細については、Manage Replacement of Simulink Data Types in Generated Codeを参照してください。

生成されたコード ファイルでの配置など、構造体の特性の制御をさらに追加する場合は、Embedded Coder ディクショナリを使用して独自の構造体化されたストレージ クラスを作成します。次に、コード マッピング エディターを使用してストレージ クラスをデータのカテゴリに適用します。ストレージ クラスは標準の構造体からデータを削除し、より細かく制御できる他の構造体を作成します。既定のストレージ クラスをデータのカテゴリに適用する方法の詳細については、Configure Default Code Generation for Dataを参照してください。ストレージ クラスの作成の詳細については、Define Service Interfaces, Storage Classes, Memory Sections, and Function Templates for Software Architectureを参照してください。

サブコンポーネントに合わせたデータの構造体への編成

  • 標準のデータ構造体で、単一インスタンスの (再呼び出し不可能な) サブルーチンまたはサブコンポーネントのデータを含むサブ構造体を作成するには、Atomic Subsystem を使用して対応するブロックをカプセル化します。サブシステム パラメーターで、[関数のパッケージ化][再利用可能な関数] に設定します。詳細については、非バーチャル サブシステムのモジュラー関数コードの生成を参照してください。

    あるいは、モデルのブロックをカプセル化して Model ブロックを使用します。参照モデルで、[コンフィギュレーション パラメーター][モデル参照][最上位モデルごとに可能なインスタンスの総数][複数] に設定します。詳細については、モデル参照階層向けのコードの生成を参照してください。

  • 別個のスタンドアロン構造体を作成し、マルチインスタンス (再呼び出し可能な) サブルーチンまたはサブコンポーネントのデータを含めるには、モデルで Atomic Subsystem を使用して対応するブロックをカプセル化します。サブシステム パラメーターで、[関数のパッケージ化][再利用できない関数] に設定し、[別々のデータをもつ関数] を選択します。詳細については、非バーチャル サブシステムのモジュラー関数コードの生成を参照してください。

    あるいは、モデルのブロックをカプセル化して Model ブロックを使用します。参照モデルで、以下のいずれかの方法を選択します。

信号およびパラメーター データの意味のあるカスタム構造体またはサブ構造体への編成

任意の信号およびパラメーターをカスタムの構造体とサブ構造体に編成するには、非バーチャル バス信号およびパラメーター構造体を作成します。オプションで、最適化によりデータがコードから消去されるのを防ぐために、バス信号またはパラメーター構造体のストレージ クラスを、[Auto] (既定の設定) 以外の値に設定します。

ブロックをモデルに追加するときに、新しい各信号とパラメーターをバスまたは構造体に明示的に配置しなければなりません。

詳細については、生成されたコードにおける構造体へのデータの整理を参照してください。

構造体フィールドの代わりとなる個別のグローバル変数の作成

内部データのカテゴリを、生成されたコードに標準のデータ構造体のフィールドではなく、個別の構造化されていないグローバル変数として表示するには、コード マッピング エディターを使用して構造体化されていないストレージ クラスをデータ カテゴリに適用します。たとえば、ストレージ クラス ExportedGlobal を適用します。ただし、コンフィギュレーション パラメーター [コード インターフェイスのパッケージ化][再利用できない関数] でない値に設定してマルチインスタンスの再呼び出し可能なコードを生成する場合、データの一部のカテゴリにこの方法は使用できません (ストレージ クラスと再呼び出し可能なマルチインスタンス モデルとコンポーネントを参照)。

コード マッピング エディターを使用して既定のストレージ クラスをデータのカテゴリに適用するには、Configure Default Code Generation for Dataを参照してください。ストレージ クラスを選択するには、生成されたコードでのデータ表示を制御するストレージ クラスの選択を参照してください。

関連するトピック