/** ****************************************************************************** * * @file plotdata.cpp * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. * @addtogroup GCSPlugins GCS Plugins * @{ * @addtogroup ScopePlugin Scope Gadget Plugin * @{ * @brief The scope Gadget, graphically plots the states of UAVObjects *****************************************************************************/ /* * 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 3 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., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "plotdata.h" #include #include PlotData::PlotData(QString p_uavObject, QString p_uavField) { uavObject = p_uavObject; if (p_uavField.contains("-")) { QStringList fieldSubfield = p_uavField.split("-", QString::SkipEmptyParts); uavField = fieldSubfield.at(0); uavSubField = fieldSubfield.at(1); haveSubField = true; } else { uavField = p_uavField; haveSubField = false; } xData = new QVector(); yData = new QVector(); yDataHistory = new QVector(); curve = 0; scalePower = 0; meanSamples = 1; meanSum = 0.0f; // mathFunction=0; correctionSum = 0.0f; correctionCount = 0; yMinimum = 0; yMaximum = 0; m_xWindowSize = 0; } double PlotData::valueAsDouble(UAVObject *obj, UAVObjectField *field) { Q_UNUSED(obj); QVariant value; if (haveSubField) { int indexOfSubField = field->getElementNames().indexOf(QRegExp(uavSubField, Qt::CaseSensitive, QRegExp::FixedString)); value = field->getValue(indexOfSubField); } else { value = field->getValue(); } // qDebug() << "Data (" << value.typeName() << ") " << value.toString(); return value.toDouble(); } PlotData::~PlotData() { delete xData; delete yData; delete yDataHistory; } bool SequentialPlotData::append(UAVObject *obj) { if (uavObject == obj->getName()) { // Get the field of interest UAVObjectField *field = obj->getField(uavField); if (field) { double currentValue = valueAsDouble(obj, field) * pow(10, scalePower); // Perform scope math, if necessary if (mathFunction == "Boxcar average" || mathFunction == "Standard deviation") { // Put the new value at the front yDataHistory->append(currentValue); // calculate average value meanSum += currentValue; if (yDataHistory->size() > meanSamples) { meanSum -= yDataHistory->first(); yDataHistory->pop_front(); } // make sure to correct the sum every meanSamples steps to prevent it // from running away due to floating point rounding errors correctionSum += currentValue; if (++correctionCount >= meanSamples) { meanSum = correctionSum; correctionSum = 0.0f; correctionCount = 0; } double boxcarAvg = meanSum / yDataHistory->size(); if (mathFunction == "Standard deviation") { // Calculate square of sample standard deviation, with Bessel's correction double stdSum = 0; for (int i = 0; i < yDataHistory->size(); i++) { stdSum += pow(yDataHistory->at(i) - boxcarAvg, 2) / (meanSamples - 1); } yData->append(sqrt(stdSum)); } else { yData->append(boxcarAvg); } } else { yData->append(currentValue); } if (yData->size() > m_xWindowSize) { // If new data overflows the window, remove old data... yData->pop_front(); } else { // ...otherwise, add a new y point at position xData xData->insert(xData->size(), xData->size()); } // notify the gui of changes in the data // dataChanged(); return true; } } return false; } bool ChronoPlotData::append(UAVObject *obj) { if (uavObject == obj->getName()) { // Get the field of interest UAVObjectField *field = obj->getField(uavField); // qDebug() << "uavObject: " << uavObject << ", uavField: " << uavField; if (field) { QDateTime NOW = QDateTime::currentDateTime(); // THINK ABOUT REIMPLEMENTING THIS TO SHOW UAVO TIME, NOT SYSTEM TIME double currentValue = valueAsDouble(obj, field) * pow(10, scalePower); // Perform scope math, if necessary if (mathFunction == "Boxcar average" || mathFunction == "Standard deviation") { // Put the new value at the back yDataHistory->append(currentValue); // calculate average value meanSum += currentValue; if (yDataHistory->size() > meanSamples) { meanSum -= yDataHistory->first(); yDataHistory->pop_front(); } // make sure to correct the sum every meanSamples steps to prevent it // from running away due to floating point rounding errors correctionSum += currentValue; if (++correctionCount >= meanSamples) { meanSum = correctionSum; correctionSum = 0.0f; correctionCount = 0; } double boxcarAvg = meanSum / yDataHistory->size(); // qDebug()<size(); i++) { stdSum += pow(yDataHistory->at(i) - boxcarAvg, 2) / (meanSamples - 1); } yData->append(sqrt(stdSum)); } else { yData->append(boxcarAvg); } } else { yData->append(currentValue); } double valueX = NOW.toTime_t() + NOW.time().msec() / 1000.0; xData->append(valueX); // qDebug() << "Data " << uavObject << "." << field->getName() << " X,Y:" << valueX << "," << valueY; // Remove stale data removeStaleData(); // notify the gui of chages in the data // dataChanged(); return true; } } return false; } void ChronoPlotData::removeStaleData() { double newestValue; double oldestValue; while (1) { if (xData->size() == 0) { break; } newestValue = xData->last(); oldestValue = xData->first(); if (newestValue - oldestValue > m_xWindowSize) { yData->pop_front(); xData->pop_front(); } else { break; } } // qDebug() << "removeStaleData "; } void ChronoPlotData::removeStaleDataTimeout() { removeStaleData(); // dataChanged(); // qDebug() << "removeStaleDataTimeout"; } bool UAVObjectPlotData::append(UAVObject *obj) { Q_UNUSED(obj); return false; }