disc potentiometer/Using the number/07. Smoothing a jittery reading
Using the number · 07 of 9

Smoothing a jittery reading

Hold the wheel still and the reading still wanders: by a count or two on an Uno, by tens of counts on an ESP32. It is the ADC and the wires, not the pot. Averaging 16 reads per value takes most of it out, and costs under 2 ms on an Uno.

A still wheel, a moving number

Run the first read and leave the wheel alone. The number does not sit still. On an Uno it flicks between two or three neighbouring values. On an ESP32 it wanders over tens of counts.

That is not the pot. The wiper is a piece of metal resting on the track, and while the wheel is still, the voltage on SIGNAL is steady. What moves is the measurement: every ADC has a little electrical noise of its own, and the wires between the block and the board pick up more. The ESP32's ADC is known for being noisier than the Uno's.

Averaging

Averaging a still wheel
Your board
Reads averaged per value
Single reads spread
58
Average of 1 spread
58
Reads per value
1
One read per value: the wheel is still and the number wanders by about 58 counts on a ESP32. That is the ADC and the wires, not the pot. A display or an LED driven straight from it flickers.

The noise is random: as often above the true value as below it. Add up several reads and divide, and the ups and downs cancel. The scatter falls roughly with the square root of the number of reads, so 4 reads halve it and 16 cut it to a quarter. The numbers in the figure are an illustration of that rule, not a measurement of this block.

The price is time. Each value now takes 16 reads instead of one. On an Uno an analogRead takes about 0.1 ms, so 16 cost under 2 ms, which nobody turning a wheel will notice. At 64 the gain is small and the lag starts to show.

Why the sum is a long

On an Uno an int is 16 bits and stops at 32767. Sixteen reads of 1023 add up to 16368 and fit, but 64 of them do not, and an overflowing sum wraps round to a negative number without any error. Keeping the sum in a long means SAMPLES can be changed without thinking about it. The division at the end brings it back into range.

What averaging cannot fix

An average removes scatter that goes both ways. It does nothing for an error that is the same every time. The ESP32's flat stretches at the two ends of the travel are that kind, and the next article is about them.

The code

The first read, plus a function that adds up SAMPLES reads and divides. It prints the single read and the average side by side, so the Serial Plotter draws both.

disc_pot_smoothing.ino
/*
  Disc Potentiometer - smoothing a jittery reading       TK07 / /p/tk07

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

    GND    -> GND
    VCC    -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
              (at one stop, SIGNAL gives your pin whatever VCC is)
    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        to see both lines
    No library needed.
*/

// The pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int POT_PIN = 4;

// What analogRead returns at full scale on your board.
// Uno: 1023. ESP32, ESP32-S3: 4095. Pico: 1023.
const int ADC_MAX = 4095;

const int SAMPLES = 16;                // reads per value

int readAveraged() {
  long sum = 0;                        // an Uno's int stops at 32767
  for (int i = 0; i < SAMPLES; i++) {
    sum += analogRead(POT_PIN);
  }
  return sum / SAMPLES;
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  int raw = analogRead(POT_PIN);
  int smooth = readAveraged();

  Serial.print("raw:");
  Serial.print(raw);
  Serial.print(" smooth:");
  Serial.println(smooth);
  delay(50);
}

The sum is a long because an int on an Uno stops at 32767: 16 reads of 1023 fit, but raise SAMPLES to 64 and they do not. Open Tools > Serial Plotter at 115200 and hold the wheel still: raw wanders, smooth barely moves.

When it does not work

Averaging made the LED lag behind the wheel.

Each value is now 16 reads, and the sketch also waits between values. Shorten the delay() before shrinking SAMPLES: the reads themselves are quick. If it still lags, 8 samples is a fair middle.

It still flickers between two values after averaging.

The average is sitting on the boundary between two numbers, and any noise at all flips it. Keep the last value you used and only change it when the new one differs by more than a few counts. That is called hysteresis, and it is three lines.

Would a capacitor do the same job?

A small capacitor, around 100 nF, from SIGNAL to GND filters in hardware what the average filters in code, and the ESP32 ADC article suggests one for long wires. For a thumbwheel on a short cable, the average alone is usually enough and needs no soldering.

Does a bigger average make the reading more accurate?

More repeatable, not more accurate. Averaging removes scatter that goes both ways. It does nothing about an error that is always the same, such as the ESP32's flat ends or a supply that is not quite 5 V.

Where this goes next

What the two stops really read, and how to take your own.

Why the ends are not exact

Edit this page — content/books/disc-potentiometer/smoothing-a-jittery-reading.mdx

Community

Questions about this product

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

Ask a question ↗

Disc 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