Added headwind to Aerolab calculation for iAero

Added a headwind data field, which is available when using
an iAero head unit, to dramatically improve the calculation
of Chung analysis for users of more recent iAero devices.

All other data files than the iAero have the headwind term set to
zero when they append a point.
This commit is contained in:
Andy Froncioni
2010-02-21 13:23:54 -05:00
committed by Sean Rhea
parent afdc862cc2
commit a02bfaf810
16 changed files with 38 additions and 25 deletions

View File

@@ -158,6 +158,10 @@ Aerolab::setData(RideItem *_rideItem, bool new_zoom) {
// Unpack:
double power = max(0, p1->watts);
double v = p1->kph/vfactor;
double headwind = v;
if( dataPresent->headwind ) {
headwind = p1->headwind/vfactor;
}
double f = 0.0;
double a = 0.0;
d += v * dt;
@@ -172,7 +176,7 @@ Aerolab::setData(RideItem *_rideItem, bool new_zoom) {
}
f *= eta; // adjust for drivetrain efficiency if using a crank-based meter
double s = slope( f, a, m, crr, cda, rho, v );
double s = slope( f, a, m, crr, cda, rho, headwind );
double de = s * v * dt;
e += de;

View File

@@ -237,7 +237,7 @@ RideFile *Computrainer3dpFileReader::openRideFile(QFile & file,
// special case first data point
rideFile->appendPoint((double) ms/1000, (double) cad,
(double) hr, km, speed, 0.0, watts,
altitude, 0, 0, 0);
altitude, 0, 0, 0.0, 0);
}
// while loop since an interval in the .3dp file might
// span more than one CT_EMIT_MS interval
@@ -285,6 +285,7 @@ RideFile *Computrainer3dpFileReader::openRideFile(QFile & file,
interpol_alt,
0, // lon
0, // lat
0.0, // headwind
0);
// reset averaging sums

View File

@@ -142,6 +142,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors) const
else if (lineno > unitsHeader) {
double minutes,nm,kph,watts,km,cad,alt,hr,dfpm;
double lat = 0.0, lon = 0.0;
double headwind = 0.0;
int interval;
int pause;
if (!ergomo && !iBike) {
@@ -175,6 +176,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors) const
if( iBikeVersion >= 11 && ( dfpm > 0.0 || dfpmExists ) ) {
dfpmExists = true;
watts = dfpm;
headwind = line.section(',', 1, 1).toDouble();
}
else {
watts = line.section(',', 2, 2).toDouble();
@@ -195,6 +197,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors) const
km *= KM_PER_MILE;
kph *= KM_PER_MILE;
alt *= METERS_PER_FOOT;
headwind *= KM_PER_MILE;
}
}
else {
@@ -234,7 +237,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors) const
watts = 0;
rideFile->appendPoint(minutes * 60.0, cad, hr, km,
kph, nm, watts, alt, lat, lon, interval);
kph, nm, watts, alt, lat, lon, headwind, interval);
}
++lineno;
}

View File

@@ -89,6 +89,7 @@ GcFileReader::openRideFile(QFile &file, QStringList &errors) const
for (QDomElement sample = samples.firstChildElement("sample");
!sample.isNull(); sample = sample.nextSiblingElement("sample")) {
double secs, cad, hr, km, kph, nm, watts, alt, lon, lat;
double headwind = 0.0;
secs = sample.attribute("secs", "0.0").toDouble();
cad = sample.attribute("cad", "0.0").toDouble();
hr = sample.attribute("hr", "0.0").toDouble();
@@ -101,7 +102,7 @@ GcFileReader::openRideFile(QFile &file, QStringList &errors) const
lat = sample.attribute("lat", "0.0").toDouble();
while ((interval < intervalStops.size()) && (secs >= intervalStops[interval]))
++interval;
rideFile->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, lon, lat, interval);
rideFile->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, lon, lat, headwind, interval);
if (!recIntSet) {
rideFile->setRecIntSecs(sample.attribute("len").toDouble());
recIntSet = true;

View File

@@ -125,7 +125,7 @@ RideFile *ManualFileReader::openRideFile(QFile &file, QStringList &errors) const
interval = 0;
rideFile->appendPoint(minutes * 60.0, cad, hr, km,
kph, nm, watts, alt, 0.0, 0.0, interval);
kph, nm, watts, alt, 0.0, 0.0, 0.0, interval);
QMap<QString,QString> bsm;
bsm.insert("value", QString("%1").arg(bs));
rideFile->metricOverrides.insert("skiba_bike_score", bsm);

View File

@@ -200,7 +200,7 @@ this differently
next_interval = intervals.at(interval);
}
}
rideFile->appendPoint(seconds, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, interval);
rideFile->appendPoint(seconds, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, 0.0, interval);
//fprintf(stderr, " %f, %f, %f, %f, %f, %f, %f, %d\n", seconds, cad, hr, km, kph, nm, watts, alt, interval);
}

View File

@@ -52,7 +52,7 @@ QuarqParser::incrementTime( const double new_time )
while (time_diff > seconds_from_start) {
rideFile->appendPoint(seconds_from_start, cad, hr, km,
kph, nm, watts, 0, 0.0, 0.0, 0);
kph, nm, watts, 0, 0.0, 0.0, 0.0, 0);
seconds_from_start += SAMPLE_INTERVAL;
}
@@ -114,7 +114,7 @@ QuarqParser::endElement( const QString&, const QString&, const QString& qName)
// flush one last data point
if (qName == "Qollector") {
rideFile->appendPoint(seconds_from_start, cad, hr, km,
kph, nm, watts, 0, 0.0, 0.0, 0);
kph, nm, watts, 0, 0.0, 0.0, 0.0, 0);
}
return TRUE;

View File

@@ -70,7 +70,7 @@ time_cb(struct tm *, time_t since_epoch, void *context)
double secs = since_epoch - state->start_since_epoch;
state->rideFile->appendPoint(secs, 0.0, 0.0,
state->last_miles * KM_PER_MILE, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, state->last_interval);
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, state->last_interval);
state->last_secs = secs;
}
@@ -84,7 +84,7 @@ data_cb(double secs, double nm, double mph, double watts, double miles, double a
ReadState *state = (ReadState*) context;
state->rideFile->appendPoint(secs, cad, hr, miles * KM_PER_MILE,
mph * KM_PER_MILE, nm, watts, alt, 0.0, 0.0, interval);
mph * KM_PER_MILE, nm, watts, alt, 0.0, 0.0, 0.0, interval);
state->last_secs = secs;
state->last_miles = miles;
state->last_interval = interval;

View File

@@ -231,10 +231,10 @@ QStringList RideFileFactory::listRideFiles(const QDir &dir) const
void RideFile::appendPoint(double secs, double cad, double hr, double km,
double kph, double nm, double watts, double alt,
double lon, double lat, int interval)
double lon, double lat, double headwind, int interval)
{
dataPoints_.append(new RideFilePoint(secs, cad, hr, km, kph,
nm, watts, alt, lon, lat, interval));
nm, watts, alt, lon, lat, headwind, interval));
dataPresent.secs |= (secs != 0);
dataPresent.cad |= (cad != 0);
dataPresent.hr |= (hr != 0);
@@ -245,5 +245,6 @@ void RideFile::appendPoint(double secs, double cad, double hr, double km,
dataPresent.alt |= (alt != 0);
dataPresent.lon |= (lon != 0);
dataPresent.lat |= (lat != 0);
dataPresent.headwind |= (headwind != 0);
dataPresent.interval |= (interval != 0);
}

View File

@@ -43,23 +43,23 @@
struct RideFilePoint
{
double secs, cad, hr, km, kph, nm, watts, alt, lon, lat;;
double secs, cad, hr, km, kph, nm, watts, alt, lon, lat, headwind;;
int interval;
RideFilePoint() : secs(0.0), cad(0.0), hr(0.0), km(0.0), kph(0.0),
nm(0.0), watts(0.0), alt(0.0), lon(0.0), lat(0.0), interval(0) {}
nm(0.0), watts(0.0), alt(0.0), lon(0.0), lat(0.0), headwind(0.0), interval(0) {}
RideFilePoint(double secs, double cad, double hr, double km, double kph,
double nm, double watts, double alt, double lon, double lat, int interval) :
double nm, double watts, double alt, double lon, double lat, double headwind, int interval) :
secs(secs), cad(cad), hr(hr), km(km), kph(kph), nm(nm),
watts(watts), alt(alt), lon(lon), lat(lat), interval(interval) {}
watts(watts), alt(alt), lon(lon), lat(lat), headwind(headwind), interval(interval) {}
};
struct RideFileDataPresent
{
bool secs, cad, hr, km, kph, nm, watts, alt, lon, lat, interval;
bool secs, cad, hr, km, kph, nm, watts, alt, lon, lat, headwind, interval;
// whether non-zero data of each field is present
RideFileDataPresent():
secs(false), cad(false), hr(false), km(false),
kph(false), nm(false), watts(false), alt(false), lon(false), lat(false), interval(false) {}
kph(false), nm(false), watts(false), alt(false), lon(false), lat(false), headwind(false), interval(false) {}
};
struct RideFileInterval
@@ -106,7 +106,7 @@ class RideFile
void appendPoint(double secs, double cad, double hr, double km,
double kph, double nm, double watts, double alt,
double lon, double lat, int interval);
double lon, double lat, double headwind, int interval);
const QList<RideFileInterval> &intervals() const { return intervals_; }
void addInterval(double start, double stop, const QString &name) {

View File

@@ -184,7 +184,7 @@ RideSummaryWindow::htmlSummary() const
if (p->secs >= interval.stop)
break;
f.appendPoint(p->secs, p->cad, p->hr, p->km, p->kph, p->nm,
p->watts, p->alt, p->lon, p->lat, 0);
p->watts, p->alt, p->lon, p->lat, p->headwind, 0);
}
if (f.dataPoints().size() == 0) {
// Interval empty, do not compute any metrics

View File

@@ -140,7 +140,7 @@ SplitRideDialog::CreateNewRideFile(const RideFile *ride, int nRecStart, int nRec
{
RideFilePoint *pPoint = ride->dataPoints().at(nItem);
newRideFile->appendPoint(pPoint->secs-pointStart->secs, pPoint->cad, pPoint->hr, pPoint->km - pointStart->km,
pPoint->kph, pPoint->nm, pPoint->watts, pPoint->alt, pPoint->lon, pPoint->lat, pPoint->interval-pointStart->interval);
pPoint->kph, pPoint->nm, pPoint->watts, pPoint->alt, pPoint->lon, pPoint->lat, pPoint->headwind, pPoint->interval-pointStart->interval);
}
newRideFile->setDeviceType(ride->deviceType());

View File

@@ -202,7 +202,7 @@ RideFile *SrmFileReader::openRideFile(QFile &file, QStringList &errorStrings) co
km += result->recIntSecs() * kph / 3600.0;
double nm = watts / 2.0 / PI / cad * 60.0;
result->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, interval);
result->appendPoint(secs, cad, hr, km, kph, nm, watts, alt, 0.0, 0.0, 0.0, interval);
++blkidx;
if ((blkidx == blockhdrs[blknum].chunkcnt) && (blknum + 1 < blockcnt)) {

View File

@@ -132,10 +132,11 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
// for smart recording, the delta_t will not be constant
// average all the calculations based on the previous
// point.
headwind = 0.0;
if(rideFile->dataPoints().empty()) {
// first point
rideFile->appendPoint(secs, cadence, hr, distance,
speed, torque, power, alt, lon, lat, lap);
speed, torque, power, alt, lon, lat, headwind, lap);
}
else {
// assumption that the change in ride is linear... :)
@@ -153,7 +154,7 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
if(deltaSecs == 1) {
// no smart recording, just insert the data
rideFile->appendPoint(secs, cadence, hr, distance,
speed, torque, power, alt, lon, lat, lap);
speed, torque, power, alt, lon, lat, headwind, lap);
}
else {
for(int i = 1; i <= deltaSecs; i++) {
@@ -176,6 +177,7 @@ TcxParser::endElement( const QString&, const QString&, const QString& qName)
prevPoint->alt + (deltaAlt * weight),
lon, // lon
lat, // lat
headwind, // headwind
lap);
}
prevPoint = rideFile->dataPoints().back();

View File

@@ -56,6 +56,7 @@ private:
double alt;
double lat;
double lon;
double headwind;
};
#endif // _TcxParser_h

View File

@@ -414,7 +414,7 @@ WKO_UCHAR *WkoParseRawData(WKO_UCHAR *fb, RideFile *rideFile, QStringList &error
// !! needs to be modified to support the new alt patch
rideFile->appendPoint((double)rtime/1000, cad, hr, km,
kph, nm, watts, alt, lon, lat, 0);
kph, nm, watts, alt, lon, lat, 0.0, 0);
}
// increment time - even for null records (perhaps especially for null