|
|
View previous topic :: View next topic |
Author |
Message |
el_tigre
Joined: 23 Dec 2007 Posts: 12 Location: Bs As : Argentina
|
Multiplication with float variables |
Posted: Mon Oct 04, 2010 12:30 pm |
|
|
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
|
|
Posted: Mon Oct 04, 2010 1:22 pm |
|
|
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
|
|
Posted: Mon Oct 04, 2010 1:41 pm |
|
|
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
|
|
Posted: Mon Oct 04, 2010 4:51 pm |
|
|
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
|
|
Posted: Mon Oct 04, 2010 5:03 pm |
|
|
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
|
|
Posted: Mon Oct 04, 2010 11:21 pm |
|
|
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: 19569
|
|
Posted: Tue Oct 05, 2010 2:26 am |
|
|
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
|
|
Posted: Tue Oct 05, 2010 3:34 am |
|
|
The said quantities are signed by nature. So %w respectively %lw don't work without additional prerequisites. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19569
|
|
Posted: Tue Oct 05, 2010 7:23 am |
|
|
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
|
|
Posted: Tue Oct 05, 2010 1:04 pm |
|
|
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
|
|
Posted: Tue Oct 05, 2010 1:56 pm |
|
|
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. |
|
|
|
|
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
|