Main Content

Represent Variant Source and Sink Blocks in Generated Code

You can use Variant Source and Variant Sink blocks to perceive multiple implementations of a model in a single, unified block diagram. Each implementation depends on conditions that you set for Variant Source and Variant Sink blocks. Simulink® propagates these conditions to upstream and downstream blocks including root input and root output ports.

You can generate:

  • Code from a Simulink model containing Variant Sink and Variant Source blocks.

  • Code that contains preprocessor conditionals that control the activation of each variant choice.

  • Preprocessor conditionals that allow for no active variant choice.

Represent Variant Source and Variant Sink Blocks in Simulink

This example shows how Variant Source blocks make model elements conditional.

  1. From the Simulink Block Library, add 1 Sine Wave Function block, two Add blocks, three Gain blocks, two Outports, and two Variant Source blocks into a new model.

  2. Open the Sine Wave Function block. For the Sine type parameter, select Sample based. For the Time (t) parameter, select Use simulation time. For the Sample time parameter, insert a value of 0.2.

  3. Make four copies of the Sine Wave Function block.

  4. Connect and name the blocks as shown.

  5. Insert values of 2, 3, and 4 in the Gain2, Gain3, and Gain4 blocks, respectively.

  6. Give the model the name inline_variants_example.

  7. Open the Block Parameters dialog box for Variant Source.

  8. In the Variant control column, for Port 1, replace Choice_1 with V==1. For Port 2, replace Choice_2 with V==2.

  9. Open the Block Parameters dialog box for Variant Source1.

  10. In the Variant control column, replace Choice_1 with W==1. For Port 2, replace Choice_2 with W==2.

  11. In the MATLAB Command Window, use these commands to define V and W as Simulink.Parameter objects.

    V = Simulink.Parameter;
    V.Value = 1;
    V.DataType='int32';
    V.CoderInfo.StorageClass = 'custom';
    V.CoderInfo.CustomStorageClass = 'Define';
    V.CoderInfo.CustomAttributes.HeaderFile='inline_importedmacro.h'
    
    W = Simulink.Parameter;
    W.Value = 2;
    W.DataType='int32';
    W.CoderInfo.StorageClass = 'custom';
    W.CoderInfo.CustomStorageClass = 'Define';
    W.CoderInfo.CustomAttributes.HeaderFile='inline_importedmacro.h'

    In this example, the variant control variables are Simulink.Parameter objects. For code generation, if you use Simulink.Variant objects to specify variant controls, use Simulink.Parameter objects or MATLAB variables to specify their conditions. .

    Variant control variables defined as Simulink.Parameter objects can have one of these storage classes:

    • Define with header file specified

    • ImportedDefine with header file specified

    • CompilerFlag

    • SystemConstant (AUTOSAR)

    • User-defined custom storage class that defines data as a macro in a specified header file

    If you use scalar variant control variables to simulate the model, you can convert those variables into Simulink.Parameter objects. See Convert Variant Control Variables into Simulink.Parameter Objects.

  12. Simulate the model.

    Input port 1 is the active choice for Variant Source because the value of variant control variable V is 1. Input port 2 is the active choice for Variant Source1 because the value of variant control variable W is 2. The inactive choices are removed from execution, and their paths are grayed-out in the diagram.

Specify Conditions That Control Variant Choice Selection

You can generate code in which each variant choice is enclosed within C preprocessor conditionals #if and #endif. The compiler chooses the active variant at compile time and the preprocessor conditionals determine which sections of the code to execute.

  1. In the Modeling tab of the Simulink toolstrip, click Model Settings.

  2. On the Code Generation pane, and set System target file to ert.tlc.

  3. On the Solver pane, set the Type parameter to Fixed-step.

  4. In your model, open the block parameters dialog box for Variant Source.

  5. Set the Variant activation time parameter to code compile. During an update diagram or simulation, when you set this parameter value, Simulink analyzes all variant choices. This analysis provides early validation of the code generation readiness of variant choices. During code generation, when you set this parameter value, the code generator generates preprocessor conditionals that control the activation of each variant choice.

  6. Clear the Allow zero active variant controls parameter.

  7. Open the Block Parameters dialog box for Variant Source 1. Repeat steps 5 through 7.

  8. Build the model. When code generation is complete, the generated code is displayed in the Code view.

Review the Generated Code

  1. In the Code view, select the inline_variants_example.c file.

  2. In the inline_variants_example.c file, the call to the inline_variants_example_step function is conditionally compiled as shown:

    /* Model step function */
    void inline_variants_example_step(void)
    {
      real_T rtb_VariantMerge_For_Variant_So;
      real_T rtb_VariantMerge_For_Variant__e;
    
      /* Sin: '<Root>/Sine2' incorporates:
       *  Sin: '<Root>/Sine3'
       *  Sum: '<Root>/Add'
       */
    #if V == 2
    
      rtb_VariantMerge_For_Variant_So = sin((real_T)
        inline_variants_example_DW.counter * 2.0 * 3.1415926535897931 / 10.0) + sin
        ((real_T)inline_variants_example_DW.counter_g * 2.0 * 3.1415926535897931 /
         10.0);
    
    #endif
    
      /* End of Sin: '<Root>/Sine2' */
    
      /* Sin: '<Root>/Sine4' incorporates:
       *  Sin: '<Root>/Sine5'
       *  Sum: '<Root>/Add1'
       */
    #if W == 2
    
      rtb_VariantMerge_For_Variant__e = sin((real_T)
        inline_variants_example_DW.counter_c * 2.0 * 3.1415926535897931 / 10.0) +
        sin((real_T)inline_variants_example_DW.counter_i * 2.0 * 3.1415926535897931 /
            10.0);
    
    #endif
    
      /* End of Sin: '<Root>/Sine4' */
    
      /* Sin: '<Root>/Sine1' */
    #if V == 1
    
      rtb_VariantMerge_For_Variant_So = sin((real_T)
        inline_variants_example_DW.counter_m * 2.0 * 3.1415926535897931 / 10.0);
    
    #endif
    
      /* End of Sin: '<Root>/Sine1' */
    
      /* Outport: '<Root>/Outport' incorporates:
       *  Gain: '<Root>/Gain1'
       */
      inline_variants_example_Y.Outport = 3.0 * rtb_VariantMerge_For_Variant_So;
    
      /* Gain: '<Root>/Gain' */
    #if W == 1
    
      rtb_VariantMerge_For_Variant__e = 2.0 * rtb_VariantMerge_For_Variant_So;
    
    #endif
    
      /* End of Gain: '<Root>/Gain' */
    
      /* Outport: '<Root>/Outport1' incorporates:
       *  Gain: '<Root>/Gain2'
       */
      inline_variants_example_Y.Outport1 = 4.0 * rtb_VariantMerge_For_Variant__e;
    
      /* Update for Sin: '<Root>/Sine2' incorporates:
       *  Sin: '<Root>/Sine3'
       */
    #if V == 2
    
      inline_variants_example_DW.counter++;
      if (inline_variants_example_DW.counter == 10) {
        inline_variants_example_DW.counter = 0;
      }
    
      inline_variants_example_DW.counter_g++;
      if (inline_variants_example_DW.counter_g == 10) {
        inline_variants_example_DW.counter_g = 0;
      }
    
    #endif
    
      /* End of Update for Sin: '<Root>/Sine2' */
    
      /* Update for Sin: '<Root>/Sine4' incorporates:
       *  Sin: '<Root>/Sine5'
       */
    #if W == 2
    
      inline_variants_example_DW.counter_c++;
      if (inline_variants_example_DW.counter_c == 10) {
        inline_variants_example_DW.counter_c = 0;
      }
    
      inline_variants_example_DW.counter_i++;
      if (inline_variants_example_DW.counter_i == 10) {
        inline_variants_example_DW.counter_i = 0;
      }
    
    #endif
    
      /* End of Update for Sin: '<Root>/Sine4' */
    
      /* Update for Sin: '<Root>/Sine1' */
    #if V == 1
    
      inline_variants_example_DW.counter_m++;
      if (inline_variants_example_DW.counter_m == 10) {
        inline_variants_example_DW.counter_m = 0;
      }
    
    #endif
    
      /* End of Update for Sin: '<Root>/Sine1' */
    }

The variables rtb_VariantMerge_For_Variant_So and rtb_VariantMerge_For_Variant_e hold the input values to the Variant Source blocks. Notice that the code for these variables is conditional. The variables inline_variants_example_Y.Outport and inline_variants_example_Y.Outport1 hold the output values of the Variant Source blocks. Notice that the code for these variables is not conditional.

Generate Code with Zero Active Variant Controls

You can generate code in which blocks connected to the input and the output of a Variant Source block are conditional.

  1. For Variant Source, open the Block Parameters dialog box. Select the parameter Allow zero active variant controls.

  2. For Variant Source 1, open the Block Parameters dialog box. Select the parameter Allow zero active variant controls.

When you select the Allow zero active variant controls parameter, you can generate code for a model containing Variant Source and Variant Sink blocks even when you specify a value for a variant control variable that does not allow for an active variant. Choosing a value for a variant control variable that does not allow for an active variant and not selecting the Allow zero active variant controls parameter, produces an error.

Generate code for inline_variants_example. Notice in the inline_variants_example.c file, that the code for the variables inline_variants_example_Y.Outport1 and inline_variants_example_Y.Outport2 is conditional.

/* Model step function */
void inline_variants_example_step(void)
{
 ...
#if V == 1 || V == 2

  inline_variants_example_Y.Outport = 3.0 * rtb_VariantMerge_For_Variant_So;

#endif


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

  inline_variants_example_Y.Outport1 = 4.0 * rtb_VariantMerge_For_Variant__e;

#endif
 
 ...

Related Topics