Implement Symbolic Dimensions for Array Sizes in Generated Code
Symbolic Dimension Variants
Use symbolic dimension variants to simulate various sets of dimension choices without regenerating code for every set. Set up your model with dimensions that you specify as symbols in blocks and data objects. These symbols propagate throughout the model during simulation, and then go into the generated code. Modeling constraints for symbols during simulation (for example, C=A+B
) are output as preprocessor conditionals in either the model.h
or the model
_
types.h
file.
You can directly specify dimension information as a symbol or a numeric constant for these blocks and data objects:
Inport
Outport
Signal Specification
Data Store Memory
Interpreted MATLAB® Function
Simulink.Signal
Simulink.Parameter
Simulink.BusElement
Simulink.LookupTable
Simulink.Breakpoint
AUTOSAR.Parameter
The Data Store Memory and Interpreted MATLAB Function blocks also support variable dimension signals. For these blocks, the symbolic dimensions control the maximum allowed size.
You must provide the initialization code for Simulink.Parameter
objects that contain symbolic dimension variants. To prevent the generated code from initializing these parameters, you must either:
Configure the parameters to use a storage class with the Data scope property set to
Imported
, such as theImportedExtern
orImportedExternPointer
built-in storage classes.Configure the parameters to use a storage class with the Data initialization property set to
None
.
You use Simulink.Parameter
objects to specify dimension information as symbols. For more information on signal dimensions, see Determine Signal Dimensions.
You must fix symbolic dimension values at compile-time. You can not resolve a symbolic dimension to another variable and then vary it during run-time because you define the behavior during simulation.
Note: The dimension variants feature is on by default. You can turn off this feature by clearing the Allow symbolic dimension specification parameter in the Configuration Parameters dialog box.
Define Symbolic Dimensions
This example uses the model DimensionVariants
to show how to implement symbolic dimensions. This model has four modeling patterns involving vectors and matrices.
To show block names, on the Debug tab, on the Information Overlays menu, clear the Hide Automatic Block Names parameter.
Open the Embedded Coder app. In the C Code tab, select Code Interface > Individual Element Code Mappings.
In the Code Mappings editor, on the Parameters tab, click the refresh button. Seven
Simulink.Parameter
objects appear. Four of these objects are for specifying symbolic dimensions. TheseSimulink.Parameter
objects have the namesA
,B
,C
, andD
. Notice that these parameters have a storage class ofCompilerFlag
.
To use a Simulink.Parameter
object for dimension specification, it must be defined in the base workspace and have one of these storage classes:
Define
orImportedDefine
with header file specifiedCompilerFlag
User-defined custom storage class that defines data as a macro in a specified header file
For Simulink.Parameter
objects with an ImportedDefine
custom storage class, provide a header file on the MATLAB path. Insert the name of the header file in the HeaderFile field in the Simulink.Parameter dialog box.
You can use MATLAB expressions to specify symbolic dimensions. For a list of supported MATLAB expressions, see the section Operators and Operands in Variant Condition Expressions in Introduction to Variant Controls.
Specify Symbolic Dimensions for Blocks and Data Objects
Click Inport Block
In2
. On the Property Inspector, on the Parameters tab, the Port Dimensions field contains theSimulink.Parameter
objectA
. For Inport blocks, you specify symbolic dimensions in the Port Dimensions field.Click Inport block
In3
. The Port Dimensions field contains theSimulink.Parameter
objectB
.Click the Constant block. The Constant value parameter has a value of
Data
. In the Code Mappings editor, on the Parameters tab, click theSimulink.Parameter
objectData
. On the Property Inspector, the Dimension field has the character vector'[1,C]'
, which is equivalent to'[1,5]'
becauseC
has a value of5
. The Value field contains an array with5
values, which is consistent with its dimensions. The dimensions of the data object must be consistent with the value of theSimulink.Parameter
object that is in the Dimensions field. Notice thatData
has a Storage class ofImportedExtern
.Open the
1-D Lookup Table1
block parameters dialog box. The Table data field contains theSimulink.Parameter
,PT
. The Breakpoints 1 field contains theSimulink.Parameter
,PB
.In the Code Mappings editor, click
PB
andPT
and view their properties. These parameters contain the character vector'[1,D]'
in their Dimensions field and are arrays consisting of 15 values. The value ofD
is consistent with the dimension of thePB
andPT
parameters becauseD
has a value of15
.Simulate the model. Simulink® propagates the dimensions symbolically in the diagram. During propagation, Simulink establishes modeling constraints among symbols. Simulink then checks for consistency with these constraints based on current numerical assignments. One modeling constraint for
DimensionVariants
is thatC=A+B
. The Diagnostic Viewer produces a warning for any violations of constraints.Change the dimension specification to a different configuration and simulate the model again.
Though not shown in this example, you can specify an n-D dimension expression with one or more of the dimensions being a symbol (for example, '[A,B,C]'
or '[1,A,3]'
). To preserve multi-dimensional information, you must specify an n-D dimension expression with each dimension that you want to preserve being a symbol.
Generate Code for a Model with Symbolic Dimension Variants
Once you have verified dimension specifications through model simulation, generate code for DimensionVariants
.
Build the model.
model = 'DimensionVariants';
slbuild(model)
### Starting build procedure for: DimensionVariants ### Successful completion of build procedure for: DimensionVariants Build Summary Top model targets built: Model Action Rebuild Reason =================================================================================================== DimensionVariants Code generated and compiled. Code generation information file does not exist. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 15.189s
View the generated code. In the variants_importedmacros.h
file, symbolic dimensions are in data declarations.
hfile = fullfile('DimensionVariants_ert_rtw',... 'DimensionVariants.h'); coder.example.extractLines(hfile,'/* External inputs', '/* Real-time', 1, 0);
/* External inputs (root inport signals with default storage) */ typedef struct { real_T In2[A]; /* '<Root>/In2' */ real_T In3[B]; /* '<Root>/In3' */ } ExtU; /* External outputs (root outports fed by signals with default storage) */ typedef struct { real_T Out1[(A + B)]; /* '<Root>/Out1' */ real_T Out2[(A + B)]; /* '<Root>/Out2' */ } ExtY;
The DimensionVariants.h
file contains data definitions and preprocessor conditionals that define constraints established among the symbols during simulation. One of these constraints is that the value of a symbolic dimension must be greater than 1
. This file also includes the user-provided header file for any Simulink.Parameter
objects with an ImportedDefine
custom storage class.
hfile = fullfile('DimensionVariants_ert_rtw',... 'DimensionVariants.h'); coder.example.extractLines(hfile,'#ifndef A', '/* Macros for accessing', 1, 0);
#ifndef A #error The value of parameter "A" is not defined #endif #ifndef B #error The value of parameter "B" is not defined #endif #ifndef C #error The value of parameter "C" is not defined #endif #ifndef D #error The value of parameter "D" is not defined #endif /* * Constraints for division operations in dimension variants */ #if (1 == 0) || (((A+B) % 1) != 0) # error "The preprocessor definition '1' must not be equal to zero and the division of '(A+B)' by '1' must not have a remainder." #endif /* * Registered constraints for dimension variants */ /* Constraint 'C == (A+B)' registered by: * '<Root>/1-D Lookup Table1' */ #if C != (A+B) # error "The preprocessor definition 'C' must be equal to '(A+B)'" #endif #if A <= 1 # error "The preprocessor definition 'A' must be greater than '1'" #endif #if B <= 1 # error "The preprocessor definition 'B' must be greater than '1'" #endif /* Constraint 'D > 1' registered by: * '<Root>/1-D Lookup Table1' */ #if D <= 1 # error "The preprocessor definition 'D' must be greater than '1'" #endif /* Constraint 'C > 3' registered by: * '<S2>/Assignment' */ #if C <= 3 # error "The preprocessor definition 'C' must be greater than '3'" #endif #if A >= 11 # error "The preprocessor definition 'A' must be less than '11'" #endif #if B >= 11 # error "The preprocessor definition 'B' must be less than '11'" #endif /* Constraint 'D < 21' registered by: * '<Root>/1-D Lookup Table1' */ #if D >= 21 # error "The preprocessor definition 'D' must be less than '21'" #endif /* Constraint 'C < 11' registered by: * '<S2>/Assignment' */ #if C >= 11 # error "The preprocessor definition 'C' must be less than '11'" #endif
In the DimensionVariants.c
file, symbolic dimensions participate in loop bound calculations, array size and index offset calculations, and a parameterized utility function (for example, Lookup Table block) calculation.
cfile = fullfile('DimensionVariants_ert_rtw',... 'DimensionVariants.c'); coder.example.extractLines(cfile,'/* Model step', '/* Model initialize', 1, 0);
/* Model step function */ void DimensionVariants_step(void) { real_T rtb_VectorConcatenate[A + B]; real_T rtb_VectorConcatenate_0; int32_T ForEach_itr; int32_T i; int32_T s2_iter; /* Gain: '<Root>/Gain' incorporates: * Inport: '<Root>/In2' */ for (ForEach_itr = 0; ForEach_itr <= (int32_T)(A - 1); ForEach_itr++) { rtb_VectorConcatenate[ForEach_itr] = 2.0 * rtU.In2[ForEach_itr]; } /* End of Gain: '<Root>/Gain' */ /* Gain: '<Root>/Gain1' incorporates: * Inport: '<Root>/In3' */ for (ForEach_itr = 0; ForEach_itr <= (int32_T)(B - 1); ForEach_itr++) { rtb_VectorConcatenate[(int32_T)(A + ForEach_itr)] = 3.0 * rtU.In3[ForEach_itr]; } /* End of Gain: '<Root>/Gain1' */ /* Outputs for Iterator SubSystem: '<Root>/For Each Subsystem' incorporates: * ForEach: '<S1>/For Each' */ for (ForEach_itr = 0; ForEach_itr <= (int32_T)((int32_T)(A + B) - 1); ForEach_itr++) { /* Sum: '<Root>/Add' incorporates: * Constant: '<Root>/Constant' * Lookup_n-D: '<Root>/1-D Lookup Table1' */ rtb_VectorConcatenate_0 = look1_binlx(Data[ForEach_itr], PB, PT, (uint32_T) (int32_T)(D - 1)) + rtb_VectorConcatenate[ForEach_itr]; rtb_VectorConcatenate[ForEach_itr] = rtb_VectorConcatenate_0; /* ForEachSliceAssignment generated from: '<S1>/Out1' incorporates: * ForEachSliceSelector generated from: '<S1>/In1' * MATLAB Function: '<S1>/MATLAB Function' */ /* MATLAB Function 'For Each Subsystem/MATLAB Function': '<S3>:1' */ /* '<S3>:1:4' y = 2*u; */ rtY.Out1[ForEach_itr] = 2.0 * rtb_VectorConcatenate_0; } /* End of Outputs for SubSystem: '<Root>/For Each Subsystem' */ /* Outputs for Iterator SubSystem: '<Root>/For Iterator Subsystem' incorporates: * ForIterator: '<S2>/For Iterator' */ /* Constant: '<Root>/Constant1' */ ForEach_itr = ((int32_T)A); if (((int32_T)A) < 0) { ForEach_itr = 0; } /* End of Constant: '<Root>/Constant1' */ for (s2_iter = 0; s2_iter < ForEach_itr; s2_iter++) { /* Assignment: '<S2>/Assignment' incorporates: * Constant: '<S2>/Constant' * Outport: '<Root>/Out2' * Product: '<S2>/Product' * Selector: '<S2>/Selector' */ if (s2_iter == 0) { for (i = 0; i <= (int32_T)((int32_T)(A + B) - 1); i++) { rtY.Out2[i] = rtb_VectorConcatenate[i]; } } rtY.Out2[s2_iter] = rtb_VectorConcatenate[s2_iter] * 2.0; /* End of Assignment: '<S2>/Assignment' */ } /* End of Outputs for SubSystem: '<Root>/For Iterator Subsystem' */ }
Close the model and code generation report.
bdclose(model)
Set Parameter Value Based on Variant Choice
When you specify the dimensions of a parameter in a model by using a symbol, you must make sure that the parameter value is consistent with the dimension value. To simulate different choices for the dimension value, you must manually correct the parameter value.
For example, in the DimensionVariants
model , the
Simulink.Parameter
object Data
stores a vector value,
[1 2 3 4 5]
, and uses a symbolic dimension C
with
initial value 5
. If you change the value of C
, to
simulate the model, you must make sure the number of elements in the vector value matches
the new value of C
.
To reduce the effort of maintenance when you change the value of C
,
you can set the value of Data
to an expression involving
C
.
Open the model.
DimensionVariants
At the command prompt, inspect the initial values of
Data
andC
. The value ofData
is a vector of integers from1
toC
.Data.Value
ans = 1 2 3 4 5
C.Value
ans = 5
In MATLAB® code syntax, the value of
Data
is1:C
. To preserve this relationship between the parameter objects, set the value ofData
by using theslexpr
function.Data.Value = slexpr('1:C');
To prevent data type propagation errors, set the data type of
Data
explicitly todouble
, which is the data type that the parameter acquired before you set the parameter value to an expression.Data.DataType = 'double';
Set the value of
C
to a different number, such as6
. Due to dimension constraints in the model, you must set the value of another dimension symbol,A
, to3
.C.Value = 6; A.Value = 3;
Simulate the model. The block diagram shows that the value of
Data
now has six elements.
For more complicated applications, you can write your own MATLAB function that returns parameter values based on dimension symbols. Set the value of the parameter data to an expression that calls your function.
For general information about using an expression to set the value of a
Simulink.Parameter
object, see Set Variable Value by Using a Mathematical Expression.
Code Generation Optimization Considerations
When you create a model with symbolic dimensions, be aware of the following optimization considerations:
The code generator reuses buffers only if dimension propagation establishes equivalence among buffers.
Two loops with symbolic loop bound calculations are fused together only if they share equivalent symbolic expression.
Optimizations do not eliminate a symbolic expression or condition check based on the current value of a symbolic dimension.
Backward Compatibility
If an existing model uses Simulink.Parameter
objects to specify dimensions,
it can be incompatible with dimension variants. Here are two common scenarios:
Only a subset of blocks accepts symbolic dimension specifications. If a block is not compatible with symbolic dimensions, it causes an update diagram error.
Simulink.Parameter
objects that you use to define symbolic dimensions or have symbolic dimensions must have one of the storage classes described in this example. If these specifications are not met, the build procedure for the model fails during code generation.
You can address these backward compatibility issues by doing the following:
Turn off dimension variants feature by clearing the Allow symbolic dimension specification parameter in the Configuration Parameters dialog box.
Update
Simulink.Parameter
objects that define symbolic dimensions or have symbolic dimension specifications.Update the model so that only supported blocks have symbolic dimensions or propagate symbolic dimensions.
Supported Blocks
For a list of supported blocks, see the Block Support Table.
To access the information in this table, enter showblockdatatypetable
at
the MATLAB command prompt. Unsupported blocks (for example, MATLAB
Function) can still work in a model containing symbolic dimensions
as long as these blocks do not directly interact with symbolic dimensions.
In the following cases, supported blocks do not propagate symbolic dimensions.
For Assignment and Selector blocks, you set the Block Parameters > Index Option parameter to
Index vector (dialog)
. For Selector and Assignment blocks, if you specify a symbolic dimension for the Index parameter, the code generator does not honor the symbolic dimension in the generated code.For the Product block, you specify a value of
1
for the Block Parameters > Number of inputs parameter, and you set the Multiply over parameter toSpecified dimensions
.For the ForEach block, you specify a symbolic dimension for the Partition Width parameter.
Note that the following modeling patterns are among those modeling patterns that can cause Simulink to error out:
For Switch blocks, an input signal or the Threshold parameter has symbolic dimensions, and you select Allow different data input sizes (Results in variable-size output signal).
A Data Store Read block selects elements of a
Simulink.Bus
signal that has symbolic dimensions.For Lookup Table blocks, on the Block Parameters > Algorithm tab, you select the parameter Use one input port for all input data.
Limitations
The following products and software capabilities support dimension variants in that they act on the numeric value of a symbolic dimension. These features do not support the propagation of symbolic dimensions during model simulation and the preservation of symbolic dimensions in the generated code.
Code Replacement for Lookup Tables
Software-in-the-Loop (SIL) and Processor-in-the-Loop (PIL) simulations
Accelerator and rapid accelerator simulation modes
Scope and simulation observation (for example, logging, SDI, and so on)
Model coverage
Simulink Design Verifier
Fixed-Point Designer
Data Dictionary
Simulink PLC Coder
HDL Coder
The following do not support dimension variants:
System Object
Stateflow charts that use MATLAB as the action language
Physical modeling
Discrete-event simulation
Frame data
MATLAB functions
The following limitations also apply to models that utilize symbolic dimensions.
For simulation, the size of a symbolic dimension can equal 1. For code generation, the size of a symbolic dimension must be greater than
1
.If a symbolic dimension is a MATLAB expression that contains an arithmetic expression and either a relational or logical expression, you must add
+0
after the relational or logical part of the MATLAB expression. If you do not add+0
, the model errors out during simulation because you cannot mix aboolean
data type with integer ordouble
data types. Adding+0
converts the data type of the relational or logical part of the expression from aboolean
to adouble
.For example, suppose in the Inport block parameters dialog box, the Port dimensions parameter has the expression
[(C==8)*D+E,3]
. The Data type parameter is set todouble
. SinceC==8
is a relational expression, you must change the expression to[((C==8)+0)*D+E,3]
to prevent the model from producing an error during simulation.Simulink propagates symbolic dimensions for an entire structure or matrix, but not for a part of a structure or matrix. For example, the
Simulink.Parameter
P
is a2x3
matrix with symbolic dimensions[Dim,Dim1]
.p=Simulink.Parameter(struct('A',[1 2 3;4 5 6])) p.DataType='Bus:bo' bo=Simulink.Bus bo.Elements(1).Name='A' bo.Elements(1).Dimensions='[Dim,Dim1]' Dim=Simulink.Parameter(2) Dim1=Simulink.Parameter(3) p.CoderInfo.StorageClass='Custom' p.CoderInfo.CustomStorageClass='Define' Dim.CoderInfo.StorageClass='Custom' Dim.CoderInfo.CustomStorageClass='Define' Dim1.CoderInfo.StorageClass='Custom' Dim1.CoderInfo.CustomStorageClass='Define'
If you specify
p.A
for a dimensions parameter, Simulink propagates the symbolic dimensions[Dim,Dim1]
. If you specifyp.A(1,:)
, Simulink propagates the numeric dimension3
but not the symbolic dimension,Dim1
.The MATLAB expression
A(:)
does not maintain symbolic dimension information. UseA
instead.The MATLAB expression
P(2:A)
does not maintain symbolic dimension information. Use the Selector block instead.The MATLAB expression
P(2,:)
is not a tunable expression, so it does not maintain symbolic dimension information.Suppose that you set the value of a mask parameter,
myMaskParam
, by using a field of a structure or by using a subset of the structures in an array of structures. You store the structure or array of structures in aSimulink.Parameter
object so that you can use aSimulink.Bus
object to apply symbolic dimensions to the structure fields. Under the mask, you configure a block parameter to use one of the fields that have symbolic dimensions. The table shows some example cases.Description Value of mask parameter ( myMaskParam
)Value of block parameter myStruct
is a structure with fieldgains
, which uses symbolic dimensions.myStruct.gains
myMaskParam
myStruct
is a structure with field hierarchymyStruct.subStruct.gains
. The fieldgains
uses symbolic dimensions.myStruct.subStruct
myMaskParam.gains
myStructs
is an array of structures. Each structure has a fieldgains
, which uses symbolic dimensions.myStructs(2)
myMaskParam.gains
In these cases, you cannot generate code from the model. As a workaround, choose one of these techniques:
Use the entire structure (
myStruct
) or array of structures (myStructs
) as the value of the mask parameter. Under the mask, configure the block parameter to dereference the target field from the mask parameter by using an expression such asmyMaskParam.subStruct.gains
.Use literal dimensions instead of symbolic dimensions for the target field (
gains
).
This limitation also applies when you use a field of a structure or a subset of the structures in an array of structures as the value of a model argument in a Model block.