Generate Code for Variant Subsystem Blocks
This example explains how to generate code for a specific implementation of a component represented using a Variant Subsystem block. You can customize the code to include one or multiple implementations of the component.
The Variant Subsystem block, a hierarchical variant block, allows you to encapsulate multiple implementations, or variants, of a component in a model. Each variant of the component represented within a Variant Subsystem block is called a variant choice. Only one variant choice within the Variant Subsystem block can be active during simulation. You can generate code that includes one or multiple variant choices of the Variant Subsystem block. For more information, see Implement Variations in Separate Hierarchy Using Variant Subsystems.
Prerequisites
We recommend completing the Implement Variations in Separate Hierarchy Using Variant Subsystems example to learn more about how to use Variant Subsystems in Simulink.
Represent Variant Choices in Variant Subsystem Block
Open the slexVariantSubsystems
model.
The slexVariantSubsystems
model contains a Variant Subsystem block named Controller
. The Controller
block encapsulates two different implementations, Linear Controller
and Nonlinear Controller
, as variant choices.
model = "slexVariantSubsystems";
open_system(model);
To open the Controller
block and view its variant choices, double-click the block and then click the Up to Parent button located in the toolbar at the top of the Simulink® model canvas.
The Linear Controller
and Nonlinear Controller
variant choices have the same number of input ports and output ports as the containing Controller
block. The variant choices can have different numbers of input and output ports as described in Map Input and Output Ports of Variant Choices in Variant Subsystem.
For information on variant choices, see Working with Variant Choices.
open_system(model+"/Controller")
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 the 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 the Controller
block and select Block Parameters (Subsystem). In this example, the variant choices in the Controller
block are associated with the variant control variable V
. Here, V
is a scalar MATLAB variant control variable. You can specify V
as a different type of variant control variable based on your requirements. For example, if you intend to specify attributes, such as data type and storage class, to control the appearance and placement of variant control variables in the generated code, specify variant control variable V
as a Simulink.Parameter
object. For more information, see Types of Variant Control Variables (Operands) in Variant Blocks.
2. In the MATLAB™ Command Window, set the value of V
to 1
and simulate the model. During simulation, the variant control expression V == 1
evaluates to true
, activating the Linear Controller
block.
V = 1; sim(model);
3. Set the value of V
to 2
and simulate the model again. During simulation, the variant control expression V == 2
evaluates to true
, activating the Nonlinear Controller
block.
V = 2; sim(model);
This mechanism allows you to swap the active and inactive variant choices in the Controller
block without modifying the model structure, making it flexible and adaptable to different scenarios.
If
objects 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.Simulink.VariantExpression
Configure Model for Generating Code
By default, Simulink supports generating code only for a specific variant choice of a Variant Subsystem block. You can customize the model to generate code for multiple variant choices of the Variant Subsystem 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, prior to simulation and code generation. For more information, see Activate Variant During Different Stages of Simulation and Code Generation Workflow.
1. To generate code for the active variant choice Nonlinear Controller
block, check these settings:
The value of the variant control variable
V
is set to2
.
V = 2;
The Variant activation time parameter of the
Controller
block is set toupdate diagram
.
set_param("slexVariantSubsystems/Controller","VariantActivationTime", "update diagram");
2. In the Apps tab of the toolstrip, navigate to Simulink Coder or Embedded Coder. In the C code tab, select Build > Generate code. Observe that the generated code includes the logic only for the Nonlinear Controller
block. Alternatively, enter this command in the Command Window.
slbuild(model)
### Starting build procedure for: slexVariantSubsystems ### Successful completion of build procedure for: slexVariantSubsystems Build Summary Top model targets: Model Build Reason Status Build Duration ======================================================================================================================== slexVariantSubsystems Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 9.4735s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 10.204s
Review Generated Code
1. In the C Code tab, select Open Report.
2. Locate and select the slexVariantSubsystems.c
file from the left pane. Observe that the calls to the step and initialization functions exclusively contain the logic for the Nonlinear Controller
block, while the logic for the Linear Controller
block is not included.
To generate code that includes logic for both the Linear Controller
and Nonlinear Controller
blocks, allowing for conditional compilation based on specific variant choices, see Compile Code Conditionally for Variations of Component Represented Using Variant Block. To generate code that allows for conditional execution of startup routines based on specific variant choices, see Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.
Note
Empty variant choices within Variant Subsystem blocks appear as commented-out sections to exclude these choices from the code regardless of the value of the variant control variable during code generation. For more information, see Empty Variant Choice.
cfile=fullfile(pwd, 'slexVariantSubsystems_ert_rtw', 'slexVariantSubsystems.c'); coder.example.extractLines(cfile, '/* Model step', '/* Model initialize', 1, 0);
/* Model step function */ void slexVariantSubsystems_step(void) { real_T lastSin_tmp; /* Sin: '<Root>/sine1' */ if (slexVariantSubsystems_DW.systemEnable != 0) { lastSin_tmp = ((slexVariantSubsystems_M->Timing.clockTick0) * 0.01); slexVariantSubsystems_DW.lastSin = sin(1.0471975511965976 * lastSin_tmp); slexVariantSubsystems_DW.lastCos = cos(1.0471975511965976 * lastSin_tmp); slexVariantSubsystems_DW.systemEnable = 0; } /* Sin: '<Root>/sine2' */ if (slexVariantSubsystems_DW.systemEnable_e != 0) { lastSin_tmp = ((slexVariantSubsystems_M->Timing.clockTick0) * 0.01); slexVariantSubsystems_DW.lastSin_g = sin(lastSin_tmp); slexVariantSubsystems_DW.lastCos_n = cos(lastSin_tmp); slexVariantSubsystems_DW.systemEnable_e = 0; } /* Sin: '<Root>/sine3' */ if (slexVariantSubsystems_DW.systemEnable_b != 0) { lastSin_tmp = ((slexVariantSubsystems_M->Timing.clockTick0) * 0.01); slexVariantSubsystems_DW.lastSin_i = sin(0.52359877559829882 * lastSin_tmp); slexVariantSubsystems_DW.lastCos_i = cos(0.52359877559829882 * lastSin_tmp); slexVariantSubsystems_DW.systemEnable_b = 0; } /* Outputs for Atomic SubSystem: '<S1>/Nonlinear Controller' */ /* Outport: '<Root>/Out1' incorporates: * Lookup_n-D: '<S2>/1-D Lookup Table' * Sin: '<Root>/sine1' * Sin: '<Root>/sine2' * Sin: '<Root>/sine3' * Sum: '<S2>/Add' */ slexVariantSubsystems_Y.Out1 = (((slexVariantSubsystems_DW.lastSin * 0.99994516936551214 + slexVariantSubsystems_DW.lastCos * -0.010471784116245792) * 0.99994516936551214 + (slexVariantSubsystems_DW.lastCos * 0.99994516936551214 - slexVariantSubsystems_DW.lastSin * -0.010471784116245792) * 0.010471784116245792) * 0.1 + look1_binlxpw (((slexVariantSubsystems_DW.lastSin_g * 0.99995000041666526 + slexVariantSubsystems_DW.lastCos_n * -0.0099998333341666645) * 0.99995000041666526 + (slexVariantSubsystems_DW.lastCos_n * 0.99995000041666526 - slexVariantSubsystems_DW.lastSin_g * -0.0099998333341666645) * 0.0099998333341666645) * 2.0, slexVariantSubsystems_ConstP.uDLookupTable_bp01Data, slexVariantSubsystems_ConstP.uDLookupTable_tableData, 10U)) + ((slexVariantSubsystems_DW.lastSin_i * 0.99998629224742674 + slexVariantSubsystems_DW.lastCos_i * -0.00523596383141958) * 0.99998629224742674 + (slexVariantSubsystems_DW.lastCos_i * 0.99998629224742674 - slexVariantSubsystems_DW.lastSin_i * -0.00523596383141958) * 0.00523596383141958) * 0.3; /* End of Outputs for SubSystem: '<S1>/Nonlinear Controller' */ /* Update for Sin: '<Root>/sine1' */ lastSin_tmp = slexVariantSubsystems_DW.lastSin; slexVariantSubsystems_DW.lastSin = slexVariantSubsystems_DW.lastSin * 0.99994516936551214 + slexVariantSubsystems_DW.lastCos * 0.010471784116245792; slexVariantSubsystems_DW.lastCos = slexVariantSubsystems_DW.lastCos * 0.99994516936551214 - lastSin_tmp * 0.010471784116245792; /* Update for Sin: '<Root>/sine2' */ lastSin_tmp = slexVariantSubsystems_DW.lastSin_g; slexVariantSubsystems_DW.lastSin_g = slexVariantSubsystems_DW.lastSin_g * 0.99995000041666526 + slexVariantSubsystems_DW.lastCos_n * 0.0099998333341666645; slexVariantSubsystems_DW.lastCos_n = slexVariantSubsystems_DW.lastCos_n * 0.99995000041666526 - lastSin_tmp * 0.0099998333341666645; /* Update for Sin: '<Root>/sine3' */ lastSin_tmp = slexVariantSubsystems_DW.lastSin_i; slexVariantSubsystems_DW.lastSin_i = slexVariantSubsystems_DW.lastSin_i * 0.99998629224742674 + slexVariantSubsystems_DW.lastCos_i * 0.00523596383141958; slexVariantSubsystems_DW.lastCos_i = slexVariantSubsystems_DW.lastCos_i * 0.99998629224742674 - lastSin_tmp * 0.00523596383141958; /* Update absolute time for base rate */ /* The "clockTick0" counts the number of times the code of this task has * been executed. The resolution of this integer timer is 0.01, which is the step size * of the task. Size of "clockTick0" ensures timer will not overflow during the * application lifespan selected. */ slexVariantSubsystems_M->Timing.clockTick0++; }
Limitations
Generating code for Variant Subsystem blocks with mass matrices, outports with constant sample time, and Simscape™ blocks as variant choices is not supported.
See Also
Remove Inactive Variant Components from Generated Code at Compile Time When No Active Choices Exist