diff --git a/src/RideFileCache.cpp b/src/RideFileCache.cpp index 566d06fbb..f2a47e58d 100644 --- a/src/RideFileCache.cpp +++ b/src/RideFileCache.cpp @@ -69,9 +69,11 @@ RideFileCache::RideFileCache(Context *context, QString fileName, RideFile *passe // time in zone are fixed to 10 zone max wattsTimeInZone.resize(10); - wattsCPTimeInZone.resize(4); // zero, moderate, heavy, severe + wattsCPTimeInZone.resize(4); // zero, I, II, III hrTimeInZone.resize(10); + hrCPTimeInZone.resize(4); // zero, I, II, III paceTimeInZone.resize(10); + paceCPTimeInZone.resize(4); // zero, I, II, III // Get info for ride file and cache file QFileInfo rideFileInfo(rideFileName); @@ -204,10 +206,11 @@ static long offsetForTiz(RideFileCacheHeader head, RideFile::SeriesType series) offset += head.wattsKgDistCount * sizeof(float); offset += head.aPowerDistCount * sizeof(float); - // tiz ist currently just for RideFile:watts and RideFile:hr series. - // watts is first - so move on with offset only for 'hr' - // structure for "tiz" data - watts(10)/CPwatts (4)/HR(10) + // tiz ist currently just for RideFile:watts, RideFile:hr and RideFile:kph series. + // watts is first - so move on with offset only for 'hr' and 'kph' + // structure for "tiz" data - watts(10)/CPwatts(4)/HR(10)/CPhr(4)/PACE(10)/CPpace if (series == RideFile::hr) offset += (10+4) * sizeof(float); + if (series == RideFile::kph) offset += 2*(10+4) * sizeof(float); return offset; } @@ -378,7 +381,9 @@ RideFileCache::RideFileCache(RideFile *ride) : wattsTimeInZone.resize(10); wattsCPTimeInZone.resize(4); hrTimeInZone.resize(10); + hrCPTimeInZone.resize(4); paceTimeInZone.resize(10); + paceCPTimeInZone.resize(4); ride->getWeight(); ride->recalculateDerivedSeries(); // accel and others @@ -1242,6 +1247,9 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s if (hrZoneRange != -1) LTHR=context->athlete->hrZones()->getLT(hrZoneRange); else LTHR=0; + if (paceZoneRange != -1) CV=context->athlete->paceZones()->getCV(paceZoneRange); + else CV=0; + // setup the array based upon the ride int decimals = decimalsFor(series); //RideFile::decimalsFor(series) ? 1 : 0; double min = RideFile::minimumFor(series) * pow(10, decimals); @@ -1264,15 +1272,15 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s if (series == RideFile::watts && zoneRange != -1) wattsTimeInZone[context->athlete->zones()->whichZone(zoneRange, dp->value(series))] += ride->recIntSecs(); - // CP zones :- moderate(Z2), severe (>CP) + // Polarized zones :- I(<0.85*CP), II (0.85*CP), III (>CP) if (series == RideFile::watts && zoneRange != -1 && CP) { - if (dp->value(series) < 1) // moderate zero watts + if (dp->value(series) < 1) // I zero watts wattsCPTimeInZone[0] += ride->recIntSecs(); - if (dp->value(series) < (CP*0.85f)) // moderate + if (dp->value(series) < (CP*0.85f)) // I wattsCPTimeInZone[1] += ride->recIntSecs(); - else if (dp->value(series) < CP) // heavy + else if (dp->value(series) < CP) // II wattsCPTimeInZone[2] += ride->recIntSecs(); - else // severe + else // III wattsCPTimeInZone[3] += ride->recIntSecs(); } @@ -1280,10 +1288,34 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s if (series == RideFile::hr && hrZoneRange != -1) hrTimeInZone[context->athlete->hrZones()->whichZone(hrZoneRange, dp->value(series))] += ride->recIntSecs(); + // Polarized zones :- I(<0.9*LTHR), II (0.9*LTHR), III (>LTHR) + if (series == RideFile::hr && hrZoneRange != -1 && LTHR) { + if (dp->value(series) < 1) // I zero + hrCPTimeInZone[0] += ride->recIntSecs(); + if (dp->value(series) < (LTHR*0.9f)) // I + hrCPTimeInZone[1] += ride->recIntSecs(); + else if (dp->value(series) < LTHR) // II + hrCPTimeInZone[2] += ride->recIntSecs(); + else // III + hrCPTimeInZone[3] += ride->recIntSecs(); + } + // pace time in zone, only for running activities if (ride->isRun() && series == RideFile::kph && paceZoneRange != -1) paceTimeInZone[context->athlete->paceZones()->whichZone(paceZoneRange, dp->value(series))] += ride->recIntSecs(); + // Polarized zones :- I(<0.9*CV), II (0.9*CV), III (>CV) + if (series == RideFile::kph && paceZoneRange != -1 && CV) { + if (dp->value(series) < 1) // I zero + paceCPTimeInZone[0] += ride->recIntSecs(); + if (dp->value(series) < (CV*0.9f)) // I + paceCPTimeInZone[1] += ride->recIntSecs(); + else if (dp->value(series) < CV) // II + paceCPTimeInZone[2] += ride->recIntSecs(); + else // III + paceCPTimeInZone[3] += ride->recIntSecs(); + } + int offset = lvalue - min; if (offset >= 0 && offset < array.size()) array[offset] += ride->recIntSecs(); } @@ -1372,7 +1404,9 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt wattsTimeInZone.resize(10); wattsCPTimeInZone.resize(4); hrTimeInZone.resize(10); + hrCPTimeInZone.resize(4); paceTimeInZone.resize(10); + paceCPTimeInZone.resize(4); // set cursor busy whilst we aggregate -- bit of feedback // and less intrusive than a popup box @@ -1425,7 +1459,11 @@ RideFileCache::RideFileCache(Context *context, QDate start, QDate end, bool filt paceTimeInZone[i] += rideCache.paceTimeInZone[i]; hrTimeInZone[i] += rideCache.hrTimeInZone[i]; wattsTimeInZone[i] += rideCache.wattsTimeInZone[i]; - if (i<4) wattsCPTimeInZone[i] += rideCache.wattsCPTimeInZone[i]; + if (i<4) { + paceCPTimeInZone[i] += rideCache.paceCPTimeInZone[i]; + hrCPTimeInZone[i] += rideCache.hrCPTimeInZone[i]; + wattsCPTimeInZone[i] += rideCache.wattsCPTimeInZone[i]; + } } } } @@ -1496,6 +1534,7 @@ RideFileCache::serialize(QDataStream *out) head.crc = crc; head.CP = CP; head.LTHR = LTHR; + head.CV = CV; head.wattsMeanMaxCount = wattsMeanMax.size(); head.hrMeanMaxCount = hrMeanMax.size(); @@ -1558,7 +1597,9 @@ RideFileCache::serialize(QDataStream *out) out->writeRawData((const char *) wattsTimeInZone.data(), sizeof(float) * wattsTimeInZone.size()); out->writeRawData((const char *) wattsCPTimeInZone.data(), sizeof(float) * wattsCPTimeInZone.size()); out->writeRawData((const char *) hrTimeInZone.data(), sizeof(float) * hrTimeInZone.size()); + out->writeRawData((const char *) hrCPTimeInZone.data(), sizeof(float) * hrCPTimeInZone.size()); out->writeRawData((const char *) paceTimeInZone.data(), sizeof(float) * paceTimeInZone.size()); + out->writeRawData((const char *) paceCPTimeInZone.data(), sizeof(float) * paceCPTimeInZone.size()); } void @@ -1634,7 +1675,9 @@ RideFileCache::readCache() inFile.readRawData((char *) wattsTimeInZone.data(), sizeof(float) * 10); inFile.readRawData((char *) wattsCPTimeInZone.data(), sizeof(float) * 4); inFile.readRawData((char *) hrTimeInZone.data(), sizeof(float) * 10); + inFile.readRawData((char *) hrCPTimeInZone.data(), sizeof(float) * 4); inFile.readRawData((char *) paceTimeInZone.data(), sizeof(float) * 10); + inFile.readRawData((char *) paceCPTimeInZone.data(), sizeof(float) * 4); // setup the doubles the users use doubleArray(wattsMeanMaxDouble, wattsMeanMax, RideFile::watts); diff --git a/src/RideFileCache.h b/src/RideFileCache.h index ffe0a5528..14a937f40 100644 --- a/src/RideFileCache.h +++ b/src/RideFileCache.h @@ -40,7 +40,7 @@ typedef double data_t; // arrays when plotting CP curves and histograms. It is precoputed // to save time and cached in a file .cpx // -static const unsigned int RideFileCacheVersion = 19; +static const unsigned int RideFileCacheVersion = 20; // revision history: // version date description // 1 29-Apr-11 Initial - header, mean-max & distribution data blocks @@ -61,6 +61,7 @@ static const unsigned int RideFileCacheVersion = 19; // 17 09-Jun-14 Move wpk meanmax array next to watts for fast read // 18 19-Oct-14 Added gearRatio distribution // 19 11-Nov-14 Added Pace Zones distribution +// 20 17-Nov-14 Added Polarized Zones for HR and Pace // The cache file (.cpx) has a binary format: // 1 x Header data - describing the version and contents of the cache @@ -105,6 +106,7 @@ struct RideFileCacheHeader { int LTHR, // used to calculate Time in Zone (TIZ) CP; // used to calculate Time in Zone (TIZ) + double CV; // used to calculate Time in Zone (TIZ) }; @@ -177,9 +179,11 @@ class RideFileCache QVector &meanMaxDates(RideFile::SeriesType series); // the dates of the bests QVector &distributionArray(RideFile::SeriesType); // return distribution array for the given series QVector &wattsZoneArray() { return wattsTimeInZone; } - QVector &wattsCPZoneArray() { return wattsCPTimeInZone; } // moderate, heavy and severe domains + QVector &wattsCPZoneArray() { return wattsCPTimeInZone; } // Polarized Zones QVector &hrZoneArray() { return hrTimeInZone; } + QVector &hrCPZoneArray() { return hrCPTimeInZone; } // Polarized Zones QVector &paceZoneArray() { return paceTimeInZone; } + QVector &paceCPZoneArray() { return paceCPTimeInZone; } // Polarized Zones QVector &heatMeanMaxArray(); // will compute if neccessary @@ -215,6 +219,7 @@ class RideFileCache // used for zoning int CP; int LTHR; + double CV; // // MEAN MAXIMAL VALUES @@ -307,9 +312,11 @@ class RideFileCache QVector wattsTimeInZone; // time in zone in seconds - QVector wattsCPTimeInZone; // time in zone in seconds for moderate, heavy and severe domains + QVector wattsCPTimeInZone; // time in zone in seconds for polarized zones QVector hrTimeInZone; // time in zone in seconds + QVector hrCPTimeInZone; // time in zone in seconds for polarized zones QVector paceTimeInZone; // time in zone in seconds + QVector paceCPTimeInZone; // time in zone in seconds for polarized zones }; // Working structured inherited from CPPlot.cpp