MATLAB Examples

Specify Buffer Reuse by Using Simulink.Signal Objects

If your model has the optimal parameter settings for removing data copies, you might be able to remove additional data copies by using Simulink.Signal objects to specify buffer reuse. After studying the generated code and the Static Code Metrics Report and identifying areas where you think buffer reuse is possible, you specify signal objects on signal lines.

You can specify buffer reuse on signals that include a pair of root inport and outport signals. You can also specify buffer reuse on just a pair of root inport and outport signals. This optimization reduces ROM and RAM consumption because there are less global variables and data copies in the generated code. Code execution speed also increases.

Contents

Example Model

The model rtwdemo_reusable_csc contains the nonreusable subsystem DeltaSubsystem and the MATLAB Function block Downsample. DeltaSubsystem contains the MATLAB Function blocks DeltaX and DeltaY.

model ='rtwdemo_reusable_csc';
open_system(model);

Specify a Simulink Signal Object for Reuse

  1. Open the base workspace. The Simulink signal objects RCSC_IMAG, RCSC_REAL, RSCS_REAL2, and RCSC_IMAG2 are for specifying buffer reuse. To use a Simulink signal object for buffer reuse, the object must have a Storage class of Reusable (Custom), which means the generated code allocates memory for a global variable, and stores intermediate calculations for that variable. If possible, the code generator reuses the same global variable for each signal object.
  2. In the model, open the Model Data Editor (View > Model Data).
  3. On the Signals tab, from the Change view drop-down list, select Code.
  4. Click the Show/refresh additional information button.
  5. Double-click DeltaSubsystem.
  6. Select the Signals tab. To associate signal lines with a Simulink signal object, you must specify the object name in the Name column and select the check box in the Resolve column. Selecting this check box means that the signal acquires settings from the signal object.

Generate Code

Build the model.

currentDir = pwd;
[~,cgDir] = rtwdemodir();
rtwbuild(model);
### Starting build procedure for model: rtwdemo_reusable_csc
### Successful completion of build procedure for model: rtwdemo_reusable_csc

For buffer reuse, the rtwdemo_reusable_csc.c file contains these global variables:

  • static real_T RCSC_IMAG[1048576];
  • static real_T RCSC_IMAG2[262144];
  • static real_T RCSC_REAL[1048576];
  • static real_T RCSC_REAL2[262144];

The rtwdemo_reusable_csc.c file contains this code:

cfile = fullfile(cgDir,'rtwdemo_reusable_csc_ert_rtw','rtwdemo_reusable_csc.c');
rtwdemodbtype(cfile,'/* Output and update for atomic system: ''<Root>/DeltaSubsystem'' */',...
    '/* Output and update for atomic system: ''<Root>/Downsample'' */',1,0);
rtwdemodbtype(cfile, '/* Model step function */','/* Model initialize function */',1,0);
/* Output and update for atomic system: '<Root>/DeltaSubsystem' */
static void DeltaSubsystem(void)
{
  /* MATLAB Function: '<S1>/DeltaX' */
  DeltaX((&(RCSC_REAL2[0])), (&(RCSC_IMAG2[0])), (&(RCSC_REAL[0])),
         (&(RCSC_IMAG[0])));

  /* MATLAB Function: '<S1>/DeltaY' */
  DeltaY((&(RCSC_REAL[0])), (&(RCSC_IMAG[0])), (&(RCSC_REAL2[0])),
         (&(RCSC_IMAG2[0])));
}

/* Model step function */
void rtwdemo_reusable_csc_step(void)
{
  int32_T i;

  /* ComplexToRealImag: '<Root>/Complex to Real-Imag' incorporates:
   *  Inport: '<Root>/ComplexData'
   */
  for (i = 0; i < 1048576; i++) {
    RCSC_REAL[i] = rtU.ComplexData[i].re;
    RCSC_IMAG[i] = rtU.ComplexData[i].im;
  }

  /* End of ComplexToRealImag: '<Root>/Complex to Real-Imag' */

  /* MATLAB Function: '<Root>/Downsample' */
  Downsample((&(RCSC_REAL[0])), (&(RCSC_IMAG[0])), (&(RCSC_REAL2[0])),
             (&(RCSC_IMAG2[0])));

  /* Outputs for Atomic SubSystem: '<Root>/DeltaSubsystem' */
  DeltaSubsystem();

  /* End of Outputs for SubSystem: '<Root>/DeltaSubsystem' */

  /* Outport: '<Root>/Out1' incorporates:
   *  RealImagToComplex: '<Root>/Real-Imag to Complex'
   */
  for (i = 0; i < 261121; i++) {
    rtY.Out1[i].re = RCSC_REAL2[i];
    rtY.Out1[i].im = RCSC_IMAG2[i];
  }

  /* End of Outport: '<Root>/Out1' */
}

The variables RCSC_REAL and RCSC_IMAG hold the outputs of the Complex to Real-Image block and DeltaX. These variables hold the inputs to the DeltaY block. The variables RCSC_REAL2 and RCSC_IMAG2 hold the outputs of Downsample and DeltaY. These variables hold the inputs to the DeltaX block. By interleaving buffers in this way, you eliminate global variables in the generated code.

To remove the signal objects from the signal lines and regenerate code, in the MATLAB Command Window, enter these commands:

portHandles = get_param('rtwdemo_reusable_csc/Complex to Real-Imag','portHandles');
set_param(portHandles.Outport(1),'MustResolveToSignalObject','off');
set_param(portHandles.Outport(2),'MustResolveToSignalObject','off');

portHandles = get_param('rtwdemo_reusable_csc/Downsample','portHandles');
set_param(portHandles.Outport(1),'MustResolveToSignalObject','off');
set_param(portHandles.Outport(2),'MustResolveToSignalObject','off');

portHandles = get_param('rtwdemo_reusable_csc/DeltaSubsystem/DeltaX','portHandles');
set_param(portHandles.Outport(1),'MustResolveToSignalObject','off');
set_param(portHandles.Outport(2),'MustResolveToSignalObject','off');

portHandles = get_param('rtwdemo_reusable_csc/DeltaSubsystem/DeltaY','portHandles');
set_param(portHandles.Outport(1),'MustResolveToSignalObject','off');
set_param(portHandles.Outport(2),'MustResolveToSignalObject','off');

rtwbuild(model);
### Starting build procedure for model: rtwdemo_reusable_csc
### Successful completion of build procedure for model: rtwdemo_reusable_csc

The The rtwdemo_reusable_csc.c file now contains this code.

cfile = fullfile(cgDir,'rtwdemo_reusable_csc_ert_rtw','rtwdemo_reusable_csc.c');
rtwdemodbtype(cfile,'/* Output and update for atomic system: ''<Root>/DeltaSubsystem'' */',...
    '/* Output and update for atomic system: ''<Root>/Downsample'' */',1,0);
rtwdemodbtype(cfile, '/* Model step function */','/* Model initialize function */',1,0);
/* Output and update for atomic system: '<Root>/DeltaSubsystem' */
static void DeltaSubsystem(void)
{
  /* MATLAB Function: '<S1>/DeltaX' */
  DeltaX(rtDWork.z2, rtDWork.z1, rtDWork.z1_m, rtDWork.z2_c);

  /* MATLAB Function: '<S1>/DeltaY' */
  DeltaY(rtDWork.z1_m, rtDWork.z2_c, &rtDWork.z1[0], &rtDWork.z2[0]);
}

/* Model step function */
void rtwdemo_reusable_csc_step(void)
{
  int32_T i;

  /* ComplexToRealImag: '<Root>/Complex to Real-Imag' incorporates:
   *  Inport: '<Root>/ComplexData'
   */
  for (i = 0; i < 1048576; i++) {
    rtDWork.RCSC_REAL[i] = rtU.ComplexData[i].re;
    rtDWork.RCSC_IMAG[i] = rtU.ComplexData[i].im;
  }

  /* End of ComplexToRealImag: '<Root>/Complex to Real-Imag' */

  /* MATLAB Function: '<Root>/Downsample' */
  Downsample(rtDWork.RCSC_REAL, rtDWork.RCSC_IMAG, rtDWork.z2, rtDWork.z1);

  /* Outputs for Atomic SubSystem: '<Root>/DeltaSubsystem' */
  DeltaSubsystem();

  /* End of Outputs for SubSystem: '<Root>/DeltaSubsystem' */

  /* Outport: '<Root>/Out1' incorporates:
   *  RealImagToComplex: '<Root>/Real-Imag to Complex'
   */
  for (i = 0; i < 261121; i++) {
    rtY.Out1[i].re = rtDWork.z1[i];
    rtY.Out1[i].im = rtDWork.z2[i];
  }

  /* End of Outport: '<Root>/Out1' */
}

The generated code contains two additional global variables for holding block inputs and outputs.

Note: You can specify buffer reuse on signals that the code generator can not implement. For those cases, use two new diagnostics to specify the message type that the model displays. In the Configuration Parameters dialog box, these diagnostics are Detect non-reused custom storage classes and Detect ambiguous custom storage class final values.

bdclose(model)
rtwdemoclean;
cd(currentDir)

Buffer Reuse for Unit Delay and Delay Blocks

To reuse the signal of a Unit Delay or Delay block:

  1. Use the same reusable custom storage class specification for a pair of input and state arguments or a pair of output and state arguments of a Unit Delay block or a Delay block.
  2. In the Model Data Editor, select the States tab and from the Change view drop-down list, select Code.
  3. Use the Name column to set the name of the target Unit Delay or Delay block states. Specify the name of the signal object that you want to reuse.
  4. For each state, check the box in the Resolve column.

For Delay blocks, you must set the Delay length parameter to 1 and Initial condition > Source to Dialog. To access these parameters, in the model, open the Property Inspector (View > Property Inspector) and click the block in the model.

Limitations for Root Inport and Outport Signals

These limitations apply to a model in which you specify buffer reuse for a pair of root inport and outport signals:

  • The output ports cannot be conditional.
  • If the code generator cannot reuse the same buffer in a top model, the generated code contains additional buffers. If the top model is a reference model, the code generator reports an error. To resolve the error, remove the Simulink.signal specification from the signal that connects to the outport port.
  • When you run the executable that the code generator produces, and you reuse a pair of root inport and outport signals, when the root input value is zero, the root output value must also be zero. If the output value is nonzero and you reuse the signals, then the results from the simulation can differ from the results that the executable produces.

Limitations for the Model

These limitations apply to a model in which you specify buffer reuse for signals:

  • Signals that you specify for reuse must have the same data types and sampling rates.
  • For user-specified buffer reuse, blocks that modify a signal specified for reuse must execute before blocks that use the original signal value. Sometimes the code generator has to change the block operation order so that buffer reuse can occur. For models in which the code generator is unable to reorder block operations, buffer reuse does not occur.
  • For models in which the code generator reorders block operations so that Simulink.Signal reuse can occur, you can observe the difference in the sorted order. In the model window, select Display > Blocks > Sorted Execution Order. To display the sorted execution order during simulation, select Simulation > Update Diagram. To display the execution order in the generated code, select Code > C/C++ Code > Build Model.