smoothing pot input

Googling arund I found this smoothing algorithm. Seems simple, but I follow how it would work.

 // declared globally
float smoothADC;

// inside loop() or other repeating function
smoothADC = 0.9 * smoothADC + 0.1 * analogRead(0);

Make sense to anyone?

No, that makes no sense as written. Are you sure nothing is omitted? That code uses an uninitialized variable, which can never ever work.

What you could do instead is save the last n values and average them. Depending upon the nature of the data that is an easy way to do it that can work well.

Googling arund I found this smoothing algorithm.

It's an "exponentially weighted moving average" or EMWA (missing the proper initialization as skyjumper mentioned).

skyjumper: No, that makes no sense as written. Are you sure nothing is omitted? That code uses an uninitialized variable, which can never ever work.

I think he asked if the algorithm is correct, not if the code was properly written. And it is only the initialization of the variable that is missing (which most likely is cleared and set in more than one place in the code).

That formula you have is a sort of averaging filter. Weighed average I think may be a better name for it.

Basically you have this:

smooth = ((smooth * 9) + analogRead(0))/10;

So every new sample has an effect of 10% in your signal. A little Excel sheet can do wonders to show the result of this and different weights applied to this formula.

Can a filter like this be used to smooth the last n samples, so that old data is at some point essentially discarded? Currently I am storing the last 20 samples and averaging them, but I have been looking for a way to achieve this without consuming 80 bytes (20 floats)...

Can a filter like this be used to smooth the last n samples, so that old data is at some point essentially discarded?

I think you are missing the point after many iterations the old data is so diluted that it has no effect, this is not homeopathic computing.

The alternative is to use an array and apply a different weighting to each sample. In this way any required filter response can be created providing you have enough terms. However, the increase in processing time reduces the top frequency of the filter. This sort of programming is known as digital signal processing.

skyjumper: Can a filter like this be used to smooth the last n samples, so that old data is at some point essentially discarded?

A follow-up to @Grumpy_Mike's answer: Assuming your samples are integers (e.g. from the analog-to-digital converter), using db2db's ? = 0.9, the contribution for the seventh previous value becomes so small that it is not present in a float. In other words, for practical purposes it's zero. ? = 0.9 gives a history of six samples (the contribution of the six is 1 / 1E-06; not much).

Currently I am storing the last 20 samples and averaging them, but I have been looking for a way to achieve this without consuming 80 bytes (20 floats)...

What are you trying to achieve? Is the goal to filter out noise when reading a stable signal (in which case the "windowed average" you're doing now is probably the right choice)? Do you need the average to "respond quickly" to signal changes?

This seems to work, but is very slow to respond. How can I speed up the response?

float smooth ;


void loop() 
{
SSerial.print(analogRead(5));  //show raw output of pot value
SSerial.print(" ");                  // add a space for readibility

smooth = 0.9 * smooth + 0.1 * analogRead(5);  
SSerial_println(smooth);  //show filtered output of pot value

delay (100);
}

Take the delay() out?

db2db: This seems to work, but is very slow to respond. How can I speed up the response?

First, let's review snippets from some of the replies...

That code uses an uninitialized variable

missing the proper initialization

And it is only the initialization of the variable that is missing

I can't help but notice that the code you posted does not initialize smooth. Do you think that might be the problem?

smooth is initialised to zero by the compiler, so it is going to take a while to ramp up.

AWOL: smooth is initialised to zero by the compiler, so it is going to take a while to ramp up.

No, its not. Only static variables are initialized by the compiler. Non-statics will have a random value.

My question is, what is a reasonable value to initialize with?

No, its not. Only static variables are initialized by the compiler. Non-statics will have a random value.

It's a global; it is initialised to zero. Happily, the float representation of zero is the same as int or long.

My question is, what is a reasonable value to initialize with?

A reading from your pot. Do it in setup().

skyjumper: My question is, what is a reasonable value to initialize with?

  1. Average of N samples where N is about the same history you get from the EWMA (for ? = 0.9, N = 4 is adequate).

  2. Start at zero and toss out values until the EWMA has a complete history (for ? = 0.9 the first six values are be discarded).

  3. Or, as @Grumpy_Mike said, one sample.

It depends on what you are trying to accomplish (and whether or not you're a statistician).

AWOL:

No, its not. Only static variables are initialized by the compiler. Non-statics will have a random value.

It's a global; it is initialised to zero. Happily, the float representation of zero is the same as int or long.

You're right, I just checked the spec. My bad.

[quote author=Coding Badly link=topic=103586.msg777439#msg777439 date=1335722944]

Currently I am storing the last 20 samples and averaging them, but I have been looking for a way to achieve this without consuming 80 bytes (20 floats)...

What are you trying to achieve? Is the goal to filter out noise when reading a stable signal (in which case the "windowed average" you're doing now is probably the right choice)? Do you need the average to "respond quickly" to signal changes?

[/quote]

I am getting speed readings several times each second from a transducer. Each of these readings tends to vary a bit from the prior one, and I just want to get a stable reading to use to present to the driver.

This works nicely. Thanks.

Seems like it can be used for minor potentiometer output jitter. If I initialize smooth to the same value of the pot, it starts the calculation there, which is good.

I now see the relationship between the two side of that formula. One side is fast to react, the other is slow but better at smoothing. Like the petrol needle in your car, very good at smoothing, but too slow to be used for updating a value based on a pot turning.

In case anyone wants to try this easily, here's my test code. If you change the pot value - which has +5/-5 value jitter added - you'll quickly see the data output of 'smooth' stabilize.

float smooth; 
int randomized_potval;

void setup() 
{
  smooth = analogRead(5);  // grab sensor value to be initial value in calculation.
  Serial.begin(115200);
}


void loop() 
{
  float potval = analogRead(5);   // read pot on pin 5
  randomized_potval = random( potval - 5, potval + 5);  // add some jitter

  smooth = (0.99 * smooth) + (0.01 * randomized_potval);  // smooth it out

  serial.print(randomized_potval);              // show jittered version of analog 5 value
  serial.print(" ");
  serial.println(int(smooth));            // OUTPUT -  we are looking for this smoothed number to be stable.

  delay (2);
}