# Finding peaks of curve with small values

I have 2d data of which I want to find the peaks.

data << "http://pastebin.com/raw/EQFz1KFn";
peaks = FindPeaks[data[[All, 2]], 0, 0, -Infinity] // N


The magnitudes of the found peaks are wrong:

{{22., 2.58437*10^-10}, {67., 2.86902*10^-10},
{109., 2.98093*10^-10}, {150., 3.21527*10^-10},
{189.5, 3.10375*10^-10}}

ListPlot[
data[[All, 2]],
Epilog -> {Red, PointSize[0.02], Point[peaks]}, ImageSize -> Large
]


If I multiply the numbers e.g. with 10^10 then the peaks are found correctly.

What am I doing wrong?

There are often problems with interpolating functions when the dependent and independent variables have such widely different ranges. The problem goes away if you rescale your values before finding the peaks,

data = << "http://pastebin.com/raw/EQFz1KFn";
peaks = {#1, 10^-10 #2} & @@@
FindPeaks[10^10 data[[All, 2]], 0, 0, -Infinity,
InterpolationOrder -> 1]
(* {{23, 5.13993*10^-10}, {68, 3.99016*10^-10}, {110,
3.43787*10^-10}, {150, 3.50107*10^-10}, {190, 3.5024*10^-10}} *)

ListPlot[data[[All, 2]],
Epilog -> {Red, PointSize[0.02], Point[peaks]}, ImageSize -> Large]


We can check what value of the rescaling is needed in order for the peaks to be found with Manipulate,

Manipulate[
sf = 10^sff;
peaks = FindPeaks[ sf data[[All, 2]], 0, 0, -Infinity,
InterpolationOrder -> 1];
ListPlot[data[[All, 2]]/mx,
Epilog -> {Red, PointSize[0.02], Point[{#1, #2/mx/sf} & @@@ peaks]},
ImageSize -> Large]
, {{sff, 0}, 0, 2, .01}]


The fact that the largest peaks are found first indicates that there is some absolute threshold value of the peak-valley that must be reached, not a relative threshold.

What is that threshold value? To check I'll do a peak fitting on a single cycle of a cosine curve, and take the percent difference between the actual peak value and the peak value found by FindPeaks, and plot it using a logarithmic x-axis.

scalingpeaklist = Table[
sf = 10^-n;
list = Table[sf (-Cos[x] + 1), {x, 0, 2 \[Pi] + 0, .01}];
{n, (Max[list] - #2)/
Max[list] & @@ (First@FindPeaks[list, 0, 0, -Infinity])},
{n, 0, 14, .1}];

ListLinePlot@scalingpeaklist


Around $10^{-8}$. If the difference between peaks and valleys is smaller than that, then the peak found is about half it's actual size (relative to the nearest valley).

If your peaks are going to be smaller than that, you are better off always rescaling before and after peak finding.

• Beaten by 1 min, nice educational use of rescale, +1
– user9660
Commented Apr 19, 2016 at 11:23
• How do I know when I have to rescale?
– mrz
Commented Apr 19, 2016 at 11:43
• @mrz, you don't have to mark it as solved, I clearly didn't read the question fully and I feel like a dunce lol, was going to delete it when you mentioned it (in a deleted comment?) Commented Apr 19, 2016 at 11:46
• But you get now the right amplitudes ... when is it necessary to rescale?
– mrz
Commented Apr 19, 2016 at 11:47
• Brute force: ListPlot[data, Epilog -> {AbsolutePointSize@10, Red, Point@data[[First /@ FindPeaks@Standardize[Last /@ data]]]}]
– Kuba
Commented Apr 19, 2016 at 13:13