The Hall effect LED current controller measures a bunch of analog signals that have a lot of PWM ripple, so I average ten readings:
//-- Read AI channel
// averages several readings to improve noise performance
// returns value in volts assuming known VCC ref voltage
#define NUM_T_SAMPLES 10
float ReadAI(byte PinNum) {
word RawAverage;
digitalWrite(PIN_SYNC,HIGH); // scope sync
RawAverage = (word)analogRead(PinNum); // prime the averaging pump
for (int i=2; i <= NUM_T_SAMPLES; i++) {
RawAverage += (word)analogRead(PinNum);
}
digitalWrite(PIN_SYNC,LOW);
RawAverage /= NUM_T_SAMPLES;
return Vcc * (float)RawAverage / 1024.0;
}
The PIN_SYNC output produces the upper trace, with the LED current in the lower trace at 50 mA/div:

In round numbers, ten samples require 1.1 ms and cover about 35 PWM pulses (using 32 kHz PWM, as you really should if you need an actual analog voltage).
Because the samples occur asynchronously with respect to the PWM pulses, the computed average comes out surprisingly close to the actual average. Fewer samples would probably be just as good, but I’m in no hurry.
Comments
2 responses to “Arduino Analog Input Averaging”
At first I thought, if you were in a hurry and had pins to spare, you could connect the signal to several analog inputs. Then I remembered that the AVR only has one digitizer and it multiplexes the inputs to it.
It’s a flying-cap multiplexer that puts an upper limit to the source impedance and the Arduino layout gives you a handful of dither for free.
In this case, however, you must do temporal averaging: many samples that are more-or-less randomly distributed over the PWM cycle.