Main Content

How to Use DWork Vectors

Using DWork Vectors in C MEX 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.

  1. 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.

  2. 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.

    AttributeMacro
    Data typessSetDWorkDataType(S, 0, SS_DOUBLE);
    SizessSetDWorkWidth(S, 0, 2);
    NamessSetDWorkName(S, 0, "sfcnState");
    Usage typessSetDWorkUsageType(S, 0, SS_DWORK_USED_AS_DSTATE);
    Numeric type, either real or complexssSetDWorkComplexSignal(S, 0, COMPLEX_NO);
    Simulink Coder™ identifierssSetDWorkRTWIdentifier(S, 0, "Gain");
    Simulink Coder storage classssSetDWorkRTWStorageClass(S, 0, 2);
    Simulink Coder C type qualifierssSetDWorkRTWTypeQualifier(S, 0, "volatile");
  3. 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.

  4. 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.

  5. 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.

DWork Vector C MEX Macros

The following table lists the C MEX macros pertaining to DWork vectors.

MacroDescription
ssSetNumDWorkSpecify the number of DWork vectors.
ssGetNumDWorkQuery the number of DWork vectors.
ssGetDWorkGet a pointer to a specific DWork vector.
ssGetDWorkComplexSignalDetermine if a specific DWork vector is real or complex.
ssGetDWorkDataTypeGet the data type of a DWork vector.
ssGetDWorkNameGet the name of a DWork vector.
ssGetDWorkRTWIdentifierGet the identifier used to declare a DWork vector in the generated code.
ssGetDWorkRTWIdentifierMustResolveToSignalObjectIndicate if a DWork vector must resolve to a Simulink.Signal object in the MATLAB® workspace.
ssGetDWorkRTWStorageClassGet the storage class of a DWork vector.
ssGetDWorkRTWTypeQualifierGet the C type qualifier used to declare a DWork vector in the generated code.
ssGetDWorkUsageTypeDetermine how a DWork vector is used in the S-function.
ssGetDWorkUsedAsDStateDetermine if a DWork vector stores discrete states.
ssGetDWorkWidthGet the size of a DWork vector.
ssSetDWorkComplexSignalSpecify if the elements of a DWork vector are real or complex.
ssSetDWorkDataTypeSpecify the data type of a DWork vector.
ssSetDWorkNameSpecify the name of a DWork vector.
ssSetDWorkRTWIdentifierSpecify the identifier used to declare a DWork vector in the generated code.
ssSetDWorkRTWIdentifierMustResolveToSignalObjectSpecify if a DWork vector must resolve to a Simulink.Signal object.
ssSetDWorkRTWStorageClassSpecify the storage class for a DWork vector.
ssSetDWorkRTWTypeQualifierSpecify the C type qualifier used to declare a DWork vector in the generated code.
ssSetDWorkUsageTypeSpecify how a DWork vector is used in the S-function.
ssSetDWorkUsedAsDStateSpecify that a DWork vector stores discrete state values.
ssSetDWorkWidthSpecify the width of a DWork vector.

Using DWork Vectors With Legacy Code

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.