Main Content

Generate Code for Variant Parameter Banks in Model Reference Hierarchy

This example shows how to generate code for a model reference hierarchy that uses the same variant parameter bank to group variant parameters used by models across the hierarchy.

A variant parameter bank (Simulink.VariantBank object) enables you to group variant parameter values with the same variant conditions into a structure array in the generated code. Variant parameters are implemented as Simulink.VariantVariable objects. For an example that shows the use of variant parameter banks, see Group Variant Parameter Values and Conditionally Switch Active Value Sets in Generated Code.

When you generate code for a model using variant parameter banks, the code generator identifies all variant parameters in a variant parameter bank within the base workspace or data dictionaries visible to the model hierarchy and includes them in the parameter bank definition. The header file that contains the type definition of the variant parameter bank is generated in a shared utilities folder slprj/ target /_sharedutils, where | _target_ | is the name of the system target file for code generation. This mechanism enables sharing the variant parameter bank across multiple models in the hierarchy.

Explore Example Model

1. Open the top-level model slexVariantParameterBankMdlRef and the referenced model slexVariantParameterBankWithSLDD.

open_system("slexVariantParameterBankMdlRef");

open_system("slexVariantParameterBankWithSLDD");

In these models:

  • The top-level model slexVariantParameterBankMdlRef contains a Gain block named Scale Value that uses a variant parameter SCALE_FACTOR to set the Gain parameter value. SCALE_FACTOR is defined as a Simulink.VariantVariable object in the data dictionary topBankedVariantParameterData.sldd.

  • The model slexVariantParameterBankWithSLDD contains multiple blocks that use variant parameters defined in the data dictionary bankedVariantParameterData.sldd. The values of the Constant parameters of the two Constant blocks in the model are set to the variant parameter objects SHIFT_VALUE and TABLE_DIM_0. The Table data and Breakpoint sets of the n-D Lookup Table blocks are specified using the variant parameter objects T1Break, T1Data, T2Break, and T2Data.

  • The Architectural Data section of bankedVariantParameterData.sldd has topBankedVariantParameterData.sldd specified as a referenced dictionary.

The top model data dictionary topBankedVariantParameterData.sldd also defines these Simulink.VariantControl, Simulink.VariantBank, and Simulink.VariantBankCoderInfo objects that are used by variant parameter objects in the model hierarchy:

  • VCtrl is defined as a Simulink.VariantControl object. The value of VCtrl is set to 1, and its activation time is set to startup. This object is used as a variant control variable to define the variant conditions for all the variant parameter objects in the model hierarchy. During simulation, the choices associated with the condition VCtrl==1 become active, and the choices associated with VCtrl==2 become inactive.

  • LUTBank is defined as a Simulink.VariantBank object. This variant parameter bank is used to group the variant parameter objects T1Break, T1Data, T2Break, T2Data, and SCALE_FACTOR. The Bank property of these variant parameter objects is set to LUTBank. LUTBank has the same set of variant conditions as these variant parameter objects. The AllChoicesCoderInfo property of this variant parameter bank object is set to LUTAllChoicesCoderInfo and the ActiveChoiceCoderInfo property is set to LUTActiveChoiceCoderInfo.

  • LUTAllChoicesCoderInfo and LUTActiveChoiceCoderInfo are Simulink.VariantBankCoderInfo objects. The LUTAllChoicesCoderInfo object specifies code generation properties such as the header file, definition file, and #pragma directives for the structure array that represents LUTBank in the generated code. Similarly, LUTActiveChoiceCoderInfo allows you to specify these attributes separately for the pointer variable.

Generate Code

To generate code that uses variant parameter bank switching, use Embedded Coder®. For more information, see Generate Code Using Embedded Coder.

slbuild("slexVariantParameterBankMdlRef")
### Searching for referenced models in model 'slexVariantParameterBankMdlRef'.
### Total of 2 models to build.
### Starting serial code generation build.
### Starting build procedure for: slexVariantParameterBankWithSLDD
### Successful completion of build procedure for: slexVariantParameterBankWithSLDD
### Starting build procedure for: slexVariantParameterBankMdlRef
### Successful completion of build procedure for: slexVariantParameterBankMdlRef

Build Summary

Model reference code generation targets:

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

Top model targets:

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

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

Review Generated Code

1. In the C Code tab, select Open Report.

2. In the code generation report, open the header files variantBank_lut_array_p.h and variantBank_lut_ptr_p.h from the shared utilities folder slprj/ert/_sharedutils. These files contain the type definition and declaration for the variant parameter bank structure array and pointer variable. The parameter bank definition contains variant parameters used by the top-level model and the referenced model.

file = fullfile("slprj/ert/_sharedutils", ...
    "variantBank_lut_array_p.h");
coder.example.extractLines(file,"typedef struct {","#pragma end",1,1)
typedef struct {
  real_T T1Break[11];
  real_T T1Data[11];
  real_T T2Break[3];
  real_T T2Data[9];
  real_T SCALE_FACTOR;
} LUTBpAndData;

/* Exported data declaration */
/* Variant parameter bank: LUTBank */

/* Variant parameter bank section */
#pragma data_seg(.arrdata)

extern const LUTBpAndData LUTBpAndData_ptr_impl[2];

file = fullfile("slprj/ert/_sharedutils/", ...
    "variantBank_lut_ptr_p.h");
coder.example.extractLines(file,"#pragma data_seg(.ptrdata)","#endif",1,0)
#pragma data_seg(.ptrdata)

extern const volatile LUTBpAndData *LUTBpAndData_ptr;

#pragma end

3. In the code generation report, open the slexVariantParameterBankMdlRef.c and slexVariantParameterBankWithSLDD.c files. The code for the top-level model and referenced model accesses the active value set fom the shared variant parameter bank using the pointer variable.

file = fullfile("slexVariantParameterBankMdlRef_ert_rtw",...
    "slexVariantParameterBankMdlRef.c");
coder.example.extractLines(file,"/* Model step function */","/* Model terminate function */",1,0)
/* Model step function */
void slexVariantParameterBankMdlRef_step(void)
{
  real_T rtb_Output;

  /* ModelReference: '<Root>/Value' */
  slexVariantParameterBankWithSLDD(&rtb_Output,
    &(slexVariantParameterBankMdlRef_DW.Value_InstanceData.rtdw));

  /* Outport: '<Root>/Out1' incorporates:
   *  Gain: '<Root>/Scale Value'
   */
  slexVariantParameterBankMdlRef_Y.Out1 = LUTBpAndData_ptr->SCALE_FACTOR *
    rtb_Output;
}

/* Model initialize function */
void slexVariantParameterBankMdlRef_initialize(void)
{
  /* Model Initialize function for ModelReference Block: '<Root>/Value' */
  slexVariantParameterBankWithSLDD_initialize(rtmGetErrorStatusPointer
    (slexVariantParameterBankMdlRef_M),
    &(slexVariantParameterBankMdlRef_DW.Value_InstanceData.rtm));

  /* Variant Parameters startup activation time */
  if (VCtrl == 1) {
    LUTBpAndData_ptr = &LUTBpAndData_ptr_impl[0U];
  } else if (VCtrl == 2) {
    LUTBpAndData_ptr = &LUTBpAndData_ptr_impl[1U];
  }

  /* Variant Parameters startup activation time */
  if (VCtrl == 1) {
    rtP_SHIFT_VALUE = -18.0;
    rtP_TABLE_DIM_0 = 10.0;
  } else if (VCtrl == 2) {
    rtP_SHIFT_VALUE = -16.0;
    rtP_TABLE_DIM_0 = 20.0;
  }

  slexVariantParameterBankMdlRef_startupVariantChecker();
}
file = fullfile("slprj/ert/slexVariantParameterBankWithSLDD",...
    "slexVariantParameterBankWithSLDD.c");
coder.example.extractLines(file,"/* Output and update for referenced model: 'slexVariantParameterBankWithSLDD' */","/* Model initialize function */",1,0)
/* Output and update for referenced model: 'slexVariantParameterBankWithSLDD' */
void slexVariantParameterBankWithSLDD(real_T *rty_Out1,
  DW_slexVariantParameterBankWithSLDD_f_T *localDW)
{
  /* Gain: '<Root>/Gain' incorporates:
   *  Constant: '<Root>/Constant'
   *  Constant: '<Root>/Constant1'
   *  Lookup_n-D: '<Root>/1D Lookup'
   *  Lookup_n-D: '<Root>/2D Lookup'
   *  Sin: '<Root>/Sine Wave'
   *  Sum: '<Root>/Sum'
   */
  *rty_Out1 = (look2_binlx(rtP_TABLE_DIM_0, look1_binlx(sin((real_T)
    localDW->counter * 2.0 * 3.1415926535897931 / 100.0) * 5.0,
    LUTBpAndData_ptr->T1Break, LUTBpAndData_ptr->T1Data, 10U),
    LUTBpAndData_ptr->T2Break, LUTBpAndData_ptr->T2Break,
    LUTBpAndData_ptr->T2Data, rtCP_uDLookup_maxIndex, 3U) + rtP_SHIFT_VALUE) *
    -2.0;

  /* Update for Sin: '<Root>/Sine Wave' */
  localDW->counter++;
  if (localDW->counter == 100) {
    localDW->counter = 0;
  }

  /* End of Update for Sin: '<Root>/Sine Wave' */
}

See Also

| |

Topics