Generate Code for Variant Start and Variant End Blocks
This example shows how to generate code for a specific implementation of a component using Variant Start and Variant End blocks. You can customize your code to include a single or multiple implementations of the component. By placing these implementations between the Variant Start and Variant End blocks, you create a bounded region to switch between different implementations without altering the structure of the model. The elements outside the bounded region remain unconditional. This approach enables you to manage the design requirements for scenarios that need a defined area with variant conditions.
Prerequisites
Review the example Control Variant Condition Propagation using Variant Start and Variant End Blocks to learn more about how to use Variant Start and Variant End blocks in Simulink®.
Represent Variant Choices in Variant Start and Variant End Blocks
Open the slexVariantStartAndEnd
model, which represents a control system. The control system contains the first-order and second-order systems that are placed in the bounded regions defined by the Variant Start and End blocks. These blocks activate the first-order or the second-order system based on the variant condition that evaluates to true
during simulation. The blocks outside this region are unconditional and remain unaffected by the variant conditions.
model = "slexVariantStartAndEnd";
open_system(model)
Specify Variant Controls for Variant Choice Selection
Each variant choice in the model is associated with a variant control. Variant controls determine which variant choice is active. By changing the value of a variant control, you can switch the active variant choice. While each variant choice is associated with a variant control, only one variant control can evaluate to true
. When a variant control evaluates to true
, Simulink activates the variant choice that corresponds to that variant control. For more information, see Introduction to Variant Controls.
1. Right-click the variant badge on a variant block and select Block Parameters. In this example, variant choice of the variant blocks is associated with variant control variables systemOrder
, isFirstOrderSystemConnected
, and isSecondOrderSystemConnected
. The variables are scalar MATLAB® variables. They are defined and set to 2
, true
, and true
, respectively, in the PostLoadFcn
callback of the model.
During simulation, the variant conditions propagate within the bounded region. For example, the variant control expression systemOrder == 2
&& isSecondOrderSystemConnected == true
evaluates to true
, activating the second-order system placed between the Variant Start1
and Variant End1
blocks. For information on the variant conditions that activate the blocks, see Control Variant Condition Propagation using Variant Start and Variant End Blocks.
2. Set the value of systemOrder
to 1
. Simulate the model again. During simulation, systemOrder == 2
&& isFirstOrderSystemConnected == true
evaluates to true
, activating the first-order system placed between the Variant Start1
and Variant End1
blocks. This mechanism allows you to swap the active and inactive choices for the variant blocks without modifying the model structure, making the model flexible and adaptable to different scenarios. If scalar variables are not suitable for your requirements, you can use different types of variant controls as described in Compare Different Types of Variant Control Modes in Variant Blocks.
systemOrder = 1; sim(model);
Configure Model to Generate Code
By default, Simulink supports generating code only for a specific choice of a variant block. You can customize your model to generate code for multiple choices of the block using the Variant activation time parameter. The Variant activation time parameter enables you to set the active variant choice at intermediate stages to improve the speed of simulation and allows you to reuse the artifacts from the previous runs in code generation workflows. It also enables you to analyze variant choices for incompatibilities, such as data type and dimension mismatches, before simulation and code generation. For more information, see code compile.
To generate code for the second-order system placed between the Variant Start1
and Variant End1
blocks, check these settings:
The values of the variant control variable
systemOrder
is set to2
andisSecondOrderSystemConnected
is set totrue
The Variant activation time parameter of the blocks is set to
update diagram
.
From the Apps tab of the toolstrip, open the Simulink Coder or Embedded Coder app. In the C code tab, select Build > Generate code. Observe that the generated code includes the logic only for the active variant choice blocks. Alternatively, enter this command in the Command Window.
slbuild(model)
### Searching for referenced models in model 'slexVariantStartAndEnd'. ### Total of 1 models to build. ### Starting build procedure for: slexVariantStartAndEnd ### Successful completion of build procedure for: slexVariantStartAndEnd Build Summary Top model targets: Model Build Reason Status Build Duration ========================================================================================================================= slexVariantStartAndEnd Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 5.004s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 5.5177s
Review Generated Code
1. In the C Code tab of the toolstrip, select Open Report.
2. Locate and select the slexVariantStartAndEnd.c
file from the left pane. Observe that the calls to the step and initialization functions contain only the code for the active blocks, while the code for the inactive blocks is not included. The variables slexVariantStartAndEnd_Y.Out2
store the output of the second-order system. To generate code that includes the logic for active and inactive choices, allowing for conditional compilation based on specific choices, see Compile Code Conditionally for Variations of Component Represented Using Variant Block. For information on conditional execution of startup routines, see see Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.
cfile=fullfile(pwd, "slexVariantStartAndEnd_grt_rtw", "slexVariantStartAndEnd.c"); coder.example.extractLines(cfile, "/* Model step", "/* Derivatives for root system: '<Root>' */", 1, 0);
/* Model step function */ void slexVariantStartAndEnd_step(void) { if (rtmIsMajorTimeStep(slexVariantStartAndEnd_M)) { /* set solver stop time */ if (!(slexVariantStartAndEnd_M->Timing.clockTick0+1)) { rtsiSetSolverStopTime(&slexVariantStartAndEnd_M->solverInfo, ((slexVariantStartAndEnd_M->Timing.clockTickH0 + 1) * slexVariantStartAndEnd_M->Timing.stepSize0 * 4294967296.0)); } else { rtsiSetSolverStopTime(&slexVariantStartAndEnd_M->solverInfo, ((slexVariantStartAndEnd_M->Timing.clockTick0 + 1) * slexVariantStartAndEnd_M->Timing.stepSize0 + slexVariantStartAndEnd_M->Timing.clockTickH0 * slexVariantStartAndEnd_M->Timing.stepSize0 * 4294967296.0)); } } /* end MajorTimeStep */ /* Update absolute time of base rate at minor time step */ if (rtmIsMinorTimeStep(slexVariantStartAndEnd_M)) { slexVariantStartAndEnd_M->Timing.t[0] = rtsiGetT (&slexVariantStartAndEnd_M->solverInfo); } /* Gain: '<Root>/Gain3' incorporates: * TransferFcn: '<Root>/First Order System' */ slexVariantStartAndEnd_B.Gain3 = slexVariantStartAndEnd_P.FirstOrderSystem_C * slexVariantStartAndEnd_X.FirstOrderSystem_CSTATE * slexVariantStartAndEnd_P.Gain3_Gain; /* Gain: '<Root>/Gain2' incorporates: * Inport: '<Root>/In1' */ slexVariantStartAndEnd_B.Gain2 = slexVariantStartAndEnd_P.Gain2_Gain * slexVariantStartAndEnd_U.In1; /* Gain: '<Root>/Gain4' incorporates: * TransferFcn: '<Root>/First Order System1' */ slexVariantStartAndEnd_B.Gain4 = slexVariantStartAndEnd_P.FirstOrderSystem1_C * slexVariantStartAndEnd_X.FirstOrderSystem1_CSTATE * slexVariantStartAndEnd_P.Gain4_Gain; if (rtmIsMajorTimeStep(slexVariantStartAndEnd_M)) { /* Outport: '<Root>/Out1' incorporates: * ZeroOrderHold: '<Root>/Zero-Order Hold' */ slexVariantStartAndEnd_Y.Out1 = slexVariantStartAndEnd_B.Gain3; /* Outport: '<Root>/Out2' incorporates: * ZeroOrderHold: '<Root>/Zero-Order Hold1' */ slexVariantStartAndEnd_Y.Out2 = slexVariantStartAndEnd_B.Gain4; } /* Gain: '<Root>/Gain1' incorporates: * Inport: '<Root>/In2' */ slexVariantStartAndEnd_B.Gain1 = slexVariantStartAndEnd_P.Gain1_Gain * slexVariantStartAndEnd_U.In2; if (rtmIsMajorTimeStep(slexVariantStartAndEnd_M)) { rt_ertODEUpdateContinuousStates(&slexVariantStartAndEnd_M->solverInfo); /* Update absolute time for base rate */ /* The "clockTick0" counts the number of times the code of this task has * been executed. The absolute time is the multiplication of "clockTick0" * and "Timing.stepSize0". Size of "clockTick0" ensures timer will not * overflow during the application lifespan selected. * Timer of this task consists of two 32 bit unsigned integers. * The two integers represent the low bits Timing.clockTick0 and the high bits * Timing.clockTickH0. When the low bit overflows to 0, the high bits increment. */ if (!(++slexVariantStartAndEnd_M->Timing.clockTick0)) { ++slexVariantStartAndEnd_M->Timing.clockTickH0; } slexVariantStartAndEnd_M->Timing.t[0] = rtsiGetSolverStopTime (&slexVariantStartAndEnd_M->solverInfo); { /* Update absolute timer for sample time: [0.2s, 0.0s] */ /* The "clockTick1" counts the number of times the code of this task has * been executed. The resolution of this integer timer is 0.2, which is the step size * of the task. Size of "clockTick1" ensures timer will not overflow during the * application lifespan selected. * Timer of this task consists of two 32 bit unsigned integers. * The two integers represent the low bits Timing.clockTick1 and the high bits * Timing.clockTickH1. When the low bit overflows to 0, the high bits increment. */ slexVariantStartAndEnd_M->Timing.clockTick1++; if (!slexVariantStartAndEnd_M->Timing.clockTick1) { slexVariantStartAndEnd_M->Timing.clockTickH1++; } } } /* end MajorTimeStep */ }
See Also
Remove Inactive Variant Components from Generated Code at Compile Time When No Active Choices Exist