Arduino sensor filtering: average vs median

Compare moving average, exponential and median filters on the same readings, with the arithmetic worked by hand, and learn which one suits a robot sensor.

Reference
RE-3801
Published
Read
4 min

About the author · Sources, testing and AI policy

Raw sensor readings are noisy, and a robot that reacts to every wobble steers badly. Three small filters fix most of it: a moving average, an exponential filter and a median. This guide shows what each one does to the same readings, with the arithmetic worked by hand, so you can pick the right one.

Status: the filters are standard textbook methods. The sketches are untested outlines and the numbers below are a hand-worked example, not data from a real sensor.

Two kinds of noise

Jitter is small random variation around the true value. Spikes are occasional wild readings, such as an ultrasonic sensor returning a very short distance for one sample. Averages smooth jitter well but are pulled by spikes. A median ignores spikes but smooths less. Knowing which problem you have decides the filter.

The example readings

Take a distance that is really 100 cm, with one bad reading of 40: 100, 100, 100, 40, 100. Here is what each filter reports at the fifth sample.

FilterHow it worksResult at the spikeNext sample
RawNo filtering40100
Moving average, window 5Mean of the last 5 values(100+100+100+40+100)/5 = 88Stays below 100 until the spike leaves the window
Exponential, alpha 0.2new = old + 0.2 × (reading − old)100 + 0.2 × (40 − 100) = 8888 + 0.2 × (100 − 88) = 90.4
Median of 3Middle of the last 3 sortedSorted 100, 40, 100 gives 100100

The spike drags the average and exponential filters down to 88 and they recover slowly, while the median of three is untouched. If a false 88 cm reading would make your robot swerve, the median is the better defence against spikes. If your signal is merely jittery, an average or exponential filter gives a smoother line.

Moving average

// Untested outline.
const int N = 5;
int buf[N];
int idx = 0;
long sum = 0;

int movingAverage(int x) {
  sum -= buf[idx];
  buf[idx] = x;
  sum += x;
  idx = (idx + 1) % N;
  return sum / N;
}

The buffer starts at zero, so the first few outputs read low. Fill the buffer with the first reading, or ignore the output until N samples have arrived. The cost is lag: a larger window is smoother but responds later, which matters for a fast line follower.

Exponential filter

// Untested outline.
float filtered = 0;
bool first = true;
const float ALPHA = 0.2;

float expFilter(float x) {
  if (first) { filtered = x; first = false; }
  else filtered += ALPHA * (x - filtered);
  return filtered;
}

It needs one variable and no buffer, which suits a small board. A small alpha is smoother and slower; a large alpha follows the reading more closely. The complementary filter guide uses the same idea to combine two sensors.

Median of three

// Untested outline.
int median3(int a, int b, int c) {
  if (a > b) { int t = a; a = b; b = t; }
  if (b > c) { int t = b; b = c; c = t; }
  if (a > b) { int t = a; a = b; b = t; }
  return b;
}

Take three readings and return the middle. For an ultrasonic sensor, see how the HC-SR04 reliable distance guide combines a median with a timeout.

Which one to use

ProblemChoose
Occasional wild readings (ultrasonic, IR)Median of 3 or 5
Steady jitter (analog sensors, battery voltage)Exponential filter or moving average
BothMedian first, then an exponential filter
Fast control loop where lag hurtsSmall window or a larger alpha; test on the bench

Common mistakes

  • Filtering so hard that the robot reacts late to a real obstacle.
  • Filtering a value that is used as a stop condition with the same filter as one used for display.
  • Using integer division and losing the fractional part in an exponential filter.
  • Calling delay() between samples; use millis() timing instead.

A test plan

  • Print raw and filtered values together on the Serial Plotter and watch the two lines.
  • Change the window or alpha and note the lag against the smoothness.
  • Wave your hand in front of the sensor to produce real spikes and see which filter ignores them.
  • Choose the weakest filter that gives steady behaviour, then test the robot on the floor.
  • Save your plots and your final settings. They are what make this guide your own.

Sources: standard digital filter definitions; the worked numbers above are arithmetic you can check by hand. Last reviewed November 2026. Written, checked and maintained by Jignesh Panchal.

Pass it onWhatsAppLinkedIn

Keep reading

Continue learning

Tutorials

Arduino serial command parsing for robots

Why Bluetooth robots lag, how the Arduino serial timeout works, and a non-blocking command parser with a simple format and a link-loss…

  • Published4 Nov 2026
  • Read4 min

Free: the final-year project pack

A shortlist with BOMs, a report outline that matches the usual chapter scheme, a costing sheet and 40 viva questions. Built for the February–April submission season.

The Build Note

One short email when something is worth your bench time.

A new build sheet, a part price that moved, or a mistake worth avoiding. No daily drip, no recycled news.

One short email when a build or a price is worth your time. Unsubscribe in one click.