This change allows us to connect the zonesChanged signal to the ride summary,
so that we don't have to call ride->htmlSummary as a special case whenever
we call zonesChanged. It will also come in useful later when I introduce a
rideSelected signal.
Computrainer 3D software lets you start your ride partway into
a course. But, if you do this, the first distance recorded
in the log file is the distance you started at, rather than zero.
GC expects the first data point to be at distance zero, however,
and therefore this causes total distance to be reported incorrectly.
This patch fixes the bug by remembering the distance of the
first data point, and subtracting that from all distances
reported to GC, so that distances are zero-based (i.e.,
so that the first data point is always at distance zero.)
Fixed a crash due to threading of the socket.
Improved performance of discovery()
Improved ability to recover from a lost channel
Fixed bug where channel ID's weren't being correctly sent.
GC wasn't waiting for Qt to return from connecting to the host. It now is.
Fixed When the user hit stop then start, the realtime thread did not start.
Specifically:
1. The previous code assumed the wrong units while extracting
speed and distance from a .3dp file. Computrainer stores
speed in (miles per hour / 160), and distance in kilometers.
This patch converts .3dp speed/distance data points into
kph and km correctly. As a side-effect, speed and distance
are displayed correctly in GC windows and calculations.
2. This patch adds code to extract altitude data from a .3dp
file and include it in a ride.
3. .3dp files do not have a consistent inter-datapoint time
interval. Since GC expects one, the earlier version of this
code averaged 1000 data points from the middle of the ride to
estimate this interval. Unfortunately, this approach caused
a bunch of problems for various calculations that GC does,
such as calculating the riding time (vs. workout time),
average speed, xPower, critical power plot and FTP, and so
on. [GC assumes that # data points * inter-datapoint-interval
= workout time, but this isn't true when you used an estimated
interval.]
To fix this, this patch adds averaging and interpolation code
to covert the data point sequence in the .3dp file to an
averaged sequence with a data point every 250ms. Since the
inter-data-point interval is now fixed, these calculation bugs
went away, and correct values are now calculated and displayed
by GC.
4. Fix (3.) has another useful side-effect: the number of data
points per ride given to GC goes down by 10x. (Raw .3dp files
have a data point every 30-50ms. This averaging/smoothing
code emits a data point every 250ms.) Since the critical
power calculation is an O(n^2) calculation, the time for
this calculation is reduced by 100x. Instead of an hour
to do the calculation for a typical 2hr ride, it now takes
less than a minute.
5. The code was cleaned up in several regards: comments
were added to help document the .3dp format and explain
the averaging/smoothing code, and types from boost/cstdint.hpp
were used instead of native C types when using a variable
of a specific size (e.g., the code now uses uint16_t instead
of unsigned short, etc.).
This patch was built by Steve Gribble and Daniel Stark.
I want to add Daniels Points to the ManualRideFile format, but until then,
simply estimate them from the BikeScore based on a weighting I took from some
of my long rides. It's mostly on long steady rides that I estimate BikeScore
as part of a ManualRideFile, so hopefully this isn't too terrible as a
temporary patch. A better fix is in the works.
Commit 420b2b6 introduced a bug whereby it used the total workout time,
rather than the time riding, to compute xPower. This should only affect
your data if you take long breaks during rides, like to stop for brunch,
or if you store multiple rides in the same ride file--i.e., you don't
use the split ride feature. Nonetheless, it's worth deleting your
stress.cache file after applying this commit, just in case.
I've also added three rides, notes, and a zones file to the test directory to
illustrate the differences discussed above. The first ride is just an hour at
CP/FTP. It should have a BikeScore of very close to 100, and Daniels Points
very close to 33. The next ride is the same as the first, but followed by 20
minutes of coasting. Its Daniels Points should be the same as the former,
but its BikeScore should be a good bit higher. The final ride is the same as
the first, but interrupted partway through by 30 minutes of no riding at all,
as though the cyclist stopped for coffee and a pastry. It should have
nearly identical BikeScore and Daniels Points to the first ride. In the
broken implementation of xPower that this commit fixes, it did not.
Dan C: I reverted your changes to the xPower calculation in this commit and
went back to my implementation. It's just easier for me to think about the
code that way. My apologies. I kept the other changes you made, though.
Fit a curve to the points system in Table 2.2 of "Daniel's Running Formula",
Second Edition, assume that power at VO2Max is 1.2 * FTP, further assume that
pace is proportional to power (which is not too far off in running), and scale
so that one hour at FTP is worth 33 points (which is the arbirary value
Daniels chose).
Just attribute all earlier rides to the first zone. We should do better in
the future, maybe by complaining to the user in a dialog, but for now,
not crashing definitely seems better than crashing.
This seems like the right call to me. If I'm doing an interval and I stop
riding for some reason, I'm resting, and that should affect my average power.
I thought it was always this way, but apparently not.
The default position of the power combo box in the Ride Plot is to shade
power. Change the default value of the shade_power variable to match. This
didn't matter before 79ced76, since prior to that commit we (mostly
redundantly) called showPower from setAllPlotWidgets, whereas now we only call
showPower after a change in the combo box.