mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
Enable Performance Tests for CV charts
Show them in CV charts and use them for fitting, just like they work in CP charts.
This commit is contained in:
@@ -57,6 +57,36 @@
|
||||
#include "qwt_spline_curve_fitter.h"
|
||||
#include "LTMTrend.h"
|
||||
|
||||
QString
|
||||
CPPlot::paceString(double secs, double kph)
|
||||
{
|
||||
QString paceStr;
|
||||
const PaceZones *zones = context->athlete->paceZones(sport=="Swim");
|
||||
const bool metricPace = zones ? appsettings->value(this, zones->paceSetting(), GlobalContext::context()->useMetricUnits).toBool() : GlobalContext::context()->useMetricUnits;
|
||||
|
||||
if (sport == "Run" || sport == "Swim") {
|
||||
|
||||
if (zones) paceStr = QString("\n%1 %2").arg(zones->kphToPaceString(kph, metricPace))
|
||||
.arg(zones->paceUnits(metricPace));
|
||||
} else if (sport == "Row") {
|
||||
|
||||
paceStr = QString("\n%1 %2").arg(kphToPace(kph*2, true, false)).arg(tr("min/500m"));
|
||||
}
|
||||
|
||||
const double km = kph*secs/60.0; // distance in km
|
||||
if (sport == "Swim") {
|
||||
|
||||
if (metricPace) paceStr += tr("\n%1 m").arg(1000*km, 0, 'f', 0);
|
||||
else paceStr += tr("\n%1 yd").arg(1000*km/METERS_PER_YARD, 0, 'f', 0);
|
||||
|
||||
} else {
|
||||
|
||||
if (metricPace) paceStr += tr("\n%1 km").arg(km, 0, 'f', 3);
|
||||
else paceStr += tr("\n%1 mi").arg(MILES_PER_KM*km, 0, 'f', 3);
|
||||
|
||||
}
|
||||
return paceStr;
|
||||
}
|
||||
|
||||
CPPlot::CPPlot(CriticalPowerWindow *parent, Context *context, bool rangemode) : QwtPlot(parent), parent(parent),
|
||||
|
||||
@@ -1064,7 +1094,8 @@ CPPlot::plotTests(RideItem *rideitem)
|
||||
QVector<QPointF> points;
|
||||
|
||||
// just plot tests as power duration for now, will reiterate to add others later.
|
||||
if (rideSeries == RideFile::watts || rideSeries == RideFile::wattsKg || criticalSeries == CriticalPowerWindow::work) {
|
||||
if (rideSeries == RideFile::watts || rideSeries == RideFile::wattsKg ||
|
||||
criticalSeries == CriticalPowerWindow::work || rideSeries == RideFile::kph) {
|
||||
|
||||
// rides to search, this one only -or- all in the date range selected?
|
||||
QList<RideItem*> rides;
|
||||
@@ -1091,7 +1122,9 @@ CPPlot::plotTests(RideItem *rideitem)
|
||||
if (interval->istest()) {
|
||||
|
||||
double duration = (interval->stop - interval->start) + 1; // add offset used on log axis
|
||||
double watts = interval->getForSymbol("average_power", GlobalContext::context()->useMetricUnits);
|
||||
double watts = rideSeries == RideFile::kph ?
|
||||
interval->getForSymbol("average_speed", GlobalContext::context()->useMetricUnits) :
|
||||
interval->getForSymbol("average_power", GlobalContext::context()->useMetricUnits);
|
||||
|
||||
|
||||
// ignore where no power present
|
||||
@@ -1121,10 +1154,11 @@ CPPlot::plotTests(RideItem *rideitem)
|
||||
test->setSymbol(sym);
|
||||
test->setValue(duration/60.00f, watts);
|
||||
|
||||
QString desc = QString("%3\n%1 %4\n%2").arg(watts,0, 'f', rideSeries == RideFile::watts ? 0 : 2)
|
||||
QString desc = QString("%3\n%1 %4%5\n%2").arg(watts,0, 'f', rideSeries == RideFile::watts ? 0 : 2)
|
||||
.arg(interval_to_str(duration))
|
||||
.arg(interval->name)
|
||||
.arg(criticalSeries == CriticalPowerWindow::work ? tr("kJ") : RideFile::unitName(rideSeries, context));
|
||||
.arg(criticalSeries == CriticalPowerWindow::work ? tr("kJ") : RideFile::unitName(rideSeries, context))
|
||||
.arg(criticalSeries == CriticalPowerWindow::kph ? paceString(duration/60.0, watts) : "");
|
||||
QwtText text(desc);
|
||||
QFont font; // default
|
||||
font.setPointSize(8);
|
||||
@@ -2114,7 +2148,7 @@ CPPlot::pointHover(QwtPlotCurve *curve, int index)
|
||||
|
||||
const double xvalue = curve->sample(index).x();
|
||||
const double yvalue = curve->sample(index).y();
|
||||
QString text, dateStr, paceStr;
|
||||
QString text, dateStr;
|
||||
QString currentRidePercentStr;
|
||||
QString units1;
|
||||
QString units2;
|
||||
@@ -2192,35 +2226,6 @@ CPPlot::pointHover(QwtPlotCurve *curve, int index)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// for speed series add pace with units according to settings
|
||||
if (criticalSeries == CriticalPowerWindow::kph) {
|
||||
|
||||
if (sport == "Run" || sport == "Swim") {
|
||||
|
||||
const PaceZones *zones = context->athlete->paceZones(sport=="Swim");
|
||||
if (zones) paceStr = QString("\n%1 %2").arg(zones->kphToPaceString(yvalue, metricPace))
|
||||
.arg(zones->paceUnits(metricPace));
|
||||
|
||||
} else if (sport == "Row") {
|
||||
|
||||
paceStr = QString("\n%1 %2").arg(kphToPace(yvalue*2, true, false)).arg(tr("min/500m"));
|
||||
}
|
||||
|
||||
const double km = yvalue*xvalue/60.0; // distance in km
|
||||
if (sport == "Swim") {
|
||||
|
||||
if (metricPace) paceStr += tr("\n%1 m").arg(1000*km, 0, 'f', 0);
|
||||
else paceStr += tr("\n%1 yd").arg(1000*km/METERS_PER_YARD, 0, 'f', 0);
|
||||
|
||||
} else {
|
||||
|
||||
if (metricPace) paceStr += tr("\n%1 km").arg(km, 0, 'f', 3);
|
||||
else paceStr += tr("\n%1 mi").arg(MILES_PER_KM*km, 0, 'f', 3);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// output the tooltip
|
||||
text = QString("%1%2\n%3 %4%5%6")
|
||||
.arg(criticalSeries == CriticalPowerWindow::veloclinicplot ?
|
||||
@@ -2229,7 +2234,7 @@ CPPlot::pointHover(QwtPlotCurve *curve, int index)
|
||||
.arg(units1)
|
||||
.arg(units2)
|
||||
.arg(currentRidePercentStr)
|
||||
.arg(paceStr)
|
||||
.arg(criticalSeries == CriticalPowerWindow::kph ? paceString(xvalue, yvalue) : "")
|
||||
.arg(dateStr);
|
||||
|
||||
// set that text up
|
||||
|
||||
@@ -149,6 +149,7 @@ class CPPlot : public QwtPlot
|
||||
void refreshReferenceLines(RideItem*);
|
||||
QString kphToString(double kph);
|
||||
QString kmToString(double km);
|
||||
QString paceString(double secs, double kph);
|
||||
|
||||
// Models and Extended Models
|
||||
int model, modelVariant;
|
||||
|
||||
@@ -210,7 +210,7 @@ PDModel::deriveCPParameters(int model)
|
||||
// RMSE
|
||||
double RMSE=sqrt(mean);
|
||||
double CV=(RMSE/MEAN) * 100;
|
||||
fitsummary = tr("RMSE %1w CV %4% R<sup>2</sup>=%3 [LR] %2 points").arg(RMSE, 0, 'f', 0)
|
||||
fitsummary = tr("RMSE %1 CV %4% R<sup>2</sup>=%3 [LR] %2 points").arg(RMSE, 0, 'f', 0)
|
||||
.arg(t.size())
|
||||
.arg(R2, 0, 'f', 3)
|
||||
.arg(CV, 0, 'f', 1);
|
||||
@@ -329,7 +329,7 @@ PDModel::deriveCPParameters(int model)
|
||||
// RMSE and CV
|
||||
double RMSE=sqrt(mean);
|
||||
double CV=(RMSE/MEAN) * 100;
|
||||
fitsummary = tr("RMSE %1w CV %3% [LM] %2 points").arg(RMSE, 0, 'f', 0)
|
||||
fitsummary = tr("RMSE %1 CV %3% [LM] %2 points").arg(RMSE, 0, 'f', 0)
|
||||
.arg(p.size())
|
||||
.arg(CV, 0, 'f', 1);
|
||||
|
||||
@@ -476,7 +476,7 @@ PDModel::calcSummary()
|
||||
// RMSE
|
||||
double RMSE=sqrt(mean);
|
||||
double CV=(RMSE/MEAN) *100;
|
||||
fitsummary = tr("RMSE %1w CV %3% [envelope] %2 points").arg(RMSE, 0, 'f', 0).arg(data.size()).arg(CV,0,'f',1);
|
||||
fitsummary = tr("RMSE %1 CV %3% [envelope] %2 points").arg(RMSE, 0, 'f', 0).arg(data.size()).arg(CV,0,'f',1);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1274,6 +1274,7 @@ ExtendedModel::deriveExtCPParameters()
|
||||
(fabs(ecp_dec - ecp_dec_prev) > ecp_dec_delta_max)
|
||||
);
|
||||
|
||||
#if 0
|
||||
// What did we get ...
|
||||
// To help debug this below we output the derived values
|
||||
// commented out for release, its quite a mouthful !
|
||||
@@ -1288,7 +1289,6 @@ ExtendedModel::deriveExtCPParameters()
|
||||
(1+ecp_dec*exp(ecp_dec_del/60.0)) *
|
||||
(1+etau/(60.0));
|
||||
|
||||
#if 0
|
||||
qDebug() <<"eCP(5.3) " << "paa" << paa << "ecp" << ecp << "etau" << etau
|
||||
<< "paa_dec" << paa_dec << "ecp_del" << ecp_del << "ecp_dec"
|
||||
<< ecp_dec << "ecp_dec_del" << ecp_dec_del;
|
||||
@@ -1317,7 +1317,7 @@ ExtendedModel::deriveExtCPParameters()
|
||||
// RMSE
|
||||
double RMSE=sqrt(mean);
|
||||
double CV=(RMSE/MEAN)*100;
|
||||
fitsummary = tr("RMSE %1w CV %3% [envelope] %2 points").arg(RMSE, 0, 'f', 0).arg(data.size()).arg(CV,0,'f',1);
|
||||
fitsummary = tr("RMSE %1 CV %3% [envelope] %2 points").arg(RMSE, 0, 'f', 0).arg(data.size()).arg(CV,0,'f',1);
|
||||
}
|
||||
|
||||
QList<QPointF>
|
||||
|
||||
Reference in New Issue
Block a user