Main Content

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 than Auto 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 (Simulink Coder).

  • 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_LIFT and SLIDER_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, and T2Data.

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

  • In this file, VCtrl is the Simulink.VariantControl object that determines the active value of the variant parameter objects MAX_LIFT, SLIDER_POS, T1Break1, T1Data, T2Break, and T2Data. The value of VCtrl is set to 1, and its activation time is specified as code compile. During simulation, the condition VCtrl==1 evaluates to true. All the values associated with VCtrl==1 become active, and the values associated with VCtrl==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 and SLIDER_POS have scalar numeric values with a default storage class Auto. When you generate the code, the values of the Constant parameters are inlined as macros. The variant parameter objects T1Break1, T1Data, T2Break, and T2Data are of Simulink.Parameter type with storage class specified as ExportedGlobal. When you generate the code, the values are represented by symbolic names as tunable variables in the generated code.

  • The variant parameter objects T1Break1 and T1Data 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 (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.

See Also