8
$\begingroup$

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?

enter image description here

$\endgroup$

1 Answer 1

13
$\begingroup$

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]

enter image description here

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}]

enter image description here

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

enter image description here

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.

$\endgroup$
9
  • $\begingroup$ Beaten by 1 min, nice educational use of rescale, +1 $\endgroup$
    – user9660
    Commented Apr 19, 2016 at 11:23
  • 1
    $\begingroup$ How do I know when I have to rescale? $\endgroup$
    – mrz
    Commented Apr 19, 2016 at 11:43
  • $\begingroup$ @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?) $\endgroup$
    – Jason B.
    Commented Apr 19, 2016 at 11:46
  • $\begingroup$ But you get now the right amplitudes ... when is it necessary to rescale? $\endgroup$
    – mrz
    Commented Apr 19, 2016 at 11:47
  • 1
    $\begingroup$ Brute force: ListPlot[data, Epilog -> {AbsolutePointSize@10, Red, Point@data[[First /@ FindPeaks@Standardize[Last /@ data]]]}] $\endgroup$
    – Kuba
    Commented Apr 19, 2016 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.