# MPower Echelon2 Import with Aerodynamic Drag Calculations

## Dec 24, 2020

I added Schwinn AC Performance Plus support via MPower Echelon2 Console CSV import to my Track My Indoor Workout application. Things were hunky-dory except that the velocities were too fast for high power outputs. This resulted in inflated average speeds and two occasions when I was on slightly miscalibrated bikes (they read higher powers) I managed to take down some Strava KOMs (King of the Mountain awards) in the Jerry Baker Memorial Velodrome - where I interpolated the GPS coordinates.

This was very alarming, because the last thing I wanted to do is to interfere with the real track cyclist of that velodrome (or anywhere else). Any of the app users could also unintendedly take down a KOM on a miscalibrated bike. It makes the problem worse that even though I specify "VirtualRide" as the sport type in my TCX Strava upload it seems to go through as a Ride.

- As an immediate crisis avoidance I relocated the GPS location from the Marymoor Park to the Hoover High School’s running track in Fresno California. The running track doesn’t have any cycling segments, so no user could take down any KOMs/QOMs any more, the app wouldn’t interfere with real riders whatsoever. The move wasn’t too hard, because that running track is also North-South oriented. Although both are 400m tracks, they are very different: an athletic running track has 100m long straight and 100m long turns whereas a velodrome has longer turns and shorter straight so the turns can be graded lower and the radius can be bigger so there would be less centripetal force on the riders. A high school track which hosts an American football field has also different shape than an athletic track although still all of them are 400m long. Fortunately I already faced this when I developed for the velodrome and I have a factor in place for the different shapes, I just needed to fine-tune that for the Hoover track with 5-6 uploads.
- As a longer term solution I needed to change how I compute velocity from a power reading. What I did so far was to look at the average power and the total distance, calculate the ratio of that and proportion that per power. This resulted in a linear power to speed equation which worked OK looking at the whole ride but would result in too fast speeds for high power outputs. That not only resulted in unwanted KOMs but Strava also automatically flagged two of my workouts which were on slightly miscalibrated bikes (with higher power readings). I knew that if I’d use physically realistic equation then it would gradually tone down the speeds for higher outputs because
*the aerodynamic drag is proportional to the square of the velocity*.

I came across this webpage by Steve Gribble which gave a nice foundation for more realistic equations. The formula is not simply reversible. There’s a closed formula to compute the forces for a specific velocity, so we use a successive approximation method to hone in to a velocity belonging to a power value. We set low and high velocity bounds and start from an approximate velocity point. In an iteration we compute the power for the current velocity point and adjust the low and high bound based on the offset of the power from the given power value. We exit the iteration if we get close enough to the given power (by an epsilon) or we exceed 100 iterations.

Since we only need a two fractional digit precision speed reading the epsilon can be fairly large: currently 0.001. The bound adjustment is halving domain distances so the iteration converges O(logN). This still means an approximation run for every data point (including the interpolated ones), but the extra time needed is still dwarfed by the speed dominating factor of the SQLite persistence. I introduced a cache for the already calculated power-speed value pairs. I spent a day to spin out the algorithm and the end result is satisfactory: I don’t see unrealistic speeds any more, and the after I re-uploaded the two previously flagged activities they didn’t get flagged any more. The downside is that the total covered distance is now noticeably lower than what the Echelon 2 console shows (for example 13 miles instead of 16), but this is a necessary result of the enhancement.