Seth on Simulink
January 13th, 2009
Bus Copies Explained!
A Simulink developer caught me in the hall last week and
asked me, “How do people use the Signal Conversion block?” He was specifically
interested in how people use Contiguous Copy mode, and if people check
the Override optimizations and always copy signal check box.

If you use the block in your models, please post a comment here
and tell us about your use case. In this post, I will show you one of the examples
I gave him that has to do with bus copies and unravel some of the interesting
semantics at work. The models I used are available for download
from the File Exchange.
Meaning of Atomic
An atomic subsystem is a Simulink semantic that means the
blocks inside execute together, so you can treat them collectively as one block.
It is like a macro or function in C. The routine executes all the code
contained within and runs to completion. When you draw a line from the output
of a subsystem (A) to another block (B), you are asking for the input to B to
be the output of A. This data dependency ensures that the signal will only change
if that atomic subsystem executes again. If an input to the atomic subsystem
is passes through to the output, unchanged, what happens when that input signal
is changed? Atomic blocks in Simulink must control their output signal memory.
This gives rise to the following example.
A Signal Runs Through It
Here is the NoSignalConversion subsystem. Notice it has a
heavy black outline because the system is atomic. The subsystem takes a bus as
input, repackages one element from the bus with a computed value and passes it
to the output.

Notice that the diagram is displaying little red numbers on
the corners of the blocks to indicate their sorted order. Virtual blocks, like
the bus selector, do not have a place in the sorted order.
When we dive into the subsystem, you can see that the Inport
In1 has a sorted order label, which means it is non-virtual. Usually
Inports are virtual. What does an input port do when it is non-virtual? Let’s
look at the code:
109 /* Outputs for atomic SubSystem: '<Root>/NoSignalConversion' */ 110 111 /* Inport: '<S1>/In1' */ 112 for (i = 0; i < 6; i++) { 113 rtb_In1[i] = rtb_FromWs[i]; 114 } 115 116 /* Gain: '<S1>/Gain' */ 117 rtb_b1 = 2.0 * rtb_In1[1]; 118 119 /* end of Outputs for SubSystem: '<Root>/NoSignalConversion' */ 120 121 /* Outport: '<Root>/Out1' */ 122 ssnoSigConv_Y.Out1[0] = rtb_In1[0]; 123 ssnoSigConv_Y.Out1[1] = rtb_b1;
It may seem a little cryptic, but the Inport makes a copy of
the memory outside the atomic subsystem into the subsystem. This copy is the rtb_In1
temporary vector (two thirds of this vector is never used!). In this
situation, the copy is wasteful*, but it happens because of the Simulink semantic
that all atomic blocks control their output memory.
Signal Conversion Block to the Rescue
We can improve our model by inserting a Signal Conversion
Block.

Inserting the signal conversion block resolves the memory
pass through issue. This prevents the Inport from becoming non-virtual, and we
no longer get a copy of all input bus elements. Here is the improved code:
108 /* Outputs for atomic SubSystem: '<Root>/WithSignalConversion' */ 109 110 /* Gain: '<S2>/Gain' */ 111 rtb_b1 = 2.0 * rtb_FromWs[1]; 112 113 /* SignalConversion: '<S2>/TmpHiddenBufferAtSignal ConversionInport1' */ 114 rtb_TmpHiddenBufferAtSignalConv = rtb_FromWs[0]; 115 116 /* end of Outputs for SubSystem: '<Root>/WithSignalConversion' */ 117 118 /* Outport: '<Root>/Out' */ 119 sswSigConv_Y.Out[0] = rtb_TmpHiddenBufferAtSignalConv; 120 sswSigConv_Y.Out[1] = rtb_b1;
Important Code Efficiency Note: If you enable the Eliminate
superfluous local variables (Expression folding) optimization, both
subsystems produce roughly identical code that looks like this:
105 /* Outport: '<Root>/Out1' incorporates: 106 * Gain: '<S1>/Gain' 107 * Inport: '<S1>/In1' 108 */ 109 ssnoSigConvExprFld_Y.Out1[0] = rtb_FromWs[0]; 110 ssnoSigConvExprFld_Y.Out1[1] = 2.0 * rtb_FromWs[1];
Interesting Semantics at Work
This is not the first time I have had to explain this
interesting interaction of semantics. Technical support will occasionally get
calls asking why the generated code includes unnecessary bus data copies. We
even wrote a technical
support solution that explains this exact phenomenon. Here is the summary
of what is happening:
Simulink requires that atomic subsystems own the memory they
output. In part, this defines the system as an atomic unit. Hence, all outputs
must originate from blocks inside the atomic subsystem. When an input port
feeds its signal directly to an output port in the atomic subsystem, the input
port becomes nonvirtual and makes a copy of its input signal. When passing bus
signals through atomic subsystems, this rule still applies, and the result is
often perceived as unnecessary copies of bus signals in the generated code.
We want your feedback!
This is only one instance of bus signal copies. What other modeling
constructs do you want to learn? How do you use the signal conversion block?
Do you use the “Override optimizations and always copy signal” check box?
Share your use case and leave a comment here.
22:00 UTC |
Posted in Code Generation, Signals, Simulink Tips |
Permalink |
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
|
Hi Seth,
I’ve used the Signal Conversion block in 2 other cases.
1. If a block output is not local (i.e. it is part of the global BlockIO structure) but you need to connect this signal to a Merge block then placing the Signal Conversion block in between creates a local copy of the signal and allows it to be connected to the Merge block.
2. I have a custom S-Function that is used to call legacy code and in one use case it was just going to pass the address of the input signal to the legacy code. Since this S-Function has ssSetInputPortRequiredContiguous set to FALSE this could potentially lead to problems, so using a Signal Conversion blocks eliminates this problem.
In both cases I left the Override Optimizations checkbox unchecked.
Regards,
Ashish.
@Ashish - Thank you for your response. I didn’t remember that merge block case. Excellent example!
Hi Seth,
1.What about when a large array input data with one index is used inside of (atomic) subsystem?
2.Couldn’t Simulink, actually RTW, detect those feed through data and make copies as needed and implicitly? What’s the advantage to let user control this aspect of model?
@wei - (1) Something similar could happen when you have a large input array. It depends on how the input is constructed. Muxed signals may behave in much the same way as a virtual bus.
(2) Please see the section entitled “Important Code Efficiency Note”. RTW WILL implicitly make only the needed copy, but this is done as part of the “Expression Folding” optimization. By turning this on, you will remove unnecessary temporary variables like the ones created in this example. Some people choose not to turn on this optimization when they need full traceability from model features down to the code.