many eval things
moved obsolete code TeX work
This commit is contained in:
@@ -58,7 +58,7 @@ ADD_DEFINITIONS(
|
|||||||
-fstack-protector-all
|
-fstack-protector-all
|
||||||
|
|
||||||
-g3
|
-g3
|
||||||
-O2
|
-O0
|
||||||
-march=native
|
-march=native
|
||||||
|
|
||||||
-DWITH_TESTS
|
-DWITH_TESTS
|
||||||
|
|||||||
@@ -167,7 +167,16 @@ public:
|
|||||||
|
|
||||||
Result fixedPosOptParamsForAll() {
|
Result fixedPosOptParamsForAll() {
|
||||||
|
|
||||||
// resulting error using the given txp,exp,waf for ALL APs
|
|
||||||
|
// get fingerprints for each AP [once]
|
||||||
|
std::unordered_map<MACAddress, std::vector<WiFiFingerprint>> fps;
|
||||||
|
for (const auto _ap : mapAPs) {
|
||||||
|
const Floorplan::AccessPoint* ap = _ap.first;
|
||||||
|
const MACAddress mac(ap->mac);
|
||||||
|
fps[mac] = calib.getFingerprintsFor(mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resulting error
|
||||||
auto errFunc = [&] (const float txp, const float exp, const float waf) -> Result {
|
auto errFunc = [&] (const float txp, const float exp, const float waf) -> Result {
|
||||||
|
|
||||||
Result res(map);
|
Result res(map);
|
||||||
@@ -179,7 +188,7 @@ public:
|
|||||||
const MACAddress mac(ap->mac);
|
const MACAddress mac(ap->mac);
|
||||||
const Point3 pos_m = ap->getPos(floor);
|
const Point3 pos_m = ap->getPos(floor);
|
||||||
res.model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
|
res.model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
|
||||||
K::Statistics<float> err = getError(mac, res.model);
|
K::Statistics<float> err = getError(mac, res.model, fps[mac]);
|
||||||
res.errAvg.add(err.getAvg());
|
res.errAvg.add(err.getAvg());
|
||||||
res.errSingle.add(err);
|
res.errSingle.add(err);
|
||||||
}
|
}
|
||||||
@@ -188,16 +197,16 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// to-be-optimized function: reduce average error among all fingerprints/AP's
|
// to-be-optimized function
|
||||||
auto optFunc = [&] (const float* params) {
|
auto optFunc = [&] (const float* params) {
|
||||||
return errFunc(params[0], params[1], params[2]).errSingle.getAvg();
|
return whatToOpt(errFunc(params[0], params[1], params[2]).errSingle);
|
||||||
};
|
};
|
||||||
|
|
||||||
// use simplex
|
// use simplex
|
||||||
float params[3] = {-40, 2, -8};
|
float params[3] = {-40, 2, -8};
|
||||||
K::NumOptAlgoDownhillSimplex<float> opt(3);
|
K::NumOptAlgoDownhillSimplex<float> opt(3);
|
||||||
opt.setMaxIterations(40);
|
opt.setMaxIterations(50);
|
||||||
opt.setNumRestarts(20);
|
opt.setNumRestarts(25);
|
||||||
opt.calculateOptimum(optFunc, params);
|
opt.calculateOptimum(optFunc, params);
|
||||||
|
|
||||||
// // use genetic
|
// // use genetic
|
||||||
@@ -232,7 +241,7 @@ public:
|
|||||||
const Point3 pos_m = ap->getPos(floor);
|
const Point3 pos_m = ap->getPos(floor);
|
||||||
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
||||||
|
|
||||||
// resulting error using the given txp,exp,waf for ALL APs
|
// resulting error
|
||||||
auto errFunc = [&] (const float txp, const float exp, const float waf) -> K::Statistics<float> {
|
auto errFunc = [&] (const float txp, const float exp, const float waf) -> K::Statistics<float> {
|
||||||
WiFiModelLogDistCeiling model(map); // new, empty model for this AP
|
WiFiModelLogDistCeiling model(map); // new, empty model for this AP
|
||||||
model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
|
model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
|
||||||
@@ -240,16 +249,16 @@ public:
|
|||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
// to-be-optimized function: reduce average error among all fingerprints/AP's
|
// to-be-optimized function
|
||||||
auto optFunc = [&] (const float* params) {
|
auto optFunc = [&] (const float* params) {
|
||||||
return errFunc(params[0], params[1], params[2]).getAvg();
|
return whatToOpt(errFunc(params[0], params[1], params[2]));
|
||||||
};
|
};
|
||||||
|
|
||||||
// use simplex
|
// use simplex
|
||||||
float params[3] = {-40, 2, -8};
|
float params[3] = {-40, 2, -8};
|
||||||
K::NumOptAlgoDownhillSimplex<float> opt(3);
|
K::NumOptAlgoDownhillSimplex<float> opt(3);
|
||||||
opt.setMaxIterations(40);
|
opt.setMaxIterations(50);
|
||||||
opt.setNumRestarts(20);
|
opt.setNumRestarts(25);
|
||||||
opt.calculateOptimum(optFunc, params);
|
opt.calculateOptimum(optFunc, params);
|
||||||
|
|
||||||
// // use genetic
|
// // use genetic
|
||||||
@@ -289,7 +298,7 @@ public:
|
|||||||
const MACAddress mac(ap->mac);
|
const MACAddress mac(ap->mac);
|
||||||
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
||||||
|
|
||||||
// resulting error using the given txp,exp,waf for ALL APs
|
// resulting error
|
||||||
auto errFunc = [&] (const Point3 pos_m, const float txp, const float exp, const float waf) -> K::Statistics<float> {
|
auto errFunc = [&] (const Point3 pos_m, const float txp, const float exp, const float waf) -> K::Statistics<float> {
|
||||||
WiFiModelLogDistCeiling model(map); // new, empty model for this AP
|
WiFiModelLogDistCeiling model(map); // new, empty model for this AP
|
||||||
model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
|
model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
|
||||||
@@ -297,10 +306,10 @@ public:
|
|||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
// to-be-optimized function: reduce average error among all fingerprints/AP's
|
// to-be-optimized function
|
||||||
auto optFunc = [&] (const float* params) {
|
auto optFunc = [&] (const float* params) {
|
||||||
const Point3 pos_m(params[0], params[1], params[2]);
|
const Point3 pos_m(params[0], params[1], params[2]);
|
||||||
return errFunc(pos_m, params[3], params[4], params[5]).getAvg(); // AVG
|
return whatToOpt(errFunc(pos_m, params[3], params[4], params[5]));
|
||||||
};
|
};
|
||||||
|
|
||||||
// params
|
// params
|
||||||
@@ -344,7 +353,7 @@ public:
|
|||||||
|
|
||||||
K::NumOptAlgoRangeRandom<float> opt(valRegion);
|
K::NumOptAlgoRangeRandom<float> opt(valRegion);
|
||||||
opt.setPopulationSize(300);
|
opt.setPopulationSize(300);
|
||||||
opt.setNumIerations(75);
|
opt.setNumIerations(100);
|
||||||
opt.calculateOptimum(optFunc, params);
|
opt.calculateOptimum(optFunc, params);
|
||||||
|
|
||||||
|
|
||||||
@@ -376,6 +385,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// the stats to optimize
|
||||||
|
static inline float whatToOpt(const K::Statistics<float>& s) {
|
||||||
|
//return s.getAvg() + s.getStdDev() / 2 + s.getMax() / 4; // for dBm
|
||||||
|
//return s.getAvg() + s.getStdDev() * 2 + s.getMax() / 2; // for probability
|
||||||
|
//return s.getQuantile(0.96);
|
||||||
|
return s.getAvg();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<WiFiFingerprint> getFingerprints(const MACAddress& mac) {
|
std::vector<WiFiFingerprint> getFingerprints(const MACAddress& mac) {
|
||||||
|
|
||||||
// get all fingerprints where the given mac was seen
|
// get all fingerprints where the given mac was seen
|
||||||
@@ -432,10 +449,14 @@ private:
|
|||||||
if (scan_rssi < -100) {throw Exception("scan rssi out of range for " + mac.asString());}
|
if (scan_rssi < -100) {throw Exception("scan rssi out of range for " + mac.asString());}
|
||||||
if (scan_rssi > -35) {throw Exception("scan rssi out of range for " + mac.asString());}
|
if (scan_rssi > -35) {throw Exception("scan rssi out of range for " + mac.asString());}
|
||||||
|
|
||||||
// difference
|
// dB error
|
||||||
//const float err = model_rssi - scan_rssi;
|
const float err = model_rssi - scan_rssi;
|
||||||
const float err = -std::log(Distribution::Normal<float>::getProbability(model_rssi, 7, scan_rssi));
|
|
||||||
float aErr = std::abs(err);
|
// probability matching error
|
||||||
|
//const float err = -std::log(Distribution::Normal<float>::getProbability(model_rssi, 8, scan_rssi));
|
||||||
|
|
||||||
|
// quadratic
|
||||||
|
float aErr = std::pow(std::abs(err), 2);
|
||||||
|
|
||||||
// penalty
|
// penalty
|
||||||
// if (model.getAP(mac).waf > -2) {aErr += 9999;}
|
// if (model.getAP(mac).waf > -2) {aErr += 9999;}
|
||||||
|
|||||||
74
EvalWiFi.h
74
EvalWiFi.h
@@ -5,6 +5,7 @@
|
|||||||
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
||||||
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
||||||
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
||||||
|
#include "Indoor/sensors/radio/model/WiFiModels.h"
|
||||||
|
|
||||||
#include "Indoor/sensors/radio/VAPGrouper.h"
|
#include "Indoor/sensors/radio/VAPGrouper.h"
|
||||||
#include "Indoor/sensors/offline/FileReader.h"
|
#include "Indoor/sensors/offline/FileReader.h"
|
||||||
@@ -32,6 +33,7 @@
|
|||||||
#include "CSV.h"
|
#include "CSV.h"
|
||||||
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
template <typename T> class Line {
|
template <typename T> class Line {
|
||||||
|
|
||||||
@@ -122,7 +124,7 @@ public:
|
|||||||
// opt = new WiFiOptimizer::LogDistCeiling(map, *vap, *calib, WiFiOptimizer::LogDistCeiling::Mode::MEDIUM);
|
// opt = new WiFiOptimizer::LogDistCeiling(map, *vap, *calib, WiFiOptimizer::LogDistCeiling::Mode::MEDIUM);
|
||||||
|
|
||||||
// how to handle VAPs
|
// how to handle VAPs
|
||||||
vap = new VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::MEDIAN);
|
vap = new VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||||
|
|
||||||
pef = new PlotErrFunc("\\small{error (m)}", "\\small{measurements (\\%)}");
|
pef = new PlotErrFunc("\\small{error (m)}", "\\small{measurements (\\%)}");
|
||||||
pef->showMarkers(false);
|
pef->showMarkers(false);
|
||||||
@@ -130,10 +132,10 @@ public:
|
|||||||
pef2 = new PlotErrFunc("\\small{-log(p(..))}", "\\small{measurements (\\%)}");
|
pef2 = new PlotErrFunc("\\small{-log(p(..))}", "\\small{measurements (\\%)}");
|
||||||
pef2->showMarkers(false);
|
pef2->showMarkers(false);
|
||||||
|
|
||||||
pet = new PlotErrTime("2", "3", "");
|
pet = new PlotErrTime("walktime (seconds)", "\\small{error (m)}", "");
|
||||||
pet->getPlot().setRangeY(K::GnuplotAxisRange(0, 40));
|
pet->getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 40));
|
||||||
|
|
||||||
pet2 = new PlotErrTime("2", "3", "");
|
pet2 = new PlotErrTime("walktime (seconds)", "\\small{-log(p(groundTruth | measurements))", "");
|
||||||
|
|
||||||
plot = new Plotty(map);
|
plot = new Plotty(map);
|
||||||
plot->buildFloorplan();
|
plot->buildFloorplan();
|
||||||
@@ -143,35 +145,25 @@ public:
|
|||||||
|
|
||||||
void load(const std::string& xmlFile, const std::string& name) {
|
void load(const std::string& xmlFile, const std::string& name) {
|
||||||
|
|
||||||
|
WiFiModelFactory fac(map);
|
||||||
|
|
||||||
// setup the model
|
// setup the model
|
||||||
WiFiModelLogDistCeiling* wiModel = new WiFiModelLogDistCeiling(map);
|
this->wiModel = fac.loadXML(xmlFile);
|
||||||
wiModel->loadXML(xmlFile);
|
|
||||||
this->wiModel = wiModel;
|
|
||||||
|
|
||||||
// fire
|
// fire
|
||||||
build(name);
|
build(name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void fixedParams(const float txp, const float exp, const float waf) {
|
|
||||||
|
|
||||||
// // how to handle VAPs
|
|
||||||
// vap = new VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
|
||||||
|
|
||||||
// // setup the model
|
|
||||||
// WiFiModelLogDistCeiling* wiModel = new WiFiModelLogDistCeiling(map);
|
|
||||||
// wiModel->loadAPs(map, *vap, txp, exp, waf, false);
|
|
||||||
// this->wiModel = wiModel;
|
|
||||||
|
|
||||||
// // fire
|
|
||||||
// run();
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void build(const std::string& name) {
|
void build(const std::string& name) {
|
||||||
|
|
||||||
|
K::GnuplotStroke stroke(
|
||||||
|
K::GnuplotDashtype::SOLID, 1.5,
|
||||||
|
K::GnuplotColor::AUTO()
|
||||||
|
);
|
||||||
static int idx = -1; ++idx;
|
static int idx = -1; ++idx;
|
||||||
|
|
||||||
|
|
||||||
@@ -179,6 +171,7 @@ private:
|
|||||||
|
|
||||||
Line<Point3> path;
|
Line<Point3> path;
|
||||||
K::GnuplotSplotElementLines* gpPath = new K::GnuplotSplotElementLines();
|
K::GnuplotSplotElementLines* gpPath = new K::GnuplotSplotElementLines();
|
||||||
|
gpPath->setStroke(stroke);
|
||||||
plot->splot.add(gpPath);
|
plot->splot.add(gpPath);
|
||||||
|
|
||||||
K::Statistics<float>* stats = new K::Statistics<float>();
|
K::Statistics<float>* stats = new K::Statistics<float>();
|
||||||
@@ -275,11 +268,11 @@ private:
|
|||||||
// parameters
|
// parameters
|
||||||
float params[3];
|
float params[3];
|
||||||
|
|
||||||
|
// USE GENETIC
|
||||||
// std::minstd_rand gen;
|
// std::minstd_rand gen;
|
||||||
// std::uniform_real_distribution<float> distX(mapBBox.getMin().x, mapBBox.getMax().x);
|
// std::uniform_real_distribution<float> distX(mapBBox.getMin().x, mapBBox.getMax().x);
|
||||||
// std::uniform_real_distribution<float> distY(mapBBox.getMin().y, mapBBox.getMax().y);
|
// std::uniform_real_distribution<float> distY(mapBBox.getMin().y, mapBBox.getMax().y);
|
||||||
// std::uniform_real_distribution<float> distZ(mapBBox.getMin().z, mapBBox.getMax().z);
|
// std::uniform_real_distribution<float> distZ(mapBBox.getMin().z, mapBBox.getMax().z);
|
||||||
|
|
||||||
// // initializer for the optimizer: random position within the map's bbox
|
// // initializer for the optimizer: random position within the map's bbox
|
||||||
// auto init = [&] (const int childIdx, float* params) {
|
// auto init = [&] (const int childIdx, float* params) {
|
||||||
// (void) childIdx;
|
// (void) childIdx;
|
||||||
@@ -287,13 +280,13 @@ private:
|
|||||||
// params[1] = distY(gen);
|
// params[1] = distY(gen);
|
||||||
// params[2] = distZ(gen);
|
// params[2] = distZ(gen);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
// K::NumOptAlgoGenetic<float> opt(3);
|
// K::NumOptAlgoGenetic<float> opt(3);
|
||||||
// opt.setPopulationSize(400);
|
// opt.setPopulationSize(400);
|
||||||
// opt.setMaxIterations(20);
|
// opt.setMaxIterations(20);
|
||||||
// opt.calculateOptimum(func, params, init);
|
// opt.calculateOptimum(func, params, init);
|
||||||
|
|
||||||
|
|
||||||
|
// USE RANGE RANDOM WITH COOLING
|
||||||
using LeOpt = K::NumOptAlgoRangeRandom<float>;
|
using LeOpt = K::NumOptAlgoRangeRandom<float>;
|
||||||
const std::vector<LeOpt::MinMax> valRegion = {
|
const std::vector<LeOpt::MinMax> valRegion = {
|
||||||
LeOpt::MinMax(mapBBox.getMin().x, mapBBox.getMax().x), // x
|
LeOpt::MinMax(mapBBox.getMin().x, mapBBox.getMax().x), // x
|
||||||
@@ -304,7 +297,7 @@ private:
|
|||||||
K::NumOptAlgoRangeRandom<float> opt(valRegion);
|
K::NumOptAlgoRangeRandom<float> opt(valRegion);
|
||||||
opt.setPopulationSize(200);
|
opt.setPopulationSize(200);
|
||||||
opt.setNumIerations(50);
|
opt.setNumIerations(50);
|
||||||
//opt.calculateOptimum(func, params);
|
opt.calculateOptimum(func, params);
|
||||||
|
|
||||||
|
|
||||||
std::cout << params[0] << "," << params[1] << "," << params[2] << std::endl;
|
std::cout << params[0] << "," << params[1] << "," << params[2] << std::endl;
|
||||||
@@ -325,27 +318,38 @@ private:
|
|||||||
plot->gp << "set arrow 1 at " << gt.x << "," << gt.y << "," << gt.z << " to " << gt.x << "," << gt.y << "," << (gt.z+1) << "\n";
|
plot->gp << "set arrow 1 at " << gt.x << "," << gt.y << "," << gt.z << " to " << gt.x << "," << gt.y << "," << (gt.z+1) << "\n";
|
||||||
|
|
||||||
// error
|
// error
|
||||||
//const float err_m = gt.xy().getDistance(curEst.xy());
|
const float err_m = gt.xy().getDistance(curEst.xy()); // 2D
|
||||||
const float err_m = gt.getDistance(curEst);
|
//const float err_m = gt.getDistance(curEst); // 3D
|
||||||
stats->add(err_m);
|
stats->add(err_m);
|
||||||
|
|
||||||
float gtFloat[3] = {gt.x, gt.y, gt.z};
|
float gtFloat[3] = {gt.x, gt.y, gt.z};
|
||||||
const double probOnGT = -func(gtFloat);
|
const double probOnGT = -func(gtFloat);
|
||||||
const double logProbOnGT = -log(probOnGT);
|
const double logProbOnGT = -std::log10(probOnGT);
|
||||||
statsProbOnGT->add(logProbOnGT);
|
const double logProbOnGTNorm = (logProbOnGT/mes.entries.size());
|
||||||
|
|
||||||
|
statsProbOnGT->add(logProbOnGTNorm);
|
||||||
|
|
||||||
|
static int xxx = 0; ++xxx;
|
||||||
|
|
||||||
// plot err
|
// plot err
|
||||||
pet->addErr(ts, err_m, idx);
|
pet->addErr(ts, err_m, idx);
|
||||||
pet2->addErr(ts, logProbOnGT/mes.entries.size(), idx);
|
pet2->addErr(ts, logProbOnGTNorm, idx);
|
||||||
|
|
||||||
// fire
|
if (xxx%2 == 0) {
|
||||||
plot->plot();
|
|
||||||
|
plot->plot();
|
||||||
|
|
||||||
|
pet->plot();
|
||||||
|
pef->plot();
|
||||||
|
|
||||||
|
pet2->plot();
|
||||||
|
pef2->plot();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||||
|
}
|
||||||
|
|
||||||
// pet->plot();
|
|
||||||
// pef->plot();
|
|
||||||
|
|
||||||
pet2->plot();
|
|
||||||
pef2->plot();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
219
EvalWifiOptResult.h
Normal file
219
EvalWifiOptResult.h
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
#ifndef EVALWIFIOPTRESULT_H
|
||||||
|
#define EVALWIFIOPTRESULT_H
|
||||||
|
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
||||||
|
|
||||||
|
#include "Indoor/sensors/radio/VAPGrouper.h"
|
||||||
|
#include "Indoor/sensors/offline/FileReader.h"
|
||||||
|
|
||||||
|
#include "Indoor/floorplan/v2/Floorplan.h"
|
||||||
|
#include "Indoor/floorplan/v2/FloorplanReader.h"
|
||||||
|
#include "Indoor/floorplan/v2/FloorplanHelper.h"
|
||||||
|
#include "Indoor/floorplan/v2/FloorplanCeilings.h"
|
||||||
|
|
||||||
|
#include "Indoor/grid/factory/v2/Helper.h"
|
||||||
|
|
||||||
|
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementColorPoints.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotPlotElementHistogram.h>
|
||||||
|
#include <KLib/misc/gnuplot/objects/GnuplotObjectRectangle.h>
|
||||||
|
|
||||||
|
#include <KLib/math/statistics/Statistics.h>
|
||||||
|
|
||||||
|
#include "Structs.h"
|
||||||
|
#include "plots/Plotty.h"
|
||||||
|
#include "plots/PlotErrTime.h"
|
||||||
|
#include "plots/PlotErrFunc.h"
|
||||||
|
|
||||||
|
#include "Settings.h"
|
||||||
|
|
||||||
|
/** plot results of the wifi optimization */
|
||||||
|
class EvalWiFiOptResult {
|
||||||
|
|
||||||
|
Floorplan::IndoorMap* map;
|
||||||
|
VAPGrouper vap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
EvalWiFiOptResult(const std::string& mapFile) : vap(Settings::WiFiModel::vg_eval) {
|
||||||
|
map = Floorplan::Reader::readFromFile(mapFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plot the error for every fingerprint
|
||||||
|
*/
|
||||||
|
template <typename Model> void showErrorPerFingerprint(const std::string& modelParamsXML, const WiFiFingerprints& fps) {
|
||||||
|
|
||||||
|
Plotty* plot = new Plotty(map);
|
||||||
|
|
||||||
|
plot->settings.obstacles = true;
|
||||||
|
plot->settings.outline = false;
|
||||||
|
plot->settings.stairs = false;
|
||||||
|
plot->settings.outlineColor = K::GnuplotColor::fromRGB(0,0,0);
|
||||||
|
plot->buildFloorplan();
|
||||||
|
plot->equalXY();
|
||||||
|
//plot.gp << "unset border\n";
|
||||||
|
plot->splot.getAxisX().setTicsVisible(false);
|
||||||
|
plot->splot.getAxisY().setTicsVisible(false);
|
||||||
|
plot->splot.getAxisZ().setTicsVisible(false);
|
||||||
|
plot->setScale(1.5, 1.5);
|
||||||
|
|
||||||
|
// the sig strength model
|
||||||
|
Model model(map);
|
||||||
|
model.loadXML(modelParamsXML);
|
||||||
|
// WiFiModelLogDistCeiling model(map);
|
||||||
|
// model.loadXML(modelParamsXML);
|
||||||
|
|
||||||
|
// combine position and error
|
||||||
|
struct ErrPoint {
|
||||||
|
Point3 pos;
|
||||||
|
float err;
|
||||||
|
ErrPoint(const Point3 pos, const float err) : pos(pos), err(err) {;}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ErrPoint> errors;
|
||||||
|
|
||||||
|
// process each location
|
||||||
|
for (const WiFiFingerprint& fp : fps.getFingerprints()) {
|
||||||
|
|
||||||
|
// estimate error for this location
|
||||||
|
K::Statistics<float> errAbs;
|
||||||
|
|
||||||
|
// vap grouping
|
||||||
|
const WiFiMeasurements mes = vap.group(fp.measurements);
|
||||||
|
|
||||||
|
// process each measured AP
|
||||||
|
for (const WiFiMeasurement& m : mes.entries) {
|
||||||
|
|
||||||
|
// fingerprint RSSI
|
||||||
|
const float scan_rssi = m.getRSSI();
|
||||||
|
|
||||||
|
// model RSSI
|
||||||
|
const float model_rssi = model.getRSSI(m.getAP().getMAC(), fp.pos_m);
|
||||||
|
|
||||||
|
// AP unknown -> skip
|
||||||
|
if (model_rssi != model_rssi) {continue;}
|
||||||
|
|
||||||
|
// update error
|
||||||
|
const float err = model_rssi - scan_rssi;
|
||||||
|
errAbs.add(std::abs(err));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// enqueue AVG error
|
||||||
|
errors.push_back(ErrPoint(fp.pos_m, errAbs.getMax()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// interpolated error points
|
||||||
|
std::vector<ErrPoint> errorsInt;
|
||||||
|
K::Statistics<float> errStats;
|
||||||
|
const float oz = 1.3;
|
||||||
|
const float ss = 1.5;
|
||||||
|
|
||||||
|
for (Floorplan::Floor* floor : map->floors) {
|
||||||
|
|
||||||
|
for (float y = -20; y < 70; y+=ss) {
|
||||||
|
for (float x = -10; x < 130; x+=ss) {
|
||||||
|
|
||||||
|
const Point3 pos(x,y,floor->atHeight+oz);
|
||||||
|
float errSum = 0;
|
||||||
|
float distSum = 0;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
float minDist = 99999;
|
||||||
|
|
||||||
|
for (const ErrPoint& ep : errors) {
|
||||||
|
if (ep.pos.z != pos.z) {continue;}
|
||||||
|
const float dist = ep.pos.getDistance(pos);
|
||||||
|
//if (dist > 4.0) {continue;}
|
||||||
|
//const float imp = 1.0 / (std::pow((dist+0.01)/4.0, 3));
|
||||||
|
//errSum += ep.err * imp;
|
||||||
|
//distSum += imp;
|
||||||
|
if (dist < minDist) {
|
||||||
|
errSum = ep.err;
|
||||||
|
distSum = 1.0;
|
||||||
|
minDist = dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
++cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// limit estimations to the floorplan's outline
|
||||||
|
bool contained = false;
|
||||||
|
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
|
||||||
|
HelperPoly hp(*poly);
|
||||||
|
if (hp.contains(pos.xy()*100)) {
|
||||||
|
if (poly->method == Floorplan::OutlineMethod::ADD) {
|
||||||
|
contained = true;
|
||||||
|
} else {
|
||||||
|
//contained = false; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distSum == 0) {continue;}
|
||||||
|
if (!contained) {continue;}
|
||||||
|
const float err = errSum/distSum;
|
||||||
|
|
||||||
|
// add
|
||||||
|
errStats.add(err);
|
||||||
|
errorsInt.push_back(ErrPoint(pos, err));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
const float minErr = 0.0;//errStats.getMin();
|
||||||
|
const float maxErr = 18.0;//errStats.getQuantile(0.9);
|
||||||
|
|
||||||
|
plot->splot.setTitle("max error: " + std::to_string(errStats.getQuantile(0.9)) + " dB");
|
||||||
|
|
||||||
|
// draw interpolated errors between min/max
|
||||||
|
for (const ErrPoint& ep : errorsInt) {
|
||||||
|
|
||||||
|
float factor = (ep.err - minErr) / (maxErr-minErr);
|
||||||
|
if (factor > 1) {factor = 1;}
|
||||||
|
|
||||||
|
// hsv green->yellow->red
|
||||||
|
// const float h = 90 * (1 - std::pow(factor, 1.0));
|
||||||
|
// K::GnuplotColor color = K::GnuplotColor::fromHSV(h, 255, 255);
|
||||||
|
|
||||||
|
// hsv white->red
|
||||||
|
const float sat = 255 * (std::pow(factor, 1.5));
|
||||||
|
K::GnuplotColor color = K::GnuplotColor::fromHSV(0, sat, 255);
|
||||||
|
|
||||||
|
K::GnuplotObjectPolygon* poly = new K::GnuplotObjectPolygon(
|
||||||
|
K::GnuplotFill(K::GnuplotFillStyle::SOLID, color),
|
||||||
|
K::GnuplotStroke::NONE()
|
||||||
|
);
|
||||||
|
|
||||||
|
const float s = ss/2;
|
||||||
|
|
||||||
|
poly->add(K::GnuplotCoordinate3(ep.pos.x-s, ep.pos.y-s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST));
|
||||||
|
poly->add(K::GnuplotCoordinate3(ep.pos.x+s, ep.pos.y-s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST));
|
||||||
|
poly->add(K::GnuplotCoordinate3(ep.pos.x+s, ep.pos.y+s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST));
|
||||||
|
poly->add(K::GnuplotCoordinate3(ep.pos.x-s, ep.pos.y+s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST));
|
||||||
|
poly->close();
|
||||||
|
poly->setZIndex(ep.pos.z);
|
||||||
|
plot->splot.getObjects().add(poly);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
plot->plot();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EVALWIFIOPTRESULT_H
|
||||||
6
Helper.h
6
Helper.h
@@ -149,6 +149,12 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void writeCode(const std::string& file, const std::string& code) {
|
||||||
|
std::ofstream out(file);
|
||||||
|
out << code;
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
static void plot(const Floorplan::IndoorMap* map, const WiFiFingerprints& inp, const std::string& title = "Fingerprints") {
|
static void plot(const Floorplan::IndoorMap* map, const WiFiFingerprints& inp, const std::string& title = "Fingerprints") {
|
||||||
|
|
||||||
Plotty* p = new Plotty(map);
|
Plotty* p = new Plotty(map);
|
||||||
|
|||||||
10
Settings.h
10
Settings.h
@@ -20,7 +20,13 @@ namespace Settings {
|
|||||||
const std::string wifiAllOptPar = pathWiFi + "allOptPar.xml";
|
const std::string wifiAllOptPar = pathWiFi + "allOptPar.xml";
|
||||||
const std::string wifiEachOptPar = pathWiFi + "eachOptPar.xml";
|
const std::string wifiEachOptPar = pathWiFi + "eachOptPar.xml";
|
||||||
const std::string wifiEachOptParPos = pathWiFi + "eachOptParPos.xml";
|
const std::string wifiEachOptParPos = pathWiFi + "eachOptParPos.xml";
|
||||||
const std::string wifiEachOptParPosNoStairNoOut = pathWiFi + "eachOptParPosNoStairNoOut.xml";
|
|
||||||
|
const std::string wifiEachOptParPos_only0th = pathWiFi + "eachOptParPos_only0th.xml";
|
||||||
|
const std::string wifiEachOptParPos_only1st = pathWiFi + "eachOptParPos_only1st.xml";
|
||||||
|
const std::string wifiEachOptParPos_only2nd = pathWiFi + "eachOptParPos_only2nd.xml";
|
||||||
|
const std::string wifiEachOptParPos_only3rd = pathWiFi + "eachOptParPos_only3rd.xml";
|
||||||
|
|
||||||
|
const std::string wifiEachOptParPos_multimodel = pathWiFi + "eachOptParPos_multimodel.xml";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -58,7 +64,7 @@ namespace Settings {
|
|||||||
|
|
||||||
namespace WiFiModel {
|
namespace WiFiModel {
|
||||||
|
|
||||||
constexpr float sigma = 11.0;
|
constexpr float sigma = 8.0;
|
||||||
|
|
||||||
/** if the wifi-signal-strengths are stored on the grid-nodes, this needs a grid rebuild! */
|
/** if the wifi-signal-strengths are stored on the grid-nodes, this needs a grid rebuild! */
|
||||||
// constexpr float TXP = -44;
|
// constexpr float TXP = -44;
|
||||||
|
|||||||
205
main.cpp
205
main.cpp
@@ -4,6 +4,7 @@
|
|||||||
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
||||||
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
||||||
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
||||||
|
#include "Indoor/sensors/radio/model/WiFiModels.h"
|
||||||
|
|
||||||
#include "Indoor/sensors/radio/VAPGrouper.h"
|
#include "Indoor/sensors/radio/VAPGrouper.h"
|
||||||
|
|
||||||
@@ -28,6 +29,9 @@
|
|||||||
#include "EvalWiFi.h"
|
#include "EvalWiFi.h"
|
||||||
#include "EvalWiFiSigStrength.h"
|
#include "EvalWiFiSigStrength.h"
|
||||||
#include "pf/EvalWalk.h"
|
#include "pf/EvalWalk.h"
|
||||||
|
#include "EvalWifiOptResult.h"
|
||||||
|
#include "wifi/EvalWiFiConvex.h"
|
||||||
|
|
||||||
|
|
||||||
#include "plots/PlotErrFunc.h"
|
#include "plots/PlotErrFunc.h"
|
||||||
|
|
||||||
@@ -36,6 +40,18 @@ void paperOutputs() {
|
|||||||
|
|
||||||
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);
|
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);
|
||||||
|
|
||||||
|
|
||||||
|
// show optimization behaviour
|
||||||
|
if (1 == 1) {
|
||||||
|
|
||||||
|
EvalWiFiConvex eval(map, Settings::fCalib);
|
||||||
|
eval.showParams();
|
||||||
|
//eval.showPos();
|
||||||
|
eval.showPosZ();
|
||||||
|
return;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// show fingerprints as plot
|
// show fingerprints as plot
|
||||||
if (1==0){
|
if (1==0){
|
||||||
EvalWiFiSigStrength sig(Settings::fMap, Settings::fCalib);
|
EvalWiFiSigStrength sig(Settings::fMap, Settings::fCalib);
|
||||||
@@ -69,28 +85,62 @@ void paperOutputs() {
|
|||||||
// };
|
// };
|
||||||
// EvalCompareOpt2 opt1(Settings::fMap, calibWalks);
|
// EvalCompareOpt2 opt1(Settings::fMap, calibWalks);
|
||||||
|
|
||||||
auto remove = [] (const WiFiFingerprint& fp) -> bool {
|
auto removeNone = [] (const WiFiFingerprint& fp) -> bool {
|
||||||
return fp.pos_m.z != 4;
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto only0th = [] (const WiFiFingerprint& fp) -> bool {
|
||||||
|
return std::abs(fp.pos_m.z - (1.3)) > 0.1;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto only1st = [] (const WiFiFingerprint& fp) -> bool {
|
||||||
|
return std::abs(fp.pos_m.z - (4+1.3)) > 0.1;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto only2nd = [] (const WiFiFingerprint& fp) -> bool {
|
||||||
|
return std::abs(fp.pos_m.z - (4+3.4+1.3)) > 0.1;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto only3rd = [] (const WiFiFingerprint& fp) -> bool {
|
||||||
|
return std::abs(fp.pos_m.z - (4+3.4+3.4+1.3)) > 0.1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// use fingerprints?
|
// use fingerprints?
|
||||||
bool ignoreStaircases = false;
|
EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, removeNone);
|
||||||
bool ignoreOutdoor = false;
|
|
||||||
bool ignoreIndoor = false;
|
|
||||||
EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, remove);
|
|
||||||
|
|
||||||
|
|
||||||
|
// optimize using all floors
|
||||||
EvalCompareOpt2::Result s1 = opt1.fixedPosFixedParamsForAll(); //BREAK;
|
EvalCompareOpt2::Result s1 = opt1.fixedPosFixedParamsForAll(); //BREAK;
|
||||||
EvalCompareOpt2::Result s2 = opt1.fixedPosOptParamsForAll(); //BREAK;
|
EvalCompareOpt2::Result s2 = opt1.fixedPosOptParamsForAll(); //BREAK;
|
||||||
EvalCompareOpt2::Result s3 = opt1.fixedPosOptParamsForEach(); //BREAK;
|
EvalCompareOpt2::Result s3 = opt1.fixedPosOptParamsForEach(); //BREAK;
|
||||||
EvalCompareOpt2::Result s4 = opt1.optPosOptParamsForEach(); //BREAK;
|
EvalCompareOpt2::Result s4 = opt1.optPosOptParamsForEach(); //BREAK;
|
||||||
|
|
||||||
|
// optimize only for the 0th floor
|
||||||
|
EvalCompareOpt2 opt_f0(Settings::fMap, Settings::fCalib, only0th);
|
||||||
|
EvalCompareOpt2::Result sf0 = opt_f0.optPosOptParamsForEach();
|
||||||
|
EvalCompareOpt2 opt_f1(Settings::fMap, Settings::fCalib, only1st);
|
||||||
|
EvalCompareOpt2::Result sf1 = opt_f1.optPosOptParamsForEach();
|
||||||
|
EvalCompareOpt2 opt_f2(Settings::fMap, Settings::fCalib, only2nd);
|
||||||
|
EvalCompareOpt2::Result sf2 = opt_f2.optPosOptParamsForEach();
|
||||||
|
EvalCompareOpt2 opt_f3(Settings::fMap, Settings::fCalib, only3rd);
|
||||||
|
EvalCompareOpt2::Result sf3 = opt_f3.optPosOptParamsForEach();
|
||||||
|
|
||||||
// save models to file
|
// save models to file
|
||||||
s1.model.saveXML(Settings::wifiAllFixed);
|
s1.model.saveXML(Settings::wifiAllFixed);
|
||||||
s2.model.saveXML(Settings::wifiAllOptPar);
|
s2.model.saveXML(Settings::wifiAllOptPar);
|
||||||
s3.model.saveXML(Settings::wifiEachOptPar);
|
s3.model.saveXML(Settings::wifiEachOptPar);
|
||||||
s4.model.saveXML(Settings::wifiEachOptParPos);
|
s4.model.saveXML(Settings::wifiEachOptParPos);
|
||||||
|
sf0.model.saveXML(Settings::wifiEachOptParPos_only0th);
|
||||||
|
sf1.model.saveXML(Settings::wifiEachOptParPos_only1st);
|
||||||
|
sf2.model.saveXML(Settings::wifiEachOptParPos_only2nd);
|
||||||
|
sf3.model.saveXML(Settings::wifiEachOptParPos_only3rd);
|
||||||
|
|
||||||
|
// fancy combined model
|
||||||
|
WiFiModelPerFloor wmpf(map);
|
||||||
|
wmpf.add(&sf0.model, map->floors[0]);
|
||||||
|
wmpf.add(&sf1.model, map->floors[1]);
|
||||||
|
wmpf.add(&sf2.model, map->floors[2]);
|
||||||
|
wmpf.add(&sf3.model, map->floors[3]);
|
||||||
|
wmpf.saveXML(Settings::wifiEachOptParPos_multimodel);
|
||||||
|
|
||||||
PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
||||||
pef.add("\\small{empiric}", &s1.errSingle);
|
pef.add("\\small{empiric}", &s1.errSingle);
|
||||||
@@ -106,68 +156,39 @@ void paperOutputs() {
|
|||||||
pef.getGP() << "set tmargin 0.4\n";
|
pef.getGP() << "set tmargin 0.4\n";
|
||||||
pef.plot();
|
pef.plot();
|
||||||
|
|
||||||
return;
|
int i = 0; (void) i;
|
||||||
|
//return;
|
||||||
//sleep(1000);
|
//sleep(1000);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// REPLACED BY EVAL OPT 2
|
/** plot wifi eval results */
|
||||||
// // perform varios AP-param optimizations
|
if (1 == 1) {
|
||||||
// // generate error plot showing the performance of each
|
|
||||||
// // save the resulting wifi-models to XML for later re-use during the walk-eval <<<<<< !!!!
|
|
||||||
// if (1 == 0) {
|
|
||||||
|
|
||||||
// bool ignoreStaircases = false;
|
WiFiFingerprints fps;
|
||||||
// bool ignoreOutdoor = false;
|
fps.load(Settings::fCalib);
|
||||||
// bool ignoreIndoor = false;
|
|
||||||
|
|
||||||
// // use walks?
|
EvalWiFiOptResult eval1(Settings::fMap);
|
||||||
//// std::vector<std::pair<std::string, std::vector<int>>> calibWalks = {
|
eval1.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos, fps);
|
||||||
//// std::make_pair(Settings::path1a, Settings::GroundTruth::path1),
|
|
||||||
//// std::make_pair(Settings::path1b, Settings::GroundTruth::path1),
|
|
||||||
//// std::make_pair(Settings::path2a, Settings::GroundTruth::path2),
|
|
||||||
//// std::make_pair(Settings::path2b, Settings::GroundTruth::path2),
|
|
||||||
//// };
|
|
||||||
//// EvalCompareOpt opt1(Settings::fMap, calibWalks);
|
|
||||||
|
|
||||||
// // use fingerprints?
|
EvalWiFiOptResult eval2(Settings::fMap);
|
||||||
// EvalCompareOpt opt1(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
|
eval2.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiAllFixed, fps);
|
||||||
|
|
||||||
// EvalCompareOpt::Result s1 = opt1.fixedPosFixedParamsForAll(); //BREAK;
|
|
||||||
// EvalCompareOpt::Result s2 = opt1.fixedPosOptParamsForAll(); //BREAK;
|
|
||||||
// EvalCompareOpt::Result s3 = opt1.fixedPosOptParamsForEach(); //BREAK;
|
|
||||||
// EvalCompareOpt::Result s4 = opt1.optPosOptParamsForEach(); //BREAK;
|
|
||||||
|
|
||||||
// ignoreStaircases = true;
|
EvalWiFiOptResult evalfloor(Settings::fMap);
|
||||||
// ignoreOutdoor = true;
|
evalfloor.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only0th, fps);
|
||||||
// EvalCompareOpt opt2(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
|
evalfloor.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only1st, fps);
|
||||||
// EvalCompareOpt::Result s4b = opt2.optPosOptParamsForEach(); //BREAK;
|
evalfloor.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only2nd, fps);
|
||||||
|
evalfloor.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only3rd, fps);
|
||||||
|
evalfloor.showErrorPerFingerprint<WiFiModelPerFloor>(Settings::wifiEachOptParPos_multimodel, fps);
|
||||||
|
|
||||||
// // save models to file
|
int i = 0; (void) i;
|
||||||
// s1.model.saveXML(Settings::wifiAllFixed);
|
|
||||||
// s2.model.saveXML(Settings::wifiAllOptPar);
|
|
||||||
// s3.model.saveXML(Settings::wifiEachOptPar);
|
|
||||||
// s4.model.saveXML(Settings::wifiEachOptParPos);
|
|
||||||
// s4b.model.saveXML(Settings::wifiEachOptParPosNoStairNoOut);
|
|
||||||
|
|
||||||
// PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
}
|
||||||
// pef.add("\\small{empiric}", s1.errAbs);
|
|
||||||
// pef.add("\\small{real pos, opt params}", s2.errAbs);
|
|
||||||
// pef.add("\\small{real pos, opt params [per AP]}", s3.errAbs);
|
|
||||||
// pef.add("\\small{opt pos, opt params [per AP]}", s4.errAbs);
|
|
||||||
// pef.add("\\small{opt pos, opt params [per AP, no stair, no out]}", s4b.errAbs);
|
|
||||||
|
|
||||||
// pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5));
|
|
||||||
// pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-methods.tex");
|
|
||||||
// pef.writeCodeTo(Settings::fPathGFX + "wifi-opt-error-hist-methods.gp");
|
|
||||||
// pef.getGP() << "set key right bottom width -4 samplen 0.5\n";
|
|
||||||
// pef.getGP() << "set rmargin 0.4\n";
|
|
||||||
// pef.getGP() << "set tmargin 0.4\n";
|
|
||||||
// pef.plot();
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// error histogram all pos, all params, between in/out/stair, in/out, in/stair, in
|
// error histogram all pos, all params, between in/out/stair, in/out, in/stair, in
|
||||||
if(1==0){
|
if(1==0){
|
||||||
@@ -218,7 +239,7 @@ void paperOutputs() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
plot.getPlot().setGrid(true);
|
plot.getPlot().setGrid(true);
|
||||||
plot.getPlot().setLegend(false);
|
plot.getPlot().getKey().setVisible(false);
|
||||||
plot.getPlot().getObjects().add(&rect);
|
plot.getPlot().getObjects().add(&rect);
|
||||||
plot.plot();
|
plot.plot();
|
||||||
|
|
||||||
@@ -263,7 +284,7 @@ int main(void) {
|
|||||||
|
|
||||||
//testWAF();
|
//testWAF();
|
||||||
|
|
||||||
//paperOutputs(); // return 0;
|
paperOutputs(); // return 0;
|
||||||
|
|
||||||
// calib error in/out
|
// calib error in/out
|
||||||
if (1 == 0) {
|
if (1 == 0) {
|
||||||
@@ -297,7 +318,7 @@ int main(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// walks
|
// walks
|
||||||
if (1 == 0) {
|
if (1 == 1) {
|
||||||
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);;
|
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);;
|
||||||
EvalWalk walk(map);
|
EvalWalk walk(map);
|
||||||
walk.walk1();
|
walk.walk1();
|
||||||
@@ -329,10 +350,12 @@ int main(void) {
|
|||||||
//ew1.fixedParams(-64.5905, 1.25988, -2.47863); BREAK;
|
//ew1.fixedParams(-64.5905, 1.25988, -2.47863); BREAK;
|
||||||
//ew1.fixedParams(-59.4903,1.52411,-3.25077); BREAK;
|
//ew1.fixedParams(-59.4903,1.52411,-3.25077); BREAK;
|
||||||
//ew1.load(Settings::wifiEachOptParPos);
|
//ew1.load(Settings::wifiEachOptParPos);
|
||||||
ew1.load(Settings::wifiAllFixed, "empirc");
|
//ew1.load<WiFiModelLogDistCeiling>(Settings::wifiAllFixed, "empirc");
|
||||||
ew1.load(Settings::wifiAllOptPar, "opt params all APs");
|
//ew1.load(Settings::wifiAllOptPar, "opt params all APs");
|
||||||
ew1.load(Settings::wifiEachOptPar, "opt params each AP");
|
//ew1.load(Settings::wifiEachOptPar, "opt params each AP");
|
||||||
ew1.load(Settings::wifiEachOptParPos, "everything opt");
|
ew1.load(Settings::wifiEachOptParPos, "everything opt");
|
||||||
|
ew1.load(Settings::wifiEachOptParPos_multimodel, "model per floor");
|
||||||
|
//ew1.load<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only1st, "everything opt");
|
||||||
|
|
||||||
sleep(1000);
|
sleep(1000);
|
||||||
|
|
||||||
@@ -394,66 +417,4 @@ int main(void) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile("/apps/android/workspace/OTHER2017/data/SHL33a.xml");
|
|
||||||
|
|
||||||
|
|
||||||
// WiFiFingerprints calib("/apps/android/workspace/OTHER2017/data/wifi_fp.dat");
|
|
||||||
|
|
||||||
// VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
|
||||||
|
|
||||||
// WiFiOptimizer opt(map, vap);
|
|
||||||
// opt.addFingerprints(calib);
|
|
||||||
// WiFiOptimizer::APParamsList list = opt.optimizeAll();
|
|
||||||
|
|
||||||
// for (Floorplan::Floor* floor : map->floors) {
|
|
||||||
// for (Floorplan::AccessPoint* ap : floor->accesspoints) {
|
|
||||||
// const WiFiOptimizer::APParamsMAC* params = list.get(ap->mac);
|
|
||||||
// if (params) {
|
|
||||||
// const float delta = ap->getPos(floor).getDistance(Point3(params->params.x, params->params.y, params->params.z));
|
|
||||||
// std::cout << ap->mac << ": " << delta << "m" << std::endl;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// static K::Gnuplot gp;
|
|
||||||
// gp << "set view equal xy\n";
|
|
||||||
|
|
||||||
// K::GnuplotSplot splot;
|
|
||||||
// K::GnuplotSplotElementPoints points; splot.add(&points); points.setPointType(7); points.setPointSize(0.5);
|
|
||||||
// K::GnuplotSplotElementLines lines; splot.add(&lines);
|
|
||||||
|
|
||||||
// for (Floorplan::Floor* floor : map->floors) {
|
|
||||||
// for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
|
||||||
// Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
|
|
||||||
// if (line) {
|
|
||||||
// const K::GnuplotPoint3 p1(line->from.x, line->from.y, floor->atHeight);
|
|
||||||
// const K::GnuplotPoint3 p2(line->to.x, line->to.y, floor->atHeight);
|
|
||||||
// lines.addSegment(p1, p2);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (const WiFiOptimizer::APParamsMAC& ap : list.get()) {
|
|
||||||
// const K::GnuplotPoint3 p3(ap.params.x, ap.params.y, ap.params.z);
|
|
||||||
// points.add(p3);
|
|
||||||
// const Floorplan::AccessPoint* fap = FloorplanHelper::getAP(map, ap.mac);
|
|
||||||
// std::string lbl = (fap) ? (fap->name) : (ap.mac.asString());
|
|
||||||
// if (!fap) {
|
|
||||||
// gp << "set label '" << lbl << "' at " << ap.params.x+1 << "," << ap.params.y+1 << "," << ap.params.z+0.3 << "\n";
|
|
||||||
|
|
||||||
// std::cout << "AP missing in Map: " << ap.mac.asString() << " @ " << ap.params.x << "," << ap.params.y << "," << ap.params.z << std::endl;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// gp.draw(splot);
|
|
||||||
// gp.flush();
|
|
||||||
|
|
||||||
// int i = 0; (void) i;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
63
old/main.h
Normal file
63
old/main.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef MAIN_H
|
||||||
|
#define MAIN_H
|
||||||
|
|
||||||
|
|
||||||
|
// Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile("/apps/android/workspace/OTHER2017/data/SHL33a.xml");
|
||||||
|
|
||||||
|
|
||||||
|
// WiFiFingerprints calib("/apps/android/workspace/OTHER2017/data/wifi_fp.dat");
|
||||||
|
|
||||||
|
// VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||||
|
|
||||||
|
// WiFiOptimizer opt(map, vap);
|
||||||
|
// opt.addFingerprints(calib);
|
||||||
|
// WiFiOptimizer::APParamsList list = opt.optimizeAll();
|
||||||
|
|
||||||
|
// for (Floorplan::Floor* floor : map->floors) {
|
||||||
|
// for (Floorplan::AccessPoint* ap : floor->accesspoints) {
|
||||||
|
// const WiFiOptimizer::APParamsMAC* params = list.get(ap->mac);
|
||||||
|
// if (params) {
|
||||||
|
// const float delta = ap->getPos(floor).getDistance(Point3(params->params.x, params->params.y, params->params.z));
|
||||||
|
// std::cout << ap->mac << ": " << delta << "m" << std::endl;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// static K::Gnuplot gp;
|
||||||
|
// gp << "set view equal xy\n";
|
||||||
|
|
||||||
|
// K::GnuplotSplot splot;
|
||||||
|
// K::GnuplotSplotElementPoints points; splot.add(&points); points.setPointType(7); points.setPointSize(0.5);
|
||||||
|
// K::GnuplotSplotElementLines lines; splot.add(&lines);
|
||||||
|
|
||||||
|
// for (Floorplan::Floor* floor : map->floors) {
|
||||||
|
// for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
||||||
|
// Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
|
||||||
|
// if (line) {
|
||||||
|
// const K::GnuplotPoint3 p1(line->from.x, line->from.y, floor->atHeight);
|
||||||
|
// const K::GnuplotPoint3 p2(line->to.x, line->to.y, floor->atHeight);
|
||||||
|
// lines.addSegment(p1, p2);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// for (const WiFiOptimizer::APParamsMAC& ap : list.get()) {
|
||||||
|
// const K::GnuplotPoint3 p3(ap.params.x, ap.params.y, ap.params.z);
|
||||||
|
// points.add(p3);
|
||||||
|
// const Floorplan::AccessPoint* fap = FloorplanHelper::getAP(map, ap.mac);
|
||||||
|
// std::string lbl = (fap) ? (fap->name) : (ap.mac.asString());
|
||||||
|
// if (!fap) {
|
||||||
|
// gp << "set label '" << lbl << "' at " << ap.params.x+1 << "," << ap.params.y+1 << "," << ap.params.z+0.3 << "\n";
|
||||||
|
|
||||||
|
// std::cout << "AP missing in Map: " << ap.mac.asString() << " @ " << ap.params.x << "," << ap.params.y << "," << ap.params.z << std::endl;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// gp.draw(splot);
|
||||||
|
// gp.flush();
|
||||||
|
|
||||||
|
// int i = 0; (void) i;
|
||||||
|
|
||||||
|
#endif // MAIN_H
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
#include "Indoor/floorplan/v2/FloorplanHelper.h"
|
#include "Indoor/floorplan/v2/FloorplanHelper.h"
|
||||||
#include "Indoor/floorplan/v2/FloorplanCeilings.h"
|
#include "Indoor/floorplan/v2/FloorplanCeilings.h"
|
||||||
|
|
||||||
#include "Indoor/sensors/radio/model/WiFiModelLogDistCeiling.h"
|
#include "Indoor/sensors/radio/model/WiFiModels.h"
|
||||||
|
|
||||||
#include "Indoor/sensors/offline/FileReader.h"
|
#include "Indoor/sensors/offline/FileReader.h"
|
||||||
#include "../Helper.h"
|
#include "../Helper.h"
|
||||||
@@ -50,7 +50,6 @@ class EvalWalk : public Offline::Listener {
|
|||||||
K::ParticleFilter<MyState, MyControl, MyObservation>* pf;
|
K::ParticleFilter<MyState, MyControl, MyObservation>* pf;
|
||||||
|
|
||||||
std::string runName;
|
std::string runName;
|
||||||
WiFiModelLogDistCeiling wifiModel;
|
|
||||||
|
|
||||||
Plotty plotty;
|
Plotty plotty;
|
||||||
PlotWifiMeasurements plotWifi;
|
PlotWifiMeasurements plotWifi;
|
||||||
@@ -79,7 +78,7 @@ class EvalWalk : public Offline::Listener {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EvalWalk(Floorplan::IndoorMap* map) : wifiModel(map), plotty(map), map(map), em(map) {
|
EvalWalk(Floorplan::IndoorMap* map) : plotty(map), map(map), em(map) {
|
||||||
|
|
||||||
const std::string saveFile = Settings::pathData + "/grid.dat";
|
const std::string saveFile = Settings::pathData + "/grid.dat";
|
||||||
grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm);
|
grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm);
|
||||||
@@ -104,14 +103,12 @@ public:
|
|||||||
|
|
||||||
pf = new K::ParticleFilter<MyState, MyControl, MyObservation>( Settings::numParticles, std::unique_ptr<PFInit>(new PFInit(grid)) );
|
pf = new K::ParticleFilter<MyState, MyControl, MyObservation>( Settings::numParticles, std::unique_ptr<PFInit>(new PFInit(grid)) );
|
||||||
|
|
||||||
// TODO: flexible model
|
|
||||||
//wifiModel.loadAPs(map, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF, false);
|
|
||||||
|
|
||||||
// transition
|
// transition
|
||||||
pf->setTransition( std::unique_ptr<PFTrans>( new PFTrans(grid)) );
|
pf->setTransition( std::unique_ptr<PFTrans>( new PFTrans(grid)) );
|
||||||
|
|
||||||
// resampling step?
|
// resampling step?
|
||||||
//pf->setNEffThreshold(0.5);
|
//pf->setNEffThreshold(0.35);
|
||||||
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) );
|
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) );
|
||||||
|
|
||||||
//pf->setNEffThreshold(0.75);
|
//pf->setNEffThreshold(0.75);
|
||||||
@@ -120,17 +117,27 @@ public:
|
|||||||
//pf->setNEffThreshold(0.75);
|
//pf->setNEffThreshold(0.75);
|
||||||
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.05)) );
|
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.05)) );
|
||||||
|
|
||||||
|
K::ParticleFilterResamplingNEff<MyState>* res = new K::ParticleFilterResamplingNEff<MyState>(0.50, 0.05);
|
||||||
pf->setNEffThreshold(1.0);
|
pf->setNEffThreshold(1.0);
|
||||||
pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingNEff<MyState>>(new K::ParticleFilterResamplingNEff<MyState>(0.50, 0.05)) );
|
pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingNEff<MyState>>(res) );
|
||||||
|
|
||||||
|
res->setDrawCallback([&] (K::Particle<MyState>& p) {
|
||||||
|
static std::minstd_rand gen;
|
||||||
|
const MyGridNode* n = grid->getNodePtrFor(p.state.position);
|
||||||
|
std::normal_distribution<float> distTurn(-0.3, +0.3);
|
||||||
|
for (int j = 0; j < 2; ++j) {
|
||||||
|
std::uniform_int_distribution<int> distIdx(0, n->getNumNeighbors()-1);
|
||||||
|
const int idx = distIdx(gen);
|
||||||
|
n = &(grid->getNeighbor(*n, idx));
|
||||||
|
}
|
||||||
|
p.state.position = *n;
|
||||||
|
p.state.heading.direction += distTurn(gen);
|
||||||
|
});
|
||||||
|
|
||||||
// state estimation step
|
// state estimation step
|
||||||
pf->setEstimation( std::unique_ptr<K::ParticleFilterEstimationWeightedAverage<MyState>>(new K::ParticleFilterEstimationWeightedAverage<MyState>()));
|
//pf->setEstimation( std::unique_ptr<K::ParticleFilterEstimationWeightedAverage<MyState>>(new K::ParticleFilterEstimationWeightedAverage<MyState>()));
|
||||||
//pf->setEstimation( std::unique_ptr<K::ParticleFilterEstimationRegionalWeightedAverage<MyState>>(new K::ParticleFilterEstimationRegionalWeightedAverage<MyState>()));
|
//pf->setEstimation( std::unique_ptr<K::ParticleFilterEstimationRegionalWeightedAverage<MyState>>(new K::ParticleFilterEstimationRegionalWeightedAverage<MyState>()));
|
||||||
//pf->setEstimation( std::unique_ptr<K::ParticleFilterEstimationOrderedWeightedAverage<MyState>>(new K::ParticleFilterEstimationOrderedWeightedAverage<MyState>(0.50f)));
|
pf->setEstimation( std::unique_ptr<K::ParticleFilterEstimationOrderedWeightedAverage<MyState>>(new K::ParticleFilterEstimationOrderedWeightedAverage<MyState>(0.25f)));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,8 +159,11 @@ public:
|
|||||||
groundTruth = FloorplanHelper::getGroundTruth(map, pathPoints);
|
groundTruth = FloorplanHelper::getGroundTruth(map, pathPoints);
|
||||||
|
|
||||||
// wifi model
|
// wifi model
|
||||||
WiFiModelLogDistCeiling wifiModel(map);
|
//WiFiModelLogDistCeiling wifiModel(map);
|
||||||
wifiModel.loadXML(Settings::wifiEachOptParPos);
|
//wifiModel.loadXML(Settings::wifiAllFixed);
|
||||||
|
//wifiModel.loadXML(Settings::wifiEachOptParPos);
|
||||||
|
WiFiModelPerFloor wifiModel(map);
|
||||||
|
wifiModel.loadXML(Settings::wifiEachOptParPos_multimodel);
|
||||||
|
|
||||||
// eval
|
// eval
|
||||||
std::unique_ptr<PFEval> eval = std::unique_ptr<PFEval>( new PFEval(grid, wifiModel, em) );
|
std::unique_ptr<PFEval> eval = std::unique_ptr<PFEval>( new PFEval(grid, wifiModel, em) );
|
||||||
|
|||||||
12
pf/PF.h
12
pf/PF.h
@@ -184,7 +184,7 @@ public:
|
|||||||
|
|
||||||
walker.addModule(&modRelHead);
|
walker.addModule(&modRelHead);
|
||||||
walker.addModule(&modAbsHead);
|
walker.addModule(&modAbsHead);
|
||||||
walker.addModule(&modActivity);
|
//walker.addModule(&modActivity);
|
||||||
|
|
||||||
//walker.addModule(&modFavorZ);
|
//walker.addModule(&modFavorZ);
|
||||||
//walker.addModule(&modImportance);
|
//walker.addModule(&modImportance);
|
||||||
@@ -219,8 +219,8 @@ public:
|
|||||||
|
|
||||||
K::Particle<MyState>& p = particles[i];
|
K::Particle<MyState>& p = particles[i];
|
||||||
|
|
||||||
p.weight = std::pow(p.weight, 0.8);
|
p.weight = std::pow(p.weight, 0.5);
|
||||||
|
//p.weight = 1;
|
||||||
double prob;
|
double prob;
|
||||||
p.state = walker.getDestination(*grid, p.state, dist_m, prob);
|
p.state = walker.getDestination(*grid, p.state, dist_m, prob);
|
||||||
//p.weight *= prob;//(prob > 0.01) ? (1.0) : (0.15);
|
//p.weight *= prob;//(prob > 0.01) ? (1.0) : (0.15);
|
||||||
@@ -228,7 +228,7 @@ public:
|
|||||||
//p.weight = prob;
|
//p.weight = prob;
|
||||||
//p.weight = 1.0; // reset
|
//p.weight = 1.0; // reset
|
||||||
//p.weight = std::pow(p.weight, 0.1); // make all particles a little more equal [less strict]
|
//p.weight = std::pow(p.weight, 0.1); // make all particles a little more equal [less strict]
|
||||||
//p.weight *= std::pow(prob, 0.1); // add grid-walk-probability
|
//p.weight *= std::pow(prob, 0.7); // add grid-walk-probability
|
||||||
p.weight *= prob; // grid-walk-probability
|
p.weight *= prob; // grid-walk-probability
|
||||||
if (p.weight != p.weight) {throw Exception("nan");}
|
if (p.weight != p.weight) {throw Exception("nan");}
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ class PFEval : public K::ParticleFilterEvaluation<MyState, MyObservation> {
|
|||||||
|
|
||||||
Grid<MyGridNode>* grid;
|
Grid<MyGridNode>* grid;
|
||||||
|
|
||||||
WiFiModelLogDistCeiling& wifiModel;
|
WiFiModel& wifiModel;
|
||||||
|
|
||||||
EarthMapping& em;
|
EarthMapping& em;
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ class PFEval : public K::ParticleFilterEvaluation<MyState, MyObservation> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PFEval(Grid<MyGridNode>* grid, WiFiModelLogDistCeiling& wifiModel, EarthMapping& em) :
|
PFEval(Grid<MyGridNode>* grid, WiFiModel& wifiModel, EarthMapping& em) :
|
||||||
grid(grid), wifiModel(wifiModel), em(em),
|
grid(grid), wifiModel(wifiModel), em(em),
|
||||||
|
|
||||||
wiFiProbability(Settings::WiFiModel::sigma, wifiModel) { // WiFi free
|
wiFiProbability(Settings::WiFiModel::sigma, wifiModel) { // WiFi free
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class PlotErrFunc {
|
|||||||
K::GnuplotPlot gplot;
|
K::GnuplotPlot gplot;
|
||||||
|
|
||||||
//std::vector<std::string> colors = {"#000000", "#ff0000", "#00bb00", "#0000ff"};
|
//std::vector<std::string> colors = {"#000000", "#ff0000", "#00bb00", "#0000ff"};
|
||||||
std::vector<std::string> colors = {"#000000", "#999999", "#0000ff", "#9999ff", "#ff0000"};
|
std::vector<std::string> colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#00aaaa"};
|
||||||
|
|
||||||
bool markers = false;
|
bool markers = false;
|
||||||
|
|
||||||
@@ -42,10 +42,10 @@ public:
|
|||||||
|
|
||||||
/** ctor with x-axis label */
|
/** ctor with x-axis label */
|
||||||
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
|
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
|
||||||
gplot.setLabelX(xLabel);
|
gplot.getAxisX().setLabel(xLabel);
|
||||||
gplot.setLabelY(yLabel);
|
gplot.getAxisY().setLabel(yLabel);
|
||||||
gplot.setRangeX(K::GnuplotAxisRange(0, K::GnuplotAxisRange::AUTO));
|
gplot.getAxisX().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
|
||||||
gplot.setRangeY(K::GnuplotAxisRange(0, K::GnuplotAxisRange::AUTO));
|
gplot.getAxisY().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** add one curve. Statistics<T> are allowed to be altered outside afterwards! */
|
/** add one curve. Statistics<T> are allowed to be altered outside afterwards! */
|
||||||
@@ -53,7 +53,7 @@ public:
|
|||||||
Entry entry(name, stats);
|
Entry entry(name, stats);
|
||||||
entry.line = new K::GnuplotPlotElementLines();
|
entry.line = new K::GnuplotPlotElementLines();
|
||||||
entry.line->setTitle(name);
|
entry.line->setTitle(name);
|
||||||
entry.line->setLineWidth(2);
|
entry.line->getStroke().setWidth(2);
|
||||||
gplot.add(entry.line);
|
gplot.add(entry.line);
|
||||||
entries.push_back(entry);
|
entries.push_back(entry);
|
||||||
}
|
}
|
||||||
@@ -89,7 +89,7 @@ public:
|
|||||||
const Entry& e = entries[i];
|
const Entry& e = entries[i];
|
||||||
|
|
||||||
e.line->clear();
|
e.line->clear();
|
||||||
e.line->setColorHex(colors[i]);
|
e.line->getStroke().getColor().setHexStr(colors[i]);
|
||||||
|
|
||||||
// distancen between min and max
|
// distancen between min and max
|
||||||
const float minX = e.stats->getQuantile(0);
|
const float minX = e.stats->getQuantile(0);
|
||||||
|
|||||||
@@ -25,16 +25,16 @@ public:
|
|||||||
/** ctor */
|
/** ctor */
|
||||||
PlotErrTime(const std::string& xLabel, const std::string& yLabel, const std::string& y2Label) {
|
PlotErrTime(const std::string& xLabel, const std::string& yLabel, const std::string& y2Label) {
|
||||||
|
|
||||||
gpplot.setLabelX(xLabel);
|
gpplot.getAxisX().setLabel(xLabel);
|
||||||
gpplot.setLabelY(yLabel);
|
gpplot.getAxisY().setLabel(yLabel);
|
||||||
gpplot.setLabelY2(y2Label);
|
gpplot.getAxisY2().setLabel(y2Label);
|
||||||
|
|
||||||
gpplot.add(&lineErr[0]); lineErr[0].setLineWidth(1.5); lineErr[0].setColorHex("#000000");
|
gpplot.add(&lineErr[0]); lineErr[0].getStroke().setWidth(1.5); lineErr[0].getStroke().getColor().setHexStr("#000000");
|
||||||
gpplot.add(&lineErr[1]); lineErr[1].setLineWidth(1.5); lineErr[1].setColorHex("#FF0000");
|
gpplot.add(&lineErr[1]); lineErr[1].getStroke().setWidth(1.5); lineErr[1].getStroke().getColor().setHexStr("#FF0000");
|
||||||
gpplot.add(&lineErr[2]); lineErr[2].setLineWidth(1.5); lineErr[2].setColorHex("#00FF00");
|
gpplot.add(&lineErr[2]); lineErr[2].getStroke().setWidth(1.5); lineErr[2].getStroke().getColor().setHexStr("#00FF00");
|
||||||
gpplot.add(&lineErr[3]); lineErr[3].setLineWidth(1.5); lineErr[3].setColorHex("#0000FF");
|
gpplot.add(&lineErr[3]); lineErr[3].getStroke().setWidth(1.5); lineErr[3].getStroke().getColor().setHexStr("#0000FF");
|
||||||
|
|
||||||
gpplot.add(&lineB); lineB.setLineWidth(1); lineB.setColorHex("#0000ff");
|
gpplot.add(&lineB); lineB.getStroke().setWidth(1); lineB.getStroke().getColor().setHexStr("#0000ff");
|
||||||
gpplot.add(&lineC);
|
gpplot.add(&lineC);
|
||||||
gpplot.setGrid(true);
|
gpplot.setGrid(true);
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ public:
|
|||||||
bool stairs = true;
|
bool stairs = true;
|
||||||
bool obstacles = true;
|
bool obstacles = true;
|
||||||
bool outline = true;
|
bool outline = true;
|
||||||
|
K::GnuplotColor outlineColor = K::GnuplotColor::fromRGB(128,128,128);
|
||||||
float minZ = -9999;
|
float minZ = -9999;
|
||||||
float maxZ = +9999;
|
float maxZ = +9999;
|
||||||
} settings;
|
} settings;
|
||||||
@@ -126,17 +127,17 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
// how to draw the floorplan
|
// how to draw the floorplan
|
||||||
mapOutlineConcrete.setColorHex("#888888"); mapOutlineConcrete.setLineWidth(2);
|
mapOutlineConcrete.getStroke().getColor().setHexStr("#888888"); mapOutlineConcrete.getStroke().setWidth(2);
|
||||||
mapOutlineDrywall.setColorHex("#888888");
|
mapOutlineDrywall.getStroke().getColor().setHexStr("#888888");
|
||||||
mapOutlineGlass.setColorHex("#888888"); mapOutlineGlass.setDashType(2);
|
mapOutlineGlass.getStroke().getColor().setHexStr("#888888"); mapOutlineGlass.getStroke().setType(K::GnuplotDashtype::DASHED);
|
||||||
splot.add(&mapOutlineConcrete);
|
splot.add(&mapOutlineConcrete);
|
||||||
splot.add(&mapOutlineDrywall);
|
splot.add(&mapOutlineDrywall);
|
||||||
splot.add(&mapOutlineGlass);
|
splot.add(&mapOutlineGlass);
|
||||||
|
|
||||||
splot.add(&particles); particles.setPointSize(0.20); //particles.setColorHex("#777777");
|
splot.add(&particles); particles.setPointSize(0.20); //particles.setColorHex("#777777");
|
||||||
|
|
||||||
splot.add(&pathReal); pathReal.setLineWidth(2); pathReal.setColorHex("#000000");
|
splot.add(&pathReal); pathReal.getStroke().setWidth(2); pathReal.getStroke().getColor().setHexStr("#000000");
|
||||||
splot.add(&pathEst); pathEst.setLineWidth(2); pathEst.setColorHex("#0000ff");
|
splot.add(&pathEst); pathEst.getStroke().setWidth(2); pathEst.getStroke().getColor().setHexStr("#0000ff");
|
||||||
|
|
||||||
splot.add(&points);
|
splot.add(&points);
|
||||||
points.setPointType(7);
|
points.setPointType(7);
|
||||||
@@ -208,16 +209,29 @@ public:
|
|||||||
if (p.z > settings.maxZ) {return;}
|
if (p.z > settings.maxZ) {return;}
|
||||||
}
|
}
|
||||||
|
|
||||||
gp << "set object polygon from ";
|
const K::GnuplotFill pfill = (fill) ? (K::GnuplotFill(K::GnuplotFillStyle::SOLID, K::GnuplotColor::fromHexStr(color))) : (K::GnuplotFill::NONE());
|
||||||
for (size_t i = 0; i < points.size(); ++i) {
|
const K::GnuplotStroke pstroke = (!fill) ? (K::GnuplotStroke(K::GnuplotDashtype::SOLID, 1.0, K::GnuplotColor::fromHexStr(color))) : (K::GnuplotStroke::NONE());
|
||||||
const Point3 p = points[i];
|
|
||||||
if (i > 0) {gp << " to ";}
|
K::GnuplotObjectPolygon* poly = new K::GnuplotObjectPolygon(pfill, pstroke);
|
||||||
gp << p.x << "," << p.y << "," << p.z << " ";
|
for (const Point3 p : points) {
|
||||||
|
poly->add(K::GnuplotCoordinate3(p.x, p.y, p.z, K::GnuplotCoordinateSystem::FIRST));
|
||||||
|
poly->setZIndex(p.z); // manual depth ordering
|
||||||
}
|
}
|
||||||
gp << (front ? "front" : "");
|
poly->setFront(front);
|
||||||
if (fill) {gp << " fs solid ";} else {gp << " fs transparent ";}
|
|
||||||
gp << " fc rgb " << "'" << color << "'";
|
splot.getObjects().add(poly);
|
||||||
gp << "\n";
|
|
||||||
|
|
||||||
|
// gp << "set object polygon from ";
|
||||||
|
// for (size_t i = 0; i < points.size(); ++i) {
|
||||||
|
// const Point3 p = points[i];
|
||||||
|
// if (i > 0) {gp << " to ";}
|
||||||
|
// gp << p.x << "," << p.y << "," << p.z << " ";
|
||||||
|
// }
|
||||||
|
// gp << (front ? "front" : "");
|
||||||
|
// if (fill) {gp << " fs solid ";} else {gp << " fs transparent ";}
|
||||||
|
// gp << " fc rgb " << "'" << color << "'";
|
||||||
|
// gp << "\n";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,6 +303,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void plot() {
|
void plot() {
|
||||||
|
|
||||||
|
this->mapOutlineConcrete.getStroke().setColor(settings.outlineColor);
|
||||||
|
this->mapOutlineDrywall.getStroke().setColor(settings.outlineColor);
|
||||||
|
this->mapOutlineGlass.getStroke().setColor(settings.outlineColor);
|
||||||
|
|
||||||
gp.draw(splot);
|
gp.draw(splot);
|
||||||
gp << "unset multiplot\n"; // scaling
|
gp << "unset multiplot\n"; // scaling
|
||||||
if (codeFile != "") {
|
if (codeFile != "") {
|
||||||
@@ -313,10 +332,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// process each selected floor
|
||||||
for (Floorplan::Floor* floor : floors) {
|
for (Floorplan::Floor* floor : floors) {
|
||||||
|
|
||||||
// plot obstacles
|
// plot obstacles?
|
||||||
if (settings.obstacles) {
|
if (settings.obstacles) {
|
||||||
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
||||||
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
|
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
|
||||||
@@ -338,14 +357,15 @@ public:
|
|||||||
// plot the floor's outline
|
// plot the floor's outline
|
||||||
if (settings.outline) {
|
if (settings.outline) {
|
||||||
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
|
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
|
||||||
gp << "set object polygon from ";
|
K::GnuplotColor color = (poly->outdoor) ? (K::GnuplotColor::fromRGB(200, 240, 200)) : (K::GnuplotColor::fromRGB(210,210,210));
|
||||||
for (size_t i = 0; i < poly->poly.points.size() + 1; ++i) {
|
K::GnuplotFill filler(K::GnuplotFillStyle::SOLID, color);
|
||||||
if (i > 0) {gp << " to ";}
|
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, K::GnuplotStroke::NONE());
|
||||||
const Point2 pt = poly->poly.points[i % poly->poly.points.size()]; // ensures closing the polygon
|
for (Point2 pt : poly->poly.points) {
|
||||||
gp << pt.x << "," << pt.y << "," << floor->atHeight << " ";
|
K::GnuplotCoordinate3 coord(pt.x, pt.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST);
|
||||||
|
gpol->add(coord);
|
||||||
}
|
}
|
||||||
gp << " fs solid fc rgb " << ( poly->outdoor ? "'#bbeebb'" : "'#dddddd'");
|
gpol->close();
|
||||||
gp << "\n";
|
splot.getObjects().add(gpol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,8 @@
|
|||||||
abstract
|
abstract
|
||||||
|
system setup kostet oft sehr viel zeit [fingerprinting kostet]
|
||||||
|
deshalb werden alternativen untersucht:
|
||||||
|
bekannte AP position mit empirischen parametern
|
||||||
|
und optimierung durch einige referenzmessungen
|
||||||
|
|
||||||
|
floorplan wird für die navigation bzw orientierung des anwenders eh gebraucht
|
||||||
|
dann kann man ihn auch gleich für ein bewegungsmodell nutzen
|
||||||
|
|||||||
@@ -1 +1,17 @@
|
|||||||
conclusion
|
conclusion
|
||||||
|
|
||||||
|
beide ansaetze sind in unserem szenario/gebaeude OK:
|
||||||
|
bekannte AP-pos + empirische parameter
|
||||||
|
komplette optimierung über fingerprints
|
||||||
|
|
||||||
|
100 prozent optimierung ist nicht moeglich, es gibt
|
||||||
|
immer stellen, die, zugunsten von anderen, schlechter werden.
|
||||||
|
es haengt auch stark davon ab, was man optimiert, das modell,
|
||||||
|
die uebereinstimmung, welche fingerprints [schlechte vs. gute stellen]
|
||||||
|
|
||||||
|
zudem ist das modell fuer unser gebaeude nicht gut ggeeignet.
|
||||||
|
zu viele verschiedene materialien und trennwaende, APs immer in raeumen,
|
||||||
|
nie auf dem flur. viele hindernisse, wenige freie raeume.
|
||||||
|
andere modelle koennten hier helfen, erfordern dann aber zur
|
||||||
|
laufzeit mehr berechnung, oder muessten vorab auf einem grid berechnet
|
||||||
|
werden \todo{cite auf competition}
|
||||||
|
|||||||
@@ -8,6 +8,24 @@ modell direkt fuer den gelaufenen pfad optimiert (also wirklich jede wifi messun
|
|||||||
der fehler wird zwar kleiner, ist aber immernoch deutlich spürbar. das spricht dafür, dass das modell einfach nicht
|
der fehler wird zwar kleiner, ist aber immernoch deutlich spürbar. das spricht dafür, dass das modell einfach nicht
|
||||||
gut geeignet ist.
|
gut geeignet ist.
|
||||||
|
|
||||||
|
outdoor fehler kann gemnindert werden mit z.B.
|
||||||
|
nicht nur die APs nehmen die ich sehe, sondern auch die, die ich sehen müsste
|
||||||
|
dann wird klar, dass es nicht gut passt. allerdings ist das auch gefaehrlich
|
||||||
|
[nicht immer tauchen alle APs im scan auf] und welchen fehler bzw. welche
|
||||||
|
dBm zahl nimmt man fuer fehlende APs an? das ist eine hardware-frage.
|
||||||
|
|
||||||
|
ein workaround fuer steigende fehler durch optimierung koennte sein,
|
||||||
|
dass man nicht jeden AP einzeln optimiert, sondern das gesamtsystem.
|
||||||
|
und auch nicht den dB fehler, sondern 'die wahrscheinlichkeit an dieser stelle zu sein'
|
||||||
|
bzw: 'die wahrscheinlichkeit aller anderen positionen minimieren' dass keine
|
||||||
|
fehl-positionierungen [wie outdoor] mehr stattfinden. allerdings ist das
|
||||||
|
problematisch da man auch hier entscheiden müsste wann ein AP nicht mehr
|
||||||
|
sichtbar ist etc.
|
||||||
|
|
||||||
|
walk1 hat eine issue kurz bevor man zur tuer zum hoersaalgebaude reingeht
|
||||||
|
je nach resampling killt dieser wlan error evtl alle partikel!
|
||||||
|
|
||||||
|
|
||||||
optimierungs input: alle 4 walks samt ground-truth
|
optimierungs input: alle 4 walks samt ground-truth
|
||||||
dann kommt fuer die 4 typen [fixed, all same par, each par, each par pos]
|
dann kommt fuer die 4 typen [fixed, all same par, each par, each par pos]
|
||||||
log probability 50 75, meter 50, 75
|
log probability 50 75, meter 50, 75
|
||||||
@@ -75,3 +93,5 @@ outdoor hat insgesamt nicht all zu viel einfluss, da die meisten APs
|
|||||||
an den outdoor punkten kaum gesehen werden. auf einzelne APs kann
|
an den outdoor punkten kaum gesehen werden. auf einzelne APs kann
|
||||||
der einfluss jedoch recht groß sein, siehe den fingerprint plot von
|
der einfluss jedoch recht groß sein, siehe den fingerprint plot von
|
||||||
dem einen ausgewählten AP
|
dem einen ausgewählten AP
|
||||||
|
|
||||||
|
wenn noch zeit ist: wie aendert sich die model prediction wenn man z.B. nur die haelfte der referenzmessungen nimmt?
|
||||||
|
|||||||
@@ -1 +1,30 @@
|
|||||||
introduction
|
introduction
|
||||||
|
|
||||||
|
|
||||||
|
setupzeiten von indoor systemen sind hoch [fingerprinting]
|
||||||
|
auch re-calibration kostet oft zeit
|
||||||
|
|
||||||
|
meistens hat man einen gebäudeplan
|
||||||
|
oft auch die info wo APs hängen
|
||||||
|
warum das nicht nutzen und mit einer groben AP position
|
||||||
|
+ fixen, empirischen param starten?
|
||||||
|
|
||||||
|
was bekomme ich für eine genauigkeit raus?
|
||||||
|
|
||||||
|
was kann ich machen um das zu verbessern?
|
||||||
|
model parameter anlernen?
|
||||||
|
|
||||||
|
wo sind die schwächen?
|
||||||
|
verschiedene modelle mit unterschiedlichem berechnungsaufwand.
|
||||||
|
|
||||||
|
indoor komplett-system mit IMU, abs-heading, rel-heading, wifi sensor
|
||||||
|
gebäudeplan, bewegungsmodell
|
||||||
|
|
||||||
|
fokus:
|
||||||
|
- wlan parameter + optimierung
|
||||||
|
- evaluation der einzel und gesamtergebnisse
|
||||||
|
|
||||||
|
contribution:
|
||||||
|
- neues wifi modell,
|
||||||
|
- neues resampling,
|
||||||
|
- model param optimierung + eval was es bringt
|
||||||
|
|||||||
@@ -1,5 +1,97 @@
|
|||||||
log normal shadowing model
|
\section{Indoor Positioning System}
|
||||||
so wie log-dist modell nur mit waf. hier: fuer decken. waende werden aktuell nicht betrachtet
|
|
||||||
|
nur grob beschreiben wie unser system funktioniert,
|
||||||
|
dass die absolute positionierung aus dem wlan kommt,
|
||||||
|
dass man dafür entweder viele fingerprints oder ein modell braucht
|
||||||
|
dann kommts zu dem modell
|
||||||
|
|
||||||
|
\subsection{Sensor Fusion}
|
||||||
|
|
||||||
|
Gesamtsystem
|
||||||
|
dann einzel-komponenten
|
||||||
|
|
||||||
|
\subsection{Signal Strength Prediction}
|
||||||
|
|
||||||
|
\begin{equation}
|
||||||
|
x = \mTXP{} + 10 \mPLE{} + \log_{10} \frac{d}{d_0} + \mGaussNoise{}
|
||||||
|
\label{eq:logDistModel}
|
||||||
|
\end{equation}
|
||||||
|
|
||||||
|
The log distance model \todo{cite} in \refeq{eq:logDistModel} is a commonly used signal strength prediction model that
|
||||||
|
is intended for line-of-sight predictions. However, depending on the surroundings, the model is versatile enough
|
||||||
|
to also serve for indoor purposes.
|
||||||
|
%
|
||||||
|
This model predicts an \docAP{}'s signal strength
|
||||||
|
for an arbitrary location given the distance between both and two environmental parameters:
|
||||||
|
The \docAPshort{}'s signal strength \mTXP{} measurable at a known distance $d_0$ (usually \SI{1}{\meter}) and
|
||||||
|
the signal's depletion over distance \mPLE{}, which depends on the \docAPshort{}'s surroundings like walls
|
||||||
|
and other obstacles.
|
||||||
|
\mGaussNoise{} is a zero-mean Gaussian noise and models the uncertainty.
|
||||||
|
|
||||||
|
The log normal shadowing model is a slight modification, to adapt the log distance model to indoor use cases.
|
||||||
|
It introduces an additional parameter, that models obstalces between (line-of-sight) the \docAPshort{} and the
|
||||||
|
location in question by attenuating the signal with a constant value.
|
||||||
|
%
|
||||||
|
Depending on the use case, this value describes the number and type of walls, ceilings, floors etc. between both locations.
|
||||||
|
For obstacles, this requires an intersection-test of each obstacle with the line-of-sight, which is costly
|
||||||
|
for larger buildings. For realtime use on a smartphone, a (discretized) model pre-computation might thus be necessary
|
||||||
|
\todo{cite competition}.
|
||||||
|
|
||||||
|
\begin{equation}
|
||||||
|
x = \mTXP{} + 10 \mPLE{} + \log_{10} \frac{d}{d_0} + \numFloors{} \mWAF{} + \mGaussNoise{}
|
||||||
|
\label{eq:logNormShadowModel}
|
||||||
|
\end{equation}
|
||||||
|
|
||||||
|
Throughout this work, walls are ignored and only floors/ceilings are considered for the model.
|
||||||
|
In \refeq{eq:logNormShadowModel}, floors/ceilings
|
||||||
|
are included using a constant attenuation factor \mWAF{} multiplied by the number of floors/ceilings \numFloors{}
|
||||||
|
between sender and the location in question. Assuming \todo{passendes wort?} buildings, this number can be determined
|
||||||
|
without costly intersection checks and thus allows for realtime use cases.
|
||||||
|
The attenuation \mWAF{} depends on the building's architecture and for common, steel enforced concrete floors
|
||||||
|
$\approx 8.0$ might be a viable choice \todo{cite}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\subsection {Model Setup}
|
||||||
|
|
||||||
|
As previously mentioned, for the prediction model to work, one needs to know the locations of all
|
||||||
|
permanently installed \docAP{}s within the building plus their environmental parameters.
|
||||||
|
%
|
||||||
|
While it is possible to use empiric values for \mTXP, \mPLE and \mWAF \cite{Ebner-15}, the positions are mandtatory.
|
||||||
|
|
||||||
|
For many installations, there should be floorplans that include the locations of all installed transmitters.
|
||||||
|
If so, a model setup takes only several minutes to (vaguely) position the \docAPshort{}s within a virtual
|
||||||
|
map and assigning them some fixed, empirically choosen parameters for \mTXP, \mPLE and \mWAF.
|
||||||
|
Depending on the building's architecture this might already provide enough accuracy for some use-cases
|
||||||
|
where a vague location information is sufficient.
|
||||||
|
|
||||||
|
|
||||||
|
\subsection{Parameter Optimization}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\input{gfx/wifiop_show_optfunc_params}
|
||||||
|
\label{fig:wifiOptFuncParams}
|
||||||
|
\caption{The average error (in \SI{}{\decibel}) between reference measurements and model predictions for one \docAPshort{} dependent on \docTXP{} and \docEXP{} [fixed position and \mWAF{}] denotes a convex function.}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
\begin{figure}
|
||||||
|
\input{gfx/wifiop_show_optfunc_pos_yz}
|
||||||
|
\label{fig:wifiOptFuncPosYZ}
|
||||||
|
\caption{The average error (in \SI{}{\decibel}) between reference measurements and model predictions for one \docAPshort{} dependent on $y$- and $z$-position [fixed $x$, \mTXP{}, \mPLE{} and \mWAF{}] usually denotes a non-convex function with multiple [here: two] local minima.}
|
||||||
|
\end{figure}
|
||||||
|
|
||||||
|
while optimizing txp and exp usually means optimizing a concave function,
|
||||||
|
optimzing the positiong usually isn't. Especially when the z-coordinate
|
||||||
|
[influencing the WAF] is involved. While this can be mitigated by introducing
|
||||||
|
a continuous function for the WAF like a sigmoid, this will still not work
|
||||||
|
for all situations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -9,6 +101,24 @@ b) bekannte pos + opt params (fur alle APs gleich) [simplex]
|
|||||||
c) bekannte pos + opt params (eigene je AP) [simplex]
|
c) bekannte pos + opt params (eigene je AP) [simplex]
|
||||||
d) alles opt: pos und params (je ap) [range-random]
|
d) alles opt: pos und params (je ap) [range-random]
|
||||||
|
|
||||||
|
wenn man nur die fingerprints des floors nimmt in dem gelaufen wird, ist alles gut
|
||||||
|
sobald man andere floors drueber/drunter dazu nimmt, ist es nicht mehr gnaz so gut, oder wird schlechter
|
||||||
|
das spricht dafuer dass das modell nicht gut passt
|
||||||
|
koennte man zeigen indem man den durchschnittlichen fehler je fingerprint plottet???
|
||||||
|
|
||||||
|
the optimization-result also depends on the optimzation target:
|
||||||
|
a) the (average) error between measurment and model prediction
|
||||||
|
b) the (average) probability for the model's prediction given the fingerprint, ...
|
||||||
|
c) ...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
\subsection {VAP grouping}
|
||||||
|
VAP grouping erklaeren
|
||||||
|
|
||||||
|
|
||||||
probleme bei der optimierung beschreiben. convex usw..
|
probleme bei der optimierung beschreiben. convex usw..
|
||||||
wo geht simplex gut, wo eher nicht
|
wo geht simplex gut, wo eher nicht
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,6 @@
|
|||||||
\newcommand{\mLogDistGamma}{\ensuremath{\gamma}}
|
\newcommand{\mLogDistGamma}{\ensuremath{\gamma}}
|
||||||
\newcommand{\mLogDistTX}{TX}
|
\newcommand{\mLogDistTX}{TX}
|
||||||
|
|
||||||
\newcommand{\mDongle}[1]{\ensuremath{D_{#1}}}
|
|
||||||
%\newcommand{\mDongle}{d} % dongle
|
|
||||||
\newcommand{\mBeacon}[1]{\ensuremath{B_{#1}}} % beacon
|
|
||||||
|
|
||||||
\newcommand{\mRssi}{\ensuremath{s}} % client's signal-strength measurement
|
\newcommand{\mRssi}{\ensuremath{s}} % client's signal-strength measurement
|
||||||
\newcommand{\mMdlRSSI}{\ensuremath{\varsigma}} % model's signal-strength
|
\newcommand{\mMdlRSSI}{\ensuremath{\varsigma}} % model's signal-strength
|
||||||
@@ -39,8 +36,6 @@
|
|||||||
\newcommand{\mSteps}{n_\text{steps}}
|
\newcommand{\mSteps}{n_\text{steps}}
|
||||||
\newcommand{\mObsSteps}{\mSteps}
|
\newcommand{\mObsSteps}{\mSteps}
|
||||||
|
|
||||||
\newcommand{\mNN}{\text{nn}}
|
|
||||||
\newcommand{\mKNN}{\text{knn}}
|
|
||||||
\newcommand{\fPos}[1]{\textbf{pos}(#1)}
|
\newcommand{\fPos}[1]{\textbf{pos}(#1)}
|
||||||
\newcommand{\fDistance}[2]{\delta(#1, #2)}
|
\newcommand{\fDistance}[2]{\delta(#1, #2)}
|
||||||
\newcommand{\fWA}[1]{\text{wall}(#1)}
|
\newcommand{\fWA}[1]{\text{wall}(#1)}
|
||||||
@@ -122,7 +117,9 @@
|
|||||||
|
|
||||||
\newcommand{\mPLE}{\ensuremath{\gamma}} % path-loss exponent
|
\newcommand{\mPLE}{\ensuremath{\gamma}} % path-loss exponent
|
||||||
\newcommand{\mTXP}{\ensuremath{P_0}} % tx-power
|
\newcommand{\mTXP}{\ensuremath{P_0}} % tx-power
|
||||||
|
\newcommand{\numFloors}{\ensuremath{n}}
|
||||||
\newcommand{\mWAF}{\ensuremath{\beta}} % wall attenuation factor
|
\newcommand{\mWAF}{\ensuremath{\beta}} % wall attenuation factor
|
||||||
|
\newcommand{\mGaussNoise}{\ensuremath{X}}
|
||||||
|
|
||||||
\newcommand{\mMdlDist}{\ensuremath{d}} % distance used within propagation models
|
\newcommand{\mMdlDist}{\ensuremath{d}} % distance used within propagation models
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
% keyword macros
|
% keyword macros
|
||||||
\newcommand{\docIBeacon}{iBeacon}
|
\newcommand{\docIBeacon}{iBeacon}
|
||||||
|
|
||||||
% wifi naming
|
|
||||||
\newcommand{\wifiRSSI}{RSSI}
|
|
||||||
\newcommand{\wifiTxPower}{TX-Power}
|
|
||||||
\newcommand{\wifiPathLossExp}{PathLoss}
|
|
||||||
|
|
||||||
\newcommand{\wifiPropLogScale}{Log-Scale}
|
\newcommand{\wifiPropLogScale}{Log-Scale}
|
||||||
\newcommand{\wifiPropLogScaleWalls}{Log-Scale-Walls}
|
\newcommand{\wifiPropLogScaleWalls}{Log-Scale-Walls}
|
||||||
@@ -13,9 +9,8 @@
|
|||||||
|
|
||||||
|
|
||||||
% misc
|
% misc
|
||||||
\newcommand{\docTxPower}{TX-Power}
|
\newcommand{\docTXP}{TX-power}
|
||||||
\newcommand{\docPathLossExp}{PathLoss}
|
\newcommand{\docEXP}{path loss exponent}
|
||||||
\newcommand{\docPathLoss}{Pathloss}
|
|
||||||
|
|
||||||
\newcommand{\docsAP}{AP}
|
\newcommand{\docsAP}{AP}
|
||||||
\newcommand{\docAPshort}{AP}
|
\newcommand{\docAPshort}{AP}
|
||||||
|
|||||||
328
wifi/EvalWiFiConvex.h
Normal file
328
wifi/EvalWiFiConvex.h
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
#ifndef EVALWIFICONVEX_H
|
||||||
|
#define EVALWIFICONVEX_H
|
||||||
|
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
||||||
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
||||||
|
#include "Indoor/sensors/radio/model/WiFiModels.h"
|
||||||
|
|
||||||
|
#include "Indoor/sensors/radio/VAPGrouper.h"
|
||||||
|
#include "Indoor/sensors/offline/FileReader.h"
|
||||||
|
|
||||||
|
#include "Indoor/floorplan/v2/Floorplan.h"
|
||||||
|
#include "Indoor/floorplan/v2/FloorplanReader.h"
|
||||||
|
#include "Indoor/floorplan/v2/FloorplanHelper.h"
|
||||||
|
#include "Indoor/floorplan/v2/FloorplanCeilings.h"
|
||||||
|
|
||||||
|
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementColorPoints.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
||||||
|
#include <KLib/misc/gnuplot/GnuplotSplotElementMesh.h>
|
||||||
|
|
||||||
|
#include <KLib/math/statistics/Statistics.h>
|
||||||
|
|
||||||
|
//#include "../Structs.h"
|
||||||
|
#include "../plots/Plotty.h"
|
||||||
|
#include "../plots/PlotErrTime.h"
|
||||||
|
#include "../plots/PlotErrFunc.h"
|
||||||
|
#include "../Settings.h"
|
||||||
|
#include "../Helper.h"
|
||||||
|
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
class EvalWiFiConvex {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Floorplan::IndoorMap* map;
|
||||||
|
std::vector<APAtFloor> mapAPs;
|
||||||
|
WiFiFingerprints calib;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
EvalWiFiConvex(Floorplan::IndoorMap* map, const std::string& fpFile) : map(map){
|
||||||
|
|
||||||
|
// all APs within the map
|
||||||
|
mapAPs = FloorplanHelper::getAPs(map);
|
||||||
|
|
||||||
|
// load fingerprints
|
||||||
|
calib = WiFiFingerprints(fpFile);
|
||||||
|
|
||||||
|
// VAP-group
|
||||||
|
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::MEDIAN);
|
||||||
|
for (WiFiFingerprint& fp : calib.getFingerprints()) {
|
||||||
|
fp.measurements = vap.group(fp.measurements);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void showParams() {
|
||||||
|
|
||||||
|
K::Gnuplot gp;
|
||||||
|
K::GnuplotSplot splot;
|
||||||
|
K::GnuplotSplotElementMesh mesh; splot.add(&mesh);
|
||||||
|
|
||||||
|
//splot.setTitle("optimizing TXP and EXP}");
|
||||||
|
splot.getAxisX().setLabel("TXP (dBm)");
|
||||||
|
splot.getAxisX().setLabelOffset(-3.9, -1.9);
|
||||||
|
splot.getAxisX().setTicsStep(2.5);
|
||||||
|
splot.getAxisX().setTicsOffset(-1, -0.1);
|
||||||
|
|
||||||
|
splot.getAxisY().setLabel("EXP");
|
||||||
|
splot.getAxisY().setLabelOffset(-0.5, -0.6);
|
||||||
|
splot.getAxisY().setTicsOffset(-0.3, -0.5);
|
||||||
|
|
||||||
|
splot.getAxisZ().setLabel("error (dB)");
|
||||||
|
|
||||||
|
splot.getAxisCB().setTicsStep(4);
|
||||||
|
|
||||||
|
splot.getView().setCamera(55, 115);
|
||||||
|
splot.getAxisZ().setLabelRotation(90);
|
||||||
|
splot.setStringMod(new K::GnuplotStringModLaTeX());
|
||||||
|
|
||||||
|
std::string name = Settings::fPathGFX + "/wifiop_show_optfunc_params";
|
||||||
|
gp.setOutput(name + ".tex");
|
||||||
|
gp.setTerminal("epslatex", K::GnuplotSize(8.7, 5.0));
|
||||||
|
splot.getAxisZ().setTicsVisible(false);
|
||||||
|
splot.getAxisZ().setLabel("");
|
||||||
|
gp << "set palette defined (0 '#00ff00', 1 '#eeeeee', 9 '#222222')\n";
|
||||||
|
|
||||||
|
gp << "set margins 0,0,0,0\n";
|
||||||
|
gp << "set multiplot layout 1,1 scale 1.25, 1.4 offset 0.02, 0.05\n";
|
||||||
|
gp << "set colorbox horizontal user origin 0.03, 0.95 size 0.4, 0.03\n";
|
||||||
|
|
||||||
|
//p mac="D8:84:66:4A:23:F0" px="46" py="47.400002" pz="13.8" txp="-40" exp="2.6500001" waf="-6.5"/>
|
||||||
|
const MACAddress mac("D8:84:66:4A:23:F0");
|
||||||
|
const Point3 pos_m(46, 47.4, 13.8);
|
||||||
|
const float waf = -6;
|
||||||
|
|
||||||
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
||||||
|
|
||||||
|
for (float txp = -45; txp <= -35; txp += 0.5) {
|
||||||
|
for (float exp = 1.5; exp <= 3.5; exp += 0.05) {
|
||||||
|
|
||||||
|
WiFiModelLogDistCeiling model(map);
|
||||||
|
model.addAP(mac, pos_m, txp, exp, waf);
|
||||||
|
|
||||||
|
const K::Statistics<float> res = getError(mac, model, fps);
|
||||||
|
const float err = res.getAvg();
|
||||||
|
mesh.add(K::GnuplotPoint3(txp, exp, err));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gp.draw(splot);
|
||||||
|
LeHelper::writeCode(name + ".gp", gp.getBuffer());
|
||||||
|
gp.flush();
|
||||||
|
|
||||||
|
//sleep(100);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// void showPos() {
|
||||||
|
|
||||||
|
// K::Gnuplot gp;
|
||||||
|
// K::GnuplotSplot splot;
|
||||||
|
// K::GnuplotSplotElementMesh mesh; splot.add(&mesh);
|
||||||
|
|
||||||
|
// //splot.setTitle("optimizing position");
|
||||||
|
// splot.getAxisX().setLabel("x-position (meter)");
|
||||||
|
// splot.getAxisY().setLabel("y-position (meter)");
|
||||||
|
// splot.getAxisZ().setLabel("error (dB)");
|
||||||
|
|
||||||
|
// splot.getAxisZ().setLabelRotation(90);
|
||||||
|
// splot.setStringMod(new K::GnuplotStringModLaTeX());
|
||||||
|
// gp << "set palette defined (0 '#00ff00', 1 '#eeeeee', 9 '#000000')\n";
|
||||||
|
|
||||||
|
// const MACAddress mac("D8:84:66:4A:23:F0");
|
||||||
|
// const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
||||||
|
|
||||||
|
// const Point3 pos_m(46, 47.4, 13.8);
|
||||||
|
// const float txp = -40;
|
||||||
|
// const float exp = 2.2;
|
||||||
|
// const float waf = -6;
|
||||||
|
|
||||||
|
// for (float ox = -10; ox <= +10; ox += 0.5) {
|
||||||
|
// for (float oy = -19; oy <= +8; oy += 0.5) {
|
||||||
|
|
||||||
|
// const Point3 pos = pos_m + Point3(ox, oy, 0);
|
||||||
|
|
||||||
|
// WiFiModelLogDistCeiling model(map);
|
||||||
|
// model.addAP(mac, pos, txp, exp, waf);
|
||||||
|
|
||||||
|
// const K::Statistics<float> res = getError(mac, model, fps);
|
||||||
|
// const float err = res.getAvg();
|
||||||
|
// mesh.add(K::GnuplotPoint3(pos.x, pos.y, err));
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// gp.draw(splot);
|
||||||
|
// gp.flush();
|
||||||
|
|
||||||
|
// //sleep(100);
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
void showPosZ() {
|
||||||
|
|
||||||
|
K::Gnuplot gp;
|
||||||
|
K::GnuplotSplot splot;
|
||||||
|
K::GnuplotSplotElementMesh mesh; splot.add(&mesh);
|
||||||
|
K::GnuplotSplotElementLines lines1; splot.add(&lines1); lines1.getStroke().setWidth(2); lines1.getStroke().setType(K::GnuplotDashtype::DOTTED);
|
||||||
|
K::GnuplotSplotElementLines lines2; splot.add(&lines2); lines2.getStroke().setWidth(2); lines2.getStroke().setType(K::GnuplotDashtype::DASHED);
|
||||||
|
K::GnuplotSplotElementLines lines3; splot.add(&lines3); lines3.getStroke().setWidth(2);
|
||||||
|
K::GnuplotSplotElementPoints points; splot.add(&points); points.setPointSize(1.5); points.setPointType(7);
|
||||||
|
|
||||||
|
//splot.setTitle("optimizing position");
|
||||||
|
splot.getAxisX().setLabel("y-pos (meter)");
|
||||||
|
splot.getAxisX().setLabelOffset(-0.9, -1.4);
|
||||||
|
splot.getAxisX().setTicsOffset(-0.9, 0);
|
||||||
|
splot.getAxisX().setTicsStep(25);
|
||||||
|
|
||||||
|
splot.getAxisY().setLabel("z-pos (meter)");
|
||||||
|
splot.getAxisY().setLabelOffset(0, -0.3);
|
||||||
|
splot.getAxisY().setTicsOffset(0, -0.5);
|
||||||
|
|
||||||
|
splot.getAxisY().setTicsStep(3);
|
||||||
|
|
||||||
|
//splot.getAxisZ().setLabel("error (dB)");
|
||||||
|
//splot.getAxisZ().setTicsStep(3);
|
||||||
|
//splot.getAxisZ().setLabelRotation(90);
|
||||||
|
splot.getAxisZ().setLabel("");
|
||||||
|
splot.getAxisZ().setTicsVisible(false);
|
||||||
|
splot.getAxisCB().setTicsStep(3);
|
||||||
|
|
||||||
|
|
||||||
|
std::string name = Settings::fPathGFX + "/wifiop_show_optfunc_pos_yz";
|
||||||
|
gp.setOutput(name + ".tex");
|
||||||
|
gp.setTerminal("epslatex", K::GnuplotSize(8.7, 5.0));
|
||||||
|
gp << "set palette defined (0 '#00ff00', 1 '#eeeeee', 9 '#222222')\n";
|
||||||
|
gp << "set margins 0,0,0,0\n";
|
||||||
|
gp << "set multiplot layout 1,1 scale 1.25,1.4 offset 0.02, 0.05\n";
|
||||||
|
gp << "set colorbox horizontal user origin 0.57, 0.95 size 0.4, 0.03\n";
|
||||||
|
|
||||||
|
// paper out
|
||||||
|
splot.setStringMod(new K::GnuplotStringModLaTeX());
|
||||||
|
splot.getView().setCamera(38, 109);
|
||||||
|
|
||||||
|
const MACAddress mac("D8:84:66:4A:23:F0");
|
||||||
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
||||||
|
|
||||||
|
const Point3 pos_m(46-15, 47.4-15, 13.8);
|
||||||
|
const float txp = -40;
|
||||||
|
const float exp = 2.2;
|
||||||
|
const float waf = -6;
|
||||||
|
|
||||||
|
const int steps = 35;
|
||||||
|
|
||||||
|
for (float sz = 0; sz < steps; ++sz) {
|
||||||
|
for (int sy = 0; sy < steps; ++sy) {
|
||||||
|
|
||||||
|
const float oz = -15.0f + 20.0f * sz / steps;
|
||||||
|
const float oy = -35.0f + 90.0f * sy / steps;
|
||||||
|
|
||||||
|
const Point3 pos = pos_m + Point3(0, oy, oz);
|
||||||
|
|
||||||
|
WiFiModelLogDistCeiling model(map);
|
||||||
|
model.addAP(mac, pos, txp, exp, waf);
|
||||||
|
|
||||||
|
const K::Statistics<float> res = getError(mac, model, fps);
|
||||||
|
const float err = res.getAvg();
|
||||||
|
const K::GnuplotPoint3 gp3(pos.y, pos.z, err);
|
||||||
|
mesh.add(gp3);
|
||||||
|
|
||||||
|
if (sy == 0) {lines1.add(gp3);}
|
||||||
|
if (sy == 17) {lines2.add(gp3);}
|
||||||
|
if (sz == 24) {lines3.add(gp3);}
|
||||||
|
|
||||||
|
if (sy == 9 && sz == 24) {points.add(gp3);}
|
||||||
|
if (sy == 26 && sz == 24) {points.add(gp3);}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gp.draw(splot);
|
||||||
|
LeHelper::writeCode(name + ".gp", gp.getBuffer());
|
||||||
|
gp.flush();
|
||||||
|
|
||||||
|
int i = 0; (void) i;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<WiFiFingerprint> getFingerprints(const MACAddress& mac) {
|
||||||
|
|
||||||
|
// get all fingerprints where the given mac was seen
|
||||||
|
const std::vector<WiFiFingerprint> fps = calib.getFingerprintsFor(mac);
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
if (fps.size() < 5) {throw Exception("not enought fingerprints for AP " + mac.asString());}
|
||||||
|
|
||||||
|
return fps;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** calculate the error for the given AP [mac + configured model] for all fingerprints for this mac */
|
||||||
|
K::Statistics<float> getError(const MACAddress& mac, const WiFiModelLogDistCeiling& model) {
|
||||||
|
|
||||||
|
// get all fingerprints where the given mac was seen
|
||||||
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
||||||
|
|
||||||
|
// fire
|
||||||
|
return getError(mac, model, fps);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** calculate the error for the given AP [mac + configured model] for all of the given FPS */
|
||||||
|
K::Statistics<float> getError(const MACAddress& mac, const WiFiModelLogDistCeiling& model, const std::vector<WiFiFingerprint>& fps) {
|
||||||
|
|
||||||
|
K::Statistics<float> res;
|
||||||
|
|
||||||
|
// calculate the model error for each fingerprint
|
||||||
|
for (const WiFiFingerprint& fp : fps) {
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
|
if (fp.measurements.entries.size() != 1) {throw Exception("invalid fingerprint");}
|
||||||
|
if (fp.measurements.entries.front().getAP().getMAC() != mac) {throw Exception("invalid fingerprint");}
|
||||||
|
|
||||||
|
// rssi prediction from the configured model
|
||||||
|
const float model_rssi = model.getRSSI(mac, fp.pos_m);
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
if (model_rssi != model_rssi) {throw Exception("model rssi not available for " + mac.asString());}
|
||||||
|
|
||||||
|
// rssi measured during scan at this location
|
||||||
|
const float scan_rssi = fp.measurements.entries.front().getRSSI();
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
if (scan_rssi < -100) {throw Exception("scan rssi out of range for " + mac.asString());}
|
||||||
|
if (scan_rssi > -35) {throw Exception("scan rssi out of range for " + mac.asString());}
|
||||||
|
|
||||||
|
// dB error
|
||||||
|
const float err = model_rssi - scan_rssi;
|
||||||
|
|
||||||
|
// quadratic
|
||||||
|
float aErr = std::pow(std::abs(err), 1);
|
||||||
|
|
||||||
|
res.add(aErr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EVALWIFICONVEX_H
|
||||||
Reference in New Issue
Block a user