Permalink
Browse files

LTM plot banister with gapped curves

.. we only have banister curves where there is data
   so if there are gaps between seasons we should not
   plot any data.

.. as a result also fixed bug that the qwt gapped
   curve would always plot first zero in a curve.
  • Loading branch information...
liversedge committed Jan 10, 2019
1 parent 5cc2e05 commit a205e7bb730ad1a288827747e0da1ebccf19b438
Showing with 42 additions and 22 deletions.
  1. +5 −1 qtsolutions/qwtcurve/qwt_plot_gapped_curve.cpp
  2. +2 −2 src/Charts/LTMPlot.cpp
  3. +34 −19 src/Metrics/Banister.cpp
  4. +1 −0 src/Metrics/Banister.h
@@ -38,7 +38,11 @@ void QwtPlotGappedCurve::drawSeries(QPainter *painter, const QwtScaleMap &xMap,
// First non-missed point will be the start of curve section.
double x = sample(i).x();
double y = sample(i).y();
if ((y < (naValue_ + -0.001) || y > (naValue_ + 0.001)) && x - last <= gapValue_) {
double yprev = 0;
if (i>0) yprev = sample(i-1).y();

if ((y < (naValue_ + -0.001) || y > (naValue_ + 0.001)) && (x - last <= gapValue_) &&
(yprev < (naValue_ + -0.001) || yprev > (naValue_ + 0.001))) {

int start = i-1;
int end = i;
@@ -444,7 +444,7 @@ LTMPlot::setData(LTMSettings *set)
if (count <= 0) continue;

// Create a curve
QwtPlotCurve *current = metricDetail.type == METRIC_ESTIMATE
QwtPlotCurve *current = (metricDetail.type == METRIC_ESTIMATE || metricDetail.type == METRIC_BANISTER)
? new QwtPlotGappedCurve(metricDetail.uname, 1)
: new QwtPlotCurve(metricDetail.uname);
current->setVisible(!metricDetail.hidden);
@@ -599,7 +599,7 @@ LTMPlot::setData(LTMSettings *set)
//qDebug()<<"Create curve data.."<<timer.elapsed();

// Create a curve
QwtPlotCurve *current = metricDetail.type == METRIC_ESTIMATE
QwtPlotCurve *current = (metricDetail.type == METRIC_ESTIMATE || metricDetail.type == METRIC_BANISTER)
? new QwtPlotGappedCurve(metricDetail.uname, 1)
: new QwtPlotCurve(metricDetail.uname);
current->setVisible(!metricDetail.hidden);
@@ -345,32 +345,37 @@ banisterFit::f(double d, const double *parms)
p0 = parms[4];

//printd("fit iter %s to %s [k1=%g k2=%g t1=%g t2=%g p0=%g]\n", startDate.toString().toStdString().c_str(), stopDate.toString().toStdString().c_str(), k1,k2,t1,t2,p0); // too much info even in debug, unless you want it

// ack, we need to recompute our window using the parameters supplied
bool first = true;
for (int index=startIndex; index < stopIndex; index++) {

// g and h are just accumulated training load with different decay parameters
if (first) {
parent->data[index].g = parent->data[index].h = 0;
first = false;
} else {
parent->data[index].g = (parent->data[index-1].g * exp (-1/t1)) + parent->data[index].score;
parent->data[index].h = (parent->data[index-1].h * exp (-1/t2)) + parent->data[index].score;
}

// apply coefficients
parent->data[index].pte = parent->data[index].g * k1;
parent->data[index].nte = parent->data[index].h * k2;
parent->data[index].perf = p0 + parent->data[index].pte - parent->data[index].nte;
}
compute(startIndex, stopIndex);
}

// return previously computed
//printd("result perf(%s)=%g vs test=%g\n", parent->start.addDays(d).toString().toStdString().c_str(),parent->data[int(d)].perf, parent->data[int(d)].test);
return parent->data[int(d)].perf;
}

void
banisterFit::compute(long start, long stop)
{
// ack, we need to recompute our window using the parameters supplied
bool first = true;
for (int index=start; index < stop; index++) {

// g and h are just accumulated training load with different decay parameters
if (first) {
parent->data[index].g = parent->data[index].h = 0;
first = false;
} else {
parent->data[index].g = (parent->data[index-1].g * exp (-1/t1)) + parent->data[index].score;
parent->data[index].h = (parent->data[index-1].h * exp (-1/t2)) + parent->data[index].score;
}

// apply coefficients
parent->data[index].pte = parent->data[index].g * k1;
parent->data[index].nte = parent->data[index].h * k2;
parent->data[index].perf = p0 + parent->data[index].pte - parent->data[index].nte;
}
}

void
banisterFit::combine(banisterFit other)
{
@@ -421,6 +426,16 @@ void Banister::fit()
printd("window %d %s [k1=%g k2=%g t1=%g t2=%g p0=%g]\n", i, lm_infmsg[status.outcome], prior[0], prior[1], prior[2], prior[3], prior[4]);
}
}

#if 0 // doesn't really make sense for now
// fill curves
for(int i=0; i<windows.length(); i++) {
if (i < (windows.length()-1))
windows[i].compute(windows[i].stopIndex, windows[i+1].startIndex);
else
windows[i].compute(windows[i].stopIndex, data.length());
}
#endif
}

//
@@ -56,6 +56,7 @@ class banisterFit {

double f(double t, const double *p);
void combine(banisterFit other);
void compute(long startIndex, long stopIndex);

long startIndex, stopIndex;
QDate startDate, stopDate;

0 comments on commit a205e7b

Please sign in to comment.