- worked on about everything - grid walker using plugable modules - wifi models - new distributions - worked on geometric data-structures - added typesafe timestamps - worked on grid-building - added sensor-classes - added sensor analysis (step-detection, turn-detection) - offline data reader - many test-cases
201 lines
4.3 KiB
C++
201 lines
4.3 KiB
C++
#ifndef OFFLINEANDROID_H
|
|
#define OFFLINEANDROID_H
|
|
|
|
#include <fstream>
|
|
#include <string>
|
|
|
|
#include "../../Assertions.h"
|
|
#include "../../math/Interpolator.h"
|
|
#include "../../geo/Point3.h"
|
|
#include "../../data/Timestamp.h"
|
|
#include "../radio/WiFiMeasurements.h"
|
|
|
|
template <typename SensorData> struct OfflineEntry {
|
|
|
|
Timestamp ts;
|
|
SensorData data;
|
|
|
|
/** ctor */
|
|
OfflineEntry(const Timestamp ts, const SensorData& data) : ts(ts), data(data) {;}
|
|
|
|
};
|
|
|
|
struct GroundTruthID {
|
|
int id;
|
|
GroundTruthID() {;}
|
|
GroundTruthID(const int id) : id(id) {;}
|
|
};
|
|
|
|
struct WalkedPath {
|
|
std::vector<Point3> pos_cm;
|
|
};
|
|
|
|
|
|
/** read recorded android sensor data files */
|
|
class OfflineAndroid {
|
|
|
|
|
|
private:
|
|
|
|
std::vector<OfflineEntry<WiFiMeasurements>> wifi;
|
|
std::vector<OfflineEntry<GroundTruthID>> groundTruth;
|
|
WalkedPath walkedPath;
|
|
|
|
public:
|
|
|
|
/** ctor */
|
|
OfflineAndroid(const std::string& file) {
|
|
parse(file);
|
|
}
|
|
|
|
/** get all ground truth readings */
|
|
const std::vector<OfflineEntry<GroundTruthID>>& getGroundTruth() const {return groundTruth;}
|
|
|
|
/** get all WiFi readings */
|
|
const std::vector<OfflineEntry<WiFiMeasurements>>& getWiFi() const {return wifi;}
|
|
|
|
/** get the walked path */
|
|
const WalkedPath& getWalkedPath() const {return walkedPath;}
|
|
|
|
/** get the interpolated walked path */
|
|
Interpolator<Timestamp, Point3> getWalkedPathInterpolatorCM() const {
|
|
Assert::equal(getWalkedPath().pos_cm.size(), getGroundTruth().size(), "entry-number mismatch!");
|
|
Interpolator<Timestamp, Point3> interpol;
|
|
for (const OfflineEntry<GroundTruthID>& entry : getGroundTruth()) {
|
|
interpol.add(entry.ts, getWalkedPath().pos_cm[entry.data.id]);
|
|
}
|
|
return interpol;
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
void parse(const std::string& file) {
|
|
|
|
// open the stream
|
|
std::ifstream inp(file);
|
|
|
|
// sanity check
|
|
if (!inp.is_open() || inp.bad() || inp.eof()) {throw Exception("failed to open " +file);}
|
|
|
|
// parse one line
|
|
while(!inp.eof()) {
|
|
|
|
// temporals
|
|
uint64_t ts;
|
|
char delim;
|
|
int32_t sensorID = 999999; // avoids issues with the last line
|
|
std::string sensorData;
|
|
|
|
// read from file
|
|
inp >> ts;
|
|
inp >> delim;
|
|
inp >> sensorID;
|
|
inp >> delim;
|
|
inp >> sensorData;
|
|
|
|
if (delim == 0) {break;}
|
|
|
|
parse(Timestamp::fromMS(ts), sensorID, sensorData);
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** parse the given data */
|
|
void parse(const Timestamp ts, const int32_t sensorID, const std::string& sensorData) {
|
|
|
|
// how to parse
|
|
switch(sensorID) {
|
|
case 8: {
|
|
OfflineEntry<WiFiMeasurements> entry(ts, parseWiFi(sensorData));
|
|
wifi.push_back(entry);
|
|
break;
|
|
}
|
|
case 99: {
|
|
OfflineEntry<GroundTruthID> entry (ts, parseGroundTruthTick(sensorData));
|
|
groundTruth.push_back(entry);
|
|
break;
|
|
}
|
|
case 100: {
|
|
walkedPath = parseWalkedPath(sensorData);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/** parse the given WiFiObservation string "MAC;freq;RSSI;MAC;freq;RSSI;...." */
|
|
static inline WiFiMeasurements parseWiFi(std::string data) {
|
|
|
|
WiFiMeasurements obs;
|
|
|
|
// process all APs
|
|
while(!data.empty()) {
|
|
|
|
const std::string mac = data.substr(0, 17);
|
|
data = data.substr(17);
|
|
assert(data[0] == ';'); data = data.substr(1);
|
|
|
|
const std::string freq = data.substr(0, 4);
|
|
data = data.substr(4);
|
|
assert(data[0] == ';'); data = data.substr(1);
|
|
|
|
const int pos = data.find(';');
|
|
const std::string rssi = data.substr(0, pos);
|
|
data = data.substr(pos);
|
|
assert(data[0] == ';'); data = data.substr(1);
|
|
|
|
const WiFiMeasurement e(mac, std::stof(rssi));
|
|
obs.entries.push_back(e);
|
|
|
|
}
|
|
|
|
return obs;
|
|
|
|
}
|
|
|
|
/** parse the given GroundTruth entry */
|
|
static inline GroundTruthID parseGroundTruthTick(const std::string& data) {
|
|
|
|
GroundTruthID id;
|
|
const int pos = data.find(';');
|
|
id.id = std::stoi(data.substr(0, pos));
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
/** parse the given WalkedPath string "x,y,z;x,y,z;x,y,..." */
|
|
static inline WalkedPath parseWalkedPath(std::string data) {
|
|
|
|
WalkedPath path;
|
|
|
|
// process all points
|
|
while(!data.empty()) {
|
|
|
|
const int pos1 = data.find(',');
|
|
const int pos2 = data.find(',', pos1+1);
|
|
const int pos3 = data.find(';', pos2+1);
|
|
|
|
const std::string x = data.substr(0, pos1);
|
|
const std::string y = data.substr(pos1+1, pos2-pos1-1);
|
|
const std::string z = data.substr(pos2+1, pos3-pos2-1);
|
|
|
|
path.pos_cm.push_back(Point3(std::stof(x), std::stof(y), std::stof(z)));
|
|
|
|
data = data.substr(pos3+1);
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif // OFFLINEANDROID_H
|