Arduino Analog Input Averaging

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);


  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:

Arduino Analog 10x sample avg - ILED 50 mA-div

Arduino Analog 10x sample avg – ILED 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.

  1. #1 by madbodger on 2013-12-02 - 08:35

    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.

    • #2 by Ed on 2013-12-02 - 08:47

      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.