Enable import of XDATA series from CSV files (#3179)

* Enable import of XDATA series from CSV files
Since XDATA series are preserved across merges this allows to add
arbitrary XDATA series to any activity.
Sample WEATHER file is included for testing.
Sample swim file is also included, once imported set Sport=Swim and use
Fix Lap Swim with pool length=25 to rebuild standard series and laps
Fixes #2010 item 4.

* FixLapSwim - Alternative way to store pauses in XData
Some devices s.t. Moov Now generates a CSV with REST field
after each length. FixLapSwim now can use this alternative
way to express pauses and to mark end of laps.
This is intended to be used together with XDATA csv import.
A Moov Now csv file modified to comply with our format is
added as an example to test folder.
This commit is contained in:
Alejandro Martinez
2019-10-10 23:16:22 -03:00
committed by GitHub
parent 8b8ddccb5b
commit 0b0f99889e
6 changed files with 260 additions and 3 deletions

View File

@@ -129,6 +129,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors, QList<Ri
XDataSeries *trainSeries=NULL;
XDataSeries *rrSeries=NULL;
XDataSeries *ibikeSeries=NULL;
XDataSeries *xdataSeries=NULL;
/* Joule 1.0
Version,Date/Time,Km,Minutes,RPE,Tags,"Weight, kg","Work, kJ",FTP,"Sample Rate, s",Device Type,Firmware Version,Last Updated,Category 1,Category 2
@@ -163,6 +164,7 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors, QList<Ri
QRegExp rowproCSV("Date,Comment,Password,ID,Version,RowfileId,Rowfile_Id", Qt::CaseInsensitive);
QRegExp wahooMACSV("GroundContactTime,MotionCount,MotionPowerZ,Cadence,MotionPowerX,WorkoutActive,Timestamp,Smoothness,MotionPowerY,_ID,VerticalOscillation,", Qt::CaseInsensitive);
QRegExp rp3CSV ("\"id\",\"workout_interval_id\",\"ref\",\"stroke_number\",\"power\",\"avg_power\",\"stroke_rate\",\"time\",\"stroke_length\",\"distance\",\"distance_per_stroke\",\"estimated_500m_time\",\"energy_per_stroke\",\"energy_sum\",\"pulse\",\"work_per_pulse\",\"peak_force\",\"peak_force_pos\",\"rel_peak_force_pos\",\"drive_time\",\"recover_time\",\"k\",\"curve_data\",\"stroke_number_in_interval\",\"avg_calculated_power\"", Qt::CaseSensitive);
QRegExp xdataCSV ("XDATA: (\\w+)", Qt::CaseSensitive);
// X-trainer format
@@ -422,6 +424,19 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors, QList<Ri
rideFile->addXData("ROW", rowSeries);
} else if (xdataCSV.indexIn(line) != -1) {
csvType = xdata;
rideFile->setDeviceType("GoldenCheetah XData");
rideFile->setFileFormat("GoldenCheetah XData CSV (csv)");
unitsHeader = -1;
recInterval = 1; // may be variable
// add XDATA
xdataSeries = new XDataSeries();
xdataSeries->name = xdataCSV.cap(1);
++lineno;
continue;
} else if (line == "secs,km,power,hr,cad,alt") {
// OpenData CSV
@@ -1137,6 +1152,57 @@ RideFile *CsvFileReader::openRideFile(QFile &file, QStringList &errors, QList<Ri
rowSeries->datapoints.append(p);
}
} else if (csvType == xdata) {
// GoldenCheetah XDATA format with N series and M rows
// XDATA: Name
// SECS, KM, serie1[:units1], ..., seriesN[:unitsN]
// secs1, km1, value11, ..., value1N
// ...
// secsM, kmM, valueM1, ..., valueMN
if (lineno == 2) {
QStringList hds = line.split(",");
if (hds.count()>2 && hds[0]=="SECS" && hds[1]=="KM") {
QRegExp hd("(\\w+)(?::(\\w+))?");
for (int i=2; i<hds.count() && i<XDATA_MAXVALUES+2; i++) {
if (hd.indexIn(hds[i]) == -1) break;
xdataSeries->valuename << hd.cap(1);
xdataSeries->unitname << hd.cap(2);
}
rideFile->addXData(xdataSeries->name, xdataSeries);
} else {
delete xdataSeries;
xdataSeries = NULL;
}
} else if (xdataSeries != NULL) {
QStringList els = line.split(",", QString::KeepEmptyParts);
if (els.count() != xdataSeries->valuename.count()+2) continue;
// add ALL data series to XDATA
XDataPoint *p = new XDataPoint();
p->secs = els[0].toDouble();
p->km = els[1].toDouble();
for(int i=2; i<els.count(); i++) p->number[i-2] = els[i].toDouble();
xdataSeries->datapoints.append(p);
// only time and distance as standard series
rideFile->appendPoint(p->secs, // time in seconds
0, 0, // cad, hr
p->km, // distance (km)
0, 0, 0, 0, 0, 0, 0, 0,
-255, // temp
0, 0, 0, 0, 0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0, 0, 0, 0, 0, 0.0, 0);
}
} else if (csvType == opendata) {
// secs,km,power,hr,cad,alt

View File

@@ -23,7 +23,7 @@
#include "RideFile.h"
struct CsvFileReader : public RideFileReader {
enum csvtypes { generic, gc, powertap, joule, ergomo, motoactv, ibike, xtrain, moxy, freemotion, peripedal, cpexport, bsx, rowpro, wprime, wahooMA, rp3, opendata };
enum csvtypes { generic, gc, powertap, joule, ergomo, motoactv, ibike, xtrain, moxy, freemotion, peripedal, cpexport, bsx, rowpro, wprime, wahooMA, rp3, opendata, xdata };
typedef enum csvtypes CsvType;
virtual RideFile *openRideFile(QFile &file, QStringList &errors, QList<RideFile*>* = 0) const;

View File

@@ -136,7 +136,7 @@ FixLapSwim::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString o
XDataSeries *series = ride->xdata("SWIM");
if (!series || series->datapoints.isEmpty()) return false;
int typeIdx = -1, durationIdx = -1, strokesIdx = -1;
int typeIdx = -1, durationIdx = -1, strokesIdx = -1, restIdx = -1;
for (int a=0; a<series->valuename.count(); a++) {
if (series->valuename.at(a) == "TYPE")
typeIdx = a;
@@ -144,6 +144,8 @@ FixLapSwim::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString o
durationIdx = a;
else if (series->valuename.at(a) == "STROKES")
strokesIdx = a;
else if (series->valuename.at(a) == "REST")
restIdx = a;
}
// Stroke Type or Duration are mandatory, Strokes only to compute cadence
if (typeIdx == -1 || durationIdx == -1) return false;
@@ -219,13 +221,38 @@ FixLapSwim::postProcess(RideFile *ride, DataProcessorConfig *config=0, QString o
last_time += length_duration;
last_distance += length_distance;
if (length_distance == 0.0) interval++; // pauses mark laps
}
}
// Alternative way to mark pauses: Rest seconds after each length
if (restIdx>0 && p->number[restIdx]>0) {
QVector<struct RideFilePoint> newRows;
interval++; // pauses mark laps
for (int i=0; i<p->number[restIdx] && i<100*GarminHWM.toInt(); i++) {
double hr = hrdata.value(last_time + i, 0.0); // recover HR data
newRows << RideFilePoint(
last_time + i, 0.0, hr,
last_distance,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0,
RideFile::NA,RideFile::NA,
0.0, 0.0,0.0, 0.0,
0.0, 0.0,
0.0, 0.0,0.0, 0.0,
0.0, 0.0,0.0, 0.0,
0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
interval);
}
ride->command->appendPoints(newRows);
last_time += p->number[restIdx];
interval++; // pauses mark laps
}
}
// Update Rec. Interval, Pool Length, set data present and commit
ride->setRecIntSecs(1.0);
ride->setTag("Pool Length", QString("%1").arg(pl));
ride->setDataPresent(ride->km, true);
ride->setDataPresent(ride->kph, true);
ride->setDataPresent(ride->cad, strokesIdx>0);
ride->command->endLUW();

View File

@@ -0,0 +1,12 @@
XDATA: WEATHER,,,,,
SECS,KM,WINDSPEED:kmh,WINDHEADING,TEMPERATURE:celsius,HUMIDITY:%
1,0.00405,7.9992,90,5,93
901,6.78945,7.9992,70,5,91
1801,9.83493,7.9992,70,5,91
2701,17.0663,7.9992,70,5,91
3601,22.8818,7.9992,70,5,91
4501,27.7603,7.9992,70,5,91
5401,34.0975,7.9992,70,5,91
6301,42.4375,7.9992,70,5,91
7201,51.6657,10.0008,220,12,57
8093,59.3946,5.0004,0,7,93
1 XDATA: WEATHER
2 SECS KM WINDSPEED:kmh WINDHEADING TEMPERATURE:celsius HUMIDITY:%
3 1 0.00405 7.9992 90 5 93
4 901 6.78945 7.9992 70 5 91
5 1801 9.83493 7.9992 70 5 91
6 2701 17.0663 7.9992 70 5 91
7 3601 22.8818 7.9992 70 5 91
8 4501 27.7603 7.9992 70 5 91
9 5401 34.0975 7.9992 70 5 91
10 6301 42.4375 7.9992 70 5 91
11 7201 51.6657 10.0008 220 12 57
12 8093 59.3946 5.0004 0 7 93

View File

@@ -0,0 +1,48 @@
XDATA: SWIM
SECS,KM,TYPE,DURATION,TURN_TIME,SWIM_TIME,STROKES,REST
1 , 0, 1,39.78,8.78,31.00,16,0.00
2 , 0, 1,44.02,7.13,36.89,17,0.00
3 , 0, 1,41.54,8.37,33.17,15,0.00
4 , 0, 1,40.92,10.54,30.38,13,0.00
5 , 0, 3,49.29,10.23,39.06,13,0.00
6 , 0, 2,57.04,4.03,53.01,29,0.00
7 , 0, 2,54.87,0.00,41.54,22,0.00
8 , 0, 2,54.25,12.40,41.85,23,28.52
9 , 0, 1,22.32,0.00,22.32,11,43.40
10 , 0, 1,34.41,0.00,34.41,15,19.84
11 , 0, 1,30.38,0.00,30.38,13,31.62
12 , 0, 1,31.31,0.00,31.31,13,31.93
13 , 0, 1,32.86,0.00,32.86,14,33.17
14 , 0, 1,31.00,0.00,31.00,13,19.84
15 , 0, 2,41.54,0.00,41.54,23,22.94
16 , 0, 2,44.95,0.00,44.95,25,21.08
17 , 0, 2,55.65,10.70,44.95,24,0.00
18 , 0, 1,50.53,11.78,38.75,16,0.00
19 , 0, 1,60.76,0.00,46.19,16,30.69
20 , 0, 1,42.78,0.00,42.78,15,27.59
21 , 0, 1,34.41,0.00,34.41,13,24.49
22 , 0, 1,33.79,0.00,33.79,13,29.45
23 , 0, 1,33.48,0.00,33.48,13,21.08
24 , 0, 1,33.79,0.00,33.79,13,20.15
25 , 0, 2,56.42,9.92,46.50,24,0.00
26 , 0, 2,57.04,9.92,47.12,23,19.53
27 , 0, 1,34.72,0.00,34.72,14,19.53
28 , 0, 1,39.68,0.00,39.68,15,44.95
29 , 0, 1,39.99,0.00,39.99,16,17.98
30 , 0, 1,37.51,0.00,37.51,14,24.18
31 , 0, 1,36.58,0.00,36.58,14,25.73
32 , 0, 1,35.03,0.00,35.03,13,34.41
33 , 0, 1,32.55,0.00,32.55,14,16.74
34 , 0, 2,46.50,0.00,46.50,25,0.00
35 , 0, 2,61.07,0.00,45.57,24,19.84
36 , 0, 1,32.55,0.00,32.55,13,33.79
37 , 0, 1,35.34,0.00,35.34,14,21.70
38 , 0, 1,31.62,0.00,31.62,11,27.59
39 , 0, 1,47.12,10.85,36.27,13,0.00
40 , 0, 1,49.29,10.85,38.44,14,32.55
41 , 0, 1,32.24,0.00,32.24,13,18.60
42 , 0, 1,45.26,10.54,34.72,14,0.00
43 , 0, 3,51.77,0.00,38.13,16,0.00
44 , 0, 2,57.35,10.54,46.81,25,16.74
45 , 0, 1,36.27,0.00,36.27,14,25.11
46 , 0, 1,31.93,0.00,31.93,12,0.00
1 XDATA: SWIM
2 SECS,KM,TYPE,DURATION,TURN_TIME,SWIM_TIME,STROKES,REST
3 1 , 0, 1,39.78,8.78,31.00,16,0.00
4 2 , 0, 1,44.02,7.13,36.89,17,0.00
5 3 , 0, 1,41.54,8.37,33.17,15,0.00
6 4 , 0, 1,40.92,10.54,30.38,13,0.00
7 5 , 0, 3,49.29,10.23,39.06,13,0.00
8 6 , 0, 2,57.04,4.03,53.01,29,0.00
9 7 , 0, 2,54.87,0.00,41.54,22,0.00
10 8 , 0, 2,54.25,12.40,41.85,23,28.52
11 9 , 0, 1,22.32,0.00,22.32,11,43.40
12 10 , 0, 1,34.41,0.00,34.41,15,19.84
13 11 , 0, 1,30.38,0.00,30.38,13,31.62
14 12 , 0, 1,31.31,0.00,31.31,13,31.93
15 13 , 0, 1,32.86,0.00,32.86,14,33.17
16 14 , 0, 1,31.00,0.00,31.00,13,19.84
17 15 , 0, 2,41.54,0.00,41.54,23,22.94
18 16 , 0, 2,44.95,0.00,44.95,25,21.08
19 17 , 0, 2,55.65,10.70,44.95,24,0.00
20 18 , 0, 1,50.53,11.78,38.75,16,0.00
21 19 , 0, 1,60.76,0.00,46.19,16,30.69
22 20 , 0, 1,42.78,0.00,42.78,15,27.59
23 21 , 0, 1,34.41,0.00,34.41,13,24.49
24 22 , 0, 1,33.79,0.00,33.79,13,29.45
25 23 , 0, 1,33.48,0.00,33.48,13,21.08
26 24 , 0, 1,33.79,0.00,33.79,13,20.15
27 25 , 0, 2,56.42,9.92,46.50,24,0.00
28 26 , 0, 2,57.04,9.92,47.12,23,19.53
29 27 , 0, 1,34.72,0.00,34.72,14,19.53
30 28 , 0, 1,39.68,0.00,39.68,15,44.95
31 29 , 0, 1,39.99,0.00,39.99,16,17.98
32 30 , 0, 1,37.51,0.00,37.51,14,24.18
33 31 , 0, 1,36.58,0.00,36.58,14,25.73
34 32 , 0, 1,35.03,0.00,35.03,13,34.41
35 33 , 0, 1,32.55,0.00,32.55,14,16.74
36 34 , 0, 2,46.50,0.00,46.50,25,0.00
37 35 , 0, 2,61.07,0.00,45.57,24,19.84
38 36 , 0, 1,32.55,0.00,32.55,13,33.79
39 37 , 0, 1,35.34,0.00,35.34,14,21.70
40 38 , 0, 1,31.62,0.00,31.62,11,27.59
41 39 , 0, 1,47.12,10.85,36.27,13,0.00
42 40 , 0, 1,49.29,10.85,38.44,14,32.55
43 41 , 0, 1,32.24,0.00,32.24,13,18.60
44 42 , 0, 1,45.26,10.54,34.72,14,0.00
45 43 , 0, 3,51.77,0.00,38.13,16,0.00
46 44 , 0, 2,57.35,10.54,46.81,25,16.74
47 45 , 0, 1,36.27,0.00,36.27,14,25.11
48 46 , 0, 1,31.93,0.00,31.93,12,0.00

View File

@@ -0,0 +1,104 @@
XDATA: SWIM
SECS,KM,TYPE,DURATION:secs,STROKES
0,0,1,26.5,11
26,0.025,1,26.562,11
53,0.05,1,26.125,11
79,0.075,1,26.625,12
105,0.1,1,25.5,10
131,0.125,1,26.875,12
158,0.15,1,25.125,11
183,0.175,1,23.84,11
207,0.2,0,37.003,0
246,0.2,1,24.062,10
270,0.225,1,26.5,11
296,0.25,1,25.625,12
322,0.275,1,24.187,11
346,0.3,1,24,11
370,0.325,1,26.812,12
397,0.35,1,25,10
422,0.375,1,21.756,11
444,0.4,0,37.678,0
481,0.4,1,24.437,10
506,0.425,1,23.5,11
529,0.45,1,24.812,11
554,0.475,1,25.5,12
580,0.5,1,24.375,11
604,0.525,1,25.25,13
629,0.55,1,24,10
653,0.575,1,21.433,11
675,0.6,0,32.484,0
707,0.6,1,24.812,10
732,0.625,1,23.812,12
756,0.65,1,24.625,11
780,0.675,1,25,11
805,0.7,1,24.437,11
830,0.725,1,25.875,12
856,0.75,1,25.562,14
881,0.775,1,22.578,10
904,0.8,0,27.316,0
931,0.8,1,24.437,10
956,0.825,1,24.437,12
980,0.85,1,23.5,12
1003,0.875,1,27.5,13
1031,0.9,1,23.187,11
1054,0.925,1,24.875,12
1079,0.95,1,24.5,12
1104,0.975,1,21.435,11
1125,1,0,564.684,0
1690,1,1,25.687,10
1715,1.025,1,22.375,11
1738,1.05,1,25,13
1763,1.075,1,24.25,12
1787,1.1,1,21.427,12
1808,1.125,0,33.911,0
1842,1.125,1,25.187,11
1867,1.15,1,24.25,11
1892,1.175,1,25.375,11
1917,1.2,1,25,12
1942,1.225,1,19.08,11
1961,1.25,0,30.837,0
1992,1.25,1,25.062,11
2017,1.275,1,25.375,13
2042,1.3,1,23.75,13
2066,1.325,1,25.437,11
2092,1.35,1,20.867,12
2113,1.375,0,31.266,0
2144,1.375,1,24,12
2168,1.4,1,25.312,12
2193,1.425,1,23.687,12
2217,1.45,1,24,12
2241,1.475,1,21.06,12
2262,1.5,0,31.053,0
2293,1.5,1,24.312,11
2317,1.525,1,25,13
2342,1.55,1,22.75,13
2365,1.575,1,24.75,13
2390,1.6,1,22.443,12
2412,1.625,0,29.42,0
2442,1.625,1,24,11
2466,1.65,1,23.812,13
2489,1.675,1,25.75,13
2515,1.7,1,25.375,13
2540,1.725,1,21.358,12
2562,1.75,0,27.151,0
2589,1.75,1,25.625,11
2615,1.775,1,23.312,12
2638,1.8,1,24.312,13
2662,1.825,1,25.375,13
2688,1.85,1,21.275,12
2709,1.875,0,29.959,0
2739,1.875,1,24.187,12
2763,1.9,1,25.062,12
2788,1.925,1,24.562,12
2813,1.95,1,25.125,13
2838,1.975,1,22.26,12
2860,2,0,66.925,0
2927,2,1,30.312,12
2957,2.025,1,31.812,14
2989,2.05,1,29.625,12
3019,2.075,1,30.687,14
3049,2.1,1,29.375,14
3079,2.125,1,31.125,14
3110,2.15,1,27.187,12
3137,2.175,1,26.583,12
3164,2.2,0,40.065,0
1 XDATA: SWIM
2 SECS,KM,TYPE,DURATION:secs,STROKES
3 0,0,1,26.5,11
4 26,0.025,1,26.562,11
5 53,0.05,1,26.125,11
6 79,0.075,1,26.625,12
7 105,0.1,1,25.5,10
8 131,0.125,1,26.875,12
9 158,0.15,1,25.125,11
10 183,0.175,1,23.84,11
11 207,0.2,0,37.003,0
12 246,0.2,1,24.062,10
13 270,0.225,1,26.5,11
14 296,0.25,1,25.625,12
15 322,0.275,1,24.187,11
16 346,0.3,1,24,11
17 370,0.325,1,26.812,12
18 397,0.35,1,25,10
19 422,0.375,1,21.756,11
20 444,0.4,0,37.678,0
21 481,0.4,1,24.437,10
22 506,0.425,1,23.5,11
23 529,0.45,1,24.812,11
24 554,0.475,1,25.5,12
25 580,0.5,1,24.375,11
26 604,0.525,1,25.25,13
27 629,0.55,1,24,10
28 653,0.575,1,21.433,11
29 675,0.6,0,32.484,0
30 707,0.6,1,24.812,10
31 732,0.625,1,23.812,12
32 756,0.65,1,24.625,11
33 780,0.675,1,25,11
34 805,0.7,1,24.437,11
35 830,0.725,1,25.875,12
36 856,0.75,1,25.562,14
37 881,0.775,1,22.578,10
38 904,0.8,0,27.316,0
39 931,0.8,1,24.437,10
40 956,0.825,1,24.437,12
41 980,0.85,1,23.5,12
42 1003,0.875,1,27.5,13
43 1031,0.9,1,23.187,11
44 1054,0.925,1,24.875,12
45 1079,0.95,1,24.5,12
46 1104,0.975,1,21.435,11
47 1125,1,0,564.684,0
48 1690,1,1,25.687,10
49 1715,1.025,1,22.375,11
50 1738,1.05,1,25,13
51 1763,1.075,1,24.25,12
52 1787,1.1,1,21.427,12
53 1808,1.125,0,33.911,0
54 1842,1.125,1,25.187,11
55 1867,1.15,1,24.25,11
56 1892,1.175,1,25.375,11
57 1917,1.2,1,25,12
58 1942,1.225,1,19.08,11
59 1961,1.25,0,30.837,0
60 1992,1.25,1,25.062,11
61 2017,1.275,1,25.375,13
62 2042,1.3,1,23.75,13
63 2066,1.325,1,25.437,11
64 2092,1.35,1,20.867,12
65 2113,1.375,0,31.266,0
66 2144,1.375,1,24,12
67 2168,1.4,1,25.312,12
68 2193,1.425,1,23.687,12
69 2217,1.45,1,24,12
70 2241,1.475,1,21.06,12
71 2262,1.5,0,31.053,0
72 2293,1.5,1,24.312,11
73 2317,1.525,1,25,13
74 2342,1.55,1,22.75,13
75 2365,1.575,1,24.75,13
76 2390,1.6,1,22.443,12
77 2412,1.625,0,29.42,0
78 2442,1.625,1,24,11
79 2466,1.65,1,23.812,13
80 2489,1.675,1,25.75,13
81 2515,1.7,1,25.375,13
82 2540,1.725,1,21.358,12
83 2562,1.75,0,27.151,0
84 2589,1.75,1,25.625,11
85 2615,1.775,1,23.312,12
86 2638,1.8,1,24.312,13
87 2662,1.825,1,25.375,13
88 2688,1.85,1,21.275,12
89 2709,1.875,0,29.959,0
90 2739,1.875,1,24.187,12
91 2763,1.9,1,25.062,12
92 2788,1.925,1,24.562,12
93 2813,1.95,1,25.125,13
94 2838,1.975,1,22.26,12
95 2860,2,0,66.925,0
96 2927,2,1,30.312,12
97 2957,2.025,1,31.812,14
98 2989,2.05,1,29.625,12
99 3019,2.075,1,30.687,14
100 3049,2.1,1,29.375,14
101 3079,2.125,1,31.125,14
102 3110,2.15,1,27.187,12
103 3137,2.175,1,26.583,12
104 3164,2.2,0,40.065,0