version 2.0.2.0 (10.9 KB) by
Nathanael Yoder

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

**Editor's Note:** This file was selected as MATLAB Central Pick of the Week

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.

Nathanael Yoder (2021). peakfinder(x0, sel, thresh, extrema, includeEndpoints, interpolate) (https://www.mathworks.com/matlabcentral/fileexchange/25500-peakfinder-x0-sel-thresh-extrema-includeendpoints-interpolate), MATLAB Central File Exchange. Retrieved .

Created with
R2009a

Compatible with any release

**Inspired:**
voigt line shape fit

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!Create scripts with code, output, and formatted text in a single executable document.

Alessandro La ChiomaThe function gives error when includeEndpoints = false and no peak is found.

This happens because ind in line 145 is empty:

(145) ind = find(dx0(1:end-1).*dx0(2:end) < 0)+1; % Find where the derivative changes sign

and then line 156 gives error:

Index exceeds the number of array elements (0).

By just changing lines 154-156

x = x0(ind);

minMag = min(x);

leftMin = min(x(1), x0(1));

into the following:

x = x0(ind);

if ~isempty(x) %Compute the following only if ~isempty(x) to prevent error

minMag = min(x);

leftMin = min(x(1), x0(1));

end

solves the issue.

Michael ClementeBalroggarimaHi,

Could you please tell if I will pass only one parameter e.g., peak finder(data), then how will this code decide threshold value?

garimaHi,

I'm trying to restrict this program to find the initial 4 peaks in datasets (irrespective of that there may be more picks are present in available data.)

Could you help me with this?

Wenzel SalzmannNice function, very helpful. Maybe you should mention that it only works on double type arrays. Had one with uint8 which didnt work before parsing it

Zan AslettAsatur KhurshudyanIvan RojkovDennis Blenke@MiguelMireles, that unfortunately doesn´t fix the problem. My signal has maximum and minimum values which are both positive (e.g. Max 15 Min 0,2). If thats the case the code doesn´t work. Not even for the maximum values

MiguelMireles@Dennis Blenke, simply multiply by minus one your signal so that your minima will become maxima and apply the code

Dennis BlenkeIs there a way to find minima even if they are higher than 0 ???

Matt CannonThis worked great and it was super easy to use. Thanks!!!

mk14The function works perfect. But why sel is set default as (max - min)/4? Any reference here? Appreciated.

Faycal SaffihThis function will perform poorly for a step function that should not be considered a pulse as this function does :-(

JeminPerfect.Thank you very much.

Alberto CominTHINH PHANThank you. It work very well on my project. I appreciate your work.

Victor Garcia MuñozBob DAGreat tool! My only request would be to add an optional output argument that provides error bars for interpolated results.

Cynthia KahlDoes this work for 3D plots?

Astha KukrejaSom AggClayder Gonzalez CadenillasThanks! This code was very useful for my purposes. I implemented a C++ version that you can find here: https://github.com/claydergc/find-peaks. Hope it helps!

Z SHUHi, well-written code. However, I am not sure about the definition of sel,

Mohamed Abd Allahgreat code. I needed to include endpoints and exclude them if they appear in the answer, otherwise in some case I get an error: index exceeds matrix dimension.

Otherwise, good code and very useful.

Thanks!

Chuck RennebergMichel du MontmorencyMuch less arguments than matlab findpeaks and, nonetheless, much more effective!

Patrick GreggSuper code. User friendly, works very well.

Patrick GreggAnna LevantGreat function, thanks! very user friendly and works perfectly.

SirmwamiThe following gives an error instead of an empty vector:

x0 = [ 1 1 0];

sel = 3;

thresh = 5;

extrema = 1;

includeEndpoints = false;

interpolate = false;

peakLoc = peakfinder(x0, sel, thresh, extrema, includeEndpoints, interpolate);

Otherwise, code is good when it works

Chrisso AnonymousDimitrios ParaskevasGreat code. Could you please be more specific as to the meaning of input variable 'sel'?

paul harderEdward Smith-UchotskiGreat code, if you wish to use in subfigure you can comment out the figure that is at the bottom of the code. This then allows you to use subplot. Amazing code

Tony MacariGreat job on this fubction Nathanael

Huzeyfe ErkekChristopher EckersonNavid Asmari SaadabadNavish WadhwaH HuangIt works very nicely for my problem! Thank you!

@Ezor: 'sel' is a relative value from my understanding.

EugenIt works!

Ramtanu MukherjeeHi Nathanael Yoder,

I'm able to find Maxima, but please let me know how to find Minima?

Regards,

Ramtanu

EzorThat's great ! It could have been even better if the variable 'sel' had refered to a relative value between two points instead of an absolute one.

StefanMike BailarnoldHi Nathanael,

very useful function, thanks.

I've been getting this warning about Nargchk for a while now, maybe you can exchange it.

===========================

Warning: NARGCHK will be removed in a future release. Use NARGINCHK or NARGOUTCHK instead.

> In peakfinder (line 83)

===========================

Carl WitthoftOK, what just happened? Matlab 2015a, and the function "boolean" doesn't exist. You should remove it in favor of the actual boolean operators, or indicate that Simulink is required.

thanks

Nathanael Yoder@Mohamed

Unfortunately there were no real equations as most of the algorithm was based on intuition. Please just cite using something similar to the link below:

https://scholar.google.com/scholar?cluster=7164010680339322125&hl=en&as_sdt=2005&authuser=1#

Glad you found it useful!

tokiyoshiMohamed Abdel HamedHi Nathanael,

Do you have a PDF with the used equations and citations ?

I need to cite your work correctly.

Thanks.

Mahmut RuziHi, Nathanael. Thanks for the code. It's very fast and easy to use. Great code !

MOHAMED BENNASARThank you for sharing this function, Is there reference for this method ?

Gerald SchlegelDipankar KumarI am new in the MATLAB. How to implement the peakfinder code?

AnaHi Nathanael,

I'm trying the following and is not working. Could you help me on this?

A=rand(1,4,5);

peak_num=zeros(5,4);

for w=1:5

peak_num(w,:)=peakfinder(A(1,1:4,w))

end

peak_num;

in this case the vector of peaks found for each w has a different size.

Thanks

AnaHi Nathanael,

I'm trying the following and is not working. Could you help me on this?

peak_num=zeros(130,108);

for w=1:108

peak_num(:,w)=peakfinder(ss(1,1:1301,w));

end

eak_num;

in this case the vector of peaks found for each w has a different size.

Thanks

Svet ShkolyarHi, I'm really new to MATLAB. I would like to use your peakfinder routine, which I think is going to do exactly what I want.

I am trying to define an approach for quantifying noise in some spectral data I've taken where contaminants are present. I'd like to use a S/N threshold to define above how many standard deviations my data is contaminant vs. real. I suspect real peaks in my spectral data will be hundreds of standard deviations above the threshold (compared to a standard) and contaminants will be maybe 10s of times above it (compared to a standard).

I downloaded your routine but I'm not sure how to modify it to read in a specific spectral data file, then find the peaks in a noisy region in that spectrum, then calculate the average and standard deviation of those peaks.

It is not clear to me where in your routine to insert a readfile command and where to insert a command that prints the peaks to a file (csv?)...

Thanks!

BinuHi Nathanael! This is very useful function. Thanks for posting it. I noticed a couple of bugs in the code. They are quick fixes.

1) Looks like a typo on line 139, instead of nargin < 6 you have it as 5.

2) In the while loop on line 205, there are conditions where the variable 'tempLoc' and 'tempMag' are not declared (E.g. line 256).

korkamthank you

Daniele DequalVery useful, many thanks!

Emmanouil BarmpounakisPradeep KumarPradeep Kumarhi folk!

Although I am new in matlab but using this peakfinder code. This is fantastic code. But I need this code in C language for that I tried to convert but not able to convert.

so please if any of you have this code in C, may I get it.

Pradeep

Edward CarneyThis code saved me hours. I had a peak-finding problem that the newest version of findpeaks took care of nicely with the MinPeakProminence parameter. Unfortunately, my colleagues at another university only had access to a previous version of the function. After tweaking some of the parameter values in the function call, all went nicely.

Thanks for your work!

Ali AllenHi 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

Peter PThis 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.

Maasi AL-MayaliHi 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

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

MoniqueDeepesh upadrashtaGood one. Nice work. Thanks.

FortyTwoExcellent. Worked well for my application.

HaithamMattWorks well, thanks!

amir afrashtehpourhello

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

MariaThanks, works great!

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

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

yonatan gerufiNathanael 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.

FrankWorks (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

dongLiang ZOUGreat. It works fine for ecg peak detection.

Liang ZOUTrevorVery 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)

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

AliIt works fine.

Is there any code to find minimums (instead of peaks)?

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

Fan D.ChenRunning very smooth, helped me a lot, thank you

SherifThanks.

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

JakobI get an error message:

Cell contents reference from a non-cell array object.

Error in peakfinder (line 98)

for cell=1:length(cellList{frame})

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

Thank You

HanBest code ever.

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

SandraHow should I cite this code?

Todd Karinemmahi team

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

Thanks

dolphingood

Ershad Ahamed Chemmalasserimitra devkotaDear 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

WillemWang Feiran, to to find valleys you can use

peakfinder(data,[],[],-1)

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

Wang FeiranBtw,how to use this code to detect valley?Thanks

Wang FeiranHello,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?

Morteza DehghanirajHello 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 ???

Jan HeldalJoanne: 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.

JoanneSorry, 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

JoanneI get the error:

Undefined function 'peakfinder' for input arguments of type

'double'.

rajthe 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

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

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

DianaHi, 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

mohammadReally nice

RobertEstella LiuElisaHi. 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.

Nathanael YoderThanks 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.

TimI 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!

Davidfantastic code, very effective even with highly noise data.

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

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

antonio Acamporathanks

AndresThe bugs were fixed quickly. Thanks Nate!

AndresI 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

Morvan