# Peak detection to find frequency of input

Hi,

I am recording a cyclic motion using an accelerometer. I have absolute points of reference; the top of the cyclic reolution and the bottom (they appear as peaks and troughs in a almost sinosoidal graph.) I want to find the frequency of the cyclic movement. For instance when the gradient goes from positive to negative I want to make a counter. so I can turn it into an RPM.

I have tried doing this, but I can only manage for the midpoint, by saying when

``````if (oldData < RefVoltage && newData > RefVoltage) { //ref voltage is at the midpoint of the wave
counter = counter +1;
}
``````

however due to external factors of my project the mid point isnt always accurate for finding frequency… Only the peaks and troughs are 100% accurate.

So I tried this:

``````if (newData < oldData && oldData >= olderData) {    //olderData  before the peak and newData after.
counter = counter + 1;
}
``````

but this gave tonnes of false readings! Can anyone give me ideas of how to approach this?

Kind regards,

Dunc

Only the peaks and troughs are 100% accurate.

but this gave tonnes of false readings!

Only one of these statements can be true.

Google “peak detection algorithm” for lots of ideas.

Measurement noise usually makes approaches like this unworkable:

``````if (oldData < RefVoltage && newData > RefVoltage) {
``````

Sorry I meant in theory ONLY peak and trough will be accurate! and in THEORY midpoints arent! I have achieved finding the midpoints but the RPM found from these wont describe the system im studying perfectly (there will be error). If I manage to effectively capture the peaks and throughs (which I so far havent been able to do) it will give me an accurate RPM that will describe the system I am testing.

Here is my entire code for midpoint:

``````#include <Wire.h>

float gForceZ;

float gForceY;
float accelX;
float accelY;
float accelZ;

float total = 0;
float average = 0;

int k=0;
float total2;
float runningAvg;

int counter;
float oldAverage;
float oldTime=0;
float diff;

void setup() {
Serial.begin(9600);
Wire.begin();
setupMPU();
}
}

void setupMPU(){
Wire.beginTransmission(0b1101000); //This is the I2C address of the MPU (b1101000/b1101001 for AC0 low/high datasheet sec. 9.2)
Wire.write(0x6B); //Accessing the register 6B - Power Management (Sec. 4.28)
Wire.write(0b00000000); //Setting SLEEP register to 0. (Required; see Note on p. 9)
Wire.endTransmission();
Wire.beginTransmission(0b1101000); //I2C address of the MPU
Wire.write(0x1C); //Accessing the register 1C - Acccelerometer Configuration (Sec. 4.5)
Wire.write(0b00000000); //Setting the accel to +/- 2g
Wire.endTransmission();
}

void loop() {

Wire.beginTransmission(0b1101000); //I2C address of the MPU
Wire.write(0x3B); //Starting register for Accel Readings
Wire.endTransmission();
Wire.requestFrom(0b1101000,6); //Request Accel Registers (3B - 40)
while(Wire.available() < 6);
gForceY = accelY / 16384.0;
gForceZ = accelZ / 16384.0;

//k = k+1;

}
runningAvg = total2/k;     //running average for as long as program has been on

diff = 50*(average - oldAverage)/ (millis()-oldTime);    //finding gradient
oldTime = millis();
//Serial.println(average - oldAverage);
if (oldAverage < runningAvg && average > runningAvg && diff> 0.03) {
counter = counter +1;
}

Serial.print(average);
Serial.print(",");
Serial.print(runningAvg);
Serial.print(",");
Serial.println(counter);

counter = 0;
delay(50);

oldAverage = average;

}
``````

To get an accurate RPM value (assuming that a single value can be used to accurately characterize the rotation), find an angular frequency that fits all the data for an entire cycle of the motion.

You should be able to fit a sine curve, but show us an example of the data.