Main Content

MATLAB Data in C S-Functions

MATLAB® data is represented as mxArrays in C/C++ language. The mxArray structure typically contains type, dimension, data, data type, sparsity, and the field and field numbers of the MATLAB array. In S-functions, Pass Dialog Parameters to S-Functions values evaluated in MATLAB are transferred into Simulink® as an mxArray. See C Matrix API for a list of functions.

S-functions read MATLAB data mainly for the following purposes:

  • Access block dialog parameters using mxArrays

  • Pass arguments to or from a MATLAB Function using mexCallMATLAB

mxArray Manipulation

You can manipulate mxArrays in S-functions using the standard MATLAB API functions. In general, if your S-function is declared exception free by passing the SS_OPTION_EXCEPTION_FREE_CODE option to ssSetOptions (see Exception Free Code in Handle Errors in S-Functions), it should avoid MATLAB API functions that throw exceptions (i.e., long jump), such as mxCreateDoubleMatrix. Otherwise, the S-function can use any of the listed functions.

Note

S-function parameters are read-only within the S-function algorithm. You can modify parameter values via the S-function block dialog or mask.

If you have Simulink Coder™, it supports a subset of the mxArray manipulation functions when generating noninlined code for an S-function. For a list of supported functions, see Write Noninlined S-Function (Simulink Coder).

Calls to the macro ssGetSFcnParam return a pointer to an mxArray, which can be used with the mxArray manipulation functions. If your S-function contains S-function parameters, use the mxArray manipulation functions in the mdlCheckParameters method to check the S-function parameter values. See the S-function sfun_runtime3.c for an example

In this S-function, the following lines check that the first S-function parameter is a character array with a length greater than or equal to two.

if (!mxIsChar(ssGetSFcnParam(S, 0)) ||
     (nu=mxGetNumberOfElements(ssGetSFcnParam(S, 0))) < 2) {
     ssSetErrorStatus(S,"1st parameter to S-function must be a "
       "string of at least 2 '+' and '-' characters");
     return;
}

mxArrays Using 32-bit APIs

To write C/C++ programs that work with MATLAB mxArray data structure, use C matrix APIs. C matrix APIs support 32-bit and 64-bit indexing. By default, your S-functions are built using 32-bit APIs. Check Upgrade MEX Files to Use 64-Bit API to see how to upgrade your existing MEX files.

To check the use of 32-bit APIs, you can run the S-function upgrade advisor. In the Modeling tab, select Model Advisor > Upgrade Advisor.

If you build your code with -largeArrayDims and your code populates the ssParamRec structure's dimension field with mxArray dimensions, starting R2018a, you can no longer cast the return value of mxGetDimensions to an int_T pointer because mxGetDimensions now returns a size_T pointer on 64-bit platforms. As a workaround, create a temporary copy of type int_T and assign it to the dims field of ssParamRec structure.

Replace:With:
ssParamRec p;
p.dims = (int_T *) mxGetDimensions(ssGetSFcnParam(S, 0));
// Set up other fields of p
if (!ssSetRunTimeParamInfo(S, 0, &p)) {
       free(dims);
       return;
}
free(dims); // free memory allocated for dimensions
ssParamRec p;
const mxArray* mxPrm = ssGetSFcnParam(S, 0);
const mwSize* mxDims = mxGetDimensions(mxPrm);
const mwSize mxNumDims = mxGetNumberOfDimensions(mxPrm);
mwSize idx;
int_T * dims = malloc(sizeof(int)*mxNumDims);
for (idx=0; idx < mxNumDims; idx++)
{
   dims[idx] = mxDims[idx];
} 

p.dims = dims;
// Set up other fields of p

if (!ssSetRunTimeParamInfo(S, 0, &p)) {
       free(dims);
       return;
}
free(dims); // free memory allocated for dimensions

mxArrays Using Interleaved Complex Representation

Until MATLAB version 9.4 (R2018a), mxArrays used separate complex representation where the real and imaginary parts of a complex number were stored separately. Starting version 9.4 (R2018a), MATLAB uses interleaved representation to store complex data, where the real and imaginary parts of a complex numbers are stored together. For S-functions to manipulate mxArrays, there is no longer need to convert data from separate to interleaved complex. See MATLAB Support for Interleaved Complex API in MEX Functions for more information on how to update your code.

Note

To store complex data for input and output signals or DWorks, Simulink uses interleaved representation.

To automatically check your S-functions on potential interleaved complex data issues, in the Modeling tab, select Model Advisor > Upgrade Advisor. In the Upgrade Advisor window, select Check model for S-function upgrade issues.

The following code sample copies a parameter value from an mxArray to the output of the S-function. In this example, the dimensions, data type, and the complexity of the parameter and the output argument are ensured to be the same. For example, if the parameter is complex, the output signal is complex. If the parameter is real, the output signal is real. For the example below, the data type of both the parameter and the output is a double (real_T). Before R2018a, you could use mxGetPr and mxGetPr to copy the real and imaginary parts of a complex data separately. With interleaved complex representation, you can use memcpy, which is a single copy instruction.

Replace:With:
    real_T            *y     = ssGetOutputPortRealSignal(S,0);
    boolean_T   yIsComplex = ssGetOutputPortComplexSignal(S, 0) == COMPLEX_YES;
    int_T             yWidth = ssGetOutputPortWidth(S,0);

    const real_T      *pr    = mxGetPr(ssGetSFcnParam(S, 0));          
    const real_T      *pi    = mxGetPi(ssGetSFcnParam(S, 0));

   int               i;

    for (i = 0; i < yWidth; i++) {

        int_T idx = (yIsComplex)  ? 2*i : i;
        y[idx] =  pr[idx];

        if(yIsComplex){
             y[idx+1] = pi[idx];
        }
    }
    real_T            *y     = ssGetOutputPortRealSignal(S,0);
    boolean_T   yIsComplex = ssGetOutputPortComplexSignal(S, 0) == COMPLEX_YES;
    int_T             yWidth = ssGetOutputPortWidth(S,0);

    mxComplexDouble *pc;
    mxDouble *pr;

   if (yIsComplex) {

        pc = mxGetComplexDoubles(ssGetSFcnParam(S, 0));
        memcpy(y, pc, yWidth*sizeof(mxComplexDouble));

   } else {

       pr = mxGetDoubles(ssGetSFcnParam(S, 0));
       memcpy(y, pr, yWidth*sizeof(mxDouble)); 

   }
a

a 

sizeof(mxComplexDouble)=2*sizeof(mxDouble)=2*sizeof(real_T)

See Also

|

Related Topics