Compile Code Conditionally for All Values of Variant Parameters with Same and Different Dimensions
This example shows how to generate a C code that contains all the active and inactive values of variant parameters. The values are enclosed in preprocessor conditionals #if
and #elif
that enables you to compile the code conditionally based on the condition that evaluates to true
.
In this example, you will learn how to:
Use storage classes to control the appearance, placement, definition, and declaration of variant parameter variables in the generated code.
Use symbolic dimensions to propagate varying dimensions of variant parameters as symbols in the generated code. Representing dimensions as symbols enables 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.
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 the variant parameter associated with the condition that evaluates to true
is the active value of that parameter. The value associated with the condition that evaluates to false
is the inactive value of that variant parameter. For more information, see Use Variant Parameters to Reuse Block Parameters with Different Values.
In the generated code, the active and inactive values of the variant parameters are enclosed in C preprocessor conditionals #if
and #elif
. The preprocessor conditionals enable you to conditionally compile the code for a given active value. You generate the code only once. You can then choose the active choice of variant parameters by changing the value of the variant control variable before running the code. You do not need to regenerate the code for different variant parameter choices.
Representation of variant parameter variables: The values are represented as inline or tunable variables in the generated code. The representation is determined by the storage class that you specify for the variant parameters in the model. The variant parameters with default storage class
Auto
are represented as inline variables. The variant parameters with storage class other thanAuto
are represented as tunable variables in the generated code. For more information on how different storage classes are represented in the generated code, see Choose Storage Class for Controlling Data Representation in Generated Code.
Representation of variant parameter dimensions: If the values of a variant parameter have different dimensions, then the dimensions are represented as symbols. These symbols propagate throughout the model during simulation and then go into the generated code. To represent dimensions as symbols, you must set Modeling > Model Settings > Diagnostics > Advanced Parameters > Allow symbolic dimension specification to
on
. For more information on symbolic dimensions, see Allow symbolic dimension specification.
Prerequisite
Before you start this example, we recommend you complete Options to Represent Variant Parameters in Generated Code.
Explore the model
1. Open the model.
open_system('slexVariantParametersCC')
The model contains blocks that have variant parameters that are specified as Simulink.VariantVariable
objects. The objects are defined in the slexVariantParameterCCData.m
file.
Constant: The Constant parameters of the Constant blocks are variant parameters. The parameters are specified as variant variable objects
MAX_LIFT
andSLIDER_POS
.
Table data and Breakpoint sets: The Table data and Breakpoint sets of the n-D Lookup Table blocks are variant parameters. The parameters are specified as variant variable objects
T1Break1
,T1Data
,T2Break
, andT2Data
.
2. Open the slexVariantParameterData.m
. Observe these settings in the file:
In this file,
VCtrl
is theSimulink.VariantControl
object that determines the active value of the variant parameter objectsMAX_LIFT
,SLIDER_POS
,T1Break1
,T1Data
,T2Break
, andT2Data
. The value ofVCtrl
is set to1
, and its activation time is specified ascode compile
. During simulation, the conditionVCtrl==1
evaluates totrue
. All the values associated withVCtrl==1
become active, and the values associated withVCtrl==2
become inactive. When you generate a code from this model, all the active and inactive values are enclosed in preprocessor conditionals#if
and#elif
.
The variant parameter objects
MAX_LIFT
andSLIDER_POS
have scalar numeric values with a default storage classAuto
. When you generate the code, the values of the Constant parameters are inlined as macros. The variant parameter objectsT1Break1
,T1Data
,T2Break
, andT2Data
are ofSimulink.Parameter
type with storage class specified asExportedGlobal
. When you generate the code, the values are represented by symbolic names as tunable variables in the generated code.
The variant parameter objects
T1Break1
andT1Data
have values with different dimensions. When you generate the code, the dimensions of these parameters are represented as symbols.
Set Active Choice of Variant Parameters
1. On the Simulink® toolstrip, click Run. During simulation, VCtrl==1
evaluates to true
. All the values associated with VCtrl==1
are assigned to the corresponding variant variable objects and, subsequently, to the variant parameters that use these objects. For example, when VCtrl==1
evaluates to true
, the value of MAX_LIFT
is set to 10
. As the Constant parameter of the Constant1
block is set to MAX_LIFT
, the value of the Constant parameter is also set to 10
.
2. To change the active values, change the value of VCtrl
to 2
, then simulate the model again.
VCtrl.Value = 2;
During simulation, all the values associated with VCtrl==2
are assigned to the variant variable objects, and those values are then assigned to the variant parameters using those objects.
Generate Code Using Embedded Coder
To generate code for variant parameters that have values with different dimensions, use Embedded Coder.
Before you generate code from the model, make sure that 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.
Review Inline and Tunable Parameters in Generated Code
1. In the C Code tab, select Open Report.
2. Select the slexVariantParametersCC_types.h
file from the Generated Code pane of the report. This file defines the value of the variant control variable VCtrl
as 1
. The variant control variable determines the active value of variant parameters.
#ifndef VCtrl #define VCtrl 1 #endif
3. Select the slexVariantParametersCC_private.h
file. This file includes macros (#define
) corresponding to all the values of the variant parameters with default storage class Auto
. The active values of variant parameters MAX_LIFT
and SLIDER_POS
are enclosed in the C preprocessor conditional statement (#if
) on the macros rtCP_Constant_MAX_LIFT
and rtCP_Constant1_SLIDER_POS
.
Note: 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.
#if VCtrl == 1 || VCtrl == 2 /* Variable: MAX_LIFT * Referenced by: '<Root>/Constant' */ #if VCtrl == 1 #define rtCP_Constant_MAX_LIFT (10.0) #elif VCtrl == 2 #define rtCP_Constant_MAX_LIFT (20.0) #endif #endif
#if VCtrl == 1 || VCtrl == 2 /* Variable: SLIDER_POS * Referenced by: '<Root>/Constant1' */ #if VCtrl == 1 #define rtCP_Constant1_SLIDER_POS (0.0) #elif VCtrl == 2 #define rtCP_Constant1_SLIDER_POS (0.5) #endif #endif
4. Select the slexVariantParametersCC.h
file. This file includes symbolic names for all the values of the variant parameters with storage class set to ExportGlobal
. The variables are defined as extern
variables.
/* Exported Global Parameters #if VCtrl == 1 || VCtrl == 2 extern real_T T1Break[T1Break_dim0]; /* Variable: T1Break * Referenced by:'<Root>/1D Lookup' */ #endif
#if VCtrl == 1 || VCtrl == 2 extern real_T T1Data[T1Data_dim0]; /* Variable: T1Data * Referenced by:'<Root>/1D Lookup' */ #endif
#if VCtrl == 1 || VCtrl == 2 extern real_T T2Break[3]; /* Variable: T2Break * Referenced by:'<Root>/2D Lookup' */ #endif
#if VCtrl == 1 || VCtrl == 2 extern real_T T2Data[9]; /* Variable: T2Data * Referenced by:'<Root>/2D Lookup' */ #endif
5. Select the slexVariantParametersCC.c
file. All the values of variant parameters are enclosed in C preprocessor conditional statements #if
and #elif
. When you compile this code, Simulink evaluates the preprocessor conditionals and compiles the code only for the active values of variant parameters. You can then specify a different value for VCtrl
and recompile the same code for any other active values of variant parameters.
/* Exported block parameters */ #if VCtrl == 1
real_T T1Break[T1Break_dim0] = { -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 } ; /* Variable: T1Break * Referenced by: '<Root>/1D Lookup' */
real_T T1Data[T1Data_dim0] = { -0.99990920426259511, -0.999329299739067, -0.99505475368673046, -0.9640275800758169, -0.76159415595576485, 0.0, 0.76159415595576485, 0.9640275800758169, 0.99505475368673046, 0.999329299739067, 0.99990920426259511 } ; /* Variable: T1Data * Referenced by: '<Root>/1D Lookup' */
real_T T2Break[3] = { -10.0, 0.0, 10.0 } ; /* Variable: T2Break * Referenced by: '<Root>/2D Lookup' */
real_T T2Data[9] = { 4.0, 16.0, 10.0, 5.0, 19.0, 18.0, 6.0, 20.0, 23.0 } ; /* Variable: T2Data * Referenced by: '<Root>/2D Lookup' */
#elif VCtrl == 2
real_T T1Break[T1Break_dim0] = { -10.0, -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0,-2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 } ; /* Variable: T1Break * Referenced by: '<Root>/1D Lookup' */
real_T T1Data[T1Data_dim0] = { -0.99999999587769273, -0.999999969540041, -0.99999977492967584, -0.99999833694394469, -0.99998771165079559, -0.99990920426259511, -0.999329299739067, -0.99505475368673046, -0.9640275800758169, -0.76159415595576485, 0.0, 0.76159415595576485, 0.9640275800758169, 0.99505475368673046, 0.999329299739067, 0.99990920426259511, 0.99998771165079559, 0.99999833694394469, 0.99999977492967584, 0.999999969540041, 0.99999999587769273 } ; /* Variable: T1Data * Referenced by: '<Root>/1D Lookup' */
real_T T2Break[3] = { -20.0, 0.0, 20.0 }; /* Variable: T2Break * Referenced by: '<Root>/2D Lookup' */
real_T T2Data[9] = { 8.0, 32.0, 20.0, 10.0, 38.0, 36.0, 12.0, 40.0, 46.0 } ; /* Variable: T2Data * Referenced by: '<Root>/2D Lookup' */
#endif
In this file, calls to the step function of each variant are conditionally compiled. In the step function, the macros and symbol names of variant parameters are used to form the equation.
/* Model step function */
void slexVariantParameters_step(void) { slexVariantParametersCC_Y.Out1 = look2_binlx(rtCP_Constant_MAX_LIFT, look1_binlx(rtCP_Constant1_SLIDER_POS, T1Break, T1Data, T1Data_dim0 - 1U), T2Break, T2Break, T2Data, slexVariantParametersCC_ConstP.uDLookup_maxIndex, 3U) * -2.0 + 2.0 * slexVariantParametersCC_U.In1; }
Review Dimension Symbol in Generated Code
Select the slexVariantParametersCC.c
file from the Generated Code pane of the report. In this file, the dimensions of variant parameters T1Break
and T1Data
are represented as symbols T1Break_dim0
and T1Data_dim0
and are enclosed in C preprocessor conditional statements #if
and #elif
. When you compile this code, Simulink evaluates the preprocessor conditionals and preserves the code only for the active values of variant parameters. If you specify the value of VCtrl
as 1
, the condition VCtrl == 1
evaluates to true
, and the values enclosed in V == 1
becomes active during code compilation. You can then specify a different value for VCtrl
and recompile the same code for any other active values of T1Break
and T1Data
.