CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Need some fixed point math help,

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
iso9001



Joined: 02 Dec 2003
Posts: 262

View user's profile Send private message

Need some fixed point math help,
PostPosted: Fri Mar 03, 2006 7:25 pm     Reply with quote

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,
PostPosted: Sat Mar 04, 2006 12:26 am     Reply with quote

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 Laughing
Ttelmah
Guest







PostPosted: Sat Mar 04, 2006 5:10 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Mar 04, 2006 7:39 am     Reply with quote

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







PostPosted: Sat Mar 04, 2006 10:18 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Mar 04, 2006 1:58 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Mar 04, 2006 3:46 pm     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Sat Mar 04, 2006 3:46 pm     Reply with quote

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
PostPosted: Sun Mar 05, 2006 7:39 pm     Reply with quote

Wow, Nice to see that Mark has made a "comeback" to the forum.. Cheers..
Mark



Joined: 07 Sep 2003
Posts: 2838
Location: Atlanta, GA

View user's profile Send private message Send e-mail

PostPosted: Mon Mar 06, 2006 7:42 pm     Reply with quote

I've been quite busy (and still am) at work and started shifting towards ARM7's which accounts for my lack of participation Sad
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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