5.4 Introduction to cmex, Part II

The following MEX-file is part two in a series of tutorials intended to demonstrate how to write C MEX-files by way of extended examples. When run in MATLAB this function, mexampl2, accepts one input, a (possibly complex) vector, and if the user requests it, returns one output scalar. The function performs the following actions:

If requested, the function returns the figure handle of the figure created in step one. The user would request this by supplying a return variable when calling mexampl2 from within MATLAB (e.g., fig_handle=mexampl2(...);).

mexampl2 calls the following MEX functions, and discusses their use in detail:

mexCallMATLAB
mexEvalString
mxGetPi
mxFreeMatrix
mxCreateString
mxGetName.
mexampl2 also calls the following MEX functions, which are described more fully in mexample, the first C MEX-files tutorial:

mexErrMsgTxt
mxGetM
mxGetN
mxIsString
mxIsSparse
mxCreateFull
mxGetPr
In addition, certain basic aspects of MATLAB Handle Graphics are briefly covered in this example.

------------------------------------------------------------

/*      Include basic header files: */
#include <math.h>  /* for sqrt, fabs, atan, etc. */
#include <stdio.h> /* for NULL */
#include <mex.h>
/*      First, create two utility functions.  These functions accept two
        arrays of doubles (one representing the real part of a vector 
        and the other representing the imaginary part of the vector) and
        return the magnitude and phase of these arrays.  The output data
        is stored in a third input array (whose memory has been 
        preallocated), while a fourth input argument represents the 
        length of the arrays. */ 
#ifdef __STDC__
void magnitude(
    double *realData,   /* real part of the input vector */
    double *imagData,   /* imaginary part of the input vector */
    double *magData,    /* magnitude of the input vector (return 
                           argument)
                        */
    int vectorSize      /* size of the input vector */
    )
#else
magnitude(realData,imagData,magData,vectorSize)
double *realData;       /* real part of the input vector */
double *imagData;       /* imaginary part of the input vector */
double *magData;        /* magnitude of the input vector (return 
                           argument)
                           */
int vectorSize;         /* size of the input vector */
#endif
{
int element;            /* loop counter to cycle through elements of the
                           input vector */
/*      if imagData is not NULL, loop through each element of the input
        vector.  For each element, store in magData the square root of
        the sum of the squares of the real and imaginary parts. */ 
    if (imagData != NULL)
        for (element=0;element<vectorSize;element++) 
            magData[element] = sqrt(realData[element]*realData[element]+
                                    imagData[element]*imagData[element]);
    else                /* otherwise imaginary part is zero, take a 
                           short cut: */
        for (element=0;element<vectorSize;element++) 
            magData[element] = fabs(realData[element]);
                                        
}                       /* END magnitude() */
#define PI 3.1415926535897934440892098500626
#ifdef __STDC__
void phase(
    double *realData,   /* real part of the input vector */
    double *imagData,   /* imaginary part of the input vector */
    double *phaseData,  /* phase of the input vector (return argument)
                        */
    int vectorSize      /* size of the input vector */
    )
#else
phase(realData,imagData,phaseData,vectorSize)
double *realData;       /* real part of the input vector */
double *imagData;       /* imaginary part of the input vector */
double *phaseData;      /* phase of the input vector (return argument)
                        */
int vectorSize;         /* size of the input vector */
#endif
{
int element;            /* loop counter to cycle through elements of the
                           input vector */
/*      if imagData is not NULL, loop through each element of the input
        vector.  For each element, store in phaseData the inverse 
        tangent of the imaginary part of the vector divided by the real
        part of the vector. */ 
  if (imagData != NULL)    
    for (element=0;element<vectorSize;element++) 
      phaseData[element] = atan(imagData[element]/realData[element]);
  else                  /* otherwise imaginary part is zero, take a 
                           short cut: */
    for (element=0;element<vectorSize;element++)
      phaseData[element] = (realData[element] > 0 ? 0 : PI);
}                       /* END phase() */
/*      Now that the utility functions are defined, we can work on
        mexFunction itself.  But first, some definitions: */ 
   
#define VECTOR_IN prhs[0]
#define SCALAR_OUT plhs[0]
 
#ifdef __STDC__
void mexFunction(
    int        nlhs,
    Matrix    *plhs[],
    int        nrhs,
    Matrix    *prhs[]
    )
#else
mexFunction(nlhs, plhs, nrhs, prhs)
int nlhs, nrhs;
Matrix *plhs[], *prhs[];
#endif
{
/*      We will be making several calls to the function mexCallMATLAB.
        Two of that function's inputs are arrays of Matrix pointers.
        The next two variables will be used when we make these calls.
        None of the mexCallMATLAB calls use more than five input 
        variables or result in more than 1 output variable, so 
        MCM_inputs is declared as a 5-element array, and MCM_outputs is
        declared as a 1 element array.  Optionally, if the maximum 
        number of input or output variables were not known ahead of 
        time, we could declare MCM_inputs and MCM_outputs to be of type
        Matrix **, and then allocate memory for the array using 
        mxCalloc. */
Matrix * MCM_inputs[5]; /* Matrix pointer array for mexCallMATLAB
                           function */
Matrix * MCM_outputs[1];/* Matrix pointer array for mexCallMATLAB
                           function */
Matrix * figure_handle; /* handle to figure that mexampl2 creates */
int      size_VECTOR_IN;/* number of elements in VECTOR_IN */
/*      Step 1: Input checking. 
        Step 1a: Check nlhs.  Should be 0 or 1. */
  if (nlhs > 1)
    mexErrMsgTxt("mexampl2 only returns up to 1 argument.");
/*      Step 1b: Check nrhs.  Should be 1. */
  if (nrhs != 1)
    mexErrMsgTxt("Requires 1 input argument.");
/*      Step 1c: check VECTOR_IN (prhs[0]).  Should be one-dimensional,
        full, and numeric.  Should not be sparse or a string. */
  if ( ((mxGetM(VECTOR_IN) != 1) && (mxGetN(VECTOR_IN) != 1)) ||
    mxIsString(VECTOR_IN) || mxIsSparse(VECTOR_IN) )
    mexErrMsgTxt("Input argument should be Nx1 or 1xN, \
full, and numeric.");
/*      For ease later on, we store the size of VECTOR_IN in the
        variable size_VECTOR_IN. */
size_VECTOR_IN = mxGetM(VECTOR_IN) * mxGetN(VECTOR_IN);
/*      Step 2: create figure and plot the plots.
        Step 2a: create the figure. In MATLAB, the figure is created
        with the figure command.  To do it here, we will use 
        mexCallMATLAB to call the figure function.  The arguments to
        mexCallMATLAB are similar to those for mexFunction itself.
        There is nlhs (the number of output arguments we are 
        requesting), plhs (an array of pointers to the output
        arguments), nrhs (the number of input arguments), and
        prhs (an array of pointers to the input arguments).  In 
        addition, there is a string which contains the name of the
        function we are going to call (in this case, figure).  The
        mexCallMATLAB call below, then, mimics the MATLAB command
        "figure_handle = figure;".  Note that in this case there are
        zero inputs to figure, so MCM_inputs does not need to be
        initialized. */
mexCallMATLAB(1,MCM_outputs,0,MCM_inputs,"figure");
  
/*      Save result (the figure handle) to SCALAR_OUT.  Since 
        mexCallMATLAB reallocates memory for its second argument,
        plhs, each time it is called, we don't need to worry about a
        future mexCallMATLAB call writing over figure_handle.*/  
figure_handle = MCM_outputs[0];
/*      Step 2b: Create each subplot, title it, and plot the
        corresponding data. This consists of calling mexEvalString to
        call subplot and title, and mexCallMATLAB to call plot.  We
        repeat this twice to plot the magnitude and phase.
        mexEvalString is a simple function which passes its one input, a
        string, to MATLAB for parsing.  Thus it is similar to the eval
        command in MATLAB. */
mexEvalString("subplot(2,1,1);");       /* causes MATLAB to execute 
                                           subplot(2,1,1); */
      
/*      Create a matrix to pass to plot as the data to be plotted.  */
MCM_inputs[0] = mxCreateFull(size_VECTOR_IN,1,REAL);
  
/*      Load this matrix with the magnitude of VECTOR_IN: */
magnitude(mxGetPr(VECTOR_IN),mxGetPi(VECTOR_IN),
mxGetPr(MCM_inputs[0]),size_VECTOR_IN);
   
/*      Call mexCallMATLAB: */
mexCallMATLAB(0,MCM_outputs,1,MCM_inputs,"plot");
   
/*      Title the plot: */
mexEvalString("title('Magnitude');");  /* Causes MATLAB to execute 
                                             title('Magnitude'); */
/*      Do it again for imaginary part: First, the subplot command: */
mexEvalString("subplot(2,1,2);"); 
/*      Load the matrix with the phase of VECTOR_IN: */
phase(mxGetPr(VECTOR_IN),mxGetPi(VECTOR_IN),
mxGetPr(MCM_inputs[0]),size_VECTOR_IN);
    
/*      Call mexCallMATLAB: */
mexCallMATLAB(0,MCM_outputs,1,MCM_inputs,"plot");
    
/*      Title the plot: */
mexEvalString("title('Phase');"); 
/*      Free the matrix pointed to by MCM_inputs[0]. */
mxFreeMatrix(MCM_inputs[0]);
    
/*      For our second to last task, let's make the title of the figure
        be the name of the variable being plotted.  To do this, we need
        to set the figure's 'NumberTitle' property to 'off' and its 
        'Name' property to the name of the variable.  We do this with
        another call to mexCallMATLAB, which call the MATLAB set
        command.  To create the MATLAB strings 'NumberTitle', 'off', and
        'Name', we use the function mxCreateString.  This function
        accepts a string input and returns a MATLAB string Matrix
        containing that string.  Note that since mxGetName returns a
        string with the name of VECTOR_IN, we can pass its output
        directly to mxCreateString to create a MATLAB string containing
        the name of VECTOR_IN. */ 
MCM_inputs[0] = figure_handle;   
MCM_inputs[1] = mxCreateString("NumberTitle");
MCM_inputs[2] = mxCreateString("off");
MCM_inputs[3] = mxCreateString("Name");
MCM_inputs[4] = mxCreateString(mxGetName(VECTOR_IN));
       
    mexCallMATLAB(0,MCM_outputs,5,MCM_inputs,"set");
/*      The above mexCallMATLAB call mimics the MATLAB command 
        set(figure_handle,'NumberTitle','off', ...
        'Name',<name of VECTOR_IN>);
        Note, however, that using MEX-files allows users access to the
        name of the input variable, something which no ordinary M-file
        could do! 
*/
/*      Finally, we need to determine what the value of SCALAR_OUT
        should be.  This depends on nlhs.  If nlhs equals 1, then the
        user requested we return the figure handle, and so SCALAR_OUT
        should be set to figure_handle.  If nlhs equals 0, no such
        request was made, and SCALAR_OUT should be NULL. */
if (nlhs)
      SCALAR_OUT = figure_handle;
else
      SCALAR_OUT = NULL;
}       /* END mexFunction() */

(c) Copyright 1994 by The MathWorks, Inc.