Author Topic: Calculation in Arduino not working out  (Read 6971 times)

0 Members and 1 Guest are viewing this topic.

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Calculation in Arduino not working out
« on: May 13, 2016, 11:32:48 am »
Hi all,

I'm trying to attempt a caulcation with some rather nasty numbers, see my code below:

Code: [Select]
  float a = 1e6f; // in counts per millisecond squared
  float t = 16000.0f; // in milliseconds
  float d = 200000.0f; //in counts
 
  float tr = micros();
 
  float velocity = 0.25f * ( (a*t) - sqrt(a) * sqrt((a*t*t) - (8.0f*d)) );
 
  float td = micros() - tr;
 
  Serial.print(velocity, DEC);
  Serial.print("c/ms, time: ");
  Serial.println(td,DEC);

The equation is basically to calculate the velocity you need to go at with a given distance, time and acceleration to move from one point to another in a trapazodial motion.

I will likely be using much larger numbers in the 'd' (distance) value too.

The problem I am getting is that I just simply get 0.000000 as an output.

I should be getting:
http://puu.sh/oQhTR/100d522819.png
12.5 counts/ms

Could anyone please give me some urgent advice? (I need to have this done by the day is over for a demo for a customer and I'm pulling my hair out on what to do!)

Huge thanks in advance.
« Last Edit: May 13, 2016, 11:37:54 am by TCWilliamson »
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3461
  • Country: it
Re: Calculation in Arduino not working out
« Reply #1 on: May 13, 2016, 11:39:34 am »
"divide and conquer"
don't write a big ass equation if you don't know how it will be actually coded/optimized
do it step by step and see where the problem(s) is (are)
 

Online Andy Watson

  • Super Contributor
  • ***
  • Posts: 2086
Re: Calculation in Arduino not working out
« Reply #2 on: May 13, 2016, 11:45:27 am »
Does micros() return a float? If not you may have to cast it. Ditto sqrt().
 

Offline botcrusher

  • Regular Contributor
  • *
  • Posts: 192
  • Country: ca
Re: Calculation in Arduino not working out
« Reply #3 on: May 13, 2016, 11:52:56 am »
You may have to use a a lower precision to et away with it on arduino.
The following is from the arduino wiki:
Quote
Floats have only 6-7 decimal digits of precision. That means the total number of digits, not the number to the right of the decimal point.
Also:
Quote
Floating point numbers are not exact, and may yield strange results when compared. For example 6.0 / 3.0 may not equal 2.0. You should instead check that the absolute value of the difference between the numbers is less than some small number.

You might have to separate whole numbers from the decimals, do math on exactly what is needed, and then merge them at the final result.

The only way around this i van think of is boiling down the equations to the simplest numbers possible and then multiply up, or use string logic to reatach the decimal to a whole number. That is some pretty hefty math for that little arduino, as this is only a snippet I'm guessing at causes here.

That 0.000000 is awfully suspicious, I'm assuming that it is returning a null value out of an error. I'd double check you aren't feeding ints or strs to the float (serial input?) If nothing else, the float just might have overflowed.
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #4 on: May 13, 2016, 11:57:17 am »
Does micros() return a float? If not you may have to cast it. Ditto sqrt().

Doesn't seem to be an issue, pinned it down to this:

(sqrt(a) * sqrt((a*t*t) - (8.0f*d))) gives the right answer

however when I subtract it from  (a*t) I get 0 in return for some reason when it should be '75'

Code at this second:
Code: [Select]
void loop() {
  // put your main code here, to run repeatedly:
  float a = 1e6f;
  float t = 16000.0f;
  float d = 300000.0f;
 
  float tr = micros();

  double partOne = ((a*t) - (sqrt(a) * sqrt((a*t*t) - (8.0f*d))));


 
  //float velocity = 0.25f * ( (a*t) - sqrt(a) * sqrt((a*t*t) - (8.0f*d)) );
 
  float td = micros() - tr;

 
  Serial.print(partOne);
  Serial.print("c/ms, time: ");
  Serial.println(td,DEC);
  delay (10);
}

return image:
http://puu.sh/oQiNX/3cfc25438e.png
« Last Edit: May 13, 2016, 11:59:32 am by TCWilliamson »
 

Offline borjam

  • Supporter
  • ****
  • Posts: 908
  • Country: es
  • EA2EKH
Re: Calculation in Arduino not working out
« Reply #5 on: May 13, 2016, 12:02:52 pm »
Doesn't seem to be an issue, pinned it down to this:

(sqrt(a) * sqrt((a*t*t) - (8.0f*d))) gives the right answer

however when I subtract it from  (a*t) I get 0 in return for some reason when it should be '75'
Pay attention to the number of digits. The maximum number of significant digits you have available are? 7 it seems.

a*t are 11 digits.

Check the number of digits (ie, decimal logarithm) of the result equation. If the difference in number of digits is larger than 2, you don't have enough precision for that calculation. Are there double precision numbers in Arduino?

 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #6 on: May 13, 2016, 12:16:15 pm »
Doesn't seem to be an issue, pinned it down to this:

(sqrt(a) * sqrt((a*t*t) - (8.0f*d))) gives the right answer

however when I subtract it from  (a*t) I get 0 in return for some reason when it should be '75'
Pay attention to the number of digits. The maximum number of significant digits you have available are? 7 it seems.

a*t are 11 digits.

Check the number of digits (ie, decimal logarithm) of the result equation. If the difference in number of digits is larger than 2, you don't have enough precision for that calculation. Are there double precision numbers in Arduino?

hmm, I see what you mean. What would be the best way to resolve this?
 

Offline AndreasF

  • Frequent Contributor
  • **
  • Posts: 251
  • Country: gb
    • mind-dump.net
Re: Calculation in Arduino not working out
« Reply #7 on: May 13, 2016, 12:16:59 pm »

OOOPS, ignore this - got the parentheses put in the wrong place.   |O |O |O


Your formula is overly complicated and can be heavily simplified:

   sqrt(a)*sqrt(a*t*t)  = sqrt(a)*sqrt(a)*sqrt(t)*sqrt(t) = a*t     (assuming both a and t are always positive of course)

therefore, your whole formula

   velocity = 0.25*(a*t - a*t - 8*d)

simplifies to

   velocity = -2*d

Somehow I doubt that's what you're after.

« Last Edit: May 13, 2016, 12:19:25 pm by AndreasF »
my random ramblings mind-dump.net
 

Online Andy Watson

  • Super Contributor
  • ***
  • Posts: 2086
Re: Calculation in Arduino not working out
« Reply #8 on: May 13, 2016, 01:20:55 pm »
Doesn't seem to be an issue, pinned it down to this:
Would it hurt to go belt and braces and try

float tr = (float)  micros();

Similarly, I believe sqrt() expects doubles and returns a double, use sqrtf to return a float.
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #9 on: May 13, 2016, 01:22:48 pm »
float types have an effective precision of 5 - 6 digits so the part in the bracket will return 0 or even negative.

go with double or revise your algorithm: for example, take sqrt(a*t) out of that bracket and make your calculation around that number. it will greatly reduce the number of calculations.
« Last Edit: May 13, 2016, 01:24:59 pm by dannyf »
================================
https://dannyelectronics.wordpress.com/
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Calculation in Arduino not working out
« Reply #10 on: May 13, 2016, 02:03:42 pm »
Welcome to the real world of finite precision. :)
 

Offline dmills

  • Super Contributor
  • ***
  • Posts: 2093
  • Country: gb
Re: Calculation in Arduino not working out
« Reply #11 on: May 13, 2016, 02:38:06 pm »
I would be very tempted to write this in fixed point, maybe use 64 bit ints and work with something like 56.8 or so (Actually, my first instinct would be to rethink how I was doing whatever it was I was doing).

The inputs differ by six orders of magnitude (And the at^2 product is going to be in the 10^16 region), which makes for an interesting precision requirement as loss of precision in the big terms will possibly swamp the much smaller (8.0f * d) term.

Floating point is horrible for this sort of thing, especially in single precision.

Goldburg wrote the classic paper on this stuff "What Every Computer Scientist Should Know About Floating-Point Arithmetic", you can find a copy here : https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Regards, Dan.
 

Offline RandallMcRee

  • Frequent Contributor
  • **
  • Posts: 541
  • Country: us
Re: Calculation in Arduino not working out
« Reply #12 on: May 13, 2016, 03:14:52 pm »
Several problems here.
Great advice on keeping things simple. Make intermediate results and check them.
Find out how to use Double and Float (hopefully before its a crisis; and with programming there is always a crisis).
Whenever I see code that uses floating point and I don't see NAN--well there is always a problem. Pretty much any code that needs to work in a non-hobby environment needs to check validity of inputs and outputs using NAN (look it up).

Time is often an issue and sure enough you have: "float t1=micros(); float td=micros()-t1;" So, here, td can be either zero or negative (on some platforms, maybe not yours). So any division by td is now suspect (NAN!).

Just took another look at micros() definition; it's EVIL!. " This number will overflow (go back to zero), after approximately 70 minutes." So, yeah, that's a totally unreliable number--what if you catch it at a transition. OMG. Useless.

To other posters; advice to use Double instead of Float is usually correct but depends on the platform--on some arduinos they map to the same datatype, on others they are different. So another rule, is to know what the underlying datatype actually is, e.g. 4 or 8 byte float/double (if in doubt check!).

Good luck!
« Last Edit: May 13, 2016, 03:20:57 pm by RandallMcRee »
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Calculation in Arduino not working out
« Reply #13 on: May 13, 2016, 03:50:40 pm »
Quote
Serial.println(td,DEC);
I don't think that "(, DEC}" is a correct print modifier for a floating point number in arduino, if the number is a float.
Try just "Serial.println(td);"
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #14 on: May 13, 2016, 04:06:33 pm »
the closest I could get is 12.499999, without resorting to double types, no sqrt(), 200+ bytes smaller and 25% faster.
================================
https://dannyelectronics.wordpress.com/
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #15 on: May 13, 2016, 04:13:57 pm »
Quote
25% faster.

For those particular numbers, I could get it 50% faster (100% faster?): 6000 cycles under my approach vs. 13000 cycles using the standard approach.
================================
https://dannyelectronics.wordpress.com/
 

Offline macboy

  • Super Contributor
  • ***
  • Posts: 2257
  • Country: ca
Re: Calculation in Arduino not working out
« Reply #16 on: May 13, 2016, 04:16:12 pm »
Doesn't seem to be an issue, pinned it down to this:

(sqrt(a) * sqrt((a*t*t) - (8.0f*d))) gives the right answer

however when I subtract it from  (a*t) I get 0 in return for some reason when it should be '75'
Pay attention to the number of digits. The maximum number of significant digits you have available are? 7 it seems.

a*t are 11 digits.

Check the number of digits (ie, decimal logarithm) of the result equation. If the difference in number of digits is larger than 2, you don't have enough precision for that calculation. Are there double precision numbers in Arduino?
Actually a*t gives 1.6e10, which is only 2 significant (decimal) digits, not 11. But consider that the exponent is very high. With single precision float, you can't add or subtract a small number such as 75 to/from this (or, equally, obtain a very small result such as 75) because there is no resolution left down at single-digits. You could try double precision floats. Just change all "float" to "double" and your "f" suffix for literals, into a "L" for long double (do not forget to use a decimal point to ensure it will be a long double and not just a long int!).

Even better: modify your calculations so that you don't take a difference between to numbers with many orders of magnitude different size. That's never a good idea even with double.

the closest I could get is 12.499999, without resorting to double types, no sqrt(), 200+ bytes smaller and 25% faster.

Did you come to brag or to help?
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #17 on: May 13, 2016, 04:28:46 pm »
Quote
advice to use Double instead of Float is usually correct

the use of double can be problematic, particularly on a small mcu here, as it usually bloats up your code, and your compiler may or may not support it. On my compiler, the use of double types adds 3K byte to my code.

================================
https://dannyelectronics.wordpress.com/
 

Offline Kalvin

  • Super Contributor
  • ***
  • Posts: 2145
  • Country: fi
  • Embedded SW/HW.
Re: Calculation in Arduino not working out
« Reply #18 on: May 13, 2016, 04:55:18 pm »
There is at least one library for big numbers implemented for AVR. If you have cycles to burn, the big numbers maybe something to look at. There might be some other libraries available too.
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #19 on: May 13, 2016, 05:41:58 pm »
I have been forced down another road due to time constraints and have had to implement the job in an existing product rather then a customized one, needless to say I still learned a lot and I think this will be very useful to know in an upcoming project!
 

Offline helius

  • Super Contributor
  • ***
  • Posts: 3643
  • Country: us
Re: Calculation in Arduino not working out
« Reply #20 on: May 13, 2016, 05:56:03 pm »
Code: [Select]
$ bc
bc 1.06
Copyright 1991-1994, 1997, 1998, 2000 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
a=1000000
t=16000
d=200000
.25*(a*t - sqrt(a)*sqrt(a*t^2 - 8*d))
250.00
If you evaluate each part of the formula you can see why this is probably not correct. \$a \cdot t^2 \$ is 256 trillion. \$8 \cdot d \$ is 1.6 million. Differences like this are bad news from a numeric stability perspective because since the minuend is so many orders of magnitude larger than the subtrahend, it only perturbs it by a little tiny bit. The last root will be extremely close to 16 million: 16 million - .05. That precision requires 9 decimal digits to represent, which is about equal to 30 binary digits: the mantissa of a single float only represents 23 bits. You need double floats to represent this quantity accurately.
What happens next makes it worse: the result is multiplied by a thousand, which makes it 16 billion - 50, and then it is subtracted from 16 billion. So from an orders of magnitude analysis, we start out with trillions and then cancel them out to zero.
This kind of formula is known as numerically unstable. There are worse examples, which don't even work with double floats, but you should re-organize the calculation so you aren't subtracting vast quantities that only slightly differ.
« Last Edit: May 13, 2016, 05:57:49 pm by helius »
 

Offline dannyf

  • Super Contributor
  • ***
  • Posts: 8221
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #21 on: May 13, 2016, 07:30:29 pm »
The answer is actually quite simple from a numerical analysis perspective, and hints were dropped earlier in the thread as well, some in your own answer.

Basically, it is about ways to calculate 1 - sqrt(1 - x) efficiently.

The solutions range from high school math from calculus 101.

the high school math approach would be to multiply it by 1 + sqrt(1-x) so you have 1 - sqrt(1-x) = x / (1 + sqrt(1 - x)) = ~x / 2: as others have pointed out, since x is so small for those numbers suggested, the denominator degenerates to 2.

the calculus approach is to use taylor expansion on sqrt(1-x): 1 - sqrt(1-x) = 1 - (1 - 0.5x - 1/8 x^2 ....) = 0.5x + 1/8 x^2 ......

Both will get you to the same place.
================================
https://dannyelectronics.wordpress.com/
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Re: Calculation in Arduino not working out
« Reply #22 on: May 13, 2016, 08:20:23 pm »
The problem I am getting is that I just simply get 0.000000 as an output.

The reason you're getting 0 for the value of 'td' is that the quantity you're printing out should almost always be zero. Paraphrased, your code does this:

Code: [Select]
float timestamp0 = micros();
// evaluate an expression in little or no compute time
float timestamp1 = micros();

println("elapsed time = %f\n", timestamp1 - timestamp0);

Your code grabs two timestamps with little or no actual time between the calls. So the difference between those two readings will most likely be zero.
 

Offline CM800Topic starter

  • Frequent Contributor
  • **
  • Posts: 882
  • Country: 00
Re: Calculation in Arduino not working out
« Reply #23 on: May 13, 2016, 09:15:21 pm »
The problem I am getting is that I just simply get 0.000000 as an output.

The reason you're getting 0 for the value of 'td' is that the quantity you're printing out should almost always be zero. Paraphrased, your code does this:

Code: [Select]
float timestamp0 = micros();
// evaluate an expression in little or no compute time
float timestamp1 = micros();

println("elapsed time = %f\n", timestamp1 - timestamp0);

Your code grabs two timestamps with little or no actual time between the calls. So the difference between those two readings will most likely be zero.

No, that was fine, I was just measuring for performance reasons. The one that I cared about is the OTHER value, regarding the velocity output being zero.
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: Calculation in Arduino not working out
« Reply #24 on: May 14, 2016, 01:21:15 am »
OK.  Nothing to do with Serial.print() after all (I actually ran the code...)
From your reference calculation, which I should have looked at earlier:



1e6*(16e3)2 =256000000000000
 8 * 2e5 = 1600000
1e6*(16e3)2  - 8 * 2e5 = 255999998400000

that result differs from the pre-subtraction value at about the 9th digit, and AVR floating point only has six digits of precision.  As far as the AVR math is concerned, 1.6e6 is zero, compared to the 256e12 it is being subtracted from.

(This is the same thing most people have been saying, only with the actual numbers filled in.)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf