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

Multiplication with float variables

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



Joined: 23 Dec 2007
Posts: 12
Location: Bs As : Argentina

View user's profile Send private message Visit poster's website

Multiplication with float variables
PostPosted: Mon Oct 04, 2010 12:30 pm     Reply with quote

Hello everyone.
I'm working on a project with an external IMU unit.
Delivery IMU unit values of different parameters in int16.
These values must be multiplied by constants to obtain the final value.

The code I use for each parameter (each parameter has three values x, y and z) is as follows.

Code:

   #ifdef angular_rate
   restart_wdt();
   y=make16(f[13],f[14]);
   p=make16(f[15],f[16]);
   r=make16(f[17],f[18]);

   yaw_r=(float)y*0.0137329;
   pitch_r=(float)p*0.0137329;
   roll_r=(float)r*0.0137329;
   sprintf(borrador,"Yr:%g Pr:%g Rr:%g ",yaw_r,pitch_r,roll_r);
   strcat(valor,borrador);
   #endif


I'm using CCS 4.093.

If I use a 18F2520 running at 40MHz, each block takes about 6.5 mS.
If instead, I use DSPIC30F3013 running at 117.92 Mhz takes about 11mS.

I can not understand why this happens, although I'm not using the specific functions of the DSP, is three times faster so it should be three times less time to perform the calculations and not twice!
Thank you very much for the help.
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Mon Oct 04, 2010 1:22 pm     Reply with quote

The unexpected slow processing isn't with the float multiply but with sprintf(). It's also the bottleneck in PIC18 performance, the arithmetic operations consumes only about 65 µs with PIC 18 (1% of total processing time) and 16.5 us with dsPIC.
el_tigre



Joined: 23 Dec 2007
Posts: 12
Location: Bs As : Argentina

View user's profile Send private message Visit poster's website

PostPosted: Mon Oct 04, 2010 1:41 pm     Reply with quote

good point! I had not thought of that.
I need to send data in ASCII format, what options do I have?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Mon Oct 04, 2010 4:51 pm     Reply with quote

I don't see a clear explanation for the slow sprintf() operation. If you need to do it fast, you should try to find out which operation is exactly that slow?
The binary to decimal conversion, the float operation with %f or %g format, the %g rounding? Depending on the results, you can e.g. try to utilize fixed point integer instead.

I have no results of other compilers at hand, is it a particular CCS C issue?
el_tigre



Joined: 23 Dec 2007
Posts: 12
Location: Bs As : Argentina

View user's profile Send private message Visit poster's website

PostPosted: Mon Oct 04, 2010 5:03 pm     Reply with quote

Hi, thanks for the answer.
I use only CCS compiler.
I do not know why this happens. I understand that's weird.
On the other hand, often do not use float variables in other projects, so I'm not familiar with the options of variable type float.

Recently I was trying to replace %g with %f, at least in the 18F makes no difference.

As I can do to try fixed point?
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Mon Oct 04, 2010 11:21 pm     Reply with quote

I found, that the extraordinary slow operation is only with print of float values. PCD is apparently using float64 in the print routines internally, for this reason it's considerably slower than PCH.

CCS C offers a built-in fixed point print option for unsigned data with the %w format. For signed, you would have to build it on your own: Convert the data to int16 or int32 with a scale factor and insert a decimal point into the string.
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Tue Oct 05, 2010 2:26 am     Reply with quote

Double 'check' if you need float.
You presumably only use a particular degree of output precision, since your incoming values can only have 65536 possible levels. So what about using the scaled integer ability?. Something like:
Code:

//Change definitions of yaw_r etc., to int32
#ifdef angular_rate
   restart_wdt();
   y=make16(f[13],f[14]);
   p=make16(f[15],f[16]);
   r=make16(f[17],f[18]);

   yaw_r=(int32)y*13733;
   pitch_r=(int32)p*13733;
   roll_r=(int32)r*13733;
   sprintf(borrador,"Yr:%.6lw Pr:%.6lw Rr:%.6lw ",yaw_r,pitch_r,roll_r);
   strcat(valor,borrador);
#endif

This will be enormously faster.
Obviously, provided the incoming numbers do not exceed 31275, you could use 137329 as the multiplier .
You won't get the rounding associated with %g, but you will gain speed...

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Oct 05, 2010 3:34 am     Reply with quote

The said quantities are signed by nature. So %w respectively %lw don't work without additional prerequisites.
Ttelmah



Joined: 11 Mar 2010
Posts: 19545

View user's profile Send private message

PostPosted: Tue Oct 05, 2010 7:23 am     Reply with quote

He said the numbers were int16 to start with.
You can deal with signed if necessary by just inverting is negative, and holding the sign bits separately. If so, it almost ensures that the six digit scale factor can be used.

Best Wishes
FvM



Joined: 27 Aug 2008
Posts: 2337
Location: Germany

View user's profile Send private message

PostPosted: Tue Oct 05, 2010 1:04 pm     Reply with quote

Yes, it can be done with %w and converting the data to a sign-magnitude representation. But is it an acceptable C programming solution?

By the way, I tried the original code with Microchip C30 (after removing special CCS functions as make16() ) and got 550 µs execution time versus said 11 ms with PCD.
el_tigre



Joined: 23 Dec 2007
Posts: 12
Location: Bs As : Argentina

View user's profile Send private message Visit poster's website

PostPosted: Tue Oct 05, 2010 1:56 pm     Reply with quote

Hello everyone.
I was doing tests with both uc.
These are my results:

18F2520
Compiled 4.093
Both functions going well, but no differences in the time of execution.
It takes about 6.5 mS (measurement with an oscilloscope).
The code I ended up using that works is:

Code:

signed int16 y1,p1,r1;
unsigned int32 yaw1,pitch1,roll1;

   y1=make16(f[7],f[8]);
   p1=make16(f[9],f[10]);
   r1=make16(f[11],f[12]);
   
   if(y1<0){y1=y1*(-1);}                                  // si es negativo le cambio el signo
   if(p1<0){p1=p1*(-1);}                                  // si es negativo le cambio el signo
   if(r1<0){r1=r1*(-1);}                                  // si es negativo le cambio el signo
   
   yaw1=(unsigned int32)y1*109863;               // calculo el angulo
   pitch1=(unsigned int32)p1*109863;              //
   roll1=(unsigned int32)r1*109863;                //

   sprintf(borrador,"z:%3.7w x:%3.7w y:%3.7w",yaw1,pitch1,roll1);
   strcat(valor,borrador);


In this case I did not realize the correction of negative sign
The first string corresponds to the output using %f
The second string is using %3.7w

z:-68.70 x:1.12 y:-0.56
z:68.7083202 x:1.1206026 y:0.56030



Dspic30F3013:

The CCS 4.093 version does not support% w to 30F3013.
The tests are performed using CCS 4.106

The code that implements it:

Code:

   signed int16 y1,p1,r1;
   unsigned int32 yaw1,pitch1,roll1;
   int1 ym=0;                                                    //
   int1 pm=0;
   int1 rm=0;
   y1=make16(fil[7],fil[8]);
   p1=make16(fil[9],fil[10]);
   r1=make16(fil[11],fil[12]);
   
   if(y1<0){y1=y1*(-1);ym=1;}                                  // si es negativo le cambio el signo
   if(p1<0){p1=p1*(-1);pm=1;}                                  // si es negativo le cambio el signo
   if(r1<0){r1=r1*(-1);rm=1;}                                  // si es negativo le cambio el signo
   
   yaw1=(unsigned int32)y1*1099;                             // calculo el angulo
   pitch1=(unsigned int32)p1*1099;                            //
   roll1=(unsigned int32)r1*1099;   

   if(ym==1){sprintf(borrador,"SPI z:-%3.5lw ",yaw1);} 
   else{sprintf(borrador,"SPI z:%3.5lw ",yaw1);}
   strcat(valor, borrador);
   
   if(pm==1){sprintf(borrador,"x:-%3.5lw ",pitch1);}
   else{sprintf(borrador,"x:%3.5lw ",pitch1);}
   strcat(valor, borrador);
   
   if(rm==1){sprintf(borrador,"y:-%3.5lw ",roll1);}
   else{sprintf(borrador,"y:%3.5lw ",roll1);}
   strcat(valor, borrador);



The first string corresponds to the output using %f
The second string is using %3.5w

z:-79.77 x:0.21 y:-3.55
z:-79.79839 x:0.21980 y:-3.56076


Finally, using %w function sprintf () takes about 1mS while using %f takes 10.9 ms, so... 10 times less.

I do not know if it's an elegant solution, but it works well and is able to reduce the time significantly.
Thank you for your help.
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