Smoothing Wobbles with Exponential Weights
When you’re centering clay on a wheel, your hands read a stream of tiny vibrations—grit in the clay, an off-center lump, the motor’s hum. If you corrected for every tremor, you’d overcorrect into chaos. Instead, you feel for the trend: where the clay wants to go, not where it is this instant.
Exponential smoothing does exactly this for data streams. Each new measurement updates your estimate, but the old estimate still has weight. The algorithm is disarmingly simple: smooth = α × new + (1 - α) × smooth. The parameter α (between 0 and 1) controls responsiveness. High α chases the signal closely. Low α ignores noise but lags behind real changes.
Here’s Ruby filtering simulated radius measurements from a pottery wheel sensor, where the clay’s actual radius is 8 cm but the sensor jitters:
readings = [8.3, 7.8, 8.5, 7.9, 8.2]
smooth = readings[0]
alpha = 0.3
readings.each do |r|
smooth = alpha * r + (1 - alpha) * smooth
puts "raw: #{format('%.2f', r)} smooth: #{format('%.2f', smooth)}"
end
And the same logic in C, processing a fixed array:
#include <stdio.h>
int main(void) {
float readings[] = {8.3f, 7.8f, 8.5f, 7.9f, 8.2f};
int n = sizeof(readings) / sizeof(readings[0]);
float smooth = readings[0];
float alpha = 0.3f;
for (int i = 0; i < n; i++) {
smooth = alpha * readings[i] + (1 - alpha) * smooth;
printf("raw: %.2f smooth: %.2f\n", readings[i], smooth);
}
}
With noisy input like [8.3, 7.8, 8.5, 7.9, 8.2], the smoothed output converges toward 8.0 without the jitter. The exponential part comes from the math: older measurements decay exponentially in influence—yesterday’s reading matters less than this morning’s, which matters less than right now.
Potters learn this intuitively. Control systems engineers rediscovered it in the 1950s for tracking aircraft. It’s the same reflex: ignore the noise, follow the shape.