diff --git a/src/AllPlot.cpp b/src/AllPlot.cpp index 20153f28c..f46a221ae 100644 --- a/src/AllPlot.cpp +++ b/src/AllPlot.cpp @@ -3480,7 +3480,7 @@ AllPlot::setDataFromPlot(AllPlot *plot) if (scope == RideFile::wprime) sd->setFactor(0.001f); // Kj if (scope == RideFile::thb || scope == RideFile::smo2 || scope == RideFile::o2hb || scope == RideFile::hhb) // Hb - sd->setDecimals(1); + sd->setDecimals(2); setAxisScaleDraw(QwtPlot::yLeft, sd); diff --git a/src/HistogramWindow.cpp b/src/HistogramWindow.cpp index 970fc8c8d..7603bab0b 100644 --- a/src/HistogramWindow.cpp +++ b/src/HistogramWindow.cpp @@ -835,7 +835,8 @@ void HistogramWindow::addSeries() << RideFile::cad << RideFile::nm << RideFile::aPower - << RideFile::gear; + << RideFile::gear + << RideFile::smo2; foreach (RideFile::SeriesType x, seriesList) seriesCombo->addItem(RideFile::seriesName(x), static_cast(x)); diff --git a/src/PowerHist.cpp b/src/PowerHist.cpp index 32ce67d3b..3516e8d22 100644 --- a/src/PowerHist.cpp +++ b/src/PowerHist.cpp @@ -161,6 +161,10 @@ PowerHist::configChanged() pen.setColor(GColor(CCADENCE).darker(200)); brush_color = GColor(CCADENCE); break; + case RideFile::smo2: + pen.setColor(GColor(CSMO2).darker(200)); + brush_color = GColor(CSMO2); + break; case RideFile::gear: pen.setColor(GColor(CGEAR).darker(200)); brush_color = GColor(CGEAR); @@ -478,6 +482,11 @@ PowerHist::recalcCompare() } + } else if (series == RideFile::smo2) { + + array = &cid.smo2Array; + arrayLength = cid.smo2Array.size(); + } else if (series == RideFile::gear) { array = &cid.gearArray; @@ -1053,6 +1062,11 @@ PowerHist::binData(HistData &standard, QVector&x, // x-axis for data selectedArray = &standard.paceZoneSelectedArray; } + } else if (series == RideFile::smo2) { + array = &standard.smo2Array; + arrayLength = standard.smo2Array.size(); + selectedArray = &standard.smo2SelectedArray; + } else if (series == RideFile::gear) { array = &standard.gearArray; arrayLength = standard.gearArray.size(); @@ -1255,6 +1269,7 @@ PowerHist::setData(RideFileCache *cache) standard.paceZoneArray.resize(10); standard.paceCPZoneArray.resize(3); standard.gearArray.resize(0); + standard.smo2Array.resize(0); standard.cadArray.resize(0); // we do not use the selected array since it is @@ -1269,6 +1284,7 @@ PowerHist::setData(RideFileCache *cache) standard.hrZoneSelectedArray.resize(0); standard.kphSelectedArray.resize(0); standard.gearSelectedArray.resize(0); + standard.smo2SelectedArray.resize(0); standard.cadSelectedArray.resize(0); longFromDouble(standard.wattsArray, cache->distributionArray(RideFile::watts)); @@ -1278,6 +1294,7 @@ PowerHist::setData(RideFileCache *cache) longFromDouble(standard.nmArray, cache->distributionArray(RideFile::nm)); longFromDouble(standard.cadArray, cache->distributionArray(RideFile::cad)); longFromDouble(standard.gearArray, cache->distributionArray(RideFile::gear)); + longFromDouble(standard.smo2Array, cache->distributionArray(RideFile::smo2)); longFromDouble(standard.kphArray, cache->distributionArray(RideFile::kph)); if (!context->athlete->useMetricUnits) { @@ -1397,6 +1414,7 @@ PowerHist::setDataFromCompare() add.paceZoneArray.resize(10); add.paceCPZoneArray.resize(3); add.gearArray.resize(0); + add.smo2Array.resize(0); add.cadArray.resize(0); longFromDouble(add.wattsArray, s->distributionArray(RideFile::watts)); @@ -1405,6 +1423,7 @@ PowerHist::setDataFromCompare() longFromDouble(add.hrArray, s->distributionArray(RideFile::hr)); longFromDouble(add.nmArray, s->distributionArray(RideFile::nm)); longFromDouble(add.gearArray, s->distributionArray(RideFile::gear)); + longFromDouble(add.smo2Array, s->distributionArray(RideFile::smo2)); longFromDouble(add.cadArray, s->distributionArray(RideFile::cad)); longFromDouble(add.kphArray, s->distributionArray(RideFile::kph)); @@ -1746,6 +1765,7 @@ PowerHist::setData(RideItem *_rideItem, bool force) (series == RideFile::nm && ride->areDataPresent()->nm) || (series == RideFile::kph && ride->areDataPresent()->kph) || (series == RideFile::gear && ride->areDataPresent()->gear) || + (series == RideFile::smo2 && ride->areDataPresent()->smo2) || (series == RideFile::cad && ride->areDataPresent()->cad) || (series == RideFile::aPower && ride->areDataPresent()->apower) || (series == RideFile::hr && ride->areDataPresent()->hr); @@ -1781,6 +1801,7 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo static const double kphDelta = 0.1; static const double cadDelta = 1.0; static const double gearDelta = 0.01; //RideFileCache creates POW(10) * decimals section + static const double smo2Delta = 1; static const int maxSize = 4096; // recording interval in minutes @@ -1799,6 +1820,7 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo standard.paceZoneArray.resize(0); standard.paceCPZoneArray.resize(0); standard.gearArray.resize(0); + standard.smo2Array.resize(0); standard.cadArray.resize(0); standard.wattsSelectedArray.resize(0); @@ -1810,6 +1832,7 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo standard.hrZoneSelectedArray.resize(0); standard.kphSelectedArray.resize(0); standard.gearSelectedArray.resize(0); + standard.smo2SelectedArray.resize(0); standard.cadSelectedArray.resize(0); // unit conversion factor for imperial units for selected parameters @@ -2020,6 +2043,19 @@ PowerHist::setArraysFromRide(RideFile *ride, HistData &standard, const Zones *zo } } + int smo2Index = int(floor(p1->smo2 / smo2Delta)); + if (smo2Index >= 0 && smo2Index < maxSize) { + if (smo2Index >= standard.smo2Array.size()) + standard.smo2Array.resize(smo2Index + 1); + standard.smo2Array[smo2Index]++; + + if (selected) { + if (smo2Index >= standard.smo2SelectedArray.size()) + standard.smo2SelectedArray.resize(smo2Index + 1); + standard.smo2SelectedArray[smo2Index]++; + } + } + int gearIndex = int(floor(p1->gear / gearDelta)); if (gearIndex >= 0 && gearIndex < maxSize) { if (gearIndex >= standard.gearArray.size()) @@ -2153,6 +2189,10 @@ PowerHist::setParameterAxisTitle() axislabel = tr("Gear Ratio"); break; + case RideFile::smo2: + axislabel = tr("SmO2"); + break; + default: axislabel = QString(tr("Unknown data series")); break; diff --git a/src/PowerHist.h b/src/PowerHist.h index 11ed38cd5..917e47f27 100644 --- a/src/PowerHist.h +++ b/src/PowerHist.h @@ -100,7 +100,7 @@ class HistData // each curve needs a lot of data (!? this may need refactoring, wattsCPZoneArray, wattsKgArray, nmArray, hrArray, hrZoneArray, hrCPZoneArray, kphArray, paceZoneArray, paceCPZoneArray, - cadArray, gearArray, metricArray; + cadArray, gearArray, smo2Array, metricArray; // storage for data counts in interval selected QVector aPowerSelectedArray, wattsSelectedArray, @@ -108,7 +108,7 @@ class HistData // each curve needs a lot of data (!? this may need refactoring, wattsKgSelectedArray, nmSelectedArray, hrSelectedArray, hrZoneSelectedArray, hrCPZoneSelectedArray, kphSelectedArray, paceZoneSelectedArray, paceCPZoneSelectedArray, - cadSelectedArray, gearSelectedArray; + cadSelectedArray, smo2SelectedArray, gearSelectedArray; }; class PowerHist : public QwtPlot diff --git a/src/RideFileCache.cpp b/src/RideFileCache.cpp index b184eec62..ca2444ce9 100644 --- a/src/RideFileCache.cpp +++ b/src/RideFileCache.cpp @@ -66,6 +66,7 @@ RideFileCache::RideFileCache(Context *context, QString fileName, RideFile *passe npDistribution.resize(0); wattsKgDistribution.resize(0); aPowerDistribution.resize(0); + smo2Distribution.resize(0); // time in zone are fixed to 10 zone max wattsTimeInZone.resize(10); @@ -205,6 +206,7 @@ static long offsetForTiz(RideFileCacheHeader head, RideFile::SeriesType series) offset += head.npDistCount * sizeof(float); offset += head.wattsKgDistCount * sizeof(float); offset += head.aPowerDistCount * sizeof(float); + offset += head.smo2DistCount * sizeof(float); // 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' @@ -376,6 +378,7 @@ RideFileCache::RideFileCache(RideFile *ride) : npDistribution.resize(0); wattsKgDistribution.resize(0); aPowerDistribution.resize(0); + smo2Distribution.resize(0); // time in zone are fixed to 10 zone max wattsTimeInZone.resize(10); @@ -418,6 +421,7 @@ RideFileCache::RideFileCache(RideFile *ride) : doubleArrayForDistribution(npDistributionDouble, npDistribution); doubleArrayForDistribution(wattsKgDistributionDouble, wattsKgDistribution); doubleArrayForDistribution(aPowerDistributionDouble, aPowerDistribution); + doubleArrayForDistribution(smo2DistributionDouble, smo2Distribution); } int @@ -449,6 +453,7 @@ RideFileCache::decimalsFor(RideFile::SeriesType series) case RideFile::vam : return 0; break; case RideFile::wattsKg : return 2; break; case RideFile::aPower : return 0; break; + case RideFile::smo2 : return 0; break; case RideFile::lrbalance : return 1; break; case RideFile::wprime : return 0; break; case RideFile::none : break; @@ -637,6 +642,10 @@ RideFileCache::distributionArray(RideFile::SeriesType series) return aPowerDistributionDouble; break; + case RideFile::smo2: + return smo2DistributionDouble; + break; + case RideFile::wattsKg: return wattsKgDistributionDouble; break; @@ -748,6 +757,7 @@ void RideFileCache::RideFileCache::compute() computeDistribution(kphDistribution, RideFile::kph); computeDistribution(wattsKgDistribution, RideFile::wattsKg); computeDistribution(aPowerDistribution, RideFile::aPower); + computeDistribution(smo2Distribution, RideFile::smo2); // wait for them threads thread1.wait(); @@ -1320,6 +1330,7 @@ RideFileCache::computeDistribution(QVector &array, RideFile::SeriesType s int offset = lvalue - min; if (offset >= 0 && offset < array.size()) array[offset] += ride->recIntSecs(); } +if (series == RideFile::smo2) qDebug()<<"smo2 array="<writeRawData((const char *) &head, sizeof(head)); @@ -1593,6 +1607,7 @@ RideFileCache::serialize(QDataStream *out) out->writeRawData((const char *) npDistribution.data(), sizeof(float) * npDistribution.size()); out->writeRawData((const char *) wattsKgDistribution.data(), sizeof(float) * wattsKgDistribution.size()); out->writeRawData((const char *) aPowerDistribution.data(), sizeof(float) * aPowerDistribution.size()); + out->writeRawData((const char *) smo2Distribution.data(), sizeof(float) * smo2Distribution.size()); // time in zone out->writeRawData((const char *) wattsTimeInZone.data(), sizeof(float) * wattsTimeInZone.size()); @@ -1641,6 +1656,7 @@ RideFileCache::readCache() npDistribution.resize(head.npDistCount); wattsKgDistribution.resize(head.wattsKgDistCount); aPowerDistribution.resize(head.aPowerDistCount); + smo2Distribution.resize(head.smo2DistCount); // read in the arrays inFile.readRawData((char *) wattsMeanMax.data(), sizeof(float) * wattsMeanMax.size()); @@ -1671,6 +1687,7 @@ RideFileCache::readCache() inFile.readRawData((char *) npDistribution.data(), sizeof(float) * npDistribution.size()); inFile.readRawData((char *) wattsKgDistribution.data(), sizeof(float) * wattsKgDistribution.size()); inFile.readRawData((char *) aPowerDistribution.data(), sizeof(float) * aPowerDistribution.size()); + inFile.readRawData((char *) smo2Distribution.data(), sizeof(float) * smo2Distribution.size()); // time in zone inFile.readRawData((char *) wattsTimeInZone.data(), sizeof(float) * 10); @@ -1707,6 +1724,7 @@ RideFileCache::readCache() doubleArrayForDistribution(npDistributionDouble, npDistribution); doubleArrayForDistribution(wattsKgDistributionDouble, wattsKgDistribution); doubleArrayForDistribution(aPowerDistributionDouble, aPowerDistribution); + doubleArrayForDistribution(smo2DistributionDouble, smo2Distribution); cacheFile.close(); } diff --git a/src/RideFileCache.h b/src/RideFileCache.h index 14a937f40..c16348bbf 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 = 20; +static const unsigned int RideFileCacheVersion = 21; // revision history: // version date description // 1 29-Apr-11 Initial - header, mean-max & distribution data blocks @@ -62,6 +62,7 @@ static const unsigned int RideFileCacheVersion = 20; // 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 +// 21 27-Nov-14 Added SmO2 distribution // The cache file (.cpx) has a binary format: // 1 x Header data - describing the version and contents of the cache @@ -102,7 +103,8 @@ struct RideFileCacheHeader { xPowerDistCount, npDistCount, wattsKgDistCount, - aPowerDistCount; + aPowerDistCount, + smo2DistCount; int LTHR, // used to calculate Time in Zone (TIZ) CP; // used to calculate Time in Zone (TIZ) @@ -298,6 +300,7 @@ class RideFileCache QVector npDistribution; // RideFile::kph QVector wattsKgDistribution; // RideFile::wattsKg QVector aPowerDistribution; // RideFile::aPower + QVector smo2Distribution; // RideFile::smo2 QVector wattsDistributionDouble; // RideFile::watts QVector hrDistributionDouble; // RideFile::hr @@ -309,6 +312,7 @@ class RideFileCache QVector npDistributionDouble; // RideFile::np QVector wattsKgDistributionDouble; // RideFile::wattsKg QVector aPowerDistributionDouble; // RideFile::aPower + QVector smo2DistributionDouble; // RideFile::aPower QVector wattsTimeInZone; // time in zone in seconds