Skip to content
Permalink
Browse files

Allow Banister to use other performance metric besides Power Index (#…

…3136)

* Allow Banister to use other performance metric besides Power Index
Performance metric can be selected from any Peak metric in LTM Charts
Datafilter now is banister(load_metric, perf_metric, ...)

* Travis-ci - R3.6 install update key
According to https://cloud.r-project.org/bin/linux/ubuntu/README
  • Loading branch information...
amtriathlon committed Aug 4, 2019
1 parent 2babb9f commit 3987833102922c517071cc647e6ff5d8eed64289
@@ -3568,7 +3568,7 @@ LTMPlot::createBanisterData(Context *context, LTMSettings *settings, MetricDetai
QVector<double>&x,QVector<double>&y,int&n, bool)
{
// banister model
Banister *banister = context->athlete->getBanisterFor(metricDetail.symbol, 50,11);
Banister *banister = context->athlete->getBanisterFor(metricDetail.symbol, metricDetail.perfSymbol, 50,11);

// should never happen...
if (banister==NULL) {
@@ -233,6 +233,7 @@ QDataStream &operator<<(QDataStream &out, const LTMSettings &settings)
out<<metric.tests;
out<<metric.perfs;
out<<metric.submax;
out<<metric.perfSymbol;
}
out<<settings.showData;
out<<settings.stack;
@@ -370,6 +371,7 @@ while(counter-- && !in.atEnd()) {
in >> m.perfs;
}
if (version >= 19) in >> m.submax;
if (version >= 21) in >> m.perfSymbol;

bool keep=true;
// check for deprecated things and set keep=false if
@@ -54,8 +54,9 @@ class RideBest;
// 18 05 Jan 2018 Mark Liversedge Performance tests and weekly performances
// 19 07 Jan 2018 Mark Liversedge Flagged as possibly submaximal weekly best
// 20 15 Apr 2019 Ale Martinez Added run flag to Estimate
// 21 31 Jul 2019 Ale Martinez Added perfSymbol for Banister

#define LTM_VERSION_NUMBER 20
#define LTM_VERSION_NUMBER 21

// group by settings
#define LTM_DAY 1
@@ -117,7 +118,7 @@ class MetricDetail {
public:

MetricDetail() : type(METRIC_DB), stack(false), hidden(false), model(""), formulaType(RideMetric::Average), name(""),
metric(NULL), stressType(0), measureGroup(0), measureField(0), tests(true), perfs(true),
metric(NULL), stressType(0), measureGroup(0), measureField(0), tests(true), perfs(true), perfSymbol("power_index"),
smooth(false), trendtype(0), topN(0), lowestN(0), topOut(0), baseline(0.0),
curveStyle(QwtPlotCurve::Lines), symbolStyle(QwtSymbol::NoSymbol),
penColor(Qt::black), penAlpha(0), penWidth(1.0), penStyle(0),
@@ -163,6 +164,9 @@ class MetricDetail {
bool perfs;
bool submax;

// for Banister
QString perfSymbol;

// GENERAL SETTINGS FOR A METRIC
QString uname, uunits; // user specified name and units (axis choice)

@@ -1953,14 +1953,30 @@ EditMetricDetailDialog::EditMetricDetailDialog(Context *context, LTMTool *ltmToo
banisterTypeSelect->addItem(tr("Predicted CP (Watts)"), BANISTER_CP);
banisterTypeSelect->setCurrentIndex(metricDetail->stressType < 4 ? metricDetail->stressType : 2);

// banister performance metric
banisterPerfMetric = new QComboBox(this);
foreach(MetricDetail metric, ltmTool->metrics)
if (metric.metric != NULL && metric.metric->type() == RideMetric::Peak)
banisterPerfMetric->addItem(metric.name, metric.symbol);
banisterPerfMetric->setCurrentIndex(banisterPerfMetric->findData(metricDetail->perfSymbol));

banisterWidget = new QWidget(this);
banisterWidget->setContentsMargins(0,0,0,0);
QHBoxLayout *banisterLayout = new QHBoxLayout(banisterWidget);
banisterLayout->setContentsMargins(0,0,0,0);
banisterLayout->setSpacing(5 *dpiXFactor);
banisterLayout->addWidget(new QLabel(tr("Curve Type"), this));
banisterLayout->addWidget(banisterTypeSelect);

QVBoxLayout *banisterLayout = new QVBoxLayout(banisterWidget);

QHBoxLayout *banisterTypeLayout = new QHBoxLayout();
banisterTypeLayout->setContentsMargins(0,0,0,0);
banisterTypeLayout->setSpacing(5 *dpiXFactor);
banisterTypeLayout->addWidget(new QLabel(tr("Curve Type"), this));
banisterTypeLayout->addWidget(banisterTypeSelect);
banisterLayout->addLayout(banisterTypeLayout);

QHBoxLayout *banisterPerfLayout = new QHBoxLayout();
banisterPerfLayout->setContentsMargins(0,0,0,0);
banisterPerfLayout->setSpacing(5 *dpiXFactor);
banisterPerfLayout->addWidget(new QLabel(tr("Perf. Metric"), this));
banisterPerfLayout->addWidget(banisterPerfMetric);
banisterLayout->addLayout(banisterPerfLayout);

metricWidget = new QWidget(this);
metricWidget->setContentsMargins(0,0,0,0);
@@ -2369,7 +2385,7 @@ EditMetricDetailDialog::banisterName()
if (chooseBanister->isChecked() == false) return;

// re-use bestSymbol like PMC does
metricDetail->bestSymbol = metricDetail->symbol;
metricDetail->bestSymbol = metricDetail->symbol+"_"+metricDetail->perfSymbol;

// append type
switch(banisterTypeSelect->currentIndex()) {
@@ -2589,7 +2605,10 @@ EditMetricDetailDialog::applyClicked()
metricDetail->stack = stack->isChecked();
metricDetail->trendtype = trendType->currentIndex();
if (chooseStress->isChecked()) metricDetail->stressType = stressTypeSelect->currentIndex();
if (chooseBanister->isChecked()) metricDetail->stressType = banisterTypeSelect->currentIndex();
if (chooseBanister->isChecked()) {
metricDetail->stressType = banisterTypeSelect->currentIndex();
metricDetail->perfSymbol = banisterPerfMetric->currentData().toString();
}
metricDetail->formula = formulaEdit->toPlainText();
metricDetail->formulaType = static_cast<RideMetric::MetricType>(formulaType->itemData(formulaType->currentIndex()).toInt());
metricDetail->measureGroup = measureGroupSelect->currentIndex();
@@ -215,6 +215,7 @@ class EditMetricDetailDialog : public QDialog

// banister
QComboBox *banisterTypeSelect; // PTE, NTE, Performance
QComboBox *banisterPerfMetric; // default Power Index

// formula
DataFilterEdit *formulaEdit; // edit your formula
@@ -266,11 +266,13 @@ LTMWindow::LTMWindow(Context *context) :

// interactive elements
banCombo = new QComboBox(this);
banPerf = new QComboBox(this);
banT1 = new QDoubleSpinBox(this);
banT2 = new QDoubleSpinBox(this);

// labels etc
ilabel = new QLabel(tr("Impulse Metric"), this);
perflabel = new QLabel(tr("Perf. Metric"), this);
plabel = new QLabel(tr("Peak"), this);
peaklabel = new QLabel(this);
peaklabel->setText("296w on 3rd July");
@@ -284,15 +286,17 @@ LTMWindow::LTMWindow(Context *context) :
// add to layout
bang->addWidget(ilabel,0,0);
bang->addWidget(banCombo,0,1,1,2,Qt::AlignLeft);
bang->addWidget(plabel, 1,0);
bang->addWidget(peaklabel,1,1,1,2,Qt::AlignLeft);
bang->addWidget(t1label1,2,0);
bang->addWidget(banT1,2,1);
bang->addWidget(t1label2,2,2);
bang->addWidget(t2label1,3,0);
bang->addWidget(banT2,3,1);
bang->addWidget(t2label2,3,2);
bang->addWidget(RMSElabel,4,0,1,3);
bang->addWidget(perflabel,1,0);
bang->addWidget(banPerf,1,1,1,2,Qt::AlignLeft);
bang->addWidget(plabel, 2,0);
bang->addWidget(peaklabel,2,1,1,2,Qt::AlignLeft);
bang->addWidget(t1label1,3,0);
bang->addWidget(banT1,3,1);
bang->addWidget(t1label2,3,2);
bang->addWidget(t2label1,4,0);
bang->addWidget(banT2,4,1);
bang->addWidget(t2label2,4,2);
bang->addWidget(RMSElabel,5,0,1,3);

// initialise
settings.ltmTool = ltmTool;
@@ -353,7 +357,8 @@ LTMWindow::LTMWindow(Context *context) :
connect(scrollRight, SIGNAL(clicked()), this, SLOT(moveRight()));

// refresh banister data when combo changes
connect(banCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshBanister(int)));
connect(banCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshBanister()));
connect(banPerf, SIGNAL(currentIndexChanged(int)), this, SLOT(refreshBanister()));
connect(banT1, SIGNAL(valueChanged(double)), this, SLOT(tuneBanister()));
connect(banT2, SIGNAL(valueChanged(double)), this, SLOT(tuneBanister()));
configChanged(CONFIG_APPEARANCE);
@@ -380,11 +385,15 @@ LTMWindow::showBanister(bool relevant)
// we reset the combo so lets remember where we were at
int remember=0;
if (banCombo->count()) remember=banCombo->currentIndex();
int rememberPerf=0;
if (banPerf->count()) rememberPerf=banPerf->currentIndex();

QStringList symbols;
QStringList perfSymbols;

// lets setup the widgets
banCombo->clear();
banPerf->clear();
foreach(MetricDetail metricDetail, settings.metrics) {
if (metricDetail.type == METRIC_BANISTER) {
if (!symbols.contains(metricDetail.symbol)) {
@@ -399,14 +408,22 @@ LTMWindow::showBanister(bool relevant)
banCombo->addItem(name, QVariant(metricDetail.symbol));
}
}
if (!perfSymbols.contains(metricDetail.perfSymbol)) {
const RideMetric *m = factory.rideMetric(metricDetail.perfSymbol);
if (m) {
perfSymbols << metricDetail.perfSymbol;
banPerf->addItem(m->name(), QVariant(metricDetail.perfSymbol));
}
}
}
}

// go back to remembered value
if (remember < banCombo->count()) banCombo->setCurrentIndex(remember);
if (rememberPerf < banPerf->count()) banPerf->setCurrentIndex(rememberPerf);

// now get the metric values etc
refreshBanister(banCombo->currentIndex());
refreshBanister();
overlayWidget->show();

} else {
@@ -444,10 +461,10 @@ LTMWindow::tuneBanister()
{

// if we have a banister...
if (banCombo->count() && banT1->value() >0 && banT2->value()>0) {
if (banCombo->count() && banPerf->count() && banT1->value() >0 && banT2->value()>0) {

// lookup and set
Banister *banister = context->athlete->getBanisterFor(banCombo->currentData().toString(),0,0);
Banister *banister = context->athlete->getBanisterFor(banCombo->currentData().toString(), banPerf->currentData().toString(),0,0);

// when user adjusts the t1/t2 parameters we need to refit
if (banT1->value() < banister->t1 || banT1->value() > banister->t1 ||
@@ -462,20 +479,25 @@ LTMWindow::tuneBanister()
}
}
void
LTMWindow::refreshBanister(int index)
LTMWindow::refreshBanister()
{
if (index >= 0 && index < banCombo->count()) {
int index = banCombo->currentIndex();
int perfIndex = banPerf->currentIndex();

if (index >= 0 && perfIndex >= 0) {

// lookup and set
Banister *banister = context->athlete->getBanisterFor(banCombo->currentData().toString(),0,0);
Banister *banister = context->athlete->getBanisterFor(banCombo->currentData().toString(), banPerf->currentData().toString(),0,0);
banT1->setValue(banister->t1);
banT2->setValue(banister->t2);

double perf=0.0;
int CP=0;
QDate when = banister->getPeakCP(settings.start.date(), settings.end.date(), CP);
QDate when = banister->getPeakPerf(settings.start.date(), settings.end.date(), perf, CP);

// set peak label
if (CP >0 && when != QDate()) peaklabel ->setText(QString("%1 watts on %2").arg(CP).arg(when.toString("d MMM yyyy")));
else if (perf >0.0 && when != QDate()) peaklabel ->setText(QString("%1 on %2").arg(perf, 0, 'f', 1).arg(when.toString("d MMM yyyy")));
else peaklabel->setText("");

// set RMSE for current view
@@ -513,6 +535,7 @@ LTMWindow::configChanged(qint32)
QFont font;
font.setPointSize(12); // reasonably big
ilabel->setFont(font);
perflabel->setFont(font);
plabel->setFont(font);
t1label1->setFont(font);
t1label2->setFont(font);
@@ -524,8 +547,10 @@ LTMWindow::configChanged(qint32)
banT1->setFont(font);
banT2->setFont(font);
banCombo->setFont(font);
banPerf->setFont(font);

ilabel->setPalette(palette);
perflabel->setPalette(palette);
plabel->setPalette(palette);
t1label1->setPalette(palette);
t1label2->setPalette(palette);
@@ -200,7 +200,7 @@ class LTMWindow : public GcChartWindow
// show the banister helper
void showBanister(bool relevant); // show banister helper if relevant to plot
void tuneBanister(); // when t1/t2 change
void refreshBanister(int); // refresh banister helper
void refreshBanister(); // refresh banister helper

void refreshPlot(); // normal mode
void refreshCompare(); // compare mode
@@ -306,9 +306,10 @@ class LTMWindow : public GcChartWindow

// banister helper
QComboBox *banCombo;
QComboBox *banPerf;
QDoubleSpinBox *banT1;
QDoubleSpinBox *banT2;
QLabel *ilabel, *plabel, *peaklabel, *t1label1, *t1label2, *t2label1, *t2label2, *RMSElabel;
QLabel *ilabel, *plabel, *peaklabel, *t1label1, *t1label2, *t2label1, *t2label2, *RMSElabel, *perflabel;

QTime lastRefresh;
bool firstshow;
@@ -525,19 +525,19 @@ Athlete::getHeight(RideFile *ride)

// working with Banister data series
Banister *
Athlete::getBanisterFor(QString metricName, int t1 , int t2)
Athlete::getBanisterFor(QString metricName, QString perfMetricName, int t1 , int t2)
{
Banister *returning = NULL;

// if we don't already have one, create it
returning = banisterData.value(metricName, NULL); // we do
returning = banisterData.value(metricName+perfMetricName, NULL); // we do
if (!returning) {

// specification is blank and passes for all
returning = new Banister(context, metricName, t1, t2); // we don't seed t1/t2 yet. (maybe never will)
returning = new Banister(context, metricName, perfMetricName, t1, t2); // we don't seed t1/t2 yet. (maybe never will)

// add to our collection
banisterData.insert(metricName, returning);
banisterData.insert(metricName+perfMetricName, returning);
}

return returning;
@@ -113,7 +113,7 @@ class Athlete : public QObject
QMap<QString, PMCData*> pmcData; // all the different PMC series

// Banister Data
Banister *getBanisterFor(QString metricName, int t1, int t2); // t1/t2 not used yet
Banister *getBanisterFor(QString metricName, QString perfMetricName, int t1, int t2); // t1/t2 not used yet
QMap<QString, Banister*> banisterData;

// athlete measures

0 comments on commit 3987833

Please sign in to comment.
You can’t perform that action at this time.