| Products & Services | Solutions | Academia | Support | User Community | Company |
| Download Product Updates | | | Get Pricing | | | Trial Software |
| Documentation → Simulink |
| Contents | Index |
| Learn more about Simulink |
| On this page… |
|---|
Using DWork Vectors in C MEX S-Functions Using DWork Vectors in Level-2 M-File S-Functions |
The following steps show how to initialize and use DWork vectors in a C MEX S-function. For a full list of SimStruct macros pertaining to DWork vectors, see DWork Vector C MEX Macros.
In mdlInitializeSizes, specify the number of DWork vectors using the ssSetNumDWork macro. For example, to specify that the S-function contains two DWork vectors, use the command
ssSetNumDWork(S, 2);
Although the mdlInitializeSizes method tells the Simulink engine how many DWork vectors the S-function will use, the engine does not allocate memory for the DWork vectors, at this time.
An S-function can defer specifying the number of DWork vectors until all information about the S-function's inputs is available by passing the value DYNAMICALLY_SIZED to the ssSetNumDWork macro. If an S-function defers specifying the number of DWork vectors in mdlInitializeSizes, it must provide a mdlSetWorkWidths method to set up the DWork vectors.
If the S-function does not provide an mdlSetWorkWidths method, the mdlInitializeSizes method sets any applicable attributes for each DWork vector. For example, the following lines initialize the widths and data types of the DWork vectors initialized in the previous step.
ssSetDWorkWidth(S, 0, 2); ssSetDWorkWidths(S, 1, 1); ssSetDWorkDataType(S, 0, SS_DOUBLE); ssSetDWorkDataType(S, 1, SS_BOOLEAN);
The following table lists attributes you can set for a DWork vector and shows an example of the macro that sets it.
| Attribute | Macro |
|---|---|
| Data type | ssSetDWorkDataType(S, 0, SS_DOUBLE); |
| Size | ssSetDWorkWidth(S, 0, 2); |
| Name | ssSetDWorkName(S, 0, "sfcnState"); |
| Usage type | ssSetDWorkUsageType(S, 0, SS_DWORK_USED_AS_DSTATE); |
| Numeric type, either real or complex | ssSetDWorkComplexSignal(S, 0, COMPLEX_NO); |
| Real-Time Workshop identifier | ssSetDWorkRTWIdentifier(S, 0, "Gain"); |
| Real-Time Workshop storage class | ssSetDWorkRTWStorageClass(S, 0, 2); |
| Real-Time Workshop C type qualifier | ssSetDWorkRTWTypeQualifier(S, 0, "volatile"); |
See ssSetDWorkRTWStorageClass for a list of supported storage classes.
In mdlStart, initialize the values of any DWork vectors that should be set only at the beginning of the simulation. Use the ssGetDWork macro to retrieve a pointer to each DWork vector and initialize the values. For example, the following mdlStart method initializes the first DWork vector.
static void mdlStart(SimStruct *S)
{
real_T *x = (real_T*) ssGetDWork(S,0);
/* Initialize the first DWork vector */
x[0] = 0;
x[1] = 2;
}
The Simulink engine allocates memory for the DWork vector before calling the mdlStart method. Because the mdlStart method is called only once at the beginning of the simulation, do not use it for data or states that need to be reinitialized, for example, when reenabling a disabled subsystem containing the S-function.
In mdlInitializeConditions, initialize the values of any DWork vectors that need to be reinitialized at certain points in the simulation. The engine executes mdlInitializeConditions at the beginning of the simulation and any time an enabled subsystem containing the S-function is reenabled. See the mdlStart example in the previous step for the commands used to initialize DWork vector values.
In mdlOutputs, mdlUpdate, etc., use the ssGetDWork macro to retrieve a pointer to the DWork vector and use or update the DWork vector values. For example, for a DWork vector storing two discrete states, the following mdlOutputs and mdlUpdate methods calculate the output and update the discrete state values.
The S-function previously defined U(element) as (*uPtrs[element]) and A, B, C, and D as the state-space matrices for a discrete state-space system.
/* Function: mdlOutputs ==============================================
* Abstract:
* y = Cx + Du
*/
static void mdlOutputs(SimStruct *S, int_T tid)
{
if( ssGetDWorkUsageType(S, 0) == SS_DWORK_USED_AS_DSTATE) {
real_T *y = ssGetOutputPortRealSignal(S,0);
real_T *x = (real_T*) ssGetDWork(S, 0);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
UNUSED_ARG(tid); /* not used in single tasking mode */
/* y=Cx+Du */
y[0]=C[0][0]*x[0]+C[0][1]*x[1]+D[0][0]*U(0)+D[0][1]*U(1);
y[1]=C[1][0]*x[0]+C[1][1]*x[1]+D[1][0]*U(0)+D[1][1]*U(1);
}
}
#define MDL_UPDATE
/* Function: mdlUpdate ===============================================
* Abstract:
* xdot = Ax + Bu
*/
static void mdlUpdate(SimStruct *S, int_T tid)
{
real_T tempX[2] = {0.0, 0.0};
real_T *x = (real_T*) ssGetDWork(S, 0);
InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0);
UNUSED_ARG(tid); /* not used in single tasking mode */
/* xdot=Ax+Bu */
tempX[0]=A[0][0]*x[0]+A[0][1]*x[1]+B[0][0]*U(0)+B[0][1]*U(1);
tempX[1]=A[1][0]*x[0]+A[1][1]*x[1]+B[1][0]*U(0)+B[1][1]*U(1);
x[0]=tempX[0];
x[1]=tempX[1];
}
You do not have to include any code in the mdlTerminate method to deallocate the memory used to store the DWork vector. Similarly, if you are generating inlined code for the S-function, you do not have to write an mdlRTW method to access the DWork vector in the TLC file. The Simulink software handles these aspects of the DWork vector for you.
The following table lists the C MEX macros pertaining to DWork vectors.
| Macro | Description |
|---|---|
Specify the number of DWork vectors. | |
Query the number of DWork vectors. | |
| ssGetDWork | Get a pointer to a specific DWork vector. |
| ssGetDWorkComplexSignal | Determine if a specific DWork vector is real or complex. |
| ssGetDWorkDataType | Get the data type of a DWork vector. |
| ssGetDWorkName | Get the name of a DWork vector. |
| ssGetDWorkRTWIdentifier | Get the identifier used to declare a DWork vector in the generated code. |
| ssGetDWorkRTWIdentifierMustResolveToSignalObject | Indicate if a DWork vector must resolve to a Simulink.Signal object in the MATLAB workspace. |
| ssGetDWorkRTWStorageClass | Get the storage class of a DWork vector. |
| ssGetDWorkRTWTypeQualifier | Get the C type qualifier used to declare a DWork vector in the generated code. |
| ssGetDWorkUsageType | Determine how a DWork vector is used in the S-function. |
| ssGetDWorkUsedAsDState | Determine if a DWork vector stores discrete states. |
| ssGetDWorkWidth | Get the size of a DWork vector. |
| ssSetDWorkComplexSignal | Specify if the elements of a DWork vector are real or complex. |
| ssSetDWorkDataType | Specify the data type of a DWork vector. |
| ssSetDWorkName | Specify the name of a DWork vector. |
| ssSetDWorkRTWIdentifier | Specify the identifier used to declare a DWork vector in the generated code. |
| ssSetDWorkRTWIdentifierMustResolveToSignalObject | Specify if a DWork vector must resolve to a Simulink.Signal object. |
| ssSetDWorkRTWStorageClass | Specify the storage class for a DWork vector. |
| ssSetDWorkRTWTypeQualifier | Specify the C type qualifier used to declare a DWork vector in the generated code. |
| ssSetDWorkUsageType | Specify how a DWork vector is used in the S-function. |
| ssSetDWorkUsedAsDState | Specify that a DWork vector stores discrete state values. |
| ssSetDWorkWidth | Specify the width of a DWork vector. |
The following steps show how to initialize and use DWork vectors in Level-2 M-file S-functions. These steps use the S-function /msfcn_unit_delay.m.
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 M-file S-function DWork vectors.
Initialize the DWork vector values in either the Start or InitializeCondition methods. Use the Start method for values that are initialized only at the beginning of the simulation. Use the InitializeCondition method for values that need to be reinitialized whenever a disabled subsystem containing the S-function is reenabled.
For example, the following InitializeCondition 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;
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 M-file 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. |
You can use DWork vectors to facilitate passing data from one S-functions to another. You do this by passing pointers, as unsigned integers, from the output port of one S-function to the input port of another S-function. For example, the following model contains two S-Function blocks, one calling the S-function creator.c and the other calling the S-function reader.c.

The S-function creator.c has one S-function dialog parameter that represents the gain value used by the S-function reader.c. The S-function reader.c outputs its input value multiplied by the gain value entered as the creator.c S-function dialog parameter.
For these two S-functions to communicate, the mdlStart method in creator.c allocates a shared piece of memory to store the S-function dialog parameter value and places the pointer to that memory in a DWork vector.
static void mdlStart(SimStruct *S)
{
/* Get the value of the S-function dialog parameter */
real_T GainVal = mxGetScalar(ssGetSFcnParam(S,0));
/* Get the DWork vector, which is a pointer to a pointer */
real_T **x = ssGetDWork(S,0);
/* Allocate memory for the dialog parameter data. The S-function
* owns this memory location. Simulink does not copy the data.
* Place the pointer to this memory in the DWork vector. */
real_T *gp = malloc(sizeof(GainVal));
if (gp==NULL){
ssSetErrorStatus(S,"Memory allocation error");
return;
}
/* Assign a value into the new memory location */
gp[0] = GainVal;
/* Initialize the DWork vector */
x[0] = gp;
}The mdlOutputs method in creator.c outputs the pointer created in the mdlStart method as an unsigned integer (uint32_T).
static void mdlOutputs(SimStruct *S, int_T tid)
{
uint32_T *y = ssGetOutputPortRealSignal(S,0);
real_T **x = ssGetDWork(S, 0);
real_T *gainAddr = x[0];
/* Pass pointer as output */
*y = (uint32_T)gainAddr;
}
The second input argument to reader.c accepts the uint32_T pointer value. The mdlOutputs method then accesses the value referenced by the pointer to use as the gain.
static void mdlOutputs(SimStruct *S, int_T tid)
{
/* Get the input signals. The second input is a pointer to
* the pointer to the memory that holds the S-function dialog
* parameter value */
InputRealPtrsType uPtrs = ssGetInputPortSignal(S,0);
uint32_T **pPtrs = ssGetInputPortSignal(S,1);
/* Get information about the output signal */
real_T *y = ssGetOutputPortSignal(S,0);
int_T width = ssGetOutputPortWidth(S,0);
int i;
/* Retrieve the creator.c S-function dialog parameter value */
uint32_T gainAddr = *pPtrs[0];
real_T Gain = *(double*)gainAddr;
/* Calculate outputs */
for(i =0; i<width; i++)
*y++ = (Gain)*(*uPtrs[i]);
}The mdlTerminate method in creator.c must free the memory created for the shared data.
static void mdlTerminate(SimStruct *S)
{
real_T **x = ssGetDWork(S, 0);
real_T *gainAddr = x[0];
/* Free the memory */
if (gainAddr != NULL) {
free(gainAddr);
}
/* Clear out the DWork vector */
x[0] = NULL;
}The previous method can be used to share any type of data between S-functions, for example, character arrays or structures.
You can use DWork vectors to communicate with legacy code. If you have existing code that allocates data structures in memory, store a pointer to those data structures in a DWork vector. Your S-function can then communicate with the legacy code via the pointer. Alternatively, for simplicity in setting up your S-function, you can use a pointer work vector to store the pointer. See Elementary Work Vectors for a description of pointer work vectors.
You can also use DWork vectors to store the state of legacy code. The template file matlabroot/simulink/src/sfuntmpl_gate_fortran.c shows how to use DWork vectors to interact with legacy Fortran code. The Legacy Code Tool uses DWork vectors to maintain the states of legacy C or C++ code incorporated through the tool. See Integrating Existing C Functions into Simulink Models with the Legacy Code Tool for more information on the Legacy Code Tool.
![]() | Types of DWork Vectors | DWork Vector Examples | ![]() |

Learn more about Simulink through this collection of videos, articles, technical literature and the Getting Started with Simulink Guide.
| © 1984-2009- The MathWorks, Inc. - Site Help - Patents - Trademarks - Privacy Policy - Preventing Piracy - RSS |