As we all know, in Simulink there are always multiple ways to implement a functionality. One situation where I often hesitate when choosing an implementation is conditional execution.
I will share a few possible options I usually consider and would like to know how you choose one versus another.
Maybe it is because it is the first method I learned when I started using Simulink long ago, but I like Enabled Subsystems.
Using this method, you use Simulink blocks to generate one logical signal for each subsystem. This method is useful when you have a small number of mutually exclusive systems and the activation logic is relatively simple.
Switch and Multiport Switch
If you enable the Conditional branch execution optimization, Simulink executes only the blocks required to compute the control input and the data input selected by the control input.
I typically use this method only when I need to switch between 2 very simple options, made of just a few directfeedthrough stateless blocks.
In this approach, you define the conditions in the dialog of the If-Else or Switch-Case block.
One thing to note with this approach is that all blocks in an Action subsystem driven by an If or Switch Case block must run at the same rate as the driving block.
Stateflow and Simulink Functions
For complex activation logic, I recommend going with Stateflow. Inside the chart, you can place the algorithms to be conditionally executed inside Simulink Functions.
I like to use this technique especially when the Simulink function is called from multiple places in the chart.
Stafeflow and Function-Call Subsystems
I have to admit, when I place a large or important algorithm inside a Stateflow Simulink Function, I feel like if I am hiding it. This is why sometimes I prefer to generate Function-Calls from the chart.
Stafeflow, Enumeration and Switch-Case Action Subsystems
One way to make it obvious that one and only one subsystem is active at a time is to generate an enumerated type from the Stateflow chart and use it in a Switch-Case construct.
All these methods have advantages and disadvantages. I think it is important to read and understand the documentation to pick the one appropriate for your use case.
When in doubt, go for readability. Try picking one that you think will make it as easy as possible to understand the functionality of your model.
Now it's your turn
I would be very interested to hear what are your criteria when choosing one versus another.
Let us know by leaving a comment here.
9 CommentsOldest to Newest
I prefer method 2 (switch and multiport switch) because no merge block is required for this. Besides that I know Simulink Coder will optimise (omit) unneccesary code for this option.
Could you shed any light on code consequences of each option?
@Guy, There is a difference between ‘switch and multiport switch’ and other usages (Guy, would you label them in your post so the reference to them is easier?) – state/output held/reset properties. Optimization also seems have some (state related) limitation.
Could this be elaborated?
@Han and wei, thank you for the comments. I will look into a follow up post to add more details on the optimization and code generation.
I like the Switch and Multiport Switch, i think it’s conceptually simpler in a data flow -based programming paradigm, and it also works in very old versions of Simulink.
I would also bet that it is the option with less overhead, but i might be wrong on that.
I find conditional execution to be one of the trickiest aspects of model based design to implement. I find this topic interesting and appreciate the post on the topic. I can’t add much to the debate, but have found personally that I never use the ‘if’ block. This is interesting considering it’s one of the most common statements in the generated code… I prefer to use switches or enabled/ triggered subsystems… Like others have said, the options get more complicated as you read down your post and simplicity is always better. I rarely use branches in state flow charts, preferring to put this type of logic in Simulink.
One request I’d like to make is for a simulink block that holds an output when enabled. I often require this function and feel using an enabled subsystem to be overkill when the internals of the sub-system are just a straight pass through… Your thoughts?
@Paul: This is interesting. I agree with you that this could be useful to include such block in the Simulink Library.
Currently, it seems that users implement this functionality in 2 ways:
- Using a straight pass through Enabled Subsystem, as you describe. This is also the one I use most often.
- Using a Switch and a Memory block.
One question: Do you think the signal controlling the holding should be on the top (like the enabled subsystem), or a normal input port?
Good thinking, the memory block would also work. It would trivial I guess to make a user library with this functionality but I thought for newcomers that are learning MBD as I did by seeing which built in functions were available, there is enough justification to warrant a dedicated hold output block. For consistency the enable port should be on the top…
I personally prefer the if-else or switch-case blocks. I can’t really tell why. Probably because I was not aware about the “Conditional branch execution” optimization when I first implemented conditional execution.
Another modeling paradigm I try to stick to is implement stateless blocks whenever possible. In theory, this should facilitate conditional execution. Yet, sometimes, the generated code shows additional state variables, which I do not understand and would like to avoid (having “hidden states” in blocks that are supposed stateless is very unfortunate). Guy, can you say some words on how the different initial output and holding output settings affect code generation?
A simple solution may be to use the switch or multiport switch blocks. Is there, in your opinion, any disadvantage if Conditional branch execution is turned on and all blocks are stateless?
The way holding or not of states and outputs for conditionally executed system influences the generated code can complex. There are many different possible combinations.
For example, a diagnostic like “Underspecified initialization detection” can influence that.
I will look into writing a post on this topic.
About the Switches option, if conditional branch execution can be applied, the code should be similar to if-else and switch-case subsystem. You can see if conditional branch execution is applied by looking at the blocks sorted order.