Permalink
Browse files

Banister Data Managed in Athlete

.. so we retrieve past ones and reuse rather than refresh
   and refit every time we plot it.
  • Loading branch information...
liversedge committed Jan 11, 2019
1 parent a205e7b commit 9871d1e53f8ad704e140f59a164d1eb18e7d2517
Showing with 67 additions and 10 deletions.
  1. +7 −4 src/Charts/LTMPlot.cpp
  2. +22 −0 src/Core/Athlete.cpp
  3. +5 −0 src/Core/Athlete.h
  4. +30 −5 src/Metrics/Banister.cpp
  5. +3 −1 src/Metrics/Banister.h
@@ -3549,10 +3549,13 @@ LTMPlot::createBanisterData(Context *context, LTMSettings *settings, MetricDetai
QVector<double>&x,QVector<double>&y,int&n, bool)
{
// banister model
Banister f(context, metricDetail.symbol, 0,0,0,0);
Banister *banister = context->athlete->getBanisterFor(metricDetail.symbol, 0,0);

// perform fit (date range todo)
f.fit();
// should never happen...
if (banister==NULL) {
n=0;
return;
}

int maxdays = groupForDate(settings->end.date(), settings->groupBy)
- groupForDate(settings->start.date(), settings->groupBy);
@@ -3579,7 +3582,7 @@ LTMPlot::createBanisterData(Context *context, LTMSettings *settings, MetricDetai
int currentDay = groupForDate(date, settings->groupBy);

// value for day
double value = f.value(date, metricDetail.stressType);
double value = banister->value(date, metricDetail.stressType);

if (plotData && (value || wantZero)) {
unsigned long seconds = 1;
@@ -36,6 +36,7 @@
#include "WithingsDownload.h"
#include "CalendarDownload.h"
#include "PMCData.h"
#include "Banister.h"
#include "ErgDB.h"
#ifdef GC_HAVE_ICAL
#include "ICalendar.h"
@@ -519,6 +520,27 @@ Athlete::getHeight(RideFile *ride)
return height;
}

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

// if we don't already have one, create it
returning = banisterData.value(metricName, 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)

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

return returning;

}

// working with PMC data series
PMCData *
Athlete::getPMCFor(QString metricName, int stsdays, int ltsdays)
@@ -62,6 +62,7 @@ class Tab;
class Leaf;
class DataFilterRuntime;
class CloudServiceAutoDownload;
class Banister;

class Athlete : public QObject
{
@@ -111,6 +112,10 @@ class Athlete : public QObject
PMCData *getPMCFor(Leaf *expr, DataFilterRuntime *df, int stsDays = -1, int ltsDays = -1); // no Specification used!
QMap<QString, PMCData*> pmcData; // all the different PMC series

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

// athlete measures
// note ride can override if passed
double getWeight(QDate date, RideFile *ride=NULL);
@@ -101,8 +101,14 @@ const int typical_SeasonBreak = 42;
//
//
Banister::Banister(Context *context, QString symbol, double t1, double t2, double k1, double k2) :
symbol(symbol), k1(k1), k2(k2), t1(t1), t2(t2), days(0), context(context)
symbol(symbol), k1(k1), k2(k2), t1(t1), t2(t2), days(0), context(context), isstale(true)
{
// when they all change we are ready to invalidate and refresh
// don't worry about upstream events, this is what we are dependant on
connect(context, SIGNAL(estimatesRefreshed()), this, SLOT(invalidate()));
connect(context, SIGNAL(estimatesRefreshed()), this, SLOT(refresh()));

// refresh
refresh();
}

@@ -112,12 +118,15 @@ Banister::value(QDate date, int type)
{
// check in range
if (date > stop || date < start) return 0;
int index=date.toJulianDay()-start.toJulianDay();

// offset, bouinds check just in case.
long index=date.toJulianDay()-start.toJulianDay();
if (index <0 || index>=data.length()) return 0;

switch(type) {
case BANISTER_NTE: return data[index].nte;
case BANISTER_PTE: return data[index].pte;
case BANISTER_CP: return data[index].perf * typical_CP / 100;
case BANISTER_NTE: return data[index].h;
case BANISTER_PTE: return data[index].g;
case BANISTER_CP: return data[index].perf > 0 ? data[index].perf * typical_CP / 100 : 0; // avoid -ve values and divzero
default:
case BANISTER_PERFORMANCE: return data[index].perf;
}
@@ -142,9 +151,20 @@ Banister::init()
t2=15;
}

void
Banister::invalidate()
{
isstale=true;
}
void
Banister::refresh()
{
// not stale
if (!isstale) return;

// unstale
isstale=false;

// clear
init();

@@ -325,6 +345,11 @@ Banister::refresh()
f.tests, f.testoffset,
f.stopIndex-f.startIndex);
}

//
// EXTRACT PARAMETERS WITH A FIT
//
fit();
}


@@ -39,7 +39,7 @@ extern const int typical_SeasonBreak;

class banisterData{
public:
banisterData() : score(0), nte(0), pte(0), perf(0), test(0) {}
banisterData() : score(0), g(0), h(0), nte(0), pte(0), perf(0), test(0) {}
double score, // TRIMP, BikeScore etc for day
g, // accumulated load with t1 decay for pte
h, // accumulated load with t2 decay for nte
@@ -108,11 +108,13 @@ class Banister : public QObject {
public slots:

void init(); // reset previous fits
void invalidate(); // mark as stale
void refresh(); // collect data from rides etc
void fit(); // perform fits along windows

private:
Context *context;
bool isstale;

};
#endif

0 comments on commit 9871d1e

Please sign in to comment.