PDA

View Full Version : How do I rescale an input value-> lower output & avoiding floating point?



HankMcSpank
- 14th June 2011, 13:27
Ok, so I have an 8 bit AD input 0-255, that I wish to rescale to a PWM output of say 0-150 (don't ask!), now in the real world I'd just divide 150 by 255, (0.0392156862745098) & then apply that to all my incoming input values....but that'd obviously involve floating point.

What's the best way to approach such rescaling in Picbasic, cos I've thoroughly checked my head, and there's nothing listed in there?

pedja089
- 14th June 2011, 13:56
PWMVar var byte
ADRes var byte
PWMVar=(ADRes*150)/255

HankMcSpank
- 14th June 2011, 13:59
Excellent...I realise this was more a maths question (which you can all now tell I suck at) rather than a PICBAsic one....but that's exactly what I needed, & I shall use it gratuitously :-)

HenrikOlsson
- 14th June 2011, 20:48
Hi,
Don't forget the */ operator.

Basically */ is like multiplying by 1/256 parts. So x = y */ 256 is the same as x = y * 1 and x = y */ 128 is the same as x = y * 0.5.

So why is it "better" than manually multiplying and dividing?

Because the */ operator doesn't actually divide anything (division is slow in software). It multiplies the two values giving a 32bit intermediate result. It then takes the middle 16 bits of that intermediate value and returns those bits as the result. Lets say ADresult = 255

PWM = ADResult */ 150
It multiplies ADresult by 150 resulting in the intermediate value of 38250 which in binary form looks like:
00000000 00000000 10010101 01101010
It then "extracts" the middle 16 bits of this value and returns those as the result. What's 00000000 10010101 in decimal? Yep, it's 150... or 149 actually.

Lets say you want to do x = 12345 * 1.45. 1.45*256=371 so

x = 12345 */ 371
Behind the scenes you'd first get 12345*371=457814 which, expressed in binary, is:
00000000 01000101 11100010 10011011
Those 16 middle bits ( 010000101 11100010 ) in decimal form is 17890 which is pretty close to 12345*1.45.

It's not perfect but there's usually a way to make it "fit" pretty good - and it avoids using division which, again, is a pretty slow operation on these devices.

Then we have the ** operator which is the same thing but it performs an inherent division of 65536 instead (ie. it returns the top 16 bits of that 32 bit intermediate result).

/Henrik.

HankMcSpank
- 14th June 2011, 22:03
Wow.....Henrik, that was a stonking reply....it's now in my test program & works a treat (as did pedja089's formula, but I like the fact that */ is that little bit quicker).

Many thanks for taking the time to explain....great stuff