current state
This commit is contained in:
@@ -58,7 +58,7 @@ ADD_DEFINITIONS(
|
||||
-fstack-protector-all
|
||||
|
||||
-g3
|
||||
-O2
|
||||
-O0
|
||||
-march=native
|
||||
|
||||
-DWITH_TESTS
|
||||
|
||||
@@ -24,6 +24,13 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
// FOR TESTING
|
||||
#define FAST 1
|
||||
#define QUALITY 2
|
||||
#define MODE QUALITY
|
||||
|
||||
//#define DO_SHOW_FINGERPRINTS
|
||||
|
||||
class EvalCompareOpt2 {
|
||||
|
||||
int power = 1;
|
||||
@@ -36,14 +43,14 @@ class EvalCompareOpt2 {
|
||||
public:
|
||||
|
||||
/** ctor with map and fingerprints */
|
||||
EvalCompareOpt2(const std::string& mapFile, const std::string& fpFile, std::function<bool(const WiFiFingerprint& fp)> remove) {
|
||||
EvalCompareOpt2(const std::string& mapFile, const std::string& fpFile, std::function<bool(const WiFiFingerprint& fp)> remove, bool removeStaircases = false) {
|
||||
|
||||
setup(mapFile);
|
||||
|
||||
// load fingerprints
|
||||
calib = WiFiFingerprints(fpFile);
|
||||
// if (ignoreOutdoor) {calib = LeHelper::removeOutdoor(calib);}
|
||||
// if (ignoreStaircases) {calib = LeHelper::removeStaircases(calib);}
|
||||
if (removeStaircases) {calib = LeHelper::removeStaircases(calib);}
|
||||
// if (ignoreIndoor) {calib = LeHelper::removeIndoor(calib);}
|
||||
calib = LeHelper::removeIf(calib, remove);
|
||||
|
||||
@@ -120,7 +127,9 @@ private:
|
||||
}
|
||||
|
||||
// plot
|
||||
#ifdef DO_SHOW_FINGERPRINTS
|
||||
LeHelper::plot(map, calib);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -205,8 +214,13 @@ public:
|
||||
// use simplex
|
||||
float params[3] = {-40, 2, -8};
|
||||
K::NumOptAlgoDownhillSimplex<float> opt(3);
|
||||
#if MODE == FAST
|
||||
opt.setMaxIterations(50);
|
||||
opt.setNumRestarts(10);
|
||||
#elif MODE == QUALITY
|
||||
opt.setMaxIterations(200);
|
||||
opt.setNumRestarts(25);
|
||||
#endif
|
||||
opt.calculateOptimum(optFunc, params);
|
||||
|
||||
// // use genetic
|
||||
@@ -257,8 +271,13 @@ public:
|
||||
// use simplex
|
||||
float params[3] = {-40, 2, -8};
|
||||
K::NumOptAlgoDownhillSimplex<float> opt(3);
|
||||
opt.setMaxIterations(50);
|
||||
opt.setNumRestarts(25);
|
||||
#if MODE == FAST
|
||||
opt.setMaxIterations(50);
|
||||
opt.setNumRestarts(10);
|
||||
#elif MODE == QUALITY
|
||||
opt.setMaxIterations(200);
|
||||
opt.setNumRestarts(25);
|
||||
#endif
|
||||
opt.calculateOptimum(optFunc, params);
|
||||
|
||||
// // use genetic
|
||||
@@ -352,8 +371,15 @@ public:
|
||||
};
|
||||
|
||||
K::NumOptAlgoRangeRandom<float> opt(valRegion);
|
||||
opt.setPopulationSize(300);
|
||||
opt.setNumIerations(100);
|
||||
|
||||
#if MODE == FAST
|
||||
opt.setPopulationSize(100);
|
||||
opt.setNumIerations(50);
|
||||
#elif MODE == QUALITY
|
||||
opt.setPopulationSize(500);
|
||||
opt.setNumIerations(250);
|
||||
#endif
|
||||
|
||||
opt.calculateOptimum(optFunc, params);
|
||||
|
||||
|
||||
|
||||
@@ -111,10 +111,10 @@ namespace Settings {
|
||||
// OTHER2017 [frank]
|
||||
const std::vector<int> path1 = {40, 41, 42, 43, 44, 45, 1, 0, 46, 47, 48, 49, 50, 51, 52};
|
||||
const std::vector<int> path2 = {53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66};
|
||||
const std::vector<int> path3 = {52, 51, 67, 68, 50, 49, 69, 70, 71, 72, 73, 74, 75, 76, 77, 73, 78, 79, 80, 81, 61, 82, 83, 84, 42, 41, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95};
|
||||
//const std::vector<int> path3 = {52, 51, 67, 68, 50, 49, 69, 70, 71, 72, 73, 74, 75, 76, 77, 73, 78, 79, 80, 81, 61, 82, 83, 84, 42, 41, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95};
|
||||
|
||||
const std::vector<int> path_toni_all_1 = {40,41,42,43,44,45, 1, 0, 46,47,48,49,50,51,52};
|
||||
const std::vector<int> path_toni_all_2 = {53,54,55,56,57,58,59,60,61,62,63,64,65,66};
|
||||
//const std::vector<int> path_toni_all_1 = {40,41,42,43,44,45, 1, 0, 46,47,48,49,50,51,52}; // same as PATH1
|
||||
//const std::vector<int> path_toni_all_2 = {53,54,55,56,57,58,59,60,61,62,63,64,65,66}; // same as PATH2
|
||||
|
||||
const std::vector<int> path_toni_inst_1 = {0,1,2,3,4,5,6,7,8,9,10};
|
||||
const std::vector<int> path_toni_inst_2 = {11, 12, 3, 2, 1, 0, 13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, 11};
|
||||
|
||||
715
main.cpp
715
main.cpp
@@ -39,6 +39,472 @@
|
||||
|
||||
#include "plots/PlotErrFunc.h"
|
||||
|
||||
|
||||
void rebuildAllModels(Floorplan::IndoorMap* map, const int skip = 0, bool ignoreStaircases = false) {
|
||||
|
||||
// // 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),
|
||||
// };
|
||||
// EvalCompareOpt2 opt1(Settings::fMap, calibWalks);
|
||||
|
||||
int skipCnt = 0;
|
||||
auto skipper = [&] (const WiFiFingerprint& fp) -> bool {
|
||||
if (skip == 0) {return false;}
|
||||
++skipCnt;
|
||||
return ((skipCnt % skip) != 0);
|
||||
};
|
||||
|
||||
// all combined
|
||||
auto removeNone = [] (const WiFiFingerprint& fp) -> bool {return false;};
|
||||
|
||||
// per floor
|
||||
auto only0th = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || std::abs(fp.pos_m.z - (1.3)) > 0.1;};
|
||||
auto only1st = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || std::abs(fp.pos_m.z - (4+1.3)) > 0.1;};
|
||||
auto only2nd = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || std::abs(fp.pos_m.z - (4+3.4+1.3)) > 0.1;};
|
||||
auto only3rd = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || std::abs(fp.pos_m.z - (4+3.4+3.4+1.3)) > 0.1;};
|
||||
|
||||
// per bbox
|
||||
#include "bboxes.h"
|
||||
auto only0H = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes0H.contains(fp.pos_m);};
|
||||
auto only0O = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes0O.contains(fp.pos_m);};
|
||||
auto only0I = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes0I.contains(fp.pos_m);};
|
||||
|
||||
auto only1H = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes1H.contains(fp.pos_m);};
|
||||
auto only1O = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes1O.contains(fp.pos_m);};
|
||||
auto only1I = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes1I.contains(fp.pos_m);};
|
||||
|
||||
auto only2H = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes2H.contains(fp.pos_m);};
|
||||
|
||||
auto only3H = [&] (const WiFiFingerprint& fp) -> bool {return skipper(fp) || !bboxes3H.contains(fp.pos_m);};
|
||||
|
||||
|
||||
// use fingerprints?
|
||||
EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, skipper, ignoreStaircases);
|
||||
|
||||
|
||||
// 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 per floor
|
||||
EvalCompareOpt2 opt_f0(Settings::fMap, Settings::fCalib, only0th, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf0 = opt_f0.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_f1(Settings::fMap, Settings::fCalib, only1st, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf1 = opt_f1.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_f2(Settings::fMap, Settings::fCalib, only2nd, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf2 = opt_f2.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_f3(Settings::fMap, Settings::fCalib, only3rd, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf3 = opt_f3.optPosOptParamsForEach();
|
||||
|
||||
|
||||
// optimize per bbox
|
||||
EvalCompareOpt2 opt_0H(Settings::fMap, Settings::fCalib, only0H, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf0H = opt_0H.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_0O(Settings::fMap, Settings::fCalib, only0O, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf0O = opt_0O.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_0I(Settings::fMap, Settings::fCalib, only0I, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf0I = opt_0I.optPosOptParamsForEach();
|
||||
|
||||
EvalCompareOpt2 opt_1H(Settings::fMap, Settings::fCalib, only1H, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf1H = opt_1H.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_1O(Settings::fMap, Settings::fCalib, only1O, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf1O = opt_1O.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_1I(Settings::fMap, Settings::fCalib, only1I, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf1I = opt_1I.optPosOptParamsForEach();
|
||||
|
||||
EvalCompareOpt2 opt_2H(Settings::fMap, Settings::fCalib, only2H, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf2H = opt_2H.optPosOptParamsForEach();
|
||||
|
||||
EvalCompareOpt2 opt_3H(Settings::fMap, Settings::fCalib, only3H, ignoreStaircases);
|
||||
EvalCompareOpt2::Result sf3H = opt_3H.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);
|
||||
|
||||
// ultra fancy combined model
|
||||
WiFiModelPerBBox wmbb(map);
|
||||
wmbb.add(&sf0H.model, bboxes0H);
|
||||
wmbb.add(&sf0O.model, bboxes0O);
|
||||
wmbb.add(&sf0I.model, bboxes0I);
|
||||
wmbb.add(&sf1H.model, bboxes1H);
|
||||
wmbb.add(&sf1O.model, bboxes1O);
|
||||
wmbb.add(&sf1I.model, bboxes1I);
|
||||
wmbb.add(&sf2H.model, bboxes2H);
|
||||
wmbb.add(&sf3H.model, bboxes3H);
|
||||
wmbb.saveXML(Settings::wifiEachOptParPos_perBBox);
|
||||
|
||||
PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
||||
pef.add("\\small{empiric}", &s1.errSingle);
|
||||
pef.add("\\small{real pos, opt params}", &s2.errSingle);
|
||||
pef.add("\\small{real pos, opt params [per AP]}", &s3.errSingle);
|
||||
pef.add("\\small{opt pos, opt params [per AP]}", &s4.errSingle);
|
||||
|
||||
pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5));
|
||||
pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-methods.tex");
|
||||
pef.writePlotToFile(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();
|
||||
|
||||
int i = 0; (void) i;
|
||||
//return;
|
||||
//sleep(1000);
|
||||
|
||||
}
|
||||
|
||||
std::vector<K::Statistics<float>> errorStatAllModels(Floorplan::IndoorMap* map) {
|
||||
|
||||
WiFiModelFactory fac(map);
|
||||
WiFiFingerprints calib(Settings::fCalib);
|
||||
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
for (WiFiFingerprint& fp : calib.getFingerprints()) {
|
||||
fp.measurements = vap.group(fp.measurements);
|
||||
}
|
||||
|
||||
// calculate the error (model vs scan) for each fingerprint using the given model
|
||||
auto calc = [&] (const WiFiModel* model, K::Statistics<float>* stats) {
|
||||
for (const WiFiFingerprint& fp : calib.getFingerprints()) {
|
||||
for (const WiFiMeasurement& m : fp.measurements.entries) {
|
||||
|
||||
const float scanRSSI = m.getRSSI();
|
||||
const float modelRSSI = model->getRSSI(m.getAP().getMAC(), fp.pos_m);
|
||||
|
||||
if (modelRSSI != modelRSSI) {
|
||||
std::cout << "unknown AP: " << m.getAP().getMAC().asString() << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
const float errAbs = std::abs(modelRSSI-scanRSSI);
|
||||
stats->add(errAbs);
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// models
|
||||
WiFiModel* mdlAllFixed = fac.loadXML(Settings::wifiAllFixed);
|
||||
K::Statistics<float> statsAllFixed;
|
||||
calc(mdlAllFixed, &statsAllFixed);
|
||||
|
||||
WiFiModel* mdlAllOptPar = fac.loadXML(Settings::wifiAllOptPar);
|
||||
K::Statistics<float> statsAllOptPar;
|
||||
calc(mdlAllOptPar, &statsAllOptPar);
|
||||
|
||||
WiFiModel* mdlEachOptPar = fac.loadXML(Settings::wifiEachOptPar);
|
||||
K::Statistics<float> statsEachOptPar;
|
||||
calc(mdlEachOptPar, &statsEachOptPar);
|
||||
|
||||
WiFiModel* mdlEachOptParPos = fac.loadXML(Settings::wifiEachOptParPos);
|
||||
K::Statistics<float> statsEachOptParPos;
|
||||
calc(mdlEachOptParPos, &statsEachOptParPos);
|
||||
|
||||
WiFiModel* mdlFloor = fac.loadXML(Settings::wifiEachOptParPos_multimodel);
|
||||
K::Statistics<float> statsFloor;
|
||||
calc(mdlFloor, &statsFloor);
|
||||
|
||||
WiFiModel* mdlBbox = fac.loadXML(Settings::wifiEachOptParPos_perBBox);
|
||||
K::Statistics<float> statsBbox;
|
||||
calc(mdlBbox, &statsBbox);
|
||||
|
||||
return {
|
||||
statsAllFixed,
|
||||
statsAllOptPar,
|
||||
statsEachOptPar,
|
||||
statsEachOptParPos,
|
||||
statsFloor,
|
||||
statsBbox,
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** error plot for all used optimization models */
|
||||
void errorPlotAllModels(Floorplan::IndoorMap* map) {
|
||||
|
||||
std::vector<K::Statistics<float>> errors = errorStatAllModels(map);
|
||||
|
||||
PlotErrFunc plot("", "fingerprints (%)");
|
||||
plot.getPlot().getAxisX().setTicsLabelFormat("%h dB");
|
||||
plot.add("\\noOptEmpiric{}", &errors[0]);
|
||||
plot.add("\\optParamsAllAP{}", &errors[1]);
|
||||
plot.add("\\optParamsEachAP{}", &errors[2]);
|
||||
plot.add("\\optParamsPosEachAP{}", &errors[3]);
|
||||
plot.add("\\optPerFloor{}", &errors[4]);
|
||||
plot.add("\\optPerRegion{}", &errors[5]);
|
||||
plot.getPlot().getKey().setVisible(true);
|
||||
plot.getPlot().getKey().setPosition(K::GnuplotKey::Hor::RIGHT, K::GnuplotKey::Ver::BOTTOM);
|
||||
|
||||
// debug view
|
||||
plot.setYRange(0, 95, 5);
|
||||
plot.plot();
|
||||
sleep(2);
|
||||
|
||||
plot.setYRange(95, 100, 1);
|
||||
plot.plot();
|
||||
sleep(2);
|
||||
|
||||
|
||||
// LATEX
|
||||
// plot.getGP() << "set lmargin 4.2\n";
|
||||
// plot.getGP() << "set tmargin 0.1\n";
|
||||
// plot.getGP() << "set rmargin 0.2\n";
|
||||
// plot.getGP() << "set bmargin 1.9\n";
|
||||
plot.getPlot().getMargin().set(4.2, 0.2, 0.1, 1.9);
|
||||
plot.getPlot().getAxisY().setLabelOffset(3.0,0);
|
||||
plot.getPlot().setStringMod(new K::GnuplotStringModLaTeX());
|
||||
plot.getPlot().getKey().setSampleLength(0.5);
|
||||
plot.getPlot().getKey().setWidthIncrement(+7.0);
|
||||
|
||||
plot.setYRange(0, 95, 5);
|
||||
plot.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 100));
|
||||
plot.getPlot().getAxisY().setTicsStep(0, 25, 100);
|
||||
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 4.0));
|
||||
plot.getPlot().getAxisX().setTicsStep(4); // 4dB
|
||||
plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0, 16));
|
||||
plot.getGP().setOutput(Settings::fPathGFX + "/wifi_model_error_0_95.tex");
|
||||
plot.writePlotToFile(Settings::fPathGFX + "/wifi_model_error_0_95.gp");
|
||||
plot.plot();
|
||||
|
||||
plot.getPlot().getKey().setVisible(false);
|
||||
plot.setYRange(97, 100, 1);
|
||||
plot.getPlot().getAxisY().setTicsStep(1);
|
||||
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 2.6));
|
||||
plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(5, 35));
|
||||
plot.getPlot().getAxisX().setTicsStep(5); // 5dB
|
||||
plot.getGP().setOutput(Settings::fPathGFX + "/wifi_model_error_95_100.tex");
|
||||
plot.writePlotToFile(Settings::fPathGFX + "/wifi_model_error_95_100.gp");
|
||||
plot.plot();
|
||||
|
||||
int i = 0; (void) i;
|
||||
//sleep(1000);
|
||||
|
||||
}
|
||||
|
||||
/** error plot for the given stats. used for fingerprint errors */
|
||||
void errorPlotNumFingerprints(const std::vector<K::Statistics<float>>& stats, const std::vector<std::string>& titles, const std::string& name) {
|
||||
|
||||
PlotErrFunc plot("", "fingerprints (%)");
|
||||
plot.getPlot().getAxisX().setTicsLabelFormat("%h dB");
|
||||
|
||||
plot.getPlot().getKey().setVisible(true);
|
||||
plot.getPlot().getKey().setPosition(K::GnuplotKey::Hor::RIGHT, K::GnuplotKey::Ver::BOTTOM);
|
||||
|
||||
|
||||
plot.clear();
|
||||
for (int j = 0; j < titles.size(); ++j) {
|
||||
plot.add(titles[j], &stats[j]);
|
||||
}
|
||||
|
||||
// // debug view
|
||||
// plot.setYRange(0, 90, 5);
|
||||
// plot.plot();
|
||||
// sleep(5);
|
||||
|
||||
// plot.setYRange(90, 100, 5);
|
||||
// plot.plot();
|
||||
// sleep(5);
|
||||
|
||||
// LATEX
|
||||
// plot.getGP() << "set lmargin 4.2\n";
|
||||
// plot.getGP() << "set tmargin 0.1\n";
|
||||
// plot.getGP() << "set rmargin 0.2\n";
|
||||
// plot.getGP() << "set bmargin 1.9\n";
|
||||
plot.getPlot().getMargin().set(4.2, 0.2, 0.1, 1.9);
|
||||
plot.getPlot().getAxisY().setLabelOffset(3.0,0);
|
||||
plot.getPlot().setStringMod(new K::GnuplotStringModLaTeX());
|
||||
plot.getPlot().getKey().setSampleLength(0.5);
|
||||
plot.getPlot().getKey().setWidthIncrement(-5.0);
|
||||
|
||||
plot.setYRange(0, 90, 5);
|
||||
plot.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 100));
|
||||
plot.getPlot().getAxisY().setTicsStep(0, 25, 100);
|
||||
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 3.3));
|
||||
plot.getPlot().getAxisX().setTicsStep(4); // 4dB
|
||||
plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0, 16));
|
||||
plot.getGP().setOutput(Settings::fPathGFX + "/" + name + "_0_90.tex");
|
||||
plot.writePlotToFile(Settings::fPathGFX + "/" + name + "_0_90.gp");
|
||||
plot.plot();
|
||||
|
||||
plot.getPlot().getKey().setVisible(false);
|
||||
plot.setYRange(90, 100, 1);
|
||||
plot.getPlot().getAxisY().setTicsStep(2);
|
||||
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 2.6));
|
||||
plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(5, 35));
|
||||
plot.getPlot().getAxisX().setTicsStep(5); // 5dB
|
||||
plot.getGP().setOutput(Settings::fPathGFX + "/" + name + "_90_100.tex");
|
||||
plot.writePlotToFile(Settings::fPathGFX + "/" + name + "_90_100.gp");
|
||||
plot.plot();
|
||||
|
||||
}
|
||||
|
||||
/** show all fingerprints within the building */
|
||||
void plotAllFingerprints(Floorplan::IndoorMap* map) {
|
||||
|
||||
WiFiFingerprints calib(Settings::fCalib);
|
||||
LeHelper::removeNonFHWS(calib);
|
||||
|
||||
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
for (WiFiFingerprint& fp : calib.getFingerprints()) {
|
||||
fp.measurements = vap.group(fp.measurements);
|
||||
}
|
||||
|
||||
// estimate stats
|
||||
K::Statistics<float> fpVisible;
|
||||
for (const WiFiFingerprint& fp : calib.getFingerprints()) {
|
||||
fpVisible.add(fp.measurements.entries.size());
|
||||
}
|
||||
|
||||
Plotty* p = new Plotty(map);
|
||||
p->buildFloorplan();
|
||||
p->cpoints.clear();
|
||||
for (const WiFiFingerprint& fp : calib.getFingerprints()) {
|
||||
const K::GnuplotPoint3 gp(fp.pos_m.x, fp.pos_m.y, fp.pos_m.z);
|
||||
const float size = fp.measurements.entries.size() / 10.0 * 1.0;
|
||||
const Point3 pos = fp.pos_m - Point3(0,0,1.2);
|
||||
Color c;
|
||||
if (pos.z < 4) {c = Color::fromRGB(128,128,128);}
|
||||
else if (pos.z < 6) {c = Color::fromRGB(255,96,96);}
|
||||
else if (pos.z < 9) {c = Color::fromRGB(128,255,128);}
|
||||
else {c = Color::fromRGB(128,128,255);}
|
||||
K::GnuplotObjectPolygon* poly = p->addFloorRect(pos, size, c);
|
||||
poly->setZIndex(pos.z + 0.1); // above the floor
|
||||
|
||||
const int visibleAPs = fp.measurements.entries.size();
|
||||
if (visibleAPs == fpVisible.getMin() || visibleAPs == fpVisible.getMax()) {
|
||||
p->addLabel("\\footnotesize{" + std::to_string(fp.measurements.entries.size()) + "}", pos+Point3(0,1,1)*0.25);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::cout << fpVisible.asString() << std::endl;
|
||||
|
||||
p->splot.getCustom() << "set view equal xy\n";
|
||||
p->splot.getCustom() << "unset border\n";
|
||||
p->splot.getMargin().set(1, 0,0,0);
|
||||
p->splot.getAxisX().setTicsVisible(false);
|
||||
p->splot.getAxisY().setTicsVisible(false);
|
||||
p->splot.getAxisZ().setTicsVisible(false);
|
||||
p->splot.getAxisZ().setRange(K::GnuplotAxis::Range(-8, 19.5));
|
||||
p->splot.getView().setCamera(74,30);
|
||||
p->splot.getView().setScaleAll(3.8);
|
||||
|
||||
p->splot.getObjects().reOrderByZIndex();
|
||||
p->plot();
|
||||
|
||||
p->gp.setTerminal("epslatex", K::GnuplotSize(8.6, 5.0));
|
||||
p->gp.setOutput(Settings::fPathGFX + "/all_fingerprints.tex");
|
||||
p->gp.writePlotToFile(Settings::fPathGFX + "/all_fingerprints.gp");
|
||||
p->plot();
|
||||
|
||||
sleep(100);
|
||||
|
||||
}
|
||||
|
||||
/** show all walked paths */
|
||||
void plotAllWalks(Floorplan::IndoorMap* map) {
|
||||
|
||||
using Walk = std::vector<Point3>;
|
||||
|
||||
Walk path1 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path1);
|
||||
Walk path2 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path2);
|
||||
//Walk path_toni_all_1 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path_toni_all_1);
|
||||
//Walk path_toni_all_2 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path_toni_all_2);
|
||||
Walk path_toni_inst_1 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path_toni_inst_1);
|
||||
Walk path_toni_inst_2 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path_toni_inst_2);
|
||||
Walk path_toni_inst_3 = FloorplanHelper::getGroundTruth(map, Settings::GroundTruth::path_toni_inst_3);
|
||||
|
||||
const std::vector<Walk> walks = {
|
||||
path1,
|
||||
path2,
|
||||
//path_toni_all_1, same as path1
|
||||
//path_toni_all_2, same as path2
|
||||
path_toni_inst_1,
|
||||
path_toni_inst_2,
|
||||
path_toni_inst_3
|
||||
};
|
||||
|
||||
const std::vector<std::string> titles = {
|
||||
"path 1", "path 2", "path 3", "path 4", "path 5"
|
||||
};
|
||||
|
||||
Plotty* p = new Plotty(map);
|
||||
p->buildFloorplan();
|
||||
|
||||
std::vector<std::string> colors = {"#000000", "#ff0000", "#00cc00", "#0000ff", "#009999", "#aa00aa"};
|
||||
|
||||
int i = 0;
|
||||
for (const Walk& walk : walks) {
|
||||
K::GnuplotSplotElementLines* line = new K::GnuplotSplotElementLines();
|
||||
line->getStroke().setWidth(2);
|
||||
line->getStroke().getColor().setHexStr(colors[i]);
|
||||
line->setTitle(titles[i]);
|
||||
//line->getStroke().setType( (i > 3) ? K::GnuplotDashtype::DASHED : K::GnuplotDashtype::SOLID );
|
||||
|
||||
float oy = 0;
|
||||
if (i == 2) {oy -= 0.5;}
|
||||
if (i == 3) {oy += 0.5;}
|
||||
|
||||
for (const Point3& pt : walk) {
|
||||
line->add(K::GnuplotPoint3(pt.x, pt.y+oy, pt.z));
|
||||
}
|
||||
p->splot.add(line);
|
||||
++i;
|
||||
}
|
||||
|
||||
p->splot.getKey().setVisible(true);
|
||||
//p->splot.getKey().setPosition(K::GnuplotKey::Hor::RIGHT, K::GnuplotKey::Ver::TOP);
|
||||
p->splot.getKey().setPosition(K::GnuplotCoordinate2(0.99, 0.99, K::GnuplotCoordinateSystem::SCREEN));
|
||||
p->splot.getKey().setSampleLength(0.5);
|
||||
//p->splot.getKey().setWidthIncrement(-4);
|
||||
p->splot.setStringMod(new K::GnuplotStringModLaTeX());
|
||||
|
||||
p->splot.getCustom() << "set view equal xy\n";
|
||||
p->splot.getCustom() << "unset border\n";
|
||||
p->splot.getMargin().set(1, 0,0,0);
|
||||
p->splot.getAxisX().setTicsVisible(false);
|
||||
p->splot.getAxisY().setTicsVisible(false);
|
||||
p->splot.getAxisZ().setTicsVisible(false);
|
||||
p->splot.getAxisZ().setRange(K::GnuplotAxis::Range(-8, 19.5));
|
||||
p->splot.getView().setCamera(74,30);
|
||||
p->splot.getView().setScaleAll(3.8);
|
||||
|
||||
p->splot.getObjects().reOrderByZIndex();
|
||||
p->plot();
|
||||
|
||||
p->gp.setTerminal("epslatex", K::GnuplotSize(8.6, 5.0));
|
||||
p->gp.setOutput(Settings::fPathGFX + "/all_walks.tex");
|
||||
p->gp.writePlotToFile(Settings::fPathGFX + "/all_walks.gp");
|
||||
p->plot();
|
||||
|
||||
sleep(100);
|
||||
|
||||
}
|
||||
|
||||
// build plots for the paper
|
||||
void paperOutputs() {
|
||||
|
||||
@@ -117,137 +583,51 @@ void paperOutputs() {
|
||||
|
||||
}
|
||||
|
||||
// show all fingerprints
|
||||
if (1 == 0) {
|
||||
plotAllFingerprints(map);
|
||||
}
|
||||
|
||||
// show all walks
|
||||
if (1 == 0) {
|
||||
plotAllWalks(map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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) {
|
||||
|
||||
// // 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),
|
||||
// };
|
||||
// EvalCompareOpt2 opt1(Settings::fMap, calibWalks);
|
||||
|
||||
// all combined
|
||||
auto removeNone = [] (const WiFiFingerprint& fp) -> bool {return false;};
|
||||
|
||||
// per floor
|
||||
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;};
|
||||
|
||||
// per bbox
|
||||
#include "bboxes.h"
|
||||
auto only0H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes0H.contains(fp.pos_m);};
|
||||
auto only0O = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes0O.contains(fp.pos_m);};
|
||||
auto only0I = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes0I.contains(fp.pos_m);};
|
||||
|
||||
auto only1H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes1H.contains(fp.pos_m);};
|
||||
auto only1O = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes1O.contains(fp.pos_m);};
|
||||
auto only1I = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes1I.contains(fp.pos_m);};
|
||||
|
||||
auto only2H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes2H.contains(fp.pos_m);};
|
||||
|
||||
auto only3H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes3H.contains(fp.pos_m);};
|
||||
rebuildAllModels(map, 0);
|
||||
/** detailled error analysis for above optimization routine */
|
||||
errorPlotAllModels(map);
|
||||
}
|
||||
|
||||
|
||||
// use fingerprints?
|
||||
EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, removeNone);
|
||||
if (1 == 0) {
|
||||
|
||||
rebuildAllModels(map,4);
|
||||
std::vector<K::Statistics<float>> stats4 = errorStatAllModels(map);
|
||||
rebuildAllModels(map,2);
|
||||
std::vector<K::Statistics<float>> stats2 = errorStatAllModels(map);
|
||||
rebuildAllModels(map,0,true);
|
||||
std::vector<K::Statistics<float>> statsNoStairs = errorStatAllModels(map);
|
||||
rebuildAllModels(map,0); // ensure all output files are overwritten with the "all fingerprints" opt!!!
|
||||
std::vector<K::Statistics<float>> stats0 = errorStatAllModels(map);
|
||||
|
||||
// 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;
|
||||
// analyze all 5 opt strategies. skip the empiric one: stats0[0]
|
||||
for (int i = 1; i < 6; ++i) {
|
||||
std::string name = "wifi_model_error_num_fingerprints_method_" + std::to_string(i);
|
||||
errorPlotNumFingerprints(
|
||||
{stats0[0], stats4[i], stats2[i], stats0[i], statsNoStairs[i]},
|
||||
{"empiric", "25%", "50%", "100%", "no stairs"},
|
||||
name
|
||||
);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
|
||||
// optimize per 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();
|
||||
|
||||
|
||||
// optimize per bbox
|
||||
EvalCompareOpt2 opt_0H(Settings::fMap, Settings::fCalib, only0H);
|
||||
EvalCompareOpt2::Result sf0H = opt_0H.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_0O(Settings::fMap, Settings::fCalib, only0O);
|
||||
EvalCompareOpt2::Result sf0O = opt_0O.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_0I(Settings::fMap, Settings::fCalib, only0I);
|
||||
EvalCompareOpt2::Result sf0I = opt_0I.optPosOptParamsForEach();
|
||||
|
||||
EvalCompareOpt2 opt_1H(Settings::fMap, Settings::fCalib, only1H);
|
||||
EvalCompareOpt2::Result sf1H = opt_1H.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_1O(Settings::fMap, Settings::fCalib, only1O);
|
||||
EvalCompareOpt2::Result sf1O = opt_1O.optPosOptParamsForEach();
|
||||
EvalCompareOpt2 opt_1I(Settings::fMap, Settings::fCalib, only1I);
|
||||
EvalCompareOpt2::Result sf1I = opt_1I.optPosOptParamsForEach();
|
||||
|
||||
EvalCompareOpt2 opt_2H(Settings::fMap, Settings::fCalib, only2H);
|
||||
EvalCompareOpt2::Result sf2H = opt_2H.optPosOptParamsForEach();
|
||||
|
||||
EvalCompareOpt2 opt_3H(Settings::fMap, Settings::fCalib, only3H);
|
||||
EvalCompareOpt2::Result sf3H = opt_3H.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);
|
||||
|
||||
// ultra fancy combined model
|
||||
WiFiModelPerBBox wmbb(map);
|
||||
wmbb.add(&sf0H.model, bboxes0H);
|
||||
wmbb.add(&sf0O.model, bboxes0O);
|
||||
wmbb.add(&sf0I.model, bboxes0I);
|
||||
wmbb.add(&sf1H.model, bboxes1H);
|
||||
wmbb.add(&sf1O.model, bboxes1O);
|
||||
wmbb.add(&sf1I.model, bboxes1I);
|
||||
wmbb.add(&sf2H.model, bboxes2H);
|
||||
wmbb.add(&sf3H.model, bboxes3H);
|
||||
wmbb.saveXML(Settings::wifiEachOptParPos_perBBox);
|
||||
|
||||
PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
||||
pef.add("\\small{empiric}", &s1.errSingle);
|
||||
pef.add("\\small{real pos, opt params}", &s2.errSingle);
|
||||
pef.add("\\small{real pos, opt params [per AP]}", &s3.errSingle);
|
||||
pef.add("\\small{opt pos, opt params [per AP]}", &s4.errSingle);
|
||||
|
||||
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();
|
||||
|
||||
int i = 0; (void) i;
|
||||
//return;
|
||||
//sleep(1000);
|
||||
sleep(1);
|
||||
|
||||
}
|
||||
|
||||
@@ -302,7 +682,7 @@ void paperOutputs() {
|
||||
|
||||
pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5));
|
||||
pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.tex");
|
||||
pef.writeCodeTo(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.gp");
|
||||
pef.writePlotToFile(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.gp");
|
||||
pef.getGP() << "set key right bottom width -3\n";
|
||||
pef.getGP() << "set rmargin 0.4\n";
|
||||
pef.getGP() << "set tmargin 0.4\n";
|
||||
@@ -546,8 +926,47 @@ int main(void) {
|
||||
|
||||
}
|
||||
|
||||
// show wifi multimodalities
|
||||
if (1 == 1) {
|
||||
|
||||
Plotty::Settings settings;
|
||||
settings.maxZ = 8;
|
||||
|
||||
EvalWiFiGround ewg(map, Settings::wifiEachOptParPos_perBBox, settings);
|
||||
//ewg.show(Settings::path1a, 30);
|
||||
//ewg.show(Settings::path1a, 70);
|
||||
//ewg.show(Settings::path1a, 90);
|
||||
|
||||
int hueGreen = 120*255/360;
|
||||
int hueYellow = 60*255/360;
|
||||
int hueBlue = 210*255/360;
|
||||
int hueRed = 0*255/360;
|
||||
|
||||
ewg.addGT(Settings::path1a, 100, hueGreen, Settings::GroundTruth::path1);
|
||||
ewg.addGT(Settings::path1a, 170-8, hueBlue, Settings::GroundTruth::path1);
|
||||
ewg.addGT(Settings::path1a, 200, hueRed, Settings::GroundTruth::path1);
|
||||
|
||||
|
||||
// green
|
||||
ewg.add(Settings::path1a, 100, hueGreen);
|
||||
|
||||
// yellow
|
||||
ewg.add(Settings::path1a, 170, hueBlue);
|
||||
|
||||
// red
|
||||
ewg.add(Settings::path1a, 200, hueRed);
|
||||
|
||||
ewg.groundProb->getPlot().splot.getObjects().reOrderByZIndex();
|
||||
ewg.groundProb->plotMe();
|
||||
|
||||
ewg.writeGP(Settings::fPathGFX, "wifiMultimodality");
|
||||
|
||||
sleep(1000);
|
||||
|
||||
}
|
||||
|
||||
if (1 == 0) {
|
||||
|
||||
std::vector<std::string> files = {
|
||||
Settings::path1a, Settings::path1b,
|
||||
Settings::path2a, Settings::path2b,
|
||||
@@ -560,33 +979,51 @@ int main(void) {
|
||||
std::vector<std::vector<int>> gtIndices = {
|
||||
Settings::GroundTruth::path1, Settings::GroundTruth::path1,
|
||||
Settings::GroundTruth::path2, Settings::GroundTruth::path2,
|
||||
Settings::GroundTruth::path_toni_all_1, Settings::GroundTruth::path_toni_all_1,
|
||||
Settings::GroundTruth::path_toni_all_2, Settings::GroundTruth::path_toni_all_2,
|
||||
Settings::GroundTruth::path1, Settings::GroundTruth::path1,
|
||||
Settings::GroundTruth::path2, Settings::GroundTruth::path2,
|
||||
// Settings::GroundTruth::path_toni_all_1, Settings::GroundTruth::path_toni_all_1,
|
||||
// Settings::GroundTruth::path_toni_all_2, Settings::GroundTruth::path_toni_all_2,
|
||||
Settings::GroundTruth::path_toni_inst_1, Settings::GroundTruth::path_toni_inst_1,
|
||||
Settings::GroundTruth::path_toni_inst_2, Settings::GroundTruth::path_toni_inst_2,
|
||||
Settings::GroundTruth::path_toni_inst_3, Settings::GroundTruth::path_toni_inst_3,
|
||||
};
|
||||
|
||||
// EvalWiFiPaths ewp(Settings::fMap);
|
||||
// ewp.loadModel(Settings::wifiAllFixed, "empirc");
|
||||
// ewp.walks(files, gtIndices);
|
||||
int numScans = 0;
|
||||
for (const std::string& file : files) {
|
||||
Offline::FileReader reader(file);
|
||||
numScans += reader.getWiFiGroupedByTime().size();
|
||||
}
|
||||
|
||||
// ewp.loadModel(Settings::wifiEachOptParPos, "normal model");
|
||||
// ewp.walks(files, gtIndices);
|
||||
std::cout << "num scans: " << numScans << std::endl;
|
||||
|
||||
// ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "model per floor");
|
||||
// ewp.walks(files, gtIndices);
|
||||
|
||||
// ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "model per region");
|
||||
// ewp.walks(files, gtIndices);
|
||||
EvalWiFiPaths ewp(Settings::fMap);
|
||||
ewp.loadModel(Settings::wifiAllFixed, "\\noOptEmpiric{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
EvalWiFiPathMethods ewpm(Settings::fMap);
|
||||
ewpm.loadModel(Settings::wifiEachOptParPos_perBBox, "model per region", "original", "alternative");
|
||||
ewpm.walks(files, gtIndices);
|
||||
ewp.loadModel(Settings::wifiEachOptParPos, "\\optParamsPosEachAP{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
// export for paper
|
||||
// using errFuncOtherExponential and only path1a, path1b
|
||||
//ewpm.writeGP(Settings::fPathGFX, "normalVsExp");
|
||||
ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "\\optPerFloor{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "\\optPerRegion{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
ewp.writeGP(Settings::fPathGFX, "modelPerformance");
|
||||
|
||||
// examine various modifications
|
||||
if (1 == 0) {
|
||||
|
||||
EvalWiFiPathMethods ewpm(Settings::fMap);
|
||||
ewpm.loadModel(Settings::wifiEachOptParPos_perBBox, "model per region", "original", "alternative");
|
||||
ewpm.walks(files, gtIndices);
|
||||
|
||||
// export for paper
|
||||
// using errFuncOtherExponential and only path1a, path1b
|
||||
//ewpm.writeGP(Settings::fPathGFX, "normalVsExp");
|
||||
|
||||
}
|
||||
|
||||
|
||||
sleep(10000);
|
||||
|
||||
@@ -306,7 +306,7 @@ private:
|
||||
++updateCount;
|
||||
static PlotErrTime pet("\\small{time (sec)}", "\\small{error (m)}", "\\small{APs visible}");
|
||||
static PlotErrFunc pef("\\small{error (m)}", "\\small{updates (\\%)}");
|
||||
pef.showMarkers(true);
|
||||
pef.showMarkers(true, true);
|
||||
|
||||
std::cout << "update" << std::endl;
|
||||
|
||||
|
||||
@@ -31,12 +31,21 @@ class PlotErrFunc {
|
||||
K::GnuplotPlot gplot;
|
||||
|
||||
//std::vector<std::string> colors = {"#000000", "#ff0000", "#00bb00", "#0000ff"};
|
||||
std::vector<std::string> colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#00aaaa"};
|
||||
std::vector<std::string> colors = {"#000000", "#ff0000", "#00ff00", "#0000ff", "#00aaaa", "#aa00aa"};
|
||||
|
||||
bool markers = false;
|
||||
struct Markers {
|
||||
bool median = false;
|
||||
bool quantil75 = false;
|
||||
} markers;
|
||||
|
||||
std::string codeFile;
|
||||
|
||||
struct Range {
|
||||
int fromPercent = 0;
|
||||
int toPercent = 0;
|
||||
int increment = 0;
|
||||
} range;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
@@ -44,8 +53,17 @@ public:
|
||||
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
|
||||
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));
|
||||
setYRange(0, 90, 5);
|
||||
//gplot.getAxisX().setRange(K::GnuplotAxis::Range(0, K::GnuplotAxis::Range::AUTO));
|
||||
gplot.getAxisX().setRange(K::GnuplotAxis::Range(K::GnuplotAxis::Range::AUTO, K::GnuplotAxis::Range::AUTO));
|
||||
}
|
||||
|
||||
/** set the percentage range to show */
|
||||
void setYRange(const int fromPercent, const int toPercent, const int increment = 5) {
|
||||
this->range.fromPercent = fromPercent;
|
||||
this->range.toPercent = toPercent;
|
||||
this->range.increment = increment;
|
||||
gplot.getAxisY().setRange(K::GnuplotAxis::Range(this->range.fromPercent, K::GnuplotAxis::Range::AUTO));
|
||||
}
|
||||
|
||||
/** add one curve. Statistics<T> are allowed to be altered outside afterwards! */
|
||||
@@ -75,14 +93,18 @@ public:
|
||||
return gplot;
|
||||
}
|
||||
|
||||
void writeCodeTo(const std::string& file) {
|
||||
this->codeFile = file;
|
||||
/** write the gnuplot commands to file for later re-use */
|
||||
void writePlotToFile(const std::string& file) {
|
||||
this->gp.writePlotToFile(file);
|
||||
}
|
||||
|
||||
void showMarkers(const bool show) {
|
||||
this->markers = show;
|
||||
/** whether to show additional markers */
|
||||
void showMarkers(const bool median, const bool quantil75) {
|
||||
this->markers.median = median;
|
||||
this->markers.quantil75 = quantil75;
|
||||
}
|
||||
|
||||
|
||||
/** plot all curves */
|
||||
void plot() {
|
||||
|
||||
@@ -100,42 +122,35 @@ public:
|
||||
const float range = e.stats->getQuantile(0.85) - minX;
|
||||
const float space = range * 0.07;
|
||||
|
||||
// 0 - 80%
|
||||
for (int j = 0; j <= 85; j+= 5) {
|
||||
// [from:stepsSize:to]
|
||||
//for (int j = this->range.fromPercent; j <= this->range.toPercent; j += this->range.increment) {
|
||||
for (int j = 0; j <= 100; j += this->range.increment) {
|
||||
|
||||
const float y = j / 100.0f;
|
||||
const float x = e.stats->getQuantile(y);
|
||||
K::GnuplotPoint2 gp2(x, y*100);
|
||||
e.line->add(gp2);
|
||||
|
||||
|
||||
|
||||
if (markers) {
|
||||
int id = (i+1) * 100;
|
||||
if (j == 50) {
|
||||
gp << "set object " << id+1 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
|
||||
gp << "set label " << id+2 << " at " << x+space << "," << j << " '" << x << "'\n";
|
||||
gp << "set arrow " << id+3 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
|
||||
gp << "set arrow " << id+4 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
|
||||
} else if (j == 75) {
|
||||
gp << "set object " << id+5 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
|
||||
gp << "set label " << id+6 << " at " << x+space << "," << j << " '" << x << "'\n";
|
||||
gp << "set arrow " << id+7 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
|
||||
gp << "set arrow " << id+8 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
|
||||
}
|
||||
// show additional markers?
|
||||
int id = (i+1) * 100;
|
||||
if (j == 50 && markers.median) {
|
||||
gp << "set object " << id+1 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
|
||||
gp << "set label " << id+2 << " at " << x+space << "," << j << " '" << x << "'\n";
|
||||
gp << "set arrow " << id+3 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
|
||||
gp << "set arrow " << id+4 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
|
||||
} else if (j == 75 && markers.quantil75) {
|
||||
gp << "set object " << id+5 << " circle at " << x << "," << j << " size screen 0.02,0.02\n";
|
||||
gp << "set label " << id+6 << " at " << x+space << "," << j << " '" << x << "'\n";
|
||||
gp << "set arrow " << id+7 << " from " << x << "," << 0 << " to " << x << "," << j << " nohead\n";
|
||||
gp << "set arrow " << id+8 << " from " << 0 << "," << j << " to " << x << "," << j << " nohead\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// render
|
||||
gp.draw(gplot);
|
||||
|
||||
if (codeFile != "") {
|
||||
std::ofstream out(codeFile);
|
||||
out << gp.getBuffer();
|
||||
out.close();
|
||||
}
|
||||
|
||||
gp.flush();
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ private:
|
||||
struct Entry {
|
||||
Point3 pos;
|
||||
K::GnuplotObjectPolygon* poly;
|
||||
float max = 0;
|
||||
float max = -1;
|
||||
float sum = 0;
|
||||
int cnt = 0;
|
||||
};
|
||||
@@ -51,19 +51,28 @@ private:
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
PlotWiFiGroundProb(const Floorplan::IndoorMap* map) : map(map), plot(map) {
|
||||
buildEvalPoints();
|
||||
PlotWiFiGroundProb(const Floorplan::IndoorMap* map, Plotty::Settings settings = Plotty::Settings()) : map(map), plot(map) {
|
||||
|
||||
plot.settings.outline = false;
|
||||
plot.settings = settings;
|
||||
|
||||
buildEvalPoints();
|
||||
plot.buildFloorplan();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
Plotty& getPlot() {
|
||||
return plot;
|
||||
}
|
||||
|
||||
/** plot the ground-probability for the given measurement */
|
||||
void show(const WiFiObserverFree& prob, const WiFiMeasurements& _mes) {
|
||||
|
||||
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
const WiFiMeasurements mes = vap.group(_mes);
|
||||
|
||||
// determine min/max probability
|
||||
double min = +99999;
|
||||
double max = -99999;
|
||||
for (Entry& e : pos) {
|
||||
@@ -71,9 +80,9 @@ public:
|
||||
if (p < min) {min = p;}
|
||||
if (p > max) {max = p;}
|
||||
}
|
||||
double diff = max-min;
|
||||
|
||||
const double diff = max-min;
|
||||
|
||||
// render
|
||||
for (Entry& e : pos) {
|
||||
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
|
||||
const double f = (p-min) / diff * 255;
|
||||
@@ -85,11 +94,51 @@ public:
|
||||
e.poly->getFill().setColor(c);
|
||||
e.max = f;
|
||||
//}
|
||||
if (f < 0.1) {
|
||||
e.poly->setEnabled(false);
|
||||
}
|
||||
|
||||
//plot.cpoints.add(K::GnuplotPoint3(pt.x, pt.y, pt.z), p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void showStrongest(const WiFiObserverFree& prob, const WiFiMeasurements& mes, const float hue) {
|
||||
|
||||
// determine min/max probability
|
||||
double min = +99999;
|
||||
double max = -99999;
|
||||
for (Entry& e : pos) {
|
||||
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
|
||||
if (p < min) {min = p;}
|
||||
if (p > max) {max = p;}
|
||||
}
|
||||
const double diff = max-min;
|
||||
|
||||
// render
|
||||
for (Entry& e : pos) {
|
||||
|
||||
// get probability within [0:255]
|
||||
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
|
||||
const double f = (p-min) / diff * 255;
|
||||
|
||||
if (p != p) {
|
||||
throw Exception("nan");
|
||||
}
|
||||
|
||||
// overwrite weak entries
|
||||
if (f > e.max) {
|
||||
|
||||
const K::GnuplotColor c = K::GnuplotColor::fromHSV(hue, f, 245);
|
||||
e.poly->getFill().setColor(c);
|
||||
e.max = f;
|
||||
|
||||
// disable unlikely onces to save performance and disk-space
|
||||
e.poly->setEnabled(f > 32);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -143,6 +192,7 @@ private:
|
||||
e.poly->close();
|
||||
e.poly->getFill().setStyle(K::GnuplotFillStyle::SOLID);
|
||||
e.poly->setStroke(K::GnuplotStroke::NONE());
|
||||
e.poly->setZIndex(f->atHeight - 0.001); // between outline and obstacles
|
||||
|
||||
e.pos = Point3(x, y, f->atHeight);
|
||||
|
||||
|
||||
144
plots/Plotty.h
144
plots/Plotty.h
@@ -10,6 +10,9 @@
|
||||
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotSplotElementColorPoints.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotSplotElementPM3D.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotSplotElementEmpty.h>
|
||||
|
||||
#include <KLib/misc/gnuplot/GnuplotPlot.h>
|
||||
#include <KLib/misc/gnuplot/GnuplotPlotElementHistogram.h>
|
||||
#include <KLib/misc/gnuplot/objects/GnuplotObjects.h>
|
||||
@@ -103,6 +106,11 @@ public:
|
||||
K::GnuplotSplotElementLines mapOutlineConcrete;
|
||||
K::GnuplotSplotElementLines mapBBoxes;
|
||||
|
||||
K::GnuplotSplotElementEmpty emptyElem;
|
||||
|
||||
|
||||
K::GnuplotSplotElementPM3D pm3doutline;
|
||||
|
||||
std::string codeFile;
|
||||
|
||||
struct Settings {
|
||||
@@ -134,6 +142,9 @@ public:
|
||||
mapOutlineDrywall.getStroke().getColor().setHexStr("#888888");
|
||||
mapOutlineGlass.getStroke().getColor().setHexStr("#888888"); mapOutlineGlass.getStroke().setType(K::GnuplotDashtype::DASHED);
|
||||
mapBBoxes.getStroke().setWidth(2);
|
||||
|
||||
splot.add(&emptyElem);
|
||||
|
||||
splot.add(&mapOutlineConcrete);
|
||||
splot.add(&mapOutlineDrywall);
|
||||
splot.add(&mapOutlineGlass);
|
||||
@@ -144,6 +155,8 @@ public:
|
||||
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(&pm3doutline);
|
||||
|
||||
splot.add(&points);
|
||||
points.setPointType(7);
|
||||
points.setPointSize(0.5);
|
||||
@@ -239,7 +252,8 @@ public:
|
||||
}
|
||||
|
||||
void addLabel(const std::string& txt, const Point3 pos) {
|
||||
gp << "set label '" << txt << "' at " << pos.x << "," << pos.y << "," << pos.z << "\n";
|
||||
//gp << "set label '" << txt << "' at " << pos.x << "," << pos.y << "," << pos.z << "\n";
|
||||
splot.getCustom() << "set label '" << txt << "' at " << pos.x << "," << pos.y << "," << pos.z << " front\n";
|
||||
}
|
||||
|
||||
void addRectangle(const Point3 p1, const Point3 p2, const Color c, bool front = false, bool fill = true) {
|
||||
@@ -271,11 +285,11 @@ public:
|
||||
splot.getObjects().add(poly);
|
||||
}
|
||||
|
||||
void addPolygon(const std::vector<Point3>& points, const std::string& color, bool front = false, bool fill = true, const float alpha = 1) {
|
||||
K::GnuplotObjectPolygon* addPolygon(const std::vector<Point3>& points, const std::string& color, bool front = false, bool fill = true, const float alpha = 1) {
|
||||
|
||||
for (const Point3 p : points) {
|
||||
if (p.z < settings.minZ) {return;}
|
||||
if (p.z > settings.maxZ) {return;}
|
||||
if (p.z < settings.minZ) {return nullptr;}
|
||||
if (p.z > settings.maxZ) {return nullptr;}
|
||||
}
|
||||
|
||||
const K::GnuplotFill pfill = (fill) ? (K::GnuplotFill(K::GnuplotFillStyle::SOLID, K::GnuplotColor::fromHexStr(color))) : (K::GnuplotFill::NONE());
|
||||
@@ -303,6 +317,8 @@ public:
|
||||
// gp << " fc rgb " << "'" << color << "'";
|
||||
// gp << "\n";
|
||||
|
||||
return poly;
|
||||
|
||||
}
|
||||
|
||||
void setZRange(const float min, const float max) {
|
||||
@@ -310,7 +326,7 @@ public:
|
||||
}
|
||||
|
||||
|
||||
void addFloorRect(const Point3 pos_m, const float size, Color c, float ratio = 1.0) {
|
||||
K::GnuplotObjectPolygon* addFloorRect(const Point3 pos_m, const float size, Color c, float ratio = 1.0) {
|
||||
|
||||
const Point3 p1 = pos_m + Point3(-size, -size/ratio, 0);
|
||||
const Point3 p2 = pos_m + Point3(+size, -size/ratio, 0);
|
||||
@@ -319,7 +335,7 @@ public:
|
||||
|
||||
std::vector<Point3> points = {p1,p2,p3,p4,p1};
|
||||
|
||||
addPolygon(points, c.toHEX(), false, true);
|
||||
return addPolygon(points, c.toHEX(), false, true);
|
||||
|
||||
// gp << "set object polygon from ";
|
||||
// for (size_t i = 0; i < points.size(); ++i) {
|
||||
@@ -397,6 +413,8 @@ public:
|
||||
|
||||
std::vector<Floorplan::Floor*> floors;
|
||||
|
||||
BBox3 bbox = FloorplanHelper::getBBox(map);
|
||||
|
||||
// only some floors??
|
||||
if (settings.floors.empty()) {
|
||||
floors = map->floors;
|
||||
@@ -406,33 +424,31 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// mapOutlineDrywall.addSegment(
|
||||
// K::GnuplotPoint3(bbox.getMin().x, bbox.getMin().y, bbox.getMin().z),
|
||||
// K::GnuplotPoint3(bbox.getMax().x, bbox.getMax().y, bbox.getMax().z)
|
||||
// );
|
||||
|
||||
splot.getAxisX().setRange(K::GnuplotAxis::Range(bbox.getMin().x, bbox.getMax().x));
|
||||
splot.getAxisY().setRange(K::GnuplotAxis::Range(bbox.getMin().y, bbox.getMax().y));
|
||||
splot.getAxisZ().setRange(K::GnuplotAxis::Range(0, 11));
|
||||
|
||||
// process each selected floor
|
||||
for (Floorplan::Floor* floor : floors) {
|
||||
|
||||
// plot obstacles?
|
||||
if (settings.obstacles) {
|
||||
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);
|
||||
switch(line->material) {
|
||||
case Floorplan::Material::CONCRETE: mapOutlineConcrete.addSegment(p1, p2); break;
|
||||
case Floorplan::Material::GLASS: mapOutlineGlass.addSegment(p1, p2); break;
|
||||
case Floorplan::Material::UNKNOWN:
|
||||
case Floorplan::Material::DRYWALL: mapOutlineDrywall.addSegment(p1, p2); break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
const float vo = floor->atHeight * 4.5;
|
||||
|
||||
// plot the floor's outline
|
||||
if (settings.outline) {
|
||||
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
|
||||
K::GnuplotColor color = K::GnuplotColor::fromRGB(210,210,210);
|
||||
if (poly->outdoor) {color = K::GnuplotColor::fromRGB(200, 240, 200);}
|
||||
|
||||
if (floor->atHeight < settings.minZ) {continue;}
|
||||
if (floor->atHeight > settings.maxZ) {continue;}
|
||||
|
||||
const float v = 180 + vo;
|
||||
|
||||
K::GnuplotColor color = K::GnuplotColor::fromRGB(v,v,v);
|
||||
if (poly->outdoor) {color = K::GnuplotColor::fromRGB(180, 240, 180);}
|
||||
//if (poly->method == Floorplan::OutlineMethod::REMOVE) {color = K::GnuplotColor::fromRGB(245,245,245);}
|
||||
K::GnuplotFill filler(K::GnuplotFillStyle::SOLID, color);
|
||||
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, K::GnuplotStroke::NONE());
|
||||
@@ -441,7 +457,56 @@ public:
|
||||
gpol->add(coord);
|
||||
}
|
||||
gpol->close();
|
||||
gpol->setZIndex(floor->atHeight-0.1); // below the lines
|
||||
//gpol->setFront(true);
|
||||
splot.getObjects().add(gpol);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// plot obstacles?
|
||||
if (settings.obstacles) {
|
||||
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
||||
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
|
||||
if (line) {
|
||||
|
||||
if (floor->atHeight < settings.minZ) {continue;}
|
||||
if (floor->atHeight > settings.maxZ) {continue;}
|
||||
|
||||
// const K::GnuplotPoint3 p1(line->from.x, line->from.y, floor->atHeight);
|
||||
// const K::GnuplotPoint3 p2(line->to.x, line->to.y, floor->atHeight);
|
||||
// switch(line->material) {
|
||||
// case Floorplan::Material::CONCRETE: mapOutlineConcrete.addSegment(p1, p2); break;
|
||||
// case Floorplan::Material::GLASS: mapOutlineGlass.addSegment(p1, p2); break;
|
||||
// case Floorplan::Material::UNKNOWN:
|
||||
// case Floorplan::Material::DRYWALL: mapOutlineDrywall.addSegment(p1, p2); break;
|
||||
// }
|
||||
|
||||
// K::GnuplotObjectArrow* arrow = new K::GnuplotObjectArrow(
|
||||
// K::GnuplotCoordinate3(line->from.x, line->from.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST),
|
||||
// K::GnuplotCoordinate3(line->to.x, line->to.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST)
|
||||
// );
|
||||
// arrow->setHead(K::GnuplotObjectArrow::Head::NONE);
|
||||
// splot.getObjects().add(arrow);
|
||||
|
||||
const float v = 140 + vo;
|
||||
|
||||
// drawing outlines as polygon is a hack for correct depth-order in gnuplot
|
||||
K::GnuplotColor color = K::GnuplotColor::fromRGB(v,v,v);
|
||||
K::GnuplotFill filler = K::GnuplotFill(K::GnuplotFillStyle::EMPTY_BORDER, color);
|
||||
K::GnuplotStroke stroke(K::GnuplotDashtype::NONE, 1, color);
|
||||
//K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(K::GnuplotFill::NONE(), stroke);
|
||||
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, stroke);
|
||||
//K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(K::GnuplotFill::NONE(), K::GnuplotStroke::NONE());
|
||||
|
||||
gpol->add(K::GnuplotCoordinate3(line->from.x, line->from.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST));
|
||||
gpol->add(K::GnuplotCoordinate3(line->to.x, line->to.y, floor->atHeight, K::GnuplotCoordinateSystem::FIRST));
|
||||
gpol->close();
|
||||
gpol->setZIndex(floor->atHeight); // above the ground polygon
|
||||
//gpol->setFront(true);
|
||||
splot.getObjects().add(gpol);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +515,32 @@ public:
|
||||
for (Floorplan::Stair* s : floor->stairs) {
|
||||
std::vector<Floorplan::Quad3> quads = Floorplan::getQuads(s->getParts(), floor);
|
||||
for (const Floorplan::Quad3& q : quads) {
|
||||
addPolygon({q.p1, q.p2, q.p3, q.p4, q.p1}, "#c0c0c0");
|
||||
// K::GnuplotObjectPolygon* poly = addPolygon({q.p1, q.p2, q.p3, q.p4, q.p1}, "#c0c0c0");
|
||||
// if (poly) {
|
||||
// poly->setZIndex(floor->atHeight+1.5); // above the floor
|
||||
// }
|
||||
|
||||
const float v1 = 180 + q.p1.z * 4.5;
|
||||
const float v2 = 140 + q.p1.z * 4.5;
|
||||
|
||||
const float z = (q.p1.z + q.p2.z + q.p3.z + q.p4.z) / 4.0f;
|
||||
|
||||
if (z < settings.minZ) {continue;}
|
||||
if (z > settings.maxZ) {continue;}
|
||||
|
||||
K::GnuplotColor color = K::GnuplotColor::fromRGB(v1,v1,v1);
|
||||
K::GnuplotColor color2 = K::GnuplotColor::fromRGB(v2,v2,v2);
|
||||
K::GnuplotFill filler(K::GnuplotFillStyle::SOLID, color);
|
||||
K::GnuplotStroke stroke(K::GnuplotDashtype::SOLID, 1, color2);
|
||||
K::GnuplotObjectPolygon* gpol = new K::GnuplotObjectPolygon(filler, stroke);
|
||||
gpol->add(K::GnuplotCoordinate3(q.p1.x, q.p1.y, q.p1.z, K::GnuplotCoordinateSystem::FIRST));
|
||||
gpol->add(K::GnuplotCoordinate3(q.p2.x, q.p2.y, q.p2.z, K::GnuplotCoordinateSystem::FIRST));
|
||||
gpol->add(K::GnuplotCoordinate3(q.p3.x, q.p3.y, q.p3.z, K::GnuplotCoordinateSystem::FIRST));
|
||||
gpol->add(K::GnuplotCoordinate3(q.p4.x, q.p4.y, q.p4.z, K::GnuplotCoordinateSystem::FIRST));
|
||||
gpol->close();
|
||||
gpol->setZIndex(z); // above the ground
|
||||
splot.getObjects().add(gpol);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
experiments
|
||||
|
||||
\todo{obwohl das angepasste modell doch recht gut laeuft und der fehler recht klein wird, sind immernoch stellen dabei,
|
||||
wo es einfach nicht gut passt, unguenstige mehrdeutigkeiten vorliegen, oder regionen einfach nicht passen wie sie sollten.
|
||||
das liegt teils auch daran, dass die fingerprints drehend aufgenommen wurden und beim laufen nach hinten durch den
|
||||
menschen abgeschottet wird. auch zeitlicher verzug kann ein problem darstellen.}
|
||||
|
||||
\todo{GPS ist leider kaum eine hilfe. entweder kein empfang wegen ueberdachung oder abschattung, oder
|
||||
zu kurz draußen um einen guten gps-fix zu bekommen.}
|
||||
\section{Experiments}
|
||||
|
||||
wir betrachten nur die fest-installierten APs die man meist anhand einer bestimmten mac-range ausmachen kann
|
||||
portable geraete von studenten, beamer, aehnliches werden ignoriert
|
||||
@@ -37,90 +30,248 @@ 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
|
||||
|
||||
path1
|
||||
31.8|38.9 7.8|11.6
|
||||
27.3|36.8 7.2|9.8
|
||||
24.0|30.3 5.8|10.24
|
||||
22.9|29.9 5.0|7.6
|
||||
|
||||
hoherer fehler weil mehr outdoor anteil
|
||||
path2
|
||||
32.0|42.4 12.6|20.9
|
||||
28.4|35.2 10.1|16.1
|
||||
27.0|34.0 7.0|10.1
|
||||
25.4|33.3 8.0|17.2
|
||||
|
||||
|
||||
je mehr outdoor, desto schlechter wird es.
|
||||
outdoor schadet auch der optimierung
|
||||
outdoor schadet mehr als indoor, weil das wifi modell fuer indoor noch halbwegs passt
|
||||
aber fuer outdoor so garned
|
||||
|
||||
|
||||
fenster sind metallbedampft und schirmen stark ab
|
||||
siehe beispielgrafik
|
||||
|
||||
gps wird so schnell nicht warm, versagt denn auf dem hof als hilfestellung
|
||||
|
||||
|
||||
|
||||
reines wifi eval mittels num-opt springt stark durch die gegend
|
||||
d.h. das bewegungsmodell rettet uns
|
||||
kann man auch testen wenn man beim particle-filter das resampling ganz aus macht
|
||||
|
||||
\todo{
|
||||
we analyzed various paths throughout the whole building
|
||||
}
|
||||
|
||||
\todo{
|
||||
mit grafik: exp-dist vergroesert teils den abstand zu anderen locations , der GT selbst wird also besser,
|
||||
aber an anderen stellen geht dafür der fehler hoch und kann zu verlaufen führen (z.B. treppenhaus)
|
||||
}
|
||||
|
||||
|
||||
|
||||
% -------------------------------- optimization -------------------------------- %
|
||||
|
||||
% used reference measurements
|
||||
\begin{figure}
|
||||
{
|
||||
\centering
|
||||
\input{gfx/all_fingerprints.tex}
|
||||
}
|
||||
\label{fig:referenceMeasurements}
|
||||
\caption{
|
||||
Locations of the 121 reference measurements.
|
||||
The size of each square denotes the number of permanently installed \docAPshort{}s
|
||||
that are visible at this location,
|
||||
and ranges between 2 and 22 with an average of 9.
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
% visible APs:
|
||||
% cnt(121) min(2.000000) max(22.000000) range(20.000000) med(8.000000) avg(9.322314) stdDev(4.386709)
|
||||
|
||||
\begin{figure}
|
||||
\input{gfx/wifi_model_error_0_95.tex}
|
||||
\input{gfx/wifi_model_error_95_100.tex}
|
||||
\label{fig:wifiModelError}%
|
||||
\caption{%
|
||||
Comparison between different optimization strategies by examining the error (in \decibel) at each reference measurement.%
|
||||
The higher the number of variable parameters, the better the model resembles real world conditions. %
|
||||
}%
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\input{gfx/compare-wifi-in-out.tex}
|
||||
\caption{
|
||||
Measurable signal strengths of a testing \docAPshort{} (black dot).
|
||||
While the signal diminishes slowly along the corridor (upper rectangle)
|
||||
the metallised windows (dashed outline) attenuate the signal by over \SI{30}{\decibel} (lower rectangle).
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
fenster sind metallbedampft und schirmen stark ab
|
||||
siehe beispielgrafik
|
||||
|
||||
\todo{
|
||||
distance between AP pos estimation and real position???
|
||||
}
|
||||
|
||||
|
||||
% -------------------------------- number of fingerprints -------------------------------- %
|
||||
|
||||
wie viele fingerprints sind genug?
|
||||
|
||||
Haengt vom modell ab
|
||||
|
||||
bei den einfachen modellen aendert sich erstmal nicht viel. man hat ja viele testdaten für ein modell mit wenigen parametern.
|
||||
je mehr variable wird, z.B. position, und das ganze pro AP und nicht füer alle, desto wichtiger wird, dass die fingerprints passen.
|
||||
|
||||
neuralgische schwachpunkte wie betonierte treppenhäuser kann man weglassen, dadurch wird der rest etwas besser,
|
||||
die treppenhäuser ansich aber natürlich nochmal schlechter. siehe \ref{fig:wifiNumFingerprints}
|
||||
|
||||
\begin{figure}
|
||||
\input{gfx/wifi_model_error_num_fingerprints_method_5_0_90.tex}
|
||||
\input{gfx/wifi_model_error_num_fingerprints_method_5_90_100.tex}
|
||||
\label{fig:wifiNumFingerprints}%
|
||||
\caption{%
|
||||
number of fingerprints
|
||||
}%
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
|
||||
% -------------------------------- wifi walk error -------------------------------- %
|
||||
|
||||
Using aforementioned model setups and the measurements $\mRssiVec$ determined by scanning for nearby \docAPshort{}s,
|
||||
we can directly perform a location estimation by rewriting \refeq{eq:wifiProb}:
|
||||
|
||||
\begin{equation}
|
||||
p(\mPosVec \mid \mRssiVec) =
|
||||
\frac{p(\mRssiVec \mid \mPosVec) p(\mPosVec)}{p(\mRssiVec)}
|
||||
\approx p(\mRssiVec \mid \mPosVec),\enskip
|
||||
p(\mPosVec) = p(\mRssiVec) = \text{const}
|
||||
.
|
||||
\label{eq:wifiBayes}
|
||||
\end{equation}
|
||||
|
||||
The pedestrian's current location $\mPosVec^*$ given $\mRssiVec$ satisfies
|
||||
|
||||
\begin{equation}
|
||||
\mPosVec^* = \argmax_{\mPosVec}
|
||||
p(\mRssiVec \mid \mPosVec)
|
||||
.
|
||||
\label{eq:bestWiFiPos}
|
||||
\end{equation}
|
||||
|
||||
The quality of the estimated location is determined by comparing the estimation
|
||||
$\mPosVec^*$ with the pedestrian's ground truth at the time the scan $\mRssiVec$
|
||||
has been received.
|
||||
|
||||
We therefore conducted 10 walks on 5 different paths within our building,
|
||||
each of which is defined by connecting several marker points at well known positions
|
||||
(see figure \ref{fig:allWalks}).
|
||||
Whenever the pedestrian reached such a marker, the current time was recorded.
|
||||
Due to constant walking speeds, the ground-truth for any timestamp can be approximated
|
||||
using linear interpolation between adjacent markers.
|
||||
|
||||
% walked paths
|
||||
\begin{figure}
|
||||
{
|
||||
\centering
|
||||
\input{gfx/all_walks.tex}
|
||||
}
|
||||
\label{fig:allWalks}
|
||||
\caption{
|
||||
Overview of all conducted paths.
|
||||
Outdoor areas are marked in green.
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
To estimate the performance of the prediction models, we compare the position estimation
|
||||
for each \docWIFI{} measurement within the recorded paths (3756 \docAPshort{} scans in total)
|
||||
against the corresponding ground-truth, which indicates the absolute 3D error in meter.
|
||||
|
||||
\begin{figure}
|
||||
\input{gfx/modelPerformance_meter.tex}
|
||||
\label{fig:modelPerformance}
|
||||
\caption{
|
||||
Error between ground truth and estimation using \refeq{eq:bestWiFiPos} depending
|
||||
on the underlying signal strength prediction model
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
As can be seen in figure \ref{fig:modelPerformance}, the quality of the location estimation
|
||||
directly scales with the quality of the signal strength prediction model.
|
||||
However, depending on the model, the maximal estimation error might increase (see \optParamsPosEachAP{}).
|
||||
%
|
||||
This is either due to multimodalities, where more than one area is possible based on the recent
|
||||
\docWIFI{} observation, or optimization yields an overadaption where the average signal
|
||||
strength prediction error is small, but the maximum error is dramatically increased for some regions.
|
||||
|
||||
|
||||
|
||||
% -------------------------------- plots indicating optimization issues -------------------------------- %
|
||||
|
||||
\begin{figure}
|
||||
\input{gfx/wifiMultimodality.tex}
|
||||
\label{fig:wifiMultimodality}
|
||||
\caption{
|
||||
Location probability \refeq{eq:bestWiFiPos} for three scans. Higher color intensities are more likely.
|
||||
Ideally, places near the ground truth (black) are highly highly probable (green).
|
||||
Often, other locations are just as likely as the ground truth (blue),
|
||||
or the location with the highest probability does not match at all (red).
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
Figure \ref{fig:wifiMultimodality} depicts aforementioned issues of multimodal (blue) or wrong (red) location
|
||||
estimations. Filtering (\refeq{eq:recursiveDensity}) thus is highly recommended as minor errors are compensated
|
||||
using other sensors and/or a movement model that prevents the estimation from leaping within the building.
|
||||
However, if wrong sensor values (red) are observed for longer time periods, even filtering will produce erroneous
|
||||
results and might get stranded (density is trapped e.g. within a room),
|
||||
as the movement model is constrained by the actual floorplan.
|
||||
|
||||
|
||||
% -------------------------------- other distributions, unseen APs, etc -------------------------------- %
|
||||
|
||||
To reduce the amount of misclassifications, where other locations within the building are (almost)
|
||||
as likely (see \refeq{eq:wifiProb}) as the pedestrians actual location, we examined various
|
||||
approaches. Unfortunately, none of which provided a viable enhancement under all conditions within
|
||||
the performed walks.
|
||||
|
||||
One possibility to dissolve an equal \docWIFI{}-likelihood between two (or more) locations within in the building
|
||||
is, to not only consider the \docAPshort{}s seen by the Smartphone, but also the \docAPshort{}s not seen
|
||||
by the Smartphone. Maybe there is an \docAP{} that should be visible at the other locations. However,
|
||||
as the Smartphone did not see this \docAPshort{} the other location can be ruled out.
|
||||
While this works in theory, evaluations revealed several issues:
|
||||
|
||||
There is a chance that an \docAPshort{} is unseen during a scan due to packet collisions or
|
||||
temporal effects within the surrounding. It thus might make sense to opt-out other locations
|
||||
only, if at least two \docAPshort{}s are missing. On the other hand, this obviously requires (at least)
|
||||
two \docAPshort{}s to actually be different between the two locations, which might not always be
|
||||
the case.
|
||||
|
||||
Also, this requires the signal strength prediction model to be fairly accurate. Within our testing
|
||||
walks there are several places surrounded by concrete walls, which cause a harsh, local drop in signal strength.
|
||||
The models used within this work will not accurately predict the signal strength for such locations.
|
||||
Including \docAPshort{}s unseen by the Smartphone thus often increases the estimation error instead
|
||||
of fixing the multimodality.
|
||||
|
||||
We therefore examined variations of the probability calculation from \refeq{eq:wifiProb}.
|
||||
Removing the strongest/weakest \docAPshort{} from $\mRssiVecWiFi{}$ yielded similar results.
|
||||
While some estimations were improved, the overall estimation error increased for our walks,
|
||||
as there are many situations where only a handful \docAP{}s can be seen. Removing (valid)
|
||||
information will highly increase the error for such situations.
|
||||
|
||||
Using a more strict exponential distribution for
|
||||
|
||||
\begin{figure}
|
||||
\input{gfx/wifiCompare_normalVsExp_cross.tex}
|
||||
\input{gfx/wifiCompare_normalVsExp_meter.tex}
|
||||
\label{fig:normalVsExponential}
|
||||
\caption{
|
||||
Comparison between normal- (black) and exponential-distribution (red) for \refeq{eq:wifiProb}.
|
||||
While misclassifications are slightly reduced (upper chart),
|
||||
the error between ground-truth and estimation (lower chart) increases by
|
||||
about \SI{1}{\meter} for the median.
|
||||
To reduce the amount such of misclassifications, where other locations within the building are
|
||||
as likely as the pedestrians actual location, we examined various approaches.
|
||||
Unfortunately, none of which provided a viable enhancement under all conditions for the performed walks:
|
||||
|
||||
One possibility to dissolve an equal \docWIFI{}-likelihood between two (or more) locations within in the building
|
||||
is, to not only consider the \docAPshort{}s seen by the Smartphone, but also the \docAPshort{}s not seen
|
||||
by the Smartphone. This additional information can be used to rule out all locations where this
|
||||
\docAP{} should be received (high signal strength from the prediction model).
|
||||
% There might be an \docAP{} that should be visible at the other locations. However,
|
||||
%as the Smartphone did not see this \docAPshort{} the other location can be ruled out.
|
||||
While this works in theory, evaluations revealed several issues:
|
||||
|
||||
There is a chance that even a nearby \docAPshort{} is unseen during a scan due to packet collisions or
|
||||
temporal effects within the surrounding. It thus might make sense to opt-out other locations
|
||||
only, if at least two \docAPshort{}s are missing. On the other hand, this obviously requires (at least)
|
||||
two \docAPshort{}s to actually be different between the two locations, and requires a lot of permanently
|
||||
installed transmitters to work out.
|
||||
|
||||
Furthermore, this requires the signal strength prediction model to be fairly accurate. Within our testing
|
||||
walks, several places are surrounded by concrete walls, which cause a harsh, local drop in signal strength.
|
||||
The models used within this work will not accurately predict the signal strength for such locations.
|
||||
Including \docAPshort{}s unseen by the Smartphone thus often increases the estimation error instead
|
||||
of fixing the multimodality.
|
||||
|
||||
|
||||
|
||||
We therefore examined variations of the probability calculation from \refeq{eq:wifiProb}.
|
||||
Removing the strongest/weakest \docAPshort{} from $\mRssiVecWiFi{}$ yielded similar results.
|
||||
While some estimations were improved, the overall estimation error increased for our walks,
|
||||
as there are many situations where only a handful \docAP{}s can be seen. Removing (valid)
|
||||
information will highly increase the error for such situations.
|
||||
|
||||
Using a more strict exponential distribution for the model vs. scan comparison in \refeq{eq:wifiProb}
|
||||
had a positive effect on the misclassification error for some of the walks, but slightly increased
|
||||
the estimation error (see figure \reffig{fig:normalVsExponential}) and thus produced negative side effects.
|
||||
|
||||
\begin{figure}
|
||||
\input{gfx/wifiCompare_normalVsExp_cross.tex}
|
||||
\input{gfx/wifiCompare_normalVsExp_meter.tex}
|
||||
\label{fig:normalVsExponential}
|
||||
\caption{
|
||||
Comparison between normal- (black) and exponential-distribution (red) for \refeq{eq:wifiProb}.
|
||||
While misclassifications are slightly reduced (upper chart),
|
||||
the median error between ground-truth and estimation (lower chart) increases by
|
||||
about \SI{1}{\meter}.
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
\todo{
|
||||
wir wollen nicht, dass die position des ground-truths durch das wifi so wahrscheinlich wie möglich ist,
|
||||
wir wollen dass die position des ground-truth einfach eine höhere wahrscheinlichkeit hat, als alle anderen punkte im gebäude
|
||||
das pruefen wir ab
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\todo{
|
||||
erkenntnisse:
|
||||
@@ -141,32 +292,33 @@ kann man auch testen wenn man beim particle-filter das resampling ganz aus macht
|
||||
|
||||
}
|
||||
|
||||
\todo{
|
||||
das bbox modell hat probleme an den uebergängen zwischen bboxes da dort teils starke spruenge sind
|
||||
die nicht immer in der realität so auch vorliegen. z.B. z-wechsel machen teils probleme.
|
||||
hier wäre ein kontinuierliches modell hilfreich bzw interpolation in randbereichen
|
||||
}
|
||||
|
||||
\todo{
|
||||
wenn ich beim fingerprinten einen AP an einer stelle NICHT gesehen habe,
|
||||
ist das auch eine aussage für die model optimierung.. da kann dann sicher keine signatlstaerke > -90 an der stelle raus kommen
|
||||
}
|
||||
% REAL WALKS
|
||||
\todo{obwohl das angepasste modell doch recht gut laeuft und der fehler recht klein wird, sind immernoch stellen dabei,
|
||||
wo es einfach nicht gut passt, unguenstige mehrdeutigkeiten vorliegen, oder regionen einfach nicht passen wie sie sollten.
|
||||
das liegt teils auch daran, dass die fingerprints drehend aufgenommen wurden und beim laufen nach hinten durch den
|
||||
menschen abgeschottet wird. auch zeitlicher verzug kann ein problem darstellen.}
|
||||
|
||||
\todo{GPS ist leider kaum eine hilfe. entweder kein empfang wegen ueberdachung oder abschattung, oder
|
||||
zu kurz draußen um einen guten gps-fix zu bekommen.}
|
||||
|
||||
|
||||
\todo{
|
||||
das bbox modell hat probleme an den uebergängen zwischen bboxes da dort teils starke spruenge sind
|
||||
die nicht immer in der realität so auch vorliegen. z.B. z-wechsel machen teils probleme.
|
||||
hier wäre ein kontinuierliches modell hilfreich bzw interpolation in randbereichen
|
||||
}
|
||||
|
||||
\todo{
|
||||
wenn ich beim fingerprinten einen AP an einer stelle NICHT gesehen habe,
|
||||
ist das auch eine aussage für die model optimierung.. da kann dann sicher keine signatlstaerke > -90 an der stelle raus kommen
|
||||
}
|
||||
|
||||
\todo{gps wird so schnell nicht warm, versagt denn auf dem hof als hilfestellung}
|
||||
|
||||
|
||||
|
||||
\todo{
|
||||
wir wollen nicht, dass die position des ground-truths durch das wifi so wahrscheinlich wie möglich ist,
|
||||
wir wollen dass die position des ground-truth einfach eine höhere wahrscheinlichkeit hat, als alle anderen punkte im gebäude
|
||||
das pruefen wir ab
|
||||
}
|
||||
|
||||
\begin{figure}
|
||||
\centering
|
||||
\input{gfx/compare-wifi-in-out.tex}
|
||||
\caption{
|
||||
Measurable signal strengths of a testing \docAPshort{} (black dot).
|
||||
While the signal diminishes slowly along the corridor (upper rectangle)
|
||||
the metallised windows (dashed outline) attenuate the signal by over \SI{30}{\decibel} (lower rectangle).
|
||||
}
|
||||
\end{figure}
|
||||
|
||||
ware das grid-model nicht da, wuerde der outdoor teil richtig schlecht laufen,
|
||||
weil das wlan hier absolut ungenau ist.. da die partikel aber aufgrund des vorherigen
|
||||
@@ -200,3 +352,6 @@ 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?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
relatedwork
|
||||
|
||||
wifi anfänge von radar (microsoft) etc
|
||||
\cite{radar} \cite{horus} \cite{secureAndRobust}
|
||||
|
||||
|
||||
andere methoden neben signalstärke
|
||||
\cite{TimeDifferenceOfArrival1} \cite{TOAAOA}
|
||||
|
||||
\cite{Ebner-15}
|
||||
|
||||
@@ -24,3 +24,13 @@
|
||||
\newcommand{\docsRSSI}{RSSI}
|
||||
|
||||
\newcommand{\docDSimplex}{downhill-simplex}
|
||||
|
||||
|
||||
|
||||
% optimizations
|
||||
\newcommand{\noOptEmpiric}{empiric params}
|
||||
\newcommand{\optParamsAllAP}{optimization 1}
|
||||
\newcommand{\optParamsEachAP}{optimization 2}
|
||||
\newcommand{\optParamsPosEachAP}{optimization 3}
|
||||
\newcommand{\optPerFloor}{model per floor}
|
||||
\newcommand{\optPerRegion}{model per region}
|
||||
|
||||
@@ -108,7 +108,7 @@ private:
|
||||
|
||||
Plotty* plot;
|
||||
|
||||
PlotWiFiGroundProb* groundProb;
|
||||
//PlotWiFiGroundProb* groundProb;
|
||||
|
||||
public:
|
||||
|
||||
@@ -133,10 +133,10 @@ public:
|
||||
vap = new VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
pef = new PlotErrFunc("\\small{error (m)}", "\\small{measurements (\\%)}");
|
||||
pef->showMarkers(false);
|
||||
pef->showMarkers(false, false);
|
||||
|
||||
pef2 = new PlotErrFunc("\\small{-log(p(..))}", "\\small{measurements (\\%)}");
|
||||
pef2->showMarkers(false);
|
||||
pef2->showMarkers(false, false);
|
||||
|
||||
pet = new PlotErrTime("walktime (seconds)", "\\small{error (m)}", "");
|
||||
pet->getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 25));
|
||||
|
||||
@@ -39,21 +39,25 @@ class EvalWiFiGround {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::IndoorMap* map;
|
||||
WiFiModel* mdl;
|
||||
WiFiObserverFree* obs;
|
||||
|
||||
public:
|
||||
|
||||
PlotWiFiGroundProb* groundProb;
|
||||
|
||||
public:
|
||||
|
||||
EvalWiFiGround(Floorplan::IndoorMap* map, const std::string calibModel) {
|
||||
EvalWiFiGround(Floorplan::IndoorMap* map, const std::string calibModel, Plotty::Settings settings = Plotty::Settings()) : map(map) {
|
||||
|
||||
mdl = WiFiModelFactory(map).loadXML(calibModel);
|
||||
obs = new WiFiObserverFree(8.0, *mdl);
|
||||
groundProb = new PlotWiFiGroundProb(map);
|
||||
groundProb = new PlotWiFiGroundProb(map, settings);
|
||||
|
||||
}
|
||||
|
||||
void show(const std::string walkFile) {
|
||||
void show(const std::string walkFile, const int idx = -1) {
|
||||
|
||||
Offline::FileReader reader(walkFile);
|
||||
int cnt = 0;
|
||||
@@ -72,6 +76,68 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void add(const std::string walkFile, const int idx, const float hue) {
|
||||
|
||||
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
Offline::FileReader reader(walkFile);
|
||||
|
||||
const auto& entry = reader.getWiFiGroupedByTime()[idx];
|
||||
const WiFiMeasurements& _mes = entry.data;
|
||||
const WiFiMeasurements mes = vap.group(_mes);
|
||||
|
||||
groundProb->showStrongest(*obs, mes, hue);
|
||||
//groundProb->plotMe();
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(2));
|
||||
|
||||
//groundProb->update();
|
||||
//groundProb->plotMe();
|
||||
int i = 0; (void) i;
|
||||
|
||||
}
|
||||
|
||||
void addGT(const std::string walkFile, const int idx, const float hue, const std::vector<int>& path) {
|
||||
|
||||
Offline::FileReader reader(walkFile);
|
||||
const auto& entry = reader.getWiFiGroupedByTime()[idx];
|
||||
const WiFiMeasurements& mes = entry.data;
|
||||
|
||||
// gt at the time of the wifi measurement
|
||||
const Timestamp ts = mes.entries.front().getTimestamp();
|
||||
const Point3 pt = reader.getGroundTruth(map, path).get(ts);
|
||||
|
||||
Color c1 = Color::fromRGB(0,0,0);
|
||||
Color c2 = Color::fromHSV(hue, 255, 255);
|
||||
|
||||
groundProb->getPlot().addFloorRect(pt+Point3(0,0,0.200), 1.5, c1);
|
||||
groundProb->getPlot().addFloorRect(pt+Point3(0,0,0.201), 1.0, c2);
|
||||
|
||||
}
|
||||
|
||||
void writeGP(const std::string& path, const std::string& name) {
|
||||
|
||||
const std::string file = path + "/" + name;
|
||||
|
||||
groundProb->getPlot().splot.getCustom() << "unset border \n";
|
||||
groundProb->getPlot().splot.getCustom() << "set view equal xy\n";
|
||||
|
||||
groundProb->getPlot().splot.getAxisX().setTicsVisible(false);
|
||||
groundProb->getPlot().splot.getAxisY().setTicsVisible(false);
|
||||
groundProb->getPlot().splot.getAxisZ().setTicsVisible(false);
|
||||
groundProb->getPlot().splot.getAxisZ().setRange(-12.500000, 21.200000);
|
||||
groundProb->getPlot().splot.getView().setCamera(72, 28);
|
||||
groundProb->getPlot().splot.getView().setScaleAll(5.5);
|
||||
|
||||
groundProb->getPlot().gp.setTerminal("epslatex", K::GnuplotSize(8.6, 4.0));
|
||||
groundProb->getPlot().gp.setOutput(file+".tex");
|
||||
groundProb->getPlot().gp.writePlotToFile(file+".gp");
|
||||
groundProb->plotMe();
|
||||
groundProb->getPlot().gp.writePlotToFile("");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // EVALWIFIGROUND_H
|
||||
|
||||
@@ -83,15 +83,15 @@ public:
|
||||
vap = new VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
pef_m = new PlotErrFunc("error (meter)", "measurements (%)");
|
||||
pef_m->showMarkers(false);
|
||||
pef_m->showMarkers(false, false);
|
||||
|
||||
pef_p = new PlotErrFunc("-log(p(..))", "measurements (%)");
|
||||
pef_p->showMarkers(false);
|
||||
pef_p->showMarkers(false, false);
|
||||
pef_p->getPlot().getAxisX().setRange(K::GnuplotAxis::Range(K::GnuplotAxis::Range::AUTO, K::GnuplotAxis::Range::AUTO));
|
||||
|
||||
|
||||
pef_c = new PlotErrFunc("cross error", "measurements (%)");
|
||||
pef_c->showMarkers(false);
|
||||
pef_c->showMarkers(false, false);
|
||||
pef_c->getPlot().getAxisX().setRange(K::GnuplotAxis::Range(K::GnuplotAxis::Range::AUTO, K::GnuplotAxis::Range::AUTO));
|
||||
|
||||
|
||||
@@ -220,9 +220,9 @@ public:
|
||||
pef.getGP() << "set tmargin 0.1\n";
|
||||
pef.getGP() << "set rmargin 0.4\n";
|
||||
pef.getGP() << "set bmargin 2.0\n";
|
||||
pef.writeCodeTo(file+".gp");
|
||||
pef.writePlotToFile(file+".gp");
|
||||
pef.plot();
|
||||
pef.writeCodeTo("");
|
||||
pef.writePlotToFile("");
|
||||
}
|
||||
|
||||
void walk(const std::string& fPath, const std::vector<int> gtIndices) {
|
||||
|
||||
@@ -72,16 +72,44 @@ public:
|
||||
// how to handle VAPs
|
||||
vap = new VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
pef_m = new PlotErrFunc("\\small{error (m)}", "\\small{measurements (\\%)}");
|
||||
pef_m->showMarkers(false);
|
||||
pef_m = new PlotErrFunc("error (m)", "measurements (%)");
|
||||
pef_m->showMarkers(false, false);
|
||||
|
||||
pef_p = new PlotErrFunc("\\small{-log(p(..))}", "\\small{measurements (\\%)}");
|
||||
pef_p->showMarkers(false);
|
||||
pef_p = new PlotErrFunc("-log(p(..))", "measurements (%)");
|
||||
pef_p->showMarkers(false, false);
|
||||
pef_p->getPlot().getAxisX().setRange(K::GnuplotAxis::Range(K::GnuplotAxis::Range::AUTO, K::GnuplotAxis::Range::AUTO));
|
||||
|
||||
}
|
||||
|
||||
|
||||
void writeGP(const std::string& path, const std::string& name) {
|
||||
writeGP(*pef_m, K::GnuplotSize(8.6, 3.3), path + "/" + name + "_meter");
|
||||
writeGP(*pef_p, K::GnuplotSize(8.6, 3.3), path + "/" + name + "_logprob");
|
||||
}
|
||||
|
||||
void writeGP(PlotErrFunc& pef, K::GnuplotSize size, const std::string& file) {
|
||||
pef.getGP().setTerminal("epslatex", size);
|
||||
pef.getGP().setOutput(file+".tex");
|
||||
pef.getPlot().getKey().setVisible(true);
|
||||
pef.getPlot().getKey().setSampleLength(0.5);
|
||||
pef.getPlot().getKey().setPosition(K::GnuplotKey::Hor::RIGHT, K::GnuplotKey::Ver::BOTTOM);
|
||||
pef.getPlot().getKey().setWidthIncrement(7);
|
||||
pef.getPlot().getAxisY().setLabelOffset(2.5, 0);
|
||||
pef.getPlot().getAxisY().setTicsStep(0, 25, 95);
|
||||
|
||||
// MANUAL AXIS RANGE SETTINGS
|
||||
pef.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0,25));
|
||||
pef.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0,95));
|
||||
|
||||
pef.getPlot().getAxisX().setLabel("");
|
||||
pef.getPlot().setStringMod(new K::GnuplotStringModLaTeX());
|
||||
pef.getPlot().getMargin().set(4.5, 0.4, 0.1, 2.0);
|
||||
pef.writePlotToFile(file+".gp");
|
||||
pef.plot();
|
||||
pef.writePlotToFile("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loadModel(const std::string& xmlFile, const std::string& name) {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user