20

I am working on a mobile robot controlled via a wireless 2.4 GHz link.The receiver is connected to the Arduino Uno which serves onboard as the main controller. The most critical (and main) input channel coming from the receiver produces a very noisy signal, which leads to lots of minor changes in the output of the actuators, even though these are not needed.

enter image description here
                    Plot of the input of the Arduino in a 30 second interval.

I am looking for libraries that can perform efficient smoothing. Are there any signal smoothing libraries available for the Arduino (Uno)?

2
  • Don't know if you can find this kind of libraries but I'm afraid these might need to much CPU power for an Arduino. I'd rather go with an electronic solution (low-pass filter) if possible.
    – jfpoilpret
    Feb 16, 2014 at 15:30
  • I am with jfpoilpret on this. I think you need an electronic solution. I would try a stabilization capacitor, (simple low pass filter). I assume you are using an adc channel, so you should put a cap from this channel to ground. Start with values around 100pf, and work up from there.
    – John b
    Mar 26, 2014 at 18:42

5 Answers 5

13

Microsmooth is a lighweight signal smoothing library currently being developed by me.

It is still being worked on and the aim is to make it lightweight in terms of memory and fast. The library provides multiple filters for smoothing:

  • Simple Moving Average
  • Exponential Moving Average
  • Cumulative Moving Average
  • Savitzky Golay Filter
  • Ramer Douglas Pecker Algorithm
  • Kalmogorov Zurbenko Filter

To use the library, download and add it to the source directory. Also, add the following line to your source file:

#include "microsmooth.h"
2
  • Hi, I'm having trouble using your library. You wouldn't use "Import Library..." to import your library right? I tried just copying the source into my .ino folder, but I'm getting errors about missing automicrosmooth.h, Serial not being defined, and missing ';'. Is this library still working? Thanks
    – waspinator
    Feb 20, 2015 at 23:38
  • @waspinator Sorry about that. Fixed the errors. Thanks for the feedback!
    – asheeshr
    Feb 21, 2015 at 2:51
7

I think I see a lot of single-sample noise spikes in your noisy signal.

The median filter does better at getting rid of single-sample noise spikes than any linear filter. (It is better than any low pass filter, moving average, weighted moving average, etc. in terms of its response time and its ability to ignore such single-sample noise spike outliers).

There are, in fact, many signal-smoothing libraries for the Arduino, many of which include a median filter.

signal-smoothing libraries at arduino.cc:

signal-smoothing libraries at github:

Would something like this work in your robot? (The median-of-3 requires very little CPU power, and hence fast):

/*
median_filter.ino
2014-03-25: started by David Cary
*/

int median_of_3( int a, int b, int c ){
    int the_max = max( max( a, b ), c );
    int the_min = min( min( a, b ), c );
    // unnecessarily clever code
    int the_median = the_max ^ the_min ^ a ^ b ^ c;
    return( the_median );
}

int newest = 0;
int recent = 0;
int oldest = 0;

void setup()
{
    Serial.begin(9600);
    // read first value, initialize with it.
    oldest = random(200);
    recent = oldest;
    newest = recent;
    Serial.println("median filter example: ");
}

void loop()
{
    // drop oldest value and shift in latest value
    oldest = recent;
    recent = newest;
    newest = random(200);

    Serial.print("new value: ");
    Serial.print(newest, DEC);

    int median = median_of_3( oldest, recent, newest );

    Serial.print("smoothed value: ");
    Serial.print(median, DEC);
    Serial.println("");

    delay(5000);
}
4

Have you tried a low pass filter? I found an example here an another one here.

Both of these libraries have a list of data being read from the analog sensor of your choice which is averaged. Every new sensor value is added to the list, and the last one is thrown out, like this:

List: 3 4 3 3 4 3 5 3 2 3 4 3 
new reading added. old one thrown out
      /--                     /--
List: 5 3 4 3 3 4 3 5 3 2 3 4
list averaged
2
  • Pretty much what a simple FIR filter does with all tap values set to 1. Fiddling with the taps values can improve the signal further, but requires higher math.
    – jippie
    Feb 16, 2014 at 15:39
  • Note: The second link computes the cumulative moving average which is not a practical choice for actuator control, especially one which may involve frequent start and stops. The smoothed signal will always trail the peak value of the actual signal by quite a margin.
    – asheeshr
    Feb 16, 2014 at 15:40
2

You could filter this digitally using a low pass filter:

int valueFilt = (1-0.99)*value + 0.99*valueFilt;

Change the 0.99 to change the cut off frequency (closer to 1.0 is lower frequency). The actual expression for that value is exp(-2*pi*f/fs) where f is the cutoff frequency you want and fs is the frequency the data is sampled at.

Another type of "digital filter" is an event filter. It works well on data that has outliers; e.g. 9,9,8,10,9,25,9 . An event filter returns the most frequent value. Statistically this is the mode.

Statistical averages such as Mean, Mode etc.. can be calculated using the Arduino Average Library.

An example taken from the Arduino Library page referred to :

#include <Average.h>
#define CNT 600
int d[CNT];

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

void loop()
{
  int i;

  for(i=0; i<CNT; i++)
  {
    d[i] = random(500);
  }  

  Serial.print("Mean: ");
  Serial.print(mean(d,CNT),DEC);
  Serial.print(" Mode: ");
  Serial.print(mode(d,CNT),DEC);
  Serial.print(" Max: ");
  Serial.print(maximum(d,CNT),DEC);
  Serial.print(" Min: ");
  Serial.print(minimum(d,CNT),DEC);
  Serial.print(" Standard deviation: ");
  Serial.print(stddev(d,CNT),4);
  Serial.println("");
  Serial.println("");

  delay(5000);
}
1
  • 1
    Note that this will be very slow, since it's doing lots of implicit casts to float and back. Feb 17, 2014 at 4:18
0

Check out the Arduino Smooth library. It uses absolutely no arrays, no looping over past values, it's fast with constant compute time, and the objects take up 8 bytes regardless of the sample window size.

1
  • 2
    It would be worth mentioning that this library, like some of the others already cited, implements an exponentially-weighted moving average. The fact that it works in constant-time and constant-size is nothing special: this is how this type of filter is always implemented. There are good use cases for an exponentially-weighted moving average, but the spiky noise of the original question is not one of them: this would be better served by a moving median. Jun 18 at 16:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.