huge commit
- 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
This commit is contained in:
18
sensors/pressure/BarometerData.h
Normal file
18
sensors/pressure/BarometerData.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef BAROMETERDATA_H
|
||||
#define BAROMETERDATA_H
|
||||
|
||||
|
||||
#include <cmath>
|
||||
|
||||
/** data received from a barometer sensor */
|
||||
struct BarometerData {
|
||||
|
||||
float hPa;
|
||||
|
||||
explicit BarometerData() : hPa(0) {;}
|
||||
|
||||
explicit BarometerData(const float hPa) : hPa(hPa) {;}
|
||||
|
||||
};
|
||||
|
||||
#endif // BAROMETERDATA_H
|
||||
227
sensors/pressure/PressureTendence.h
Normal file
227
sensors/pressure/PressureTendence.h
Normal file
@@ -0,0 +1,227 @@
|
||||
#ifndef PRESSURETENDENCE_H
|
||||
#define PRESSURETENDENCE_H
|
||||
|
||||
#include "../../data/Timestamp.h"
|
||||
#include "../../math/MovingAVG.h"
|
||||
#include "../../math/MovingMedian.h"
|
||||
#include "../../math/Median.h"
|
||||
|
||||
#include "BarometerData.h"
|
||||
|
||||
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class PressureTendence {
|
||||
|
||||
private:
|
||||
|
||||
/** barometer history entries (timestamp -> value) */
|
||||
struct History {
|
||||
Timestamp ts;
|
||||
BarometerData data;
|
||||
History(const Timestamp ts, const BarometerData data) : ts(ts), data(data) {;}
|
||||
};
|
||||
|
||||
Timestamp timeframe;
|
||||
|
||||
std::vector<History> history;
|
||||
|
||||
public:
|
||||
|
||||
enum class Type {
|
||||
STRONG_MOVING_UPWARDS,
|
||||
MOVING_UPWARDS,
|
||||
NO_CHANGE,
|
||||
MOVING_DOWNWARDS,
|
||||
STRONG_MOVING_DOWNWARDS,
|
||||
};
|
||||
|
||||
struct Debug {
|
||||
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot plot;
|
||||
|
||||
K::GnuplotPlotElementLines raw;
|
||||
K::GnuplotPlotElementLines avg;
|
||||
K::GnuplotPlotElementLines tendence;
|
||||
|
||||
Debug() {
|
||||
plot.add(&raw); raw.setColorHex("#999999");
|
||||
plot.add(&avg); avg.setColorHex("#000000");
|
||||
plot.add(&tendence); tendence.setLineWidth(2);
|
||||
tendence.setCustomAttr(" axes x1y2 ");
|
||||
gp << "set y2tics\n";
|
||||
gp << "set y2range[-0.3:+0.3]\n";
|
||||
}
|
||||
|
||||
void addRaw(Timestamp ts, float val) {
|
||||
raw.add(K::GnuplotPoint2(ts.ms(), val));
|
||||
}
|
||||
|
||||
void addAvg(Timestamp ts, float val) {
|
||||
avg.add(K::GnuplotPoint2(ts.ms(), val));
|
||||
}
|
||||
|
||||
void addTendence(Timestamp ts, float val) {
|
||||
tendence.add(K::GnuplotPoint2(ts.ms(), val));
|
||||
}
|
||||
|
||||
void show() {
|
||||
static int cnt = 0;
|
||||
if (++cnt % 4 == 0) {
|
||||
gp.draw(plot);
|
||||
gp.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Debug debug;
|
||||
|
||||
|
||||
/** ctor with the timeframe to use. 1.0 sec should be fine */
|
||||
PressureTendence(const Timestamp timeframe) : timeframe(timeframe) {
|
||||
|
||||
}
|
||||
|
||||
/** add new sensor readings that were received at the given timestamp */
|
||||
void add(const Timestamp& ts, const BarometerData& baro) {
|
||||
|
||||
static MovingAVG<float> avg(5);
|
||||
avg.add(baro.hPa);
|
||||
|
||||
debug.addRaw(ts, baro.hPa);
|
||||
debug.addAvg(ts, avg.get());
|
||||
debug.show();
|
||||
|
||||
// add to the history
|
||||
//history.push_back(History(ts, baro));
|
||||
history.push_back(History(ts, BarometerData(avg.get())));
|
||||
|
||||
// remove too old values
|
||||
while( (ts - history[0].ts) > Timestamp::fromMS(2000)) {history.erase(history.begin());}
|
||||
|
||||
}
|
||||
|
||||
/** get the current tendence */
|
||||
float get() {
|
||||
|
||||
// static MovingAVG<float> avg(3);
|
||||
|
||||
if (history.empty()) {return 0;}
|
||||
|
||||
// const float tendence = history.back().data.hPa - history.front().data.hPa;
|
||||
// avg.add(tendence);
|
||||
|
||||
// debug.addTendence(history.back().ts, avg.get());
|
||||
|
||||
// return tendence;
|
||||
|
||||
|
||||
// const int ws = 5;
|
||||
|
||||
// if (history.size() < (ws+1)) {return 0;}
|
||||
|
||||
// const int s = history.size() - 1;
|
||||
|
||||
// bool rising = true;
|
||||
// for (int i = s-ws; i < s; ++i) {
|
||||
// if (history[i+0].data.hPa >= history[i+1].data.hPa) {rising = false; break;}
|
||||
// }
|
||||
|
||||
// bool falling = true;
|
||||
// for (int i = s-ws; i < s; ++i) {
|
||||
// if (history[i+0].data.hPa <= history[i+1].data.hPa) {falling = false; break;}
|
||||
// }
|
||||
|
||||
// float tendence = 0;
|
||||
// if (rising) {tendence = +0.1;}
|
||||
// if (falling) {tendence = -0.1;}
|
||||
|
||||
|
||||
float tendence = 0;
|
||||
|
||||
|
||||
|
||||
// if (delta > +0.1) {tendence = +0.1;}
|
||||
// if (delta < -0.1) {tendence = -0.1;}
|
||||
|
||||
int numUp = 0;
|
||||
int numDown = 0;
|
||||
|
||||
float slopeSum = 0;
|
||||
float slopeUp = 0;
|
||||
float slopeDown = 0;
|
||||
|
||||
int cnt=0;
|
||||
|
||||
for (int i = 0; i < history.size() - 1; ++i) {
|
||||
if (history[i+0].data.hPa < history[i+1].data.hPa) {++numUp;} else {++numDown;}
|
||||
const float slope = history[i+0].data.hPa - history[i+1].data.hPa;
|
||||
slopeSum += slope;
|
||||
if (slope > 0) {slopeUp += slope;}
|
||||
if (slope < 0) {slopeDown += slope;}
|
||||
++cnt;
|
||||
}
|
||||
|
||||
//tendence = (numUp-numDown)/((float)cnt)/10.0f;
|
||||
tendence = (std::abs(slopeUp) - std::abs(slopeDown)) ;
|
||||
//slopeSum /= cnt;
|
||||
|
||||
|
||||
// const float sd = std::abs(slopeUp) - std::abs(slopeDown);
|
||||
// tendence = sd;
|
||||
// if (std::abs(sd) > 0.07) {
|
||||
// tendence = 0.1;
|
||||
// }
|
||||
|
||||
// const int delta = numUp - numDown;
|
||||
// if (std::abs(delta) > cnt*0.3) {
|
||||
// if (delta < 0) {tendence = -0.1;}
|
||||
// if (delta > 0) {tendence = +0.1;}
|
||||
// }
|
||||
|
||||
//if (std::abs(deltaP) < 0.005) {tendence = 0;}
|
||||
|
||||
|
||||
// const float delta = history.front().data.hPa - history.back().data.hPa;
|
||||
// tendence = delta > 0.15;
|
||||
|
||||
debug.addTendence(history.back().ts, tendence);
|
||||
|
||||
|
||||
|
||||
|
||||
return tendence;
|
||||
|
||||
|
||||
// const int avgSize = 7;
|
||||
|
||||
// if (history.size() < avgSize) {return 0;}
|
||||
|
||||
// Median<float> hPa1;
|
||||
// Median<float> hPa2;
|
||||
|
||||
// int s = history.size() - 1;
|
||||
|
||||
// for (int i = 0; i < avgSize; ++i) {
|
||||
// hPa1.add(history[0+i].data.hPa);
|
||||
// hPa2.add(history[s-i].data.hPa);
|
||||
// }
|
||||
|
||||
// const float diff = (hPa2.get()) - (hPa1.get());
|
||||
// return diff;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // PRESSURETENDENCE_H
|
||||
139
sensors/pressure/RelativePressure.h
Normal file
139
sensors/pressure/RelativePressure.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#ifndef BAROMETER_H
|
||||
#define BAROMETER_H
|
||||
|
||||
#include "../../data/Timestamp.h"
|
||||
#include "../../math/MovingAVG.h"
|
||||
|
||||
#include "BarometerData.h"
|
||||
|
||||
/**
|
||||
* calculates the pressure realtive to a startup-calibration of a barometer
|
||||
* hereafter all returned values are relative to the calibration
|
||||
*
|
||||
*/
|
||||
class RelativePressure {
|
||||
|
||||
private:
|
||||
|
||||
/** barometer history entries (timestamp -> value) */
|
||||
struct History {
|
||||
Timestamp ts;
|
||||
BarometerData data;
|
||||
History(const Timestamp ts, const BarometerData data) : ts(ts), data(data) {;}
|
||||
};
|
||||
|
||||
/** barometer calibration helper */
|
||||
struct Calibration {
|
||||
|
||||
Timestamp neededTimeframe = Timestamp::fromMS(5000);
|
||||
|
||||
std::vector<History> history;
|
||||
bool isCalibrated = false;
|
||||
float baseAvg = 0;
|
||||
float sigma = 0;
|
||||
|
||||
// prevent sensor-startup-issues and skip the first 25% of measurement values
|
||||
float skipStart = 0.25;
|
||||
|
||||
void tryToCalibrate() {
|
||||
|
||||
// determine the timeframe contained within the history
|
||||
const Timestamp timeframe = history.back().ts - history.front().ts;
|
||||
|
||||
// do we have enough values to perform a calibration?
|
||||
if (timeframe < neededTimeframe) {return;}
|
||||
|
||||
// we need double as float would lead to huge rounding errors!
|
||||
double sum = 0;
|
||||
double sum2 = 0;
|
||||
int cnt = 0;
|
||||
|
||||
// calculate sum and sum²
|
||||
for (int i = (int)(skipStart*history.size()); i < (int)history.size(); ++i) {
|
||||
const History& h = history[i];
|
||||
sum += h.data.hPa;
|
||||
sum2 += ((double)h.data.hPa * (double)h.data.hPa);
|
||||
++cnt;
|
||||
}
|
||||
|
||||
// calculate E(x) and E(x²)
|
||||
double avg = sum / (double)cnt;
|
||||
double avg2 = sum2 / (double)cnt;
|
||||
|
||||
// set calibrated values
|
||||
this->baseAvg = avg;
|
||||
this->sigma = std::sqrt( avg2 - (avg*avg) );
|
||||
this->isCalibrated = true;
|
||||
|
||||
}
|
||||
|
||||
void reset() {
|
||||
history.clear();
|
||||
isCalibrated = false;
|
||||
sigma = 0;
|
||||
baseAvg = 0;
|
||||
}
|
||||
|
||||
} calib;
|
||||
|
||||
float latesthPa;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
RelativePressure() {
|
||||
|
||||
}
|
||||
|
||||
/** set the timeframe used for the startup calibration (e.g. 5 seconds) */
|
||||
void setCalibrationTimeframe(const Timestamp timeframe) {
|
||||
this->calib.neededTimeframe = timeframe;
|
||||
}
|
||||
|
||||
/** add new sensor readings that were received at the given timestamp */
|
||||
void add(const Timestamp& ts, const BarometerData& baro) {
|
||||
|
||||
// perform calibration?
|
||||
if (!calib.isCalibrated) {
|
||||
calib.history.push_back(History(ts, baro));
|
||||
calib.tryToCalibrate();
|
||||
}
|
||||
|
||||
// most recent pressure reading
|
||||
latesthPa = baro.hPa;
|
||||
|
||||
}
|
||||
|
||||
/** get the most recent pressure reading realtive to the startup calibration. returns 0 until the sensor is calibrated */
|
||||
float getPressureRealtiveToStart() {
|
||||
if (calib.isCalibrated) {
|
||||
return latesthPa - calib.baseAvg;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** reset the sensor's calibration */
|
||||
void reset() {
|
||||
calib.reset();
|
||||
}
|
||||
|
||||
/** get the barometer's calibrated uncertainty determined during the startup calibration */
|
||||
float getSigma() {
|
||||
return calib.sigma;
|
||||
}
|
||||
|
||||
/** get the barometer's calibrated average during the startup calibration */
|
||||
float getBaseAvg() {
|
||||
return calib.baseAvg;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // BAROMETER_H
|
||||
Reference in New Issue
Block a user