Main Content

Group Variant Parameter Values and Conditionally Switch Active Value Sets in Generated Code

This example shows how to group variant parameters with the same variant conditions into a structure in the generated code. You will learn to:

  • Use variant parameter banks to group variant parameters with startup activation time in code generated by Embedded Coder®.

  • Specify code generation properties for variant parameter banks.

Overview of Variant Parameters

Variant parameters enable you to conditionally vary the values of block parameters in a Simulink® model. Use the Simulink.VariantVariable class to create a variant parameter object. A variant parameter object defines a set of values, referred to as choices, and variant condition expressions associated with each choice. During simulation, the choice associated with the variant condition that evaluates to true becomes the active value of the variant parameter.

To specify the variant conditions for a variant parameter, use a variant control variable of type Simulink.VariantControl. The Simulink.VariantControl object allows you to specify a variant activation time for the variant parameter. For example, in this MATLAB® code, VCtrl is a variant control with startup activation time. The variant parameter TABLE_DIM_0 has two choices, 10 and 20. For each choice, a variant condition is specified using VCtrl.

VCtrl = Simulink.VariantControl('Value',1,'ActivationTime','startup');
TABLE_DIM_0 = Simulink.VariantVariable('Choices',{'VCtrl == 1',10,'VCtrl == 2',20});

The representation of variant parameters in the generated code depends on the ActivationTime of Simulink.VariantControl and the Specification property of the Simulink.VariantVariable object. Based on the variant activation time, Simulink determines whether to include only the active choice or both the active and inactive choices of the variant parameter in the code. The Specification property allows you to specify properties such as data type, dimensions, and storage class applicable to all the choices.

For more information on variant activation times, see Activate Variant During Different Stages of Simulation and Code Generation Workflow. For information on variant parameter code generation, see Options to Represent Variant Parameters in Generated Code (Embedded Coder).

Overview of Variant Parameter Banks

When you generate code for variant parameters with startup activation time, the values of variant parameters are enclosed in if and else if statements in the model_initialize function. This involves reading and copying all parameter values into the program memory. Also, when you define a custom storage class to define the variant parameter values in a separate definition file, only the active values of the parameters are present in the definition file. To improve the efficiency and readability of the generated code for variant parameters with startup activation time, you can use variant parameter banks.

Parameter banks help you to:

  • Group variant parameter values with the same variant conditions into a structure array.

  • Use a pointer switching mechanism to switch the set of active parameter values in the code based on variant conditions.

  • Customize code placement and specify the memory section to place the parameter values in the compiled code.

A variant parameter bank is an object of type Simulink.VariantBank. To add a variant parameter to a variant parameter bank, set the Bank property of the Simulink.VariantVariable object to the name of the Simulink.VariantBank object. When you generate code, Simulink.VariantVariable objects that share the same Bank property become part of the same structure in the code.

You must specify a list of variant conditions for a parameter bank. These conditions must match the variant conditions of the variant parameters in this parameter bank, except any default variant choice specified for the variant parameters using the (default) keyword. For example, this MATLAB code creates a variant parameter bank.

LUTBank = Simulink.VariantBank(Name='LUTBpAndData',...
    Description='Lookup table breakpoint and data',...
    VariantConditions={'VCtrl == 1','VCtrl == 2'});

Note: Specifying storage class using the Specification property is not supported if the Simulink.VariantVariable object is part of a variant parameter bank.

Explore Example Model

1. Open the model slexVariantParameterBank.

model = "slexVariantParameterBank";
open_system(model);

The slexVariantParameterBank model contains blocks that use variant parameters. The variant parameters are defined as Simulink.VariantVariable objects in the slexVariantParameterBankData.m file.

  • 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.

2. Open the file slexVariantParameterBankData.m. Observe these settings in the file:

  • 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. 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, and T2Data. Hence, LUTBank has the same set of variant conditions as these variant parameter objects. The BankCoderInfo property of this variant parameter bank object is set to LUTBankCoderInfo.

  • LUTBankCoderInfo is a Simulink.VariantBankCoderInfo object. The object is used to specify code generation properties such as the header file, definition file, and #pragma directives for the variant parameter bank LUTBank.

  • The Bank property of the variant parameter objects T1Break, T1Data, T2Break, and T2Data is set to LUTBank.

Generate Code Using Embedded Coder

To generate code that uses variant parameter bank switching, use Embedded Coder.

Before you generate code from the model, check whether you have write permission in your current folder. To generate code, in the Apps gallery of the model toolstrip, click Embedded Coder. On the C Code tab, click Build. For more information, see Generate Code Using Embedded Coder (Embedded Coder).

Review Generated Code

1. In the C Code tab, select Open Report. The header and definition files are named according to the properties of the object LUTBankCoderInfo.

2. Select the header file slexVariantParameterBank_lut_params.h from the Code section of the report. The file contains the type definition and data declarations of the variant parameter bank.

The variant parameters that are part of the parameter bank LUTBank are grouped in the same structure. This structure is named LUTBpAndData, according to the Name property of the object LUTBank.

typedef struct {
real_T T1Break[11];
real_T T1Data[11];
real_T T2Break[3];
real_T T2Data[9];
} LUTBpAndData;

A structure array of type LUTBpAndData is declared. The number of elements in the array depends on the number of variant conditions in the VariantConditions property of the parameter bank object LUTBank. A pointer LUTBpAndData_ptr of structure type LUTBpAndData is declared. These statements are guarded with the code specified in the PreStatement and PostStatement properties of the LUTBankCoderInfo object.

#pragma data_seg(.mydata)
extern LUTBpAndData LUTBpAndData_ptr_impl[2];
extern LUTBpAndData *LUTBpAndData_ptr;
#pragma end

3. Select the definition file slexVariantParameterBank_lut_params.c. The file contains the definition of the structure array and the pointer variable.

The LUTBpAndData_ptr_impl array contains the choices of the variant parameters, grouped by the variant conditions specified for the parameter bank. The pointer variable LUTBpAndData_ptr holds the reference to the active element of the structure array.

#pragma data_seg(.mydata)
LUTBpAndData LUTBpAndData_ptr_impl[2] = {
  {
    /* Variable: T1Break
     * Referenced by: '<Root>/1D Lookup'
     */
    { -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 },
    /* Variable: T1Data
     * Referenced by: '<Root>/1D Lookup'
     */
    { -0.99990920426259511, -0.999329299739067, -0.99505475368673046,
      -0.9640275800758169, -0.76159415595576485, 0.0, 0.76159415595576485,
      0.9640275800758169, 0.99505475368673046, 0.999329299739067,
      0.99990920426259511 },
    /* Variable: T2Break
     * Referenced by: '<Root>/2D Lookup'
     */
    { -10.0, 0.0, 10.0 },
    /* Variable: T2Data
     * Referenced by: '<Root>/2D Lookup'
     */
    { 4.0, 16.0, 10.0, 5.0, 19.0, 18.0, 6.0, 20.0, 23.0 }
  }, {
    /* Variable: T1Break
     * Referenced by: '<Root>/1D Lookup'
     */
    { -10.0, -8.0, -6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0 },
    /* Variable: T1Data
     * Referenced by: '<Root>/1D Lookup'
     */
    { -74.203210577788752, -27.28991719712775, -10.017874927409903,
      -3.626860407847019, -1.1752011936438014, 0.0, 1.1752011936438014,
      3.626860407847019, 10.017874927409903, 27.28991719712775,
      74.203210577788752 },
    /* Variable: T2Break
     * Referenced by: '<Root>/2D Lookup'
     */
    { -20.0, 0.0, 20.0 },
    /* Variable: T2Data
     * Referenced by: '<Root>/2D Lookup'
     */
    { 6.0, 16.0, 12.0, 7.0, 19.0, 16.0, 8.0, 20.0, 20.0 }
  }
};
LUTBpAndData *LUTBpAndData_ptr = &LUTBpAndData_ptr_impl[0];
#pragma end

4. Select the slexVariantParameterBank.c file. The model_initialize function contains the code to switch the active variant choice based on variant conditions. For variant parameters that are part of a parameter bank, the pointer variable is used to access the active value set from the structure array based on variant conditions.

if (VCtrl == 1) {
  LUTBpAndData_ptr = &LUTBpAndData_ptr_impl[0U];
} else if (VCtrl == 2) {
  LUTBpAndData_ptr = &LUTBpAndData_ptr_impl[1U];
}

See Also

| |

Related Topics