mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-04-13 12:42:20 +00:00
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.
This commit is contained in:
@@ -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,25 +345,7 @@ 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
|
||||
@@ -371,6 +353,29 @@ banisterFit::f(double d, const double *parms)
|
||||
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 @@ public:
|
||||
|
||||
double f(double t, const double *p);
|
||||
void combine(banisterFit other);
|
||||
void compute(long startIndex, long stopIndex);
|
||||
|
||||
long startIndex, stopIndex;
|
||||
QDate startDate, stopDate;
|
||||
|
||||
Reference in New Issue
Block a user