Guy and Seth on Simulink
August 20th, 2009
A Better If-Else Construct
In a previous post, I answered a question about how
to model an If-Else behavior. Here I will restate the algorithm I want to create:
if(sel==0)
out = 2*in1;
elseif (sel==1)
out = 3*in2;
The first answer I gave relied upon a Switch block and the Conditional
Input Branch Execution optimization to get an efficient If-Else construct
in the model. While this works, I don’t like reliance on an optimization to
provide good behavior. Sometimes, small changes to the model prevent Simulink
from applying an optimization. I think it is best to implement requirements explicitly.
In this post, I want to show you a way to model explicitly an If-Else conditional
execution behavior.
Conditionally Executed Subsystems and Merge
The If-Else construct requires decision logic to control the
execution of algorithm contained within the expression. One way to do this is
using the If block (from the Ports & Subsystems library), combined with the
If Action Subsystem. The If Action Subsystem executes based on the conditional
expression in the If block. If you have used Function Call subsystems, this is
very similar.

The If block provides control over If and ElseIf conditions,
and there is even an option to provide an Else signal.

This model will give you the conditional execution of the
two subsystem, however, the subsystems write their outputs to separate signals.
How do you get two subsystem to write to the same signal?
Merge the Signals
The Merge block provides a way for both subsystems to write
to the same signal.

In many ways, the Merge block doesn’t behave like a block
with the traditional input/output relationship. I think of it more like a
jumper across multiple wires. The merge block specifies that all signals
connected to it have the same value and actually share the same memory. This
is the programming practice of specifying multiple writers to the same
variable.
Generated Code with Merge
The code generated from the above model looks a lot like our
original algorithm.
34 /* If: '<Root>/If' incorporates: 35 * ActionPort: '<S1>/Action Port' 36 * ActionPort: '<S2>/Action Port' 37 * Inport: '<Root>/In3' 38 * SubSystem: '<Root>/If Action Subsystem' 39 * SubSystem: '<Root>/If Action Subsystem1' 40 */ 41 if (sel == 0.0) { 42 /* Gain: '<S1>/Gain' incorporates: 43 * Inport: '<Root>/In1' 44 */ 45 out = 2.0 * u1; 46 } else { 47 if (sel == 1.0) { 48 /* Gain: '<S2>/Gain' incorporates: 49 * Inport: '<Root>/In2' 50 */ 51 out = 3.0 * u2; 52 } 53 }
Correct use of Merge
Because Merge blocks are a memory specification rather than
an algorithmic construct, there are some guidelines
for using merge blocks. The documentation shows some correct and incorrect
usage patterns. If you use merge block in your model, I suggest you run the Model
Advisor Check for proper Merge block usage.
Now it’s your turn
Do you use the Merge block in your models? Leave a comment here and
share your experience.
01:55 UTC |
Posted in Code Generation, Modeling, Real-Time Workshop, Simulink Tips |
Permalink |
10 Comments »
You can follow any responses to this entry through the RSS 2.0 feed.
You can skip to the end and leave a response. Pinging is currently not allowed.
Leave a Reply
|
A topic that has caused great trouble over the years. As you mention, Simulink doesn’t always apply the conditional execution optimization (code that has states is a common reason here) and so it is generally required that developers use the If/Action or the Switch/Action (a great alternative to an If block with u1==0, u1==1, u1==2,…).
These always draw complaints about how many lines one needs to connect properly, how easy it is to make a mistake, and how hard it is to visually inspect. Most of the Action subsystems are more complex, with multiple inputs and outputs feeding multiple merge blocks and lines crossing everywhere.
To deal with this, I’ve seen:
- Put all the merge blocks in a merge subsystem to prevent lines crossing. Inside the merge subsystem, ports 1 & 3 feed the first merge block, ports 2 & 4 feed the second, or similar.
- Change the foreground color on the Action subsystem so the lines are colored and easier to trace.
- Use a virtual bus to bring all the signals together and then break apart without lines crossing.
- Use local From/Goto blocks to avoid crossing signals.
Some people also use the From/Goto to avoid having the dashed action lines crossing other lines on their way to that top port.
And because this is so messy, just the mechanics of implementing If/Then/Else logic gets dedicated to its own subsystem so it can be inspected independently. If the logic is complex, sometimes the If block gets its own subsystem (or Stateflow chart with Boolean outputs) too.
We encourage people to do something, but don’t have a standard. What do others do to create maintainable models as the Action subsystem I/O grows?
Hello Seth!
Read all your good articles.
But can you please consider my question for your next article of just give me your kind shortly explanation.
Cant build simulink model for that ODE:
L1*x1′ + R1*x1 + M12*x2′ + 1/C1*int(x) = 0
L2*x2′ + R2*x2 + M21*x1′ = 0
where int(x1) = Uc
build model like this:
http://picspix.com/img87/5728/16333.jpg
but it was failed..
It’s classic quotation of LC circuit+mutal inductance bind
Thanks a lot, and
sorry for out of topic post.
Regards,
Valentino.
@Bob – You got me thinking about this. I see what you mean about the number of wires and the challenge of making sure they get connected correctly every time. I hope I’ll be able to propose some kind of solution in a future post.
@valio – Start by rewriting the ODEs in terms of first order derivatives. This was discussed in a previous blog post about How to draw ODEs in Simulink.
please tell me how can i get the sampling time used in simulation
Seth,
I’m having trouble with “if/then” subsystem you described above. I left a posted a message on Mathworks blog, yesterday, but gotten no responses. I believe my trouble is correct syntax. I believe it comes down to how to reset the “if/then” subsystem to false after it has been enabled the first time. Your thoughts will be very helpful.
Gerry
Hi Gerry – By double-clicking on the output port of the conditionnal subsystem, you can specify the “Output When Disabled” to be “reset” or “held”. If you set it to “reset”, the output will reset to the value specified in the “Initial Output” parameter when the condition is false. You can see an example of it in the demo model sldemo_ifsub.mdl.
Guy
Guy, I wanted to thank you. I followed your instructions and “reset” the “output” with a specified value and that did the trick. I would have never thought to double-click the output field for more options.
Gerry
hi
i am having problem using the merge block for a fixed step solver with sample time 0.1s. the problem is simple consisting of two pulse generator blocks and their o/p s are merged. the first pulse generator o/p a positive pulse of 0.5s pulse width & 0.1 amp after 10 s. the second pulse o/p a pulse of same pulse width but amp of -0.1 after 15s pulse delay. if i use a variable solver (ode45) the o/p of the merge block comes perfectly with consisting of a positive pulse followed by a negative pulse after 5 s. but if the solver is changed to fixed step solver (ode4 ) the o/p of the merge block is the negative pulse after 15s. the positive pulse disappears. i have change the pulse generator i/p to sample type with 0.1 s sample period then also the problem is not getting solved.
@rima, The Pulse Generator block takes different time steps when used with a variable step solver, versus fixed-step solver. This is why to see a different ouptut.
To avoid this change of behavior, I recommend following the guidelines provided in the Merge block documentation. Especially:
- Always use conditionally-executed subsystems to drive Merge blocks.
- Write your control logic to ensure that at most one of the driving conditionally-executed subsystems executes at any time step.