Signal Storage, Optimization, and Interfacing

Introduction

The Real-Time Workshop product offers a number of options that let you control how signals in your model are stored and represented in the generated code. This section discusses how you can use these options to

The discussion in the following sections refers to code generated from signal_examp, the model shown in the next figure.

Signal_examp Model

Signal Storage Concepts

This section discusses structures and concepts you must understand to choose the best signal storage options for your application:

The Global Block I/O Structure

By default, the Real-Time Workshop product attempts to optimize memory usage by sharing signal memory and using local variables.

However, there are a number of circumstances in which it is desirable or necessary to place signals in global memory. For example,

In such cases, it is possible to override the default behavior and store selected (or all) signals in a model-specific global block I/O data structure. The global block I/O structure is called model_B (in earlier versions this was called rtB).

The following code shows how model_B is defined and declared in code generated (with signal storage optimizations off) from the signal_examp model shown in the Signal_examp Model figure.

(in signal_examp.h)
/* Block signals (auto storage) */
extern BlockIO_signal_examp signal_examp_B;

(in signal_examp.c)
/* Block signals (auto storage) */
BlockIO_signal_examp signal_examp_B;

Field names for signals stored in model_B are generated according to the rules described in Symbolic Naming Conventions for Signals in Generated Code.

Signals Storage Classes

In the Real-Time Workshop product, the storage class property of a signal specifies how the product declares and stores the signal. In some cases this specification is qualified by more options.

In the context of the Real-Time Workshop product, the term "storage class" is not synonymous with the term storage class specifier, as used in the C language.

Default Storage Class.   Auto is the default storage class. Auto is the appropriate storage class for signals that you do not need to interface to external code. Signals with Auto storage class can be stored in local and/or shared variables or in a global data structure. The form of storage depends on the Signal storage reuse, Reuse block outputs, Enable local block outputs, and Minimize data copies between local and global variables options, and on available stack space. See Signals with Auto Storage Class for a full description of code generation options for signals with Auto storage class.

Explicitly Assigned Storage Classes.   Signals with storage classes other than Auto are stored either as members of model_B, or in unstructured global variables, independent of model_B. These storage classes are appropriate for signals that you want to monitor and/or interface to external code.

The Signal storage reuse, Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (Expression folding), and Minimize data copies between local and global variables optimizations do not apply to signals with storage classes other than Auto.

Use the Signal Properties dialog box to assign these storage classes to signals:

Signals with Auto Storage Class

Options are available for signals with Auto storage class:

Use these options to control signal memory reuse and choose local or global (model_B) storage for signals. The Signal storage reuse option is on the Optimization pane of the Configuration Parameters dialog box, as shown in the next figure.

When you select Signal storage reuse, the Enable local block outputs, Reuse block outputs, Eliminate superfluous local variables (Expression folding), and Minimize data copies between local and global variables options in the Code Generation section of the dialog box are enabled.

These options interact. When the Signal storage reuse option is selected,

The following code examples illustrate the effects of the Signal storage reuse, Enable Local block outputs, Reuse block outputs, Eliminate superfluous local variables (Expression folding) and Minimize data copies between local and global variables options. The examples were generated from the signal_examp model (see figure Signal_examp Model).

The first example illustrates signal storage optimization, with Signal storage reuse, Enable Local block outputs, Reuse block outputs, and Minimize data copies between local and global variables selected. (For clarity in showing the individual Gain and Sum block computation, expression folding is off in this example.) The output signal from the Sum block reuses signal_examp_Y.Out1, a variable local to the model output function.

/* Model output function */
static void signal_examp_output(int_T tid)
{
  /* Sum: '<Root>Sum' incorporates:
   *  Constant: '<Root>/Constant'
   *  Inport: '<Root>>/In1'
   */
  signal_examp_Y.Out1 = signal_examp_U.In1 + signal_examp_P.Constant_Value;
  
  /* Gain: '<Root>/Gain' */
  signal_examp_Y.Out1 = signal_examp_P.Gain_Gain * signal_examp_Y.Out1;

  /* tid is required for a uniform function interface.
   * Argument tid is not used in the function. */
  UNUSED_PARAMETER(tid);
}

If you are constrained by limited stack space, you can turn Enable local block outputs off and still benefit from memory reuse. The following example was generated with Enable local block outputs cleared and Signal storage reuse, Reuse block outputs, and Minimize data copies between local and global variables selected. The output signals from the Sum and Gain blocks use global structure signal_examp_B rather than declaring local variables and in both cases the signal name is gainSig.

/* Model output function */
static void signal_examp_output(int_T tid)
{
  /* Sum: '<Root>/Add' incorporates:
   *  Constant: '<Root>/Constant'
   *  Inport: '<Root>/In1'
   */
  signal_examp_B.gainSig = signal_examp_U.In1 + 
    signal_examp_P.Constant_Value;

  /* Gain: '<Root>/Gain' */
  signal_examp_B.gainSig = signal_examp_P.Gain_Gain * 
    signal_examp_B.gainSig;

  /* Outport: '<Root>/Out1' */
  signal_examp_Y.Out1 = signal_examp_B.gainSig;
  
  /* tid is required for a uniform function interface.
   * Argument tid is not used in the function. */
  UNUSED_PARAMETER(tid);
}

When the Signal storage reuse option is cleared, Reuse block outputs, Enable local block outputs, and Minimize data copies between local and global variables are disabled. This makes the block output signals global and unique, signal_examp_B.sumSig and signal_examp_B.gainSig, as shown in the following code.

/* Model output function */
static void signal_examp_output(int_T tid)
{
  /* Sum: '<Root>/Add' incorporates:
   *  Constant: '<Root>/Constant'
   *  Inport: '<Root>/In1'
   */
  signal_examp_B.sumSig = signal_examp_U.In1 + 
    signal_examp_P.Constant_Value;

  /* Gain: '<Root>/Gain' */
  signal_examp_B.gainSig = signal_examp_P.Gain_Gain * 
    signal_examp_B.sumSig;

  /* Outport: '<Root>/Out1' */
  signal_examp_Y.Out1 = signal_examp_B.gainSig;

  /* tid is required for a uniform function interface.
   * Argument tid is not used in the function. */
  UNUSED_PARAMETER(tid);
}

In large models, disabling Signal storage reuse can significantly increase RAM and ROM usage. Therefore, this approach is not recommended for code deployment; however it can be useful in rapid prototyping environments.

The following table summarizes the possible combinations of the Signal storage reuse / Reuse block outputs and Enable local block outputs options.

Signal storage reuse and Reuse block outputs ON

Signal storage reuse OFF
(Reuse block outputs disabled)

Enable local block outputs ON

Reuse signals in local memory (fully optimized)

N/A

Enable local block outputs OFF

Reuse signals in model_B structure

Individual signal storage in model_B structure

Controlling Stack Space Allocation

When the Enable local block outputs option is on, the following TLC variables constrain the use of stack space by local block output variables:

You may need to adjust the settings of these variables when working with models that contain large signals. When a variable exceeds MaxStackVariableSize, the Real-Time Workshop product places the variable in global memory space. Similarly, if the accumulated size of variables in local memory exceeds MaxStackSize, the product places subsequent local variables in global memory space. The Real-Time Workshop product analyzes the accumulated size of local variables based on a worst-case scenario without taking into account that local variables are released after functions return.

Consider the following options for your specific model:

See Setting Target Language Compiler Options for more information.

Signals with Test Points

A test point is a signal that is stored in a unique location no other signals share or reuse. See Working with Test Points in the Simulink documentation for information about including test points in your model.

When you generate code for models that include test points, the Real-Time Workshop build process allocates a separate memory buffer for each test point. Test points are stored as members of the model_B structure.

Declaring a signal as a test point disables the following options for that signal. This can lead to increased code and data size. You do not lose the benefits of optimized storage for any other signals in your model.

For an example of storage declarations and code generated for a test point, see Summary of Signal Storage Class Options.

If you have a Real-Time Workshop Embedded Coder license, you can specify that the Real-Time Workshop build process ignore all test points in the model, allowing optimal buffer allocation, using the Ignore test point signals parameter. Ignoring test points facilitates transitioning from prototyping to deployment and avoids accidental degradation of generated code due to workflow artifacts. For more information, see Ignore test point signals in the Real-Time Workshop Reference.

Interfacing Signals to External Code

The Simulink Signal Properties dialog box lets you interface selected signals to externally written code. In this way, your hand-written code has access to such signals for monitoring or other purposes. To interface a signal to external code, use the Real-Time Workshop tab of the Signal Properties dialog box to assign one of the following storage classes to the signal:

Set the storage class as follows:

  1. In your Simulink block diagram, select the line that carries the signal. Then select Signal Properties from the Edit menu of your model. This opens the Signal Properties dialog box. Alternatively, right-click the line that carries the signal, and select Signal properties from the menu.

  2. Select the Real-Time Workshop tab of the Signal Properties dialog box.

  3. Select the desired storage class (Auto, ExportedGlobal, ImportedExtern, or ImportedExternPointer) from the RTW storage class menu. The next figure shows ExportedGlobal selected.

  4. Optional: For storage classes other than Auto, you can enter a storage type qualifier such as const or volatile in the RTW storage type qualifier field. The Real-Time Workshop product does not check this string for errors; whatever you enter is included in the variable declaration.

  5. Click Apply.

Symbolic Naming Conventions for Signals in Generated Code

When signals have a storage class other than Auto, the Real-Time Workshop product preserves symbolic information about the signals or their originating blocks in the generated code.

For labeled signals, field names in model_B derive from the signal names. In the following example, the field names model_B.sumSig and model_B.gainSig are derived from the corresponding labeled signals in the signal_examp model (shown in figure Signal_examp Model).

/* Block signals (auto storage) */
typedef struct _BlockIO_signal_examp {
    real_T sumSig;                        /* '<Root>/Add' */
    real_T gainSig;                       /* '<Root>/Gain' */
} BlockIO_signal_examp;

When you clear the Signal Storage Reuse optimization, sumSig is not part of model_B, and a local variable is used for it instead. For unlabeled signals, model_B field names are derived from the name of the source block or subsystem.

The components of a generated signal label are

The number of characters that a signal label can have is limited by the Maximum identifier length parameter specified on the Symbols pane of the Configuration Parameters dialog box. See Configuring Generated Identifiers for more detail.

When a signal has Auto storage class, the Real-Time Workshop build process controls generation of variable or field names without regard to signal labels.

Summary of Signal Storage Class Options

The next table shows, for each signal storage class option, the variable declaration and the code generated for Sum (sumSig) and Gain (gainSig) block outputs of the model shown in figure Signal_examp Model.

Storage Class

Declaration

Code

Auto

(with signal storage reuse optimizations on)

In model.c or model.cpp

real_T rtb_sumSig;
rtb_sumSig = signal_examp_U.In1 +
  signal_examp_P.Constant_Value;
rtb_sumSig *=
  signal_examp_P.Gain_Gain;
signal_examp_Y.Out1 = rtb_sumSig;

Test point (for sumSig only)

In model.h

typedef struct
_BlockIO_signal_examp 
{
  real_T sumSig;
}
BlockIO_signal_examp;

In model.c or model.cpp

BlockIO_signal_examp
signal_examp_B; 
real_T rtb_gainSig;
signal_examp_B.sumSig =
  signal_examp_U.In1 +
  signal_examp_P.Constant_Value;
rtb_gainSig = 
  signal_examp_B.sumSig * 
  signal_examp_P.Gain_Gain;
signal_examp_Y.Out1 = rtb_gainSig;

ExportedGlobal (for sumSig only)

In model.h

extern real_T sumSig;

In model.c or model.cpp

real_T sumSig; 
real_T rtb_gainSig; 
sumSig = signal_examp_U.In1 +
signal_examp_P.Constant_Value;
rtb_gainSig = sumSig *
  signal_examp_P.Gain_Gain;
signal_examp_Y.Out1 = rtb_gainSig;

ImportedExtern

In model_private.h

extern real_T sumSig;

In model.c or model.cpp

real_T rtb_gainSig;
sumSig = signal_examp_U.In1 +
signal_examp_P.Constant_Value;
rtb_gainSig = sumSig *
  signal_examp_P.Gain_Gain;
signal_examp_Y.Out1 = rtb_gainSig;

ImportedExternPointer

In model_private.h

extern real_T *sumSig;

In model.c or model.cpp

real_T rtb_gainSig;
(*sumSig) = signal_examp_U.In1 +
  signal_examp_P.Constant_Value;
rtb_gainSig = (*sumSig) *
  signal_examp_P.Gain_Gain;
signal_examp_Y.Out1 = rtb_gainSig;

  


 © 1984-2008- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS