From 405c1d2ddecc73a9041c6cab6d68d6cf7b3e6c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20T=C5=AFma?= Date: Thu, 15 Oct 2015 01:30:21 +0200 Subject: [PATCH] Use NMEA speed data if available Now using median speed filtering --- src/gpx.cpp | 40 +++++++++++++++++++++++++++++++--------- src/parser.cpp | 21 +++++++++++++++++++++ src/parser.h | 6 ++++++ src/speedgraph.cpp | 31 +++++++++++++++++++++---------- 4 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/gpx.cpp b/src/gpx.cpp index 6e8d5aeb..d68e9d86 100644 --- a/src/gpx.cpp +++ b/src/gpx.cpp @@ -3,9 +3,12 @@ #include "ll.h" #include "gpx.h" +#include + + +#define ALPHA 0.5 +#define WINDOW 5 -#define ALPHA_E 0.5 -#define ALPHA_S 0.1 bool GPX::loadFile(const QString &fileName) { @@ -38,14 +41,25 @@ void GPX::elevationGraph(QVector &graph) const for (int i = 1; i < _data.size(); i++) { dist += llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); dh = _data.at(i).elevation; - acc = (i == 1) ? dh : (ALPHA_E * dh) + (1.0 - ALPHA_E) * acc; + acc = (i == 1) ? dh : (ALPHA * dh) + (1.0 - ALPHA) * acc; graph.append(QPointF(dist, acc)); } } +static bool lt(const QPointF &p1, const QPointF &p2) +{ + return p1.y() < p2.y(); +} + +static qreal median(QVector v) +{ + qSort(v.begin(), v.end(), lt); + return v.at(v.size() / 2).y(); +} + void GPX::speedGraph(QVector &graph) const { - qreal dist = 0, v, ds, dt, acc; + qreal dist = 0, v, ds, dt; if (!_data.size()) return; @@ -54,13 +68,21 @@ void GPX::speedGraph(QVector &graph) const for (int i = 1; i < _data.size(); i++) { ds = llDistance(_data.at(i).coordinates, _data.at(i-1).coordinates); dt = _data.at(i-1).timestamp.msecsTo(_data.at(i).timestamp) / 1000.0; - if (dt == 0) - continue; dist += ds; - v = ds / dt; - acc = (i == 1) ? v : (ALPHA_S * v) + (1.0 - ALPHA_S) * acc; - graph.append(QPointF(dist, acc)); + + if (_data.at(i).speed < 0) { + if (dt == 0) + continue; + v = ds / dt; + } else + v = _data.at(i).speed; + + graph.append(QPointF(dist, v)); } + + if (graph.size() > WINDOW) + for (int i = WINDOW/2; i < graph.size() - WINDOW/2; i++) + graph[i].setY(median(graph.mid(i - WINDOW/2, WINDOW))); } void GPX::track(QVector &track) const diff --git a/src/parser.cpp b/src/parser.cpp index ab09335d..6fc1be6d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,5 +1,14 @@ #include "parser.h" +#include + + +void Parser::handleExtensionData(QVector &data, + QStringRef element, const QString &value) +{ + if (element == "speed") + data.last().speed = value.toDouble(); +} void Parser::handleTrekPointData(QVector &data, QStringRef element, const QString &value) @@ -19,11 +28,23 @@ void Parser::handleTrekPointAttributes(QVector &data, } +void Parser::extensions(QVector &data) +{ + while (_reader.readNextStartElement()) { + if (_reader.name() == "speed") + handleExtensionData(data, _reader.name(), _reader.readElementText()); + else + _reader.skipCurrentElement(); + } +} + void Parser::trekPointData(QVector &data) { while (_reader.readNextStartElement()) { if (_reader.name() == "ele" || _reader.name() == "time") handleTrekPointData(data, _reader.name(), _reader.readElementText()); + else if (_reader.name() == "extensions") + extensions(data); else _reader.skipCurrentElement(); } diff --git a/src/parser.h b/src/parser.h index 12dfb724..0f02b779 100644 --- a/src/parser.h +++ b/src/parser.h @@ -10,6 +10,9 @@ struct TrackPoint QPointF coordinates; QDateTime timestamp; qreal elevation; + qreal speed; + + TrackPoint() {speed = -1;} }; class Parser @@ -23,12 +26,15 @@ private: void gpx(QVector &data); void trek(QVector &data); void trekPoints(QVector &data); + void extensions(QVector &data); void trekPointData(QVector &data); void handleTrekPointAttributes(QVector &data, const QXmlStreamAttributes &attr); void handleTrekPointData(QVector &data, QStringRef element, const QString &value); + void handleExtensionData(QVector &data, QStringRef element, + const QString &value); QXmlStreamReader _reader; }; diff --git a/src/speedgraph.cpp b/src/speedgraph.cpp index 5399d4d8..9e378a5e 100644 --- a/src/speedgraph.cpp +++ b/src/speedgraph.cpp @@ -1,5 +1,7 @@ #include "speedgraph.h" +#include + SpeedGraph::SpeedGraph() { _max = 0; @@ -14,26 +16,35 @@ SpeedGraph::SpeedGraph() void SpeedGraph::loadData(const QVector &data) { - qreal max = 0, sum = 0, avg, distance, w; + qreal max = 0, sum = 0, w = 0, avg; + qreal dist; + + if (data.size() < 2) + return; + + dist = data.at(data.size() - 1).x() - data.at(0).x(); - distance = (data.at(data.size() - 1).x() - data.at(0).x()); for (int i = 1; i < data.size(); i++) { - qreal val = data.at(i).y(); + QPointF cur = data.at(i); + QPointF prev = data.at(i-1); + qreal ds = cur.x() - prev.x(); - sum += val; + if (cur.y() == 0) + continue; + sum += ds; + w += ds / cur.y(); - if (val > max) - max = val; + max = qMax(max, cur.y()); } - avg = sum / data.size(); + avg = sum / w; - _avg.append(QPointF(avg, distance)); + _avg.append(QPointF(dist, avg)); sum = 0; w = 0; for (QList::iterator it = _avg.begin(); it != _avg.end(); it++) { - sum += it->x() * it->y(); - w += it->y(); + sum += it->y() * it->x(); + w += it->x(); } avg = sum / w;