rotary potentiometer/Using the number/09. Smoothing the reading
Using the number · 09 of 10

Smoothing the reading

A still knob does not give a still number: every ADC reading wanders by a few counts. A running average takes the wander out, and the price is lag. Moving the average an eighth of the way to each new reading, a hundred times a second, is steady and still feels direct.

A still knob, a moving number

Leave the knob alone and print the reading, and the last digit or two keep changing. The ADC is measuring a real voltage with real electrical noise on it, and every conversion lands a little differently. On an Uno the wander is usually a count or two; on the 12-bit boards, and the ESP32 in particular, it is more.

For a knob that only sets a brightness, nobody notices. For a knob whose value is printed, compared with a threshold or shown on a display, the flicker is the first thing anyone sees.

Jitter against lag
Weight of each new reading
Raw noise
up to 12 either side
Average wanders
10 counts
Readings to follow a turn
8
The grey dots are what analogRead returns: the knob is still, but the number is not. The green line is the average the sketch keeps. Run it.

An average that moves a fraction each time

The sketch keeps one number, the average, and each time it reads the pin it moves the average a fraction of the way towards the new reading. With a weight of 1/4 the average goes a quarter of the way; with 1/16, a sixteenth. Noise pulls it up and down by a fraction of the noise, so the wander shrinks. A real turn keeps pulling it the same way, so the average follows, a little late.

The figure's noise is a picture of the behaviour, not a measurement of any board. Its shape is what matters: at 1/16 the line is steadiest, and takes about 35 readings to catch up with a turn. At 1/4 it catches up in about 8 and wanders more. The sketch uses 1/8, about 17 readings, and at a reading every 10 ms that is under two tenths of a second, which still feels direct.

This is the same trade as debouncing a button: a window long enough to ignore what you do not want, and short enough that the reader does not feel it.

A dead band, for values you act on

A smoothed number still flips between two neighbours when it sits right on the boundary. If the sketch does something when the value changes, send a message, move a servo, redraw a display, only accept a change of two counts or more from the last value it acted on. That dead band costs no lag, and the flicker stops.

Smoothing does not straighten the bend: it averages the reading it is given. Smooth first, then look the result up in the calibration table.

The code

One reading every 10 ms, and an average that moves an eighth of the way towards each new reading. It prints both, labelled, so the Serial Plotter draws the raw reading and the smoothed one as two lines on the same axes.

rotary_pot_smooth.ino
/*
  Rotary Potentiometer - smoothing                       TK08 / /p/tk08

  Wiring. Count from the square pad on the TinkerBlock board, knob
  up, header at the bottom:

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
              (the full turn puts VCC on your analog pin)
    NC     -> nothing   (unconnected on the board)
    SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
              ESP32-S3, GP26 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. ESP32S3 Dev Module
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    Tools > Serial Plotter        at 115200, Serial Monitor closed
    No library needed.
*/

// The pin SIGNAL is wired to, picked for the board you compile for.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
#if defined(ARDUINO_ARCH_AVR)
const int POT_PIN = A0;
#elif defined(ARDUINO_ARCH_RP2040)
const int POT_PIN = 26;
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
const int POT_PIN = 4;
#else
const int POT_PIN = 34;         // the classic ESP32
#endif

const int SMOOTH_N = 8;         // each reading moves the average 1/8
float average;

void setup() {
  Serial.begin(115200);
#if !defined(ARDUINO_ARCH_AVR)
  analogReadResolution(12);     // the Pico's core starts at 10 bits
#endif
  average = analogRead(POT_PIN);    // start from a real reading
}

void loop() {
  int raw = analogRead(POT_PIN);
  average += (raw - average) / SMOOTH_N;

  Serial.print("raw:");
  Serial.print(raw);
  Serial.print(" smooth:");
  Serial.println(average, 0);
  delay(10);                    // a hundred readings a second
}

The average is a float so the eighths are not lost to rounding. Start it at a real reading, as setup() does, or it spends its first second climbing up from zero. SMOOTH_N sets the trade: larger is steadier and slower.

When it does not work

The smoothed value still flickers by one at the edge.

Any number that is rounded will sit on a boundary sometimes and flip between two values. If something acts on the exact value, only accept a change of two counts or more from the last value you acted on. That dead band, called hysteresis, stops the flicker without adding lag.

The knob feels slow to respond.

The average is too heavy, or the loop too slow. With a weight of 1/8 the average needs about seventeen readings to catch up with a quick turn; at a reading every 10 ms that is under two tenths of a second. Use a lighter weight, or read more often.

Should I average in the ADC instead?

You can take several readings in a row and average them, as the calibration sketch does with sixteen. That smooths each value but makes each one slower to take. The running average here keeps one cheap reading per loop and spreads the averaging over time.

How much wander is normal?

A few counts on an Uno, and often more on the 12-bit boards, especially the ESP32, whose ADC is noisy by design. Wander of tens of counts that follows your hand is not noise: the SIGNAL wire is loose and the pin is floating.

Where this goes next

Six wrong readings and the one thing to check for each.

When the reading is wrong

Edit this page — content/books/rotary-potentiometer/smoothing-the-reading.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Rotary Potentiometer

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum