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.

Signal Conversion block set to contiguous copy mode.

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.

Example atomic subsystem with inport directly passing through 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.

Atomic subsystem using a Signal Conversion block to copy the one element that passes through to the output.

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.

4 Responses to “Bus Copies Explained!”

  1. Ashish Sadanandan replied on :

    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.

  2. Seth replied on :

    @Ashish - Thank you for your response. I didn’t remember that merge block case. Excellent example!

  3. wei replied on :

    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?

  4. Seth replied on :

    @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.

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Seth Popinchalk is an Application Engineer for The MathWorks. He writes here about Simulink and other MathWorks tools used in Model-Based Design.
  • Mohamamd: Hi Suth, I try to simulate a load tap-changing transformer in simulink but its control part has to be...
  • Han Geerligs: Hello Guy, thanks for the clarificaton and link. However in the documentation I am missing the...
  • Guy: @Han, you probably already know, but I think it is good to share with everyone. To zoom in use the key...
  • Han Geerligs: Hi Seth, Once again I’d like to point out that my biggest accelerator is using mouse and keyboard...
  • XaL: Hi, thanks for the tips. As someone wrote in http://blogs.mathwor ks.com/seth/2009/03/ 13/new-%C2%A0rele...
  • Uba osy: Hi, in the introductory example for fuzzy logic toolbox it was noted that using non fuzzy means, you could...
  • Prashant: How can I have same example but instead AC(1 to 10V 50 or 60Hz) and DC(0.5 to 10 V) then adding AC+DC but...
  • adrian chavarro: Great tool, for educational and sicentific, simulation. I would like to know where can i place a...
  • Ashish Sadanandan: @wei, I was talking about the case where the compiler would perform the ‘model_Xdim...
  • wei: @Ashish, I agree with your observation on compiler optimization but fail to see why Han’s code would be...

These postings are the author's and don't necessarily represent the opinions of The MathWorks.