Arduino Forum

Using Arduino => Introductory Tutorials => Topic started by: RIN67630 on Feb 12, 2020, 08:43 pm

Title: Smooth a value in one instruction.
Post by: RIN67630 on Feb 12, 2020, 08:43 pm
Here is the way to smooth a value in one line:
Code: [Select]
A0smooth = A0smooth + (A0 - A0smooth) / 2;
smoothes A0 to A0smooth.
You should run that with A0 and A0smooth being floats.
If you want a stronger smoothing replace /2 by /3 or more.
The higher the value the stronger the smoothing.

This code does a smoothing in the same way than a RC filter in electronics.
Title: Re: Smooth a value in one instruction.
Post by: DrAzzy on Feb 21, 2020, 01:44 am
That's one line of code, not one instruction (by my count, it's like 10-12 instructions - load, sub, rightshift, add, store - times 2 because on an 8-bit avr, and 16-bit operands...)

As an aside, dividing by 3 is much worse, while dividing by 4 (or other powers of 2) is not - division on AVRs is implemented in software and slow.
Title: Re: Smooth a value in one instruction.
Post by: PaulMurrayCbr on Jul 10, 2020, 04:40 am
AKA a recursive lowpass filter. In general
Code: [Select]

weight = .95;
value = value * weight + newValue * (1-weight);


See http://www.dspguide.com/ for a free webbook on this topic.
Title: Re: Smooth a value in one instruction.
Post by: TheMemberFormerlyKnownAsAWOL on Jul 12, 2020, 06:59 pm
Quote
Here is the way to smooth a value in one line:
Code: [Select]

A0smooth = A0smooth + (A0 - A0smooth) / 2;


smoothes A0 to A0smooth.
... but remember that on a UNO, A0 always has the value 14, so doesn't really need smoothing. :D
Title: Re: Smooth a value in one instruction.
Post by: RIN67630 on Jul 24, 2020, 10:58 pm
Code: [Select]

weight = .95;
value = value * weight + newValue * (1-weight);

That will not do: You must add the weighted increment*, not the newValue
Title: Re: Smooth a value in one instruction.
Post by: PaulMurrayCbr on Jul 26, 2020, 06:18 am
That will not do: You must add the weighted increment*, not the newValue
The weighted increment is (newValue-value)*(1-weight), and - looking at it - I agree that doing it that way is better, as it involves one fewer floating-point multiplications. BUt mathematically it comes out the same.

Of course, subtracting the weight from 1 is just a result of what you decide that "weight" means.
Title: Re: Smooth a value in one instruction.
Post by: johnerrington on Sep 16, 2020, 09:40 am
I'm hesitant to contribute in such distinguished company; however I'd suggest it would be better to use integer arithmentic.

Suppose you get a 12 bit integer value "newValue" from the ADC;

using a weight of .75 ..

to smooth it you take int smoothValue = (smoothValue*3 + newValue) /4

as smoothValue = (smoothValue + smoothValue<1 + newValue) >>2
Title: Re: Smooth a value in one instruction.
Post by: TheMemberFormerlyKnownAsAWOL on Sep 16, 2020, 09:50 am
I'm hesitant to contribute in such distinguished company; however I'd suggest it would be better to use integer arithmentic.

Suppose you get a 12 bit integer value "newValue" from the ADC;

using a weight of .75 ..

to smooth it you take int smoothValue = (smoothValue*3 + newValue) /4

as smoothValue = (smoothValue + smoothValue<1 + newValue) >>2
better still, "smoothValue<<1"

Or just leave it as "(smoothValue*3 + newValue) /4", and let the compiler figure it out.
Title: Re: Smooth a value in one instruction.
Post by: johnerrington on Sep 16, 2020, 10:18 am
smoothValue<<1  loses precision.

Quote
Or just leave it as "(smoothValue*3 + newValue) /4", and let the compiler figure it out.
my suggestion is based on several factors:

firstly that CHOOSING to use integer arithmetic forces the use of a sensible weighting - i.e. not something like 0.93;

and secondly that  it helps to see where precision could be lost.

also I get very fustrated when reading that someone has read the value of a voltage with the adc as 3.4326171875 volts,  just because the reading was 703 on a 5V=1024 scale.

Maintaining precision in a digital filter is important.
Title: Re: Smooth a value in one instruction.
Post by: TheMemberFormerlyKnownAsAWOL on Sep 16, 2020, 10:20 am
as smoothValue = (smoothValue + smoothValue<1 + newValue) >>2
Loses even more precision ;)
Title: Re: Smooth a value in one instruction.
Post by: johnerrington on Sep 16, 2020, 06:54 pm
Yes;  the precision is of course lost in the final divide (or shift)

the integer values need to be manipulated at hgher precision for the results to be sensible.  

My old brain was struggling so I used excel.

This filter is Vn+1 = (3*Vn + 256*Sn) >>2

the "voltage" is calculated at the END by (integer) dividing by 256.

You can see that by using higher order bits in the integer value precision is maintained in the filter calculation.

A single bit is lost in the conversion to "voltage" - as it would be in converting from a float.


I've attached the spreadsheet as a zip file.  Change the yellow value to change the "seed" sample value.  Its filtering a step function.

The graph shows the filter response: Its important to realise that at any instant the filtered value is unlikely to match the current value of your reading.


(https://forum.arduino.cc/index.php?action=dlattach;topic=664407.0;attach=382085)

(https://forum.arduino.cc/index.php?action=dlattach;topic=664407.0;attach=382087)
Title: Re: Smooth a value in one instruction.
Post by: TheMemberFormerlyKnownAsAWOL on Sep 16, 2020, 07:01 pm
It wasn't a shift I was highlighting, it was a Boolean expression
Title: Re: Smooth a value in one instruction.
Post by: johnerrington on Sep 16, 2020, 07:06 pm
My bad - a typo - unacceptable in a program!  However it triggered an interesting excursion.  Thanks.
I've updated the spreadsheet and graph above.