File Exchange

image thumbnail

peakdet

version 1.2.0.0 (4.89 KB) by Marco Borges
Detect Peaks and Depressions in a signal

8 Downloads

Updated 20 Jan 2015

View License

peakdet returns peaks and depressions (local maxima and minimum) in the input signal. It can detect peaks/dep crossing the threshold or zero. Signal data requires a row or column vector with real-valued elements. If there are no local minimum/maxima returns empty.

Comments and Ratings (6)

Great work!
However, for-loops in Matlab are pretty slow. So I transfered a simplified version (just giving the positions) of this into a mex file:
[mnpos,mxpos] = mex_pekdet(vector,delta)
you get the values in matlab using
mxval = vector(mxpos)

#include <math.h>
#include "mex.h"
#include "stdio.h"
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
int n, nmax=0,nmin=0, lookformax = 1;
int i,mnpos,mxpos;
double mn,mx,currval;
double *pin=NULL, *pdelta=NULL, *poutmn=NULL,*poutmx=NULL;
double tmpmn[100]; // temporary arrays for max 100 peaks
double tmpmx[100];
//int status = 0;
/* Examine input arguments. */
if( nrhs != 2 || nlhs != 2)
{
mexErrMsgTxt("Usage: [mx,mn]=mex_peakdet(vector,delta)");
}

if ( mxIsClass(prhs[0], "sparse") || !mxIsNumeric(prhs[0]) )
{ /* check the type of input argument */
mexErrMsgTxt("Input must be full vector");
}

/* get input configuration */
n = mxGetNumberOfElements(prhs[0]);
mn = 1e20; mx = -1e20;

/* get pointers to the real parts of input and output */
pin = mxGetPr(prhs[0]);
pdelta = mxGetPr(prhs[1]);

// find local maxima by delta definition
for ( i = 0; i < n; ++i)
{
currval = pin[i];
if (currval > mx)
{
mx = currval;
mxpos = i+1;
}
if (currval < mn)
{
mn = currval;
mnpos = i+1;
}

if (lookformax)
{
if (currval < (mx-*pdelta))
{
tmpmx[nmax] = mxpos;
++nmax;
mn = currval;
mnpos = i;
lookformax = 0;
}
}
else
{
if (currval > (mn + *pdelta))
{
tmpmn[nmin] = mnpos;
++nmin;
mx = currval;
mxpos = i;
lookformax = 1;
}
}
}
/* create output matrix (double array) */
/* Should have the same complexity as input */
plhs[0]=mxCreateDoubleMatrix(nmin,1,mxREAL);
plhs[1]=mxCreateDoubleMatrix(nmax,1,mxREAL);
poutmn = mxGetPr(plhs[0]);
poutmx = mxGetPr(plhs[1]);

// write to output arrays
for (i = 0;i< nmin;++i)
poutmn[i] = tmpmn[i];
for (i = 0;i< nmax;++i)
poutmx[i] = tmpmx[i];
return;
}

A very useful addition would be if this could handle matrices as well as vectors.

Peak finding is a very useful function to have, which is why there are more than fifty submissions on FEX offering some kind of peak detection (according to the search that I just made).

The code quality/algorithm is poor, in particular:

* Loops are used which could easily be vectorized. The function |diff| would achieve most of what the main loop does.

* No array preallocation: the peak-vectors are generated by concatenating new values onto the end of the vectors: this is slow, and a poor use of MATLAB.

There are much better peak finders on MATLAB FEX, such as:

http://ww.mathworks.com/matlabcentral/fileexchange/25500-peakfinder

And even from MATLAB themselves:

http://www.mathworks.com/help/signal/ref/findpeaks.html

Updates

1.2.0.0

add minimum distance between any two peaks (local maximum)

1.1.0.0

accept row vector

MATLAB Release Compatibility
Created with R2012b
Compatible with any release
Platform Compatibility
Windows macOS Linux
Acknowledgements

Inspired: PeakPoints