You could use an EMA. Keep in mind that it introduces some latency (as do all real low-pass filters).
/*
Exponential Moving Average filter (single-pole IIR filter)
Difference equation:
y[n] = k*x[n] + (1-k)*y[n-1]
where y[n] is the filtered output at time n,
and x[n] the raw input at time n
y[n-1] is the previous filtered output.
k == 0.5^shiftFac
Fixed point arithmetic is used for speed.
1 == 1 << (2*shiftFac)
Two times shiftFac because otherwise, precision
would be lost when shifting (value - filtered).
Rounding is performed by adding 0.5 to the
fixed point representation before converting
to an integer.
0.5 == 1 << (2*shiftFac - 1)
*/
class EMA {
public:
/* Constructor: Initialize constants */
EMA(uint8_t shiftFac)
: shiftFac(shiftFac), fixedPointAHalf(1 << ((shiftFac * 2) - 1)) {}
/* Filter a new raw input value x[n] and return the filtered output y[n].
Should be called at regular intervals for best results. */
int32_t filter(int32_t value) {
value = value << (shiftFac * 2);
filtered = filtered + ((value - filtered) >> shiftFac);
return (filtered + fixedPointAHalf) >> (shiftFac * 2);
}
private:
/* Member variables */
const uint8_t shiftFac;
const int32_t fixedPointAHalf;
int32_t filtered = 0;
};
EMA ema(4); // k = 0.5^4 = 0.0625
const unsigned long interval = 10000; // sample every 10 milliseconds
void measureAndFilter() {
int x = analogRead(A0);
int y = ema.filter(x);
Serial.println(y);
}
void setup() {
Serial.begin(115200);
}
void loop() {
static unsigned long previousMicros = micros();
if (micros() - previousMicros > interval) { // sample at precise interval
measureAndFilter();
previousMicros += interval;
}
}
Pieter