Created Wed, 24 Oct 2012 09:29:14 +0000 by alunosepf
Wed, 24 Oct 2012 09:29:14 +0000
Hello, i have this code with atmega2560, sends correct value off sin(x) an cos(x) over the serial port. if i chose cerebot mx3k the values are incorrect. can help?
double PwmMotor1; double PwmMotor2; double PwmMotor3; double PwmMotor4; double radianos;
double var1; double var2;
void Movimento( int Velocidade_Linear,int Velocidade_Rotacional,int direcao) {
// velocidade máxima 127
radianos=2*PI;
radianos=radianos*(double)direcao/360;
PwmMotor1=Velocidade_Linear*cos(radianos)+Velocidade_Rotacional;
PwmMotor3=PwmMotor1;
PwmMotor4=Velocidade_Linear*sin(radianos)+Velocidade_Rotacional;
PwmMotor2=PwmMotor4;
Serial.println(" Motor ");
Serial.print (PwmMotor1); Serial.print(" ");
Serial.print (PwmMotor2);Serial.print(" ");
Serial.print (PwmMotor3);Serial.print(" ");
Serial.print (PwmMotor4);Serial.print(" ");
}
Wed, 24 Oct 2012 22:33:55 +0000
Try changing the 'double' types to 'float' types. I had trouble before with the arctan and it was because I was using a double precision. If a double was good enough on your arduino, a float for chipkit should be just as good as they are both 32 bits.
Hope it helps.
Thu, 25 Oct 2012 20:36:27 +0000
Try changing the 'double' types to 'float' types. I had trouble before with the arctan and it was because I was using a double precision. If a double was good enough on your arduino, a float for chipkit should be just as good as they are both 32 bits. Hope it helps.
What is the problem with the double precision? I bought the max32 because I have a project that involves lots of maths and greater precision is needed than can be obtained through the Arduino Mega 2560. I quote from stackoverflow:
http://stackoverflow.com/questions/2386772/difference-between-float-and-double
[There ia a...] Huge difference. As the name implies, a double has 2x the precision of float[1]. In general a double has 15 to 16 decimal digits of precision, while float only has 7.
My project uses some very large numbers (>10^^6) where precision is required right down to the 12+ decimal place. Almost all the calculations are trigonometric so it's just not possible not to use sin, cos, atan2, etc...
Thanks, Ric
Thu, 25 Oct 2012 22:53:51 +0000
You could use a Taylor series and make your own function that uses doubles (I would use a higher one then only use the part close to zero and mirror it for the other values)
Remember cos(x)=sin(x-pi/2) tan(x)=sin(x)/cos(x)
Sat, 27 Oct 2012 08:29:47 +0000
Now that ChipKit is all newlib and open source based, we don't have the excuse of conflicts between the open source and proprietary libraries, and we should figure out for sure IF the double-precision math functions are broken. And if they are, we should fix them; there are for-sure working dp math functions distributed with gcc, right? (perhaps not very well optimized, but they should be working...)
Sat, 27 Oct 2012 12:11:51 +0000
... and we should figure out for sure IF the double-precision math functions are broken. And if they are, we should fix them...
It is clear that since this time last year the double precision has been implemented. long double also appears to be 8 bytes but I cannot see that offers any advantage over the current double.
Like some other posters, I am calculating astronomical ephemeris where lack of precision in the early calculations propagates to significant errors further down the line (there may be 10 or more stages of computation for some ephemeris). Maintaining precision early on really does make a difference.
I am moving from the Arduino 2560 where I had to create functions that combined both integer and floating point calculations so that I could handle the limited precision of the avr libs (double and float are both 4 bytes which means you cannot have large numbers whilst at the same time retain precision to the nth decimal place).
I have only just started to use the Max32 these past 3 or 4 days and already I can see that some double float calculations are not as accurate as those optimised for the Arduino. This is something I had not expected. I will spend some time these next few days going through each calculation for a range of values to see where the discrepancies occur.
If I come up with anything definitive I will report back. Either way I need to see why the initial results seem so poor. I haven't yet ruled out stupidity on my part.
However I am completely in agreement with WestfW. I haven't seen any concrete evidence yet that the libraries are broken, so for me the Jury is still out. We do however need answers based on reproducible conditions.
Regards, Ric
PS: Initial results for Julian Day & Time since the J2000.0 equinox show that the dp calculation in MAX32 is accurate within the limits of the expected precision. My optimised functions combining integer and floating point are working perfectly also with the difference being that the fractional component is now accurate to 15dp rather tha the 6 or 7dp in AVR. I am perfectly happy with these results but note that none of the calculations involved use the trig functions. That's the next step.
PPS: thanks mikes for the links to the Taylor series. I hadn't thought of rolling my own but hopefully the existing library functions will turn out good. Let's see.
Sun, 28 Oct 2012 12:08:47 +0000
BTW the Microchip's double precision floating point calcs (incl. trigs) were the most precise when compared to other compilers .. p.
Sun, 28 Oct 2012 12:26:31 +0000
For a quick test how fast and how precise your math libs and especially trig libs are you may run this simple test called "9 degree test" as the correct result shall be 9.000000000000000 (all vars are double except timer which is unsigned int):
printf (" THIS IS THE START \r\n");
p64 = 3.1415926535897932384626433832795;
timer = millis;
for (i=1;i<=1000;i++) {
// 9 degree
q64 = 9.000;
// Convert to radians
q64 = q64 * p64 / 180.0;
// Make the test
q64 = asin(acos(atan(tan(cos(sin(q64))))));
// Convert to degree
q64 = q64 * 180.0 / p64;
}
timer = millis - timer;
printf(" THIS IS THE END \r\n");
printf(" Elapsed time 1000x : %u millis\r\n", timer);
printf(" Result= %1.15e \r\n",q64);
The precision comparision for various calculators: http://www.rskey.org/~mwsebastian/miscprj/results.htm
Sun, 28 Oct 2012 14:33:02 +0000
Which, when converted to Arduino/chipKIT style, looks like this:
void setup()
{
float p64, q64;
int i, timer;
Serial.begin(9600);
delay(4000);
Serial.println ("THIS IS THE START");
p64 = 3.1415926535897932384626433832795;
timer = micros();
for (i=0; i <= 1000; i++) {
// 9 degree
q64 = 9.000;
// Convert to radians
q64 = q64 * p64 / 180.0;
// Make the test
q64 = asin(acos(atan(tan(cos(sin(q64))))));
// Convert to degree
q64 = q64 * 180.0 / p64;
}
timer = micros() - timer;
Serial.println("THIS IS THE END");
Serial.print("Elapsed time 1000x : ");
Serial.print(timer);
Serial.println(" microseconds");
Serial.print("Result= ");
Serial.print(q64,15);
Serial.println("");
}
void loop(void)
{
}
Now, when I run the above on my FubarinoSD board (or any chipKIT board for that matter), I get the following result:
THIS IS THE START THIS IS THE END Elapsed time 1000x : 1 microseconds Result= 9.000000000000000
But I'm not sure I believe that. How can we do that much math in such little time? I added a Serial.print(q64,15); inside the loop, and it does actually print out all those iterations (takes forever). Maybe the compiler sees all of those nested functions and is smart enough to replace the whole mess with 9.0? I don't know. But it gets the right answer, and it's really fast. Cool.
*Brian
Sun, 28 Oct 2012 17:09:42 +0000
In reality the calculation does not take 1usec :). If that loop got optimised out then you possess a good compiler, indeed. Try to disable the optimisation. I would expect something like 500-1000ms for 1000x. And the precision - something like 8.9999999993432, maybe..
Sun, 28 Oct 2012 17:35:45 +0000
FYI- this is a result from ARM STM32F100 @48MHz, IAR compiler: THIS IS THE START THIS IS THE END Elapsed time 1000x : 273 millis Result= 8.999999999999968e+00
Sun, 28 Oct 2012 17:45:46 +0000
OK, so with no optimizations, I get the following output: THIS IS THE START THIS IS THE END Elapsed time 1000x : 332117 microseconds Result= 9.000000000000000
(332ms) which seems like a very reasonable number. Normally the MPIDE compiler is at -O2 optimization level, and in the version of gcc that we are using, this must allow it to seriously optimize the math functions in this test code.
*Brian
Sun, 28 Oct 2012 17:53:51 +0000
The time seems to be ok, the precision is fantastic - are you sure your printf(..) does not provide a kind of rounding? Is that the equivalent of %1.15e ?
Sun, 28 Oct 2012 18:19:21 +0000
Pito,
I believe it is. For example, if I modify the code like this :
void setup()
{
float p64, q64;
int i, timer;
char t[100];
Serial.begin(9600);
delay(4000);
Serial.println ("THIS IS THE START");
p64 = 3.1415926535897932384626433832795;
timer = micros();
for (i=0; i <= 1000; i++) {
// 9 degree
q64 = 9.000;
// Convert to radians
q64 = q64 * p64 / 180.0;
// Make the test
q64 = asin(acos(atan(tan(cos(sin(q64))))));
// Convert to degree
q64 = q64 * 180.0 / p64;
}
timer = micros() - timer;
Serial.println("THIS IS THE END");
Serial.print("Elapsed time 1000x : ");
Serial.print(timer);
Serial.println(" microseconds");
Serial.print("Result= ");
Serial.print(q64,15);
Serial.println("");
sprintf(t, "%1.15e", q64);
Serial.println(t);
}
void loop(void)
{
}
I get the following output:
THIS IS THE START THIS IS THE END Elapsed time 1000x : 1 microseconds Result= 9.000000000000000 9.000000000000000e+00
Is that pretty good proof that the value and accuracy we see is real? (I've never really pushed the limits of floats before, so I don't know exactly what to look for here.)
*Brian
Sun, 28 Oct 2012 18:27:01 +0000
1usec - it seems to be optimised out. You must get the elepsed time as you got before - 332ms.. Precision - 9.000000000000000 to get is rare with 64bit fp. That is typical for 80bit or 128bit (34 dec places). Typical 64bit fp results I've seen with AVR, PIC24/33, ARM is from 8.999999999XXXXXX to 8.9999999999999XX, the best results with MCHP C30 (PIC24/33) and IAR (AVR, ARM).
Sun, 28 Oct 2012 20:40:31 +0000
Yup, the 1us is 'optimized out'. If I make the floats volatile (even with -O2), then the time jumps up to 343ms.
Gcc probably sees that the result is never used, and so the whole loop just goes away.
*Brian
Sun, 28 Oct 2012 21:35:40 +0000
I've split the calc (latest MPIDE beta, fubarinoSD795): // Make the test q64 = (tan(cos(sin(q64)))); q64 = (asin(acos(atan(q64)))); With volatile float I get: Elapsed time 1000x : 332988 microseconds Result= 9.000000953674316 With volatile double: Elapsed time 1000x : 323840 microseconds Result= 9.000000000000010 I'm a little bit confused with the timings as the double fp takes usually ~2x single fp. It seems there are still some issues with the math, or better we have to read the manual :). Maybe you have got something like sin(), sinf(), sinl(), etc.
Sun, 28 Oct 2012 22:13:21 +0000
I wonder why the results are different than when you have everything all on a single line. Shouldn't the answer come out the same?
*Brian
Mon, 29 Oct 2012 03:34:45 +0000
The math routines probably use doubles so when you use a float type your just up converting to a double in the math calls (hence similar times).
Jacob
Mon, 29 Oct 2012 04:28:25 +0000
Hmm. Using the last "release" version (I think. I can't actually read the version number in the "about" dialog...), I get:
Elapsed time 10000x : 390 milliseconds
Result= 9.000030517578125
But it's not doing double-precision trig:
q64 = asin(acos(atan(tan(cos(sin(q64))))));
9d0013f4: 8fa40018 lw a0,24(sp)
9d0013f8: 8fa5001c lw a1,28(sp)
9d0013fc: 0f400efb jal 9d003bec <__truncdfsf2>
9d001400: 00000000 nop
9d001404: 0f40137b jal 9d004dec <fpsin>
9d001408: 00402021 move a0,v0
9d00140c: 0f401336 jal 9d004cd8 <cosf>
9d001410: 00402021 move a0,v0
9d001414: 0f4012cc jal 9d004b30 <fptan>
9d001418: 00402021 move a0,v0
9d00141c: 0f4009b4 jal 9d0026d0 <atanf>
9d001420: 00402021 move a0,v0
9d001424: 0f400b63 jal 9d002d8c <acosf>
9d001428: 00402021 move a0,v0
9d00142c: 0f400b81 jal 9d002e04 <asinf>
9d001430: 00402021 move a0,v0
9d001434: 0f400ed2 jal 9d003b48 <__extendsfdf2>
9d001438: 00402021 move a0,v0
9d00143c: afa20018 sw v0,24(sp)
9d001440: afa3001c sw v1,28(sp)
Mon, 29 Oct 2012 05:03:20 +0000
The latest test image (20121013) does indeed seem to support "long double" as a 64 bit quantity, and comes up with exactly 9....
// Make the test
q64 = asin(acos(atan(tan(cos(sin(q64))))));
9d0013f4: 8fa40020 lw a0,32(sp)
9d0013f8: 8fa50024 lw a1,36(sp)
9d0013fc: 0f400ab3 jal 9d002acc <sin>
9d001400: 00000000 nop
9d001404: 00402021 move a0,v0
9d001408: 0f400a76 jal 9d0029d8 <cos>
9d00140c: 00602821 move a1,v1
9d001410: 00402021 move a0,v0
9d001414: 0f400aee jal 9d002bb8 <tan>
9d001418: 00602821 move a1,v1
9d00141c: 00402021 move a0,v0
9d001420: 0f40090e jal 9d002438 <atan>
9d001424: 00602821 move a1,v1
9d001428: 00402021 move a0,v0
9d00142c: 0f400b12 jal 9d002c48 <acos>
9d001430: 00602821 move a1,v1
9d001434: 00402021 move a0,v0
9d001438: 0f400b60 jal 9d002d80 <asin>
9d00143c: 00602821 move a1,v1
9d001440: afa20020 sw v0,32(sp)
9d001444: afa30024 sw v1,36(sp)
"Print" Still doesn't support long double, though... The image has gotten pretty huge: 20121013: Binary sketch size: 58336 bytes (of a 126976 byte maximum) 20120903: Binary sketch size: 34288 bytes (of a 126976 byte maximum) AVR1.0.1: Binary sketch size: 6,854 bytes (of a 32,256 byte maximum) (keep in mind that AVR has it's own special math library for microcontrollers, optimized for low memory footprint. (pretty neat stuff, actually.))
Mon, 29 Oct 2012 05:12:19 +0000
(I should note that the new mpide is using the 64bit trig functions even for "float" variables (just like a "real" computer))
Mon, 29 Oct 2012 07:51:54 +0000
FYI - some ~2-3 years old results I've found:
float 9.000009536743164e+00 float fast_math_lib 9.000010490417480e+00 double 8.999999999999971e+00
float 32bit 8.999962806701660156E+00 float 48bit 9.000006227055564522E+00 double 64bit 9.000001620467530827E+00
PS: the code with C30 is ~4x smaller (pic24HJ, 16.3kB, double) than with the latest MPIDE.
Mon, 29 Oct 2012 11:53:07 +0000
pito, when comparing code sizes, are you JUST looking at the math libraries and the test code? Or (for the MPIDE builds) are you also including all of the other core library code that always gets included in a sketch? (Like serial, interrupt handling, etc.)
I just want to make sure you're comparing apples to apples. The MPIDE sketches are pretty large, primarily because we don't compile in MIPS16 mode and we include a lot of libraries by default. The good news is that, as you add your own sketch, the overall image size doesn't grow as fast as you think it might, meaning that you can put a whole lot of your own code in a 256K part.
*Brian
Mon, 29 Oct 2012 20:19:40 +0000
Brian, that is a complete code for above test (pic24hj, serial setup, printf, math_libs, interrupts, oscillators, everything..). The fast_math lib worked with dspic33. From C30 and p24HJ128GP502 (9degree test, double, res=8.999999999999971e+00 ):
Program Memory [Origin = 0x200, Length = 0x15600]
section address length (PC units) length (bytes) (dec)
------- ------- ----------------- --------------------
.text 0x200 0x26d0 0x3a38 (14904)
.const 0x28d0 0xdc 0x14a (330)
.text 0x29ac 0x188 0x24c (588)
.dinit 0x2b34 0x146 0x1e9 (489)
.isr 0x2c7a 0x2 0x3 (3)
Total program memory used (bytes): 0x3fba (16314) 12%]
FYI - the complete single precision math lib (inclusive trig functions) for atmega32 is ~4-5kBytes. For double and 32bit mips32 I would expect max 16kBytes. You may try to compile with mips16. The code might be 20-30% smaller. p.