Organize Related Block Parameter Definitions in Structures
When you use numeric MATLAB® variables to set block parameter values in a model, large models can accumulate many variables, increasing the effort of maintenance and causing the variable names to grow in length.
Instead, you can organize these parameter values into structures. Each structure is a single variable and each field of the structure stores a numeric parameter value. You can assign meaningful names to the structures, substructures, and fields to indicate the purpose of each value.
Use structures to:
Reduce the number of workspace variables that you must maintain.
Avoid name conflicts between workspace variables.
You cannot create two variables that have the same name in the same scope, such as in the base workspace. When you create structures, you must provide each field a name, but multiple structures can each contain a field that uses the same name. Therefore, you can use each structure and substructure as a namespace that prevents the field names from conflicting with each other and with other variable names in the same scope.
Logically group sets of block parameter values. For example, use nested structures to clearly identify the parameter values that each subsystem or referenced model uses.
If you use mask parameters or model arguments to pass parameter values to the components of a system, you can use structures to reduce the number of individual mask parameters or model arguments that you must maintain. Instead of passing multiple variables, you can pass a single structure variable.
For basic information about creating and manipulating MATLAB structures, see Structures. For basic information about setting block parameter values in a model, see Set Block Parameter Values.
To use structures to initialize bus signals, see Specify Initial Conditions for Bus Elements.
Create and Use Parameter Structure
This example shows how to create and use a parameter structure in a model.
The example model f14
uses multiple variables
from the base workspace to set block parameter values. For example,
when you open the model, it creates the variables Zw
, Mw
,
and Mq
in the base workspace. To organize these
variables into a single structure variable:
At the command prompt, open the example model.
f14
At the command prompt, create the parameter structure
myGains
. Set the field values by using the values of the target variables.myGains.Zw = Zw; myGains.Mw = Mw; myGains.Mq = Mq;
In the Model Explorer, on the Model Hierarchy pane, click Base Workspace. In the Contents pane, right-click the variable
Mq
and select Find Where Used.In the Select a system dialog box, click the node f14 and click OK. Click OK when asked about updating the diagram.
In the Contents pane, right-click the row corresponding to the block labeled Gain1 and select Properties. The Gain1 block dialog box opens.
Change the value of the Gain parameter from
Mq
tomyGains.Mq
and click OK.In the Contents pane, right-click the row corresponding to the Transfer Fcn.1 block and select Properties.
Change the value of the Denominator coefficients parameter from
[1,-Mq]
to[1,-myGains.Mq]
and click OK.In the Model Hierarchy pane, click Base Workspace. Use Find Where Used to locate the blocks that use the variables
Mw
andZw
. In the block dialog boxes, replace the references to the variable names according to the table.Variable Name Replacement Name Mw
myGains.Mw
Zw
myGains.Zw
Clear the old variables.
clear Zw Mw Mq
Each of the modified block parameters now uses a field of the myGains
structure.
The numeric value of each structure field is equal to the value of
the corresponding variable that you cleared.
You can migrate a model to use a single parameter structure instead of multiple workspace variables.
Store Data Type Information in Field Values
To use a structure or array of structures to organize parameter
values that use a data type other than double
,
you can explicitly specify the type when you create the structure.
When you create the structure, use typed expressions such as single(15.23)
to
specify the field values.
myParams.Gain = single(15.23);
If you want to change the field value later, you must remember
to explicitly specify the type again. If you do not specify the type,
the field value uses the data type double
instead:
myParams.Gain = 15.23;
% The field 'Gain' now uses the data type 'double' instead of 'single'.
To preserve the type specification, you can use subscripted assignment to assign a new value to the field:
% Assign value of type 'single'. myParams.Gain = single(15.23); % Assign new value while retaining type 'single'. myParams.Gain(:) = 11.79;
To match a fixed-point data type, set the field value by using
an fi
(Fixed-Point Designer) object.
Control Field Data Types and Characteristics by Creating Parameter Object
A Simulink.Parameter
object allows you to separate the value of a block
parameter from its data type. If you use a parameter object to store a structure or
array of structures, you can create a Simulink.Bus
object to use as the data type of the entire structure.
You can use the bus object and the parameter object to explicitly control:
The data type of each field. When you use this technique, you do not have to remember to use typed expressions or subscripted assignment to set the field values.
The complexity, dimensions, and units of each field.
The minimum and maximum value of each field if the field represents a tunable parameter value.
The shape of the entire structure. The shape of the structure is the number, names, and hierarchy of fields.
The tunability of the structure in the code that you generate from the model.
Create a parameter structure
myParams
.myParams = struct(... 'SubsystemA',struct(... 'Gain',15.23,... 'Offset',89,... 'Init',0.59),... 'SubsystemB',struct(... 'Coeffs',[5.32 7.99],... 'Offset',57,... 'Init1',1.76,... 'Init2',2.76)... );
Use the function
Simulink.Bus.createObject
to createSimulink.Bus
objects that represent the structure and substructures.Simulink.Bus.createObject(myParams)
Because
myParams
contains two unique substructures, the function creates threeSimulink.Bus
objects: one namedslBus1
to represent the parent structuremyParams
, one namedSubsystemA
for the substructureSubsystemA
, and one namedSubsystemB
for the substructureSubsystemB
.Rename the bus object
slBus1
asmyParamsType
.myParamsType = slBus1; clear slBus1
Store the structure
myParams
in aSimulink.Parameter
object.myParams = Simulink.Parameter(myParams);
The
Value
property of the parameter object contains the structure.Set the data type of the parameter object to the bus object
myParamsType
.myParams.DataType = 'Bus: myParamsType';
Open the Type Editor to view the bus objects.
typeeditor
In the table, expand the bus object named
SubsystemA
. Then, set the data types according to the figure.Optionally, change the data types for the bus object named
SubsystemB
.
The parameter object myParams
stores the
parameter structure. The data type of the parameter object is the
bus object myParamsType
. Prior to simulation and
code generation, the parameter object casts the field values to the
data types that you specified in the bus object.
To use one of the fields to set a block parameter value, specify
an expression such as myParams.SubsystemB.Init1
.
To access the field values at the command prompt, use the Value
property
of the parameter object. Because the bus object controls the field
data types, you do not need to use a typed expression to set the field
value.
myParams.Value.SubsystemA.Gain = 12.79;
The bus object strictly controls the field characteristics and
the shape of the structure. For example, if you set the value of the
two-element field myParams.SubsystemB.Coeffs
to
a three-element array, the model generates an error when you set a
block parameter value. To change the dimensions of the field, modify
the element Coeffs
in the bus object SubsystemB
.
To manipulate bus objects after you create them, see Create Simulink Bus Objects and Save Simulink Bus Objects.
Match Field Data Type with Signal Data Type
Suppose that you use the field myParams.SubsystemA.Gain
to set the value of
the Gain parameter in a Gain block. If you want the
data type of the field to match the data type of the output signal of the block, you
cannot rely on context-sensitive data typing (see Context-Sensitive Data Typing).
Consider using a Simulink.AliasType
or a
Simulink.NumericType
object to set the data type of the field and the
signal. If you do not use a data type object, you must remember to change the data type of
the field whenever you change the data type of the signal.
In the MATLAB Command Window, create a
Simulink.AliasType
object that represents the data typesingle
.myType = Simulink.AliasType; myType.BaseType = 'single';
In the Gain block dialog box, on the Signal Attributes tab, set Output data type to
myType
.In the MATLAB Command Window, open the Type Editor.
typeeditor
Select the bus object named
SubsystemA
. Then, set the data type of the element namedGain
tomyType
.
Now, both the output signal of the Gain block
and the structure field myParams.SubsystemA.Gain
use
the data type that you specify by using the BaseType
property
of myType
.
For more information about data type objects, see Simulink.AliasType
and Simulink.NumericType
.
Manage Structure Variables
To create, modify, and inspect a variable whose value is a structure, you can use the Variable Editor. For more information, see Modify Structure and Array Variables Interactively.
Define Parameter Hierarchy by Creating Nested Structures
To further organize block parameter values, create a hierarchy of nested structures.
For example, suppose that you create subsystems named SubsystemA
and SubsystemB
in
your model. You use variables such as Offset_SubsystemA
and Offset_SubsystemB
to
set block parameter values in the subsystems.
Gain_SubsystemA = 15.23; Offset_SubsystemA = 89; Init_SubsystemA = 0.59; Coeffs_SubsystemB = [5.32 7.99]; Offset_SubsystemB = 57; Init1_SubsystemB = 1.76; Init2_SubsystemB = 2.76;
Create a parameter structure that contains a substructure for each subsystem. Use the values of the existing variables to set the field values.
myParams = struct(... 'SubsystemA',struct(... 'Gain',Gain_SubsystemA,... 'Offset',Offset_SubsystemA,... 'Init',Init_SubsystemA),... 'SubsystemB',struct(... 'Coeffs',Coeffs_SubsystemB,... 'Offset',Offset_SubsystemB,... 'Init1',Init1_SubsystemB,... 'Init2',Init2_SubsystemB)... );
The single structure variable myParams
contains
all of the parameter information for the blocks in the subsystems.
Because each substructure acts as a namespace, you can define the Offset
field
more than once.
To use the Offset
field from the substructure SubsystemB
as
the value of a block parameter, specify the parameter value in the
block dialog box as the expression myParams.SubsystemB.Offset
.
Group Multiple Parameter Structures into an Array
To organize parameter structures that have similar characteristics, you can create a single variable whose value is an array of structures. This technique helps you to parameterize a model that contains multiple instances of an algorithm, such as a library subsystem or a referenced model that uses model arguments.
Suppose that you create two identical subsystems in a model.
Suppose that the blocks in each subsystem require three numeric values to set parameter values. Create an array of two structures to store the values.
myParams(1).Gain = 15.23; myParams(1).Offset = 89; myParams(1).Init = 0.59; myParams(2).Gain = 11.93; myParams(2).Offset = 57; myParams(2).Init = 2.76;
Each structure in the array stores the three parameter values for one of the subsystems.
To set the value of a block parameter in one of the subsystems,
specify an expression that references a field of one of the structures
in the array. For example, use the expression myParams(2).Init
.
Organize Parameter Values for Reusable Components and Iterative Algorithms
You can also partition an array of structures in a For Each Subsystem block. This technique helps you to organize workspace variables when a model executes an algorithm repeatedly, for example by iterating the algorithm over a vector signal. For an example, see Repeat an Algorithm Using a For-Each Subsystem.
If you use model arguments to specify different parameter values across multiple instances of a referenced model, you can use arrays of structures to organize the model argument values. In the referenced model workspace, create a structure variable and configure the model to use the structure as a model argument. Use the fields of the structure to set block parameter values in the model. Then, create an array of structures in the base workspace or a data dictionary to which the parent model or models are linked. In the parent model or models, use each of the structures in the array as the value of the model argument in a Model block. Each structure in the array stores the parameter values for one instance of the referenced model.
For example, consider a model that contains three instances (Model blocks) of a
masked referenced model. The base workspace variables IC1
,
IC2
, Param1
, and
Param2
are Simulink.Parameter
objects
whose values are structures. The parent model uses these variables to set the
values of mask parameters on the Model blocks. Since
IC1
is structurally identical to IC2
,
and Param1
to Param2
, you can combine
these four structures into two arrays of structures.
The parent model creates the four Simulink.Parameter
objects
in the base workspace. In the referenced model, the model workspace defines two
model arguments, CounterICs
and
CounterParams
, whose values are structures. The blocks in
the model use the fields of these structures to set parameter values.
For this case, you can combine the four parameter objects into two parameter objects whose values are arrays of structures.
% Create a new parameter object by copying Param1. Param = Param1.copy; % Use the structure in Param2 as the second structure in the new object. Param.Value(2) = Param2.Value; % The value of Param is now an array of two structures. % Delete the old objects Param1 and Param2. clear Param1 Param2 % Create a new parameter object by copying IC1. % Use the structure in IC2 as the second structure in the new object. IC = IC1.copy; IC.Value(2) = IC2.Value; clear IC1 IC2
In the parent model, you can now replace the values of the mask parameters according to the table.
Previous Value | New Value |
---|---|
Param1 | Param(1) |
IC1 | IC(1) |
Param2 | Param(2) |
IC2 | IC(2) |
Each Model block sets the value of the model
argument CounterICs
by using one of the structures
in the array IC
. Similarly, each block sets the
value of CounterParams
by using one of the structures
in Param
.
Enforce Uniformity in an Array of Structures
All of the structures in an array of structures must have the same hierarchy of fields. Each field in the hierarchy must have the same characteristics throughout the array. You can use a parameter object and a bus object to enforce this uniformity among the structures.
To use a parameter object to represent an array of parameter structures, set the value of the object to the array of structures:
% Create array of structures. myParams(1).Gain = 15.23; myParams(1).Offset = 89; myParams(1).Init = 0.59; myParams(2).Gain = 11.93; myParams(2).Offset = 57; myParams(2).Init = 2.76; % Create bus object. Simulink.Bus.createObject(myParams); myParamsType = slBus1; clear slBus1 % Create parameter object and set data type. myParams = Simulink.Parameter(myParams); myParams.DataType = 'Bus: myParamsType';
To use one of the fields to set a block parameter value, specify
an expression such as myParams(2).Offset
.
To access the field values at the command prompt, use the Value
property
of the parameter object.
myParams.Value(2).Offset = 129;
Create a Structure of Constant-Valued Signals
You can use a structure in a Constant block to create a single bus that transmits multiple numeric constants. For more information, see Constant. For information about buses, see Composite Interface Guidelines.
Considerations Before Migrating to Parameter Structures
Before you migrate a model to use parameter structures, discover all of the blocks in the target model and in other models that use the variables that you intend to replace.
For example, suppose two blocks in a model use the workspace variable
myVar
. If you create a structuremyParams
with a fieldmyVar
, and set the parameter value in only one of the blocks tomyParams.myVar
, the other block continues to use the variablemyVar
. If you deletemyVar
, the model generates an error because the remaining block requires the deleted variable.To discover all of the blocks that use a variable:
Open all models that might use the variable. If the models are in a model reference hierarchy, you can open only the top model.
In the Model Data Editor or in the Model Explorer Contents pane, right-click the variable and select Find Where Used. The Model Explorer displays all of the blocks that use the variable.
You can discover variable usage only in models that are open. Before you migrate to parameter structures, open all models that might use the target variables. For more information about determining variable usage in a model, see Finding Blocks That Use a Specific Variable.
Alternatively, you can refrain from deleting
myVar
. However, if you change the value of themyParams.myVar
structure field, you must remember to change the value ofmyVar
to match.You can combine multiple separate variables or parameter objects (such as
Simulink.Parameter
) into a structure that you store in a single variable or parameter object (to combine parameter objects, see Combine Existing Parameter Objects into a Structure). However, the resulting variable or object acts as a single entity. As a result, you cannot apply different code generation settings, such as storage classes, to individual fields in the structure.
Combine Existing Parameter Objects into a Structure
When you use parameter objects to set block parameter values (for example, so you can apply storage classes), to combine the objects into a single structure:
Create a MATLAB structure and store it in a variable. To set the field values, use the parameter values that each existing parameter object stores.
Convert the variable to a parameter object. Create and use a
Simulink.Bus
object as the data type of the parameter object (see Control Field Data Types and Characteristics by Creating Parameter Object).Choose a storage class to apply to the resulting parameter object. You can choose only one storage class, which applies to the entire structure.
Transfer parameter metadata, such as the
Min
andMax
properties of the existing parameter objects, to the corresponding properties of theSimulink.BusElement
objects in the bus object.
For example, suppose you have three individual parameter objects.
coeff = Simulink.Parameter(17.5); coeff.Min = 14.33; coeff.DataType = 'single'; coeff.StorageClass = 'ExportedGlobal'; init = Simulink.Parameter(0.00938); init.Min = -0.005; init.Max = 0.103; init.DataType = 'single'; init.StorageClass = 'Model default'; offset = Simulink.Parameter(199); offset.DataType = 'uint8'; offset.StorageClass = 'ExportedGlobal';
Create a structure variable.
myParams.coeff = coeff.Value; myParams.init = init.Value; myParams.offset = offset.Value;
Convert the variable to a parameter object.
myParams = Simulink.Parameter(myParams);
Create a bus object and use it as the data type of the parameter object.
Simulink.Bus.createObject(myParams.Value); paramsDT = copy(slBus1); myParams.DataType = 'Bus: paramsDT';
Transfer metadata from the old parameter objects to the bus elements in the bus object.
% coeff paramsDT.Elements(1).Min = coeff.Min; paramsDT.Elements(1).DataType = coeff.DataType; % init paramsDT.Elements(2).Min = init.Min; paramsDT.Elements(2).Max = init.Max; paramsDT.Elements(2).DataType = init.DataType; % offset paramsDT.Elements(3).DataType = offset.DataType;
To help you write a script that performs this transfer operation, you can use the
properties
function to find the properties that the bus elements and the old parameter objects have in common. To list the structure fields so that you can iterate over them, use thefieldnames
function.Apply a storage class to the parameter object.
myParams.StorageClass = 'ExportedGlobal';
Now, you can use the fields of myParams
, instead
of the old parameter objects, to set the block parameter values.
Parameter Structures in the Generated Code
You can configure parameter structures to appear in the generated code as structures and arrays of structures. For information about generating code with parameter structures, see Organize Data into Structures in Generated Code (Simulink Coder).
Parameter Structure Limitations
All of the structures in an array of structures must have the same hierarchy of fields. Each field in the hierarchy must have the same characteristics throughout the array:
Field name
Numeric data type, such as
single
orint32
Complexity
Dimensions
Suppose that you define an array of two structures.
paramStructArray = ... [struct('sensor1',int16(7),'sensor2',single(9.23)) ... struct('sensor1',int32(9),'sensor2',single(11.71))];
You cannot use any of the fields in a block parameter because the field
sensor1
uses a different data type in each structure.Parameter structures do not support context-sensitive data typing in the generated code. If the parameter structure is tunable in the code, the fields of the structure use the numeric data types that you specify by using either typed expressions or a
Simulink.Bus
object. If you do not use typed expressions or aSimulink.Bus
object, the fields of the structure use thedouble
data type.The code generator does not preserve the tunability of a structure if the structure or any of its substructures has a field with an empty value (set to
[]
).
Package Shared Breakpoint and Table Data for Lookup Tables
When you share data between lookup table blocks, consider using Simulink.LookupTable
and Simulink.Breakpoint
objects
instead of structures to store and group the data. This technique
improves model readability by clearly identifying the data as parts
of a lookup table and explicitly associating breakpoint data with
table data. See Package Shared Breakpoint and Table Data for Lookup Tables.
Create Parameter Structure According to Structure Type from Existing C Code
You can create a parameter structure that conforms to a struct
type
definition that your existing C code defines. Use this technique to:
Replace existing C code with a Simulink® model.
Integrate existing C code for simulation in Simulink (for example, by using the Legacy Code Tool). For an example, see Integrate C Function Whose Arguments Are Pointers to Structures.
Generate C code (Simulink Coder™) that you can compile with existing C code into a single application. For an example, see Exchange Structured and Enumerated Data Between Generated and External Code (Embedded Coder).
In MATLAB, store the parameter structure in a parameter
object and use a bus object as the data type (see Control Field Data Types and Characteristics by Creating Parameter Object).
To create the bus object according to your C-code struct
type,
use the Simulink.importExternalCTypes
function.