Go Down

Topic: Dealing with very small numbers? (Read 938 times) previous topic - next topic

jimford

I'm measuring current and want to calculate and continuously display Amp Hours.

The problem is that I'm measuring milliseconds and need to convert to hours, and float can't deal with the maths.

I'm accumulating the AH as follows:

total_amp_hours = total_amp_hours + current*(float(period/2160000000));

Where 'current' is typically < 1A and 'period' is around 2000 milliseconds. 2160000000 is the number of milliseconds in an hour. The problem arises because 2000/2160000000 equates to zero with float.

I guess I could use a much longer time period, but would lose precision with current changes during the 'slot'.

I'd welcome any ideas to help me with the problem, please!

Jim

robtillaart

Several solutions are possible:

There was a NIck Gammon who implemented the big number class which can also do very small numbers
- http://arduino.cc/forum/index.php/topic,85692.0.html -

Performance is traded for precision !

You could do the math right as it contains an error
Quote
total_amp_hours = total_amp_hours + current*(float(period/2160000000));


==> total_amp_hours = total_amp_hours + current * (1.0 * period)/2.16e9);

Final option:
Add the amps per second in an intermediate variable and when a second has passed add its value to the amp_hour

loop()
{
 total_amp_second +=  current * (1.0* period/2.16e9));
 if (second has passed)
 {
   total_amp_hour += total_amp_second;
   total_amp_second = 0.0;
   Serial.println(total_amp_hour);
 }
}

Quote
2160000000 is the number of milliseconds in an hour.

In my days there were 3.600.000 milliseconds in an hour, but times seem to go fast in the internet era ;)

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

el_supremo

If total_amp_hours is an integer, the roundoff lost by adding a small floating point number to an integer is going to be quite substantial.
E.G. if the new amount is 1.95 Ah then you will only add 1 to total_amp_hours.
You would be better off declaring total_amp_hours as a float and when it is being displayed, round it off to an integer.
Code: [Select]

float total_amp_hours;

total_amp_hours += current*period/3600000.0;
integer_amp_hours = total_amp_hours + 0.5;
// then display integer_amp_hours


Pete

PeterH


The problem arises because 2000/2160000000 equates to zero with float.


I suspect the problem is that you aren't actually using float values for all your intermediate values.

2000/21600000000 equals integer 0, if you assign it to a float you get 0.0.

But 2000.0/2160000000.0 equals a small non-zero float number.

(Not the number you wanted if you thought there were 21600000000 milliseconds in an hour, but not zero.)
I only provide help via the forum - please do not contact me for private consultancy.

Morris Dovey

I'm not certain I completely understand your problem. If calculating in msec means working with a too small number, then why not calculate in microseconds and scale back (or not) to milliseconds in your calculated result?
There's always a better way!

Jack Christensen

#5
Feb 06, 2012, 04:04 am Last Edit: Feb 06, 2012, 04:05 am by Jack Christensen Reason: 1
Agree with PeterH. I'd say total_amp_hours needs to be typed as float for sure. If current and period are not floats, then coerce them as follows and all should be well.

Code: [Select]
   total_amp_hours += float(current) * float(period) / 3.6e6;


(Last I checked, there are 3,600,000 milliseconds per hour.)
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

GoForSmoke

There is a very simple answer: When you measure to small scale, use smaller rulers.

Instead of units in Amp hours, use micro-Amp or pico-Amp hours and do your math in 32 or 64 bit integers. That will give you 6 to 9 digits right of Amp hours decimal, 32 bit integer will give you that from +2 to -2A. If you're going to need roots, trig or logs, either use a table in PROGMEM or get a finite series formula into a function, except for power of 2 operations. It should still be faster than FP as well as more accurate. Need more accuracy, use nano-Amp hour units. They still add up to Amps, just more zeros.

Look at how your multimeter ranges work....

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Nick Gammon


There was a NIck Gammon who implemented...


There still is a Nick Gammon. ;)
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

jimford

Thanks for all the helpful replies. I think I've enough to work on now.

It was pretty stupid of me to say that there are 2160000000 milliseconds in an hour! The only excuse I can offer is that I was befuddled by the number of zeros accumulating and multiplied by an extra 60!

Thanks again.

Jim

GoForSmoke

You use milliseconds to measure to the millisecond in integer. And the result is always faster and correct.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Go Up