I have a dataset of an evenly spaced pulse train, formatted as $(t, a(t))$ where of course $t$ is time and $a$ is the amplitude.

I would like to extract, from this dataset, the first (or, in general, the $n$-th) pulse and its neighbourhood, to fit it with a Gaussian/Lorentzian.

  • I could do it manually, ListPlot-ing the whole dataset and roughly choosing the subset I need;
  • I could "brute force" it and write a long set of rules to achieve my goal.

Is there a neater way to do it?


As requested, here's my code so far. After importing the data, I define a function xPulse which, assuming the pulse is not right at the beginning of the file, takes $t$ elements of the list, where $t$ is the period up to a multiplying constant, defined at the beginning. This way I'm sure that (if the pulse is not right at the start of the dataset) I only get the $n$-th pulse:

xPulse[x_]:= Module[{y = t*(x - 1) + 1}, data[[y ;; y + t, 2]]]

I then fit the result

fit = Normal@NonlinearModelFit[xPulse[1], {Exp[-((x - s)^2/(2*m^2))] + n, {s > 0, m > 0}}, {s, m, n}, x, MaxIterations -> 5000]

This is what I got so far, but the approach assumes the knowledge in advance of the repetition rate (whose measurement should become a part of the notebook in the future), as well as not working correctly if the first point is part of a pulse nor taking account of the time scale.


Here's a plot of the pulse train: Pulse Train

  • $\begingroup$ Can you post an example of what exactly you mean by neighborhood. Also, please post the code you have tried. $\endgroup$ – Anjan Kumar Jun 26 '17 at 13:50
  • $\begingroup$ Are the pulses equally spaced? Please share some sample data, in addition to what @AnjanKumar mentioned as well. $\endgroup$ – MarcoB Jun 26 '17 at 14:23
  • $\begingroup$ Added what I have so far. I didn't add sample data as just one pulse takes up to 1000 points. By neighbourhood I simply mean a subset of $t$ elements containing one pulse only, preferably positioned in the centre of the subset $\endgroup$ – Enzo Jun 26 '17 at 16:22
  • $\begingroup$ Can you display a plot of an example pulse train? The key is to discriminate pulse from not-pulse. After that, the problem is easy. $\endgroup$ – MikeY Jun 26 '17 at 16:34
  • $\begingroup$ @MikeY done. The discrimination is pretty evident. $\endgroup$ – Enzo Jun 26 '17 at 16:42

some made up data similar to yours:

pulse := 20 Table[ 
   Sin[2 Pi x/50] + RandomVariate[NormalDistribution[0, .1]], {x, 0, 
data = Table[ 
    Sin[x] + RandomVariate[NormalDistribution[0, .1]], {x, 1000}] + 
   Total@Table[SparseArray[ (Range[i + #, 50 + i + #] &@
         RandomInteger[20]) -> pulse, {1000}], {i, 1, 950, 150}];
ListPlot[data, Joined -> True, PlotRange -> All]

enter image description here

find the lead edge of each pulse by threshold detection:

threshold = 10;
pulses = First /@ 
  SequencePosition[data, {x_ /; x < threshold, y_ /; y >= threshold}]

{5, 167, 322, 475, 610, 755, 905}

look at neighborhood of each pulse.

ListPlot[data[[Max[1, # - 20] ;; Min[# + 80, Length@data]]], 
   Joined -> True, PlotRange -> All] & /@ pulses

enter image description here

  • $\begingroup$ Thanks, this is a very neat approach. What if I wanted to have the peak (in my case) or the centre (in yours) of the pulse in the centre of the subset, so I have the same number of points both left and right of my pulse? I'm assuming I'll have to change those $20$ and $80$ values in the ListPlot, where you are selecting the interval. But hardcoding values can be counterproductive, as a pulse can be wider (hence requiring more points) or narrower. $\endgroup$ – Enzo Jun 27 '17 at 9:37
  • $\begingroup$ I found the function FindPeaks which, however, doesn't give the same results as your approach (in fact, FindPeaks gives 300 more elements that expected, as your code confirms. Is FindPeaks[data,0,0,threshold] wrong? If I set a blurring parameter it gives either a 1-element array, with a low blurring parameter, or random values increasing the blurring... $\endgroup$ – Enzo Jun 27 '17 at 10:44
  • 1
    $\begingroup$ Your original data looks so clean I don't see a need to try to do something more complicated than simple threshold detection. You might find each peak, then calculated the midpoints between them and call that the neighborhood without hard coding anything. $\endgroup$ – george2079 Jun 27 '17 at 18:38
  • $\begingroup$ I found a way to do that (simply calculating the mean value of the position difference between consecutive peaks, so I have the period of the train expressed in points number). I'll just use that to make sure the peak is centred. The other issue is that the time axis always starts from 0, instead of the actual time. But I guess that's easy to work around. Thank you very much. I should look into a way to fit the entire train without extracting every single peak, maybe, and a way to calculate the pulse width, but that's material for another question, I assume. $\endgroup$ – Enzo Jun 28 '17 at 10:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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