Defining the interface of a software component, such as a C or MATLAB® code function or a Simulink® subsystem, is a key first step before others can use it, for these reasons:
Agreeing on an interface is a useful first step in deciding how to break down the functionality of a large system into subcomponents.
After you define interfaces between components, you can develop the components in parallel. If the interface remains stable, then it is easy to integrate those components into a larger system.
Changing the interface between components is expensive. It requires changes to at least two components (the source and any sinks) and to any test harnesses. It also makes all previous versions of those components incompatible with the current and future versions.
When you must change an interface, doing so is much easier if the components are stored under configuration management. You can track configurations of compatible component versions to prevent incompatible combinations of components.
Suggestions for defining the interfaces of components for a new project:
Base the boundaries of the components upon the boundaries of the corresponding real systems. This guideline is especially useful when the model contains:
Both physical (plant and environment) and control systems
Algorithms that run at different rates
Consider future model elaboration. If you intend to add models of sensors, then put them in from the start as an empty subsystem that passes signals straight through or performs a unit delay or name conversion.
Consider future component reuse.
Consider using a signal naming convention.
Use data objects for:
Defining component interfaces
Precise control over data attributes
Simplify interface design by grouping signals into buses. Buses are well suited for use at the high levels of models, where components often have many signals going in and out, and do not use all the signals available. Using buses can simplify modifying the interface to a component. For example, if you must add or remove signals used by a component, it can be simpler to modify a bus than to add or remove input or output ports to that component. However, using a bus that crosses model reference boundaries requires using a bus object.
Best practices for using Simulink buses and bus objects:
Make buses virtual, except for at model reference component boundaries.
Use nonvirtual buses when defining interfaces between components. A bus object must define each nonvirtual bus. Bus objects completely define the properties of the signals on a bus, giving an unambiguous interface definition.
Include bus objects in a data dictionary, or save bus objects
as a .mat
or .m
file, in
order to place them under revision control.
Pass only required signals to each component to reduce costly passing of unnecessary data. Signal buses allow the full set of input and output signals to be defined, but not necessarily used or created.
Make sure that the interface specifies exactly what the component uses.
Use a rigorous naming convention for bus objects. Unless you use a data dictionary, bus objects are stored in the base workspace.
At the lower levels of a model, consider using input and output ports for each signal. At lower levels of a model, where components typically implement algorithms rather than serve as containers for other components, it can increase readability if you use individual input and output ports for components, instead of using signal buses. However, creating interfaces in this way has a greater risk of connection problems, because it is difficult to check the validity of connections, other than their data type, size, etc.
To package signals or parameters into structures that
correspond to a struct
type definition that
your external C code defines, import the type as a bus object
and use the object as a data type for buses and MATLAB structures. To create the object, use the
Simulink.importExternalCTypes
function.
Explicitly control the scope of data for your components. Some techniques:
Global parameters — A common approach in the automotive world is to completely separate the problem of parameter storage from model storage. The parameters for a model come from a database of calibration data, and the specific calibration file used becomes part of the configuration. The calibration data is treated as global data, and resides in the base MATLAB workspace. You can migrate base workspace data to a data dictionary for more control.
Nonglobal parameters — Combining components that store their own parameter data has the risk of parameter name collisions. If you do not use a naming convention for parameters or, alternatively, a list of unique parameter names and definitions, then there is the risk that two components use a parameter with the same name but with different meanings.
Methods for storing local parameter data include:
Partition data into reference dictionaries for each component.
For referenced models, you can use model workspaces.
Use parameter files (.m
or
.mat
) and callbacks of the individual
Simulink models (e.g., preload
function).
You can also automatically load required data using project shortcuts.
Mask workspaces, with or without the use of mask initialization functions.
For subsystems, you can control the scope of data for a subsystem using the Subsystem Parameters, Permit Hierarchical Resolution dialog box.
Whether you use referenced models or subsystems to break a large system into components, the components can exchange signal data through Inport and Outport blocks. You can explicitly configure design attributes (such as data type and numeric complexity) of the interface to prevent modeling errors and make integrating the components easier.
After you create the Inport and Outport blocks, you can use the Model Data Editor and the interface display to configure the design attributes (such as data type and numeric complexity) of the blocks. Use this technique to view the component interface in its entirety at once and to trace the pieces of the interface to usage points in the internal block algorithm. You can also use this technique to configure the interface of a component before you develop the internal algorithm, in which case the component contains unconnected Inport and Outport blocks.
The example model sldemo_fuelsys_dd
contains two components
which are referenced models:
A plant component, sldemo_fuelsys_dd_plant
.
A controller component,
sldemo_fuelsys_dd_controller
.
Use the Model Data Editor and the interface display to examine and configure the interface of the plant component.
Open the plant component.
sldemo_fuelsys_dd_plant
On the Modeling tab, under Design, click Model Interface.
On the Modeling tab, click Model Data Editor.
By default, in the Model Data Editor, the
Inports/Outports tab is selected. Each row in
the table represents an Inport or Outport
block. By default, the Change view drop-down list
is set to Design
.
Tip
To view only the Inport and Outport blocks at the root level of the model (by excluding the blocks inside the subsystems), deactivate the Change Scope button.
Use the columns in the Model Data Editor to explicitly configure the design attributes of the interface. For example, specify minimum and maximum values for each Inport and Outport block by using the Min and Max columns.
To configure code generation settings for the interface of a controller component,
in the Model Data Editor, set the Change view drop-down list to
Code
.
For more information about using the interface display, see Trace Connections Using Interface Display. For more information about the Model Data Editor, see Configure Data Properties by Using the Model Data Editor.