Manage Variant Components to Pass Specified Values from Inactive Variant Subsystems with No Active Choice
This example shows how to manage variant components when no choices of a Variant Subsystem block are active.
Simulink® enables you to specify the output values from the Variant Subsystem block when none of its variant choices are active during simulation or code generation. You must specify the output values to ensure that unintended values do not propagate to other parts of the model. Select one of these options to specify the value to output from an inactive Variant Subsystem block:
The Built-in empty choice parameter to remove variant components and output zeroes
The Built-in passthrough choice parameter to skip variant components and assign input values to the output ports
Prerequisites
Complete the Implement Variations in Separate Hierarchy Using Variant Subsystems example to learn more about how to use the Variant Subsystem block in Simulink.
Explore the Model
Open the slexVariantSubsystemsAdaptiveInterface
model. The model contains a Variant Subsystem block named Controller
with two variant choices, Linear
and Nonlinear
. The Linear
controller is active when V == 1
evaluates to true
, and the Nonlinear
controller is active when V == 2
evaluates to true
. V
is a variant control variable and is defined in the PreLoadFcn
callback of the model.
model = "slexVariantSubsystemsAdaptiveInterface";
open_system(model);
To view the contents of the Controller
block, 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
and Nonlinear
controller blocks do not have the same interface. The input ports sensor1
and sensor3
are used in the Linear
controller and Nonlinear
controller blocks, but sensor2
is used only in the Nonlinear
controller block. Therefore, the sensor2
block is active only when the Nonlinear
controller is active and is not executed when the Linear
controller is active. To make the model components outside the Controller
block aware of the active or inactive state of blocks within the Controller
block, the block variant conditions must propagate outside the boundaries of the block. To propagate the variant conditions outside of the Controller
block, select Propagate conditions outside of variant subsystem in the Block Parameters dialog box. For more information on how the variant conditions propagate outside of the Variant Subsystem blocks, see Propagate Variant Conditions to Define Variant Regions Outside Variant Subsystems to Promote Consistency and Reduce Errors.
open_system(model+"/Controller")
Output Zero from Variant Subsystem Block with No Active Variant Choice
When you select the Built-in empty choice parameter of a Variant Subsystem block, Simulink propagates the variant conditions to the blocks within a variant region (including the always true or unconditional blocks). The propagated variant condition on a block is a combination of the variant conditions from the connected Variant Subsystem blocks. For information on how the variant conditions propagated are combined, see . 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 Subsystem block, including the inputs and outputs of the subsystem itself, and outputs zeroes.
To output zero from the Controller
block when none of its variant choices Linear
or Nonlinear
controllers are active, perform these steps.
1. Specify the Variant activation time parameter of the Controller
block to code compile
to analyze the Linear
and Nonlinear
variant choices for consistency across the model.
set_param(model+"/Controller","VariantActivationTime","code compile");
2. Select the Built-in empty choice parameter, so that, the model simulates successfully even if the Controller
block has no active variant choice.
set_param(model+"/Controller","EmptyChoice","on"); set_param(model+"/Controller","PassThrough","off");
3. In the MATLAB® Command Window, set the value of V
to 3
and simulate the model.
V = 3; sim(model);
Observe the variant conditions that propagate from the Controller
block:
When the Built-in empty choice parameter is cleared, the model requires either the
Linear
orNonlinear
controller block to betrue
for successful simulation. In this case, the blocksIn1
,In3
, andu
that are used by both theLinear
andNonlinear
controller blocks remain unconditional and active regardless of which variant choice is active, because at least one is alwaystrue
.
When the Built-in empty choice parameter is selected, you can simulate the model even if no variant choice is active. In this scenario, variant conditions propagate to the
In1
,In3
, andu
blocks as well. If none of the variant choices are active, these blocks are removed from compilation.
In this example, with the Built-in empty choice parameter selected and the value of V
set to 3
, the variant conditions V == 1
and V == 2
evaluate to false
. Consequently, both the Linear
and Nonlinear
controller blocks, along with other conditional blocks, become inactive, causing the Controller
block to output zeroes.
When you generate code with the Built-in empty choice parameter set to on
, the code generator guards the blocks of the variant region with an additional variant condition by using #if
preprocessor conditional statements. This variant condition is a combination of conditions from the connected variant blocks that enable you to completely remove the variant region from the code when none of the variant choices are active.
4. To generate code with preprocessor conditionals #if
and elif
, you must have an Embedded Coder® license. Specify the system target configuration file as ert.tlc
.
set_param(model,"SystemTargetFile","ert.tlc");
5. In the Apps tab of the toolstrip, open the Embedded Coder app. In the C code tab, select Build > Generate code. Alternatively, enter this command in the Command Window:
slbuild(model);
### Searching for referenced models in model 'slexVariantSubsystemsAdaptiveInterface'. ### Total of 1 models to build. ### Starting build procedure for: slexVariantSubsystemsAdaptiveInterface ### Successful completion of build procedure for: slexVariantSubsystemsAdaptiveInterface Build Summary Top model targets: Model Build Reason Status Build Duration ========================================================================================================================================= slexVariantSubsystemsAdaptiveInterface Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 8.0175s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 8.6383s
6. In the C Code tab, select Open Report. Locate and select the slexVariantSubsystemsAdaptiveInterface.h
file from the left pane. In the generated code, the In1
, In3
, and u
blocks connected to the Controller
block are enclosed in an additional preprocessor conditional V == 1 || V == 2
, thus enabling complete removal of the blocks when the Controller
block is inactive. For information on conditional compilation of variant choices, see Compile Code Conditionally for Variations of Component Represented Using Variant Block.
cfile = fullfile(pwd, "slexVariantSubsystemsAdaptiveInterface_ert_rtw", "slexVariantSubsystemsAdaptiveInterface.h"); coder.example.extractLines(cfile, "/* External inputs (root inport signals with default storage) */", "/* Real-time Model Data Structure */", 1, 0); close_system(model,0)
/* External inputs (root inport signals with default storage) */ typedef struct { #if V == 1 || V == 2 real_T In1; /* '<Root>/In1' */ #ifndef EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #define EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #endif #endif #if V == 2 real_T In2; /* '<Root>/In2' */ #ifndef EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #define EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #endif #endif #if V == 1 || V == 2 real_T In3; /* '<Root>/In3' */ #ifndef EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #define EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #endif #endif #ifndef EXTU_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS uchar_T rt_unused; #endif } ExtU_slexVariantSubsystemsAda_T; /* External outputs (root outports fed by signals with default storage) */ typedef struct { #if V == 1 || V == 2 real_T u; /* '<Root>/u' */ #ifndef EXTY_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #define EXTY_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS #endif #endif #ifndef EXTY_SLEXVARIANTSUBSYSTEMSADA_T_VARIANT_EXISTS uchar_T rt_unused; #endif } ExtY_slexVariantSubsystemsAda_T;
Note: To specify a value other than zero from the Variant Subsystem block when none of its variant choices are active, select the Specify output when source is unconnected parameter of the Outport blocks and specify the desired values.
Map Input to Output in Variant Subsystem Block with No Active Variant Choice
When you select the Built-in passthrough choice parameter of a Variant Subsystem block and no variant choice is active, Simulink disconnects the variant choices of the Variant Subsystem block. This parameter retains only the input and output ports, allowing values to pass directly from input to output.
For the values to be mapped from input ports to output ports when no variant choice is active, the Variant Subsystem block must have the same number of data input ports and output ports, and both must match the number of ports on the variant choices.
To map values from the input ports to the output ports of the Controller
block when none of its variant choices Linear
or Nonlinear
controllers are active, perform these steps.
1. Run the convertVariantModelForPassthrough.m
file to update the slexVariantSubsystemsAdaptiveInterface
model to contain equal number of input and output data ports. The input ports map to output ports by matching their port numbers. For example, the input port In1
with port number 1 passes the value to the output port u
with port number 1.
load_system(model) convertVariantModelForPassthrough open_system(model)
V = 1
2. Select the Built-in passthrough choice parameter of the Controller
block so that you can simulate the model successfully even if the Controller
block has no active variant choice.
set_param(model+"/Controller","EmptyChoice","off"); set_param(model+"/Controller","PassThrough","on");
3. In the MATLAB Command Window, set the value of V
to 3
and simulate the model.
V = 3; sim(model);
Because the value of V
is set to 3
, the variant conditions V == 1
and V == 2
evaluate to false
. Consequently, the Linear
and Nonlinear
controller blocks become inactive and assign the values from input ports to the output ports.
4. Generate code and open the code generation report.
slbuild(model);
### Searching for referenced models in model 'slexVariantSubsystemsAdaptiveInterface'. ### Total of 1 models to build. ### Starting build procedure for: slexVariantSubsystemsAdaptiveInterface ### Successful completion of build procedure for: slexVariantSubsystemsAdaptiveInterface Build Summary Top model targets: Model Build Reason Status Build Duration ===================================================================================================================== slexVariantSubsystemsAdaptiveInterface Generated code was out of date. Code generated and compiled. 0h 0m 5.8972s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 6.4008s
5. Locate and select the slexVariantSubsystemsAdaptiveInterface.c
file from the left pane. In the generated code, the output port variables slexVariantSubsystemsAdaptive_Y.u
and slexVariantSubsystemsAdaptive_Y.v
are assigned the value of inputs slexVariantSubsystemsAdaptive_U.In1
and slexVariantSubsystemsAdaptiv_DW.filter_states
.
cfile = fullfile(pwd, "slexVariantSubsystemsAdaptiveInterface_ert_rtw", "slexVariantSubsystemsAdaptiveInterface.c"); coder.example.extractLines(cfile, "/* End of Outputs for SubSystem: '<S1>/Nonlinear' */", "/* End of Outputs for SubSystem: '<Root>/Controller' */", 1, 0);
/* End of Outputs for SubSystem: '<S1>/Nonlinear' */ #elif (V != 1) && (V != 2) /* VariantMerge generated from: '<S1>/u' incorporates: * Inport: '<Root>/In1' * SignalConversion generated from: '<S1>/Passthrough' */ slexVariantSubsystemsAdaptive_Y.u = slexVariantSubsystemsAdaptive_U.In1; /* VariantMerge generated from: '<S1>/saturate' incorporates: * DiscreteTransferFcn: '<Root>/filter' * SignalConversion generated from: '<S1>/Passthrough' */ slexVariantSubsystemsAdaptive_Y.v = slexVariantSubsystemsAdaptiv_DW.filter_states; #endif
See Also
Remove Inactive Variant Components from Generated Code at Compile Time When No Active Choices Exist