Main Content

Specify Instance-Specific Parameter Values for Reusable Referenced Model

When you use model referencing to break a large system into components, each component is a separate model. You can reuse a component by referring to it with multiple Model blocks. Each Model block is an instance of the component. You can then configure a block parameter (such as the Gain parameter of a Gain block) to use either the same value or a different value for each instance of the component. To use different values, create and use a model argument to set the value of the block parameter.

When you generate code from a model hierarchy that uses model arguments, the arguments appear in the code as formal parameters of the referenced model entry-point functions, such as the output (step) function. The generated code then passes the instance-specific parameter values, which you specify in each Model block, to the corresponding function calls.

Whether you use or do not use model arguments, you can use storage classes to configure block parameters to appear in the generated code as tunable global variables. You can also use storage classes to generate tunable model argument values, which the generated code stores in memory and passes to the function calls. You can then change the values during execution.

Pass Parameter Data to Referenced Model Entry-Point Functions as Arguments

Configure a referenced model to accept parameter data through formal parameters of the generated model entry-point function. This technique enables you to specify a different parameter value for each instance (Model block) of the referenced model.

Configure Referenced Model to Use Model Arguments

Open the model ex_arg_code_ref. This model represents a reusable algorithm.

open_system('ex_arg_code_ref')

On the Modeling tab, click Model Data Editor.

In the Model Data editor, in the data table, use the Data Type column to set the data type of the Inport block to single. Due to data type inheritance, the other signals in the model use the same data type.

Select the Parameters tab.

In the model, select the Gain block.

In the Model Data Editor, use the Value column to set the value of the Gain parameter to gainArg. gainArg is a Simulink.Parameter object in the model workspace whose value is 3.17.

Use the Model Data Editor to set the Numerator parameter to the Simulink.Parameter object coeffArg whose value is 1.05.

In the Model Data Editor, click the Show/refresh additional information button.

Use the Filter contents box to find each parameter object (gainArg and coeffArg). For each object, select the check box in the Argument column.

Save the ex_arg_code_ref model.

Alternatively, at the command prompt, you can use these commands to configure the blocks and the parameter objects:

set_param('ex_arg_code_ref/In1','OutDataTypeStr','single')

set_param('ex_arg_code_ref/Gain','Gain','gainArg')
modelWorkspace = get_param('ex_arg_code_ref','ModelWorkspace');
assignin(modelWorkspace,'gainArg',Simulink.Parameter(3.17));

set_param('ex_arg_code_ref/Discrete Filter','Numerator','coeffArg')
assignin(modelWorkspace,'coeffArg',Simulink.Parameter(1.05));

set_param('ex_arg_code_ref','ParameterArgumentNames','coeffArg,gainArg')

save_system('ex_arg_code_ref')

Specify Instance-Specific Parameter Values in Model Blocks

Open the model ex_arg_code. This model uses multiple instances (Model blocks) of the reusable algorithm.

open_system('ex_arg_code')

In the model, open the Model Data Editor Parameters tab (Modeling > Model Data Editor). The Model Data Editor shows four rows that correspond to the model arguments, coeffArg and gainArg, that you can specify for the two Model blocks.

Use the Model Data Editor to set values for the model arguments in Model. For example, use the values in the figure. For Model1, do not specify a value for the model arguments. By default, a model argument uses the last value specified below it in the model hierarchy (indicated by the value from below).

Alternatively, at the command prompt, you can use this command to set the values for Model:

instSpecParams = get_param('ex_arg_code/Model','InstanceParameters');
instSpecParams(1).Value = '.98';
instSpecParams(2).Value = '2.98';
set_param('ex_arg_code/Model','InstanceParameters',instSpecParams);

Generate code from the top model.

slbuild('ex_arg_code')
### Searching for referenced models in model 'ex_arg_code'.
### Found 1 model reference targets to update.
### Starting serial model reference code generation build.
### Successfully updated the model reference code generation target for: ex_arg_code_ref
### Starting build procedure for: ex_arg_code
### Successful completion of build procedure for: ex_arg_code

Build Summary

Model reference code generation targets:

Model            Build Reason                               Status                        Build Duration
========================================================================================================
ex_arg_code_ref  Target (ex_arg_code_ref.c) did not exist.  Code generated and compiled.  0h 0m 11.409s 

Top model targets:

Model        Build Reason                                         Status                        Build Duration
==============================================================================================================
ex_arg_code  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 17.315s 

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

The file ex_arg_code_ref.c defines the referenced model entry-point function, ex_arg_code_ref. The function has two formal parameters, rtp_coeffArg and rtp_gainArg, that correspond to the model arguments, coeffArg and gainArg. The formal parameters use the data type real32_T, which corresponds to the data type single in Simulink®.

file = fullfile('slprj','grt','ex_arg_code_ref','ex_arg_code_ref.c');
coder.example.extractLines(file,'/* Output and update for referenced model:',...
    'real32_T rtp_gainArg)',1,1)
/* Output and update for referenced model: 'ex_arg_code_ref' */
void ex_arg_code_ref(const real32_T *rtu_In1, real32_T *rty_Out1, real32_T
                     rtp_coeffArg, real32_T rtp_gainArg, DW_ex_arg_code_ref_f_T *
                     localDW)
{
  real32_T denAccum;
  real32_T rtb_Sum;

  /* Sum: '<Root>/Sum' incorporates:
   *  UnitDelay: '<Root>/Unit Delay'
   */
  rtb_Sum = *rtu_In1 + localDW->UnitDelay_DSTATE;

  /* Gain: '<Root>/Gain' */
  rtb_Sum *= rtp_gainArg;

  /* DiscreteFilter: '<Root>/Discrete Filter' */
  localDW->DiscreteFilter_tmp = rtb_Sum - 0.5F * localDW->DiscreteFilter_states;
  denAccum = rtp_coeffArg * localDW->DiscreteFilter_tmp;
  *rty_Out1 = denAccum;

  /* Update for UnitDelay: '<Root>/Unit Delay' */
  localDW->UnitDelay_DSTATE = rtb_Sum;

  /* Update for DiscreteFilter: '<Root>/Discrete Filter' */
  localDW->DiscreteFilter_states = localDW->DiscreteFilter_tmp;
}

/* Model initialize function */
void ex_arg_code_ref_initialize(const char_T **rt_errorStatus,
  RT_MODEL_ex_arg_code_ref_T *const ex_arg_code_ref_M, DW_ex_arg_code_ref_f_T
  *localDW)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatusPointer(ex_arg_code_ref_M, rt_errorStatus);

  /* states (dwork) */
  (void) memset((void *)localDW, 0,
                sizeof(DW_ex_arg_code_ref_f_T));
}

The file ex_arg_code.c contains the definition of the top model entry-point function, ex_arg_code. This function calls the referenced model entry-point function, ex_arg_code_ref, and uses the model argument values that you specified (such as 1.11 and 3.34) as the values of rtp_coeffArg and rtp_gainArg.

file = fullfile('ex_arg_code_grt_rtw','ex_arg_code.c');
coder.example.extractLines(file,'/* ModelReference: ''<Root>/Model'' incorporates:',...
    '1.05F, 3.17F)',1,1)
  /* ModelReference: '<Root>/Model' incorporates:
   *  Inport: '<Root>/In1'
   *  Outport: '<Root>/Out1'
   */
  ex_arg_code_ref(&ex_arg_code_U.In1, &ex_arg_code_Y.Out1, 0.98F, 2.98F,
                  &(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* ModelReference: '<Root>/Model1' incorporates:
   *  Inport: '<Root>/In1'
   *  Outport: '<Root>/Out2'
   */
  ex_arg_code_ref(&ex_arg_code_U.In1, &ex_arg_code_Y.Out2, 1.05F, 3.17F,
                  &(ex_arg_code_DW.Model1_InstanceData.rtdw));

  /* Matfile logging */
  rt_UpdateTXYLogVars(ex_arg_code_M->rtwLogInfo,
                      (&ex_arg_code_M->Timing.taskTime0));

  /* signal main to stop simulation */
  {                                    /* Sample time: [0.2s, 0.0s] */
    if ((rtmGetTFinal(ex_arg_code_M)!=-1) &&
        !((rtmGetTFinal(ex_arg_code_M)-ex_arg_code_M->Timing.taskTime0) >
          ex_arg_code_M->Timing.taskTime0 * (DBL_EPSILON))) {
      rtmSetErrorStatus(ex_arg_code_M, "Simulation finished");
    }
  }

  /* Update absolute time for base rate */
  /* The "clockTick0" counts the number of times the code of this task has
   * been executed. The absolute time is the multiplication of "clockTick0"
   * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
   * overflow during the application lifespan selected.
   * Timer of this task consists of two 32 bit unsigned integers.
   * The two integers represent the low bits Timing.clockTick0 and the high bits
   * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
   */
  if (!(++ex_arg_code_M->Timing.clockTick0)) {
    ++ex_arg_code_M->Timing.clockTickH0;
  }

  ex_arg_code_M->Timing.taskTime0 = ex_arg_code_M->Timing.clockTick0 *
    ex_arg_code_M->Timing.stepSize0 + ex_arg_code_M->Timing.clockTickH0 *
    ex_arg_code_M->Timing.stepSize0 * 4294967296.0;
}

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

  /* initialize non-finites */
  rt_InitInfAndNaN(sizeof(real_T));

  /* initialize real-time model */
  (void) memset((void *)ex_arg_code_M, 0,
                sizeof(RT_MODEL_ex_arg_code_T));
  rtmSetTFinal(ex_arg_code_M, 10.0);
  ex_arg_code_M->Timing.stepSize0 = 0.2;

  /* Setup for data logging */
  {
    static RTWLogInfo rt_DataLoggingInfo;
    rt_DataLoggingInfo.loggingInterval = (NULL);
    ex_arg_code_M->rtwLogInfo = &rt_DataLoggingInfo;
  }

  /* Setup for data logging */
  {
    rtliSetLogXSignalInfo(ex_arg_code_M->rtwLogInfo, (NULL));
    rtliSetLogXSignalPtrs(ex_arg_code_M->rtwLogInfo, (NULL));
    rtliSetLogT(ex_arg_code_M->rtwLogInfo, "tout");
    rtliSetLogX(ex_arg_code_M->rtwLogInfo, "");
    rtliSetLogXFinal(ex_arg_code_M->rtwLogInfo, "");
    rtliSetLogVarNameModifier(ex_arg_code_M->rtwLogInfo, "rt_");
    rtliSetLogFormat(ex_arg_code_M->rtwLogInfo, 0);
    rtliSetLogMaxRows(ex_arg_code_M->rtwLogInfo, 0);
    rtliSetLogDecimation(ex_arg_code_M->rtwLogInfo, 1);

    /*
     * Set pointers to the data and signal info for each output
     */
    {
      static void * rt_LoggedOutputSignalPtrs[] = {
        &ex_arg_code_Y.Out1,
        &ex_arg_code_Y.Out2
      };

      rtliSetLogYSignalPtrs(ex_arg_code_M->rtwLogInfo, ((LogSignalPtrsType)
        rt_LoggedOutputSignalPtrs));
    }

    {
      static int_T rt_LoggedOutputWidths[] = {
        1,
        1
      };

      static int_T rt_LoggedOutputNumDimensions[] = {
        1,
        1
      };

      static int_T rt_LoggedOutputDimensions[] = {
        1,
        1
      };

      static boolean_T rt_LoggedOutputIsVarDims[] = {
        0,
        0
      };

      static void* rt_LoggedCurrentSignalDimensions[] = {
        (NULL),
        (NULL)
      };

      static int_T rt_LoggedCurrentSignalDimensionsSize[] = {
        4,
        4
      };

      static BuiltInDTypeId rt_LoggedOutputDataTypeIds[] = {
        SS_SINGLE,
        SS_SINGLE
      };

      static int_T rt_LoggedOutputComplexSignals[] = {
        0,
        0
      };

      static RTWPreprocessingFcnPtr rt_LoggingPreprocessingFcnPtrs[] = {
        (NULL),
        (NULL)
      };

      static const char_T *rt_LoggedOutputLabels[] = {
        "",
        "" };

      static const char_T *rt_LoggedOutputBlockNames[] = {
        "ex_arg_code/Out1",
        "ex_arg_code/Out2" };

      static RTWLogDataTypeConvert rt_RTWLogDataTypeConvert[] = {
        { 0, SS_SINGLE, SS_SINGLE, 0, 0, 0, 1.0, 0, 0.0 },

        { 0, SS_SINGLE, SS_SINGLE, 0, 0, 0, 1.0, 0, 0.0 }
      };

      static RTWLogSignalInfo rt_LoggedOutputSignalInfo[] = {
        {
          2,
          rt_LoggedOutputWidths,
          rt_LoggedOutputNumDimensions,
          rt_LoggedOutputDimensions,
          rt_LoggedOutputIsVarDims,
          rt_LoggedCurrentSignalDimensions,
          rt_LoggedCurrentSignalDimensionsSize,
          rt_LoggedOutputDataTypeIds,
          rt_LoggedOutputComplexSignals,
          (NULL),
          rt_LoggingPreprocessingFcnPtrs,

          { rt_LoggedOutputLabels },
          (NULL),
          (NULL),
          (NULL),

          { rt_LoggedOutputBlockNames },

          { (NULL) },
          (NULL),
          rt_RTWLogDataTypeConvert
        }
      };

      rtliSetLogYSignalInfo(ex_arg_code_M->rtwLogInfo, rt_LoggedOutputSignalInfo);

      /* set currSigDims field */
      rt_LoggedCurrentSignalDimensions[0] = &rt_LoggedOutputWidths[0];
      rt_LoggedCurrentSignalDimensions[1] = &rt_LoggedOutputWidths[1];
    }

    rtliSetLogY(ex_arg_code_M->rtwLogInfo, "yout");
  }

  /* states (dwork) */
  (void) memset((void *)&ex_arg_code_DW, 0,
                sizeof(DW_ex_arg_code_T));

  /* external inputs */
  ex_arg_code_U.In1 = 0.0F;

  /* external outputs */
  (void)memset(&ex_arg_code_Y, 0, sizeof(ExtY_ex_arg_code_T));

  /* Model Initialize function for ModelReference Block: '<Root>/Model' */
  ex_arg_code_ref_initialize(rtmGetErrorStatusPointer(ex_arg_code_M),
    &(ex_arg_code_DW.Model_InstanceData.rtm),
    &(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* Model Initialize function for ModelReference Block: '<Root>/Model1' */
  ex_arg_code_ref_initialize(rtmGetErrorStatusPointer(ex_arg_code_M),
    &(ex_arg_code_DW.Model1_InstanceData.rtm),
    &(ex_arg_code_DW.Model1_InstanceData.rtdw));

  /* Matfile logging */
  rt_StartDataLoggingWithStartTime(ex_arg_code_M->rtwLogInfo, 0.0, rtmGetTFinal
    (ex_arg_code_M), ex_arg_code_M->Timing.stepSize0, (&rtmGetErrorStatus
    (ex_arg_code_M)));

  /* SystemInitialize for ModelReference: '<Root>/Model' */
  ex_arg_code_ref_Init(&(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* SystemInitialize for ModelReference: '<Root>/Model1' */
  ex_arg_code_ref_Init(&(ex_arg_code_DW.Model1_InstanceData.rtdw));
}

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

The formal parameters use the data type real32_T (single) because:

  1. The block parameters in ex_arg_code_ref determine their data types through internal rules. For example, in the Gain block dialog box, on the Parameter Attributes tab, Parameter data type is set to Inherit: Inherit via internal rule (the default). In this case, the internal rule chooses the same data type as the input and output signals, single.

  2. The model arguments in the model workspace use context-sensitive data typing because the value of the DataType property is set to auto (the default). With this setting, the model arguments use the same data type as the block parameters, single.

  3. The formal parameters in the generated code use the same data type as the model arguments, single.

Generate Tunable Argument Values

You can configure the instance-specific values in the Model blocks to appear in the generated code as tunable global variables. This technique enables you to store the parameter values for each instance in memory and to tune the values during code execution.

In the top model ex_arg_code, select the Model Data Editor Parameters tab.

Use the Model Data Editor to set the values of the model arguments according to this figure.

View the contents of the ex_arg_code_ref model workspace in Model Explorer.

Copy gainArg and coeffArg from the ex_arg_code_ref model workspace to the base workspace.

Rename gainArg as gainForInst1. Rename coeffArg as coeffForInst1.

gainForInst1 = getVariable(modelWorkspace,'gainArg');
gainForInst1 = copy(gainForInst1);
coeffForInst1 = getVariable(modelWorkspace,'coeffArg');
coeffForInst1 = copy(coeffForInst1);

Copy gainForInst1 and coeffForInst1 as gainForInst2 and coeffForInst2.

gainForInst2 = copy(gainForInst1);
coeffForInst2 = copy(coeffForInst1);

Set the instance-specific parameter values by using the Value property of the parameter objects in the base workspace.

gainForInst1.Value = 2.98;
coeffForInst1.Value = 0.98;

gainForInst2.Value = 3.34;
coeffForInst2.Value = 1.11;

For each new parameter object, on the Code Generation tab, set StorageClass to ExportedGlobal. This setting causes the parameter objects to appear in the generated code as tunable global variables.

gainForInst1.StorageClass = 'ExportedGlobal';
coeffForInst1.StorageClass = 'ExportedGlobal';
gainForInst2.StorageClass = 'ExportedGlobal';
coeffForInst2.StorageClass = 'ExportedGlobal';

instSpecParams = get_param('ex_arg_code/Model','InstanceParameters');
instSpecParams(1).Value = 'coeffForInst1';
instSpecParams(2).Value = 'gainForInst1';
instSpecParams1 = get_param('ex_arg_code/Model1','InstanceParameters');
instSpecParams1(1).Value = 'coeffForInst2';
instSpecParams1(2).Value = 'gainForInst2';
set_param('ex_arg_code/Model','InstanceParameters',instSpecParams);
set_param('ex_arg_code/Model1','InstanceParameters',instSpecParams1);

Generate code from the top model.

slbuild('ex_arg_code')
### Searching for referenced models in model 'ex_arg_code'.
### Found 1 model reference targets to update.
### Starting serial model reference code generation build.
### Model reference code generation target for ex_arg_code_ref is up to date.
### Starting build procedure for: ex_arg_code
### Successful completion of build procedure for: ex_arg_code

Build Summary

Top model targets:

Model        Build Reason                     Status                        Build Duration
==========================================================================================
ex_arg_code  Generated code was out of date.  Code generated and compiled.  0h 0m 11.257s 

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

The file ex_arg_code.c defines the global variables that correspond to the parameter objects in the base workspace.

file = fullfile('ex_arg_code_grt_rtw','ex_arg_code.c');
coder.example.extractLines(file,'/* Exported block parameters */',...
    '/* Block states (default storage) */',1,0)
/* Exported block parameters */
real32_T coeffForInst1 = 0.98F;        /* Variable: coeffForInst1
                                        * Referenced by: '<Root>/Model'
                                        */
real32_T coeffForInst2 = 1.11F;        /* Variable: coeffForInst2
                                        * Referenced by: '<Root>/Model1'
                                        */
real32_T gainForInst1 = 2.98F;         /* Variable: gainForInst1
                                        * Referenced by: '<Root>/Model'
                                        */
real32_T gainForInst2 = 3.34F;         /* Variable: gainForInst2
                                        * Referenced by: '<Root>/Model1'
                                        */

In each call to ex_arg_code_ref, the top model algorithm uses the global variables to set the values of the formal parameters.

coder.example.extractLines(file,'/* ModelReference: ''<Root>/Model'' incorporates:',...
    'gainForInst2);',1,1)
  /* ModelReference: '<Root>/Model' incorporates:
   *  Inport: '<Root>/In1'
   *  Outport: '<Root>/Out1'
   */
  ex_arg_code_ref(&ex_arg_code_U.In1, &ex_arg_code_Y.Out1, coeffForInst1,
                  gainForInst1, &(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* ModelReference: '<Root>/Model1' incorporates:
   *  Inport: '<Root>/In1'
   *  Outport: '<Root>/Out2'
   */
  ex_arg_code_ref(&ex_arg_code_U.In1, &ex_arg_code_Y.Out2, coeffForInst2,
                  gainForInst2, &(ex_arg_code_DW.Model1_InstanceData.rtdw));

  /* Matfile logging */
  rt_UpdateTXYLogVars(ex_arg_code_M->rtwLogInfo,
                      (&ex_arg_code_M->Timing.taskTime0));

  /* signal main to stop simulation */
  {                                    /* Sample time: [0.2s, 0.0s] */
    if ((rtmGetTFinal(ex_arg_code_M)!=-1) &&
        !((rtmGetTFinal(ex_arg_code_M)-ex_arg_code_M->Timing.taskTime0) >
          ex_arg_code_M->Timing.taskTime0 * (DBL_EPSILON))) {
      rtmSetErrorStatus(ex_arg_code_M, "Simulation finished");
    }
  }

  /* Update absolute time for base rate */
  /* The "clockTick0" counts the number of times the code of this task has
   * been executed. The absolute time is the multiplication of "clockTick0"
   * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
   * overflow during the application lifespan selected.
   * Timer of this task consists of two 32 bit unsigned integers.
   * The two integers represent the low bits Timing.clockTick0 and the high bits
   * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
   */
  if (!(++ex_arg_code_M->Timing.clockTick0)) {
    ++ex_arg_code_M->Timing.clockTickH0;
  }

  ex_arg_code_M->Timing.taskTime0 = ex_arg_code_M->Timing.clockTick0 *
    ex_arg_code_M->Timing.stepSize0 + ex_arg_code_M->Timing.clockTickH0 *
    ex_arg_code_M->Timing.stepSize0 * 4294967296.0;
}

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

  /* initialize non-finites */
  rt_InitInfAndNaN(sizeof(real_T));

  /* initialize real-time model */
  (void) memset((void *)ex_arg_code_M, 0,
                sizeof(RT_MODEL_ex_arg_code_T));
  rtmSetTFinal(ex_arg_code_M, 10.0);
  ex_arg_code_M->Timing.stepSize0 = 0.2;

  /* Setup for data logging */
  {
    static RTWLogInfo rt_DataLoggingInfo;
    rt_DataLoggingInfo.loggingInterval = (NULL);
    ex_arg_code_M->rtwLogInfo = &rt_DataLoggingInfo;
  }

  /* Setup for data logging */
  {
    rtliSetLogXSignalInfo(ex_arg_code_M->rtwLogInfo, (NULL));
    rtliSetLogXSignalPtrs(ex_arg_code_M->rtwLogInfo, (NULL));
    rtliSetLogT(ex_arg_code_M->rtwLogInfo, "tout");
    rtliSetLogX(ex_arg_code_M->rtwLogInfo, "");
    rtliSetLogXFinal(ex_arg_code_M->rtwLogInfo, "");
    rtliSetLogVarNameModifier(ex_arg_code_M->rtwLogInfo, "rt_");
    rtliSetLogFormat(ex_arg_code_M->rtwLogInfo, 0);
    rtliSetLogMaxRows(ex_arg_code_M->rtwLogInfo, 0);
    rtliSetLogDecimation(ex_arg_code_M->rtwLogInfo, 1);

    /*
     * Set pointers to the data and signal info for each output
     */
    {
      static void * rt_LoggedOutputSignalPtrs[] = {
        &ex_arg_code_Y.Out1,
        &ex_arg_code_Y.Out2
      };

      rtliSetLogYSignalPtrs(ex_arg_code_M->rtwLogInfo, ((LogSignalPtrsType)
        rt_LoggedOutputSignalPtrs));
    }

    {
      static int_T rt_LoggedOutputWidths[] = {
        1,
        1
      };

      static int_T rt_LoggedOutputNumDimensions[] = {
        1,
        1
      };

      static int_T rt_LoggedOutputDimensions[] = {
        1,
        1
      };

      static boolean_T rt_LoggedOutputIsVarDims[] = {
        0,
        0
      };

      static void* rt_LoggedCurrentSignalDimensions[] = {
        (NULL),
        (NULL)
      };

      static int_T rt_LoggedCurrentSignalDimensionsSize[] = {
        4,
        4
      };

      static BuiltInDTypeId rt_LoggedOutputDataTypeIds[] = {
        SS_SINGLE,
        SS_SINGLE
      };

      static int_T rt_LoggedOutputComplexSignals[] = {
        0,
        0
      };

      static RTWPreprocessingFcnPtr rt_LoggingPreprocessingFcnPtrs[] = {
        (NULL),
        (NULL)
      };

      static const char_T *rt_LoggedOutputLabels[] = {
        "",
        "" };

      static const char_T *rt_LoggedOutputBlockNames[] = {
        "ex_arg_code/Out1",
        "ex_arg_code/Out2" };

      static RTWLogDataTypeConvert rt_RTWLogDataTypeConvert[] = {
        { 0, SS_SINGLE, SS_SINGLE, 0, 0, 0, 1.0, 0, 0.0 },

        { 0, SS_SINGLE, SS_SINGLE, 0, 0, 0, 1.0, 0, 0.0 }
      };

      static RTWLogSignalInfo rt_LoggedOutputSignalInfo[] = {
        {
          2,
          rt_LoggedOutputWidths,
          rt_LoggedOutputNumDimensions,
          rt_LoggedOutputDimensions,
          rt_LoggedOutputIsVarDims,
          rt_LoggedCurrentSignalDimensions,
          rt_LoggedCurrentSignalDimensionsSize,
          rt_LoggedOutputDataTypeIds,
          rt_LoggedOutputComplexSignals,
          (NULL),
          rt_LoggingPreprocessingFcnPtrs,

          { rt_LoggedOutputLabels },
          (NULL),
          (NULL),
          (NULL),

          { rt_LoggedOutputBlockNames },

          { (NULL) },
          (NULL),
          rt_RTWLogDataTypeConvert
        }
      };

      rtliSetLogYSignalInfo(ex_arg_code_M->rtwLogInfo, rt_LoggedOutputSignalInfo);

      /* set currSigDims field */
      rt_LoggedCurrentSignalDimensions[0] = &rt_LoggedOutputWidths[0];
      rt_LoggedCurrentSignalDimensions[1] = &rt_LoggedOutputWidths[1];
    }

    rtliSetLogY(ex_arg_code_M->rtwLogInfo, "yout");
  }

  /* states (dwork) */
  (void) memset((void *)&ex_arg_code_DW, 0,
                sizeof(DW_ex_arg_code_T));

  /* external inputs */
  ex_arg_code_U.In1 = 0.0F;

  /* external outputs */
  (void)memset(&ex_arg_code_Y, 0, sizeof(ExtY_ex_arg_code_T));

  /* Model Initialize function for ModelReference Block: '<Root>/Model' */
  ex_arg_code_ref_initialize(rtmGetErrorStatusPointer(ex_arg_code_M),
    &(ex_arg_code_DW.Model_InstanceData.rtm),
    &(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* Model Initialize function for ModelReference Block: '<Root>/Model1' */
  ex_arg_code_ref_initialize(rtmGetErrorStatusPointer(ex_arg_code_M),
    &(ex_arg_code_DW.Model1_InstanceData.rtm),
    &(ex_arg_code_DW.Model1_InstanceData.rtdw));

  /* Matfile logging */
  rt_StartDataLoggingWithStartTime(ex_arg_code_M->rtwLogInfo, 0.0, rtmGetTFinal
    (ex_arg_code_M), ex_arg_code_M->Timing.stepSize0, (&rtmGetErrorStatus
    (ex_arg_code_M)));

  /* SystemInitialize for ModelReference: '<Root>/Model' */
  ex_arg_code_ref_Init(&(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* SystemInitialize for ModelReference: '<Root>/Model1' */
  ex_arg_code_ref_Init(&(ex_arg_code_DW.Model1_InstanceData.rtdw));
}

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

The global variables in the generated code use the data type real32_T (single) because:

  1. The parameter objects in the base workspace use context-sensitive data typing because the DataType property is set to auto (the default). With this setting, the parameter objects in the base workspace use the same data type as the model arguments, single.

  2. The global variables in the generated code use the same data type as the parameter objects in the base workspace.

Group Multiple Model Arguments into Single Structure

Use the Model Explorer to copy gainArg and coeffArg from the ex_arg_code_ref model workspace into the base workspace.

temp = getVariable(modelWorkspace,'gainArg');
gainArg = copy(temp);
temp = getVariable(modelWorkspace,'coeffArg');
coeffArg = copy(temp);

At the command prompt, combine these two parameter objects into a structure, structArg.

structArg = Simulink.Parameter(struct('gain',gainArg.Value,...
    'coeff',coeffArg.Value));

Use the Model Explorer to move structArg into the model workspace.

assignin(modelWorkspace,'structArg',copy(structArg));
clear structArg gainArg coeffArg

In the Contents pane, configure structArg as the only model argument.

set_param('ex_arg_code_ref','ParameterArgumentNames','structArg')

In the ex_arg_code_ref model, select the Model Data Editor Parameters tab.

Use the Model Data Editor to set the value of the Gain parameter to structArg.gain and the value of the Numerator parameter to structArg.coeff. Save the model.

set_param('ex_arg_code_ref/Gain','Gain','structArg.gain')
set_param('ex_arg_code_ref/Discrete Filter',...
    'Numerator','structArg.coeff')
save_system('ex_arg_code_ref')

At the command prompt, combine the four parameter objects in the base workspace into two structures. Each structure stores the parameter values for one instance of ex_arg_code_ref.

structForInst1 = Simulink.Parameter(struct('gain',gainForInst1.Value,...
    'coeff',coeffForInst1.Value));

structForInst2 = Simulink.Parameter(struct('gain',gainForInst2.Value,...
    'coeff',coeffForInst2.Value));

In the top model ex_arg_code, use the Model Data Editor to set the argument values according to this figure.

instSpecParams = get_param('ex_arg_code/Model','InstanceParameters');
instSpecParams(1).Value = 'structForInst1';
instSpecParams1 = get_param('ex_arg_code/Model1','InstanceParameters');
instSpecParams1(1).Value = 'structForInst2';
set_param('ex_arg_code/Model','InstanceParameters',instSpecParams);
set_param('ex_arg_code/Model1','InstanceParameters',instSpecParams1);

Click the Show/refresh additional information button.

For the new parameter objects structForInst1 and structForInst2, use the Model Explorer to apply the storage class ExportedGlobal.

structForInst1.StorageClass = 'ExportedGlobal';
structForInst2.StorageClass = 'ExportedGlobal';

At the command prompt, use the function Simulink.Bus.createObject to create a Simulink.Bus object. The hierarchy of elements in the object matches the hierarchy of the structure fields. The default name of the object is slBus1.

Simulink.Bus.createObject(structForInst1.Value);

Rename the bus object as myParamStructType by copying it.

myParamStructType = copy(slBus1);

In the Model Data Editor for ex_arg_code, use the Data Type column to set the data type of structForInst1 and structForInst2 to Bus: myParamStructType.

structForInst1.DataType = 'Bus: myParamStructType';
structForInst2.DataType = 'Bus: myParamStructType';

temp = getVariable(modelWorkspace,'structArg');
temp = copy(temp);
temp.DataType = 'Bus: myParamStructType';
assignin(modelWorkspace,'structArg',copy(temp));

Save the ex_arg_code_ref model.

save_system('ex_arg_code_ref')

When you use structures to group parameter values, you cannot take advantage of context-sensitive data typing to control the data types of the fields of the structures (for example, the fields of structForInst1). However, you can use the properties of the bus object to control the field data types.

At the command promt, set the data type of the elements in the bus object to single. The corresponding fields in the structures (such as structForInst1 and structArg) use the same data type.

myParamStructType.Elements(1).DataType = 'single';
myParamStructType.Elements(2).DataType = 'single';

Generate code from the top model, ex_arg_code.

slbuild('ex_arg_code')
### Searching for referenced models in model 'ex_arg_code'.
### Found 1 model reference targets to update.
### Starting serial model reference code generation build.
### Successfully updated the model reference code generation target for: ex_arg_code_ref
### Starting build procedure for: ex_arg_code
### Successful completion of build procedure for: ex_arg_code

Build Summary

Model reference code generation targets:

Model            Build Reason                               Status                        Build Duration
========================================================================================================
ex_arg_code_ref  Model or library ex_arg_code_ref changed.  Code generated and compiled.  0h 0m 10.215s 

Top model targets:

Model        Build Reason                     Status                        Build Duration
==========================================================================================
ex_arg_code  Referenced models were updated.  Code generated and compiled.  0h 0m 12.233s 

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

The file ex_arg_code_types.h defines the structure type myParamStructType, which corresponds to the Simulink.Bus object.

file = fullfile('ex_arg_code_grt_rtw','ex_arg_code_types.h');
coder.example.extractLines(file,'typedef struct {','} myParamStructType;',1,1)
typedef struct {
  real32_T gain;
  real32_T coeff;
} myParamStructType;

In the file ex_arg_code_ref.c, the referenced model entry-point function has a formal parameter, rtp_structArg, that correspond to the model argument structArg.

file = fullfile('slprj','grt','ex_arg_code_ref','ex_arg_code_ref.c');
coder.example.extractLines(file,'/* Output and update for referenced model:',...
    '*rtp_structArg)',1,1)
/* Output and update for referenced model: 'ex_arg_code_ref' */
void ex_arg_code_ref(const real32_T *rtu_In1, real32_T *rty_Out1, const
                     myParamStructType *rtp_structArg, DW_ex_arg_code_ref_f_T
                     *localDW)
{
  real32_T rtb_Sum;

  /* Sum: '<Root>/Sum' incorporates:
   *  UnitDelay: '<Root>/Unit Delay'
   */
  rtb_Sum = *rtu_In1 + localDW->UnitDelay_DSTATE;

  /* Gain: '<Root>/Gain' */
  rtb_Sum *= rtp_structArg->gain;

  /* DiscreteFilter: '<Root>/Discrete Filter' */
  localDW->DiscreteFilter_tmp = rtb_Sum - 0.5F * localDW->DiscreteFilter_states;
  *rty_Out1 = rtp_structArg->coeff * localDW->DiscreteFilter_tmp;

  /* Update for UnitDelay: '<Root>/Unit Delay' */
  localDW->UnitDelay_DSTATE = rtb_Sum;

  /* Update for DiscreteFilter: '<Root>/Discrete Filter' */
  localDW->DiscreteFilter_states = localDW->DiscreteFilter_tmp;
}

/* Model initialize function */
void ex_arg_code_ref_initialize(const char_T **rt_errorStatus,
  RT_MODEL_ex_arg_code_ref_T *const ex_arg_code_ref_M, DW_ex_arg_code_ref_f_T
  *localDW)
{
  /* Registration code */

  /* initialize error status */
  rtmSetErrorStatusPointer(ex_arg_code_ref_M, rt_errorStatus);

  /* states (dwork) */
  (void) memset((void *)localDW, 0,
                sizeof(DW_ex_arg_code_ref_f_T));
}

The file ex_arg_code.c defines the global structure variables that correspond to the parameter objects in the base workspace.

file = fullfile('ex_arg_code_grt_rtw','ex_arg_code.c');
coder.example.extractLines(file,'/* Exported block parameters */',...
    '/* Block states (default storage) */',1,0)
/* Exported block parameters */
myParamStructType structForInst1 = {
  2.98F,
  0.98F
} ;                                    /* Variable: structForInst1
                                        * Referenced by: '<Root>/Model'
                                        */

myParamStructType structForInst2 = {
  3.34F,
  1.11F
} ;                                    /* Variable: structForInst2
                                        * Referenced by: '<Root>/Model1'
                                        */

The top model algorithm in the file ex_arg_code.c passes the addresses of the structure variables to the referenced model entry-point function.

file = fullfile('ex_arg_code_grt_rtw','ex_arg_code.c');
coder.example.extractLines(file,'/* ModelReference: ''<Root>/Model'' incorporates:',...
    '&structForInst2);',1,1)
  /* ModelReference: '<Root>/Model' incorporates:
   *  Inport: '<Root>/In1'
   *  Outport: '<Root>/Out1'
   */
  ex_arg_code_ref(&ex_arg_code_U.In1, &ex_arg_code_Y.Out1, &structForInst1,
                  &(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* ModelReference: '<Root>/Model1' incorporates:
   *  Inport: '<Root>/In1'
   *  Outport: '<Root>/Out2'
   */
  ex_arg_code_ref(&ex_arg_code_U.In1, &ex_arg_code_Y.Out2, &structForInst2,
                  &(ex_arg_code_DW.Model1_InstanceData.rtdw));

  /* Matfile logging */
  rt_UpdateTXYLogVars(ex_arg_code_M->rtwLogInfo,
                      (&ex_arg_code_M->Timing.taskTime0));

  /* signal main to stop simulation */
  {                                    /* Sample time: [0.2s, 0.0s] */
    if ((rtmGetTFinal(ex_arg_code_M)!=-1) &&
        !((rtmGetTFinal(ex_arg_code_M)-ex_arg_code_M->Timing.taskTime0) >
          ex_arg_code_M->Timing.taskTime0 * (DBL_EPSILON))) {
      rtmSetErrorStatus(ex_arg_code_M, "Simulation finished");
    }
  }

  /* Update absolute time for base rate */
  /* The "clockTick0" counts the number of times the code of this task has
   * been executed. The absolute time is the multiplication of "clockTick0"
   * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not
   * overflow during the application lifespan selected.
   * Timer of this task consists of two 32 bit unsigned integers.
   * The two integers represent the low bits Timing.clockTick0 and the high bits
   * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment.
   */
  if (!(++ex_arg_code_M->Timing.clockTick0)) {
    ++ex_arg_code_M->Timing.clockTickH0;
  }

  ex_arg_code_M->Timing.taskTime0 = ex_arg_code_M->Timing.clockTick0 *
    ex_arg_code_M->Timing.stepSize0 + ex_arg_code_M->Timing.clockTickH0 *
    ex_arg_code_M->Timing.stepSize0 * 4294967296.0;
}

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

  /* initialize non-finites */
  rt_InitInfAndNaN(sizeof(real_T));

  /* initialize real-time model */
  (void) memset((void *)ex_arg_code_M, 0,
                sizeof(RT_MODEL_ex_arg_code_T));
  rtmSetTFinal(ex_arg_code_M, 10.0);
  ex_arg_code_M->Timing.stepSize0 = 0.2;

  /* Setup for data logging */
  {
    static RTWLogInfo rt_DataLoggingInfo;
    rt_DataLoggingInfo.loggingInterval = (NULL);
    ex_arg_code_M->rtwLogInfo = &rt_DataLoggingInfo;
  }

  /* Setup for data logging */
  {
    rtliSetLogXSignalInfo(ex_arg_code_M->rtwLogInfo, (NULL));
    rtliSetLogXSignalPtrs(ex_arg_code_M->rtwLogInfo, (NULL));
    rtliSetLogT(ex_arg_code_M->rtwLogInfo, "tout");
    rtliSetLogX(ex_arg_code_M->rtwLogInfo, "");
    rtliSetLogXFinal(ex_arg_code_M->rtwLogInfo, "");
    rtliSetLogVarNameModifier(ex_arg_code_M->rtwLogInfo, "rt_");
    rtliSetLogFormat(ex_arg_code_M->rtwLogInfo, 0);
    rtliSetLogMaxRows(ex_arg_code_M->rtwLogInfo, 0);
    rtliSetLogDecimation(ex_arg_code_M->rtwLogInfo, 1);

    /*
     * Set pointers to the data and signal info for each output
     */
    {
      static void * rt_LoggedOutputSignalPtrs[] = {
        &ex_arg_code_Y.Out1,
        &ex_arg_code_Y.Out2
      };

      rtliSetLogYSignalPtrs(ex_arg_code_M->rtwLogInfo, ((LogSignalPtrsType)
        rt_LoggedOutputSignalPtrs));
    }

    {
      static int_T rt_LoggedOutputWidths[] = {
        1,
        1
      };

      static int_T rt_LoggedOutputNumDimensions[] = {
        1,
        1
      };

      static int_T rt_LoggedOutputDimensions[] = {
        1,
        1
      };

      static boolean_T rt_LoggedOutputIsVarDims[] = {
        0,
        0
      };

      static void* rt_LoggedCurrentSignalDimensions[] = {
        (NULL),
        (NULL)
      };

      static int_T rt_LoggedCurrentSignalDimensionsSize[] = {
        4,
        4
      };

      static BuiltInDTypeId rt_LoggedOutputDataTypeIds[] = {
        SS_SINGLE,
        SS_SINGLE
      };

      static int_T rt_LoggedOutputComplexSignals[] = {
        0,
        0
      };

      static RTWPreprocessingFcnPtr rt_LoggingPreprocessingFcnPtrs[] = {
        (NULL),
        (NULL)
      };

      static const char_T *rt_LoggedOutputLabels[] = {
        "",
        "" };

      static const char_T *rt_LoggedOutputBlockNames[] = {
        "ex_arg_code/Out1",
        "ex_arg_code/Out2" };

      static RTWLogDataTypeConvert rt_RTWLogDataTypeConvert[] = {
        { 0, SS_SINGLE, SS_SINGLE, 0, 0, 0, 1.0, 0, 0.0 },

        { 0, SS_SINGLE, SS_SINGLE, 0, 0, 0, 1.0, 0, 0.0 }
      };

      static RTWLogSignalInfo rt_LoggedOutputSignalInfo[] = {
        {
          2,
          rt_LoggedOutputWidths,
          rt_LoggedOutputNumDimensions,
          rt_LoggedOutputDimensions,
          rt_LoggedOutputIsVarDims,
          rt_LoggedCurrentSignalDimensions,
          rt_LoggedCurrentSignalDimensionsSize,
          rt_LoggedOutputDataTypeIds,
          rt_LoggedOutputComplexSignals,
          (NULL),
          rt_LoggingPreprocessingFcnPtrs,

          { rt_LoggedOutputLabels },
          (NULL),
          (NULL),
          (NULL),

          { rt_LoggedOutputBlockNames },

          { (NULL) },
          (NULL),
          rt_RTWLogDataTypeConvert
        }
      };

      rtliSetLogYSignalInfo(ex_arg_code_M->rtwLogInfo, rt_LoggedOutputSignalInfo);

      /* set currSigDims field */
      rt_LoggedCurrentSignalDimensions[0] = &rt_LoggedOutputWidths[0];
      rt_LoggedCurrentSignalDimensions[1] = &rt_LoggedOutputWidths[1];
    }

    rtliSetLogY(ex_arg_code_M->rtwLogInfo, "yout");
  }

  /* states (dwork) */
  (void) memset((void *)&ex_arg_code_DW, 0,
                sizeof(DW_ex_arg_code_T));

  /* external inputs */
  ex_arg_code_U.In1 = 0.0F;

  /* external outputs */
  (void)memset(&ex_arg_code_Y, 0, sizeof(ExtY_ex_arg_code_T));

  /* Model Initialize function for ModelReference Block: '<Root>/Model' */
  ex_arg_code_ref_initialize(rtmGetErrorStatusPointer(ex_arg_code_M),
    &(ex_arg_code_DW.Model_InstanceData.rtm),
    &(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* Model Initialize function for ModelReference Block: '<Root>/Model1' */
  ex_arg_code_ref_initialize(rtmGetErrorStatusPointer(ex_arg_code_M),
    &(ex_arg_code_DW.Model1_InstanceData.rtm),
    &(ex_arg_code_DW.Model1_InstanceData.rtdw));

  /* Matfile logging */
  rt_StartDataLoggingWithStartTime(ex_arg_code_M->rtwLogInfo, 0.0, rtmGetTFinal
    (ex_arg_code_M), ex_arg_code_M->Timing.stepSize0, (&rtmGetErrorStatus
    (ex_arg_code_M)));

  /* SystemInitialize for ModelReference: '<Root>/Model' */
  ex_arg_code_ref_Init(&(ex_arg_code_DW.Model_InstanceData.rtdw));

  /* SystemInitialize for ModelReference: '<Root>/Model1' */
  ex_arg_code_ref_Init(&(ex_arg_code_DW.Model1_InstanceData.rtdw));
}

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

Control Data Types of Model Arguments and Argument Values

When you use model arguments, you can apply a data type to:

  • The block parameters that use the arguments (for certain blocks, such as those in the Discrete library).

  • The arguments in the referenced model workspace.

  • The argument values that you specify in Model blocks.

To generate efficient code by eliminating unnecessary typecasts and C shifts, consider using inherited and context-sensitive data typing to match the data types.

  • In the model workspace, use a MATLAB® variable whose data type is double or a parameter object whose DataType property is set to auto. In this case, the variable or object uses the same data type as the block parameter.

  • When you set the argument values in Model blocks, take advantage of context-sensitive data typing. To set an argument value, use an untyped value.

    • A literal number such as 15.23. Do not use a typed expression such as single(15.23).

    • A MATLAB variable whose data type is double.

    • A Simulink.Parameter object whose DataType property is set to auto.

    In these cases, the number, variable, or object uses the same data type as the model argument in the referenced model workspace. If you also configure the model argument to use context-sensitive data typing, you can control the data types of the block parameter, the argument, and the argument value by specifying the type only for the block parameter.

For basic information about controlling parameter data types, see Parameter Data Types in the Generated Code.

Use Model Argument in Different Data Type Contexts

If you use a model argument to set multiple block parameter values, and the data types of the block parameters differ, you cannot use context-sensitive data typing (double or auto) for the argument in the model workspace. You must explicitly specify a data type for the argument. For example, if the argument in the model workspace is a parameter object (such as Simulink.Parameter), set the DataType property to a value other than auto. For more information about this situation, see Reuse Parameter Data in Different Data Type Contexts.

In this case, you can continue to take advantage of context-sensitive data typing to control the data type of the argument values that you specify in Model blocks. Each argument value uses the data type that you specify for the corresponding argument in the model workspace.

Related Topics