Main Content

Remove Inactive Variant Components from Generated Code at Compile Time When No Active Choices Exist

This example shows how to remove variant components from the generated code when no variant choices of a variant block are active.

When you select the Allow zero active variant controls parameter of a variant block, Simulink® propagates the variant conditions to all the blocks (including the always true or unconditional blocks) within a variant region. The propagated variant condition on a block is a combination of all the variant conditions from the connected variant blocks. If none of the variant choices evaluate to true, the consolidated variant condition evaluates to false. Simulink disconnects the blocks connected to the input and output ports of the variant block, thus completely removing the variant components during model compilation. When generating code, the code generator skips the compilation of these variant components thus removing the variant regions completely from the code.

Prerequisites

To learn more about how to use Variant Source and Variant Sink blocks, see Propagate Variant Conditions to Define Variant Regions Using Variant Source and Variant Sink Blocks.

Explore the Model

Open the slexVariantSourceAndSink model. The model contains two Variant Source blocks, Variant Source1 and Variant Source2, and a Variant Sink block.

model = "slexVariantSourceAndSink";
open_system(model);

Specify the variant control variables V and W as Simulink.Parameter objects. The objects can have any of the storage classes listed in Storage Classes for Different Variant Activation Times. Based on your requirement, you can specify V and W as different type of variant control variable as described in Types of Variant Control Variables (Operands) in Variant Blocks. The variant conditions that use these variant control variables determine the activation and deactivation of the blocks connected to the Variant Source and the Variant Sink blocks. For information related to the variant conditions, see Propagate Variant Conditions to Define Variant Regions Using Variant Source and Variant Sink Blocks.

V = Simulink.Parameter;
V.Value = 1;
V.DataType = "int32";
V.CoderInfo.StorageClass = "Custom";
V.CoderInfo.CustomStorageClass = "Define";
V.CoderInfo.CustomAttributes.HeaderFile = "macros.h";
W = Simulink.Parameter;
W.Value = 1;
W.DataType = "int32";
W.CoderInfo.StorageClass = "Custom";
W.CoderInfo.CustomStorageClass = "Define";
W.CoderInfo.CustomAttributes.HeaderFile = "macros.h";

Simulate Model with No Active Variant Choice

Select the Allow zero active variant controls parameter of the variant blocks, so that, the model simulates successfully even if the variant blocks have no active variant choice.

set_param(model+"/Variant Source1","AllowZeroVariantControls","on");
set_param(model+"/Variant Source2","AllowZeroVariantControls","on");
set_param(model+"/Variant Sink","AllowZeroVariantControls","on");

In the MATLAB™ Command Window, set the value of W to 3 and simulate the model. During simulation, Simulink propagates variant conditions to all connected blocks within the variant region, including the unconditional blocks Sine5 and Gain4. For example, if the Allow zero active variant controls parameter of the Variant Sink block is set to off, the Sine5 and Gain4 blocks are not subject to variant conditions and thus remain active regardless of the active variant choice of the Variant Sink block. However, if the Allow zero active variant controls parameter is set to on, Simulink propagates the variant conditions to these blocks as well. Blocks such as Sine6 continue to be unconditional as their entire paths do not belong to a variant region.

W.Value = 3;
sim(model);

Because the value of W is set to 3, the variant conditions W == 1 and W == 2 evaluate to false. Consequently, the variant condition W == 1 || W == 2, propagated to the Sine5 and Gain4 blocks, evaluates to false. The states of the blocks change as follows:

  • The input port of the Variant Sink block is deactivated. This leads the Sine5 and Gain4 blocks to become inactive. As a result, the Sine5 and Gain4 blocks are removed from simulation when the Variant Sink block is inactive.

  • Both output ports of the Variant Sink block become inactive, resulting in no active variant choice. As a result, the bottom input to the Sum block bottom becomes inactive, providing a ground (zero) input to the Sum block. Because the Sine6 block is unconditional, its output is available to the Sum block. Consequently, the Sum block is unconditional, allowing it to perform the summation using the unconditional input from the Sine6 block. The Out2 port is calculated as the sum of Sine6 and ground, preventing the generation of any random or invalid values for Out2.

Guard Variant Regions in #if Conditionals for Complete Removal of Variant Components

When you generate code with the Allow zero active variant controls parameter of the Variant Sink block set to on, the code generator guards the blocks of the variant region with an additional variant condition by using #if preprocessor conditional statements. The variant condition is a combination of conditions from the connected variant blocks. These additional variant conditions enable you to completely remove the variant region from the code when none of the variant choices are active.

To generate code with preprocessor conditionals #if and elif, you must have an using Embedded Coder® license.

1. Specify the Variant activation time parameter of the variant blocks to code compile.

set_param(model+"/Variant Source1","VariantActivationTime","code compile");
set_param(model+"/Variant Source2","VariantActivationTime","code compile");
set_param(model+"/Variant Sink","VariantActivationTime","code compile");

2. Specify the system target configuration file as ert.tlc.

set_param(model,"SystemTargetFile","ert.tlc");

In the Apps tab of the toolstrip, navigate to Embedded Coder.

3. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window:

slbuild(model);
### Starting build procedure for: slexVariantSourceAndSink
### Successful completion of build procedure for: slexVariantSourceAndSink

Build Summary

Top model targets:

Model                     Build Reason                                         Status                        Build Duration
===========================================================================================================================
slexVariantSourceAndSink  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 10.612s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 11.569s

4. In the C Code tab, select Open Report.

5. Locate and select the slexVariantSourceAndSink.c file from the left pane. In the generated code, the Gain4 and Sine5 blocks connected to the Variant Sink block are enclosed in an additional preprocessor conditional W == 1 || W == 2, thus enabling complete removal of the blocks when the Variant Sink block is inactive. For more information on conditional compilation of variant choices, see Compile Code Conditionally for Variations of Component Represented Using Variant Block.

cfile=fullfile(pwd, "slexVariantSourceAndSink_ert_rtw", "slexVariantSourceAndSink.c");
coder.example.extractLines(cfile, "/* Model step", "/* Model initialize", 1, 0);
/* Model step function */
void step(void)
{

#if (V == 1) || (V == 2)

  real_T rtb_Sine6;

#endif

#if (V == 2) || (W == 1) || (W == 2)

  real_T rtb_Gain5;

#endif

#if (W == 1) || (W == 2)

  real_T rtb_Gain4;

#endif

  real_T rtb_VM_Conditional_Signal_Sum_1;

  /* Sin: '<Root>/Sine1' incorporates:
   *  Sin: '<Root>/Sine2'
   */
#if V == 1

  rtb_Sine6 = sin(((real_T)slexVariantSourceAndSink_DW.counter +
                   slexVariantSourceAndSink_P.Sine1_Offset) * 2.0 *
                  3.1415926535897931 / slexVariantSourceAndSink_P.Sine1_NumSamp)
    * slexVariantSourceAndSink_P.Sine1_Amp +
    slexVariantSourceAndSink_P.Sine1_Bias;

#elif V == 2

  /* Sin: '<Root>/Sine2' */
  rtb_Gain5 = sin(((real_T)slexVariantSourceAndSink_DW.counter_i +
                   slexVariantSourceAndSink_P.Sine2_Offset) * 2.0 *
                  3.1415926535897931 / slexVariantSourceAndSink_P.Sine2_NumSamp)
    * slexVariantSourceAndSink_P.Sine2_Amp +
    slexVariantSourceAndSink_P.Sine2_Bias;

#endif

  /* End of Sin: '<Root>/Sine1' */

  /* Sin: '<Root>/Sine3' incorporates:
   *  SignalConversion generated from: '<Root>/Add1'
   */
#if (V == 2) && (W == 1)

  /* VariantMerge generated from: '<Root>/Add1' incorporates:
   *  Sin: '<Root>/Sine3'
   */
  slexVariantSourceAndSink_B.VM_Conditional_Signal_Add1_1 = sin(((real_T)
    slexVariantSourceAndSink_DW.counter_f +
    slexVariantSourceAndSink_P.Sine3_Offset) * 2.0 * 3.1415926535897931 /
    slexVariantSourceAndSink_P.Sine3_NumSamp) *
    slexVariantSourceAndSink_P.Sine3_Amp + slexVariantSourceAndSink_P.Sine3_Bias;

#elif (V == 2) && (W != 1)

  /* VariantMerge generated from: '<Root>/Add1' incorporates:
   *  SignalConversion generated from: '<Root>/Add1'
   */
  slexVariantSourceAndSink_B.VM_Conditional_Signal_Add1_1 = 0.0;

#endif

  /* End of Sin: '<Root>/Sine3' */

  /* Sum: '<Root>/Add1' */
#if V == 2

  rtb_Sine6 = rtb_Gain5 +
    slexVariantSourceAndSink_B.VM_Conditional_Signal_Add1_1;

#endif

  /* End of Sum: '<Root>/Add1' */

  /* Gain: '<Root>/Gain3' incorporates:
   *  Outport: '<Root>/Out1'
   */
#if (V == 1) || (V == 2)

  slexVariantSourceAndSink_Y.Out1 = slexVariantSourceAndSink_P.Gain3_Gain *
    rtb_Sine6;

#endif

  /* End of Gain: '<Root>/Gain3' */

  /* Sin: '<Root>/Sine5' incorporates:
   *  Gain: '<Root>/Gain4'
   */
#if (W == 1) || (W == 2)

  rtb_Gain5 = sin(((real_T)slexVariantSourceAndSink_DW.counter_d +
                   slexVariantSourceAndSink_P.Sine5_Offset) * 2.0 *
                  3.1415926535897931 / slexVariantSourceAndSink_P.Sine5_NumSamp)
    * slexVariantSourceAndSink_P.Sine5_Amp +
    slexVariantSourceAndSink_P.Sine5_Bias;
  rtb_Gain4 = slexVariantSourceAndSink_P.Gain4_Gain * rtb_Gain5;

#endif

  /* End of Sin: '<Root>/Sine5' */

  /* Gain: '<Root>/Gain5' incorporates:
   *  SignalConversion generated from: '<Root>/Sum'
   * */
#if W == 1

  rtb_Gain5 = slexVariantSourceAndSink_P.Gain5_Gain * rtb_Gain4;
  rtb_VM_Conditional_Signal_Sum_1 = rtb_Gain5;

#else

  /* SignalConversion generated from: '<Root>/Sum' */
  rtb_VM_Conditional_Signal_Sum_1 = 0.0;

#endif

  /* End of Gain: '<Root>/Gain5' */

  /* Outport: '<Root>/Out2' incorporates:
   *  Sin: '<Root>/Sine6'
   *  Sum: '<Root>/Sum'
   */
  slexVariantSourceAndSink_Y.Out2 = (sin(((real_T)
    slexVariantSourceAndSink_DW.counter_g +
    slexVariantSourceAndSink_P.Sine6_Offset) * 2.0 * 3.1415926535897931 /
    slexVariantSourceAndSink_P.Sine6_NumSamp) *
    slexVariantSourceAndSink_P.Sine6_Amp + slexVariantSourceAndSink_P.Sine6_Bias)
    + rtb_VM_Conditional_Signal_Sum_1;

  /* Outport: '<Root>/Out3' */
#if W == 1

  slexVariantSourceAndSink_Y.Out3 = rtb_Gain5;

#endif

  /* End of Outport: '<Root>/Out3' */

  /* Update for Sin: '<Root>/Sine1' incorporates:
   *  Sin: '<Root>/Sine2'
   */
#if V == 1

  slexVariantSourceAndSink_DW.counter++;
  if (slexVariantSourceAndSink_DW.counter ==
      slexVariantSourceAndSink_P.Sine1_NumSamp) {
    slexVariantSourceAndSink_DW.counter = 0;
  }

#elif V == 2

  /* Update for Sin: '<Root>/Sine2' */
  slexVariantSourceAndSink_DW.counter_i++;
  if (slexVariantSourceAndSink_DW.counter_i ==
      slexVariantSourceAndSink_P.Sine2_NumSamp) {
    slexVariantSourceAndSink_DW.counter_i = 0;
  }

#endif

  /* End of Update for Sin: '<Root>/Sine1' */

  /* Update for Sin: '<Root>/Sine3' */
#if (V == 2) && (W == 1)

  slexVariantSourceAndSink_DW.counter_f++;
  if (slexVariantSourceAndSink_DW.counter_f ==
      slexVariantSourceAndSink_P.Sine3_NumSamp) {
    slexVariantSourceAndSink_DW.counter_f = 0;
  }

#endif

  /* End of Update for Sin: '<Root>/Sine3' */

  /* Update for Sin: '<Root>/Sine6' */
  slexVariantSourceAndSink_DW.counter_g++;
  if (slexVariantSourceAndSink_DW.counter_g ==
      slexVariantSourceAndSink_P.Sine6_NumSamp) {
    slexVariantSourceAndSink_DW.counter_g = 0;
  }

  /* End of Update for Sin: '<Root>/Sine6' */

  /* Update for Sin: '<Root>/Sine5' */
#if (W == 1) || (W == 2)

  slexVariantSourceAndSink_DW.counter_d++;
  if (slexVariantSourceAndSink_DW.counter_d ==
      slexVariantSourceAndSink_P.Sine5_NumSamp) {
    slexVariantSourceAndSink_DW.counter_d = 0;
  }

#endif

  /* End of Update for Sin: '<Root>/Sine5' */
}

When you set the activation time of the variant block to the startup activation time, the variant blocks are executed conditionally at startup routines depending on the specific variant choices. The blocks are not removed from the code. For more information, see Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.

Note

If your model has a Variant Subsystem block with the unconnected (inactive) output ports, the block outputs a ground (zero) value. To output a value other than ground, select the Specify output when source is unconnected parameter of the Outport block and specify a value.

Related Topics