Code covered by the BSD License  

Highlights from
peakfinder(x0, sel, thresh, extrema, includeEndpoints, interpolate)

4.925
4.9 | 46 ratings Rate this file 328 Downloads (last 30 days) File Size: 11 KB File ID: #25500 Version: 2.0
image thumbnail

peakfinder(x0, sel, thresh, extrema, includeEndpoints, interpolate)

by

 

06 Oct 2009 (Updated )

Quickly finds local maxima (peaks) or minima (valleys) in a noisy signal.

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

| Watch this File

File Information
Description

This function quickly finds local peaks or valleys (local extrema) in a noisy vector using a user defined magnitude threshold to determine if each peak is significantly larger (or smaller) than the data around it. The problem with the strictly derivative based peak finding algorithms is that if the signal is noisy many spurious peaks are found. However, more complex methods often take much longer for large data sets, require a large amount of user interaction, and still give highly variable results.
This function attempts to use the alternating nature of the derivatives along with the user defined threshold to identify local maxima or minima in a vector quickly and robustly. The function is able to correctly identify the major peaks on a 1.5 million data point noisy sum of sinusoids in under a second as is shown in the example in the code comments.

Please don't hesitate to comment or contact me if you have suggestions about improvements that could be made to this function.

MATLAB release MATLAB 7.8 (R2009a)
MATLAB Search Path
/
Other requirements None
Tags for This File   Please login to tag files.
Please login to add a comment or rating.
Comments and Ratings (66)
27 Jul 2015 Ali Allen

Hi guys
Thanks a lot for your great efforts
I have a periodic signal, can you guide me in how to find its peaks and valleys using the peakfinder function. I am very sorry since I am still new to matlab

my regards

Comment only
09 Jul 2015 Peter P

This function works well most of the time. However, in the case when the data only has one or two extrema, the code assume the function is monotonic and assumes the points are the end points and then excludes them if 'includeEndpoints' is false, when it should be returning the peak. A good test case is a quadratic.

Comment only
19 Jun 2015 Maasi AL-Mayali

Hi all,
I have x,y data for roughness profile I need to find the valleys for all valleys points, how I can do that please
maasi
Cardiff

Comment only
07 May 2015 Monique

Just adding a comment after using this function for a few months (thanks again!!!) - it would be useful to add a test at the beginning checking whether there are NaN's in x0, which causes the function to fail (without an error, ie. peaks are returned, but they don't work). Now that I know I simply remove them before running the function and add them again, but it took me a little while to notice that something was wrong and understand why.

27 Feb 2015 Monique  
27 Feb 2015 Deepesh upadrashta

Good one. Nice work. Thanks.

10 Feb 2015 FortyTwo

Excellent. Worked well for my application.

02 Feb 2015 Haitham  
30 Jan 2015 Matt

Matt (view profile)

Works well, thanks!

21 Jan 2015 amir afrashtehpour

hello
thanks for the great upload
it really works great
i have a question
i want to run this program in a loop (the ipeak.m)
i have done that and it works great.
but i don't need the code to plot it i just want the "ans" data
how to modify the code to turn of plotting
is it possible for you to change the code so the ipeak.m take a function like yes or no as input argument to wether plot the data or not
thanks

29 Oct 2014 Maria

Maria (view profile)

Thanks, works great!

29 Oct 2014 Maria

Maria (view profile)

 
20 Sep 2014 Orkhan

Orkhan (view profile)

 
31 Aug 2014 Frank

Frank (view profile)

@Nathanael Yoder: With the new version from 13.8.2014 all peaks in my data are found. Thanks again.

Comment only
23 Aug 2014 LAKSHMAN

hi all,
i want to find distance between 2 peaks of a continuous signal. the signal is like a ECG signal but no -ve values. In my signal i have only positive peaks and i want to find frequency b/w peaks. The frequency b/w peaks are not const. So i want to find 2 successive peaks and distance b/w them.. I have tried using FFT but but i want to know abt amplitude data.. Could anyone plz help me in developing algorithm...

Comment only
11 Aug 2014 yonatan gerufi  
05 Aug 2014 Nathanael Yoder

@Frank I believe the function works as intended with the current indexing methodology. By using the same index (ii) for traversing both the valleys and the peaks, the function has to come down at least sel between each peak and two peaks can't be right next to each other. That said, please email me if you have an example of where you feel it does not work and I'd be happy to take a look.

Comment only
09 Apr 2014 Frank

Frank (view profile)

Works (almost) good.
However it does not detect all peaks, I think there is a bug. The index in lines 186ff for finding the valley should be different from ii, e.g. jj:

jj = ii+1; % Move onto the valley
% Come down at least sel from peak
if ~foundPeak && tempMag > sel + x(jj)
foundPeak = true; % We have found a peak
leftMin = x(jj);
peakLoc(cInd) = tempLoc; % Add peak to index
peakMag(cInd) = tempMag;
cInd = cInd+1;
elseif x(jj) < leftMin % New left minima
leftMin = x(jj);
end

09 Apr 2014 dong

dong (view profile)

 
07 Feb 2014 Liang ZOU

Great. It works fine for ecg peak detection.

07 Feb 2014 Liang ZOU  
06 Feb 2014 Trevor

Trevor (view profile)

Very useful, thanks! For my application I was trying to find the average of peaks from some experimental data that had some outliers, so I used trimmean() on the output of this function.

@mptorr - just do a max() on the output. e.g. [~,peakdata]=peakfinder(x0) ... max(peakdata)

@Ali - there is an option for this in peakfinder. Make the 4th input argument -1 to find minimums (type "help peakfinder" into the command window for more info)

30 Dec 2013 mptorr

mptorr (view profile)

is there a way to have peakfinder return only ONE peak -- the highest -- from x0?

29 Dec 2013 Ali

Ali (view profile)

It works fine.
Is there any code to find minimums (instead of peaks)?

20 Dec 2013 Kevin

Kevin (view profile)

Exactly what I needed. Works well with mid-infrared spectra. Thanks!

08 Dec 2013 Fan D.Chen

Running very smooth, helped me a lot, thank you

05 Dec 2013 Sherif

Sherif (view profile)

Thanks.

23 Aug 2013 Nathanael Yoder

@Jakob Are you sure you are calling this function? Line 98 in this peakfinder is: dx0 = diff(x0); % Find derivative.

Also the function unfortunately does not accept cell inputs

Comment only
23 Aug 2013 Jakob

Jakob (view profile)

I get an error message:

Cell contents reference from a non-cell array object.

Error in peakfinder (line 98)
for cell=1:length(cellList{frame})

Comment only
09 Aug 2013 FEI

FEI (view profile)

 
27 Jun 2013 Shirah

Shirah (view profile)

Hello, does anybody know how to replicate these peaks into a grayscale image.

Thank You

Comment only
17 Jun 2013 Han

Han (view profile)

Best code ever.

02 Jun 2013 Opalan

Opalan (view profile)

 
19 Apr 2013 Brett Shoelson

Brett Shoelson (view profile)

I've tried several approaches to detecting peaks in noisy data; this one worked best, and is exceptionally fast. Very nice work!

18 Apr 2013 Sandra

Sandra (view profile)

How should I cite this code?

09 Mar 2013 Todd Karin  
22 Feb 2013 emma

emma (view profile)

hi team

I am very new at this. How do I make this code find multiple peaks?

Thanks

02 Nov 2012 dolphin

good

08 Jun 2012 Ershad Ahamed Chemmalasseri  
03 Jun 2012 mitra devkota

Dear MATLAB users community,
I am a matlab newbie,I have x and y as vectors, I plotted them in MATLAB and now I need to detect the peaks and also find the corresponding peak locations. How can I use this code in my case?
Thanks in advance.
Mitra

Comment only
09 May 2012 Willem

Willem (view profile)

Wang Feiran, to to find valleys you can use
peakfinder(data,[],[],-1)

Comment only
03 May 2012 Wang Feiran  
29 Apr 2012 Wang Feiran

Btw,the commend i was using is >>peakfinder(data) and i am a matlab newbie xD

Comment only
29 Apr 2012 Wang Feiran

Btw,how to use this code to detect valley?Thanks

29 Apr 2012 Wang Feiran

Hello,i also have a problem with this code when i input the data under 1200 sampling frequency it doing well can detect all the peak points,but when i tried with other data under different sampling frequency sometimes it only can give me like half points some are missing,i don't know how to attach the image file,but can give me any help?

28 Apr 2012 Morteza Dehghani  
12 Apr 2012 raj

raj (view profile)

Hello all, I have a problem with this code when my SNR is less 1.9 dB I CANT DETECT MY PEAKS OF INTEREST. What i want to know is it not possible to detect peaks at such noisy conditions ???

Comment only
12 Apr 2012 Jan Heldal

Joanne: That kind of error-message typically arises when Matlab does not know where the command resides (or when you misspelled it). Make sure that any m-file you wish to run are either in the current directory, and/or in your Matlab-path. If you have a separate folder for non-builtin m-files (such as peakfinder) that you wish to use, you can add that folder to the Matlab-path with the 'addpath' command, and put those m-files there.

Comment only
10 Apr 2012 Joanne

Joanne (view profile)

Sorry, I thought I'd written a longer message! I am also a MatLab newbie and am struggling to input the data and I get the above error message. Thanks if anyone can help. Jo

Comment only
04 Apr 2012 Joanne

Joanne (view profile)

I get the error:
Undefined function 'peakfinder' for input arguments of type
'double'.

Comment only
28 Mar 2012 raj

raj (view profile)

the code works well but some times it happens that peaks which are not required I mean after initializing a certain value for 'sel' the peaks which are not supposed to be detected (peaks created by noise) and sometimes they are not detected

12 Mar 2012 Michelle

very quick and supportive response from the author. The output issue as listed above is due to my misunderstanding of the varargout. The other issue may also results from the Matlab setting rather than the code. Thank you, Nate.

Comment only
12 Mar 2012 Michelle

very useful code. However, it cannot output the PeakMag, but only the PeakLoc when I tried it recently. and after I used it several times with a vector, the acceptable number of the element seems to be locked. When used with other vectors having different numbers of elements,the extra elements cannot be shown in the plot and the output results. I hope someone can kindly explain this...

02 Dec 2011 Diana

Diana (view profile)

Hi, I find this routine very good and useful. However, for my problem I would need the start-end information about each peak so I could select just the peaks and work with them, How can I get this information?

Thanks in advance

22 Sep 2011 mohammad

Really nice

12 Aug 2011 Robert

Robert (view profile)

 
11 Aug 2011 Estella Liu  
18 Jun 2011 Elisa

Elisa (view profile)

Hi. I need to find peaks in a waveform and calculate the inter-pulse interval and the pulse rate from the position of the peaks. My data are sounds recorded at 24000Hz and saved in .wav files. This code seems to be doing exactly what I want but since I’m a matlab newbie I’m not quite sure how to input my data. Do you have any suggestions?
I hope this is the right place to post this message, otherwise I apologise.

Comment only
14 Jun 2011 Nathanael Yoder

Thanks for catching that Tim. You were exactly right, the redundancy is an artifact from when I preallocated the matrix for speed. However, I essentially replaced this statement with the leftMin variable which is why you got the same results. The end effect is that the second part of that conditional can simply be eliminated.

Thanks again for your help and an updated version with the addition of a user defined threshold should be available shortly.

Comment only
09 Feb 2011 Tim

Tim (view profile)

I think I found a mistake in the code. Or at least something strange:

if foundPeak && (x(ii) > peakMag(end) || leftMin < peakMag(end)-thresh)

The second part, x(ii) > peakMag(end), is rather strange, since peakMag(end) will ALWAYS be equal to zero, since peakMag was preallocated with zeros. I guess this is a remainder from the time before you preallocated peakMag for speed.

I replaced the mistake with the following:

if foundPeak && (x(ii) > peakMag(cInd-1) || leftMin < peakMag(cInd-1)-thresh)

The strange thing is that the results luckily stay exactly the same, which is good but strange at the same time. There is probably some redundancy in the code.

In any case, your method was more or less what I was looking for. Just need to make some small adaptations to it for my purpose, of course leaving all credits to you. Thanks!

17 Jun 2010 David

David (view profile)

fantastic code, very effective even with highly noise data.

notably, it might be worth including an histogram based thresholding for a more optimal threshold selection.

27 May 2010 Nicholas

Does anyone know of a comparable code that finds extrema in 2D or 3D data?

Comment only
28 Apr 2010 antonio Acampora

thanks

02 Dec 2009 Andres

Andres (view profile)

The bugs were fixed quickly. Thanks Nate!

30 Nov 2009 Andres

Andres (view profile)

I was happily using peakfinder until I had severe trouble with a dataset beginning with repeated values.
I've boiled it down to a short example:

t = [49 49 54 49 -57 46 -96 -10 39 0];
startI1 = 1;
[Loc1, Peak1] = peakfinder(t(startI1:end),20);
startI2 = 2;
[Loc2, Peak2] = peakfinder(t(startI2:end),20);

figure
plot(t,'b.-')
hold on
plot(Loc1-1+startI1,Peak1,'ro')
plot(Loc2-1+startI2,Peak2,'go')

Problems:
1) The first call returns a wrong result (Loc1 = 2, Peak1 = 49).
2) The second call returns all three peaks, but the last one appears twice (Loc2 = [2 5 8 8].', Peak2 = [54 46 39 39].').

I hope these issues can be fixed as peakfinder works promisingly fast.
A minor suggestion: if the input is a row vector the output should be a row vector, too.

Regards
Andres

16 Nov 2009 Morvan

Morvan (view profile)

 
Updates
06 Nov 2009 1.1

Updated code to make it slightly faster.

06 Nov 2009 1.2

Updated algorithm to make it slightly faster.

11 Nov 2009 1.3

Fixed example and error checking code. Thanks to Jiro Doke for catching my mistakes.

01 Dec 2009 1.4

Fixed problems with repeated initial values, repeated final values, and other directional issues. Thanks to Andres for his help finding and debugging these problems.

08 Dec 2009 1.5

Added support for monotone increase/decreasing functions and empty inputs. Thanks again to Andres for the debugging help.

08 Oct 2010 1.6

Updated the error checking on the threshold level.

14 Jun 2011 1.7

Removed redundancy (thanks Tim) and added thresholding option (thanks Femi).

02 Dec 2013 1.8

Added an optional boolean to exclude the endpoints since, as pointed out by Peter Cavanagh, most definitions of local extrema do not include them. By default the endpoints are included to maintain backward compatibility.

13 Aug 2014 1.9

Fix bug related to a missing equality comparison (thanks Nina Merkle!) and fix inconsistency when the endpoints are not treated as extrema (thanks Solomon Grant!).

11 Jun 2015 2.0

Added ability to quickly estimate the location and magnitude of the extrema between data points for regularly spaced data using quadratic interpolation. The function continues to work for irregularly spaced data. Default is no interpolation.

Contact us