DEMO: Succesive Aproximation Normalization (SAN) Filter
Beau Schwabe
Posts: 6,566
This is just a cool little code snip-it I wanted to pass along. Although written for the Propeller, it could easily be adapted to a Basic Stamp.
Purpose:
Take a data value where you know the upper and lower limits and
"normalize" the data so that it proportionally scales to a binary
weighted value.
For instance, say you have a potentiometer that reads 204 on one extreme
and 8453 on the other extreme. ...And the current value is 2834.
You want to scale that to a 12-Bit number? Simply load the Data,
BitResolution, RefLOW, RefHIGH variables and call the function. The
returned value will contain the result. 1306 in this case.
Yes, you could apply the formula ...
Data = [(Data-RefLOW)/(RefHIGH-RefLOW)]*(2^BitResolution)
... but the SAN filter avoids any floating point, and gets the job done
using only shift and adds.
enjoy!
OBEX:
http://obex.parallax.com/snippet/699
Purpose:
Take a data value where you know the upper and lower limits and
"normalize" the data so that it proportionally scales to a binary
weighted value.
For instance, say you have a potentiometer that reads 204 on one extreme
and 8453 on the other extreme. ...And the current value is 2834.
You want to scale that to a 12-Bit number? Simply load the Data,
BitResolution, RefLOW, RefHIGH variables and call the function. The
returned value will contain the result. 1306 in this case.
Yes, you could apply the formula ...
Data = [(Data-RefLOW)/(RefHIGH-RefLOW)]*(2^BitResolution)
... but the SAN filter avoids any floating point, and gets the job done
using only shift and adds.
enjoy!
OBEX:
http://obex.parallax.com/snippet/699
Comments
thanks,
Jonathan
Thanks... I added and Assembly option to the OBEX file ... version 1.1
-Phil
You realize the algorithm is just a classic game of "Pick a number between 1 and 10 in the fewest number of guesses"? ; the only feedback you get is if your guessed number is higher or lower than the actual number. What most people don't realize is that this classic game produces a binary equivalent of the actual number that you are trying to guess if you were to keep track of the HIGH and LOW results when guessing.
Here is a writeup I did back in March for our local Hacker space:
Thanks Beau, nice and neat. I normally do this with scaled integers but here is your method tested in my Tachyon Forth.
Just copy and paste all of this to load and run.
This is the result:
BTW, this is the normal named variables method in place of the temporary "registers"
and wondered about the real timings of the different versions of to solve this problem
so I made some experiments, first in Tachyon then in SPIN.
For the Tachyon code see this post in the Tachyon thread.
What is still missing is a straight forward SPIN implementation using the FLOAT library
which I expect to be really slow.
Maybe someone can provide the numbers.
this is the problem we want to solve:
1) Data = [(Data-RefLOW)/(RefHIGH-RefLOW)]*(2^BitResolution)
if we rearrange it a little we get rid of the requirement for float immediately
2) Data = (Data-RefLOW) * (2^BitResolution) / (RefHIGH-RefLOW)
and then replace the * 2^n with shift left
3) Data = ((Data-RefLOW) SHL BitResolution) / (RefHIGH-RefLOW)
I get the following timings: @80MHz
Beau's filter in PASM 26 us
Beau's filter in SPIN 579 us ( Peter writes around 1300us in his EXTEND.fth, I don't know how he measured it)
EQ3 in SPIN 34 us
from Tachyon
Beau's filter in TForth 205 us
EQ2 in a lazy impl. in TF 208 us
EQ2 fast impl. in TF 28 us
EQ3 fast TF impl. 24 us
SPIN FLOAT-LIB ?? the horrible example of NOT to do it ;-)
PASM impl. of EQ3 ?? would be a great reference