many eval things

moved obsolete code
TeX work
This commit is contained in:
2017-04-10 18:20:11 +02:00
parent b2adb16b49
commit 32674e3fbb
21 changed files with 1063 additions and 251 deletions

View File

@@ -58,7 +58,7 @@ ADD_DEFINITIONS(
-fstack-protector-all
-g3
-O2
-O0
-march=native
-DWITH_TESTS

View File

@@ -167,7 +167,16 @@ public:
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 {
Result res(map);
@@ -179,7 +188,7 @@ public:
const MACAddress mac(ap->mac);
const Point3 pos_m = ap->getPos(floor);
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.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) {
return errFunc(params[0], params[1], params[2]).errSingle.getAvg();
return whatToOpt(errFunc(params[0], params[1], params[2]).errSingle);
};
// use simplex
float params[3] = {-40, 2, -8};
K::NumOptAlgoDownhillSimplex<float> opt(3);
opt.setMaxIterations(40);
opt.setNumRestarts(20);
opt.setMaxIterations(50);
opt.setNumRestarts(25);
opt.calculateOptimum(optFunc, params);
// // use genetic
@@ -232,7 +241,7 @@ public:
const Point3 pos_m = ap->getPos(floor);
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> {
WiFiModelLogDistCeiling model(map); // new, empty model for this AP
model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
@@ -240,16 +249,16 @@ public:
return err;
};
// to-be-optimized function: reduce average error among all fingerprints/AP's
// to-be-optimized function
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
float params[3] = {-40, 2, -8};
K::NumOptAlgoDownhillSimplex<float> opt(3);
opt.setMaxIterations(40);
opt.setNumRestarts(20);
opt.setMaxIterations(50);
opt.setNumRestarts(25);
opt.calculateOptimum(optFunc, params);
// // use genetic
@@ -289,7 +298,7 @@ public:
const MACAddress mac(ap->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> {
WiFiModelLogDistCeiling model(map); // new, empty model for this AP
model.addAP(mac, pos_m, txp, exp, waf, false); // allow unsafe txp,exp,waf params
@@ -297,10 +306,10 @@ public:
return err;
};
// to-be-optimized function: reduce average error among all fingerprints/AP's
// to-be-optimized function
auto optFunc = [&] (const float* params) {
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
@@ -344,7 +353,7 @@ public:
K::NumOptAlgoRangeRandom<float> opt(valRegion);
opt.setPopulationSize(300);
opt.setNumIerations(75);
opt.setNumIerations(100);
opt.calculateOptimum(optFunc, params);
@@ -376,6 +385,14 @@ public:
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) {
// 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 > -35) {throw Exception("scan rssi out of range for " + mac.asString());}
// difference
//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);
// dB error
const float err = model_rssi - scan_rssi;
// 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
// if (model.getAP(mac).waf > -2) {aErr += 9999;}

View File

@@ -5,6 +5,7 @@
#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"
@@ -32,6 +33,7 @@
#include "CSV.h"
#include <unordered_set>
#include <thread>
template <typename T> class Line {
@@ -122,7 +124,7 @@ public:
// opt = new WiFiOptimizer::LogDistCeiling(map, *vap, *calib, WiFiOptimizer::LogDistCeiling::Mode::MEDIUM);
// 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->showMarkers(false);
@@ -130,10 +132,10 @@ public:
pef2 = new PlotErrFunc("\\small{-log(p(..))}", "\\small{measurements (\\%)}");
pef2->showMarkers(false);
pet = new PlotErrTime("2", "3", "");
pet->getPlot().setRangeY(K::GnuplotAxisRange(0, 40));
pet = new PlotErrTime("walktime (seconds)", "\\small{error (m)}", "");
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->buildFloorplan();
@@ -143,35 +145,25 @@ public:
void load(const std::string& xmlFile, const std::string& name) {
WiFiModelFactory fac(map);
// setup the model
WiFiModelLogDistCeiling* wiModel = new WiFiModelLogDistCeiling(map);
wiModel->loadXML(xmlFile);
this->wiModel = wiModel;
this->wiModel = fac.loadXML(xmlFile);
// fire
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:
void build(const std::string& name) {
K::GnuplotStroke stroke(
K::GnuplotDashtype::SOLID, 1.5,
K::GnuplotColor::AUTO()
);
static int idx = -1; ++idx;
@@ -179,6 +171,7 @@ private:
Line<Point3> path;
K::GnuplotSplotElementLines* gpPath = new K::GnuplotSplotElementLines();
gpPath->setStroke(stroke);
plot->splot.add(gpPath);
K::Statistics<float>* stats = new K::Statistics<float>();
@@ -275,11 +268,11 @@ private:
// parameters
float params[3];
// USE GENETIC
// std::minstd_rand gen;
// 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> distZ(mapBBox.getMin().z, mapBBox.getMax().z);
// // initializer for the optimizer: random position within the map's bbox
// auto init = [&] (const int childIdx, float* params) {
// (void) childIdx;
@@ -287,13 +280,13 @@ private:
// params[1] = distY(gen);
// params[2] = distZ(gen);
// };
// K::NumOptAlgoGenetic<float> opt(3);
// opt.setPopulationSize(400);
// opt.setMaxIterations(20);
// opt.calculateOptimum(func, params, init);
// USE RANGE RANDOM WITH COOLING
using LeOpt = K::NumOptAlgoRangeRandom<float>;
const std::vector<LeOpt::MinMax> valRegion = {
LeOpt::MinMax(mapBBox.getMin().x, mapBBox.getMax().x), // x
@@ -304,7 +297,7 @@ private:
K::NumOptAlgoRangeRandom<float> opt(valRegion);
opt.setPopulationSize(200);
opt.setNumIerations(50);
//opt.calculateOptimum(func, params);
opt.calculateOptimum(func, params);
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";
// error
//const float err_m = gt.xy().getDistance(curEst.xy());
const float err_m = gt.getDistance(curEst);
const float err_m = gt.xy().getDistance(curEst.xy()); // 2D
//const float err_m = gt.getDistance(curEst); // 3D
stats->add(err_m);
float gtFloat[3] = {gt.x, gt.y, gt.z};
const double probOnGT = -func(gtFloat);
const double logProbOnGT = -log(probOnGT);
statsProbOnGT->add(logProbOnGT);
const double logProbOnGT = -std::log10(probOnGT);
const double logProbOnGTNorm = (logProbOnGT/mes.entries.size());
statsProbOnGT->add(logProbOnGTNorm);
static int xxx = 0; ++xxx;
// plot err
pet->addErr(ts, err_m, idx);
pet2->addErr(ts, logProbOnGT/mes.entries.size(), idx);
pet2->addErr(ts, logProbOnGTNorm, idx);
// fire
plot->plot();
if (xxx%2 == 0) {
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
View 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

View File

@@ -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") {
Plotty* p = new Plotty(map);

View File

@@ -20,7 +20,13 @@ namespace Settings {
const std::string wifiAllOptPar = pathWiFi + "allOptPar.xml";
const std::string wifiEachOptPar = pathWiFi + "eachOptPar.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 {
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! */
// constexpr float TXP = -44;

205
main.cpp
View File

@@ -4,6 +4,7 @@
#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"
@@ -28,6 +29,9 @@
#include "EvalWiFi.h"
#include "EvalWiFiSigStrength.h"
#include "pf/EvalWalk.h"
#include "EvalWifiOptResult.h"
#include "wifi/EvalWiFiConvex.h"
#include "plots/PlotErrFunc.h"
@@ -36,6 +40,18 @@ void paperOutputs() {
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
if (1==0){
EvalWiFiSigStrength sig(Settings::fMap, Settings::fCalib);
@@ -69,28 +85,62 @@ void paperOutputs() {
// };
// EvalCompareOpt2 opt1(Settings::fMap, calibWalks);
auto remove = [] (const WiFiFingerprint& fp) -> bool {
return fp.pos_m.z != 4;
auto removeNone = [] (const WiFiFingerprint& fp) -> bool {
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?
bool ignoreStaircases = false;
bool ignoreOutdoor = false;
bool ignoreIndoor = false;
EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, remove);
EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, removeNone);
// optimize using all floors
EvalCompareOpt2::Result s1 = opt1.fixedPosFixedParamsForAll(); //BREAK;
EvalCompareOpt2::Result s2 = opt1.fixedPosOptParamsForAll(); //BREAK;
EvalCompareOpt2::Result s3 = opt1.fixedPosOptParamsForEach(); //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
s1.model.saveXML(Settings::wifiAllFixed);
s2.model.saveXML(Settings::wifiAllOptPar);
s3.model.saveXML(Settings::wifiEachOptPar);
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 (\\%)}");
pef.add("\\small{empiric}", &s1.errSingle);
@@ -106,68 +156,39 @@ void paperOutputs() {
pef.getGP() << "set tmargin 0.4\n";
pef.plot();
return;
int i = 0; (void) i;
//return;
//sleep(1000);
}
// REPLACED BY EVAL OPT 2
// // perform varios AP-param optimizations
// // 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) {
/** plot wifi eval results */
if (1 == 1) {
// bool ignoreStaircases = false;
// bool ignoreOutdoor = false;
// bool ignoreIndoor = false;
WiFiFingerprints fps;
fps.load(Settings::fCalib);
// // use walks?
//// std::vector<std::pair<std::string, std::vector<int>>> calibWalks = {
//// 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);
EvalWiFiOptResult eval1(Settings::fMap);
eval1.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos, fps);
// // use fingerprints?
// EvalCompareOpt opt1(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
EvalWiFiOptResult eval2(Settings::fMap);
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;
// ignoreOutdoor = true;
// EvalCompareOpt opt2(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
// EvalCompareOpt::Result s4b = opt2.optPosOptParamsForEach(); //BREAK;
EvalWiFiOptResult evalfloor(Settings::fMap);
evalfloor.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only0th, fps);
evalfloor.showErrorPerFingerprint<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only1st, fps);
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
// 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);
int i = 0; (void) i;
// 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
if(1==0){
@@ -218,7 +239,7 @@ void paperOutputs() {
);
plot.getPlot().setGrid(true);
plot.getPlot().setLegend(false);
plot.getPlot().getKey().setVisible(false);
plot.getPlot().getObjects().add(&rect);
plot.plot();
@@ -263,7 +284,7 @@ int main(void) {
//testWAF();
//paperOutputs(); // return 0;
paperOutputs(); // return 0;
// calib error in/out
if (1 == 0) {
@@ -297,7 +318,7 @@ int main(void) {
}
// walks
if (1 == 0) {
if (1 == 1) {
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);;
EvalWalk walk(map);
walk.walk1();
@@ -329,10 +350,12 @@ int main(void) {
//ew1.fixedParams(-64.5905, 1.25988, -2.47863); BREAK;
//ew1.fixedParams(-59.4903,1.52411,-3.25077); BREAK;
//ew1.load(Settings::wifiEachOptParPos);
ew1.load(Settings::wifiAllFixed, "empirc");
ew1.load(Settings::wifiAllOptPar, "opt params all APs");
ew1.load(Settings::wifiEachOptPar, "opt params each AP");
//ew1.load<WiFiModelLogDistCeiling>(Settings::wifiAllFixed, "empirc");
//ew1.load(Settings::wifiAllOptPar, "opt params all APs");
//ew1.load(Settings::wifiEachOptPar, "opt params each AP");
ew1.load(Settings::wifiEachOptParPos, "everything opt");
ew1.load(Settings::wifiEachOptParPos_multimodel, "model per floor");
//ew1.load<WiFiModelLogDistCeiling>(Settings::wifiEachOptParPos_only1st, "everything opt");
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
View 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

View File

@@ -31,7 +31,7 @@
#include "Indoor/floorplan/v2/FloorplanHelper.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 "../Helper.h"
@@ -50,7 +50,6 @@ class EvalWalk : public Offline::Listener {
K::ParticleFilter<MyState, MyControl, MyObservation>* pf;
std::string runName;
WiFiModelLogDistCeiling wifiModel;
Plotty plotty;
PlotWifiMeasurements plotWifi;
@@ -79,7 +78,7 @@ class EvalWalk : public Offline::Listener {
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";
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)) );
// TODO: flexible model
//wifiModel.loadAPs(map, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF, false);
// transition
pf->setTransition( std::unique_ptr<PFTrans>( new PFTrans(grid)) );
// resampling step?
//pf->setNEffThreshold(0.5);
//pf->setNEffThreshold(0.35);
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) );
//pf->setNEffThreshold(0.75);
@@ -120,17 +117,27 @@ public:
//pf->setNEffThreshold(0.75);
//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->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
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::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);
// wifi model
WiFiModelLogDistCeiling wifiModel(map);
wifiModel.loadXML(Settings::wifiEachOptParPos);
//WiFiModelLogDistCeiling wifiModel(map);
//wifiModel.loadXML(Settings::wifiAllFixed);
//wifiModel.loadXML(Settings::wifiEachOptParPos);
WiFiModelPerFloor wifiModel(map);
wifiModel.loadXML(Settings::wifiEachOptParPos_multimodel);
// eval
std::unique_ptr<PFEval> eval = std::unique_ptr<PFEval>( new PFEval(grid, wifiModel, em) );

12
pf/PF.h
View File

@@ -184,7 +184,7 @@ public:
walker.addModule(&modRelHead);
walker.addModule(&modAbsHead);
walker.addModule(&modActivity);
//walker.addModule(&modActivity);
//walker.addModule(&modFavorZ);
//walker.addModule(&modImportance);
@@ -219,8 +219,8 @@ public:
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;
p.state = walker.getDestination(*grid, p.state, dist_m, prob);
//p.weight *= prob;//(prob > 0.01) ? (1.0) : (0.15);
@@ -228,7 +228,7 @@ public:
//p.weight = prob;
//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(prob, 0.1); // add grid-walk-probability
//p.weight *= std::pow(prob, 0.7); // add grid-walk-probability
p.weight *= prob; // grid-walk-probability
if (p.weight != p.weight) {throw Exception("nan");}
@@ -247,7 +247,7 @@ class PFEval : public K::ParticleFilterEvaluation<MyState, MyObservation> {
Grid<MyGridNode>* grid;
WiFiModelLogDistCeiling& wifiModel;
WiFiModel& wifiModel;
EarthMapping& em;
@@ -260,7 +260,7 @@ class PFEval : public K::ParticleFilterEvaluation<MyState, MyObservation> {
public:
PFEval(Grid<MyGridNode>* grid, WiFiModelLogDistCeiling& wifiModel, EarthMapping& em) :
PFEval(Grid<MyGridNode>* grid, WiFiModel& wifiModel, EarthMapping& em) :
grid(grid), wifiModel(wifiModel), em(em),
wiFiProbability(Settings::WiFiModel::sigma, wifiModel) { // WiFi free

View File

@@ -31,7 +31,7 @@ class PlotErrFunc {
K::GnuplotPlot gplot;
//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;
@@ -42,10 +42,10 @@ public:
/** ctor with x-axis label */
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
gplot.setLabelX(xLabel);
gplot.setLabelY(yLabel);
gplot.setRangeX(K::GnuplotAxisRange(0, K::GnuplotAxisRange::AUTO));
gplot.setRangeY(K::GnuplotAxisRange(0, K::GnuplotAxisRange::AUTO));
gplot.getAxisX().setLabel(xLabel);
gplot.getAxisY().setLabel(yLabel);
gplot.getAxisX().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
gplot.getAxisY().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
}
/** add one curve. Statistics<T> are allowed to be altered outside afterwards! */
@@ -53,7 +53,7 @@ public:
Entry entry(name, stats);
entry.line = new K::GnuplotPlotElementLines();
entry.line->setTitle(name);
entry.line->setLineWidth(2);
entry.line->getStroke().setWidth(2);
gplot.add(entry.line);
entries.push_back(entry);
}
@@ -89,7 +89,7 @@ public:
const Entry& e = entries[i];
e.line->clear();
e.line->setColorHex(colors[i]);
e.line->getStroke().getColor().setHexStr(colors[i]);
// distancen between min and max
const float minX = e.stats->getQuantile(0);

View File

@@ -25,16 +25,16 @@ public:
/** ctor */
PlotErrTime(const std::string& xLabel, const std::string& yLabel, const std::string& y2Label) {
gpplot.setLabelX(xLabel);
gpplot.setLabelY(yLabel);
gpplot.setLabelY2(y2Label);
gpplot.getAxisX().setLabel(xLabel);
gpplot.getAxisY().setLabel(yLabel);
gpplot.getAxisY2().setLabel(y2Label);
gpplot.add(&lineErr[0]); lineErr[0].setLineWidth(1.5); lineErr[0].setColorHex("#000000");
gpplot.add(&lineErr[1]); lineErr[1].setLineWidth(1.5); lineErr[1].setColorHex("#FF0000");
gpplot.add(&lineErr[2]); lineErr[2].setLineWidth(1.5); lineErr[2].setColorHex("#00FF00");
gpplot.add(&lineErr[3]); lineErr[3].setLineWidth(1.5); lineErr[3].setColorHex("#0000FF");
gpplot.add(&lineErr[0]); lineErr[0].getStroke().setWidth(1.5); lineErr[0].getStroke().getColor().setHexStr("#000000");
gpplot.add(&lineErr[1]); lineErr[1].getStroke().setWidth(1.5); lineErr[1].getStroke().getColor().setHexStr("#FF0000");
gpplot.add(&lineErr[2]); lineErr[2].getStroke().setWidth(1.5); lineErr[2].getStroke().getColor().setHexStr("#00FF00");
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.setGrid(true);

View File

@@ -107,6 +107,7 @@ public:
bool stairs = true;
bool obstacles = true;
bool outline = true;
K::GnuplotColor outlineColor = K::GnuplotColor::fromRGB(128,128,128);
float minZ = -9999;
float maxZ = +9999;
} settings;
@@ -126,17 +127,17 @@ public:
// how to draw the floorplan
mapOutlineConcrete.setColorHex("#888888"); mapOutlineConcrete.setLineWidth(2);
mapOutlineDrywall.setColorHex("#888888");
mapOutlineGlass.setColorHex("#888888"); mapOutlineGlass.setDashType(2);
mapOutlineConcrete.getStroke().getColor().setHexStr("#888888"); mapOutlineConcrete.getStroke().setWidth(2);
mapOutlineDrywall.getStroke().getColor().setHexStr("#888888");
mapOutlineGlass.getStroke().getColor().setHexStr("#888888"); mapOutlineGlass.getStroke().setType(K::GnuplotDashtype::DASHED);
splot.add(&mapOutlineConcrete);
splot.add(&mapOutlineDrywall);
splot.add(&mapOutlineGlass);
splot.add(&particles); particles.setPointSize(0.20); //particles.setColorHex("#777777");
splot.add(&pathReal); pathReal.setLineWidth(2); pathReal.setColorHex("#000000");
splot.add(&pathEst); pathEst.setLineWidth(2); pathEst.setColorHex("#0000ff");
splot.add(&pathReal); pathReal.getStroke().setWidth(2); pathReal.getStroke().getColor().setHexStr("#000000");
splot.add(&pathEst); pathEst.getStroke().setWidth(2); pathEst.getStroke().getColor().setHexStr("#0000ff");
splot.add(&points);
points.setPointType(7);
@@ -208,16 +209,29 @@ public:
if (p.z > settings.maxZ) {return;}
}
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 << " ";
const K::GnuplotFill pfill = (fill) ? (K::GnuplotFill(K::GnuplotFillStyle::SOLID, K::GnuplotColor::fromHexStr(color))) : (K::GnuplotFill::NONE());
const K::GnuplotStroke pstroke = (!fill) ? (K::GnuplotStroke(K::GnuplotDashtype::SOLID, 1.0, K::GnuplotColor::fromHexStr(color))) : (K::GnuplotStroke::NONE());
K::GnuplotObjectPolygon* poly = new K::GnuplotObjectPolygon(pfill, pstroke);
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" : "");
if (fill) {gp << " fs solid ";} else {gp << " fs transparent ";}
gp << " fc rgb " << "'" << color << "'";
gp << "\n";
poly->setFront(front);
splot.getObjects().add(poly);
// 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() {
this->mapOutlineConcrete.getStroke().setColor(settings.outlineColor);
this->mapOutlineDrywall.getStroke().setColor(settings.outlineColor);
this->mapOutlineGlass.getStroke().setColor(settings.outlineColor);
gp.draw(splot);
gp << "unset multiplot\n"; // scaling
if (codeFile != "") {
@@ -313,10 +332,10 @@ public:
}
}
// process each selected floor
for (Floorplan::Floor* floor : floors) {
// plot obstacles
// plot obstacles?
if (settings.obstacles) {
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
@@ -338,14 +357,15 @@ public:
// plot the floor's outline
if (settings.outline) {
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
gp << "set object polygon from ";
for (size_t i = 0; i < poly->poly.points.size() + 1; ++i) {
if (i > 0) {gp << " to ";}
const Point2 pt = poly->poly.points[i % poly->poly.points.size()]; // ensures closing the polygon
gp << pt.x << "," << pt.y << "," << floor->atHeight << " ";
K::GnuplotColor color = (poly->outdoor) ? (K::GnuplotColor::fromRGB(200, 240, 200)) : (K::GnuplotColor::fromRGB(210,210,210));
K::GnuplotFill filler(K::GnuplotFillStyle::SOLID, color);
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, K::GnuplotStroke::NONE());
for (Point2 pt : poly->poly.points) {
K::GnuplotCoordinate3 coord(pt.x, pt.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST);
gpol->add(coord);
}
gp << " fs solid fc rgb " << ( poly->outdoor ? "'#bbeebb'" : "'#dddddd'");
gp << "\n";
gpol->close();
splot.getObjects().add(gpol);
}
}

View File

@@ -1 +1,8 @@
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

View File

@@ -1 +1,17 @@
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}

View File

@@ -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
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
dann kommt fuer die 4 typen [fixed, all same par, each par, each par pos]
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
der einfluss jedoch recht groß sein, siehe den fingerprint plot von
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?

View File

@@ -1 +1,30 @@
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

View File

@@ -1,5 +1,97 @@
log normal shadowing model
so wie log-dist modell nur mit waf. hier: fuer decken. waende werden aktuell nicht betrachtet
\section{Indoor Positioning System}
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]
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..
wo geht simplex gut, wo eher nicht

View File

@@ -4,9 +4,6 @@
\newcommand{\mLogDistGamma}{\ensuremath{\gamma}}
\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{\mMdlRSSI}{\ensuremath{\varsigma}} % model's signal-strength
@@ -39,8 +36,6 @@
\newcommand{\mSteps}{n_\text{steps}}
\newcommand{\mObsSteps}{\mSteps}
\newcommand{\mNN}{\text{nn}}
\newcommand{\mKNN}{\text{knn}}
\newcommand{\fPos}[1]{\textbf{pos}(#1)}
\newcommand{\fDistance}[2]{\delta(#1, #2)}
\newcommand{\fWA}[1]{\text{wall}(#1)}
@@ -122,7 +117,9 @@
\newcommand{\mPLE}{\ensuremath{\gamma}} % path-loss exponent
\newcommand{\mTXP}{\ensuremath{P_0}} % tx-power
\newcommand{\numFloors}{\ensuremath{n}}
\newcommand{\mWAF}{\ensuremath{\beta}} % wall attenuation factor
\newcommand{\mGaussNoise}{\ensuremath{X}}
\newcommand{\mMdlDist}{\ensuremath{d}} % distance used within propagation models

View File

@@ -1,10 +1,6 @@
% keyword macros
\newcommand{\docIBeacon}{iBeacon}
% wifi naming
\newcommand{\wifiRSSI}{RSSI}
\newcommand{\wifiTxPower}{TX-Power}
\newcommand{\wifiPathLossExp}{PathLoss}
\newcommand{\wifiPropLogScale}{Log-Scale}
\newcommand{\wifiPropLogScaleWalls}{Log-Scale-Walls}
@@ -13,9 +9,8 @@
% misc
\newcommand{\docTxPower}{TX-Power}
\newcommand{\docPathLossExp}{PathLoss}
\newcommand{\docPathLoss}{Pathloss}
\newcommand{\docTXP}{TX-power}
\newcommand{\docEXP}{path loss exponent}
\newcommand{\docsAP}{AP}
\newcommand{\docAPshort}{AP}

328
wifi/EvalWiFiConvex.h Normal file
View 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