No announcement yet.

Peak Detection (waveforms)

  • Filter
  • Time
  • Show
Clear All
new posts

  • Peak Detection (waveforms)

    Does anybody have some code or references for doing peak detection in waveforms. I want to locate peaks, some positive, some negative, some sharp, some broad, in a fairly short collection of data points, say less than 10,000. I'm fiddling with a slope approach, but suspect I'm reinventing the wheel.


  • #2
    Maybe a selection window ?


    I do not have code for you, but just a remark.
    I have done a lot of measuring, but automatic detection of peaks is in general not so easy.
    Waveforms may be very complex and often there are many points that may be considered as peaks.
    In general peak detection will work properly only for specific cases.
    The best approach i have seen, is to provide a selection window to close in one specific peak,
    after which the precise amplitude can be found easily.

    Arie Verheul


    • #3
      forgive an ignorant question - I've never tried this - but how is a peak defined? I thought maybe a peak is an observation or set of equal observations preceded by lower values suceeded by lower values?


      • #4
        What kind of wave are you asking about? Waves usually are symmetrical beasts of a sort, implying consistent distances between peaks and troughs with accommodation for the Doppler effect. Such waves are generally the same height although they can be diminishing or increasing depending on direction from the source.
        This sounds to me like you are referring to something like stock market quotes for example, some of which appear to have a wave like existence, but oscillations are not consistent.
        In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.


        • #5
          Already you've given me a huge help- define what the heck it is I'm trying to detect, and what environment it exists in. In my case, the waveform is more or less sinusoidal, but with variation of period between the cycles. Basically some FM. The amplitude is moderately stable, but varies by 20% or so. The only cases where slope might fail are where the noise level is high and I don't allow a wide enough window. Fortunately, it's not like music and there aren't any significant secondary peaks to lead me astray. I should have this working over the weekend and will post the code (for good or bad).



          • #6
            Originally posted by Rodney Hicks View Post
            Waves usually are symmetrical beasts of a sort...
            I take it that you live at a considerable distance from the sea?


            • #7
              There is a marker on the Trans-Canada Highway just 35 kilometers east of where I live that declares the East to West midpoint of Canada. And it's a big country. So yeah, you could say I'm not accustomed to the large bodies of water.

              But "of a sort" was my qualifier.
              In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.


              • #8
                FWIW, here's the useful part of the function that's working well for me-

                FUNCTION ReduceMyData(P() AS SINGLE, FD() AS SINGLE, N AS LONG) AS LONG
                                                       'P() holds X axis, FD() holds amplitude (y axis), N is number of data points
                    LOCAL MyCount AS LONG              'loop counter
                    LOCAL PeakPos() AS LONG            'array stores location/position of peaks
                    LOCAL PeakCnt AS LONG              'accumulates peaks
                    LOCAL LastSign AS LONG             'slope of last test
                    LOCAL w AS LONG                    'window width
                    LOCAL hDlg AS DWORD
                    DIM PeakPos(200)                   'dimension this for greater than expected total number of peaks in data
                    DIM P(N)
                    DIM FD(N)
                    w = 5                                                       'window width, use odd number, increase for noisy data
                    LastSign = SGN(FD(w)-FD(0))                                 'get starting slope
                    FOR MyCount = 1 TO N-w
                        IF SGN(FD(MyCount+w)-FD(MyCount)) <> LastSign THEN      'look for change in slope
                             PeakPos(PeakCnt)=P(MyCount+1+w\2)                  'store location/position of detected peak
                             LastSign *= -1                                     'flip the sign of the sign flag
                             PeakCnt += 1                                       'increment the peak counter
                        END IF
                    NEXT MyCount
                END FUNCTION
                The whole IF statement can be done on one line, but I'm not sure it saves anything. Also, is *= -1 a good way to flip a sign, or is there a preferred way?



                • #9
                  is *= -1 a good way to flip a sign, or is there a preferred way?
                  I'd prefer:
                  LastSign = -LastSign


                  • #10
                    absolutes and check the sign of the direction??? (just a thought)
                    Engineer's Motto: If it aint broke take it apart and fix it

                    "If at 1st you don't succeed... call it version 1.0"

                    "Half of Programming is coding"....."The other 90% is DEBUGGING"

                    "Document my code????" .... "WHYYY??? do you think they call it CODE? "


                    • #11
                      Originally posted by Conrad Hoffman View Post
                      The whole IF statement can be done on one line, but I'm not sure it saves anything.
                      The difference in execution time is probably less than insignificant. Many many program snafus are the result of line packing. Code is MUCH easier to follow broken into separate lines. Though it does look cool (to some) to have long involved formulas in one line.
                      Also, is *= -1 a good way to flip a sign, or is there a preferred way?
                      If it works for you that's fine. What I often use is
                       Flag = Flag XOR 1 ' 0 or 1
                      Sooner or later,
                      false thinking brings wrong conduct.
                      Julian Huxley
                      Last edited by Gösta H. Lovgren-2; 6 Dec 2008, 10:17 PM.
                      It's a pretty day. I hope you enjoy it.


                      JWAM: (Quit Smoking):
                      LDN - A Miracle Drug:


                      • #12
                        Also, is *= -1 a good way to flip a sign, or is there a preferred way?
                        It is a good way to flip a sign, just not as self evident as others.
                        It's one of those things that I have to stop and make sure I interpreted it correctly, breaking the flow so to speak.
                        It is a tool in the toolbox, to be used if you're comfortable with it for yourself.
                        In some future era, dark matter and dark energy will only be found in Astronomy's Dark Ages.


                        • #13
                          It seems to me that if your data 'flat lines,' i.e. you get an indefinite set of equal amplitudes having SGN()=0, then you will be mis-counting these data as peaks.

                          Also, I'm curious, did you mean this, PeakPos(PeakCnt)= MyCount+1+w\2, instead of this, PeakPos(PeakCnt)=P(MyCount+1+w\2) ?

                          Am I misunderstanding the value of setting w =5? But doesn't interating though every data point with a span of w simply offset the literal peak? Why not examine every interval, w=1, collecting all counted peaks, and then afterward discount peaks that occur within a of span=w ?


                          • #14
                            Hi John- Looking for peaks in flat line data definitely breaks things. Fortunately my data is a nice continuous waveform of decent amplitude so the case doesn't arise. I'm not sure how one would handle it, other than increasing w, which improves resistance to noise and short term variations. That, BTW, is the reason for w, as it allows me to eliminate minor bumps and such that don't qualify as peaks. There are also two types of data. Mine is in the form of amplitude and position, and position is not necessarily regular, thus my use of P(). If one had regular data, say from a signal generator or audio recorder, where the sample time was constant, a different and probably even simpler method could be used. One more note- I use odd values for w so I can identify the peak as being the center value, but my overall code was a bit convoluted because of an invalid first data point (the result of what generates the data), and I ended up with the peaks offset by one point. This was easily fixed by not adding 1 someplace, but I think the posted code is correct. Now I'm on to smoothing, graphing, interpreting what it all means, and incorporating the function into the full test program it was intended for!

                            Here's source, exe and sample peak file to play with. Not fancy.
                            Attached Files
                            Last edited by Conrad Hoffman; 7 Dec 2008, 04:46 PM. Reason: Added source and exe for demo


                            • #15
                              Hmmm... if I don't bump this, nobody will know I added the files to the last post.



                              • #16
                                I also needed zero crossing detection and found that accuracy could be improved if I just did a linear interpolation back from the point just over zero. Here's the code for that.

                                   'Find the Zero Crossings
                                    LastSign = SGN(FD(0))
                                    FOR mc = 1 TO N-1
                                        IF SGN(FD(mc)) <> LastSign THEN               'this identifies the second of two points *after* crossing zero so let's interpolate
                                            ZeroPos(ZeroCnt) = P(mc-1) + ((0-FD(mc-1)) * (P(mc)-P(mc-1)) / (FD(mc)-FD(mc-1)))           'linear interpolation from previous point
                                            LastSign = -LastSign                      'warning- SGN can return zero for exact zero numbers- rare but might need to trap this
                                            ZeroCnt += 1
                                        END IF
                                    NEXT mc