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 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); ssSetDWorkWidth(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. See ssSetDWorkRTWStorageClass
for a list
of supported storage classes.
Attribute | Macro |
---|---|
Data type |
|
Size |
|
Name |
|
Usage type |
|
Numeric type, either real or complex |
|
Simulink Coder™ identifier |
|
Simulink Coder storage class |
|
Simulink Coder C type qualifier |
|
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])
, 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 |
---|---|
ssSetNumDWork | Specify the number of DWork vectors. |
ssGetNumDWork | 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. |
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 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 Integrate C Functions Using Legacy Code Tool for more information on the Legacy Code Tool.