3
\$\begingroup\$

I'm trying to get the peaks/zero crossings from a basic 1D signal and am not sure if my naive/basic approach is correct:

float[] signal = {168.02423,167.11852,167.50813,166.8597,166.05814,165.11226,164.18024,162.52278,159.26706,154.01059,151.02512,145.88942,139.96555,131.64963,128.41841,125.55873,123.26397,121.80526,120.997765,120.13878,120.15161,120.45633,121.23436,120.788994,120.17174,119.775856,119.009384,117.477,115.0316,108.588875,100.850945,88.417404,82.39221,74.47572,68.39083,60.352554,57.09356,54.930645,54.195927,53.56418,53.094868,53.119434,53.129646,53.692352,53.817867,54.48929,55.07399,56.200096,56.464325,56.61977,56.26392,55.87918,55.708,56.005222,56.370075,57.943306,60.338276,66.09525,71.971245,83.3894,93.25841,106.6345,111.20811,114.71198,117.44606,120.572174,122.55059,125.76803,130.27737,136.78697,139.3824,141.46649,143.04817,146.876,153.58531,163.69055,167.01625,169.79066,171.79346,172.96455,174.65863,174.15462,169.83751,160.82489,157.3805,154.58945,152.88863,151.37778,149.86177,148.10445,146.99503,143.16574,136.07457,123.7554,116.98741,107.79893,101.15501,92.90702,89.435356,86.62778,84.60331,82.44227,81.345985,80.086426,78.7316,75.1582,70.30843,62.90986,60.226223,57.940796,56.880646,55.95489,55.675377,55.12072,54.582558,53.560856,53.353596,53.047993,52.981926,52.87674,53.188942,53.541054,53.332302,52.96336,52.367634,53.034874,54.12153,54.88389,57.317207,60.54665,66.118195,70.391785,77.9589,84.03312,93.41969,99.085686,105.99711,109.171776,112.26317,114.13363,116.024254,117.41363,118.9697,120.61764,121.154816,121.67257,121.55961,121.32448,120.59877,120.989365,121.22733,121.907104,122.72483,123.732155,124.994804,126.84889,129.00806,134.3398,141.73413,152.50774,156.32497,159.0031,160.628,161.92178,163.19771,164.65904,166.22505,167.14778,167.68938,168.30038,168.64857,169.15517,168.63728,168.94241};
int sl = signal.length;

void setup(){
  size(400,400);
  noFill();
  smooth();

  float[] sorted = new float[sl];
  arrayCopy(signal,sorted);
  Arrays.sort(sorted);
  float min = sorted[0];
  float max = sorted[sl-1];

  background(255);
  boolean wasPlus = true,isPlus = false;
  for(int i = 0 ; i < sl; i++){
    //plotting
    float x = map(i,0,sl,1,width-1);
    float y = map(signal[i],min,max,height,0);
    stroke(0);
    line(x,height,x,y);
    //zerox
    float c = signal[i];//current
    float p = signal[i < 1 ? sl-1 : i-1];//previous
    isPlus = (c-p) > 0;
    if(isPlus != wasPlus) {
      stroke(192,0,0);
      ellipse(x,y,5,5);
      wasPlus = isPlus;
    }
  }
}

Results:

zerox preview

It looks like I'm close, but I was hoping I can get one circle at a peak, not several. Any hints/tips?

\$\endgroup\$
1
\$\begingroup\$

Well, fine for good signals. Good signals means low noise level, absense of features like very slow volume change rates, etc. Otherwise, you need things like FIR filter(s) to average and diffifentiate signal and use an interpolation to increase precision of the detection.

\$\endgroup\$
  • \$\begingroup\$ Thanks! I've used 'triangle' smoothing/averaging on the original data first, above is the result. Any tips on how I can get one peak marked instead of several close ones ? \$\endgroup\$ – George Profenza Mar 28 '12 at 10:30
  • \$\begingroup\$ Sorry, I didn't do my reading on FIR filters :) Moving average does the tricky in this case. Thanks again! \$\endgroup\$ – George Profenza Mar 28 '12 at 10:38
  • \$\begingroup\$ Moving average is an example of FIR :) \$\endgroup\$ – Michael Mar 28 '12 at 11:39

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.