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
Autoare represented as inline variables. The variant parameters with storage class other thanAutoare 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 (Embedded Coder).
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_LIFTandSLIDER_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,
VCtrlis theSimulink.VariantControlobject that determines the active value of the variant parameter objectsMAX_LIFT,SLIDER_POS,T1Break1,T1Data,T2Break, andT2Data. The value ofVCtrlis set to1, and its activation time is specified ascode compile. During simulation, the conditionVCtrl==1evaluates totrue. All the values associated withVCtrl==1become active, and the values associated withVCtrl==2become inactive. When you generate a code from this model, all the active and inactive values are enclosed in preprocessor conditionals#ifand#elif.
The variant parameter objects
MAX_LIFTandSLIDER_POShave 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, andT2Dataare ofSimulink.Parametertype 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
T1Break1andT1Datahave 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 (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'
*/
#endif5. 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.