|
|
View previous topic :: View next topic |
Author |
Message |
iso9001
Joined: 02 Dec 2003 Posts: 262
|
Need some fixed point math help, |
Posted: Fri Mar 03, 2006 7:25 pm |
|
|
I need to read in a 16bit number from ADC and then modify it by a certain percentage. I searched but found no examples of anyone doing this, (I know, I know, keep reading)
I read that Floating point is slow and fixed point is better, but I just can't see how to do fixed point with the data I have since I need to send it over spi as the modified number when finished
ex:
Code: |
int16 x;
float percent = .204; //20.4%
...
x = read_adc();
x = (x * percent) + x;
spi_write(x);
|
Maybe I am missing somthing but if I did this in fixed point wouldn't I have to do this:
Code: |
int16 x;
int percent = 204;
...
x = read_adc();
x*= 10;
x = (x * percent) + x;
x/=10;
spi_write(x);
|
Which does not at all seem like a good idea. Is there any faster way add a percentage to a number ?
I don't think lookup table will work since I have over 8000 possible values coming in. Besides I think that would take more then the 32k I have for rom
But speed is VERY important.
Ideas ? |
|
|
Guest
|
Actually, |
Posted: Sat Mar 04, 2006 12:26 am |
|
|
I'de like to know how to do this also.
I am was working on somthing like this awhile back. I used floating point but I had 100ms between samples so I really could do whatever I wanted. Did feel a little guilty using floating point |
|
|
Ttelmah Guest
|
|
Posted: Sat Mar 04, 2006 5:10 am |
|
|
Normally, when working with integers like this, you keep the integer scaled. So (for instance), you might multiply the incoming number by 100, and then only divide it back at the end of whatever operations you want. For the simple scaling here, provided you are only multiplying, then staying with a float, is probably the best solution. A float multiplication, on a 40MHz PIC18, only takes typically 36uSec (remember these chips have a hardware 8*8 multiplier, which makes a big difference). There will be some overhead, converting back from float to integer, but the total from using int arithmetic is not likely to be much better. Where things improve a lot, is on things like division, where a float divide easily takes 4* the time of an int16 divide, and things like sin, where the time shoots up.
I'd suggest that the fastest solution, would be:
Code: |
int16 x;
...
x = (int16)(read_adc() * 1.204);
spi_write(x);
|
Note the use of '1+percent', rather than multiplying, and then performing an addition. A float addition, actually takes longer than a multiply on a PIC18, and you are already performing a multiply, so why not do the two operations in one!. Also using a constant, may save a couple of I/O cycles.
Best Wishes |
|
|
rberek
Joined: 10 Jan 2005 Posts: 207 Location: Ottawa, Canada
|
|
Posted: Sat Mar 04, 2006 7:39 am |
|
|
You can also do a multiplication by 1.204 as a shift and add operation. It will not be exact but you can get it within 21 parts per million if you are using a 16-bit x value.
x * 1.204 is approximately equal to
x + x/8 + x/16 + x/64 + x/2048 + x/4096 + x/8192
or
x + x>>3 + x>>4 + x>>6 + x>>11 + x>>12 + x>>13
Actually this gives you x*1.203979 which should be close enough for most people.
I don't know how this works as far as speed goes, but I offer it as an alternative. _________________ The difference between genius and stupidity is that genius has its limits... |
|
|
Ttelmah Guest
|
|
Posted: Sat Mar 04, 2006 10:18 am |
|
|
I suspect it'll be slower on the 18 chips, but might be better on the 16 chips (because of the lack of the hardware multiplier). You'd probably be better to shift a temporary store, otherwise there is a lot of 'repeat shifting' going on. Certainly in many cases, an approach like this is well worth considering.
Best Wishes |
|
|
iso9001
Joined: 02 Dec 2003 Posts: 262
|
|
Posted: Sat Mar 04, 2006 1:58 pm |
|
|
Freakin sweet! I like both.
I feel rather dumb for forgeting to * 1.204 and not *.204+x. Don't know what I was thinking.
I know the 18F has the hardware multiply, but going off of CCS's chart in the help file it looks like my mulitply will take ~360 instructions like Ttelmah said. I need to do this twice in a row for two different numbers so I almost thinking 360x2 is near the time limit I have.
I really like the shifting. That seems to me like it would be less then ~350, but I have no idea yet.
I'll need to look closer at how you figured out the shift pattern. I don't get it but I only glanced at it for a second.
Wanted to say thanks, I'll try a bunch of different ways out and time them all
Ttelmah: Shift a temporary store ?? |
|
|
rberek
Joined: 10 Jan 2005 Posts: 207 Location: Ottawa, Canada
|
|
Posted: Sat Mar 04, 2006 3:46 pm |
|
|
Its just binary math.
When you do an integer binary multiplication, like 56x11, you'd do
Code: |
0111000
x 1011
------------
0111000
+ 01110000
+ 0111000000
----------------
1001101000
|
Which is 56 + (56x2) + (56x8)
or
56 + 56<<1 + 56<<3
You do the same thing in decimal multiplication too, but you never think about it.
When you do fractions in binary, you only have available 1/2, 1/4, 1/8 etc to make up the decimal fraction. If you look at .204, it is made up of:
0.125 + 0.0625 + 0.15625 ....
you can come close to representing any decimal fraction as binary shifts, as long as the number you are shifting is large enough. Clearly you can't right-shift a 4-bit number very often before the shift results in a zero. _________________ The difference between genius and stupidity is that genius has its limits... |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sat Mar 04, 2006 3:46 pm |
|
|
If your percentage is fixed at 20.4% then multiplying by 209 and dividing by 1024 will give you 20.41%. The divide by 1024 will be fast since its a binary number. If you can live with 20.3% then you could just multiply by 52 and truncate the last byte. |
|
|
Holy Ghost Guest
|
Back again |
Posted: Sun Mar 05, 2006 7:39 pm |
|
|
Wow, Nice to see that Mark has made a "comeback" to the forum.. Cheers.. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Mon Mar 06, 2006 7:42 pm |
|
|
I've been quite busy (and still am) at work and started shifting towards ARM7's which accounts for my lack of participation |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|