Blog reader Paul
J. shared with us his mental model of the bus as a structure. While this
isn’t true of virtual buses, it is precisely true of nonvirtual buses. In
fact, when you generate the code for a nonvirtual bus using Real-Time Workshop, the
result is a structure.
This model has the root level boundaries defined by the
inport and outport blocks. It also has a boundary at the edge of the ReusableFcn
subsystem. The main_bus crosses this boundary and the generated code is
different if the bus is virtual versus nonvirtual.
The ReusableFcn subsystem contains a Bus Selector and two
gain blocks.
I configured the subsystem to generate a reusable function.
Here are the settings for the subsystem:
Basically, I have specified how Real-Time Workshop should
wrap up the algorithm implemented inside this system. By specifying “Treat as
atomic unit”, the blocks inside the system execute together. Real-Time
Workshop will generate reusable function code with my specified name
(ReusableFcn) into a file of the same name (ReusableFcn.c). The reusable
function code will pass input and output signals as arguments to the function.
I can now picture what this will look like:
ReusableFcn(inputs..., outputs...)
Virtual buses pass every element separately
When the bus signal is virtual at the inport to the
ReusableFcn, only the elements of the bus that are used in the system need to
be passed through the boundary. Here is the actual code for the function call:
Notice, there is no evidence in the code that a bus signal
exists. At compile-time, direct connections between sources and destinations
replace the virtual bus.
Each of the input signals is being copied into the
rtb_main_bus variable, which is an instance of the main_bus type. This
structure matches the bus object definition specified by main_bus, bus1, and
bus2.
I notice that the ReusableFcn has a shorter interface. Now
the only input signal is a pointer to the rtb_main_bus, which is allocated
locally.
In the case of nonvirtual bus signals, the concept of
interface specification using the bus object carries all the way down to the
generated code.
Now it’s your turn
We have now covered most of the important topics on bus
signals. What questions remain about bus signals and their use in your models?
Post a comment
here.
Most Simulink users have a good idea of what a bus signal is
but I have found people are not as clear about what distinguishes virtual and
nonvirtual buses. We have discussed bus signals in recent posts, and we are
now ready to answer blog reader Han
Geerligs request for “more explanation on virtal/nonvirtual buses.”
What is a nonvirtual bus?
Here are the two types of bus signals, virtual and
nonvirtual.
To make a bus nonvirtual, provide a bus object and check the
“Output as nonvirtual bus” check box in the Bus Creator dialog. You can review
how to make a bus object with the example provided in this
previous post.
The big difference between virtual and nonvirtual buses is
how Simulink treats memory allocation. A virtual bus does not allocate specific
memory for the bus, whereas nonvirtual bus signals represent memory.
In a previous
post, we saw that when you update your diagram (Ctrl-D), the virtual buses
disappear and what remains are connections between the actual source and the
destination block. The memory allocated for those signals is not contiguous.
Using a nonvirtual bus specifies the creation of a structure, which resides in
contiguous memory.
Both use bus objects to specify the interface to the
ReusableFcn subsystem, but simplebusdemo_nv has a nonvirtual bus crossing the
boundary. Here is my mental picture of memory being allocated for the virtual bus
example.
The first and fifth inport have type double inputs, with one and two elements respectively
represented in red. The second inport has three elements of int16, represented in green. The
third inport is one element of type uint32
represented by orange, and the fourth inport is one element of type single represented by blue. The bus
creators and bus signals are all virtual blocks, so there is no memory
associated with those blocks or their ports.
The inports for the nonvirtual bus example have the same
pattern of memory allocation, but now we have to add in the memory for the
nonvirtual bus. Here is the way I picture it.
The output of the bus creator is a scalar element of main_bus type as defined by the bus
object. The bus object is the definition, and the nonvirtual bus is an
instance of a structure with that definition. I often see confusion between
bus objects and instances defined by bus objects. They are not the same
thing. The bus object is a definition of an interface. Your model may
contain many instances that share that same interface definition.
Nonvirtual bus signals and efficiency
As you can see from the above picture, the nonvirtual bus
has added memory to the model. In this case, that memory consists of copies of
the memory defined at the inports. I have often heard the rumor that bus
signals result in many unnecessary copies. This is not completely accurate.
Nonvirtual bus signals can result in additional copies, but from the
Simulink engine perspective, this is the specification. Another way to build
this model would be to remove the five inports and replace them with a single inport,
which outputs a main_bus type.
Then it would look like this.
Notice, when you specify a bus object on an inport, the icon
changes to show that a bus object defines that interface.
When do you need a nonvirtual bus?
The only places you need nonvirtual buses are at the
boundaries in your model when you want to define the interface as a structure.
Some examples of these boundaries are Stateflow charts and model reference
blocks. At the interface between systems, virtual buses are as a collection of
individual elements, with each passing separately to the system. The
nonvirtual bus forces the memory to be a contiguous structure passed into the
system.
Nonvirtual buses show up in other places in models where
they are not required by semantics. Most often the reason it is done is to
control the signal memory allocation in the generate code.
Virtual versus nonvirtual buses
To summarize,
Virtual buses don’t really exist in memory (the memory they represent is at the actual source)
Virtual bus elements are not contiguous in memory
Nonvirtual buses resides in contiguous memory
Nonvirtual buses may incur copies which could reduce the
efficiency of the system
Virtual buses will often require less memory
I think these concepts still require further illustration by
looking at the generated code. You can get a sneak peak if you want to
download the models and build the code yourself, or, tune in next week when I
post about bus signals in the generated code.
Now it’s your turn
Do you ever picture the memory allocated in your Simulink
model? Did I describe the reason you use nonvirtual bus signals? Are there
other reasons I didn’t consider? Post a comment
and share your thoughts.
A few recent comments on this blog have asked about bus
objects. Blog reader KMR
remarked that "bus objects are one of the most important parts of the
whole bus concept: allowing you to lock down an interface." This week I introduce bus objects
and how they can help avoid modeling errors.
Bus objects provide a specification
In an earlier
post, we saw that virtual bus signals do not have to include any
information about the size and datatype of their signals. This information
propagates from the other blocks (like sources and Inports) in the diagram.
The simplebusdemo.mdl
doesn’t need a specification for the bus signal because it is virtual. Our
mental model of the bus signal is a bundle of rainbow colored wires that link
the sources to their destinations. We often refer to a bus as a tie-wrap of
signals.
If you did want to lock down the description of this bus,
you must use a bus object. If the bus is the rainbow colored bundle of wires,
in my mental model the bus object is the definition for the cable
connector at the end of that bundle. It defines all the pins and their
exact configuration and asserts that only those types of signals may be
connected.
Check “Specify properties via bus object” and include the
bus object name on the Bus Creator blocks to add the specification to your
model. I’ll get to creating bus objects in the next section.
Bus Creators use bus objects for error checking. If the
input signals do not have the same types and dimensions as the elements in the
bus object Simulink will error. There is also a connectivity diagnostic to
check for element name mismatch in the bus object. Turn the diagnostic up to
warning or error to ensure your signals are consistent with the block
specification.
Making a bus object
The easiest way to make a bus object is directly from your
diagram. Simulink.Bus.createObject
is a function that generates a bus object for the block you specify based on
your diagram. Specify the bus creator or port that has the highest level in
the hierarchy of the bus. Simulink.Bus.createObject recursively creates bus objects for buses
that feed into the given block. For our example, the main_bus is specified by the
simplebusdemo/Bus Creator (not Bus Creator1 or Bus Creator2).
>> Simulink.Bus.createObject('simplebusdemo', 'simplebusdemo/Bus Creator');
>> whos
Name Size Bytes Class Attributes
To look at bus objects, use the buseditor. (click to enlarge)
As of R2008a Simulink has a new bus editor, so unless you
are using this release, your version will look different. The left pane shows
all bus objects in the workspace. The selected node in the tree displays its
children in the center pane, and on the right, you have the details for each
selected element. The information about dimensions, datatype and signal name
are all a part of the bus object. For hierarchical bus signals, the element
datatype is the name of another bus. Looking at the main_bus, it has two
signals, bus1 of type bus1, and bus2 of type bus2. The name and type do not
have to match, but they do in this case.
If you are happy with your bus objects, I recommend saving
them to a MAT-file so you do not have to regenerate them every time. Some
people prefer to generate an M-file and call that as part of their initialization
routines, instead of loading the MAT-file. I have automatically generated this
M-file during the call to Simulink.Bus.createObject. Given an output file
name, Simulink.bus.createObject also outputs the code you need to make that bus
object.
If I change my constant input signal to be type int8 instead
of double Simulink will throw an error during update diagram (Ctrl-D).
The input bus to block
'simplebusdemo_bo_error/Bus Creator1' does not match the bus specified by the
bus object 'bus1' on the block dialog. The following errors were detected :
Bus element 'Constant' of bus
object 'bus1' is specified to be of datatype 'double', but the incoming signal
has a datatype of 'int8'.
As you can see, the bus object has locked down the
specification for the signals fed into the bus creator. When something does
not match Simulink reports an error.
Bus objects can be specified on ports
In addition to the bus creators, Inports and Outports can
also be fully specified with a bus object. When a bus object is used on a port
you are asserting that only that special type of connector can be used with
that port. This port could be a root level Inport or Outport, or a port on a
subsystem. If the subsystem is in a library, you have defined its interface,
and all instances of the library block must match the specification.
Getting back to the comment that “[bus objects] are one of
the most important parts of the whole bus concept: allowing you to lock down an
interface.” The concept of locking down an interface is important to
developing reusable components as well as working with others on large modeling
projects. This is a very powerful concept I have seen used in conjunction with
an interface control document (ICD) to define the interface to a system. The
document specifies the characteristics of the bus signals, and the bus object
enforces that those characteristics are true.
I have also seen a Simulink model specify the interface, with a script used
to generate the ICD from the model. This makes the Simulink model the single
source of truth. Your model will always be in sync with the specification if
this is your workflow.
Now it’s your turn
What do you think about bus objects? Do you use them? I
still have not had anyone volunteer to show off their use of bus signals with a
screen capture from their model. Leave a comment
and then send
me an e-mail with the image. I will post it for you and we can all marvel
at your work.
Today I present for your reading pleasure a continuation of our discussion on mux and bus signals. Last week we looked at the advanced uses of Mux Blocks. This week I want to discuss the mental model of virtual bus signals.
We start with a simple bus model
I have slightly modified the busdemo.mdl example that ships with Simulink to make my simplebusdemo.mdl. Buses are used to route signals around complex diagrams, and this model is not complex, so bear with me. In addition, bus signals usually pass through levels of hierarchy, but for convenience, I am keeping everything at a single level.
The mental model of the bus
In a previous post, I talked about the mental model of the bus as a tie-wrap of wires. I imagine the rainbow bundle of wires gathered together at the bus creator, and just the wires I am interested in emerging from the bus selector. Virtual bus signals are simply a graphical convenience and do not change the behavior of the model.
What do you mean by a virtual bus?
When you look at the bus creator block, you will notice that there is a box to check labeled "Output as nonvirtual bus". Unless this is checked, a virtual bus signal is output.
The Bus Creator and Bus Selector dialog show the contents of the bus by signal name. These signals (the individual colored wires) are arranged hierarchically by their connections to the Bus Creator blocks. The Bus Creator blocks do not actually change the signals, and so we can call these virtual buses. The diagram represents the bus as we draw it, and this keeps everything nice and organized for us.
What does Simulink do with the bus?
Simulink needs to know the actual sources that feed into the bus, and the destination blocks that are connected to the outputs of the Bus Selector. Simulink gets this information in the first part of the simulation process during Update Diagram. Before the model runs, Simulink compiles the diagram into an internal representation. This compile process is part of Update Diagram. You can force Simulink to compile the diagram through the menu Edit->Update Diagram, or use the hot-key Ctrl-D.
Update diagram analyzes the model to make sure that it conforms to the semantics of Simulink. I have not always thought of Simulink as a programming language, but when I draw the diagram, I am actually programming! The compiled internal representation removes any unnecessary stuff in the model. In our model, there are five inputs and two outputs. To calculate the outputs we only need the Pulse and Chirp signals. So what happens to the other signals?
When you update the diagram, it is equivalent to a wiring of the actual sources directly to the blocks consuming those signals. Simulink does not include the virtual bus in its internal representation. We can imagine the internal Simulink representation for our simple bus model, after update diagram:
Virtual buses are efficient
Virtual bus signals are efficient because Simulink optimizes the unused signals out of the model. For many of the large models I work with, virtual buses keep the diagram organized and do not add overhead in the model. If you go back to our mental model of the rainbow bundle of wires, the unused signals are essentially like wires that only connect at one end. They might be a part of the bundle, but there is nothing connected at the destination. Simulink only needs to keep track of the wires that run from a source to a destination.
When I want to see another view on the internal representation in Simulink, I use the Real-Time Workshop to generated C-code. The integration of Simulink and Real-Time Workshop allow you to convert the model in to C-code that is appropriate for running on a real-time embedded system.
If you did not believe me that Simulink gets rid of the virtual bus, look at the C-code. There is no evidence of bus signals here:
All that remains are the connections from the Pulse and Chirp inputs (part of the input signals structures model_U) to the gain blocks (which have been in-lined in the code) to the outputs.
Back to basics
I am eager to get into nonvirtual bus signals; however, I think it is important to review the basics before we jump into the advanced. Did you already know this? Does this fit with your mental model of virtual bus signals? Leave a comment and tell me about it.
Last week I started a discussion of mux and bus signals. Our mental model of the mux signal is a vector. The Mux and Demux Blocks can do more than just combine and break apart the elements of a vector. This week I want to go a level deeper and talk about the advanced maneuvers using Mux/Demux Blocks.
Mux Blocks as specifications
The first thing I want to show you is how to use the Mux Block to specify additional information about the signal dimensions at its ports. Instead of just putting the number of ports, you can specify the width of each signal line connected to the Mux Block.
This helps if you want to add a little more information to your model and include specifications at the Mux Block ports. When a signal is connected to the Mux Block and it has the wrong width, an error is thrown when the model is compiled.
Error in port widths or dimensions. Invalid dimension has been specified for input port 3 of 'model/System/Mux'.
Source blocks and ports can also supply this type of dimension information. I recommend that you specify dimensions on those source and port elements also, rather than just relying on the Mux Block. Information like dimensions should be included in interface and source blocks. For example, here is where you would add dimension information in the Inport dialog:
Demux Specifications
The mux is nice to have, but the Demux Block puts this concept to good use for selecting out subsets of your signal. When specifying the number of outputs as a vector of widths, you can pull out blocks of elements from your vector into subvectors.
Here is an example of the Demux Block breaking a vector of 8 elements into new signals of widths 1, 5 and 2.
Going back to our mental model of the mux signal as a vector, I only use this technique if it is logical to represent my signal this way. In this model, peeling off each chunk of signals makes the diagram flow very nicely. This replaces the need to demux all elements of the signal and then mux the subset of the signal into a vector.
Mux and Demux Blocks also work with special signal types
Another use of Mux and Demux Blocks involves the special function call signal type. Before I talk about what mux and demux do, let us review the basics of function calls.
A short introduction to function calls
A function call system is similar to a triggered system except that instead of executing based on the value of a signal they execute immediately when called by the function call initiator. I have seen function call systems used to simulate asynchronous behavior or to schedule the execution of a component independent of other components. Function calls are critical when designing your own scheduler for an embedded system.
Function Call Generators (1 below), Stateflow(2), and S-functions are the most common function call initiators. Model Reference Blocks(3) and Function call subsystems (4) are two examples of functions that can be called.
Function calls and Mux Blocks
When you have a single function call initiator, and a single system to be called, the connection is simply from initiator to the system being called. When you have multiple function call initiators, the Mux block is used to join the function calls together. (Blocks can only have one function call port.)
Function calls and Demux Blocks
When a single initiator needs to call multiple systems, the Demux Block allows you to split the signal. This is a very important semantic role for the Demux Block because function call signals are not allowed to branch like normal signals. Function call signals determine the execution order of the blocks they are connected to. If a function call was to branch, which destination system would be executed first? The Demux Block specifies the order of execution based on the port number that the signal is connected to. Port numbers are always counted from top to bottom, or left to right. Here is an example:
In this example, the function call initiator Task1 will execute Sys1, Sys2 and Sys3 in that order. I don’t know about you, but when I look at that picture I feel an aesthetic desire to uncross the lines going to Sys1 and Sys2. My urge is to reconnect the first and second outport from the Demux in order to uncross the signals, like this:
This would fundamentally change the behavior of the system. The order of execution would then be Sys2, Sys1, and then Sys3. The Demux Block is an important part of function call semantics, and semantics trump aesthetics.
What do you think?
You may have started reading this post with the expectation to learn all about Mux and Demux, but you also got my elevator speech about function calls. Did you know about this use for Mux and Demux? What is new or different in your mental model for these blocks? Leave a comment and tell me about it.
The answer is short and sweet. A composite signal is a mux or a bus signal. These can be thought of as a collection of other component signals. The subtleties of using bus signals and mux signals are a common source of modeling questions, and in 2006 The MathWorks published a new section of Simulink documentation to specifically discuss Composite Signals. In this post I will start to share my mental model of the mux and bus.
It started with mux
The basic concept for the Mux Block is the idea of bundling signals together. This bundle of signals can be routed through the model, and then operated upon as a collective unit. (Mux actually stands for multiplex.) Along with the Mux Block is the Demux Block, which breaks signals apart into their components to be operated on individually. Take a look at this example.
The Mux is putting the three signals, (x,y,z) into a single line of width 3. The Demux Block is used to break apart the signals into their basic elements. The Mux and Demux do not change the signals, and are considered virtual. When the model is run, it is as if the blocks don’t exist, and only the connections from source to destination remain, like this:
An important mental model to use for the mux is the idea of creating a vector. This means you can do things to the output signal that you would do with a vector. For example, multiply the vector by 2.
These types of vector operations impose an important requirement that all signals passed into a Mux Block are the same data type. In my mental model of the mux, it only makes sense to lump signals together if they make sense as a vector. Usually the elements have the same units or they are useful as a group. The only specification you need for a Mux Block is the number of inputs.
Another benefit of using the mental model of a vector is that you can index with the selector block to pick off signals or rewire your connections.
Later on came the bus
When I need to bundle together signals of different types or I can’t naturally express my diagram with a vector, I use a bus. Bus signals can really clean up your diagram. Bus Creators and Bus Selectors provide a graphically convenient way to manage signals and organize your model. In my mental model of the bus, I imagine a rainbow of wires bundled together with a tie-wrap. Without that tie-wrap holding it together I would quickly loose my ability to keep the signals organized. To demonstrate this, I want to look at an example model of the DeHaviland Beaver from the Aerospace Blockset:
At the top level of the model, everything is nice and orderly because all the information calculated by each subsystem is bundled up into a bus. Each system packages all the relevant signals into a bus using a Bus Creator, and then passes the bus along to the systems that consume those signals.
Can you imagine if the signals were not bused together? This is a relatively modest model, but it would be a mess!
Most of the component systems in this model use bus signals to provide simplified interface. I have noticed that some people will place signals in the bus, just in case they might be needed in another system. Here is an example of a system whose interface is defined with bus signals.
With a quick glance at this diagram you can determine that the flight parameters (FltParams) can be calculated from environmental signals (EnvirBus) and aircraft signals (ACBus). Inside the system you can see Bus Selectors used to pull specific elements from the bundle of signals. The computed flight parameters are combined with a Bus Creator to define the FltParams Bus.
Bus signals can represent hierarchy
Let’s look at the hierarchy found in the Environment Bus. This is a simple example of a bus being fed into another bus. The environmental signals for gravity (g), pressure (rho), and wind bus (Vwind) are passed into the Bus Creator. The wind bus is defined by the body velocities (uvw_wind) and body rates (pqr_wind).
This leads to an organized collection of signals in the bus, as shown by the Bus Creator dialog.
At its most basic level, you only need specify the number of inputs to your bus creator. The names of elements are derived from the signal names. Like the Mux Blocks, these bus creators have not changed the signals at all, so we can call them virtual.
It doesn’t end here
We are just starting to get into this topic. Next week we will talk about more advanced maneuvers with Mux and Demux Blocks, specifying interfaces with Bus Objects, and nonvirtual buses.
Now it’s your turn
How do you use bus and mux signals? What kinds of modeling questions about composite signals do you have? Care to share? Post a comment below. If you want to show off the complicated bus hierarchy from your model, e-mail me a picture of your bus and I’ll post it for you (image tags are stripped from comments).
When I started using Simulink, the libraries were organized a little differently than they are today. There were fewer blocks and no such thing as a Library Browser. Take a look at Simulink 1.3c from 1996.
This version was a little before my time. However, users of that era may remember it. When I joined The MathWorks in 1998, the Simulink 2 library looked like this.
The main challenge with Simulink 2 was screen real estate. In order to build a model, you had to open each of the sub-libraries in a new window. First, you would need a Signal Generator, so you open Sources. Next you need a Unit Delay, so you open the Discrete library. Then you need a Scope, so you open Sinks, yet another window. In a short time your desktop would look like this.
In the latter part of 1998 Simulink 3 was introduced. Along with it came the Library Browser on the PC. It was revolutionary because you didn't have to clutter your entire desktop with windows to get access to the blocks you needed. This made a real difference if all you had was an 800x600 pixel monitor.
Unfortunately users on non-Windows platforms were stuck with the old interface. Even Simulink developers who preferred Linux we relegated to the "old school" libraries. Luckily, screen sizes have continued to increase since the 90s.
R2008a
With the release of R2008a all platforms can now use the same Library Browser. Our Linux-loving Simulink developers can now use the same great Library Browser we have on the PC. The Library Browser has a new grid view in addition to the traditional list view.
Notice the search tab, item 1 in the diagram below. This is an improvement over the old version. When searching, you will now see all the results in one place rather than having to walk through the tree to view each match. The results are grouped by library and can be collapsed to simplify browsing (2). The search options (3) also allow for regular expressions.
The R2008a Library Browser has improved graphics and better performance compared with previous releases. The old version would redraw all blocks each time you viewed them, and in order to see the blocks in a library it had to be loaded into memory. The new browser uses caching to improve performance. The cache also enables faster searches without fully loading all libraries into memory. By the way, building the cache incurs a one time cost which you may notice the first time you start the Library Browser.
After seeing the new Library Browser, most people ask the same question:
But Seth, how do I add my library to the browser?
It has always been possible to add a library to Simulink, and you can read about it in the documentation. In order to add a library to the browser, create an slblocks.m file. You should store it in the directory with your library. I’m going to use the example library from a previous post. The most basic slblocks.m file looks like this:
function blkStruct = slblocks
%SLBLOCKS Defines a block library. % Library's name. The name appears in the Library Browser's % contents pane.
blkStruct.Name = ['A PID' sprintf('\n') 'Library'];
% The function that will be called when the user double-clicks on% the library's name.
blkStruct.OpenFcn = 'pidLibrary';
% The argument to be set as the Mask Display for the subsystem. You% may comment this line out if no specific mask is desired. % Example: blkStruct.MaskDisplay = 'plot([0:2*pi],sin([0:2*pi]));';
blkStruct.MaskDisplay = '';
% End of blocks
After creating the library, you will need to select Refresh Tree View from the Library Browser View menu.
It is also possible to specify multiple libraries within the same slblocks.m. I recommend looking at the other slblocks.m files on your path for examples.
>> which -all slblocks
A well-documented example is in $matlab/toolbox/simulink/blocks/slblocks.m. You can start by making a copy of that one and then edit it to reference your library.
Try it yourself
If you have never added a library, try making a library of your most commonly used components. Select File -> New -> Library from the Library Browser. Drag in your favorite blocks and add this to the Library Browser to increase your productivity.
Do you have custom libraries? Are they displayed in the Library Browser? Let me know in the comments.
I am eager for winter to release its icy grip on New England. Fortunately, change is in the air and spring is around the corner. At work, the big change is the new release of MATLAB. After installation I immediately notice the slight differences in the UI.
The new release of MATLAB and Simulink products went live for download at the beginning of this month. You can read about some of the changes to R2008a in the release notes. Here are some of my favorites:
Simulink has a new library browser available on all supported platforms! The graphics are smoother, and the search capabilities have been enhanced. Take a look:
The bus editor has been re-designed. The tree displayed in the left pane now shows the full bus hierarchy under each bus, instead of just the immediate child elements. I have been frustrated in the past when I forgot to save the changes to my bus objects back into a MAT-file for future sessions. The new editor now has load and save capabilities built in.
More simulation data can be logged on 64-Bit platforms. The limit is now up to 2^48-1 bytes (one byte shy of 256 TB!) in each field of the logging Structure, Timeseries or each Array variable! The limit on earlier releases is about 2 GB per variable.
New autosave options are available for Simulink models to help guard against loss of work.
There is a new zero crossing algorithm for use with the variable step solvers. The adaptive zero crossing mode better handles systems which exhibit chatter.
Over the next few months, as the spring flowers bloom (for those of us in the northern latitudes), I will highlight many of these new features.
These are some of my favorite enhancements to Simulink products. Have you activated your new copy of R2008a? What do you see in the release notes that you want to try out?
Here we have an example library consisting of masked subsystems.
sys = 'pidLibrary';
open_system(sys)
When you double click on a block, you get the mask dialog, and the Help button displays the MaskHelp if you click on it.
Some of these blocks are properly documented, but others have no MaskHelp. You could click through all the blocks in this library and click on the help button, but that would be a painful manual
process. How can you audit this library and ensure that the components are properly documented?
find_system
find_system is a very powerful tool for scripting in Simulink which allows you to automate tasks that might otherwise be time-consuming
to perform. The find_system syntax is very specific:
find_system takes a set of constraints ('c1', cv1, 'c2', cv2) and searches for blocks in the system (sys) that have the specified parameter values ('p1', v1, 'p2', v2). Notice that all constraint/value pairs are passed to find_systembefore the parameter/value pairs. This confused me once when I got the order wrong, so watch out for that.
Here is a quick find_system command that returns the right answer.
blksNoHelp =
'pidLibrary/Continuous PI
Controller'
'pidLibrary/Discrete PI
Controller'
It is important to be aware of the search constraint defaults.
SearchDepth is set to all levels, but this can be changed to 0 for only open systems, 1 to search only the specified system, 2 for that
system and its children, etc.
LookUnderMasks defaults to graphical only, which means find_system doesn’t look under functional masks (those with a dialog and workspace).
FollowLinks defaults to off, which means linked blocks are not searched. This is very important when the block might reside in a library linked from
your system.
FindAll defaults to off, which means you will only get blocks back from the search. The other option is to specify on and find_system will also return lines and annotations from the model.
CaseSensitive is on by default, so make sure your caps lock isn’t turned on. This constraint affects the value inputs only; parameters are not
treated as being case sensitive.
In our example, if we were also concerned with the contents of those masked blocks, we would need to expand our search to
LookUnderMasks. This search would then return Simulink base blocks because they do not use MaskHelp. To reduce the results to only those blocks that are masked, we can do a search where the Mask property is set to on.
blksNoHelp2 =
'pidLibrary/Continuous PI
Controller'
'pidLibrary/Discrete PI
Controller'
'pidLibrary/Discrete PID
Controller/Discrete Derivative'
Another reason constraints are so important is that the amount of work done by find_system is proportional to the number of blocks included in the search. If you are looking under all masks, following all links
and searching the full depth of the model hierarchy, the speed of the search will be proportional to the size of your model.
find_system is not a Simulink Google search that skips across indexed model information. When find_system is called it has to resolve all block parameters as it works. This means that you will evaluate all the dialog code and parameters
required by the search. To speed up find_system, include the appropriate constraints to reduce the number of blocks being evaluated.
Tip: Where ever possible include a SearchDepth to cast a small net.
Challenge
This got me thinking about how you might perform the inverse of this search. How would you find blocks that have MaskHelp without specifying the value it is set to? The first person to provide a correct answer in the comments gains fame and notoriety
as a find_system expert.
Did you already know how to use find_system? This is my second post and I’m looking for feedback on how much experience you have with Simulink. Post a comment and tell
me what you think.
Welcome to the MATLAB Central Simulink blog! The purpose of this blog is twofold: First, I want to share Simulink tips and
tricks that I've learned over the years. At the same time, I hope to learn from you about your experiences with Simulink.
Where is it good? How can we improve it?
I've been using Simulink for 9 years, first as a member of our technical support team, and then as a trainer. I still remember
when I first learned about the power of Simulink as a newly hired support engineer back in 1998. During a training class I
saw differential equations drawn on a whiteboard and then simulated with a few clicks of the mouse. I got excited by how clearly
it all worked. Simulink provided me with a framework for thinking about systems and the relationships between their basic
components.
Of course, Simulink is much more than a simple tool for solving differential equations. It has a richness and depth that will
give me plenty of material to draw on. What kind of topics can you expect to read about here? We'll talk about applications
of Simulink in controls, signal processing and communications system design. With your help, we'll talk about how Simulink
is used in areas I don't even know about yet. We'll talk about Model-Based Design in general, and we'll get a peek at some
of the internal machinery of Simulink. I look forward to posts about all of these:
solvers
sample times
modeling
hacks
blocks
model reference
libraries
masking
custom code
An example: batch simulation
Let me start off with a specific example about running simulations. Simulink models are built using block diagrams, and once
they've been created most everyone runs them by clicking the run button on the toolbar.
If you have to run a sweep of parameters you might change the parameter and then click run, change it again and click run.
But if you have to run hundreds or thousands of simulations while modifying a parameter you will want to write a script for
batch simulation. You can run simulations directly from MATLAB with the sim command like so.
>> [t,x,y] = sim(sys);
This returns the root level outputs (y) and the internal states of the model (x) at each recorded time step (t). A batch
script might look like this:
open_system('vdp_mu')
muSweep = .5:.1:1.5;
for i = 1:length(muSweep)
mu = muSweep(i);
[t,x,y] = sim('vdp_mu');
plot(t,y); hold on;
end
title('VDP States for mu=.5 to 1.5')
xlabel('Time'); legend('x1','x2')
If you are already familiar with the sim command, then you probably know that some times you are only interested in the outputs (y) of the model, and not the states
(x). For large models, or long simulations, those state variable outputs could be a waste of valuable memory. Using simset you can provide additional options to the sim command to specify that you only want time (t) and outputs (y). The state variable returned from sim will be empty.
That's your first Simulink tip. Now it's your turn. What do you like about Simulink? What would you like to talk about in
future posts? Please leave a comment below. I have learned from Doug that t-shirts get comments on your blog, so I'll be randomly selecting five commenters on this post to receive a MathWorks
t-shirt!
Recent Comments