<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>MeccaBLOG: Peak search algorithm</title>
    <link>http://meccablog.ing.unitn.it/articles/2009/07/08/peak-search-algorithm</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>The Mechatronics Group at the University of Trento</description>
    <item>
      <title>Peak search algorithm</title>
      <description>&lt;p&gt;Automation relies on autonomous evaluation of data. Someone would probably call it &amp;#8220;data mining&amp;#8221;. Today I discuss a simple data mining problem related with machining.&lt;/p&gt;


	&lt;p&gt;Let imagine that you would monitor the frequencies of vibration generated by a cutting process (say a turning operation). You are more interested in frequency than in amplitude, because process changes are more easily correlated to frequencies than to amplitudes.&lt;/p&gt;


	&lt;p&gt;Now you&amp;#8217;re probably saying: &amp;#8220;that&amp;#8217;s a piece of cake: let&amp;#8217;s attach a couple of accelerometers to the lathe, acquire the signal and compute its &lt;span class="caps"&gt;FFT&lt;/span&gt;!&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;Well, that&amp;#8217;s actually only the first part of the problem.&lt;/p&gt;


	&lt;p&gt;The second part of the problem is to &lt;em&gt;automatcally&lt;/em&gt; extract the frequencies of &lt;span class="caps"&gt;FFT&lt;/span&gt; peaks so any suitable control algorithms could use them.&lt;/p&gt;


	&lt;p&gt;Let&amp;#8217;s come to an example. The figure hereafter is a plot of acceleration (in appropriate unit of measure) vs. time.&lt;/p&gt;


	&lt;p&gt;&lt;img src="/files/peaksearch_signal.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;As you see, looks like we have a few frequencies, plus noise , and plus a damping decay.&lt;/p&gt;


	&lt;p&gt;You decide to sample 20 seconds of this signal at 100 Hz and then to apply a Hamming window (just to avoid nasty effects in &lt;span class="caps"&gt;FFT&lt;/span&gt;!). What you get is something like that:&lt;/p&gt;


	&lt;p&gt;&lt;img src="/files/peaksearch_windowed.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;OK, next step is to apply the ubiquitous Fast Fourier Transform and to plot its modulus as a function of frequency:&lt;/p&gt;


	&lt;p&gt;&lt;img src="/files/peaksearch_fft.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;You&amp;#8217;d say: see! looks like we have four modes: at 1, 5, 24, and 32 Hz (approximatively). Right, but now the question is: how can we detect these four peaks &lt;em&gt;programmatically&lt;/em&gt;? Can we define an algorithm that sips that plot and gives back an array of four frequency values?&lt;/p&gt;


	&lt;p&gt;Yes we can, that&amp;#8217;s obvious. There are different ways to do that, and one is to mimic what we do when we look at a plot and spot out the significative peaks.&lt;/p&gt;


	&lt;p&gt;To do that, our eyes make a collection of &amp;#8220;objects&amp;#8221; that have a significative difference with respect to the average &amp;#8220;noise&amp;#8221; we see looking at the plot.&lt;/p&gt;


	&lt;p&gt;A pseudo-code algorithm to do that would look like that:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;initialize peaks as empty array
initialize in_a_peak = false
initialize s = sd(fft intensities)
initialize i = 0
initialize max = 0
for each point in fft
  set x as sd(point.freq and its n followers)
  if x &amp;gt; k*s then
    set in_a_peak as true
    if point.width &amp;gt; max then
      set peaks[i] = [point.freq, point.width]
      max = peaks[i].width
  else
    if in_a_peak then
      set i = i + 1
    set max = 0
    set in_a_peak = false&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
where sd() is the standard deviation function.

	&lt;p&gt;Note that the above sketched algorithm depends on n, which is the width of the moving window, and on k, which is the number of standard deviations that separate a peak from noise. The former parameter should be large enough to hold  the typical peak width, and small enough to contain no more than one peak. The latter has to be adjusted on the basis of the typical &amp;#8220;noise&amp;#8221; of the &lt;span class="caps"&gt;FFT&lt;/span&gt; spectrum: if it is large, it only detects highest peaks, if it is too small, you&amp;#8217;d probably catch up false peaks.&lt;/p&gt;


	&lt;p&gt;The following plot shows the moving window standard deviation on the &lt;span class="caps"&gt;FFT&lt;/span&gt; spectrum. Look carefully at it and I bet that the pseudocode above gets clearer.&lt;/p&gt;


	&lt;p&gt;&lt;img src="/files/peaksearch_fft2.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;The output of such a peak search algorithm would be something like that:&lt;/p&gt;


&lt;pre&gt;
SETTINGS:
---------
window size: 20
sigmas:      1

STATISTICS:
-----------
Overall standard deviation: 1.36238996838388 UoM
Mean value:                 1.04531452925845 UoM
Extremes:                   [0.0698284841788967, 26.0194668958268]

PEAK SEARCH RESULTS:
--------------------
Peak  0 @   34: f =     1.700 Hz,   a =    26.019 UoM (  13.2 dB)
Peak  1 @  101: f =     5.050 Hz,   a =    17.212 UoM (   9.5 dB)
Peak  2 @  487: f =    24.350 Hz,   a =     9.448 UoM (   3.4 dB)
Peak  3 @  640: f =    32.000 Hz,   a =     7.550 UoM (   2.7 dB)
&lt;/pre&gt;

	&lt;p&gt;Written in Ruby, the peak search above requests 12 milliseconds, performed on a spectrum of 2000 points. In C++ you&amp;#8217;d probably crunch the computation time down to 2 ms.&lt;/p&gt;</description>
      <pubDate>Wed, 08 Jul 2009 15:53:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:6d169467-2f9d-4ddf-b992-6609d722171c</guid>
      <author>Paolo Bosetti</author>
      <link>http://meccablog.ing.unitn.it/articles/2009/07/08/peak-search-algorithm</link>
      <category>research</category>
    </item>
  </channel>
</rss>
