Main Content

Use DWork Vectors in S-Functions

What is a DWork Vector?

DWork vectors are blocks of memory that an S-function asks the Simulink® engine to allocate to each instance of the S-function in a model. If multiple instances of your S-function can occur in a model, your S-function must use DWork vectors instead of global or static memory to store instance-specific values of S-function variables. Otherwise, your S-function runs the risk of one instance overwriting data needed by another instance, causing a simulation to fail or produce incorrect results. The ability to keep track of multiple instances of an S-function is called reentrancy.

You can create an S-function that is reentrant by using DWork vectors that the engine manages for each particular instance of the S-function.

DWork vectors have several advantages:

  • Provide instance-specific storage for block variables

  • Support floating-point, integer, pointer, and general data types

  • Eliminate static and global variables

  • Interact directly with the Simulink engine to perform memory allocation, initialization, and deallocation

  • Facilitate inlining the S-function during code generation

  • Provide more control over how data appears in the generated code

Note

DWork vectors are the most generalized and versatile type of work vector and the following sections focus on their use. The Simulink product provides additional elementary types of work vectors that support floating-point, integer, pointer, and mode data. You can find a discussion of these work vectors in Elementary Work Vectors.

DWork vectors provide the most flexibility for setting data types, names, etc., of the data in the simulation and during code generation. The following list describes all the properties that you can set on a DWork vector:

  • Data type

  • Size

  • Numeric type, either real or complex

  • Name

  • Usage type (see Types of DWork Vectors)

  • Simulink Coder™ identifier

  • Simulink Coder storage class

  • Simulink Coder C type qualifier

See How to Use DWork Vectors for instructions on how to set these properties. The three Simulink Coder properties pertain only to code generation and have no effect during simulation.

How to use DWork Vectors in Level-2 MATLAB S-Functions

Using DWork Vectors in Level-2 MATLAB S-Functions

The following steps show how to initialize and use DWork vectors in Level-2 MATLAB® S-functions. These steps use the S-function msfcn_unit_delay.m.

  1. In the PostPropagationSetup method, initialize the number of DWork vectors and the attributes of each vector. For example, the following PostPropagationSetup callback method configures one DWork vector used to store a discrete state.

    function PostPropagationSetup(block)
    
      %% Setup Dwork
      block.NumDworks                = 1;
      block.Dwork(1).Name            = 'x0'; 
      block.Dwork(1).Dimensions      = 1;
      block.Dwork(1).DatatypeID      = 0;
      block.Dwork(1).Complexity      = 'Real';
      block.Dwork(1).UsedAsDiscState = true;
    

    The reference pages for Simulink.BlockCompDworkData and the parent class Simulink.BlockData list the properties you can set for Level-2 MATLAB S-function DWork vectors.

  2. Initialize the DWork vector values in either the Start or InitializeConditions methods. Use the Start method for values that are initialized only at the beginning of the simulation. Use the InitializeConditions method for values that need to be reinitialized whenever a disabled subsystem containing the S-function is reenabled.

    For example, the following InitializeConditions method initializes the value of the DWork vector configured in the previous step to the value of the first S-function dialog parameter.

    function InitializeConditions(block)
    
      %% Initialize Dwork
      block.Dwork(1).Data = block.DialogPrm(1).Data;
  3. In the Outputs, Update, etc. methods, use or update the DWork vector values, as needed. For example, the following Outputs method sets the S-function output equal to the value stored in the DWork vector. The Update method then changes the DWork vector value to the current value of the first S-function input port.

    %% Outputs callback method
    function Outputs(block)
    
      block.OutputPort(1).Data = block.Dwork(1).Data;
      
    %% Update callback method
    function Update(block)
    
      block.Dwork(1).Data = block.InputPort(1).Data;

Note

Level-2 MATLAB S-functions do not support MATLAB sparse matrices. Therefore, you cannot assign a sparse matrix to the value of a DWork vector. For example, the following line of code produces an error

block.Dwork(1).Data = speye(10);

where the speye command produces a sparse identity matrix.

Level-2 MATLAB S-Function DWork Vector Example

The example S-function msfcn_varpulse.m models a variable width pulse generator. The S-function uses two DWork vectors. The first DWork vector stores the pulse width value, which is modified at every major time step in the Update method. The second DWork vector stores the handle of the pulse generator block in the Simulink model. The value of this DWork vector does not change over the course of the simulation.

The PostPropagationSetup method, called DoPostPropSetup in this S-function, sets up the two DWork vectors.

function DoPostPropSetup(block)

% Initialize the Dwork vector
block.NumDworks = 2;

% Dwork(1) stores the value of the next pulse width
block.Dwork(1).Name            = 'x1';
block.Dwork(1).Dimensions      = 1;
block.Dwork(1).DatatypeID      = 0;      % double
block.Dwork(1).Complexity      = 'Real'; % real
block.Dwork(1).UsedAsDiscState = true;

% Dwork(2) stores the handle of the Pulse Geneator block
block.Dwork(2).Name            = 'BlockHandle';
block.Dwork(2).Dimensions      = 1;
block.Dwork(2).DatatypeID      = 0;      % double
block.Dwork(2).Complexity      = 'Real'; % real
block.Dwork(2).UsedAsDiscState = false;

The Start method initializes the DWork vector values.

function Start(block)

% Populate the Dwork vector
block.Dwork(1).Data = 0;

% Obtain the Pulse Generator block handle
pulseGen = find_system(gcs,'BlockType','DiscretePulseGenerator');
blockH = get_param(pulseGen{1},'Handle');
block.Dwork(2).Data = blockH;

The Outputs method uses the handle stored in the second DWork vector to update the pulse width of the Pulse Generator block.

function Outputs(block)

% Update the pulse width value
set_param(block.Dwork(2).Data, 'PulseWidth', num2str(block.InputPort(1).data));

The Update method then modifies the first DWork vector with the next value for the pulse width, specified by the input signal to the S-Function block.

function Update(block)

% Store the input value in the Dwork(1)
block.Dwork(1).Data = block.InputPort(1).Data;

%endfunction

See Also

| | |

Related Topics