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.

Post ALL of your code.

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;

const int numReadings =10;
float readings[numReadings];
int readIndex = 0;
float total = 0;
float average = 0;

int k=0;
float total2;
float readings2;
float runningAvg;

int counter;
float oldAverage;
float oldTime=0;
float diff;
 
void setup() {
  Serial.begin(9600);
  Wire.begin();
  setupMPU();
 for (int thisReading = 0; thisReading<numReadings; thisReading++){
  readings[thisReading]=0;
 }
  }

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() {
  total = total - readings[readIndex];
  
  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);      
  accelX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX
  accelY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
  accelZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
  gForceY = accelY / 16384.0; 
  gForceZ = accelZ / 16384.0;
  
  readings[readIndex] = (gForceY + gForceZ);
  total = total +readings[readIndex];
 
  total2 = total2 + readings[readIndex];
  
  readIndex = readIndex + 1;
  
  //k = k+1;
  
 if (readIndex >=numReadings){
  readIndex = 0;
 }
  runningAvg = total2/k;     //running average for as long as program has been on
 
  average = total/numReadings;
  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.