Main Content

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 the ImportedExtern or ImportedExternPointer 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.

  1. To show block names, on the Debug tab, on the Information Overlays menu, clear the Hide Automatic Block Names parameter.

  2. Open the Embedded Coder app. In the C Code tab, select Code Interface > Individual Element Code Mappings.

  3. 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. These Simulink.Parameter objects have the names A, B, C, and D. Notice that these parameters have a storage class of CompilerFlag.

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 or ImportedDefine with header file specified

  • CompilerFlag

  • 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

  1. Click Inport Block In2. On the Property Inspector, on the Parameters tab, the Port Dimensions field contains the Simulink.Parameter object A. For Inport blocks, you specify symbolic dimensions in the Port Dimensions field.

  2. Click Inport block In3. The Port Dimensions field contains the Simulink.Parameter object B.

  3. Click the Constant block. The Constant value parameter has a value of Data. In the Code Mappings editor, on the Parameters tab, click the Simulink.Parameter object Data. On the Property Inspector, the Dimension field has the character vector '[1,C]', which is equivalent to '[1,5]' because C has a value of 5. The Value field contains an array with 5 values, which is consistent with its dimensions. The dimensions of the data object must be consistent with the value of the Simulink.Parameter object that is in the Dimensions field. Notice that Data has a Storage class of ImportedExtern.

  4. Open the 1-D Lookup Table1 block parameters dialog box. The Table data field contains the Simulink.Parameter, PT. The Breakpoints 1 field contains the Simulink.Parameter, PB.

  5. In the Code Mappings editor, click PB and PT 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 of D is consistent with the dimension of the PB and PT parameters because D has a value of 15 .

  6. 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 that C=A+B. The Diagnostic Viewer produces a warning for any violations of constraints.

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

  1. Open the model.

    DimensionVariants

  2. At the command prompt, inspect the initial values of Data and C. The value of Data is a vector of integers from 1 to C.

    Data.Value
    
    ans =
    
         1     2     3     4     5
    C.Value
    ans =
    
         5

  3. In MATLAB® code syntax, the value of Data is 1:C. To preserve this relationship between the parameter objects, set the value of Data by using the slexpr function.

    Data.Value = slexpr('1:C');

  4. To prevent data type propagation errors, set the data type of Data explicitly to double, which is the data type that the parameter acquired before you set the parameter value to an expression.

    Data.DataType = 'double';

  5. Set the value of C to a different number, such as 6. Due to dimension constraints in the model, you must set the value of another dimension symbol, A, to 3.

    C.Value = 6;
    A.Value = 3;

  6. 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 to Specified 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 a boolean data type with integer or double data types. Adding +0 converts the data type of the relational or logical part of the expression from a boolean to a double.

    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 to double. Since C==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 a 2x3 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 specify p.A(1,:), Simulink propagates the numeric dimension 3 but not the symbolic dimension, Dim1.

  • The MATLAB expression A(:) does not maintain symbolic dimension information. Use A 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 a Simulink.Parameter object so that you can use a Simulink.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.

    DescriptionValue of mask parameter (myMaskParam)Value of block parameter
    myStruct is a structure with field gains, which uses symbolic dimensions.myStruct.gainsmyMaskParam
    myStruct is a structure with field hierarchy myStruct.subStruct.gains. The field gains uses symbolic dimensions.myStruct.subStructmyMaskParam.gains
    myStructs is an array of structures. Each structure has a field gains, 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 as myMaskParam.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.

Related Topics