/* * Copyright (c) 2010 Mark Liversedge (liversedge@gmail.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "RealtimePlotWindow.h" #include "Athlete.h" RealtimePlotWindow::RealtimePlotWindow(Context *context) : GcWindow(context), context(context), active(false) { setContentsMargins(0,0,0,0); setProperty("color", GColor(CTRAINPLOTBACKGROUND)); QWidget *c = new QWidget; QVBoxLayout *cl = new QVBoxLayout(c); setControls(c); // setup the controls QLabel *showLabel = new QLabel(tr("Show"), c); cl->addWidget(showLabel); showHr = new QCheckBox(tr("Heart Rate"), this); showHr->setCheckState(Qt::Checked); cl->addWidget(showHr); showSpeed = new QCheckBox(tr("Speed"), this); showSpeed->setCheckState(Qt::Checked); cl->addWidget(showSpeed); showCad = new QCheckBox(tr("Cadence"), this); showCad->setCheckState(Qt::Checked); cl->addWidget(showCad); showPower = new QCheckBox(tr("Power"), this); showPower->setCheckState(Qt::Checked); cl->addWidget(showPower); showAlt = new QCheckBox(tr("Alternate Power"), this); showAlt->setCheckState(Qt::Checked); cl->addWidget(showAlt); showPow30s = new QCheckBox(tr("30s Power"), this); showPow30s->setCheckState(Qt::Checked); cl->addWidget(showPow30s); showSmO2 = new QCheckBox(tr("SmO2"), this); showSmO2->setCheckState(Qt::Checked); cl->addWidget(showSmO2); showtHb = new QCheckBox(tr("tHb"), this); showtHb->setCheckState(Qt::Checked); cl->addWidget(showtHb); showO2Hb = new QCheckBox(tr("O2Hb"), this); showO2Hb->setCheckState(Qt::Checked); cl->addWidget(showO2Hb); showHHb = new QCheckBox(tr("HHb"), this); showHHb->setCheckState(Qt::Checked); cl->addWidget(showHHb); QLabel *smoothLabel = new QLabel(tr("Smoothing (5Hz Samples)"), this); smoothLineEdit = new QLineEdit(this); smoothLineEdit->setFixedWidth(40); cl->addWidget(smoothLabel); cl->addWidget(smoothLineEdit); smoothSlider = new QSlider(Qt::Horizontal); smoothSlider->setTickPosition(QSlider::TicksBelow); smoothSlider->setTickInterval(10); smoothSlider->setMinimum(1); smoothSlider->setMaximum(150); smoothLineEdit->setValidator(new QIntValidator(smoothSlider->minimum(), smoothSlider->maximum(), smoothLineEdit)); cl->addWidget(smoothSlider); cl->addStretch(); QVBoxLayout *layout = new QVBoxLayout(this); rtPlot = new RealtimePlot(); layout->addWidget(rtPlot); // common controls connect(showPower, SIGNAL(stateChanged(int)), this, SLOT(setShowPower(int))); connect(showPow30s, SIGNAL(stateChanged(int)), this, SLOT(setShowPow30s(int))); connect(showHr, SIGNAL(stateChanged(int)), this, SLOT(setShowHr(int))); connect(showSpeed, SIGNAL(stateChanged(int)), this, SLOT(setShowSpeed(int))); connect(showCad, SIGNAL(stateChanged(int)), this, SLOT(setShowCad(int))); connect(showAlt, SIGNAL(stateChanged(int)), this, SLOT(setShowAlt(int))); connect(showSmO2, SIGNAL(stateChanged(int)), this, SLOT(setShowSmO2(int))); connect(showtHb, SIGNAL(stateChanged(int)), this, SLOT(setShowtHb(int))); connect(showO2Hb, SIGNAL(stateChanged(int)), this, SLOT(setShowO2Hb(int))); connect(showHHb, SIGNAL(stateChanged(int)), this, SLOT(setShowHHb(int))); connect(smoothSlider, SIGNAL(valueChanged(int)), this, SLOT(setSmoothingFromSlider())); connect(smoothLineEdit, SIGNAL(editingFinished()), this, SLOT(setSmoothingFromLineEdit())); // get updates.. connect(context, SIGNAL(telemetryUpdate(RealtimeData)), this, SLOT(telemetryUpdate(RealtimeData))); // lets initialise all the smoothing variables hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0; smo2tot = smo2index = thbtot = thbindex = o2hbtot = o2hbindex = hhbtot = hhbindex = 0; for(int i=0; i<150; i++) { powHist[i] = altHist[i] = spdHist[i] = cadHist[i] = hrHist[i] = 0; smo2Hist[i] = thbHist[i] = o2hbHist[i] = hhbHist[i] = 0; } // set to zero telemetryUpdate(RealtimeData()); } void RealtimePlotWindow::start() { // lets initialise all the smoothing variables hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0; smo2tot = smo2index = thbtot = thbindex = o2hbtot = o2hbindex = hhbtot = hhbindex = 0; for(int i=0; i<150; i++) { powHist[i] = altHist[i] = spdHist[i] = cadHist[i] = hrHist[i] = 0; smo2Hist[i] = thbHist[i] = o2hbHist[i] = hhbHist[i] = 0; } } void RealtimePlotWindow::stop() { // lets initialise all the smoothing variables hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0; smo2tot = smo2index = thbtot = thbindex = o2hbtot = o2hbindex = hhbtot = hhbindex = 0; for(int i=0; i<150; i++) { powHist[i] = altHist[i] = spdHist[i] = cadHist[i] = hrHist[i] = 0; smo2Hist[i] = thbHist[i] = o2hbHist[i] = hhbHist[i] = 0; } } void RealtimePlotWindow::pause() { } void RealtimePlotWindow::telemetryUpdate(RealtimeData rtData) { // lets apply smoothing if we have to if (rtPlot->smooth > 0) { // Heartrate double hr = rtData.value(RealtimeData::HeartRate); hrtot += hr; hrtot -= hrHist[hrindex]; hrHist[hrindex] = hr; hrindex++; if (hrindex >= rtPlot->smooth) hrindex = 0; hr = hrtot / rtPlot->smooth; rtPlot->hrData->addData(hr); // Speed double spd= rtData.value(RealtimeData::Speed); spdtot += spd; spdtot -= spdHist[spdindex]; spdHist[spdindex] = spd; spdindex++; if (spdindex >= rtPlot->smooth) spdindex = 0; spd = spdtot / rtPlot->smooth; if (!context->athlete->useMetricUnits) spd *= MILES_PER_KM; rtPlot->spdData->addData(spd); // Power double pow = rtData.value(RealtimeData::Watts); powtot += pow; powtot -= powHist[powindex]; powHist[powindex] = pow; powindex++; if (powindex >= rtPlot->smooth) powindex = 0; pow = powtot / rtPlot->smooth; rtPlot->pwrData->addData(pow); // Alternate Power double alt = rtData.value(RealtimeData::AltWatts); alttot += alt; alttot -= altHist[altindex]; altHist[altindex] = alt; altindex++; if (altindex >= rtPlot->smooth) altindex = 0; alt = alttot / rtPlot->smooth; rtPlot->altPwrData->addData(alt); // Cadence double cad = rtData.value(RealtimeData::Cadence); cadtot += cad; cadtot -= cadHist[cadindex]; cadHist[cadindex] = cad; cadindex++; if (cadindex >= rtPlot->smooth) cadindex = 0; cad = cadtot / rtPlot->smooth; rtPlot->cadData->addData(cad); // SmO2 double smo2 = rtData.value(RealtimeData::SmO2); smo2tot += smo2; smo2tot -= smo2Hist[smo2index]; smo2Hist[smo2index] = smo2; smo2index++; if (smo2index >= rtPlot->smooth) smo2index = 0; smo2 = smo2tot / rtPlot->smooth; rtPlot->smo2Data->addData(smo2); // tHb double thb = rtData.value(RealtimeData::tHb); thbtot += thb; thbtot -= thbHist[thbindex]; thbHist[thbindex] = thb; thbindex++; if (thbindex >= rtPlot->smooth) thbindex = 0; thb = thbtot / rtPlot->smooth; rtPlot->thbData->addData(thb); // O2Hb double o2hb = rtData.value(RealtimeData::O2Hb); o2hbtot += o2hb; o2hbtot -= o2hbHist[o2hbindex]; o2hbHist[o2hbindex] = o2hb; o2hbindex++; if (o2hbindex >= rtPlot->smooth) o2hbindex = 0; o2hb = o2hbtot / rtPlot->smooth; rtPlot->o2hbData->addData(o2hb); // HHb double hhb = rtData.value(RealtimeData::HHb); hhbtot += hhb; hhbtot -= hhbHist[hhbindex]; hhbHist[hhbindex] = hhb; hhbindex++; if (hhbindex >= rtPlot->smooth) hhbindex = 0; hhb = hhbtot / rtPlot->smooth; rtPlot->hhbData->addData(hhb); // its smoothed to 30s anyway rtPlot->pwr30Data->addData(rtData.value(RealtimeData::Watts)); } else { rtPlot->pwrData->addData(rtData.value(RealtimeData::Watts)); rtPlot->altPwrData->addData(rtData.value(RealtimeData::AltWatts)); rtPlot->pwr30Data->addData(rtData.value(RealtimeData::Watts)); rtPlot->cadData->addData(rtData.value(RealtimeData::Cadence)); rtPlot->spdData->addData(rtData.value(RealtimeData::Speed)); rtPlot->hrData->addData(rtData.value(RealtimeData::HeartRate)); rtPlot->smo2Data->addData(rtData.value(RealtimeData::SmO2)); rtPlot->thbData->addData(rtData.value(RealtimeData::tHb)); rtPlot->o2hbData->addData(rtData.value(RealtimeData::O2Hb)); rtPlot->hhbData->addData(rtData.value(RealtimeData::HHb)); } rtPlot->replot(); // redraw } void RealtimePlotWindow::setSmoothingFromSlider() { // active tells us we have been triggered by // the setSmoothingFromLineEdit which will also // recalculates smoothing, lets not double up... if (active) return; else active = true; if (rtPlot->smooth != smoothSlider->value()) { setSmoothing(smoothSlider->value()); smoothLineEdit->setText(QString("%1").arg(rtPlot->smooth)); } active = false; } void RealtimePlotWindow::setSmoothingFromLineEdit() { // active tells us we have been triggered by // the setSmoothingFromSlider which will also // recalculates smoothing, lets not double up... if (active) return; else active = true; int value = smoothLineEdit->text().toInt(); if (value != rtPlot->smooth) { smoothSlider->setValue(value); setSmoothing(value); } active = false; } void RealtimePlotWindow::setShowPow30s(int value) { showPow30s->setChecked(value); rtPlot->showPow30s(value); rtPlot->replot(); } void RealtimePlotWindow::setShowPower(int value) { showPower->setChecked(value); rtPlot->showPower(value); rtPlot->replot(); } void RealtimePlotWindow::setShowSmO2(int value) { showSmO2->setChecked(value); rtPlot->showSmO2(value); rtPlot->replot(); } void RealtimePlotWindow::setShowtHb(int value) { showtHb->setChecked(value); rtPlot->showtHb(value); rtPlot->replot(); } void RealtimePlotWindow::setShowO2Hb(int value) { showO2Hb->setChecked(value); rtPlot->showO2Hb(value); rtPlot->replot(); } void RealtimePlotWindow::setShowHHb(int value) { showHHb->setChecked(value); rtPlot->showHHb(value); rtPlot->replot(); } void RealtimePlotWindow::setShowHr(int value) { showHr->setChecked(value); rtPlot->showHr(value); rtPlot->replot(); } void RealtimePlotWindow::setShowSpeed(int value) { showSpeed->setChecked(value); rtPlot->showSpeed(value); rtPlot->replot(); } void RealtimePlotWindow::setShowCad(int value) { showCad->setChecked(value); rtPlot->showCad(value); rtPlot->replot(); } void RealtimePlotWindow::setShowAlt(int value) { showAlt->setChecked(value); rtPlot->showAlt(value); rtPlot->replot(); } void RealtimePlotWindow::setSmoothing(int value) { hrtot = hrindex = cadtot = cadindex = spdtot = spdindex = alttot = altindex = powtot = powindex = 0; smoothSlider->setValue(value); rtPlot->setSmoothing(value); }