Main Content

Implement Symbolic Dimensions for Array Sizes in Generated Code

Symbolic dimensions allow you to use symbols instead of fixed numbers for dimensions when you are developing a model. Wherever you need to specify a signal dimension in your model, you can use symbolic dimensions instead of actual numbers, which provides flexibility for changing the dimensions. For more information, see Use Symbolic Dimensions for Signal Dimensions (Embedded Coder).

You can specify symbolic dimensions for the blocks and data objects that includes:

  • Inport

  • Outport

  • Signal Specification

  • Data Store Memory

  • Simulink.Signal

  • Simulink.Parameter

  • Simulink.BusElement

  • Simulink.LookupTable

  • Simulink.Breakpoint

  • AUTOSAR.Parameter

Tip

To identify blocks that support symbolic dimension specification, enter showblockdatatypetable in the MATLAB® command prompt and check the Block Support Table.

Define Symbolic Dimension Variable

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 or Simulink Coder app. In the C Code tab, select Code Interface > Individual Element Code Mappings.

  3. In the Code Mappings editor, under the Parameters tab, click the refresh button. Seven Simulink.Parameter objects appear. Four of these objects are designated for specifying symbolic dimensions. These Simulink.Parameter objects are named A, B, C, and D. Note 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. Enter the name of the header file in the HeaderFile field in the Simulink.Parameter dialog box.

To use a AUTOSAR.Parameter object for dimension specification, the storage class can be mapped to something other than AUTO in the AUTOSAR mappings.

Specify Symbolic Dimensions for Blocks and Data Objects

  1. Click Inport Block In1. 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 In2. 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. 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 Variables

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:

Model              Build Reason                                         Status                        Build Duration
====================================================================================================================
DimensionVariants  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 45.856s 

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 53.662s

View the generated code. In the DimensionVariants.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 In1[A];                       /* '<Root>/In1' */
  real_T In2[B];                       /* '<Root>/In2' */
} 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>/In1'
   */
  for (ForEach_itr = 0; ForEach_itr < A; ForEach_itr++) {
    rtb_VectorConcatenate[ForEach_itr] = 2.0 * rtU.In1[ForEach_itr];
  }

  /* End of Gain: '<Root>/Gain' */

  /* Gain: '<Root>/Gain1' incorporates:
   *  Inport: '<Root>/In2'
   */
  for (ForEach_itr = 0; ForEach_itr < B; ForEach_itr++) {
    rtb_VectorConcatenate[A + ForEach_itr] = 3.0 * rtU.In2[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 < A + B; 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)
      (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 < A + B; 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 ensure that the parameter value aligns 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, ensure the vector's length 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.

Tip

You must provide the initialization code for Simulink.Parameter objects that contain symbolic dimensions. 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.

Related Topics