Main Content

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:

  1. At the command prompt, open the example model.

    f14

  2. 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;

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

  4. In the Select a system dialog box, click the node f14 and click OK. Click OK when asked about updating the diagram.

  5. In the Contents pane, right-click the row corresponding to the block labeled Gain1 and select Properties. The Gain1 block dialog box opens.

  6. Change the value of the Gain parameter from Mq to myGains.Mq and click OK.

  7. In the Contents pane, right-click the row corresponding to the Transfer Fcn.1 block and select Properties.

  8. Change the value of the Denominator coefficients parameter from [1,-Mq] to [1,-myGains.Mq] and click OK.

  9. In the Model Hierarchy pane, click Base Workspace. Use Find Where Used to locate the blocks that use the variables Mw and Zw. In the block dialog boxes, replace the references to the variable names according to the table.

    Variable NameReplacement Name
    MwmyGains.Mw
    ZwmyGains.Zw

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

  1. 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)...
    );

  2. Use the function Simulink.Bus.createObject to create Simulink.Bus objects that represent the structure and substructures.

    Simulink.Bus.createObject(myParams)
    

    Because myParams contains two unique substructures, the function creates three Simulink.Bus objects: one named slBus1 to represent the parent structure myParams, one named SubsystemA for the substructure SubsystemA, and one named SubsystemB for the substructure SubsystemB.

  3. Rename the bus object slBus1 as myParamsType.

    myParamsType = slBus1;
    clear slBus1

  4. Store the structure myParams in a Simulink.Parameter object.

    myParams = Simulink.Parameter(myParams);

    The Value property of the parameter object contains the structure.

  5. Set the data type of the parameter object to the bus object myParamsType.

    myParams.DataType = 'Bus: myParamsType';

  6. Open the Type Editor to view the bus objects.

    typeeditor

  7. In the table, expand the bus object named SubsystemA. Then, set the data types according to the figure.

    The Bus object named SubsystemA contains three elements: Gain (single), Offset (int8), and Init (single).

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

  1. In the MATLAB Command Window, create a Simulink.AliasType object that represents the data type single.

    myType = Simulink.AliasType;
    myType.BaseType = 'single';

  2. In the Gain block dialog box, on the Signal Attributes tab, set Output data type to myType.

  3. In the MATLAB Command Window, open the Type Editor.

    typeeditor

  4. Select the bus object named SubsystemA. Then, set the data type of the element named Gain to myType.

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.

The model sldemo_mdlref_datamngt contains three instances (Model blocks) of the masked referenced model sldemo_mdlref_counter_datamngt. 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.

  1. Open the example parent model.

    openExample('sldemo_mdlref_datamngt')

    The model creates the four Simulink.Parameter objects in the base workspace.

  2. Open the example referenced model.

    sldemo_mdlref_counter_datamngt

    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.

  3. In the model sldemo_mdlref_datamngt, open the Model Data Editor (on the Modeling tab, click Model Data Editor). In the Model Data Editor, inspect the Parameters tab.

  4. In the model, click one of the Model blocks.

    The Model Data Editor highlights rows that correspond to two mask parameters on the selected Model block. The block uses the mask parameters to set the values of the two model arguments defined by the referenced model, sldemo_mdlref_counter_datamngt. Each Model block uses a different combination of the four parameter objects from the base workspace to set the argument values.

  5. In the Model Data Editor Value column, click one of the cells to begin editing the value of the corresponding mask parameter (for example, IC1). Next to the parameter value, click the action button and select Open. The property dialog box for the parameter object opens.

  6. In the property dialog box, next to the Value box, click the action button and select Open Variable Editor.

    The Variable Editor shows that the parameter object stores a structure. The structures in Param2 and IC2 have the same fields as the structures in Param1 and IC1 but different field values.

  7. At the command prompt, 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

  8. In the parent model, in the Model Data Editor, use the Value column to replace the values of the mask parameters according to the table

    Previous ValueNew Value
    Param1Param(1)
    IC1IC(1)
    Param2Param(2)
    IC2IC(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 structure myParams with a field myVar, and set the parameter value in only one of the blocks to myParams.myVar, the other block continues to use the variable myVar. If you delete myVar, the model generates an error because the remaining block requires the deleted variable.

    To discover all of the blocks that use a variable:

    1. Open all models that might use the variable. If the models are in a model reference hierarchy, you can open only the top model.

    2. 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 the myParams.myVar structure field, you must remember to change the value of myVar 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:

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

  2. 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).

  3. Choose a storage class to apply to the resulting parameter object. You can choose only one storage class, which applies to the entire structure.

  4. Transfer parameter metadata, such as the Min and Max properties of the existing parameter objects, to the corresponding properties of the Simulink.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';

  1. Create a structure variable.

    myParams.coeff = coeff.Value;
    myParams.init = init.Value;
    myParams.offset = offset.Value;

  2. Convert the variable to a parameter object.

    myParams = Simulink.Parameter(myParams);

  3. 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';

  4. 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 the fieldnames function.

  5. 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 or int32

    • 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 a Simulink.Bus object, the fields of the structure use the double 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:

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.

Related Topics