Generate Code for Variant Source and Variant Sink Blocks
This example explains how to generate code for a specific implementation of a component represented using Variant Source and Variant Sink blocks. You can customize your code to include one or multiple implementations of the component.
The Variant Source and Variant Sink blocks are inline variant blocks that allow you to include multiple implementations, or variants, of a component in a single model. Each variant of the component connected to the input or output ports of the Variant Sink and Variant Source block is called a variant choice. Similarly, each variation of the component connected to the output ports of the Variant Sink block is also referred to as a variant choice. Only one variant choice of an inline variant block can be active during model simulation. You can generate code that includes one or multiple choices of inline variant blocks. For more information, see Propagate Variant Conditions to Define Variant Regions Using Variant Source and Variant Sink Blocks.
Prerequisites
We recommend completing the Propagate Variant Conditions to Define Variant Regions Using Variant Source and Variant Sink Blocks to learn more about how to use Variant Source and Variant Sink blocks in Simulink®.
Represent Variant Choices in Variant Source and Variant Sink Blocks
Open the model slexVariantSourceAndSink
.
The slexVariantSourceAndSink
model contains two Variant Source blocks, Variant Source1
and Variant Source2
, and a Variant Sink
block. The variant conditions at the input and output ports of the Variant Source and the Variant Sink blocks determine the activation and deactivation of the blocks connected to them.
model = "slexVariantSourceAndSink";
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, each variant choice of the variant blocks is associated with variant control variables V
and W
. The variables V
and W
are
objects defined in the PostLoadFcn callback of Modeling > Model Settings > Model Properties.Simulink.Parameter
2. In the MATLAB™ Command Window, set the value of V
to 1
and W
to 1
. Simulate the model. During simulation, the variant control expressions V == 1
and W == 1
evaluate to true
, activating the first input ports of the Variant Source2
and Variant Sink
blocks.
V.Value = 1; W.Value = 1; sim(model);
3. Set the value of V
to 2
and W
to 1
. Simulate the model again. During simulation, V == 2
and W == 1
evaluate to true
, activating the first input port of the Variant Source1
block and the second input port of the Variant Source2
block.
V.Value = 2; W.Value = 1; sim(model);
For information on the variant conditions that activate the Variant Source1
and the Variant Sink
blocks, see Propagate Variant Conditions to Define Variant Regions Using Variant Source and Variant Sink 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
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.Parameter
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, 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 first inputs of the Variant Source2
and Variant Sink
blocks, check these settings:
The values of the variant control variables
V
andW
are set to1
.
V.Value = 1; W.Value = 1;
The Variant activation time parameter of the blocks is set to
update diagram
.
set_param(model+"/Variant Source2","VariantActivationTime","update diagram"); set_param(model+"/Variant Sink","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 active variant choice blocks. 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 12.242s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 13.087s
Use of VariantMerge Blocks
For modeling patterns in which a root Inport block connects to a variant block with one variant choice, Simulink inserts a hidden block combination of a Ground block, Signal Conversion block, and VariantMerge block. If the variant choice evaluates to false
, this block combination produces an output of 0.0
.
For example, the model Varianttoground
contains a Variant Source block with one variant choice. When the variant control SYSCONST_A == 6
evaluates to true
, the input to Subsystem is a sine wave. When SYSCONST_A == 6
evaluates to false
, the input to Subsystem is 0.0
.
The varianttoground.c
file contains this code:
* Sin: '<Root>/Sine Wave' incorporates: * SignalConversion generated from: '<Root>/Subsystem' */ #if SYSCONST_A == 6
Varianttoground_B.VM_Conditional_Signal_Subsystem_0 = sin (Varianttoground_M->Timing.t[0]);
#else
/* SignalConversion generated from: '<Root>/Subsystem' */ Varianttoground_B.VM_Conditional_Signal_Subsystem_0 = 0.0;
#endif
/* End of Sin: '<Root>/Sine Wave' */
The comments in the generated code indicate the presence of the hidden signal conversion block. In the hyperlinked comments, you can trace to the original block in the model that triggered the insertion of the hidden block. The code does not contain a comment for the VariantMerge block because this block does not have associated generated code. The VariantMerge block is used internally and is not in the Simulink library.
Review Generated Code
In the C Code tab of the toolstrip, select Open Report.
Locate and select the slexVariantSourceAndSink.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 slexVariantSourceAndSink_Y.Out1
store the output of the Variant Source2
block and the variables slexVariantSourceAndSink_Y.Out2
and slexVariantSourceAndSink_Y.Out3
store the output of the Variant Sink
block.
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 Run Executables for Variant Blocks Without Recompiling Code for Changing Active Choices Using Startup Activation Time.
cfile=fullfile(pwd, "slexVariantSourceAndSink_ert_rtw", "slexVariantSourceAndSink.c"); coder.example.extractLines(cfile, "/* Model step", "/* Model terminate function */", 1, 1);
/* Model step function */ void step(void) { real_T rtb_Gain5; /* Outport: '<Root>/Out1' incorporates: * Gain: '<Root>/Gain3' * Sin: '<Root>/Sine1' */ slexVariantSourceAndSink_Y.Out1 = (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) * slexVariantSourceAndSink_P.Gain3_Gain; /* Gain: '<Root>/Gain5' incorporates: * Gain: '<Root>/Gain4' * Sin: '<Root>/Sine5' */ 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) * slexVariantSourceAndSink_P.Gain4_Gain * slexVariantSourceAndSink_P.Gain5_Gain; /* 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_Gain5; /* Outport: '<Root>/Out3' */ slexVariantSourceAndSink_Y.Out3 = rtb_Gain5; /* Update for Sin: '<Root>/Sine1' */ slexVariantSourceAndSink_DW.counter++; if (slexVariantSourceAndSink_DW.counter == slexVariantSourceAndSink_P.Sine1_NumSamp) { slexVariantSourceAndSink_DW.counter = 0; } /* End of Update for Sin: '<Root>/Sine1' */ /* 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' */ slexVariantSourceAndSink_DW.counter_d++; if (slexVariantSourceAndSink_DW.counter_d == slexVariantSourceAndSink_P.Sine5_NumSamp) { slexVariantSourceAndSink_DW.counter_d = 0; } /* End of Update for Sin: '<Root>/Sine5' */ } /* Model initialize function */ void initialize(void) { /* Registration code */ /* initialize error status */ rtmSetErrorStatus(slexVariantSourceAndSink_M, (NULL)); /* states (dwork) */ (void) memset((void *)&slexVariantSourceAndSink_DW, 0, sizeof(DW_slexVariantSourceAndSink_T)); /* external outputs */ (void)memset(&slexVariantSourceAndSink_Y, 0, sizeof (ExtY_slexVariantSourceAndSink_T)); /* InitializeConditions for Sin: '<Root>/Sine1' */ slexVariantSourceAndSink_DW.counter = 0; /* InitializeConditions for Sin: '<Root>/Sine6' */ slexVariantSourceAndSink_DW.counter_g = 0; /* InitializeConditions for Sin: '<Root>/Sine5' */ slexVariantSourceAndSink_DW.counter_d = 0; }
See Also
Remove Inactive Variant Components from Generated Code at Compile Time When No Active Choices Exist