All the variables are 32bit, which holds a nice big number (4 gig) you don't have to worry about running out with right away.
However, in order to retain precision after a math operation, like where you need to multiply by one thing and divide by another, you should always do the multiplication parts first. i.e. in integers, 50x21/3 is different than 50/3x21.
So the big size problem comes in when doing the multiplication parts. If you were to multiply 65536 by 65536, boom! you just went over your 32 bit budget, even though it only takes 17 bits to represent an unsigned 65536.
To put 65536 in perspective, lets say you have set pulsesPerMile to 10000, the trip accumulator will have reached 65536 pulses after 6.5536 miles. Injector open time is measured in microseconds, so it doesn't take long to accumulate rather large numbers there either.
So the scheme here is to use 64 bit math "Temporarily" inside functions that do computations. But the functions still have to be arranged and organized internally so that they are reasonably sure that they will return 32 bit numbers under ordinary circumstances, while not losing precision to scaling.
Ok, so we have a scheme for dealing with fairly large numbers, the next issue is space/resources. It turns out that the compiler does have a long long type, but it soaked up so much space when it was included that it was impractical to use. So I put some simple routines (add/div/mul/sub,init).
Init usually is used to "promote" a 32 bit number to the 64 bit representation. So lets look at a snippet:
init64(tmp1, 0, 1000ul);
init64(tmp2, 0, imph);
mul64(tmp1, tmp2);
init64(tmp2, 0, igph);
div64(tmp1,tmp2);
return tmp1[1];
so: we multiply imph (instant mph) by 1000, then divide it by igph.
note also that some variables have an implied 3 decimal places. So that 45.502 mph is represented as 45502 , floating point math is no good on these chips, space pigs and slow so this is a common approach. So here we multiplied by 1000 first so that the result would also have the implied 3 decimal places.
so these should use init, and careful though about when to multiply/divide and if the variable is already in implied decimal or not.
i.e. this is not how to initialize one of these 64 bit variables, it isn't array notation and it introduced a floating point into our land of happy integers:
tmp1 = 17.9999999; // tank mpg temp
instead it should arguably be:
init64(tmp1, 0, 17999ul);
I always have to sketch out the whole function, to figure out the right order of operations, and do some sanity checks on it, then double check the cpu screen after it is implemented to ensure we have not depleted our resource budget.
Even miles remaining is not contention free. Earlier discussion on it were concerned if it should start with the gallons remaining in the tank, then perhaps it should use the current trip mpg to give a more "how am I driving today" feel to the miles remaining number. Some thought it should only be the last 5 minutes of driving (have fun tracking that), and I never saw it as being a terribly interesting metric since there is a lot of fudge involved and you would have to be naive to rely on it completely. I think there are still some interesting functionality to implement, i.e. coastdown/cda/rolling resistance calculator or some measure of "realtime" bsfc, which is where I usually think of to poke at it next, and given limited cpu resources I prefer to think about what items will lead to the most efficient drivers myself, i.e. what tools could a dedicated hypermiler use to be more efficient that they don't have?
__________________
WINDMILLS DO NOT WORK THAT WAY!!!
|