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