Three Methods to Filter Noisy Arduino Measurements

 In Articles

Measurements from the real world often contain noise. Loosely speaking, noise is just the part of the signal you didn’t want. Maybe it comes from electrical noise: the random variations you see when calling analogRead on a sensor that should be stable. Noise also arises from real effects on the sensor. Vibration from the engine adds noise if you’re measuring the acceleration of a go-kart, for example. Filtering is a method to remove some of the unwanted signal to leave a smoother result.

In this post we look at three simple filtering techniques to help you get rid of noise.

Something to Filter

To generate some ‘noisy’ data for filtering a thermistor was connected to analog-input 0 on an Arduino Uno. A thermistor is a resistor whose resistance changes with temperature. As temperature increases, resistance goes down; as temperature decreases, resistance goes up. The thermistor was connected in a voltage divider configuration with one leg connected to ground and the other to the analog-input. A 100kΩ resistance was connected between the 3.3V output of the Arduino and the analog-input to provide current for the thermistor.

To measure temperature, the analog value was read. Then the raw analog value was converted to temperature, in degrees Celsius, using the following Arduino code:

After applying the various filters, the data was sent to MegunoLink for plotting.

Filtering Algorithms

The three filtering algorithms we are going to look at are:

  1. Averaging
  2. Running average
  3. Exponential filter

The screenshot from MegunoLink below shows these algorithms together. A small rise in temperature was created by touching the thermistor to see how the different filters would respond. The grey line is the raw temperature measurement. It is pretty good with not much noise. But there is still room for improvement.

Filtering a noisy signal

The raw temperature signal (grey) smoothed by averaging 16 measurements (green), a running average of 16 measurements (blue) and an exponential recursive filter (red) is plotted. The temperature increase was caused by touching the thermistor.

Plot from Arduino sketches with MegunoLink

Averaging

One of the easiest ways to filter noisy data is by averaging.

Averaging works by adding together a number of measurements, the dividing the total by the number of measurements you added together. The more measurements you include in the average the more noise gets removed. There is a diminishing return though: the average of 101 measurements isn’t going to be much less noisy than the average of 100 measurements.

Here’s the code to calculate an average temperature measurement:

Notice the delay between each measurement. That delay is to give the analog-input time to stabilize between each measurement. Without it, your average will tend to be lower than the true measurement.

The picture below shows just the raw data and the average filter. Averaging, even only 16 measurements, does a pretty good job of smoothing the small random noise in the raw measurements. Even better, it tracks the change in temperature (when I touched the sensor) very closely.

Average filter

A 16 measurement average (green) along with a single raw temperature measurement (grey) is plotted. Note how the average is smoother.

The average filter might be the best one for this application, when the original measurement is not very noisy.

Running Average

One downside of the average filter is the amount of time needed to make a measurement. The measurement time can be important in low-power applications. The Arduino uses much more power when it is awake and running your program than it does when it asleep in standby.

An alternative to making all the measurements at once then averaging them is to make one measurement at a time and add it to a running average. The calculation of the average is the same: sum up all the measurements and divide by how many you made.

But we have to store the measurement history. Here’s a snippet of code to do the running average:

This gives a much slower response to changes because of the 100 ms delay between making each measurement. In other words, it only takes 16 ms for the average filter to get 16 new measurements but it takes 1.6 seconds (16 x 100 ms) for the running average to get 16 new measurements. So it responds to changes more slowly. And you can see that in the picture below. The grey line is the same raw temperature measurement as before. The running average is shown in blue.

Running average filter

A 16 point running average from a temperature sensor is plotted (blue). The raw temperature is shown in grey.

If the delay at the end of the loop was reduced from 100 ms to 1 ms, the response of the running average would be the same as the simple average. However, the longer delay between measurements is time when the Arduino could be asleep, saving battery power. Or busy doing something else.

The running average seems like a good alternative to a simple average to give a smoother output and let the Arduino work on other things. But it has one big down side: memory use.

Because you have to keep track of the history to calculate a running average, filtering many measurements quickly becomes impractical. The Arduino Uno only has 2k of RAM to store this history and you will quickly run out. If you needed to keep the history for some other reason, it could be a good choice. But I wouldn’t use a running average filter on an Arduino very often because of the amount of memory it uses.

Exponential Filter

The last filter is a recursive filter. A recursive filter is just one that calculates a new, smoothed value (yn) by using the last smoothed value (yn – 1) and a new measurement (xn):

yn = w × xn + (1 – w) × yn – 1

The amount of smoothing is controlled by a weighting parameter (w). The weight is a value between 0% and 100%. When the weight is high (say 90%), the filter doesn’t smooth the measurements very much but responds quickly to changes. If the weight is low (say 10%), the filter smooths the measurements a lot but doesn’t respond very quickly to changes.

This is my favorite filter because:

  • it doesn’t need much memory (just enough to store the last measurement)
  • you can control how much filtering is applied with a single parameter (the weight)
  • it works well in battery powered applications because you don’t need to make many measurements at once

Its so useful, we added the exponential filter to our Arduino library. And that makes it easy to use as well! Here’s what you need:

With a weight of 20, we get a fairly strong filter but it is still more responsive than the running average:

Exponential filter smoothing

Raw temperature measurements from a thermistor (grey) and a temperature measurement smoothed by an exponential filter (red) are shown.

Conclusion

So there we have it. 3 methods to filter noisy measurements you make with an Arduino:

  • Averaging: easy to implement and understand.
  • Running average: can use a lot of memory; usually not a good choice for an Arduino sketch.
  • Exponential filter: easy to change the amount of filtering using a weight; doesn’t need much memory; easy to implement with our Arduino filter library.

Post a comment below and let us know what kind of smoothing you use in your Arduino sketches. Or if you want to make plots to see what your data looks like, download MegunoLink to get started.

Recent Posts
Showing 8 comments
  • I Crawford
    Reply
    • Paul Martinsen
      Reply

      I had not seen these before. Will take a look. Thanks.

  • unclethehornet
    Reply

    Rather than apply the exponential filter to smooth the raw signal, have you tried applying the filter to smooth the rate of change of the raw signal (ie, the first derivative – it’s velocity). Would this not give you all the benefits without the lag?

    • Paul Martinsen
      Reply

      I didn’t try filtering the derivative here. But generally filtering is applied before taking a first derivative because the derivative itself tends to accentuate noise. Could be worth exploring though.

  • Randall
    Reply

    Binomial filtering seems to be appropriate for 2-d data, but not (1-d) sensor data. For filtering that does not lag the response try variants of the SG (Savitzky-Golay) filter:
    https://ai.berkeley.edu/~ee123/sp15/docs/SGFilter.pdf

    Would be nice to incorporate this into your filtering library. I can do that if you guys like? I have a lot of data to filter.

    New meguno link user.

    • Philip Rowe
      Reply

      Hi Randall, feel free to build it into the library file. I think you can some how submit it back using github if you have an account. If not maybe you can post your updated library file to our forum and I can integrate it back into github myself.

      Thanks
      Phil

pingbacks / trackbacks
  • […] One of the first frustrating situations a beginning microcontroller programmer will come across is the issue of debouncing switches. Microcontrollers are faster than switches, and the switch has yet to be built that can change state in zero time like they can on paper. This hurdle is easily overcome, but soon we are all faced with another issue: filtering noise from an analog signal. Luckily [Paul Martinsen] has put together a primer of three different ways to use an Arduino to filter signals. […]

  • […] Interested? You can find the tutorial and explore the code on MegunoLing’s blog post here. […]

Leave a Comment

Contact Us

Send us an email and we will get back to you shortly.

Not readable? Change text.

Start typing and press Enter to search