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)?

asheeshr
  • 3,847
  • 3
  • 26
  • 61

5 Answers5

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"
asheeshr
  • 3,847
  • 3
  • 26
  • 61
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);
}
David Cary
  • 1,122
  • 8
  • 23
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
TheDoctor
  • 3,509
  • 1
  • 22
  • 39
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);
}
akellyirl
  • 2,156
  • 1
  • 15
  • 19
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.

Ripred
  • 1