Calculation with multiple integers
PlaneTeeR
Posts: 100
Hello,
For my project I have to make an average speed calculation. This I have to do with distance/time. But my program has multiple integers that represent the distance and time.
distance has two integeres (Km and m).
time has three integers (hours, minutes and seconds).
When I add them two one integer my range is limited (37,767), that means distance max 37KM and time max 10 hours.
How can i do this without these limitations?
Johnny
For my project I have to make an average speed calculation. This I have to do with distance/time. But my program has multiple integers that represent the distance and time.
distance has two integeres (Km and m).
time has three integers (hours, minutes and seconds).
When I add them two one integer my range is limited (37,767), that means distance max 37KM and time max 10 hours.
How can i do this without these limitations?
Johnny
Comments
then your range is 65535.999 km. If you want even larger integers
you can use the Int32 class.
(with the Format class you can print unsigned integers hence 65535)
The only option for high numbers in a single integer is the fp3 class.
This is a floating point number with only 3 digits: range up to 0.999E+15
(E stands for power of 10). For example:·0.999E+00 km (999 m) or 0.999E+03 km (999 km)
but I don't think you want that for your display.
regards peter
2 voor distance 3 for time
distance / time = avg
Johnny
avg [noparse][[/noparse]m/s] = (1000*km + m) / (3600*hours + 60*minutes + seconds)
avg [noparse][[/noparse]km/h] = (km + m/1000) / (hours + minutes/60 + seconds/3600) =
················· (intnom + frnom/65536)/(intden + frden/65536)
minutes/60 and seconds/3600 are fractions (0 < value < 1)
m/1000 is also a fraction
frmin = UnsignedIntMath.ufrac(minutes,60);
frsec = UnsignedIntMath.ufrac(seconds,3600);
intden = hours; //integer of denominator
frden = frmin + frsec; //fraction of denominator
if (CPU.carry()) intden++;
frnom = UnsignedIntMath.ufrac(m,10000); //fraction of nominator,·m is 0.1m units
intnom = km; //integer of nominator
Now we only need to rearrange the formula to calculate avg [noparse][[/noparse]km/h].
I have to think about·how this can·be approximated easily.
regards peter
Keep the average updated every loop:
·············+---+ speed
avgold
+···|
·············|·· |
·············|·· |
···· 0
······ 0·····T1· T2
avgold is the·average speed for all previous loops,
speed is the speed for the current loop
T2-T1 is the time for the current loop
T1 is the realtime for all previous loops
T2 is the new realtime
Then avgnew = ( (T1*avgold) + (T2-T1)*speed ) / T2
= (T1/T2)*avgold + ((T2-T1)/T2)*speed
T1/T2 is a fraction, as is (T2-T1)/T2
These fractions are multiplied by integers.
So this can be calculated using the UnsignedIntMath methods ufrac() and umulf().
regards peter
If the looptime is about 10 msec every loop,
then T1/T2 equals 1 after T2=65536*10mSec = 655.36Sec = approx.·11 minutes.
So after 11 minutes realtime, T1/T2 reaches 1
But then (T2-T1)/T2 reaches 0
so avgnew = avgold
Conclusion: after about 11 minutes the average speed will not change.
This is of course due to the 16bit math.
You could of course use Float32 but I wonder if that would make
much difference, unless the speed really increases or decreases after
11 minutes.
Another option is to scale down·T1,·T2 and (T2-T1) by a factor 10
(after 11 minutes) and then perform the calculations. This would ensure
the parameters are kept in the right range.
regards peter
Post Edited (Peter Verkaik) : 5/26/2006 2:58:35 PM GMT
The solution is to use larger time units for calculating the average
speed. Say you calculate the average for the last 5 seconds
and assume this is the speed for the current loop.
Then recalculate T1 and T2 in 5sec units. (T2-T1 then equals 1)
The above approach then works until
T2 = 65536*5Sec = 327680Sec = 91 hours.
I don't think you cycle that long!
It does mean your average speed display is only updated every 5 seconds.
regards peter
Post Edited (Peter Verkaik) : 5/26/2006 3:14:08 PM GMT
Thanks again for this info .
Johnny
I now use sensor to keep track of number of pulses which in processor class be calculated into dstm / dstKm. And there we have the chronometer of seconds minutes and hours. I'm now not using the loop. But a method to calculate the average speed.
Johnny
Ideally you would want a sensor that gives you the speed
at the moment you poll your sensor.
So have a method int getSpeed() in your sensor class.
Distance and average speed should be calculated in your application class (Main).
I noticed you create a new Display() in your main class and then
your mainloop starts in display.
I think you must restrict Display to just do the printing to your display.
After all, your display class should be independant of your current application.
It is your application class that should create instances of your objects (display,sensor,buttons,uarts,timers)
and then process and control information you get from those objects.
That way your library classes (display,sensor) are independant of the current application
and can then be reused by other applications.
Edit:
You can calculate distance and average speed also in your sensor class
based on passed time between polls. Then those functions are also
independant of your current application. And these two properties are
closely related to your sensor.
Or put those calculations in a seperate class so they can be reused
when getting speed from an other source than your sensor.
regards peter
Post Edited (Peter Verkaik) : 5/31/2006 10:26:03 AM GMT
When you want to display the speed the application starts calculation in processor which retreives the current pulseTime and calculates..
That should work fine doesn't it?
This class (for the math package) calculates
distance based on speed and time
speed based on distance and time
Since these calculations are just a mathematical issue,
I think it is wise to have them in a seperate class
so other applications can use it also.
It is by no means correct or complete
but it lets you concentrate on the math only.
I have defined the units which give the
best possible range using integers.
Problems arise when time,·speed or distance are very small
so it probably is best to include some·methods
that accumulate results until the results are within the
range of preferred units.
This class can be tested with just a javelin. No external hardware required.
I will keep working on this. Please post any solutions you find.
regards peter
calculated in the sensor class rather than the processor class?
That really isn't an issue.
It is much better to have more small classes than a few classes
that integrate everything.
The travel class in my previous post for example, is very small
and handles a small part of your application, but it is in no way
dependant of your application.
That is what object oriented programming (OOP) is all about.
regards peter
When distance is in two seperate ints and time in 3.·The limit of 16 bit is really irritant!
Johnny
Since both speed and average speed are in 0.01 km/h units it is possible
to calculate these results using 16bit math by using fractions and
rearranging the calculations.
Like I said, this is a mathematical problem that really is independant
of your particular application.
I wrote out how to calculate distance in 0.1m units using speed in 0.01km/h units
and time in ms units.
distance[noparse][[/noparse]0.1m] = 100 * distance[noparse][[/noparse]0.01km]
···················· = 100 * speed[noparse][[/noparse]0.01km/h] * time[noparse][[/noparse]h]
···················· = 100 * speed[noparse][[/noparse]0.01km/h] * (1/60) * time[noparse][[/noparse]m]
···················· = 100 * speed[noparse][[/noparse]0.01km/h] * (1/60) * (1/60000) * time[noparse][[/noparse]ms]
The trick is now to do these calculations in 16bit math without over- or underflow.
The class UnsignedIntMath should be able to solve this. I am working on this.
For example, speed=30000 (300 km/h) and time=30000 (30 sec) results
in 25000 (2500 m).
Obviously if time exceeds its limit then other units must be used.
so multiple methods for different units may be necessary.
regards peter
You can run the attached test program to see calculated distances
in 0.1m units for several given speed[noparse][[/noparse]0.01km/h] and time[noparse][[/noparse]ms] values.
Here is the output of the test program:
distance[noparse][[/noparse]0.1m] = speed[noparse][[/noparse]0.01km/h] * time[noparse][[/noparse]ms]
distance[noparse][[/noparse]0.1m] = 30000 * 30000 = 25000
distance[noparse][[/noparse]0.1m] = 10000 * 30000 = 8333
distance[noparse][[/noparse]0.1m] = 3000 * 30000 = 2500
distance[noparse][[/noparse]0.1m] = 1000 * 30000 = 833
distance[noparse][[/noparse]0.1m] = 30000 * 10000 = 8333
distance[noparse][[/noparse]0.1m] = 10000 * 10000 = 2778
distance[noparse][[/noparse]0.1m] = 3000 * 10000 = 833
distance[noparse][[/noparse]0.1m] = 1000 * 10000 = 278
distance[noparse][[/noparse]0.1m] = 30000 * 3000 = 2500
distance[noparse][[/noparse]0.1m] = 10000 * 3000 = 833
distance[noparse][[/noparse]0.1m] = 3000 * 3000 = 250
distance[noparse][[/noparse]0.1m] = 1000 * 3000 = 83
distance[noparse][[/noparse]0.1m] = 30000 * 1000 = 833
distance[noparse][[/noparse]0.1m] = 10000 * 1000 = 278
distance[noparse][[/noparse]0.1m] = 3000 * 1000 = 83
distance[noparse][[/noparse]0.1m] = 1000 * 1000 = 27
program finished
regards peter
Note that average is speed but uses different units for distance and time.
For average:
The distance units are 10m, the time units are seconds.
Using positive integers that means distance has a range of 32767*10m = 327.67km
and time has a range of 32767*1s = 9.1h
If your application has stored hours, minutes and seconds
(I assume you have stored distance in 0.01km units = 10m units)
you use averageSpeed = travel.average(distance,(60*hours+minutes)*60+seconds)
If you have stored the distance in two integers dstKm[noparse][[/noparse]km] and dstm[noparse][[/noparse]0.1m] then use
distance = dstKm*100+(dstm/100) in the above formula.
regards peter
Post Edited (Peter Verkaik) : 6/1/2006 6:23:59 AM GMT