int HrPwWindow::findDelay(QVector<double> &wattsArray, QVector<double> &hrArray, int rideTimeSecs) { int delay = 0; double maxr = 0; if (rideTimeSecs>= 60) { for (int a = 10; a <=60; ++a) { QVector<double> delayHr(rideTimeSecs); for (int j = a; j<rideTimeSecs; ++j) { delayHr[j-a] = hrArray[j]; } for (int j = rideTimeSecs-a; j<rideTimeSecs; ++j) { delayHr[j] = 0.0; } double r = corr(wattsArray, delayHr, rideTimeSecs-a); //fprintf(stderr, "findDelay %d: %.2f \n", a, r); if (r>maxr) { maxr = r; delay = a; } } } delayEdit->setText(QString("%1").arg(delay)); rDelayEdit->setText(QString("%1").arg(delay)); delaySlider->setValue(delay); rDelaySlider->setValue(delay); return delay; }
void HrPwPlot::recalc() { if (timeArray.count() == 0) return; int rideTimeSecs = (int) ceil(timeArray[arrayLength - 1]); if (rideTimeSecs > SECONDS_IN_A_WEEK) { return; } // ------ smoothing ----- double totalWatts = 0.0; double totalHr = 0.0; QList<DataPoint*> list; int i = 0; QVector<double> smoothWatts(rideTimeSecs + 1); QVector<double> smoothHr(rideTimeSecs + 1); QVector<double> smoothTime(rideTimeSecs + 1); int decal=0; //int interval = 0; int smooth = hrPwWindow->smooth; for (int secs = smooth; secs <= rideTimeSecs; ++secs) { while ((i < arrayLength) && (timeArray[i] <= secs)) { DataPoint *dp = new DataPoint(timeArray[i], hrArray[i], wattsArray[i], interArray[i]); totalWatts += wattsArray[i]; totalHr += hrArray[i]; list.append(dp); ++i; } while (!list.empty() && (list.front()->time < secs - smooth)) { DataPoint *dp = list.front(); list.removeFirst(); totalWatts -= dp->watts; totalHr -= dp->hr; delete dp; } if (list.empty()) ++decal; else { smoothWatts[secs-decal] = totalWatts / list.size(); smoothHr[secs-decal] = totalHr / list.size(); } smoothTime[secs] = secs / 60.0; } // Delete temporary list qDeleteAll(list); list.clear(); rideTimeSecs = rideTimeSecs-decal; smoothWatts.resize(rideTimeSecs); smoothHr.resize(rideTimeSecs); // Clip to max QVector<double> clipWatts(rideTimeSecs); QVector<double> clipHr(rideTimeSecs); decal = 0; for (int secs = 0; secs < rideTimeSecs; ++secs) { if (smoothHr[secs]>= minHr && smoothWatts[secs]>= minWatt && smoothWatts[secs]<maxWatt) { clipWatts[secs-decal] = smoothWatts[secs]; clipHr[secs-decal] = smoothHr[secs]; } else decal ++; } rideTimeSecs = rideTimeSecs-decal; clipWatts.resize(rideTimeSecs); clipHr.resize(rideTimeSecs); // Find Hr Delay if (delay == -1) delay = hrPwWindow->findDelay(clipWatts, clipHr, clipWatts.size()); else if (delay>rideTimeSecs) delay=rideTimeSecs; // Apply delay QVector<double> delayWatts(rideTimeSecs-delay); QVector<double> delayHr(rideTimeSecs-delay); for (int secs = 0; secs < rideTimeSecs-delay; ++secs) { delayWatts[secs] = clipWatts[secs]; delayHr[secs] = clipHr[secs+delay]; } rideTimeSecs = rideTimeSecs-delay; double rslope = hrPwWindow->slope(delayWatts, delayHr, delayWatts.size()); double rintercept = hrPwWindow->intercept(delayWatts, delayHr, delayWatts.size()); double maxr = hrPwWindow->corr(delayWatts, delayHr, delayWatts.size()); // ----- limit plotted points --- int intpoints = 10; // could be ride length dependent int nbpoints = (int)floor(rideTimeSecs/intpoints); QVector<double> plotedWatts(nbpoints); QVector<double> plotedHr(nbpoints); for (int secs = 0; secs < nbpoints; ++secs) { plotedWatts[secs] = clipWatts[secs*intpoints]; plotedHr[secs] = clipHr[secs*intpoints]; } int nbpoints2 = (int)floor(nbpoints/36)+2; double *plotedWattsArray[36]; double *plotedHrArray[36]; for (int i = 0; i < 36; ++i) { plotedWattsArray[i]= new double[nbpoints2]; plotedHrArray[i]= new double[nbpoints2]; } for (int secs = 0; secs < nbpoints; ++secs) { for (int i = 0; i < 36; ++i) { if (secs >= i*nbpoints2 && secs< (i+1)*nbpoints2) { plotedWattsArray[i][secs-i*nbpoints2] = plotedWatts[secs-i]; plotedHrArray[i][secs-i*nbpoints2] = plotedHr[secs-i]; } } } for (int i = 0; i < 36; ++i) { if (nbpoints-i*nbpoints2>0) { hrCurves[i]->setSamples(plotedWattsArray[i], plotedHrArray[i], (nbpoints-i*nbpoints2<nbpoints2?nbpoints-i*nbpoints2:nbpoints2)); hrCurves[i]->setVisible(true); } else hrCurves[i]->setVisible(false); } // Clean up memory for (int i = 0; i < 36; ++i) { delete plotedWattsArray[i]; delete plotedHrArray[i]; } setAxisScale(xBottom, 0.0, maxWatt); setYMax(); refreshZoneLabels(); QString labelp; labelp.setNum(rslope, 'f', 3); QString labelo; labelo.setNum(rintercept, 'f', 1); QString labelr; labelr.setNum(maxr, 'f', 3); QString labeldelay; labeldelay.setNum(delay); int power150 = (int)floor((150-rintercept)/rslope); QString labelpower150; labelpower150.setNum(power150); QwtText textr = QwtText(labelp+"*x+"+labelo+" : R "+labelr+" ("+labeldelay+") \n Power@150:"+labelpower150+"W"); textr.setFont(QFont("Helvetica", 10, QFont::Bold)); textr.setColor(GColor(CPLOTMARKER)); r_mrk1->setValue(0,0); r_mrk1->setLineStyle(QwtPlotMarker::VLine); r_mrk1->setLabelAlignment(Qt::AlignRight | Qt::AlignBottom); r_mrk1->setLinePen(QPen(GColor(CPLOTMARKER), 0, Qt::DashDotLine)); double averagewatt = hrPwWindow->average(clipWatts, clipWatts.size()); r_mrk1->setValue(averagewatt, 0.0); r_mrk1->setLabel(textr); r_mrk2->setValue(0,0); r_mrk2->setLineStyle(QwtPlotMarker::HLine); r_mrk2->setLabelAlignment(Qt::AlignRight | Qt::AlignTop); r_mrk2->setLinePen(QPen(GColor(CPLOTMARKER), 0, Qt::DashDotLine)); double averagehr = hrPwWindow->average(clipHr, clipHr.size()); r_mrk2->setValue(0.0,averagehr); addWattStepCurve(clipWatts, clipWatts.size()); addHrStepCurve(clipHr, clipHr.size()); addRegLinCurve(rslope, rintercept); setJoinLine(joinLine); replot(); }