mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Add Watts/Kg in the cpx cache files and in the CP plot
modified: src/CpintPlot.cpp modified: src/CriticalPowerWindow.cpp modified: src/CriticalPowerWindow.h modified: src/HistogramWindow.cpp modified: src/RideFile.cpp modified: src/RideFile.h modified: src/RideFileCache.cpp modified: src/RideFileCache.h
This commit is contained in:
@@ -175,6 +175,13 @@ CpintPlot::setSeries(RideFile::SeriesType x)
|
||||
setAxisTitle(yLeft, tr("Skiba xPower (watts)"));
|
||||
break;
|
||||
|
||||
case RideFile::wattsKg:
|
||||
if (appsettings->value(NULL, GC_UNIT).toString() == "Metric")
|
||||
setAxisTitle(yLeft, tr("Watts per kilo (watts/kg)"));
|
||||
else
|
||||
setAxisTitle(yLeft, tr("Watts per lb (watts/lb)"));
|
||||
break;
|
||||
|
||||
case RideFile::vam:
|
||||
setAxisTitle(yLeft, tr("VAM (meters per hour)"));
|
||||
break;
|
||||
@@ -343,9 +350,17 @@ CpintPlot::plot_CP_curve(CpintPlot *thisPlot, // the plot we're currently di
|
||||
#if USE_T0_IN_CP_MODEL
|
||||
curve_title.sprintf("CP=%.1f W; AWC/CP=%.2f m; t0=%.1f s", cp, tau, 60 * t0);
|
||||
#else
|
||||
curve_title.sprintf("CP=%.0f W; AWC=%.0f kJ", cp, cp * tau * 60.0 / 1000.0);
|
||||
if (series == RideFile::wattsKg)
|
||||
curve_title.sprintf("CP=%.2f W/kg; AWC=%.2f kJ/kg", cp, cp * tau * 60.0 / 1000.0);
|
||||
else
|
||||
curve_title.sprintf("CP=%.0f W; AWC=%.0f kJ", cp, cp * tau * 60.0 / 1000.0);
|
||||
#endif
|
||||
if (series == RideFile::watts) curveTitle.setLabel(QwtText(curve_title, QwtText::PlainText));
|
||||
if (series == RideFile::watts || series == RideFile::wattsKg) curveTitle.setLabel(QwtText(curve_title, QwtText::PlainText));
|
||||
|
||||
if (series == RideFile::wattsKg)
|
||||
curveTitle.setYValue(0.6);
|
||||
else
|
||||
curveTitle.setYValue(20);
|
||||
|
||||
CPCurve = new QwtPlotCurve(curve_title);
|
||||
if (appsettings->value(this, GC_ANTIALIAS, false).toBool() == true)
|
||||
@@ -488,6 +503,8 @@ CpintPlot::plot_allCurve(CpintPlot *thisPlot,
|
||||
}
|
||||
else {
|
||||
ymax = 100 * ceil(power_values[0] / 100);
|
||||
if (ymax == 100)
|
||||
ymax = 5 * ceil(power_values[0] / 5);
|
||||
}
|
||||
thisPlot->setAxisScale(thisPlot->yLeft, 0, ymax);
|
||||
}
|
||||
@@ -512,7 +529,7 @@ CpintPlot::calculate(RideItem *rideItem)
|
||||
// PLOT MODEL CURVE (DERIVED)
|
||||
//
|
||||
curveTitle.setLabel(QwtText("", QwtText::PlainText)); // default to no title
|
||||
if (series == RideFile::xPower || series == RideFile::NP || series == RideFile::watts || series == RideFile::none) {
|
||||
if (series == RideFile::xPower || series == RideFile::NP || series == RideFile::watts || series == RideFile::wattsKg || series == RideFile::none) {
|
||||
|
||||
if (bests->meanMaxArray(series).size() > 1) {
|
||||
// calculate CP model from all-time best data
|
||||
@@ -523,7 +540,7 @@ CpintPlot::calculate(RideItem *rideItem)
|
||||
//
|
||||
// CP curve only relevant for Energy or Watts (?)
|
||||
//
|
||||
if (series == RideFile::watts || series == RideFile::none) {
|
||||
if (series == RideFile::watts || series == RideFile::wattsKg || series == RideFile::none) {
|
||||
if (!CPCurve) plot_CP_curve(this, cp, tau, t0);
|
||||
else {
|
||||
// make sure color reflects latest config
|
||||
@@ -726,7 +743,7 @@ CpintPlot::pointHover(QwtPlotCurve *curve, int index)
|
||||
// output the tooltip
|
||||
text = QString("%1\n%3 %4%5")
|
||||
.arg(interval_to_str(60.0*xvalue))
|
||||
.arg(yvalue, 0, 'f', RideFile::decimalsFor(series) ? 1 : 0)
|
||||
.arg(yvalue, 0, 'f', RideFile::decimalsFor(series))
|
||||
.arg(RideFile::unitName(series))
|
||||
.arg(dateStr);
|
||||
|
||||
|
||||
@@ -53,21 +53,28 @@ CriticalPowerWindow::CriticalPowerWindow(const QDir &home, MainWindow *parent) :
|
||||
QLabel *cpintTimeLabel = new QLabel(tr("Duration:"), this);
|
||||
cpintTimeValue = new QLineEdit("0 s");
|
||||
QLabel *cpintTodayLabel = new QLabel(tr("Today:"), this);
|
||||
cpintTodayValue = new QLineEdit(tr("no data"));
|
||||
cpintTodayValue = new QLabel(tr("no data"));
|
||||
QLabel *cpintAllLabel = new QLabel(tr("Best:"), this);
|
||||
cpintAllValue = new QLineEdit(tr("no data"));
|
||||
cpintAllValue = new QLabel(tr("no data"));
|
||||
QLabel *cpintCPLabel = new QLabel(tr("CP Curve:"), this);
|
||||
cpintCPValue = new QLineEdit(tr("no data"));
|
||||
cpintCPValue = new QLabel(tr("no data"));
|
||||
|
||||
QFontMetrics metrics(QApplication::font());
|
||||
//QFontMetrics metrics(QApplication::font());
|
||||
//int width = metrics.width("8888 watts (88/88/8888)") + 10;
|
||||
//cpintAllValue->setFixedWidth(width);
|
||||
//cpintCPValue->setFixedWidth(width); // so lines up nicely
|
||||
|
||||
cpintTimeValue->setReadOnly(false);
|
||||
cpintTodayValue->setReadOnly(true);
|
||||
cpintAllValue->setReadOnly(true);
|
||||
cpintCPValue->setReadOnly(true);
|
||||
//cpintTodayValue->setReadOnly(true);
|
||||
//cpintAllValue->setReadOnly(true);
|
||||
//cpintCPValue->setReadOnly(true);
|
||||
|
||||
QFont font = cpintTimeValue->font();
|
||||
font.setPointSize(font.pointSize());
|
||||
cpintTodayValue->setFont(font);
|
||||
cpintAllValue->setFont(font);
|
||||
cpintCPValue->setFont(font);
|
||||
|
||||
cpintPickerLayout->addRow(cpintTimeLabel, cpintTimeValue);
|
||||
cpintPickerLayout->addRow(cpintTodayLabel, cpintTodayValue);
|
||||
cpintPickerLayout->addRow(cpintAllLabel, cpintAllValue);
|
||||
@@ -166,10 +173,10 @@ CriticalPowerWindow::cpintSetCPButtonClicked()
|
||||
mainWindow->setCriticalPower(cp);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
curve_to_point(double x, const QwtPlotCurve *curve)
|
||||
static double
|
||||
curve_to_point(double x, const QwtPlotCurve *curve, RideFile::SeriesType serie)
|
||||
{
|
||||
unsigned result = 0;
|
||||
double result = 0;
|
||||
if (curve) {
|
||||
const QwtSeriesData<QPointF> *data = curve->data();
|
||||
|
||||
@@ -180,7 +187,10 @@ curve_to_point(double x, const QwtPlotCurve *curve)
|
||||
while (min < max - 1) {
|
||||
mid = (max - min) / 2 + min;
|
||||
if (x < data->sample(mid).x()) {
|
||||
result = (unsigned) round(data->sample(mid).y());
|
||||
double a = pow(10,RideFileCache::decimalsFor(serie));
|
||||
|
||||
result = ((int)((0.5/a + data->sample(mid).y()) * a))/a;
|
||||
//result = (unsigned) round(data->sample(mid).y());
|
||||
max = mid;
|
||||
}
|
||||
else {
|
||||
@@ -223,6 +233,10 @@ CriticalPowerWindow::updateCpint(double minutes)
|
||||
units = "metres/hour";
|
||||
break;
|
||||
|
||||
case RideFile::wattsKg:
|
||||
units = "Watts/kg";
|
||||
break;
|
||||
|
||||
default:
|
||||
case RideFile::watts:
|
||||
units = "Watts";
|
||||
@@ -232,18 +246,18 @@ CriticalPowerWindow::updateCpint(double minutes)
|
||||
|
||||
// current ride
|
||||
{
|
||||
unsigned value = curve_to_point(minutes, cpintPlot->getThisCurve());
|
||||
double value = curve_to_point(minutes, cpintPlot->getThisCurve(), series());
|
||||
QString label;
|
||||
if (value > 0)
|
||||
label = QString("%1 %2").arg(value).arg(units);
|
||||
label = QString("%1 %2").arg(value).arg(units);
|
||||
else
|
||||
label = tr("no data");
|
||||
label = tr("no data");
|
||||
cpintTodayValue->setText(label);
|
||||
}
|
||||
|
||||
// cp line
|
||||
if (cpintPlot->getCPCurve()) {
|
||||
unsigned value = curve_to_point(minutes, cpintPlot->getCPCurve());
|
||||
double value = curve_to_point(minutes, cpintPlot->getCPCurve(), series());
|
||||
QString label;
|
||||
if (value > 0)
|
||||
label = QString("%1 %2").arg(value).arg(units);
|
||||
@@ -258,7 +272,11 @@ CriticalPowerWindow::updateCpint(double minutes)
|
||||
int index = (int) ceil(minutes * 60);
|
||||
if (index >= 0 && cpintPlot->getBests().count() > index) {
|
||||
QDate date = cpintPlot->getBestDates()[index];
|
||||
unsigned value = cpintPlot->getBests()[index];
|
||||
double value = cpintPlot->getBests()[index];
|
||||
|
||||
double a = pow(10,RideFileCache::decimalsFor(series()));
|
||||
value = ((int)((0.5/a + value) * a))/a;
|
||||
|
||||
#if 0
|
||||
label = QString("%1 kJ (%2)").arg(watts * minutes * 60.0 / 1000.0, 0, 'f', 0);
|
||||
#endif
|
||||
@@ -290,6 +308,7 @@ void CriticalPowerWindow::addSeries()
|
||||
{
|
||||
// setup series list
|
||||
seriesList << RideFile::watts
|
||||
<< RideFile::wattsKg
|
||||
<< RideFile::xPower
|
||||
<< RideFile::NP
|
||||
<< RideFile::hr
|
||||
|
||||
@@ -86,9 +86,9 @@ class CriticalPowerWindow : public GcWindow
|
||||
CpintPlot *cpintPlot;
|
||||
MainWindow *mainWindow;
|
||||
QLineEdit *cpintTimeValue;
|
||||
QLineEdit *cpintTodayValue;
|
||||
QLineEdit *cpintAllValue;
|
||||
QLineEdit *cpintCPValue;
|
||||
QLabel *cpintTodayValue;
|
||||
QLabel *cpintAllValue;
|
||||
QLabel *cpintCPValue;
|
||||
QComboBox *seriesCombo;
|
||||
QComboBox *cComboSeason;
|
||||
QPushButton *cpintSetCPButton;
|
||||
|
||||
@@ -213,6 +213,7 @@ void HistogramWindow::addSeries()
|
||||
{
|
||||
// setup series list
|
||||
seriesList << RideFile::watts
|
||||
<< RideFile::wattsKg
|
||||
<< RideFile::hr
|
||||
<< RideFile::kph
|
||||
<< RideFile::cad
|
||||
|
||||
@@ -77,6 +77,7 @@ RideFile::seriesName(SeriesType series)
|
||||
case RideFile::temp: return QString(tr("Temperature"));
|
||||
case RideFile::interval: return QString(tr("Interval"));
|
||||
case RideFile::vam: return QString(tr("VAM"));
|
||||
case RideFile::wattsKg: return QString(tr("Power/Weight"));
|
||||
default: return QString(tr("Unknown"));
|
||||
}
|
||||
}
|
||||
@@ -104,6 +105,7 @@ RideFile::unitName(SeriesType series)
|
||||
case RideFile::temp: return QString(tr("°C"));
|
||||
case RideFile::interval: return QString(tr("Interval"));
|
||||
case RideFile::vam: return QString(tr("meters per hour"));
|
||||
case RideFile::wattsKg: return QString(useMetricUnits ? tr("watts/kg") : tr("watts/lb"));
|
||||
default: return QString(tr("Unknown"));
|
||||
}
|
||||
}
|
||||
@@ -272,6 +274,7 @@ RideFile *RideFileFactory::openRideFile(MainWindow *main, QFile &file,
|
||||
|
||||
// NULL returned to indicate openRide failed
|
||||
if (result) {
|
||||
result->mainwindow = main;
|
||||
if (result->intervals().empty()) result->fillInIntervals();
|
||||
|
||||
|
||||
@@ -493,6 +496,7 @@ RideFilePoint::value(RideFile::SeriesType series) const
|
||||
case RideFile::slope : return slope; break;
|
||||
case RideFile::temp : return temp; break;
|
||||
case RideFile::interval : return interval; break;
|
||||
|
||||
default:
|
||||
case RideFile::none : break;
|
||||
}
|
||||
@@ -502,6 +506,8 @@ RideFilePoint::value(RideFile::SeriesType series) const
|
||||
double
|
||||
RideFile::getPointValue(int index, SeriesType series) const
|
||||
{
|
||||
if (series == wattsKg)
|
||||
qDebug() << "wattsKg value";
|
||||
return dataPoints_[index]->value(series);
|
||||
}
|
||||
|
||||
@@ -511,6 +517,8 @@ RideFile::getPoint(int index, SeriesType series) const
|
||||
double value = getPointValue(index, series);
|
||||
if (series==RideFile::temp && value == RideFile::noTemp)
|
||||
return "";
|
||||
else if (series==RideFile::wattsKg)
|
||||
return "";
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -535,6 +543,7 @@ RideFile::decimalsFor(SeriesType series)
|
||||
case temp : return 1; break;
|
||||
case interval : return 0; break;
|
||||
case vam : return 0; break;
|
||||
case wattsKg : return 2; break;
|
||||
case none : break;
|
||||
}
|
||||
return 2; // default
|
||||
@@ -561,6 +570,7 @@ RideFile::maximumFor(SeriesType series)
|
||||
case temp : return 100; break;
|
||||
case interval : return 999; break;
|
||||
case vam : return 9999; break;
|
||||
case wattsKg : return 50; break;
|
||||
case none : break;
|
||||
}
|
||||
return 9999; // default
|
||||
@@ -587,6 +597,7 @@ RideFile::minimumFor(SeriesType series)
|
||||
case temp : return -100; break;
|
||||
case interval : return 0; break;
|
||||
case vam : return 0; break;
|
||||
case wattsKg : return 0; break;
|
||||
case none : break;
|
||||
}
|
||||
return 0; // default
|
||||
@@ -635,3 +646,23 @@ RideFile::emitModified()
|
||||
{
|
||||
emit modified();
|
||||
}
|
||||
|
||||
double
|
||||
RideFile::getWeight()
|
||||
{
|
||||
// ride
|
||||
double weight;
|
||||
if ((weight = getTag("Weight", "0.0").toDouble()) > 0) {
|
||||
return weight;
|
||||
}
|
||||
#if 0
|
||||
// withings?
|
||||
QList<SummaryMetrics> measures = main->metricDB->getAllMeasuresFor(QDateTime::fromString("Jan 1 00:00:00 1900"), ride->startTime());
|
||||
if (measures.count()) {
|
||||
return measures.last().getText("Weight", "0.0").toDouble();
|
||||
}
|
||||
#endif
|
||||
|
||||
// global options
|
||||
return appsettings->cvalue(mainwindow->cyclist, GC_WEIGHT, "75.0").toString().toDouble(); // default to 75kg
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class RideFile : public QObject // QObject to emit signals
|
||||
virtual ~RideFile();
|
||||
|
||||
// Working with DATASERIES
|
||||
enum seriestype { secs, cad, hr, km, kph, nm, watts, alt, lon, lat, headwind, slope, temp, interval, NP, xPower, vam, none };
|
||||
enum seriestype { secs, cad, hr, km, kph, nm, watts, alt, lon, lat, headwind, slope, temp, interval, NP, xPower, vam, wattsKg, none };
|
||||
enum specialValues { noTemp = -255 };
|
||||
|
||||
typedef enum seriestype SeriesType;
|
||||
@@ -146,6 +146,9 @@ class RideFile : public QObject // QObject to emit signals
|
||||
QString getTag(QString name, QString fallback) const { return tags_.value(name, fallback); }
|
||||
void setTag(QString name, QString value) { tags_.insert(name, value); }
|
||||
|
||||
const MainWindow *mainwindow;
|
||||
double getWeight();
|
||||
|
||||
// METRIC OVERRIDES
|
||||
QMap<QString,QMap<QString,QString> > metricOverrides;
|
||||
|
||||
@@ -191,7 +194,6 @@ class RideFile : public QObject // QObject to emit signals
|
||||
QList<RideFileInterval> intervals_;
|
||||
QMap<QString,QString> tags_;
|
||||
EditorData *data;
|
||||
|
||||
};
|
||||
|
||||
struct RideFilePoint
|
||||
|
||||
@@ -40,6 +40,7 @@ RideFileCache::RideFileCache(MainWindow *main, QString fileName, RideFile *passe
|
||||
xPowerMeanMax.resize(0);
|
||||
npMeanMax.resize(0);
|
||||
vamMeanMax.resize(0);
|
||||
wattsKgMeanMax.resize(0);
|
||||
wattsDistribution.resize(0);
|
||||
hrDistribution.resize(0);
|
||||
cadDistribution.resize(0);
|
||||
@@ -47,6 +48,7 @@ RideFileCache::RideFileCache(MainWindow *main, QString fileName, RideFile *passe
|
||||
kphDistribution.resize(0);
|
||||
xPowerDistribution.resize(0);
|
||||
npDistribution.resize(0);
|
||||
wattsKgDistribution.resize(0);
|
||||
|
||||
// time in zone are fixed to 10 zone max
|
||||
wattsTimeInZone.resize(10);
|
||||
@@ -108,6 +110,31 @@ RideFileCache::RideFileCache(MainWindow *main, QString fileName, RideFile *passe
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
RideFileCache::decimalsFor(RideFile::SeriesType series)
|
||||
{
|
||||
switch (series) {
|
||||
case RideFile::cad : return 0; break;
|
||||
case RideFile::hr : return 0; break;
|
||||
case RideFile::kph : return 1; break;
|
||||
case RideFile::nm : return 2; break;
|
||||
case RideFile::watts : return 0; break;
|
||||
case RideFile::xPower : return 0; break;
|
||||
case RideFile::NP : return 0; break;
|
||||
case RideFile::alt : return 1; break;
|
||||
case RideFile::lon : return 6; break;
|
||||
case RideFile::lat : return 6; break;
|
||||
case RideFile::headwind : return 1; break;
|
||||
case RideFile::slope : return 1; break;
|
||||
case RideFile::temp : return 1; break;
|
||||
case RideFile::interval : return 0; break;
|
||||
case RideFile::vam : return 0; break;
|
||||
case RideFile::wattsKg : return 2; break;
|
||||
case RideFile::none : break;
|
||||
}
|
||||
return 2; // default
|
||||
}
|
||||
|
||||
//
|
||||
// DATA ACCESS
|
||||
//
|
||||
@@ -148,6 +175,10 @@ RideFileCache::meanMaxDates(RideFile::SeriesType series)
|
||||
return vamMeanMaxDate;
|
||||
break;
|
||||
|
||||
case RideFile::wattsKg:
|
||||
return wattsKgMeanMaxDate;
|
||||
break;
|
||||
|
||||
default:
|
||||
//? dunno give em power anyway
|
||||
return wattsMeanMaxDate;
|
||||
@@ -192,6 +223,10 @@ RideFileCache::meanMaxArray(RideFile::SeriesType series)
|
||||
return vamMeanMaxDouble;
|
||||
break;
|
||||
|
||||
case RideFile::wattsKg:
|
||||
return wattsKgMeanMaxDouble;
|
||||
break;
|
||||
|
||||
default:
|
||||
//? dunno give em power anyway
|
||||
return wattsMeanMaxDouble;
|
||||
@@ -224,6 +259,10 @@ RideFileCache::distributionArray(RideFile::SeriesType series)
|
||||
return kphDistributionDouble;
|
||||
break;
|
||||
|
||||
case RideFile::wattsKg:
|
||||
return wattsKgDistributionDouble;
|
||||
break;
|
||||
|
||||
default:
|
||||
//? dunno give em power anyway
|
||||
return wattsMeanMaxDouble;
|
||||
@@ -293,6 +332,7 @@ void RideFileCache::RideFileCache::compute()
|
||||
MeanMaxComputer thread6(ride, xPowerMeanMax, RideFile::xPower); thread6.start();
|
||||
MeanMaxComputer thread7(ride, npMeanMax, RideFile::NP); thread7.start();
|
||||
MeanMaxComputer thread8(ride, vamMeanMax, RideFile::vam); thread8.start();
|
||||
MeanMaxComputer thread9(ride, wattsKgMeanMax, RideFile::wattsKg); thread9.start();
|
||||
|
||||
// all the different distributions
|
||||
computeDistribution(wattsDistribution, RideFile::watts);
|
||||
@@ -300,6 +340,7 @@ void RideFileCache::RideFileCache::compute()
|
||||
computeDistribution(cadDistribution, RideFile::cad);
|
||||
computeDistribution(nmDistribution, RideFile::nm);
|
||||
computeDistribution(kphDistribution, RideFile::kph);
|
||||
computeDistribution(wattsKgDistribution, RideFile::wattsKg);
|
||||
|
||||
// wait for them threads
|
||||
thread1.wait();
|
||||
@@ -310,6 +351,7 @@ void RideFileCache::RideFileCache::compute()
|
||||
thread6.wait();
|
||||
thread7.wait();
|
||||
thread8.wait();
|
||||
thread9.wait();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -533,7 +575,7 @@ void
|
||||
MeanMaxComputer::run()
|
||||
{
|
||||
// xPower and NP need watts to be present
|
||||
RideFile::SeriesType baseSeries = (series == RideFile::xPower || series == RideFile::NP) ?
|
||||
RideFile::SeriesType baseSeries = (series == RideFile::xPower || series == RideFile::NP || series == RideFile::wattsKg) ?
|
||||
RideFile::watts : series;
|
||||
|
||||
if (series == RideFile::vam) baseSeries = RideFile::alt;
|
||||
@@ -546,7 +588,8 @@ MeanMaxComputer::run()
|
||||
// convert from high-precision double to long
|
||||
// e.g. 145.456 becomes 1455 if we want decimals
|
||||
// and becomes 145 if we don't
|
||||
double decimals = RideFile::decimalsFor(baseSeries) ? 10 : 1;
|
||||
double decimals = pow(10, RideFileCache::decimalsFor(series));
|
||||
//double decimals = RideFile::decimalsFor(baseSeries) ? 10 : 1;
|
||||
|
||||
// decritize the data series - seems wrong, since it just
|
||||
// rounds to the nearest second - what if the recIntSecs
|
||||
@@ -692,6 +735,13 @@ MeanMaxComputer::run()
|
||||
}
|
||||
}
|
||||
|
||||
if (series == RideFile::wattsKg) {
|
||||
for (int i=0; i<data.points.size(); i++) {
|
||||
double wattsKg = data.points[i].value / ride->getWeight();
|
||||
data.points[i].value = wattsKg;
|
||||
}
|
||||
}
|
||||
|
||||
// the bests go in here...
|
||||
QVector <double> ride_bests(total_secs + 1);
|
||||
|
||||
@@ -741,8 +791,11 @@ MeanMaxComputer::run()
|
||||
void
|
||||
RideFileCache::computeDistribution(QVector<float> &array, RideFile::SeriesType series)
|
||||
{
|
||||
RideFile::SeriesType baseSeries = (series == RideFile::wattsKg) ?
|
||||
RideFile::watts : series;
|
||||
|
||||
// only bother if the data series is actually present
|
||||
if (ride->isDataPresent(series) == false) return;
|
||||
if (ride->isDataPresent(baseSeries) == false) return;
|
||||
|
||||
// get zones that apply, if any
|
||||
int zoneRange = main->zones() ? main->zones()->whichRange(ride->startTime().date()) : -1;
|
||||
@@ -755,7 +808,7 @@ RideFileCache::computeDistribution(QVector<float> &array, RideFile::SeriesType s
|
||||
else LTHR=0;
|
||||
|
||||
// setup the array based upon the ride
|
||||
int decimals = RideFile::decimalsFor(series) ? 1 : 0;
|
||||
int decimals = decimalsFor(series); //RideFile::decimalsFor(series) ? 1 : 0;
|
||||
double min = RideFile::minimumFor(series) * pow(10, decimals);
|
||||
double max = RideFile::maximumFor(series) * pow(10, decimals);
|
||||
|
||||
@@ -830,6 +883,7 @@ RideFileCache::RideFileCache(MainWindow *main, QDate start, QDate end)
|
||||
xPowerMeanMax.resize(0);
|
||||
npMeanMax.resize(0);
|
||||
vamMeanMax.resize(0);
|
||||
wattsKgMeanMax.resize(0);
|
||||
wattsDistribution.resize(0);
|
||||
hrDistribution.resize(0);
|
||||
cadDistribution.resize(0);
|
||||
@@ -837,6 +891,7 @@ RideFileCache::RideFileCache(MainWindow *main, QDate start, QDate end)
|
||||
kphDistribution.resize(0);
|
||||
xPowerDistribution.resize(0);
|
||||
npDistribution.resize(0);
|
||||
wattsKgDistribution.resize(0);
|
||||
|
||||
// time in zone are fixed to 10 zone max
|
||||
wattsTimeInZone.resize(10);
|
||||
@@ -863,6 +918,7 @@ RideFileCache::RideFileCache(MainWindow *main, QDate start, QDate end)
|
||||
meanMaxAggregate(xPowerMeanMaxDouble, rideCache.xPowerMeanMaxDouble, xPowerMeanMaxDate, rideDate);
|
||||
meanMaxAggregate(npMeanMaxDouble, rideCache.npMeanMaxDouble, npMeanMaxDate, rideDate);
|
||||
meanMaxAggregate(vamMeanMaxDouble, rideCache.vamMeanMaxDouble, vamMeanMaxDate, rideDate);
|
||||
meanMaxAggregate(wattsKgMeanMaxDouble, rideCache.wattsKgMeanMaxDouble, wattsKgMeanMaxDate, rideDate);
|
||||
|
||||
distAggregate(wattsDistributionDouble, rideCache.wattsDistributionDouble);
|
||||
distAggregate(hrDistributionDouble, rideCache.hrDistributionDouble);
|
||||
@@ -871,6 +927,7 @@ RideFileCache::RideFileCache(MainWindow *main, QDate start, QDate end)
|
||||
distAggregate(kphDistributionDouble, rideCache.kphDistributionDouble);
|
||||
distAggregate(xPowerDistributionDouble, rideCache.xPowerDistributionDouble);
|
||||
distAggregate(npDistributionDouble, rideCache.npDistributionDouble);
|
||||
distAggregate(wattsKgDistributionDouble, rideCache.wattsKgDistributionDouble);
|
||||
|
||||
// cumulate timeinzones
|
||||
for (int i=0; i<10; i++) {
|
||||
@@ -905,6 +962,7 @@ RideFileCache::serialize(QDataStream *out)
|
||||
head.xPowerMeanMaxCount = xPowerMeanMax.size();
|
||||
head.npMeanMaxCount = npMeanMax.size();
|
||||
head.vamMeanMaxCount = vamMeanMax.size();
|
||||
head.wattsKgMeanMaxCount = wattsKgMeanMax.size();
|
||||
|
||||
head.wattsDistCount = wattsDistribution.size();
|
||||
head.xPowerDistCount = xPowerDistribution.size();
|
||||
@@ -913,6 +971,8 @@ RideFileCache::serialize(QDataStream *out)
|
||||
head.cadDistCount = cadDistribution.size();
|
||||
head.nmDistrCount = nmDistribution.size();
|
||||
head.kphDistCount = kphDistribution.size();
|
||||
head.wattsKgDistCount = wattsKgDistribution.size();
|
||||
|
||||
out->writeRawData((const char *) &head, sizeof(head));
|
||||
|
||||
// write meanmax
|
||||
@@ -924,6 +984,7 @@ RideFileCache::serialize(QDataStream *out)
|
||||
out->writeRawData((const char *) xPowerMeanMax.data(), sizeof(float) * xPowerMeanMax.size());
|
||||
out->writeRawData((const char *) npMeanMax.data(), sizeof(float) * npMeanMax.size());
|
||||
out->writeRawData((const char *) vamMeanMax.data(), sizeof(float) * vamMeanMax.size());
|
||||
out->writeRawData((const char *) wattsKgMeanMax.data(), sizeof(float) * wattsKgMeanMax.size());
|
||||
|
||||
// write dist
|
||||
out->writeRawData((const char *) wattsDistribution.data(), sizeof(float) * wattsDistribution.size());
|
||||
@@ -933,6 +994,7 @@ RideFileCache::serialize(QDataStream *out)
|
||||
out->writeRawData((const char *) kphDistribution.data(), sizeof(float) * kphDistribution.size());
|
||||
out->writeRawData((const char *) xPowerDistribution.data(), sizeof(float) * xPowerDistribution.size());
|
||||
out->writeRawData((const char *) npDistribution.data(), sizeof(float) * npDistribution.size());
|
||||
out->writeRawData((const char *) wattsKgDistribution.data(), sizeof(float) * wattsKgDistribution.size());
|
||||
|
||||
// time in zone
|
||||
out->writeRawData((const char *) wattsTimeInZone.data(), sizeof(float) * wattsTimeInZone.size());
|
||||
@@ -959,6 +1021,8 @@ RideFileCache::readCache()
|
||||
npMeanMax.resize(head.npMeanMaxCount);
|
||||
vamMeanMax.resize(head.vamMeanMaxCount);
|
||||
xPowerMeanMax.resize(head.xPowerMeanMaxCount);
|
||||
wattsKgMeanMax.resize(head.wattsKgMeanMaxCount);
|
||||
|
||||
wattsDistribution.resize(head.wattsDistCount);
|
||||
hrDistribution.resize(head.hrDistCount);
|
||||
cadDistribution.resize(head.cadDistCount);
|
||||
@@ -966,6 +1030,7 @@ RideFileCache::readCache()
|
||||
kphDistribution.resize(head.kphDistCount);
|
||||
xPowerDistribution.resize(head.xPowerDistCount);
|
||||
npDistribution.resize(head.npDistCount);
|
||||
wattsKgDistribution.resize(head.wattsKgDistCount);
|
||||
|
||||
// read in the arrays
|
||||
inFile.readRawData((char *) wattsMeanMax.data(), sizeof(float) * wattsMeanMax.size());
|
||||
@@ -976,6 +1041,7 @@ RideFileCache::readCache()
|
||||
inFile.readRawData((char *) xPowerMeanMax.data(), sizeof(float) * xPowerMeanMax.size());
|
||||
inFile.readRawData((char *) npMeanMax.data(), sizeof(float) * npMeanMax.size());
|
||||
inFile.readRawData((char *) vamMeanMax.data(), sizeof(float) * vamMeanMax.size());
|
||||
inFile.readRawData((char *) wattsKgMeanMax.data(), sizeof(float) * wattsKgMeanMax.size());
|
||||
|
||||
|
||||
// write dist
|
||||
@@ -986,6 +1052,7 @@ RideFileCache::readCache()
|
||||
inFile.readRawData((char *) kphDistribution.data(), sizeof(float) * kphDistribution.size());
|
||||
inFile.readRawData((char *) xPowerDistribution.data(), sizeof(float) * xPowerDistribution.size());
|
||||
inFile.readRawData((char *) npDistribution.data(), sizeof(float) * npDistribution.size());
|
||||
inFile.readRawData((char *) wattsKgDistribution.data(), sizeof(float) * wattsKgDistribution.size());
|
||||
|
||||
// time in zone
|
||||
inFile.readRawData((char *) wattsTimeInZone.data(), sizeof(float) * 10);
|
||||
@@ -1000,6 +1067,8 @@ RideFileCache::readCache()
|
||||
doubleArray(npMeanMaxDouble, npMeanMax, RideFile::NP);
|
||||
doubleArray(vamMeanMaxDouble, vamMeanMax, RideFile::vam);
|
||||
doubleArray(xPowerMeanMaxDouble, xPowerMeanMax, RideFile::xPower);
|
||||
doubleArray(wattsKgMeanMaxDouble, wattsKgMeanMax, RideFile::wattsKg);
|
||||
|
||||
doubleArray(wattsDistributionDouble, wattsDistribution, RideFile::watts);
|
||||
doubleArray(hrDistributionDouble, hrDistribution, RideFile::hr);
|
||||
doubleArray(cadDistributionDouble, cadDistribution, RideFile::cad);
|
||||
@@ -1007,6 +1076,7 @@ RideFileCache::readCache()
|
||||
doubleArray(kphDistributionDouble, kphDistribution, RideFile::kph);
|
||||
doubleArray(xPowerDistributionDouble, xPowerDistribution, RideFile::xPower);
|
||||
doubleArray(npDistributionDouble, npDistribution, RideFile::NP);
|
||||
doubleArray(wattsKgDistributionDouble, wattsKgDistribution, RideFile::wattsKg);
|
||||
|
||||
cacheFile.close();
|
||||
}
|
||||
@@ -1015,7 +1085,7 @@ RideFileCache::readCache()
|
||||
// unpack the longs into a double array
|
||||
void RideFileCache::doubleArray(QVector<double> &into, QVector<float> &from, RideFile::SeriesType series)
|
||||
{
|
||||
double divisor = RideFile::decimalsFor(series) ? 10 : 1;
|
||||
double divisor = pow(10, decimalsFor(series)); // ? 10 : 1;
|
||||
into.resize(from.size());
|
||||
for(int i=0; i<from.size(); i++) into[i] = from[i] / divisor;
|
||||
|
||||
|
||||
@@ -38,7 +38,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 = 5;
|
||||
static const unsigned int RideFileCacheVersion = 6;
|
||||
// revision history:
|
||||
// version date description
|
||||
// 1 29-Apr-11 Initial - header, mean-max & distribution data blocks
|
||||
@@ -46,6 +46,7 @@ static const unsigned int RideFileCacheVersion = 5;
|
||||
// 3 02-May-11 Moved to float precision not integer.
|
||||
// 4 02-May-11 Moved to Mark Rages mean-max function with higher precision
|
||||
// 5 18-Aug-11 Added VAM mean maximals
|
||||
// 6 27-Jun-12 Added W/kg mean maximals and distribution
|
||||
|
||||
// The cache file (.cpx) has a binary format:
|
||||
// 1 x Header data - describing the version and contents of the cache
|
||||
@@ -69,13 +70,15 @@ struct RideFileCacheHeader {
|
||||
xPowerMeanMaxCount,
|
||||
npMeanMaxCount,
|
||||
vamMeanMaxCount,
|
||||
wattsKgMeanMaxCount,
|
||||
wattsDistCount,
|
||||
hrDistCount,
|
||||
cadDistCount,
|
||||
nmDistrCount,
|
||||
kphDistCount,
|
||||
xPowerDistCount,
|
||||
npDistCount;
|
||||
npDistCount,
|
||||
wattsKgDistCount;
|
||||
|
||||
int LTHR, // used to calculate Time in Zone (TIZ)
|
||||
CP; // used to calculate Time in Zone (TIZ)
|
||||
@@ -120,6 +123,8 @@ class RideFileCache
|
||||
// across a date range. This is used to provide aggregated data.
|
||||
RideFileCache(MainWindow *main, QDate start, QDate end);
|
||||
|
||||
static int decimalsFor(RideFile::SeriesType series);
|
||||
|
||||
// get data
|
||||
QVector<double> &meanMaxArray(RideFile::SeriesType); // return meanmax array for the given series
|
||||
QVector<QDate> &meanMaxDates(RideFile::SeriesType series); // the dates of the bests
|
||||
@@ -172,6 +177,8 @@ class RideFileCache
|
||||
QVector<float> xPowerMeanMax; // RideFile::kph
|
||||
QVector<float> npMeanMax; // RideFile::kph
|
||||
QVector<float> vamMeanMax; // RideFile::vam
|
||||
QVector<float> wattsKgMeanMax; // watts/kg
|
||||
|
||||
QVector<double> wattsMeanMaxDouble; // RideFile::watts
|
||||
QVector<double> hrMeanMaxDouble; // RideFile::hr
|
||||
QVector<double> cadMeanMaxDouble; // RideFile::cad
|
||||
@@ -180,6 +187,8 @@ class RideFileCache
|
||||
QVector<double> xPowerMeanMaxDouble; // RideFile::kph
|
||||
QVector<double> npMeanMaxDouble; // RideFile::kph
|
||||
QVector<double> vamMeanMaxDouble; // RideFile::kph
|
||||
QVector<double> wattsKgMeanMaxDouble; // watts/kg
|
||||
|
||||
QVector<QDate> wattsMeanMaxDate; // RideFile::watts
|
||||
QVector<QDate> hrMeanMaxDate; // RideFile::hr
|
||||
QVector<QDate> cadMeanMaxDate; // RideFile::cad
|
||||
@@ -188,6 +197,7 @@ class RideFileCache
|
||||
QVector<QDate> xPowerMeanMaxDate; // RideFile::kph
|
||||
QVector<QDate> npMeanMaxDate; // RideFile::kph
|
||||
QVector<QDate> vamMeanMaxDate; // RideFile::vam
|
||||
QVector<QDate> wattsKgMeanMaxDate; // watts/kg
|
||||
|
||||
//
|
||||
// SAMPLE DISTRIBUTION
|
||||
@@ -204,6 +214,8 @@ class RideFileCache
|
||||
QVector<float> kphDistribution; // RideFile::kph
|
||||
QVector<float> xPowerDistribution; // RideFile::kph
|
||||
QVector<float> npDistribution; // RideFile::kph
|
||||
QVector<float> wattsKgDistribution; // RideFile::wattsKg
|
||||
|
||||
QVector<double> wattsDistributionDouble; // RideFile::watts
|
||||
QVector<double> hrDistributionDouble; // RideFile::hr
|
||||
QVector<double> cadDistributionDouble; // RideFile::cad
|
||||
@@ -211,6 +223,8 @@ class RideFileCache
|
||||
QVector<double> kphDistributionDouble; // RideFile::kph
|
||||
QVector<double> xPowerDistributionDouble; // RideFile::kph
|
||||
QVector<double> npDistributionDouble; // RideFile::kph
|
||||
QVector<double> wattsKgDistributionDouble; // RideFile::wattsKg
|
||||
|
||||
|
||||
QVector<float> wattsTimeInZone; // time in zone in seconds
|
||||
QVector<float> hrTimeInZone; // time in zone in seconds
|
||||
|
||||
Reference in New Issue
Block a user