Pages: [1]   Go Down
Author Topic: Dealing with very small numbers?  (Read 596 times)
0 Members and 1 Guest are viewing this topic.
Hertfordshire, U.K.
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12482
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-wink

Logged

Rob Tillaart

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

Offline Offline
Edison Member
*
Karma: 35
Posts: 1429
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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
Logged

Where are the Nick Gammons of yesteryear?

UK
Offline Offline
Shannon Member
****
Karma: 184
Posts: 11195
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.)
Logged

I only provide help via the forum - please do not contact me for private consultancy.

West Des Moines, Iowa USA
Offline Offline
Sr. Member
****
Karma: 2
Posts: 428
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

There's always a better way!

Grand Blanc, MI, USA
Offline Offline
Faraday Member
**
Karma: 71
Posts: 3532
CODE is a mass noun and should not be used in the plural or with an indefinite article.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
   total_amp_hours += float(current) * float(period) / 3.6e6;

(Last I checked, there are 3,600,000 milliseconds per hour.)
« Last Edit: February 05, 2012, 10:05:54 pm by Jack Christensen » Logged

MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 4028
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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....

Logged

Examples can be found in your IDE.

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There was a NIck Gammon who implemented...

There still is a Nick Gammon. smiley-wink
Logged

Hertfordshire, U.K.
Offline Offline
Jr. Member
**
Karma: 1
Posts: 84
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 58
Posts: 4028
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

Examples can be found in your IDE.

Pages: [1]   Go Up
Jump to: