Merge branch 'master' of https://git.frank-ebner.de/FHWS/Indoor
This commit is contained in:
@@ -11,13 +11,20 @@
|
||||
#include "../../math/MovingAverageTS.h"
|
||||
#include "../../math/MovingStdDevTS.h"
|
||||
|
||||
#include "../../data/HistoryTS.h"
|
||||
|
||||
#include "../activity/Activity.h"
|
||||
|
||||
//#define ACT_DET_DEBUG_PLOT
|
||||
|
||||
#ifdef ACT_DET_DEBUG_PLOT
|
||||
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* simple step detection based on accelerometer magnitude.
|
||||
@@ -37,50 +44,49 @@ private:
|
||||
MovingAverageTS<float> baroAvgSlow;
|
||||
MovingAverageTS<float> baroAvgFast;
|
||||
|
||||
MovingAverageTS<float> baroAvg;
|
||||
HistoryTS<float> baroHistory;
|
||||
|
||||
Activity current;
|
||||
|
||||
public:
|
||||
|
||||
#ifdef ACT_DET_DEBUG_PLOT
|
||||
K::Gnuplot gp;
|
||||
K::GnuplotPlot gplot;
|
||||
K::GnuplotPlotElementLines l1;
|
||||
K::GnuplotPlotElementLines l2;
|
||||
#endif
|
||||
|
||||
/** ctor */
|
||||
ActivityDetector() : avgLong(Timestamp::fromMS(1500), 0), avgShort(Timestamp::fromMS(500), 0),
|
||||
stdDev(Timestamp::fromMS(200), 0), stdDev2(Timestamp::fromMS(2000), 0) {
|
||||
stdDev(Timestamp::fromMS(150), 0), stdDev2(Timestamp::fromMS(2000), 0),
|
||||
baroAvg(Timestamp::fromMS(500), 0), baroHistory(Timestamp::fromMS(4000)) {
|
||||
;
|
||||
gplot.add(&l1);
|
||||
gplot.add(&l2); l2.getStroke().getColor().setHexStr("#ff0000");
|
||||
|
||||
#ifdef ACT_DET_DEBUG_PLOT
|
||||
gplot.add(&l1);
|
||||
gplot.add(&l2); l2.getStroke().getColor().setHexStr("#ff0000");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//int xx = 0;
|
||||
|
||||
/** add barometer data */
|
||||
void add(const Timestamp ts, const BarometerData& baro) {
|
||||
if (baro.isValid()) {
|
||||
baroAvgSlow.add(ts, baro.hPa);
|
||||
baroAvgFast.add(ts, baro.hPa);
|
||||
baroAvg.add(ts, baro.hPa);
|
||||
const float avg = baroAvg.get();
|
||||
baroHistory.add(ts, avg);
|
||||
//l1.add(K::GnuplotPoint2(xx, avg));
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
Activity get() {
|
||||
|
||||
// delta in acceleration
|
||||
const float delta_acc = std::abs(avgLong.get() - avgShort.get());
|
||||
|
||||
if (delta_acc < 0.3) {
|
||||
return Activity::STANDING;
|
||||
}
|
||||
|
||||
// delta in pressure
|
||||
const float delta_hPa = baroAvgFast.get() - baroAvgSlow.get();
|
||||
|
||||
if (std::abs(delta_hPa) < 0.1) {
|
||||
return Activity::WALKING;
|
||||
} else if (delta_hPa > 0) {
|
||||
return Activity::WALKING_DOWN;
|
||||
} else {
|
||||
return Activity::WALKING_UP;
|
||||
}
|
||||
|
||||
/** get the currently detected activity */
|
||||
Activity get() const {
|
||||
return current;
|
||||
}
|
||||
|
||||
/** does the given data indicate a step? */
|
||||
@@ -96,13 +102,6 @@ public:
|
||||
|
||||
// static int x = 0; ++x;
|
||||
|
||||
//// if (x % 10 == 0) {
|
||||
//// l1.add({x, avgLong.get()});
|
||||
//// l2.add({x, avgShort.get()});
|
||||
//// gp.draw(gplot);
|
||||
//// gp.flush();
|
||||
//// }
|
||||
|
||||
// if (delta < 0.3) {
|
||||
// return Activity::STANDING;
|
||||
// }
|
||||
@@ -118,8 +117,41 @@ public:
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** estimate the current activity based on the sensor data */
|
||||
void update() {
|
||||
|
||||
// delta in acceleration
|
||||
const float delta_acc = std::abs(avgLong.get() - avgShort.get());
|
||||
|
||||
if (delta_acc < 0.015) {
|
||||
current = Activity::STANDING;
|
||||
return;
|
||||
}
|
||||
|
||||
// delta in pressure
|
||||
const float delta_hPa = baroHistory.getMostRecent() - baroHistory.getOldest();
|
||||
|
||||
#ifdef ACT_DET_DEBUG_PLOT
|
||||
l2.add(K::GnuplotPoint2(xx, delta_hPa));
|
||||
gp.draw(gplot);
|
||||
gp.flush();
|
||||
++xx;
|
||||
#endif
|
||||
|
||||
if (std::abs(delta_hPa) < 0.042) {
|
||||
current = Activity::WALKING;
|
||||
return;
|
||||
} else if (delta_hPa > 0) {
|
||||
current = Activity::WALKING_DOWN;
|
||||
return;
|
||||
} else {
|
||||
current = Activity::WALKING_UP;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -50,18 +50,27 @@ private:
|
||||
/** the signal-strength aggregation algorithm to use */
|
||||
const Aggregation agg;
|
||||
|
||||
/** respect only outputs with at-least X occurences of one physical hardware [can be used to prevent issues] */
|
||||
int minOccurences;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
VAPGrouper(const Mode mode, const Aggregation agg) : mode(mode), agg(agg) {
|
||||
|
||||
VAPGrouper(const Mode mode, const Aggregation agg, const int minOccurences = 2) :
|
||||
mode(mode), agg(agg), minOccurences(minOccurences) {
|
||||
;
|
||||
}
|
||||
|
||||
/** set the number of needed occurences per VAP-group to be accepted */
|
||||
void setMinOccurences(const int min) {
|
||||
this->minOccurences = min;
|
||||
}
|
||||
|
||||
/** get a vap-grouped version of the given input */
|
||||
WiFiMeasurements group(const WiFiMeasurements& original) const {
|
||||
|
||||
// first, group all VAPs into a vector [one vector per VAP-group]
|
||||
// by using the modified MAC address that all VAPs have in common
|
||||
std::unordered_map<MACAddress, std::vector<WiFiMeasurement>> grouped;
|
||||
|
||||
for (const WiFiMeasurement& m : original.entries) {
|
||||
@@ -72,8 +81,9 @@ public:
|
||||
|
||||
}
|
||||
|
||||
// output
|
||||
// to-be-constructed output
|
||||
WiFiMeasurements result;
|
||||
int skipped = 0;
|
||||
|
||||
// perform aggregation on each VAP-group
|
||||
for (auto it : grouped) {
|
||||
@@ -81,6 +91,9 @@ public:
|
||||
const MACAddress& base = it.first;
|
||||
const std::vector<WiFiMeasurement>& vaps = it.second;
|
||||
|
||||
// remove entries that do not satify the min-occurences metric
|
||||
if ((int)vaps.size() < minOccurences) {++skipped; continue;}
|
||||
|
||||
// group all VAPs into one measurement
|
||||
const WiFiMeasurement groupedMeasurement = groupVAPs(base, vaps);
|
||||
|
||||
@@ -89,8 +102,12 @@ public:
|
||||
|
||||
}
|
||||
|
||||
Log::add(name, "grouped " + std::to_string(original.entries.size()) + " measurements into " + std::to_string(result.entries.size()), true);
|
||||
|
||||
// debug
|
||||
Log::add(name,
|
||||
"grouped " + std::to_string(original.entries.size()) + " measurements " +
|
||||
"into " + std::to_string(result.entries.size()) + " [omitted: " + std::to_string(skipped) + "]",
|
||||
true
|
||||
);
|
||||
|
||||
// done
|
||||
return result;
|
||||
|
||||
@@ -32,6 +32,46 @@ struct WiFiMeasurements {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/** remove the entry for the given MAC (if any) */
|
||||
void remove(const MACAddress& mac) {
|
||||
for (size_t i = 0; i < entries.size(); ++i) {
|
||||
if (entries[i].getAP().getMAC() == mac) {
|
||||
entries.erase(entries.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** create a combination */
|
||||
static WiFiMeasurements mix(const WiFiMeasurements& a, const WiFiMeasurements& b, float sec = 3) {
|
||||
|
||||
Timestamp max;
|
||||
WiFiMeasurements res;
|
||||
|
||||
for (const WiFiMeasurement& m : a.entries) {
|
||||
res.entries.push_back(m);
|
||||
if (m.getTimestamp() > max) {max = m.getTimestamp();}
|
||||
}
|
||||
|
||||
for (const WiFiMeasurement& m : b.entries) {
|
||||
res.entries.push_back(m);
|
||||
if (m.getTimestamp() > max) {max = m.getTimestamp();}
|
||||
}
|
||||
|
||||
std::vector<WiFiMeasurement> tmp;
|
||||
std::swap(res.entries, tmp);
|
||||
|
||||
for (const WiFiMeasurement& m : tmp) {
|
||||
if ((max - m.getTimestamp()).sec() < sec) {
|
||||
res.entries.push_back(m);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // WIFIMEASUREMENTS_H
|
||||
|
||||
@@ -45,7 +45,6 @@ public:
|
||||
|
||||
double prob = 1.0;
|
||||
//double prob = 0;
|
||||
double error = 0;
|
||||
|
||||
int numMatchingAPs = 0;
|
||||
|
||||
@@ -77,14 +76,13 @@ public:
|
||||
const float sigma = this->sigma + this->sigmaPerSecond * age.sec();
|
||||
|
||||
// probability for this AP
|
||||
//double local = Distribution::Normal<double>::getProbability(modelRSSI, sigma, scanRSSI);
|
||||
double local = Distribution::Exponential<double>::getProbability(0.1, std::abs(modelRSSI-scanRSSI));
|
||||
double local = Distribution::Normal<double>::getProbability(modelRSSI, sigma, scanRSSI);
|
||||
//double local = Distribution::Exponential<double>::getProbability(0.1, std::abs(modelRSSI-scanRSSI));
|
||||
|
||||
// also add the error value? [location is OK but model is wrong]
|
||||
if (useError) {
|
||||
local = 0.95 * local + 0.05 * (1.0-local);
|
||||
//local = 0.95 * local + 0.05;
|
||||
#warning "TODO"
|
||||
}
|
||||
|
||||
// update probability
|
||||
|
||||
@@ -68,8 +68,8 @@ private:
|
||||
const float stdDev = std::sqrt(avg2 - avg*avg);
|
||||
|
||||
// avg rssi score
|
||||
const float minRSSI = -90;
|
||||
const float maxRSSI = -65;
|
||||
const float minRSSI = -85;
|
||||
const float maxRSSI = -70;
|
||||
float score1 = (avg-minRSSI) / (maxRSSI-minRSSI); // min = 0; max = 1
|
||||
if (score1 > 1) {score1 = 1;}
|
||||
if (score1 < 0) {score1 = 0;}
|
||||
|
||||
@@ -149,6 +149,7 @@ public:
|
||||
// WAF loss (params.waf is a negative value!) -> WAF loss is also a negative value
|
||||
//const float wafLoss = params.waf * ceilings.numCeilingsBetween(position_m, params.position_m);
|
||||
const float wafLoss = params.waf * ceilings.numCeilingsBetweenFloat(position_m, params.position_m);
|
||||
//const float wafLoss = params.waf * ceilings.numCeilingsBetweenLinearInt(position_m, params.position_m);
|
||||
|
||||
// combine
|
||||
const float res = rssiLOS + wafLoss;
|
||||
|
||||
@@ -52,15 +52,18 @@ public:
|
||||
|
||||
/** get a list of all APs known to the model */
|
||||
std::vector<AccessPoint> getAllAPs() const override {
|
||||
|
||||
// combine all submodels
|
||||
std::vector<AccessPoint> res;
|
||||
for (const ModelForBBoxes& sub : models) {
|
||||
for (const AccessPoint& ap : sub.mdl->getAllAPs()) {
|
||||
if (std::find(res.begin(), res.end(), ap) == res.end()) {
|
||||
if (std::find(res.begin(), res.end(), ap) == res.end()) { // TODO use map instead?
|
||||
res.push_back(ap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
void add(WiFiModel* mdl, const BBoxes3 bboxes) {
|
||||
|
||||
@@ -49,7 +49,18 @@ public:
|
||||
|
||||
/** get a list of all APs known to the model */
|
||||
std::vector<AccessPoint> getAllAPs() const override {
|
||||
return models.front().mdl->getAllAPs();
|
||||
|
||||
// combine all submodels
|
||||
std::vector<AccessPoint> res;
|
||||
for (const ModelForFloor& sub : models) {
|
||||
for (const AccessPoint& ap : sub.mdl->getAllAPs()) {
|
||||
if (std::find(res.begin(), res.end(), ap) == res.end()) { // TODO use map instead?
|
||||
res.push_back(ap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
void add(WiFiModel* mdl, const Floorplan::Floor* floor) {
|
||||
|
||||
Reference in New Issue
Block a user