Still tweaking, but things are looking good. The rest of this post is a lot of technical details to give those who are interested some idea of just how complicated it is to answer the simple question: "am I steadily cruising?"
Some of my expectations were quite wrong. I expected that my RPM readings would be quite smooth/consistent so that I wouldn't have to worry about noise filtering or averaging much, and I expected that throttle readings would be noisy due to bumps, sneezes, nervous twitches, etc. It's quite the opposite in reality.
When cruising steadily, throttle is very steady. It varies by less than 0.5% over the course of 1/2 a second on smooth roads, and up to about 3% when dodging potholes, changing lanes, hitting bumps, etc. It often even stays within about 0.2% for several seconds at a time if the road is flat.
RPM readings fluctuate quite a bit, by up to about 16 RPM over the course of 1/2 a second when cruising perfectly steadily on a flat, smooth road. Rough spots, bumps, slight changes in throttle, etc. create more variation even, though you maintain the same steady speed. These fluctuations don't show up in my data logs, because they are too small to be visibly represented in the line, but they are large enough to be a problem to my calculations. I had to log raw readings from my device to EEPROM memory on the microcontroller, then copy that data to my computer and manually analyze it to get this info (and by manually, I mean with the help of a nice text editor with regular expression enabled search/replace, then quickly wrote some code to process the re-formatted data and get results in terms of RPM fluctuations, etc.)
It makes sense after thinking about it. I'm calculating RPM by precisely measuring (down to 1 millionth of a second) the time between pulses from the camshaft position sensor (1 pulse per 2 revolutions of the engine). Any slight variation in the timing between pulses results in a significant different in the calculated RPMs. The difference between 3000 RPM and 3010 RPM corresponds to a difference of only 0.000133 seconds between pulse timing. At higher RPMs, the difference is even smaller: 0.000048 seconds for 5000 - 5010 RPM. There's also quite a bit of slack in the drivetrain. Put your bike in gear on the center stand (engine off) and see how far you can move the rear tire. The drivetrain is not heavily loaded when steadily cruising at less-than-highway speeds, so any slight bump, dip, rise, etc. can cause the drivetrain to unload. The engine will now spin quicker for the next couple revolutions while eating up that slack. Or a bump/dip/rice could momentarily put more load on the drivetrain, causing the engine to spin slightly slower. It all happens so quickly that you perceive that you are steadily cruising, but the engine speed is jumping all over the place within a small RPM range between each individual rotation. An average RPM over several rotations would give a more meaningful representation of the speed of the motor.
So here's my problem... I want a fairly small threshold on how much the RPMs are allowed to change within a short amount of time to be considered "steady". The shorter the time, the more responsive it will be to changes, but threshold has to smaller and more easily falsely exceeded by normal RPM variations. If I look at RPM variations over a longer time, my threshold can be larger for the same limit on rate of change in RPM, so it will be less likely exceeded by normal variations, but it will be less responsive to changes. For example, if I sampled 10 seconds of data, I would have to accelerate above the allowed rate for up to 10 seconds before my device could detect that I'm accelerating too fast to be cruising.
And here's the overall approach I'm taking to determining which fuel map to use:
- Every time a pulse comes from the camshaft sensor...
Calculate an RPM reading based on the time that passed over the 5 previous pulses. This gives me the average RPM over the past 10 revolutions of the engine, which will smooth out some of the "normal" variations.
- Store the RPM reading, so that it can be sampled later. All RPM readings since the last sampling are stored.
[*]Every 1/16th of a second (this is when all the sampling and decision work happens)...
- Sample the current RPM. To do this, I average all of the calculated RPM readings that have happened since the last sampling. At any RPM above 1920, pulses will be occurring more frequently than 16 times a second. Rather than just going with the most recent reading, I calculate the average RPM over the previous 1/16 of a second. This also helps smooth out normal variations.
- Sample the current throttle position. Throttle is simply an analog input (0-5v), but 0% throttle is above 0v and 100% throttle is below 5v, so I do have to convert it to a range of 0-100% based on calibrated end points.
- Maintain a list of the 8 most recent throttle and RPM samples (that's 1/2 second of data).
- Consider the bike to be "steady" if...
All recent throttle positions are below 0.5% AND all recent RPM are below 1300 RPM (idling).
- OR All recent throttle positions are above 0.5% AND all recent RPM are above 1300 RPM (not idling) AND all recent throttle positions are within 3.5% of each other AND all recent RPMs are within 80 RPM of each other.
[*]Some explanation of the "steady" conditions above...
- The RPM varies even more when idling, because the engine is under no load. This is why I don't care about variations being within the thresholds as long as all readings are within the idling range.
- The requirement that all readings must be above idling AND within thresholds results in instant response when starting to accelerate from a stop. As soon as the throttle exceeds 0.5% or the RPM exceeds 1300, it is considered not "steady", even if everything was within the steady thresholds. It also results in instant non-steady response when closing the throttle completely while slowing for a corner, no matter how gently you close the throttle.
- The 80 RPM per 1/2 second threshold theoretically enforces a maximum acceleration as follows:
1st gear: ~1.06 mph per second
- 2st gear: ~1.60 mph per second
- 3st gear: ~2.13 mph per second
- 4st gear: ~2.56 mph per second
- 5st gear: ~3.02 mph per second
[*]In lower gears, the RPM threshold will be more easily exceeded that the throttle threshold, because the bike can accelerate/decelerate more quickly with smaller changes in throttle.
[*]Likewise, in higher gears, the throttle threshold will more likely be exceeded before the RPM threshold.
[*]If the bike has been "steady" for the past 64 samplings (that's 4 seconds), then select the cruising map. Otherwise, select the smoothness/power map. This creates a waiting period before going into cruising mode. Note that it only takes one non-steady sampling period to switch from cruising to smoothness/power.
[*]Worst case scenario, it will take 1/2 second to respond to a throttle/RPM change that is just barely above the threshold and switch out of cruising mode.
[*]If you whack the throttle open or closed, or shift gears, it will switch out of cruising mode within 1/16 of a second.
Well, there you have it. Anyone still with me?
All the specifics mentioned above (number of pulse timings averaged together, number of samples considered against thresholds, threshold values, etc) are what I am currently tweaking to find a good balance between reliably staying in cruising mode when I'm actually cruising, and quickly switching out of cruising mode ASAP when I want it to. I'm placing more importance on quickly getting out of cruising mode. I bet vehicle manufactures probably place more importance on staying in cruising mode (closed-loop mode) until it is absolutely certain that the driver is no longer cruising, thanks to the EPA
My goal is to improve fuel mileage significantly without ever noticing that my bike is running leaner when I'm accelerating, cornering, or doing anything else where I need/want smooth throttle control. I don't care about some minor lean surging while steadily cruising. So far, I can say that the bike has been smooth whenever I expect it to be. In a few more days, I'll be able to report mileage on my first full tank of gas since I installed this. I hope it's good...