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.
This example shows how Variant Source blocks make model elements conditional.
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.
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
.
Make four copies of the Sine Wave Function block.
Connect and name the blocks as shown.
Insert values of 2
, 3
,
and 4
in the Gain2
, Gain3
,
and Gain4
blocks, respectively.
Give the model the name inline_variants_example
.
Open the Block Parameters dialog box for Variant
Source
.
In the Variant control column, for Port 1, replace
Choice_1
with V==1
. For Port 2, replace
Choice_2
with V==2
.
Open the Block Parameters dialog box for Variant
Source1
.
In the Variant control column, replace
Choice_1
with W==1
. For Port 2, replace
Choice_2
with W==2
.
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.
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.
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.
In the Modeling tab of the Simulink toolstrip, click Model Settings.
On the Code Generation pane, and set System target
file to ert.tlc
.
On the Solver pane, set the Type
parameter to Fixed-step
.
In your model, open the block parameters dialog box
for Variant Source
.
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.
Clear the Allow zero active variant controls parameter.
Open the Block Parameters dialog box for Variant
Source 1
. Repeat steps 5 through 7.
Build the model. When code generation is complete, the generated code is displayed in the Code view.
In the Code view, select the inline_variants_example.c
file.
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.
You can generate code in which blocks connected to the input and the output of a Variant Source block are conditional.
For Variant Source
, open the Block
Parameters dialog box. Select the parameter Allow zero active
variant controls.
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 ...