Pages: 1 [2] 3   Go Down
Author Topic: smoothing pot input  (Read 2340 times)
0 Members and 1 Guest are viewing this topic.
Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 206
Posts: 12894
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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).
Logged

Smithfield, Rhode Island
Offline Offline
God Member
*****
Karma: 3
Posts: 843
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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.
Logged

Smithfield, Rhode Island
Offline Offline
God Member
*****
Karma: 3
Posts: 843
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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


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.

Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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.

Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.


Code:
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);
}






« Last Edit: April 29, 2012, 07:04:53 pm by db2db » Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 206
Posts: 12894
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

α = 0.25 gives a window that almost decays away at 20 samples and can be implemented without floating-point.  I think this will work...

Code:
unsigned long history;
unsigned short value;

void setup( void )
{
  Serial.begin( 250000 );
  history = analogRead( 0 ) * 4;
}

void loop( void )
{
  history = analogRead( 0 ) + (((3 * history) + 2) / 4);
  value = (history + 2) / 4;

  Serial.println( value );

  delay( 100 );
}


Edit: added rounding.
« Last Edit: April 30, 2012, 03:13:24 pm by Coding Badly » Logged

Smithfield, Rhode Island
Offline Offline
God Member
*****
Karma: 3
Posts: 843
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks!!!  I'll play with that...
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 206
Posts: 12894
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I think dot-8 rather than dot-2 fixed-point may give slightly more accurate results.  Try this one instead...

Code:
unsigned long history;
unsigned short value;

void setup( void )
{
  Serial.begin( 250000 );
  history = analogRead( 0 ) * 256;
}

void loop( void )
{
  history = (64*analogRead(0)) + (((64*3*history)+128) / 256);
  value = (history + 128) / 256;

  Serial.println( value );

  delay( 100 );
}


Edit: added rounding.
« Last Edit: April 30, 2012, 03:12:54 pm by Coding Badly » Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


This looks very interesting, but I don't seem to follow the formula.

Can you explain what it's doing?
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 206
Posts: 12894
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


The basic formula is...
v1 = (α * analogRead) + ((1 - α) * v0)

α = 0.25 or 1/4 ...
v1 = ((1/4) * analogRead) + ((1 - (1/4)) * v0)
v1 = ((1/4) * analogRead) + ((3/4) * v0)

To make it fixed-point with eight bits for the fraction multiple both sides by 256 (2 to the power of 8)...
256*v1 = 256 * { ((1/4) * analogRead) + ((3/4) * v0) }
256*v1 = ((256/4) * analogRead) + ((3*256/4) * v0)
256*v1 = ((64) * analogRead) + ((3*64) * v0)

The right-side has "v0" not "256*v0" so we have to perform the division when calculating the next value.  The multiplication is performed first to preserve the precision...
256*v1 = (64 * analogRead) + ((3*64*v0) / 256)

Finally, to improve the accuracy we need to include rounding...
256*v1 = (64 * analogRead) + (((3*64*v0)+(256/2)) / 256)

So, history is the "actual" value multiplied by 256.  Another way to look it: history / 256 is the whole number part and history % 256 is the fractional part.
« Last Edit: April 30, 2012, 03:15:49 pm by Coding Badly » Logged

West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Nice!
Logged

There's always a better way!

Offline Offline
Full Member
***
Karma: 0
Posts: 217
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Going back to the original, is the big disavantage that you have to use a float?

Is that much slower? How much?
Logged

Manchester (England England)
Offline Offline
Brattain Member
*****
Karma: 625
Posts: 34099
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Float is a lot slower, but I haven't got figures to say exactly how much. At least four times slower.
Logged

Smithfield, Rhode Island
Offline Offline
God Member
*****
Karma: 3
Posts: 843
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Going back to the original, is the big disavantage that you have to use a float?

Is that much slower? How much?

Floats are bigger as well. In my case, unsigned short int is more than enough space for 2 bytes.
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 206
Posts: 12894
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Good point about storage.  history in Reply #20 can be unsigned short (half the size of float).  Assuming the "raw" values are between 0 and 1023, up to six fractional bits are possible with an unsigned short (instead of multiplying both sides by 256, multiply both sides by 64).  Which is a very nice compromise: about 1.5 decimals, smoothing, and fast all from just two bytes!  Warning: updating history overflows an unsigned short so the equation will have to be cast to an unsigned long before the right-side multiply.

history in Reply #22 has to remain an unsigned long (same size as float).  


Note: I updated #20 and #22 to make them a bit more accurate.
« Last Edit: April 30, 2012, 03:16:14 pm by Coding Badly » Logged

Pages: 1 [2] 3   Go Up
Jump to: