Hi all,
I'm working on a project which logs the RPM of a shaft; shaft has magnets on it and I'm using a reed switch which pulls an input to ground when a magnet is near. The code is using an interrupt and measuring the period to work out RPM. This works fine. However I'd like to include some 'smoothing' or noise reduction in the data.
My ISR for the rpm calc is as follows;
void DSIsr()
{
unsigned long DSnow = micros();
unsigned long DSinterval = DSnow - DSlastPulseTime;
if (DSinterval > 100)
{
DSrpm = 60000000.0/(DSinterval * DSpulsesPerRev);
DSlastPulseTime = DSnow;
}
}
I then log the result of DSrpm (to SD card eventually but currently just to the Serial output) at an adjustable refresh rate using;
Adding in a fraction, say 30%, of the difference between the current value and the new data creates a much smoother change profile and eliminates spikes and fluctuation.
Your ISR should simply count pulses (one per time called). You should only calculate RPM when you need to display it. The RPM value is a function of the number of pulses per unit of time. The number of pulses is known, as is the unit of time (the refresh time).
like marco_c said, using a fraction will smooth the data. I use the code below in several sketches, a method I found in the book "30 Arduino Projects for the Evil Genius" by Simon Monk. Alpha is a number between zero and one. Larger alpha for more smoothing.
Use a Hall sensor instead of a reed switch to detect the magnets. Contact bounce in the reed switch is likely to cause jitter. There may be less need for smoothing if you eliminate this jitter. Hall sensors cost very little these days.
One way of smoothing the output is to measure the time for several rotations instead of just one. You could have the ISR record the times of e.g. the last 8 pulses instead of just the last one, like this (warning: untested code!):
Use a Hall sensor instead of a reed switch to detect the magnets. Contact bounce in the reed switch is likely to cause jitter. There may be less need for smoothing if you eliminate this jitter. Hall sensors cost very little these days.
One way of smoothing the output is to measure the time for several rotations instead of just one. You could have the ISR record the times of e.g. the last 8 pulses instead of just the last one, like this (warning: untested code!):
unsigned long refreshcurrentMillis = millis();
if(refreshcurrentMillis - refreshpreviousMillis > refresh) {
refreshpreviousMillis = refreshcurrentMillis;
noInterrupts();
unsigned int lr = lastReading;
unsigned long interval = times[lr] - times[(lr + 1) % nReadings];
interrupts();
unsigned long DSrpm = ((nReadings - 1) * 60000000UL)/interval;
lcd.setCursor(0, 1);
lcd.print(DSrpm);
lcd.print(" ");
lcd.print("RPM ");
}
I've done the calculation in unsigned long instead of float for better speed, but you can use float if you want to display fractional RPM.
Thanks for that!
Fractional RPM isn't needed, not sure why I used float in my code actually, I think it's code I used from another project that displayed a fractional RPM.
The whole length of the event I'm logging will only be 9 seconds (hopefully a bit less) and the shaft will accelerate from 0 RPM to about 7000 in that 9 seconds. I'm looking for the most accurate RPM calculation I can get to analyse the acceleration rate of the shaft over the 9 seconds. The shaft will have 4 magnets at 90 degree intervals, so there will be 4 'pulses' per revolution.
Will your method give a less accurate or less 'responsive' result then the original calculations, or will the difference be negligible?
nitrolx:
I'm looking for the most accurate RPM calculation I can get to analyse the acceleration rate of the shaft over the 9 seconds.
I think you need to be clearer about what you're trying to achieve. Smoothing will reduce the accuracy, not increase it. Exactly what are you trying to get out of this thing?