Elementary Work Vectors
Description of Elementary Work Vector
In addition to DWork vectors, the Simulink® software provides a simplified set of work vectors. In some S-functions, these elementary work vectors can provide an easier solution than using DWork vectors:
IWork vectors store integer data.
Mode vectors model zero crossings or other features that require a single mode vector.
PWork vectors store pointers to data structures, such as those that interface the S-function to legacy code, another software application, or a hardware application.
RWork vectors store floating-point (real) data.
Relationship to DWork Vectors
The following table compares each type of work vector to a DWork vector.
Work Vector Type | Comparison to DWork Vector | How to create equivalent DWork vector |
---|---|---|
IWork | IWork vectors cannot be customized in the generated code. Also, you are allowed only one IWork vector. | ssSetNumDWork(S,1); ssSetDWorkDataType(S, 0, SS_INT8); |
Mode | Mode vectors require more memory than DWork vectors since the
mode vector is always stored with an integer data
type. Also, you are allowed only one Mode vector. | ssSetNumDWork(S,1); ssSetDWorkUsageType(S, 0, SS_DWORK_USED_AS_MODE); ssSetDWorkDataType(S, 0, SS_INT8); |
PWork | Unlike DWork vectors, PWork vectors cannot be named in the generated code. Also, you are allowed only one PWork vector. | ssSetNumDWork(S,1); ssSetDWorkDataType(S, 0, SS_POINTER); |
RWork | RWork vectors cannot be customized in the generated code. Also, you are allowed only one RWork vector. | ssSetNumDWork(S,1); ssSetDWorkDataType(S, 0, SS_DOUBLE); |
Using Elementary Work Vectors
The process for using elementary work vectors is similar to that for DWork vectors (see Using DWork Vectors in C MEX S-Functions.) The elementary work vectors have fewer properties, so the initialization process is simpler. However, if you need to generate code for the S-function, the S-function becomes more involved than when using DWork vectors.
The following steps show how to set up and use elementary work vectors. See Additional Work Vector Macros for a list of macros related to each step in the following process.
In
mdlInitializeSizes
, specify the size of the work vectors using thessSetNum
macro, for example:X
WorkssSetNumPWork(S, 2);
This macro indicates how many elements the work vector contains, however, the Simulink engine does not allocate memory, at this time.
An S-function can defer specifying the length of the work vectors until all information about the S-function inputs is available by passing the value
DYNAMICALLY_SIZED
to thessSetNum
macro. If an S-function defers specifying the length of the work vectors inX
WorkmdlInitializeSizes
, it must provide amdlSetWorkWidths
method to set up the work vectors.Note
If an S-function uses
mdlSetWorkWidths
, all work vectors used in the S-function must be set toDYNAMICALLY_SIZED
inmdlInitializeSizes
, even if the exact value is known beforemdlInitializeSizes
is called. The sizes to be used by the S-function are than specified inmdlSetWorkWidths
.For an example, see
sfun_dynsize.c
.In
mdlStart
, assign values to the work vectors that are initialized only at the start of the simulation. Use thessGet
macro to retrieve a pointer to each work vector and use the pointer to initialize the work vector values. Alternatively, use theX
WorkssGet
to assign values to particular elements of the work vector.X
WorkValuesThe Simulink engine calls the
mdlStart
method once at the beginning of the simulation. Before calling this method, the engine allocates memory for the work vectors. Do not use themdlStart
method for data that needs to be reinitialized over the course of the simulation, for example, data that needs to be reinitialized when an enabled subsystem containing the S-function is enabled.In
mdlInitializeConditions
, initialize the values of any work vectors that might need to be reinitialized at certain points in the simulation. The engine executesmdlInitializeConditions
at the beginning of the simulation and any time an enabled subsystem containing the S-function is reenabled.In
mdlOutputs
,mdlUpdate
, etc., use thessGet
macro to retrieve a pointer to the work vector and use the pointer to access or update the work vector values.X
WorkWrite an
mdlRTW
method to allow the Target Language Compiler (TLC) to access the work vector. This step is not necessary if the S-function uses DWork vectors. For information on writing parameter data in anmdlRTW
method, seessWriteRTWParamSettings
. For more information on generating code using anmdlRTW
method, see Write Fully Inlined S-Functions with mdlRTW Routine (Simulink Coder).
Additional Work Vector Macros
Macro | Description |
---|---|
ssSetNumRWork | Specify the width of the real work vector. |
ssGetNumRWork | Query the width of the real work vector. |
ssSetNumIWork | Specify the width of the integer work vector. |
ssGetNumIWork | Query the width of the integer work vector. |
ssSetNumPWork | Specify the width of the pointer work vector. |
ssGetNumPWork | Query the width of the pointer work vector. |
ssSetNumModes | Specify the width of the mode work vector. |
ssGetNumModes | Query the width of the mode work vector. |
ssGetIWork | Get a pointer to the integer work vector. |
ssGetIWorkValue | Get an element of the integer work vector. |
ssGetModeVector | Get a pointer to the mode work vector. |
ssGetModeVectorValue | Get an element of the mode work vector. |
ssGetPWork | Get a pointer to the pointer work vector. |
ssGetPworkValue | Get one element from the pointer work vector. |
ssGetRWork | Get a pointer to the floating-point work vector. |
ssGetRWorkValue | Get an element of the floating-point work vector. |
ssSetIWorkValue | Set the value of one element of the integer work vector. |
ssSetModeVectorValue | Set the value of one element of the mode work vector. |
ssSetPWorkValue | Set the value of one element of the pointer work vector. |
ssSetRWorkValue | Set the value of one element of the floating-point work vector. |
Elementary Work Vector Examples
The following sections provide examples of the four types of elementary work vectors.
Pointer Work Vector
This example opens a file and stores the FILE
pointer
in the pointer work vector.
The following statement, included in the mdlInitializeSizes
function,
indicates that the pointer work vector is to contain one element.
ssSetNumPWork(S, 1) /* pointer-work vector */
The following code uses the pointer work vector to store a FILE
pointer,
returned from the standard I/O function fopen
.
#define MDL_START /* Change to #undef to remove function. */ #if defined(MDL_START) static void mdlStart(real_T *x0, SimStruct *S) { FILE *fPtr; void **PWork = ssGetPWork(S); fPtr = fopen("file.data", "r"); PWork[0] = fPtr; } #endif /* MDL_START */
The following code retrieves the FILE
pointer
from the pointer work vector and passes it to fclose
in
order to close the file.
static void mdlTerminate(SimStruct *S) { if (ssGetPWork(S) != NULL) { FILE *fPtr; fPtr = (FILE *) ssGetPWorkValue(S,0); if (fPtr != NULL) { fclose(fPtr); } ssSetPWorkValue(S,0,NULL); } }
Note
Although the Simulink engine handles deallocating the PWork
vector, the mdlTerminate
method must always free
the memory stored in the PWork vector.
Real and Integer Work Vectors
The S-function stvctf.c
uses
RWork and IWork vectors to model a time-varying continuous transfer
function. For a description of this S-function, see the example Discontinuities in Continuous States.
Mode Vector
The following example implements a switch block using a mode
work vector. The mdlInitializeSizes
method configures
two input ports with direct feedthrough and one output port. The mode
vector element indicates if the signal from the first or second input
port is propagated to the output. The S-function uses one S-function
parameter and a corresponding run-time parameter to store the mode
value and allow the switch to be toggled during simulation.
static void mdlInitializeSizes(SimStruct *S) { /* Initialize one S-function parameter to toggle the mode value */ ssSetNumSFcnParams(S, 1); if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { /* Return if number of expected != number of actual parameters */ return; } { int iParam = 0; int nParam = ssGetNumSFcnParams(S); for ( iParam = 0; iParam < nParam; iParam++ ) { ssSetSFcnParamTunable( S, iParam, SS_PRM_TUNABLE ); } } /* Initialize two input ports with direct feedthrough */ if (!ssSetNumInputPorts(S, 2)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortWidth(S, 1, 1); ssSetInputPortDataType( S, 0, SS_DOUBLE); ssSetInputPortDataType( S, 1, SS_DOUBLE); ssSetInputPortDirectFeedThrough( S, 0, 1); ssSetInputPortDirectFeedThrough( S, 1, 1); /* Initialize one output port */ if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetOutputPortDataType( S, 0, SS_DOUBLE); /* Initialize one element in the mode vector */ ssSetNumSampleTimes(S, 1); ssSetNumModes(S,1); ssSetOptions(S, SS_OPTION_WORKS_WITH_CODE_REUSE | SS_OPTION_USE_TLC_WITH_ACCELERATOR | SS_OPTION_DISALLOW_CONSTANT_SAMPLE_TIME | SS_OPTION_NONVOLATILE); }
The mdlInitializeConditions
method initializes
the mode vector value using the current value of the S-function dialog
parameter.
#define MDL_INITIALIZE_CONDITIONS /* Function: mdlInitializeConditions ============================= * Abstract: * Initialize the mode vector value. */ static void mdlInitializeConditions(SimStruct *S) { int_T *mv = ssGetModeVector(S); real_T param = mxGetScalar(ssGetSFcnParam(S,0)); mv[0] = (int_T)param; }
The mdlProcessParameters
and mdlSetWorkWidths
methods
initialize and update the run-time parameter. As the simulation runs,
changes to the S-function dialog parameter are mapped to the run-time
parameter.
/* Function: mdlSetWorkWidths ============================================= * Abstract: * Sets the number of runtime parameters. */ #define MDL_SET_WORK_WIDTHS static void mdlSetWorkWidths(SimStruct *S) { ssSetNumRunTimeParams(S,1); ssRegDlgParamAsRunTimeParam(S,0,0,"P1",SS_INT16); } /* Function: mdlProcessParameters =========================================== * Abstract: * Update run-time parameters. */ #define MDL_PROCESS_PARAMETERS static void mdlProcessParameters(SimStruct *S) { ssUpdateDlgParamAsRunTimeParam(S,0); }
The mdlOutputs
method updates the mode vector
value with the new run-time parameter value at every major time step.
It then uses the mode vector value to determine which input signal
to pass through to the output.
static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); InputRealPtrsType u2Ptrs = ssGetInputPortRealSignalPtrs(S,1); real_T *y = ssGetOutputPortSignal(S,0); int_T *mode = ssGetModeVector(S); real_T param = mxGetScalar(ssGetSFcnParam(S,0)); if (ssIsMajorTimeStep(S)) { mode[0] = (int_T)param; } if (!mode[0]) { /* first input */ y[0] = (*uPtrs[0]); } if (mode[0]) { /* second input */ y[0] = (*u2Ptrs[0]); } }