The gear detector I built last week works beautifully — in simulation. There's just one catch: to make it commit to a gear, you'd have to hold that gear, steadily, for the better part of thirty seconds. Nobody rides a bike like that. Chasing down why led somewhere I didn't expect — to a small truth about what a bicycle sensor is actually telling you, and to the uncomfortable discovery that the simulator I'd been trusting was quietly lying to me.
A detector that needs you to sit still
The detector from the last devlog watches the gear ratio and, once it has held steady inside a band for a minimum number of samples, commits it as a gear. In the data viewer, we fed a ride where each gear was held for a good long while, it drew a lovely clean staircase. When we fed it a ride with realistic shifting — a gear held for ten or fifteen seconds before the next change — it fell apart: spurious rungs, ratios committed mid-transition, a ladder that climbed in the wrong order.
The binding number turned out to be the averaging window. To beat the sensor noise the detector leans on roughly sixteen crank revolutions, plus a handful more to confirm — call it twenty-four crank revolutions before it'll trust a gear. At a normal 75 rpm that's about twenty seconds, and I'd padded it to thirty for margin. Wonderful for a bench test. Useless as a thing you ask a human to do at a traffic light.
What the sensor was actually saying
Here is the thing I had been walking straight past. A Bluetooth speed or cadence sensor doesn't just hand you a count. The standard Cycling Speed and Cadence profile gives you a cumulative revolution count and the time of the most recent revolution — stamped on the sensor's own clock, to one part in 1024 of a second. That second number is the whole gift.
Because the time is measured at the actual revolution — not at some arbitrary sampling boundary — you can compute a frequency from a single revolution and have it be accurate. Wheel frequency is revolutions divided by the precisely measured time those revolutions took. Do the same for the crank. The gear is just their ratio.
The simulator was lying
So why had I needed the window at all? Because the bench simulator I had been testing against was generating its fake sensor data the easy way — integer revolution counts ticked off a single shared clock. A close look at the output and we found the wheel frequency was always exactly one-times, two-times, three-times the crank. Never the 1.41× of first gear. It had thrown away the one piece of information the real approach depends on: that the wheel and the crank are timed independently, by two separate clocks, to sub-revolution precision.
The thirty-second window was never a property of the problem. It was a property of my test rig. I had built a simulator that was easier to write than reality, and it had lied to me in precisely the place I most needed the truth.
So: a bench that doesn't lie
The fix isn't a cleverer detector. It's an honest bench. Three rules fell out of the post-mortem.
-
01
Two clocks, not one Time the wheel and the crank independently, each on its own hardware, exactly as two separate physical sensors do. That independence is the signal.
-
02
Feed pulses, not numbers Don't hand a sensor a frequency. Hand it edges — a string of pulses — and let it timestamp them itself, the way a reed switch times a magnet sweeping by. Then the timing is real, jitter and all.
-
03
Match the actual product The bike will carry two separate sensors — a speed unit and a cadence unit — on two separate radios. So should the bench. The Magene S3+ and CYCPLUS C3 pairs are already in the mail; the rig should behave like them before they arrive.
Loading…