Options to Represent Variant Parameters in Generated Code
You can generate the code only for active values or for both active and inactive values of variant parameters in Simulink®. You can also represent the values of variant parameters as inline variables or as tunable variables in the generated code.
Note
For variant parameters associated with the startup
activation
time, you can generate code for both active and inactive choices by installing Simulink
Coder™ or Embedded Coder®.
For variant parameters associated with the code compile
activation time:
You must install Simulink Coder to generate code for only active values of variant parameters. Generating code using Simulink Coder is supported only if values of a variant parameter have same dimension.
You must install Embedded Coder to generate code for both active and inactive values of variant parameters. Generating code using Embedded Coder is supported for variant parameters values having same and different dimensions.
Overview of Variant Parameters
Variant parameters can have multiple values. Each value of the variant parameter is
associated with a variant condition expression. During simulation, the value of a variant
parameter associated with the condition that evaluates to true
is the
active value of the variant parameter. The value associated with the condition that
evaluates to false
is the inactive value of the variant parameter. When
you generate code, you can choose to include only the active value or both the active and
inactive values in the generated code. You can also choose to represent the values as inline
or as tunable variables in the generated code. For more information on variant parameters,
see Use Variant Parameters to Reuse Block Parameters with Different Values.
Choice of Values in Generated Code
Simulink supports generating code only for active values or for both active and inactive values of variant parameters. Values included in the code are based on the variant activation time you specify for the variant parameters. For more information, see Activate Variant During Different Stages of Simulation and Code Generation Workflow.
When you specify the variant activation time as:
'update diagram'
–– Simulink does not analyze the values of variant parameters for incompatibilities in signal attributes. It generates code only for the active values of variant parameters.'update diagram analyze all choices'
–– Simulink analyzes both active and inactive values of variant parameters for incompatibilities in signal attributes, however it generates code only for the active values of variant parameters.'code compile'
–– Simulink analyzes both active and inactive values of variant parameters for incompatibilities in signal attributes and it also generates code for both active and inactive values of the variant parameters. The values are enclosed in C preprocessor conditional statements#if
and#endif
that are conditionally compiled when you compile the generated code. If the variant parameter has a default value specified using the(default)
variant condition, the value is assigned in the#else
condition in the code.'startup'
––Simulink analyzes both active and inactive values of variant parameters for incompatibilities in signal attributes and it also generates code for both active and inactive values of the variant parameters. The values are enclosed in regularif
conditions inside themodel_initialize
function of the generated code that are conditionally evaluated when you run the executable that is built from the code. If the variant parameter has a default value specified using the(default)
variant condition, the value is assigned in theelse
condition in the code.
Types of Variables in Generated Code
Simulink supports representing the values of variant parameters as inline variables or as tunable variables in the generated code. The representation of values in the code are based on the storage class you specify for the variant parameters.
Inline variable: If you specify the storage class of a variant parameter as
Auto
, which is a default storage class, and the activation time asupdate diagram
orupdate diagram analyze all choices
, then the variant parameter is inlined to the literal numeric value of the parameter in the generated code. If you specify the storage class of a variant parameter asAuto
and the activation time ascode compile
, then the variant parameter is inlined as macros in the generated code. Inlined variables reduce global RAM usage and increase efficiency of the generated code. The code does not allocate memory to represent numeric block parameters, such as the Gain parameter of a Gain block. Instead, the code is inlined to the literal numeric value of the parameter.Tunable: If you specify the storage class of a variant parameter as anything other than
Auto
, then the variant parameter is represented using symbolic names in the generated code. For a list of built-in storage classes supported for different activation times, see Storage Classes for Different Variant Activation Times.
Storage Classes for Different Variant Activation Times
When you specify a condition expression to determine the active choice, each variant control variable of the expression has a storage class associated with it. Use storage classes to control the appearance and placement of the variant control variables in the generated code. Storage classes also prevent the optimizations such as elimination of the storage for variant control variables in the generated code. For more information, see Choose Storage Class for Controlling Data Representation in Generated Code.
The variables used in the variant condition expressions must satisfy these criteria to generate code with Simulink Coder or Embedded Coder.
The variant control variables in variant condition expressions must have these storage classes.
This table lists the built-in storage classes supported for different activation times to generate code using Simulink Coder and Embedded Coder.
Built-in Storage Class Variant activation time code compile
startup
ExportedGlobal x ✓ Model Default x ✓ ImportedExtern, ImportedExternPointer x ✓ Auto x x This table lists the custom storage classes supported for different activation times to generate code using Embedded Coder.
Custom Storage Class Variant activation time code compile
startup
GetSet (Embedded Coder) x ✓ Define, ImportedDefine (Embedded Coder) ✓ x CompilerFlag (Embedded Coder) ✓ x Const and ConstVolatile. See, Const, Volatile, and ConstVolatile (Embedded Coder) x x Bitfield (Embedded Coder) x ✓ Struct (Embedded Coder) x ✓ ExportToFile (Embedded Coder) x ✓ ImportFromFile (Embedded Coder) x ✓ Volatile. See, Const, Volatile, and ConstVolatile (Embedded Coder) x ✓
If the activation time of a variant control variable is set to
startup
, then specifying its storage class to any of these is not supported:Storage classes such as
Define
that generates macros in the code.Storage classes such as
Const
that generates constant qualified variables in the code.
If a variant parameter is part of a variant parameter bank (a
Simulink.VariantBank
object) and if the activation time of the corresponding variant control variable is set tostartup
, specifying storage class using theSpecification
property of theSimulink.VariantVariable
object is not supported. Use theSimulink.VariantBankCoderInfo
class instead.If the activation time of a variant control variable is set to
code compile
and if the values have different dimensions, then specifying its storage class such asDefine
that generates macros in the code is not supported.
Symbolic Dimensions in Generated Code
If a variant parameter has values with multiple dimensions, Simulink generates symbols to represent dimensions in the generated code. Representing dimensions as symbols enable the code to flexibly switch between dimension values for the given active choice without regenerating code every time you change the value of the variant control variable. For more information on symbolic dimensions in variant parameters, see Compile Code Conditionally for All Values of Variant Parameters with Same and Different Dimensions.
Group Variant Parameter Values in Generated Code
With Embedded Coder, you can use variant parameter banks to group variant parameters that have the
same set of variant conditions into a structure in the generated code. The code generator
supports variant parameter banks only for variant parameters with variant activation time
set to startup
.
The generated code contains an array of the variant parameter bank structure type. The
code generator groups all choice values of the variant parameters based on variant
conditions and each set of choice values becomes an element of the array. The code uses a
pointer variable to access the active set of values from the array. Parameter bank switching
using a pointer variable avoids copying the choice values into the main program memory and
improves the efficiency and readability of the generated code. See Simulink.VariantBank
.
Generate C Code for Variant Parameters
This example shows how to generate C code for variant parameters.
Explore the Model
Consider the slexVariantParameters
model. To open the model, use
the following
command.
openExample('simulink_variants/CreateASimpleVariantParameterModelExample');
The Gain parameters of the Gain1 and the
Gain2 blocks are variant parameters with their values set to
K1
and K2
, respectively. The variable
K1
has two values: 3.5
and 8.5
.
The variable K2
has two values: 4.5
and
9.5
.
Simulink chooses active values of K1
and K2
based on the value of the variant control variable V
. If
V==1
evaluates to true
, then the value of
K1
is set to 3.5
, and the value of
K2
is set to 8.5
. If V==2
evaluates to true
, then the value of K1
is set to
4.5
, and the value of K2
is set to
9.5
.
In this example, the variant activation time is set to update
diagram
, and the storage class is set as Auto
. When you
generate a code from this model, the code is generated only for the active values of
K1
and K2
. In the generated code, the values are
inlined to the literal value of the parameters.
Generate Inline and Tunable Code for Variant Parameters using Embedded Coder
Before you generate code from the model, you must have write permission in your current folder.
Prepare the model for code generation by specifying code generation settings in the Configuration Parameters dialog box. Choose the solver and code generation target, and check the model configuration for execution efficiency. For more details on each of these steps, see Generate Code Using Embedded Coder (Embedded Coder).
In the Apps gallery of the model toolstrip, click Simulink Coder.
On the C Code tab, click Build.
The code generator creates the folder
slexVariantParameters_ert_rtw
in your current working folder and places source code files in that folder. The generated code is in two primary files:slexVariantParameters.c
andslexParameters.h
. The fileslexVariantParameters.h
contains the value of the variant control variable, and the fileslexVariantParameters.c
contains the values of the variant parameters.In the C Code tab, select Open Report.
Select the
slexVariantParameters.c
file from the Generated Code pane of the report. The code is generated only for the active values of theK1
andK2
. In the generated code, the values are inlined to the literal value of the parameters.slexVariantParameters_Y.Out1 = 3.5 * slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = 4.5 * slexVariantParameters_U.In2;
In the model, change the activation time to
code compile
and the storage class toExportedGlobal
, then generate the code again. Observe the change in the style of the generated code.The code is generated only for all the active and inactive values of
K1
andK2
. In the generated code, the values are represented using symbolic names.This table shows the difference in the style of the generated code for storage classes
Auto
andExportedGlobal
with different activation times.Activation time Storage class Auto
(default)ExportedGlobal
update diagram
The code is generated only for the active values of the variant parameters. In the generated code, the values are inlined to the literal value of the parameters.
Consider this snippet of the generated code.
4.5
and3.5
are inline active values of the variant parameters Gain1 and Gain2.void slexVariantParameters_step(void) { slexVariantParameters_Y.Out1 = 3.5 * slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = 4.5 * slexVariantParameters_U.In2; }
The code is generated only for the active values of variant parameters. In the generated code, the values are represented using symbolic names.
Consider this snippet of the generated code. Here,
K1
andK2
are symbolic names for active values of variant parameters Gain1 and Gain2.real_T K1 = 3.5; real_T K2 = 4.5; … … void slexVariantParameters_step(void) { slexVariantParameters_Y.Out1 = K1 * slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = K2 * slexVariantParameters_U.In2; }
update diagram analyze all choices
The generated code is same as that of
update diagram
. The only difference is that the active and the inactive values of variant parameters are analyzed for consistency of signal attributes such as dimension and data type across the model.The generated code is same as that of
update diagram
. The only difference is that the active and the inactive values of variant parameters are analyzed for consistency of signal attributes such as dimension and data type across the model.code compile
The code is generated for all the active and inactive values of the variant parameters. All of the values are analyzed for consistency of signal attributes such as dimension and data type across the model. In the generated code, the values are inlined as macros and are enclosed in preprocessor conditionals
#if
and#elif
.Consider this snippet of the generated code. The active and inactive values are enclosed in C preprocessor conditional statements
#if
and#elif
.rtCP_Gain1_K1
andrtCP_Gain_K2
are the macros for variant parameters Gain1 and Gain2.#if V == 1 #define rtCP_Gain1_K1 (3.5) #elif V == 2 #define rtCP_Gain1_K1 (8.5) #endif #if V == 1 #define rtCP_Gain_K2 (4.5) #elif V == 2 #define rtCP_Gain_K2 (9.5) #endif void slexVariantParameters_step(void) { slexVariantParameters_Y.Out1 = rtCP_Gain_K1 * slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = rtCP_Gain1_K2 * slexVariantParameters_U.In2; }
The code is generated for all the active and inactive values of variant parameters. All of the values are analyzed for consistency of signal attributes such as dimension and data type across the model. In the generated code, the values are represented using symbolic names and are enclosed in preprocessor conditionals
#if
and#elif
.Consider this snippet of the generated code. The active and inactive values are enclosed in C preprocessor conditional statements
#if
and#elif
. Here,K1
andK2
are symbolic names for variant parameters Gain1 and Gain2.#if V == 1 real_T K1 = 3.5; real_T K2 = 4.5; #elif V == 2 real_T K1 = 8.5; real_T K2 = 9.5; #endif void slexVariantParameters_step(void) { slexVariantParameters_Y.Out1 = K1 * slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = K2 * slexVariantParameters_U.In2; )
startup
The code is generated for all the active and inactive values of the variant parameters. All of the values are analyzed for consistency of signal attributes such as dimension and data type across the model. In the generated code, the values are inlined as macros and are enclosed in regular
if
conditions.Consider this snippet of the generated code. The active and inactive values are enclosed in regular
if
condition statements inside themodel_initialize
function. Themodel_initialize
function also contains an assertion statement to check that at least one variant value is active while running the executable.slexVariantParameters_P.K1
andslexVariantParameters_P.K2
are the members of a structure for variant parameters Gain1 and Gain2.static void slexVaria_startupVariantChecker(void) { /* startup variant condition checks */ utAssert((V == 1) + (V == 2) == 1); } void slexVariantParameters_step(void) { slexVariantParameters_Y.Out1 = slexVariantParameters_P.K1 * ... slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = slexVariantParameters_P.K2 * ... slexVariantParameters_U.In2; } void slexVariantParameters_initialize(void) { if (V == 1) { slexVariantParameters_P.K1 = 3.5; slexVariantParameters_P.K2 = 4.5; } else if (V == 2) { slexVariantParameters_P.K1 = 8.5; slexVariantParameters_P.K2 = 9.5; } slexVaria_startupVariantChecker(); }
The code is generated for all the active and inactive values of variant parameters. All of the values are analyzed for consistency of signal attributes such as dimension and data type across the model. In the generated code, the values are represented using symbolic names and are enclosed in regular
if
conditions.Consider this snippet of the generated code. The active and inactive values are enclosed in regular
if
condition statements inside themodel_initialize
function. Themodel_initialize
function contains an assertion statement to check that at least one variant value is active. Here,K1
andK2
are symbolic names for variant parameters Gain1 and Gain2.static void slexVaria_startupVariantChecker(void) { /* startup variant condition checks */ utAssert((V == 1) + (V == 2) == 1); } void slexVariantParameters_step(void) { slexVariantParameters_Y.Out1 = K1 * slexVariantParameters_U.In1; slexVariantParameters_Y.Out2 = K2 * slexVariantParameters_U.In2; } void slexVariantParameters_initialize(void) { if (V == 1) { K1 = 3.5; K2 = 4.5; } else if (V == 2) { K1 = 8.5; K2 = 9.5; } slexVaria_startupVariantChecker(); }
See Also
Use Variant Parameters to Reuse Block Parameters with Different Values | Choose Storage Class for Controlling Data Representation in Generated Code