Main Content

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 Simulink.VariantExpression 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.

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 to 2.

V = 2;
  • The Variant activation time parameter of the Controller block is set to update 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