current code and TeX. code fine?!?!?!

This commit is contained in:
2017-04-29 20:57:12 +02:00
parent fc72a75f57
commit 60712689cf
41 changed files with 804 additions and 234 deletions

View File

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

0
CSV.h Normal file → Executable file
View File

0
EvalApOpt.h Normal file → Executable file
View File

0
EvalCompareOpt.h Normal file → Executable file
View File

9
EvalCompareOpt2.h Normal file → Executable file
View File

@@ -317,6 +317,15 @@ public:
const MACAddress mac(ap->mac); const MACAddress mac(ap->mac);
const std::vector<WiFiFingerprint> fps = getFingerprints(mac); const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
// ensure a certain number of fingerprints
// otherwise: ignore this AP as it can not be optimized!
if (fps.size() < 3) {
std::cout << "IGNORING " << mac.asString() << " due to insufficient fingerprints! using fixed -100 entry" << std::endl;
res.model.addAP(mac, Point3(0,0,0), -100, 0, 0, false);
//res.model.addAP(mac, pos_m, params[3], params[4], params[5], false);
continue;
}
// resulting error // resulting error
auto errFunc = [&] (const Point3 pos_m, const float txp, const float exp, const float waf) -> K::Statistics<float> { auto errFunc = [&] (const Point3 pos_m, const float txp, const float exp, const float waf) -> K::Statistics<float> {
WiFiModelLogDistCeiling model(map); // new, empty model for this AP WiFiModelLogDistCeiling model(map); // new, empty model for this AP

0
EvalData.h Normal file → Executable file
View File

0
EvalWiFiSigStrength.h Normal file → Executable file
View File

0
EvalWifiOptResult.h Normal file → Executable file
View File

0
Helper.h Normal file → Executable file
View File

0
README.md Normal file → Executable file
View File

19
Settings.h Normal file → Executable file
View File

@@ -6,10 +6,11 @@
namespace Settings { namespace Settings {
const std::string pathData = "/apps/android/workspace/OTHER2017/data/"; const std::string pathbase = "/mnt/vm/paper/OTHER2017/";
const std::string pathWalks = "/apps/android/workspace/OTHER2017/data/"; const std::string pathData = pathbase + "/data/";
const std::string pathWalksToni = "/apps/android/workspace/OTHER2017/data/toni/"; const std::string pathWalks = pathbase + "/data/";
const std::string pathWiFi = "/apps/android/workspace/OTHER2017/data/wifi/"; const std::string pathWalksToni = pathbase + "/data/toni/";
const std::string pathWiFi = pathbase + "/data/wifi/";
// GPS walks // GPS walks
const std::string path1a = pathWalks + "path1/1490208103510.csv"; const std::string path1a = pathWalks + "path1/1490208103510.csv";
@@ -51,19 +52,19 @@ namespace Settings {
const std::string wifiEachOptParPos_perBBox = pathWiFi + "eachOptParPos_perBBox.xml"; const std::string wifiEachOptParPos_perBBox = pathWiFi + "eachOptParPos_perBBox.xml";
const std::string fMap = "/apps/android/workspace/IndoorMap/maps/SHL38_no_elev.xml"; const std::string fMap = pathbase + "/data/SHL38_no_elev.xml";
const std::string fCalib = "/apps/android/workspace/OTHER2017/data/wifi_fp_all.dat"; const std::string fCalib = pathbase + "/data/wifi_fp_all.dat";
const std::string fPathGFX = "/apps/android/workspace/OTHER2017/tex/gfx/"; const std::string fPathGFX = pathbase + "/tex/gfx/";
int numParticles = 2500; int numParticles = 5000;
float smartphoneAboveGround = 1.3; float smartphoneAboveGround = 1.3;
namespace IMU { namespace IMU {
const float turnSigma = 1.25;//1.5; const float turnSigma = 1.25;//1.5;
const float stepLength = 0.70+0.3; const float stepLength = 0.70+0.3;
const float stepSigma = 0.10; const float stepSigma = 0.15 + 0.10;
const float absHeadSigma = 20; const float absHeadSigma = 20;
} }

0
Structs.h Normal file → Executable file
View File

0
TestMapEarthReg.h Normal file → Executable file
View File

0
bboxes.h Normal file → Executable file
View File

231
main.cpp Normal file → Executable file
View File

@@ -248,7 +248,7 @@ void errorPlotAllModels(Floorplan::IndoorMap* map) {
std::vector<K::Statistics<float>> errors = errorStatAllModels(map); std::vector<K::Statistics<float>> errors = errorStatAllModels(map);
PlotErrFunc plot("", "fingerprints (%)"); PlotErrFunc plot("", "reference measurements (%)");
plot.getPlot().getAxisX().setTicsLabelFormat("%h dB"); plot.getPlot().getAxisX().setTicsLabelFormat("%h dB");
plot.add("\\noOptEmpiric{}", &errors[0]); plot.add("\\noOptEmpiric{}", &errors[0]);
plot.add("\\optParamsAllAP{}", &errors[1]); plot.add("\\optParamsAllAP{}", &errors[1]);
@@ -275,14 +275,15 @@ void errorPlotAllModels(Floorplan::IndoorMap* map) {
// plot.getGP() << "set rmargin 0.2\n"; // plot.getGP() << "set rmargin 0.2\n";
// plot.getGP() << "set bmargin 1.9\n"; // plot.getGP() << "set bmargin 1.9\n";
plot.getPlot().getMargin().set(4.2, 0.2, 0.1, 1.9); plot.getPlot().getMargin().set(4.2, 0.2, 0.1, 1.9);
plot.getPlot().getAxisY().setLabelOffset(3.0,0); plot.getPlot().getAxisY().setLabelOffset(3.0 - 0.75, 0);
plot.getPlot().setStringMod(new K::GnuplotStringModLaTeX()); plot.getPlot().setStringMod(new K::GnuplotStringModLaTeX());
plot.getPlot().getKey().setSampleLength(0.5); plot.getPlot().getKey().setSampleLength(0.5);
plot.getPlot().getKey().setWidthIncrement(+7.0); plot.getPlot().getKey().setWidthIncrement(+7.0);
plot.setYRange(0, 95, 5); plot.setYRange(0, 95, 5);
plot.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 100)); plot.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 95));
plot.getPlot().getAxisY().setTicsStep(0, 25, 100); //plot.getPlot().getAxisY().setTicsStep(0, 25, 100);
plot.getPlot().getAxisY().setTicsStep({0,25,50,75,95});
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 4.0)); plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 4.0));
plot.getPlot().getAxisX().setTicsStep(4); // 4dB plot.getPlot().getAxisX().setTicsStep(4); // 4dB
plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0, 16)); plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0, 16));
@@ -308,7 +309,7 @@ void errorPlotAllModels(Floorplan::IndoorMap* map) {
/** error plot for the given stats. used for fingerprint errors */ /** 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) { void errorPlotNumFingerprints(const std::vector<K::Statistics<float>>& stats, const std::vector<std::string>& titles, const std::string& name) {
PlotErrFunc plot("", "fingerprints (%)"); PlotErrFunc plot("", "ref. measurements (%)");
plot.getPlot().getAxisX().setTicsLabelFormat("%h dB"); plot.getPlot().getAxisX().setTicsLabelFormat("%h dB");
plot.getPlot().getKey().setVisible(true); plot.getPlot().getKey().setVisible(true);
@@ -335,22 +336,26 @@ void errorPlotNumFingerprints(const std::vector<K::Statistics<float>>& stats, co
// plot.getGP() << "set rmargin 0.2\n"; // plot.getGP() << "set rmargin 0.2\n";
// plot.getGP() << "set bmargin 1.9\n"; // plot.getGP() << "set bmargin 1.9\n";
plot.getPlot().getMargin().set(4.2, 0.2, 0.1, 1.9); plot.getPlot().getMargin().set(4.2, 0.2, 0.1, 1.9);
plot.getPlot().getAxisY().setLabelOffset(3.0,0); plot.getPlot().getAxisY().setLabelOffset(3.0 - 0.7,0);
plot.getPlot().setStringMod(new K::GnuplotStringModLaTeX()); plot.getPlot().setStringMod(new K::GnuplotStringModLaTeX());
plot.getPlot().getKey().setSampleLength(0.5); plot.getPlot().getKey().setSampleLength(0.5);
plot.getPlot().getKey().setWidthIncrement(-5.0); plot.getPlot().getKey().setWidthIncrement(-5.0);
plot.setYRange(0, 90, 5); plot.setYRange(0, 90, 5);
plot.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 100)); plot.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 90));
plot.getPlot().getAxisY().setTicsStep(0, 25, 100); plot.getPlot().getAxisY().setTicsStep({0, 25, 50, 75, 90});
//lot.getPlot().getAxisY().setTicsStep(0, 25, 100);
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 3.3)); plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 3.3));
plot.getPlot().getAxisX().setTicsStep(4); // 4dB plot.getPlot().getAxisX().setTicsStep(4); // 4dB
plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0, 16)); plot.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0, 14));
plot.getGP().setOutput(Settings::fPathGFX + "/" + name + "_0_90.tex"); plot.getGP().setOutput(Settings::fPathGFX + "/" + name + "_0_90.tex");
plot.writePlotToFile(Settings::fPathGFX + "/" + name + "_0_90.gp"); plot.writePlotToFile(Settings::fPathGFX + "/" + name + "_0_90.gp");
plot.plot(); plot.plot();
// changes
plot.getPlot().getKey().setVisible(false); plot.getPlot().getKey().setVisible(false);
plot.getPlot().getAxisY().setLabel("");
plot.setYRange(90, 100, 1); plot.setYRange(90, 100, 1);
plot.getPlot().getAxisY().setTicsStep(2); plot.getPlot().getAxisY().setTicsStep(2);
plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 2.6)); plot.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 2.6));
@@ -572,6 +577,8 @@ void plotEstAndRealApPosDistance(Floorplan::IndoorMap* map) {
} }
#warning "TODO: code um alle pfade MEHRFACH mit allen modellen durch den filter laufen zu lassen"
// build plots for the paper // build plots for the paper
void paperOutputs() { void paperOutputs() {
@@ -666,13 +673,15 @@ void paperOutputs() {
// perform varios AP-param optimizations // perform varios AP-param optimizations
// generate error plot showing the performance of each // generate error plot showing the performance of each
// save the resulting wifi-models to XML for later re-use during the walk-eval <<<<<< !!!! // save the resulting wifi-models to XML for later re-use during the walk-eval <<<<<< !!!!
if (1 == 0) { if (1 == 1) {
rebuildAllModels(map, 0); rebuildAllModels(map, 0);
/** detailled error analysis for above optimization routine */ /** detailled error analysis for above optimization routine */
errorPlotAllModels(map); errorPlotAllModels(map);
} }
// leaving out fingerprints and the effects on all optimization strategies
if (1 == 0) { if (1 == 0) {
rebuildAllModels(map,4); rebuildAllModels(map,4);
@@ -686,6 +695,13 @@ void paperOutputs() {
// analyze all 5 opt strategies. skip the empiric one: stats0[0] // analyze all 5 opt strategies. skip the empiric one: stats0[0]
for (int i = 1; i < 6; ++i) { for (int i = 1; i < 6; ++i) {
std::cout << "leaving out fingerprints for model " << i << std::endl;
std::cout << "\t 25%: " << stats4[i].asString() << std::endl;
std::cout << "\t 50%: " << stats2[i].asString() << std::endl;
std::cout << "\t 100%: " << stats0[i].asString() << std::endl;
std::cout << "\t noStair%: " << statsNoStairs[i].asString() << std::endl;
std::cout << std::endl;
std::string name = "wifi_model_error_num_fingerprints_method_" + std::to_string(i); std::string name = "wifi_model_error_num_fingerprints_method_" + std::to_string(i);
errorPlotNumFingerprints( errorPlotNumFingerprints(
{stats0[0], stats4[i], stats2[i], stats0[i], statsNoStairs[i]}, {stats0[0], stats4[i], stats2[i], stats0[i], statsNoStairs[i]},
@@ -729,62 +745,36 @@ void paperOutputs() {
// error histogram all pos, all params, between in/out/stair, in/out, in/stair, in // // error histogram all pos, all params, between in/out/stair, in/out, in/stair, in
if(1==0){ // if(1==0){
EvalCompareOpt e1(Settings::fMap, Settings::fCalib, false, false, false); // EvalCompareOpt e1(Settings::fMap, Settings::fCalib, false, false, false);
EvalCompareOpt e2(Settings::fMap, Settings::fCalib, true, false, false); // EvalCompareOpt e2(Settings::fMap, Settings::fCalib, true, false, false);
EvalCompareOpt e3(Settings::fMap, Settings::fCalib, false, true, false); // EvalCompareOpt e3(Settings::fMap, Settings::fCalib, false, true, false);
EvalCompareOpt e4(Settings::fMap, Settings::fCalib, true, true, false); // EvalCompareOpt e4(Settings::fMap, Settings::fCalib, true, true, false);
K::Statistics<float> s1 = e1.optPosOptParamsForEach().errAbs; // K::Statistics<float> s1 = e1.optPosOptParamsForEach().errAbs;
K::Statistics<float> s2 = e2.optPosOptParamsForEach().errAbs; // K::Statistics<float> s2 = e2.optPosOptParamsForEach().errAbs;
K::Statistics<float> s3 = e3.optPosOptParamsForEach().errAbs; // K::Statistics<float> s3 = e3.optPosOptParamsForEach().errAbs;
K::Statistics<float> s4 = e4.optPosOptParamsForEach().errAbs; // K::Statistics<float> s4 = e4.optPosOptParamsForEach().errAbs;
PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}"); // PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
pef.add("\\small{floor + stairs + out}", &s1); // pef.add("\\small{floor + stairs + out}", &s1);
pef.add("\\small{floor + out}", &s2); // pef.add("\\small{floor + out}", &s2);
pef.add("\\small{floor + stairs}", &s3); // pef.add("\\small{floor + stairs}", &s3);
pef.add("\\small{floor}", &s4); // pef.add("\\small{floor}", &s4);
pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5)); // pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5));
pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.tex"); // pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.tex");
pef.writePlotToFile(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 key right bottom width -3\n";
pef.getGP() << "set rmargin 0.4\n"; // pef.getGP() << "set rmargin 0.4\n";
pef.getGP() << "set tmargin 0.4\n"; // pef.getGP() << "set tmargin 0.4\n";
pef.plot(); // pef.plot();
} // }
// wifi issue for path1
if (1 == 0) {
Offline::FileReader reader(Settings::path1a);
PlotWifiMeasurements plot;
for (int i = 0; i < 60; ++i) {
const WiFiMeasurements mes = reader.getWiFiGroupedByTime().at(i).data;
const WiFiMeasurements mes2 = Settings::WiFiModel::vg_eval.group(mes);
plot.add(mes2);
}
K::GnuplotObjectRectangle rect(
K::GnuplotCoordinate2(0, K::GnuplotCoordinateSystem::FIRST, 0, K::GnuplotCoordinateSystem::GRAPH),
K::GnuplotCoordinate2(10, K::GnuplotCoordinateSystem::FIRST, 1, K::GnuplotCoordinateSystem::GRAPH),
K::GnuplotFill(K::GnuplotFillStyle::SOLID, K::GnuplotColor::fromRGB(128,128,128), 0.5),
K::GnuplotStroke()
);
plot.getPlot().setGrid(true);
plot.getPlot().getKey().setVisible(false);
plot.getPlot().getObjects().add(&rect);
plot.plot();
sleep(100);
}
} }
@@ -799,13 +789,20 @@ void testWAF() {
K::Gnuplot gp; K::Gnuplot gp;
K::GnuplotPlot gplot; K::GnuplotPlot gplot;
K::GnuplotPlotElementLines lines; gplot.add(&lines); K::GnuplotPlotElementLines lines; gplot.add(&lines);
K::GnuplotPlotElementLines ceils; gplot.add(&ceils);
const Point3 posAP(0, 0, 8); const Point3 posAP(0, 0, 8);
for (const float h : ceilings.getCeilings()) {
ceils.addSegment(K::GnuplotPoint2(h, -2), K::GnuplotPoint2(h, +4));
}
for (float z = 0; z < 15; z += 0.1) { for (float z = 0; z < 15; z += 0.1) {
const Point3 posMe(0, 0, z); const Point3 posMe(0, 0, z);
//float factor = ceilings.numCeilingsBetweenLinearInt(posAP, posMe);
float factor = ceilings.numCeilingsBetweenFloat(posAP, posMe); float factor = ceilings.numCeilingsBetweenFloat(posAP, posMe);
lines.add({z, factor}); lines.add({z, factor});
} }
@@ -813,7 +810,7 @@ void testWAF() {
gp.draw(gplot); gp.draw(gplot);
gp.flush(); gp.flush();
sleep(1000); sleep(10);
} }
@@ -900,6 +897,10 @@ int main(void) {
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap); Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);
//testWAF(); //testWAF();
//sleep(1);
//const float rssi = LogDistanceModel::distanceToRssi(-100, 0, 999);
//int i = 0; (void) i;
//paperOutputs(); return 0; //paperOutputs(); return 0;
@@ -908,11 +909,41 @@ int main(void) {
//showFingerprintsFor(Settings::fMap, Settings::fCalib, "D8:84:66:4A:4A:E0"); //showFingerprintsFor(Settings::fMap, Settings::fCalib, "D8:84:66:4A:4A:E0");
//showModelFor(Settings::fMap, Settings::wifiEachOptParPos_multimodel, "D8:84:66:4A:4A:E0"); //showModelFor(Settings::fMap, Settings::wifiEachOptParPos_multimodel, "D8:84:66:4A:4A:E0");
if (1 == 1) { if (1 == 0) {
plotEstAndRealApPosDistance(map); plotEstAndRealApPosDistance(map);
int i = 0; (void) i; int i = 0; (void) i;
} }
// // wifi issue for path1
// if (1 == 1) {
// Offline::FileReader reader(Settings::path1a);
// PlotWifiMeasurements plot;
// for (int i = 0; i < 60; ++i) {
// const WiFiMeasurements mes = reader.getWiFiGroupedByTime().at(i).data;
// const WiFiMeasurements mes2 = Settings::WiFiModel::vg_eval.group(mes);
// plot.add(mes2);
// }
// K::GnuplotObjectRectangle rect(
// K::GnuplotCoordinate2(0, K::GnuplotCoordinateSystem::FIRST, 0, K::GnuplotCoordinateSystem::GRAPH),
// K::GnuplotCoordinate2(10, K::GnuplotCoordinateSystem::FIRST, 1, K::GnuplotCoordinateSystem::GRAPH),
// K::GnuplotFill(K::GnuplotFillStyle::SOLID, K::GnuplotColor::fromRGB(128,128,128), 0.5),
// K::GnuplotStroke()
// );
// plot.getPlot().setGrid(true);
// plot.getPlot().getKey().setVisible(false);
// plot.getPlot().getObjects().add(&rect);
// plot.plot();
// sleep(100);
// }
// calib error in/out // calib error in/out
if (1 == 0) { if (1 == 0) {
@@ -942,22 +973,31 @@ int main(void) {
} }
// prob on ground // plot probability within the building for every wifi measurement
if (1 == 0) { if (1 == 0) {
EvalWiFiGround eval(map, Settings::wifiEachOptParPos_multimodel); Plotty::Settings settings;
settings.outline = false;
EvalWiFiGround eval(map, Settings::wifiEachOptParPos_multimodel, settings);
//EvalWiFiGround eval(map, Settings::wifiEachOptParPos_perBBox, settings);
//EvalWiFiGround eval(map, Settings::wifiEachOptPar, settings);
//EvalWiFiGround eval(map, Settings::wifiEachOptParPos, settings);
//eval.show(Settings::path1a); //eval.show(Settings::path1a);
eval.show(Settings::path2a); //eval.show(Settings::path_toni_inst_2b, Settings::GroundTruth::path_toni_inst_2);
eval.show(Settings::path_toni_inst_3a, Settings::GroundTruth::path_toni_inst_3);
int i = 0; (void) i; int i = 0; (void) i;
} }
// walks // walks
if (1 == 0) { if (1 == 1) {
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);; Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);;
EvalWalk walk(map); //EvalWalk walk(map);
walk.walk1(); //walk.walk1();
EvalWalk::walkEverything(map);
EvalWalk::walkEverythingBuildStats(map);
return 0; return 0;
} }
@@ -1069,21 +1109,24 @@ int main(void) {
std::cout << "num scans: " << numScans << std::endl; std::cout << "num scans: " << numScans << std::endl;
if (1 == 1) {
EvalWiFiPaths ewp(Settings::fMap); EvalWiFiPaths ewp(Settings::fMap);
ewp.loadModel(Settings::wifiAllFixed, "\\noOptEmpiric{}"); ewp.loadModel(Settings::wifiAllFixed, "\\noOptEmpiric{}");
ewp.walks(files, gtIndices); ewp.walks(files, gtIndices);
ewp.loadModel(Settings::wifiEachOptParPos, "\\optParamsPosEachAP{}"); ewp.loadModel(Settings::wifiEachOptParPos, "\\optParamsPosEachAP{}");
ewp.walks(files, gtIndices); ewp.walks(files, gtIndices);
ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "\\optPerFloor{}"); ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "\\optPerFloor{}");
ewp.walks(files, gtIndices); ewp.walks(files, gtIndices);
ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "\\optPerRegion{}"); ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "\\optPerRegion{}");
ewp.walks(files, gtIndices); ewp.walks(files, gtIndices);
ewp.writeGP(Settings::fPathGFX, "modelPerformance"); ewp.writeGP(Settings::fPathGFX, "modelPerformance");
}
// examine various modifications // examine various modifications
if (1 == 0) { if (1 == 0) {
@@ -1114,27 +1157,27 @@ int main(void) {
} }
// compare wifi opt methods // // compare wifi opt methods
if (1 == 0) { // if (1 == 0) {
const bool ignoreStaircases = false; // const bool ignoreStaircases = false;
const bool ignoreOutdoor = false; // const bool ignoreOutdoor = false;
const bool ignoreIndoor = false; // const bool ignoreIndoor = false;
EvalCompareOpt opt(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor); // EvalCompareOpt opt(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
EvalCompareOpt::Result s1 = opt.fixedPosFixedParamsForAll(); //BREAK; // EvalCompareOpt::Result s1 = opt.fixedPosFixedParamsForAll(); //BREAK;
EvalCompareOpt::Result s2 = opt.fixedPosOptParamsForAll(); //BREAK; // EvalCompareOpt::Result s2 = opt.fixedPosOptParamsForAll(); //BREAK;
EvalCompareOpt::Result s3 = opt.fixedPosOptParamsForEach(); //BREAK; // EvalCompareOpt::Result s3 = opt.fixedPosOptParamsForEach(); //BREAK;
EvalCompareOpt::Result s4 = opt.optPosOptParamsForEach(); //BREAK; // EvalCompareOpt::Result s4 = opt.optPosOptParamsForEach(); //BREAK;
PlotErrFunc pef("error (dB)", "fingerprints (%)"); // PlotErrFunc pef("error (dB)", "fingerprints (%)");
pef.add("empiric", &s1.errAbs); // pef.add("empiric", &s1.errAbs);
pef.add("real pos, opt params [same for all]", &s2.errAbs); // pef.add("real pos, opt params [same for all]", &s2.errAbs);
pef.add("real pos, opt params [for each]", &s3.errAbs); // pef.add("real pos, opt params [for each]", &s3.errAbs);
pef.add("opt pos, opt params [for each]", &s4.errAbs); // pef.add("opt pos, opt params [for each]", &s4.errAbs);
pef.plot(); // pef.plot();
} // }
// compare leaving out fingerprints // compare leaving out fingerprints
if (1 == 0) { if (1 == 0) {

0
old/main.h Normal file → Executable file
View File

398
pf/EvalWalk.h Normal file → Executable file
View File

@@ -44,6 +44,15 @@
#include <Indoor/sensors/offline/FileReader.h> #include <Indoor/sensors/offline/FileReader.h>
#include <Indoor/sensors/offline/Listener.h> #include <Indoor/sensors/offline/Listener.h>
#define PLOT_LIVE
//#define PLOT_WIFI
//#define PLOT_ERROR_TIME
//#define PLOT_ERROR_FUNC
#define PLOT_UPDATE_STEP 20
class EvalWalk : public Offline::Listener { class EvalWalk : public Offline::Listener {
Grid<MyGridNode>* grid; Grid<MyGridNode>* grid;
@@ -53,6 +62,8 @@ class EvalWalk : public Offline::Listener {
Plotty plotty; Plotty plotty;
PlotWifiMeasurements plotWifi; PlotWifiMeasurements plotWifi;
PlotErrTime pet;
PlotErrFunc pef;
Offline::FileReader reader; Offline::FileReader reader;
Offline::FilePlayer player; Offline::FilePlayer player;
@@ -74,11 +85,15 @@ class EvalWalk : public Offline::Listener {
EarthMapping em; EarthMapping em;
std::string walkName;
float absHead = 0; float absHead = 0;
public: public:
EvalWalk(Floorplan::IndoorMap* map) : plotty(map), map(map), em(map) { EvalWalk(Floorplan::IndoorMap* map) : plotty(map), map(map), em(map),
pet("\\small{time (sec)}", "\\small{error (m)}", "\\small{APs visible}"),
pef("\\small{error (m)}", "\\small{updates (\\%)}") {
const std::string saveFile = Settings::pathData + "/grid.dat"; const std::string saveFile = Settings::pathData + "/grid.dat";
grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm); grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm);
@@ -108,8 +123,8 @@ public:
pf->setTransition( std::unique_ptr<PFTrans>( new PFTrans(grid)) ); pf->setTransition( std::unique_ptr<PFTrans>( new PFTrans(grid)) );
// resampling step? // resampling step?
//pf->setNEffThreshold(0.15); pf->setNEffThreshold(0.02);
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) ); pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) );
//pf->setNEffThreshold(0.75); //pf->setNEffThreshold(0.75);
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.10)) ); //pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.10)) );
@@ -117,9 +132,9 @@ public:
//pf->setNEffThreshold(0.75); //pf->setNEffThreshold(0.75);
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.05)) ); //pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.05)) );
K::ParticleFilterResamplingNEff<MyState>* res = new K::ParticleFilterResamplingNEff<MyState>(0.75, 0.05); // K::ParticleFilterResamplingNEff<MyState>* res = new K::ParticleFilterResamplingNEff<MyState>(0.75, 0.05);
pf->setNEffThreshold(1.0); // pf->setNEffThreshold(1.0);
pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingNEff<MyState>>(res) ); // pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingNEff<MyState>>(res) );
// move during resampling. NOT ALLOWED! // move during resampling. NOT ALLOWED!
// res->setDrawCallback([&] (K::Particle<MyState>& p) { // res->setDrawCallback([&] (K::Particle<MyState>& p) {
@@ -145,6 +160,211 @@ public:
} }
struct LeWalk {
std::string name;
float absHead;
std::string walkFile;
std::vector<int> gtIndices;
LeWalk(const std::string& name, float absHead, std::string walkFile, std::vector<int> gtIndices) :
name(name), absHead(absHead), walkFile(walkFile), gtIndices(gtIndices) {
;
}
};
struct LeModel {
std::string name;
WiFiModel* model;
LeModel(const std::string& name, WiFiModel* model) : name(name), model(model) {;}
};
static void serialize(const K::Statistics<float>& stats, const LeWalk& walk, const LeModel& model, const int idx) {
const std::string file = Settings::fPathGFX + "/walks/data/" + walk.name + "_" + model.name + "_" + std::to_string(idx) + ".txt";
std::ofstream out(file);
for (const float f : stats.getAll()) {
out << f << "\n";
}
out.close();
}
static K::Statistics<float>* deserialize(const LeWalk& walk, const LeModel& model, const int idx) {
const std::string file = Settings::fPathGFX + "/walks/data/" + walk.name + "_" + model.name + "_" + std::to_string(idx) + ".txt";
K::Statistics<float>* res = new K::Statistics<float>();
std::ifstream inp(file);
while(inp) {
float f;
inp >> f;
res->add(f);
}
return res;
}
static std::vector<LeWalk> allWalks() {
return {
LeWalk("path1a", M_PI/2, Settings::path1a, Settings::GroundTruth::path1),
LeWalk("path1b", M_PI/2, Settings::path1b, Settings::GroundTruth::path1),
LeWalk("toni-all-1a", M_PI/2, Settings::path_toni_all_1a, Settings::GroundTruth::path1),
LeWalk("toni-all-1b", M_PI/2, Settings::path_toni_all_1b, Settings::GroundTruth::path1),
LeWalk("path2a", 0, Settings::path2a, Settings::GroundTruth::path2),
LeWalk("path2b", 0, Settings::path2b, Settings::GroundTruth::path2),
LeWalk("toni-all-2a", M_PI/2, Settings::path_toni_all_2a, Settings::GroundTruth::path2),
LeWalk("toni-all-2b", M_PI/2, Settings::path_toni_all_2b, Settings::GroundTruth::path2),
/////////LeWalk("toni-inst-1a", M_PI/2, Settings::path_toni_inst_1a, Settings::GroundTruth::path_toni_inst_1),
LeWalk("toni-inst-1b", M_PI/2, Settings::path_toni_inst_1b, Settings::GroundTruth::path_toni_inst_1),
LeWalk("toni-inst-2a", M_PI/2, Settings::path_toni_inst_2a, Settings::GroundTruth::path_toni_inst_2),
LeWalk("toni-inst-2b", M_PI/2, Settings::path_toni_inst_2b, Settings::GroundTruth::path_toni_inst_2),
LeWalk("toni-inst-3a", M_PI/2, Settings::path_toni_inst_3a, Settings::GroundTruth::path_toni_inst_3),
LeWalk("toni-inst-3b", M_PI/2, Settings::path_toni_inst_3b, Settings::GroundTruth::path_toni_inst_3),
};
}
static std::vector<LeModel> allModels(Floorplan::IndoorMap* map) {
WiFiModelFactory fac(map);
return {
//LeModel("empiric", fac.loadXML(Settings::wifiAllFixed)),
//LeModel("opt 1", fac.loadXML(Settings::wifiAllOptPar)),
//LeModel("opt 2", fac.loadXML(Settings::wifiEachOptPar)),
//LeModel("opt 3", fac.loadXML(Settings::wifiEachOptParPos)),
//LeModel("per floor", fac.loadXML(Settings::wifiEachOptParPos_multimodel)),
LeModel("per bbox", fac.loadXML(Settings::wifiEachOptParPos_perBBox)),
};
}
static constexpr int numRepeats = 1;
/** create GFX for all previously walked parts */
static void walkEverythingBuildStats(Floorplan::IndoorMap* map) {
const std::vector<LeWalk> walks = allWalks();
const std::vector<LeModel> models = allModels(map);
PlotErrFunc* pefAll = new PlotErrFunc();
int numStuck = 0;
int numTotal = 0;
for (const LeModel& mdl : models) {
K::Statistics<float>* modelStatsAvg = new K::Statistics<float>();
K::Statistics<float>* modelStatsMed = new K::Statistics<float>();
K::Statistics<float>* modelStatsSingle = new K::Statistics<float>();
pefAll->add(mdl.name, modelStatsSingle);
// ... to perform every walk...
for (const LeWalk& walk : walks) {
for (int i = 0; i < numRepeats; ++i) {
++numTotal;
K::Statistics<float>* walkStats = deserialize(walk, mdl, i);
if (walkStats->getMedian() < 10) {
modelStatsSingle->add(*walkStats);
pefAll->plot();
} else {
++numStuck;
}
}
}
sleep(1);
}
std::cout << "stuck: " << numStuck << " (" << (numStuck*100/numTotal) << "%)" << std::endl;
sleep(100);
}
/** perform all walks and write them to file */
static void walkEverything(Floorplan::IndoorMap* map) {
const std::vector<LeWalk> walks = allWalks();
const std::vector<LeModel> models = allModels(map);
PlotErrFunc* pefAll = new PlotErrFunc();
// use every model ...
for (const LeModel& mdl : models) {
K::Statistics<float>* modelStatsSingle = new K::Statistics<float>();
pefAll->add(mdl.name, modelStatsSingle);
// ... to perform every walk...
for (const LeWalk& walk : walks) {
//K::Statistics<float> curWalkRepeatStatsAvg;
//K::Statistics<float> curWalkRepeatStatsMed;
// ... several times
for (int i = 0; i < numRepeats; ++i) {
EvalWalk ew(map);
ew.walkName = walk.name + " - " + mdl.name + " - " + std::to_string(i);
// get ground-truth
ew.absHead = walk.absHead;
ew.groundTruth = FloorplanHelper::getGroundTruth(map, walk.gtIndices);
// eval
std::unique_ptr<PFEval> eval = std::unique_ptr<PFEval>( new PFEval(ew.grid, *mdl.model, ew.em) );
ew.pf->setEvaluation( std::move(eval) );
// data-file
ew.reader.open(walk.walkFile);
ew.groundTruthLive = ew.reader.getGroundTruth(map, walk.gtIndices);
ew.player.setReader(&ew.reader);
ew.player.setListener(&ew);
ew.player.start();
// wait for completion
ew.player.join();
// write plots
ew.writeToFile();
// add every single error for each timestamp to the overall model error
modelStatsSingle->reset();
modelStatsSingle->add(ew.statsErr);
// export this walks's statistics
serialize(ew.statsErr, walk, mdl, i);
pefAll->plot();
}
// all repeats done
const std::string walkname = walk.name + " - " + mdl.name;
std::cout << "walk result for " << walkname << std::endl;
//std::cout << "\t" << curWalkRepeatStatsAvg.asString() << std::endl;
//std::cout << "\t" << curWalkRepeatStatsMed.asString() << std::endl;
std::cout << std::endl;
//sleep(1);
}
// all walks for one model done
std::cout << "MODEL RESULTS for " << mdl.name << std::endl;
//std::cout << "\t" << modelStatsAvg->asString() << std::endl;
//std::cout << "\t" << modelStatsMed->asString() << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << std::endl;
sleep(2);
}
}
void walk1() { void walk1() {
// path1 // path1
@@ -211,7 +431,7 @@ public:
++curCtrl.numStepsSinceLastTransition; ++curCtrl.numStepsSinceLastTransition;
} }
gotSensorData(ts); gotSensorData(ts);
curCtrl.activityNew = actDetect.add(ts, data); actDetect.add(ts, data);
} }
virtual void onGravity(const Timestamp ts, const GravityData data) override { virtual void onGravity(const Timestamp ts, const GravityData data) override {
@@ -219,14 +439,18 @@ public:
} }
virtual void onWiFi(const Timestamp ts, const WiFiMeasurements data) override { virtual void onWiFi(const Timestamp ts, const WiFiMeasurements data) override {
std::cout << "WIFI" << std::endl;
curObs.wifi = data; curObs.wifi = data;
//curObs.wifi = WiFiMeasurements::mix(curObs.wifi, data);
#ifdef PLOT_WIFI
plotWifi.add(Settings::WiFiModel::vg_eval.group(data)); plotWifi.add(Settings::WiFiModel::vg_eval.group(data));
plotWifi.plot(); plotWifi.plot();
#endif
} }
virtual void onBarometer(const Timestamp ts, const BarometerData data) override { virtual void onBarometer(const Timestamp ts, const BarometerData data) override {
; actDetect.add(ts, data);
curCtrl.activityNew = actDetect.get();
curObs.activityNew = actDetect.get();
} }
virtual void onGPS(const Timestamp ts, const GPSData data) override { virtual void onGPS(const Timestamp ts, const GPSData data) override {
@@ -300,12 +524,48 @@ private:
return set.size(); return set.size();
} }
void writeToFile() {
std::string path = Settings::fPathGFX;
std::string base = path + "/walks/" + "walk-" + walkName;
plotty.gp << "unset arrow 1\n";
plotty.gp << "unset arrow 2\n";
plotty.gp << "unset colorbox\n";
plotty.gp << "unset border\n";
plotty.gp << "set view equal xy\n";
plotty.splot.getView().setCamera(74,30);
plotty.splot.getView().setScaleAll(3.5);
plotty.splot.getAxisX().setTicsVisible(false);
plotty.splot.getAxisY().setTicsVisible(false);
plotty.splot.getAxisZ().setTicsVisible(false);
plotty.particles.clear();
plotty.gp.setTerminal("epslatex", K::GnuplotSize(8.6, 4.5));
plotty.gp.setOutput(base + "-map.tex");
plotty.writeCodeTo(base + "-map.gp");
plotty.plot();
pef.getPlot().getMargin().set(4, 0.2, 0.1, 2.0);
pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 3.0));
pef.getGP().setOutput(base + "-error-cum.tex");
pef.writePlotToFile(base + "-error-cum.gp");
pef.plot();
pet.getPlot().getMargin().set(4, 0.2, 0.1, 2.0);
pet.getGP().setTerminal("epslatex", K::GnuplotSize(8.6, 3.0));
pet.getGP().setOutput(base + "-error-time.tex");
pet.writePlotToFile(base + "-error-time.gp");
pet.plot();
}
/** perform a filter-update (called from a background-loop) */ /** perform a filter-update (called from a background-loop) */
void filterUpdate() { void filterUpdate() {
++updateCount; ++updateCount;
static PlotErrTime pet("\\small{time (sec)}", "\\small{error (m)}", "\\small{APs visible}");
static PlotErrFunc pef("\\small{error (m)}", "\\small{updates (\\%)}");
pef.showMarkers(true, true); pef.showMarkers(true, true);
std::cout << "update" << std::endl; std::cout << "update" << std::endl;
@@ -319,22 +579,23 @@ private:
const Point3 curGT = groundTruthLive.get(lastTransition); const Point3 curGT = groundTruthLive.get(lastTransition);
plotty.setCurEst(curEst.position.inMeter()); // start the error-over-time plot after some filter updates
plotty.setGroundTruth(curGT); if (updateCount > 12) {
if (updateCount > 4) {
// error between ground-truth and estimation // error between ground-truth and estimation
const float estRealErr = curEst.position.inMeter().getDistance(curGT); const float estRealErr = curEst.position.inMeter().getDistance(curGT);
statsErr.add(estRealErr); statsErr.add(estRealErr);
#ifdef PLOT_ERROR_FUNC
pef.clear(); pef.clear();
pef.add("", &statsErr); pef.add("", &statsErr);
pef.plot(); #endif
#ifdef PLOT_ERROR_TIME
// timed error // timed error
pet.addErr(lastTransition, estRealErr); pet.addErr(lastTransition, estRealErr);
pet.addB(lastTransition, getNumFHWSAPs(curObs.wifi)); pet.addB(lastTransition, getNumFHWSAPs(curObs.wifi));
pet.plot(); #endif
// update estimated path // update estimated path
const K::GnuplotPoint3 p3(curEst.position.x_cm, curEst.position.y_cm, curEst.position.z_cm); const K::GnuplotPoint3 p3(curEst.position.x_cm, curEst.position.y_cm, curEst.position.z_cm);
@@ -342,50 +603,73 @@ private:
} }
std::cout << statsErr.asString() << std::endl;
// show particles
float maxWeight = 0;
float minWeight = 99;
plotty.particles.clear();
for (const auto p : pf->getParticles()) {
const K::GnuplotPoint3 p3(p.state.position.x_cm, p.state.position.y_cm, p.state.position.z_cm);
plotty.particles.add(p3/100, p.weight);
if (p.weight > maxWeight) {maxWeight = p.weight;}
if (p.weight < minWeight) {minWeight = p.weight;}
}
plotty.gp << "set cbrange [" << minWeight << ":" << maxWeight << "] \n";
// show ground-truth
plotty.pathReal.clear();
for (const Point3 pt : groundTruth) {
plotty.pathReal.add(K::GnuplotPoint3(pt.x, pt.y, pt.z));
}
std::string title =
" time " + std::to_string(curObs.currentTime.sec()) +
" steps: " + std::to_string(ctrlCopy.numStepsSinceLastTransition) +
" turn: " + std::to_string(ctrlCopy.turnSinceLastTransition_rad) +
" APs: " + std::to_string(curObs.wifi.entries.size()) +
" Act: " + std::to_string((int)curCtrl.activityNew);
plotty.setTitle(title);
// relative heading and compass
{
Point2 cen(0.1, 0.9);
Point2 dir(std::cos(absHead), std::sin(absHead));
Point2 arr = cen + dir * 0.1;
plotty.gp << "set arrow 1 from screen " << cen.x << "," << cen.y << " to screen " << arr.x << "," << arr.y << "\n";
dir = Point2(std::cos(ctrlCopy.compassAzimuth_rad), std::sin(ctrlCopy.compassAzimuth_rad));
arr = cen + dir * 0.05;
plotty.gp << "set arrow 2 from screen " << cen.x << "," << cen.y << " to screen " << arr.x << "," << arr.y << "\n";
}
// plot // plot
plotty.plot(); static int cnt = 0;
if (++cnt % PLOT_UPDATE_STEP == 0) {
std::this_thread::sleep_for(std::chrono::milliseconds(5)); std::cout << statsErr.asString() << std::endl;
// estimation and ground-truth
plotty.setCurEst(curEst.position.inMeter());
plotty.setGroundTruth(curGT);
// show particles
float maxWeight = 0;
float minWeight = 99;
plotty.particles.clear();
for (int i = 0; i < pf->getParticles().size(); i += 10) {
const auto p = pf->getParticles()[i];
const K::GnuplotPoint3 p3(p.state.position.x_cm, p.state.position.y_cm, p.state.position.z_cm);
plotty.particles.add(p3/100, p.weight);
if (p.weight > maxWeight) {maxWeight = p.weight;}
if (p.weight < minWeight) {minWeight = p.weight;}
}
plotty.gp << "set cbrange [" << minWeight << ":" << maxWeight << "] \n";
// show ground-truth
plotty.pathReal.clear();
for (const Point3 pt : groundTruth) {
plotty.pathReal.add(K::GnuplotPoint3(pt.x, pt.y, pt.z));
}
std::string title =
" time " + std::to_string(curObs.currentTime.sec()) +
" steps: " + std::to_string(ctrlCopy.numStepsSinceLastTransition) +
" turn: " + std::to_string(ctrlCopy.turnSinceLastTransition_rad) +
" APs: " + std::to_string(curObs.wifi.entries.size()) +
" Act: " + std::to_string((int)curCtrl.activityNew) +
" " + walkName;
plotty.setTitle(title);
// relative heading and compass
{
Point2 cen(0.1, 0.9);
Point2 dir(std::cos(absHead), std::sin(absHead));
Point2 arr = cen + dir * 0.1;
plotty.gp << "set arrow 1 from screen " << cen.x << "," << cen.y << " to screen " << arr.x << "," << arr.y << "\n";
dir = Point2(std::cos(ctrlCopy.compassAzimuth_rad), std::sin(ctrlCopy.compassAzimuth_rad));
arr = cen + dir * 0.05;
plotty.gp << "set arrow 2 from screen " << cen.x << "," << cen.y << " to screen " << arr.x << "," << arr.y << "\n";
}
#ifdef PLOT_LIVE
plotty.plot();
#endif
#ifdef PLOT_ERROR_TIME
pet.plot();
#endif
#ifdef PLOT_ERROR_FUNC
pef.plot();
#endif
}
//std::this_thread::sleep_for(std::chrono::milliseconds(5));
curCtrl.resetAfterTransition(); curCtrl.resetAfterTransition();

98
pf/PF.h Normal file → Executable file
View File

@@ -98,7 +98,8 @@ struct MyObservation {
// TODO: switch to a general activity enum/detector for barometer + accelerometer + ...? // TODO: switch to a general activity enum/detector for barometer + accelerometer + ...?
/** detected activity */ /** detected activity */
ActivityButterPressure::Activity activity; //ActivityButterPressure::Activity activity;
Activity activityNew = Activity::STANDING;
/** time of evaluation */ /** time of evaluation */
Timestamp currentTime; Timestamp currentTime;
@@ -119,9 +120,9 @@ struct MyControl {
// TODO: switch to a general activity enum/detector using barometer + accelerometer? // TODO: switch to a general activity enum/detector using barometer + accelerometer?
/** currently detected activity */ /** currently detected activity */
ActivityButterPressure::Activity activity = ActivityButterPressure::Activity::STAY; //ActivityButterPressure::Activity activity = ActivityButterPressure::Activity::STAY;
Activity activityNew; Activity activityNew = Activity::STANDING;
/** reset the control-data after each transition */ /** reset the control-data after each transition */
void resetAfterTransition() { void resetAfterTransition() {
@@ -150,8 +151,10 @@ public:
std::uniform_real_distribution<float> distHead(0, 2*M_PI); std::uniform_real_distribution<float> distHead(0, 2*M_PI);
for (K::Particle<MyState>& p : particles) { for (K::Particle<MyState>& p : particles) {
const int idx = distIdx(gen); again:
const MyGridNode& node = (*grid)[idx]; const int idx = distIdx(gen);
const MyGridNode& node = (*grid)[idx];
if (node.getNumNeighbors() != 8) {goto again;}
p.state.position = node; // random position p.state.position = node; // random position
p.state.heading.direction = Heading(distHead(gen)); // random heading p.state.heading.direction = Heading(distHead(gen)); // random heading
p.weight = 1.0 / particles.size(); // equal weight p.weight = 1.0 / particles.size(); // equal weight
@@ -174,7 +177,7 @@ public:
WalkModuleFavorZ<MyGridNode, MyState> modFavorZ; WalkModuleFavorZ<MyGridNode, MyState> modFavorZ;
WalkModuleNodeImportance<MyGridNode, MyState> modImportance; WalkModuleNodeImportance<MyGridNode, MyState> modImportance;
WalkModuleFollowDestination<MyGridNode, MyState> modDestination; WalkModuleFollowDestination<MyGridNode, MyState> modDestination;
WalkModuleActivityControl<MyGridNode, MyState, MyControl> modActivity; //WalkModuleActivityControl<MyGridNode, MyState, MyControl> modActivity;
WalkModuleHeadingControl<MyGridNode, MyState, MyControl> modRelHead; WalkModuleHeadingControl<MyGridNode, MyState, MyControl> modRelHead;
WalkModuleAbsoluteHeadingControl<MyGridNode, MyState, MyControl> modAbsHead; WalkModuleAbsoluteHeadingControl<MyGridNode, MyState, MyControl> modAbsHead;
@@ -183,7 +186,11 @@ public:
public: public:
PFTrans(Grid<MyGridNode>* grid) : grid(grid), modRelHead(&ctrl, Settings::IMU::turnSigma), modAbsHead(&ctrl, Settings::IMU::absHeadSigma), modDestination(*grid), modActivity(&ctrl) { PFTrans(Grid<MyGridNode>* grid) : grid(grid), modRelHead(&ctrl, Settings::IMU::turnSigma),
modAbsHead(&ctrl, Settings::IMU::absHeadSigma),
modDestination(*grid)
//,modActivity(&ctrl)
{
walker.addModule(&modRelHead); walker.addModule(&modRelHead);
//walker.addModule(&modAbsHead); //walker.addModule(&modAbsHead);
@@ -234,10 +241,9 @@ public:
K::Particle<MyState>& p = particles[i]; K::Particle<MyState>& p = particles[i];
// first transitions: more variation as the state is unknown // first transitions: more variation as the state is unknown
if (numTrans < 50 || numTrans % 10 == 0) { if (numTrans < 70 || numTrans % (10*1) == 0) {
const MyGridNode* n = grid->getNodePtrFor(p.state.position); const MyGridNode* n = grid->getNodePtrFor(p.state.position);
std::normal_distribution<float> distTurn(0, 0.4);
for (int j = 0; j < 5; ++j) { for (int j = 0; j < 5; ++j) {
std::uniform_int_distribution<int> distIdx(0, n->getNumNeighbors()-1); std::uniform_int_distribution<int> distIdx(0, n->getNumNeighbors()-1);
@@ -246,9 +252,10 @@ public:
} }
p.state.position = *n; p.state.position = *n;
if (numTrans < 50) { if (numTrans < 70) {
p.state.heading.direction += distTurn(gen); std::normal_distribution<float> distTurn(0, 0.3);
dist_m += 0.5; p.state.heading.direction += distTurn(gen);
dist_m += 0.5;
} }
} }
@@ -264,6 +271,11 @@ public:
p.state = walker.getDestination(*grid, p.state, dist_m, prob); p.state = walker.getDestination(*grid, p.state, dist_m, prob);
p.weight *= prob; // grid-walk-probability p.weight *= prob; // grid-walk-probability
//const GridNode gn = grid->getNodeFor(p.state.position);
//const double probNode = (gn.getNumNeighbors() >= 8) ? (0.7) : (0.3);
//p.weight *= probNode;
if (p.weight != p.weight) { if (p.weight != p.weight) {
throw Exception("nan"); throw Exception("nan");
} }
@@ -320,14 +332,31 @@ public:
double res = 0; double res = 0;
if (angularDiff > Angle::degToRad(90)) {res = 0.05;} if (angularDiff > Angle::degToRad(120)) {res = 0.30;}
else if (angularDiff > Angle::degToRad(45)) {res = 0.25;} else {res = 0.70;}
else {res = 0.70;}
return res; return res;
} }
double getActivity(const MyState& s, const MyObservation& obs) {
const MyGridNode& n = grid->getNodeFor(s.position);
switch(obs.activityNew) {
case Activity::WALKING:
return (n.getType() != MyGridNode::TYPE_STAIR) ? (0.7) : (0.3);
case Activity::WALKING_DOWN:
case Activity::WALKING_UP:
return (n.getType() == MyGridNode::TYPE_STAIR) ? (0.7) : (0.3);
default:
return 1;
}
return 1.0;
}
WiFiQualityAnalyzer wqa; WiFiQualityAnalyzer wqa;
double evaluation(std::vector<K::Particle<MyState>>& particles, const MyObservation& _observation) override { double evaluation(std::vector<K::Particle<MyState>>& particles, const MyObservation& _observation) override {
@@ -343,7 +372,9 @@ public:
wqa.add(wifiObs); wqa.add(wifiObs);
const float quality = wqa.getQuality(); float quality = wqa.getQuality();
std::cout << "wifi quality: " << quality << std::endl;
// GPS // GPS
const GPSProbability gpsProb(em); const GPSProbability gpsProb(em);
@@ -353,7 +384,7 @@ public:
Assert::equal((int)particles.size(), Settings::numParticles, "number of particles does not match the settings!"); Assert::equal((int)particles.size(), Settings::numParticles, "number of particles does not match the settings!");
// use (0.9 * p) + (0.1 * (1-p)) for error cases // use (0.9 * p) + (0.1 * (1-p)) for error cases
wiFiProbability.setUseError(false); wiFiProbability.setUseError(true);
//#pragma omp parallel for num_threads(3) //#pragma omp parallel for num_threads(3)
for (int i = 0; i < Settings::numParticles; ++i) { for (int i = 0; i < Settings::numParticles; ++i) {
@@ -362,16 +393,15 @@ public:
// WiFi free // WiFi free
double pWiFi = wiFiProbability.getProbability(p.state.position.inMeter()+person, observation.currentTime, wifiObs); double pWiFi = wiFiProbability.getProbability(p.state.position.inMeter()+person, observation.currentTime, wifiObs);
double pWiFiMod = Distribution::Exponential<double>::getProbability(0.20, -std::log(pWiFi)); //double pWiFiMod = Distribution::Exponential<double>::getProbability(0.20, -std::log(pWiFi));
double pWiFiVeto = wiFiProbability.getVeto(p.state.position.inMeter()+person, observation.currentTime, wifiObs); //double pWiFiMod = std::pow(pWifi, 0.2);
//double pWiFiVeto = wiFiProbability.getVeto(p.state.position.inMeter()+person, observation.currentTime, wifiObs);
const bool volatile init = observation.currentTime.sec() < 25;
//double pWiFiMod = (init) ? (std::pow(pWiFi, 0.1)) : (std::pow(pWiFi, 0.5));
double pWiFiMod = (init) ? (std::pow(pWiFi, 0.5)) : (std::pow(pWiFi, 0.9));
if (quality < 0.2) {
pWiFi = 1;
pWiFiVeto = 1;
std::cout << "disabling WiFi" << std::endl;
}
// WiFi grid // WiFi grid
//const MyGridNode& node = grid->getNodeFor(p.state.position); //const MyGridNode& node = grid->getNodeFor(p.state.position);
@@ -379,9 +409,18 @@ public:
//const double pWiFi = wiFiProbability.getProbability(node, observation.currentTime, wifiObs); //const double pWiFi = wiFiProbability.getProbability(node, observation.currentTime, wifiObs);
//const double pStair = 1;//getStairProb(p, observation.activity); //const double pStair = 1;//getStairProb(p, observation.activity);
const double pGPS = gpsProb.getProbability(p.state.position.inMeter(), observation.gps); double pGPS = gpsProb.getProbability(p.state.position.inMeter(), observation.gps);
const double pAbsHead = getAbsHead(p.state, observation); double pAbsHead = getAbsHead(p.state, observation);
const double prob = pWiFi * pWiFiVeto;// * pAbsHead; double pActivty = getActivity(p.state, observation);
// bad wifi? -> we have no idea where we are!
if (quality < 0.25 && !init) {
pWiFiMod = 1;
//p.weight = std::pow(p.weight, 0.5);
}
// overall evaluation
const double prob = pWiFiMod * pAbsHead * pActivty;
//GPS ERROR?!?!?! does it work without disabling wifi when gps is disabled? //GPS ERROR?!?!?! does it work without disabling wifi when gps is disabled?
@@ -392,6 +431,11 @@ public:
// TESTING // TESTING
//p.weight = std::pow(p.weight, 0.5); //p.weight = std::pow(p.weight, 0.5);
// // do NOT update weights
// if (quality < 0.25) {
// p.weight = 1;
// }
p.weight *= prob; // NOTE: keeps the weight returned by the transition step! p.weight *= prob; // NOTE: keeps the weight returned by the transition step!
//p.weight = prob; // does NOT keep the weights returned by the transition step //p.weight = prob; // does NOT keep the weights returned by the transition step

5
plots/PlotErrFunc.h Normal file → Executable file
View File

@@ -49,6 +49,11 @@ class PlotErrFunc {
public: public:
/** empty ctor */
PlotErrFunc() {
setYRange(0, 90, 5);
}
/** ctor with x-axis label */ /** ctor with x-axis label */
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) { PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
gplot.getAxisX().setLabel(xLabel); gplot.getAxisX().setLabel(xLabel);

14
plots/PlotErrTime.h Normal file → Executable file
View File

@@ -23,6 +23,11 @@ private:
public: public:
/** empty ctor */
PlotErrTime() {
}
/** ctor */ /** ctor */
PlotErrTime(const std::string& xLabel, const std::string& yLabel, const std::string& y2Label) { PlotErrTime(const std::string& xLabel, const std::string& yLabel, const std::string& y2Label) {
@@ -41,6 +46,15 @@ public:
} }
K::Gnuplot& getGP() {
return gp;
}
/** write the gnuplot commands to file for later re-use */
void writePlotToFile(const std::string& file) {
this->gp.writePlotToFile(file);
}
void clear() { void clear() {
for (int i = 0; i < 8; ++i) {lineErr[i].clear();} for (int i = 0; i < 8; ++i) {lineErr[i].clear();}
lineB.clear(); lineB.clear();

24
plots/PlotWiFiGroundProb.h Normal file → Executable file
View File

@@ -67,16 +67,13 @@ public:
} }
/** plot the ground-probability for the given measurement */ /** plot the ground-probability for the given measurement */
void show(const WiFiObserverFree& prob, const WiFiMeasurements& _mes) { void show(const WiFiObserverFree& prob, const WiFiMeasurements& mes, const Timestamp ts) {
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
const WiFiMeasurements mes = vap.group(_mes);
// determine min/max probability // determine min/max probability
double min = +99999; double min = +99999;
double max = -99999; double max = -99999;
for (Entry& e : pos) { for (Entry& e : pos) {
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes); const double p = prob.getProbability(e.pos, ts, mes);
if (p < min) {min = p;} if (p < min) {min = p;}
if (p > max) {max = p;} if (p > max) {max = p;}
} }
@@ -84,8 +81,11 @@ public:
// render // render
for (Entry& e : pos) { for (Entry& e : pos) {
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes); const double p = prob.getProbability(e.pos, ts, mes);
const double f = (p-min) / diff * 255; double f = (p-min) / diff * 255;
if (f < 0) {f = 0;}
if (f > 255) {f = 255;}
e.sum += p; e.sum += p;
e.cnt++; e.cnt++;
@@ -93,10 +93,14 @@ public:
const K::GnuplotColor c = K::GnuplotColor::fromHSV(0, f, 255); const K::GnuplotColor c = K::GnuplotColor::fromHSV(0, f, 255);
e.poly->getFill().setColor(c); e.poly->getFill().setColor(c);
e.max = f; e.max = f;
e.poly->setEnabled(f > 32);
//} //}
if (f < 0.1) { // if (f < 32) {
e.poly->setEnabled(false); // e.poly->setEnabled(false);
} // } else {
// e.poly->setEnabled(true);
// }
//plot.cpoints.add(K::GnuplotPoint3(pt.x, pt.y, pt.z), p); //plot.cpoints.add(K::GnuplotPoint3(pt.x, pt.y, pt.z), p);
} }

0
plots/Plotty.h Normal file → Executable file
View File

2
tex/bare_conf.tex Normal file → Executable file
View File

@@ -81,6 +81,8 @@
%\usepackage{ulem} %\usepackage{ulem}
%\setcounter{figure}{0}
%\renewcommand{\thefigure}{A\arabic{section}.\arabic{figure}}
% replacement for the SI package % replacement for the SI package

0
tex/chapters/abstract.tex Normal file → Executable file
View File

0
tex/chapters/conclusion.tex Normal file → Executable file
View File

97
tex/chapters/experiments.tex Normal file → Executable file
View File

@@ -41,13 +41,13 @@
\centering \centering
\input{gfx/all_fingerprints.tex} \input{gfx/all_fingerprints.tex}
} }
\label{fig:referenceMeasurements}
\caption{ \caption{
Locations of the 121 reference measurements. Locations of the 121 reference measurements.
The size of each square denotes the number of permanently installed \docAPshort{}s The size of each square denotes the number of permanently installed \docAPshort{}s
that are visible at this location, that are visible at this location,
and ranges between 2 and 22 with an average of 9. and ranges between 2 and 22 with an average of 9.
} }
\label{fig:referenceMeasurements}
\end{figure} \end{figure}
% visible APs: % visible APs:
@@ -56,12 +56,12 @@
\begin{figure}[b] \begin{figure}[b]
\centering \centering
\input{gfx/compare-wifi-in-out.tex} \input{gfx/compare-wifi-in-out.tex}
\label{fig:wifiIndoorOutdoor}
\caption{ \caption{
Measurable signal strengths of a testing \docAPshort{} (black dot). Measurable signal strengths of a testing \docAPshort{} (black dot).
While the signal diminishes slowly along the corridor (upper rectangle) 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). the metallised windows (dashed outline) attenuate the signal by over \SI{30}{\decibel} (lower rectangle).
} }
\label{fig:wifiIndoorOutdoor}
\end{figure} \end{figure}
Figure \ref{fig:wifiIndoorOutdoor} depicts the to-be-expected issues by examining the signal strength Figure \ref{fig:wifiIndoorOutdoor} depicts the to-be-expected issues by examining the signal strength
@@ -105,11 +105,11 @@
\begin{figure} \begin{figure}
\input{gfx/wifi_model_error_0_95.tex} \input{gfx/wifi_model_error_0_95.tex}
%\input{gfx/wifi_model_error_95_100.tex} %\input{gfx/wifi_model_error_95_100.tex}
\label{fig:wifiModelError}
\caption{ \caption{
Comparison between different optimization strategies by examining the error (in \decibel) at each reference measurement. 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. The higher the number of variable parameters, the better the model resembles real world conditions.
} }
\label{fig:wifiModelError}
\end{figure} \end{figure}
% statds: % statds:
@@ -135,30 +135,77 @@
As we try to minimize the system's setup time as much as possible, we need to determine As we try to minimize the system's setup time as much as possible, we need to determine
the amount of necessary reference measurements for the optimization to produce viable model parameters. the amount of necessary reference measurements for the optimization to produce viable model parameters.
Depending on the number of to-be-optimized model parameters, more measurements are required. Depending on the chosen model and thus the number of to-be-optimized parameters, more measurements are required.
This especially holds true for {\em \optPerRegion{}} where each region needs at least some measurements
to determine transmitter positions and parameters. While there was almost no difference between using 121 or 30 reference measurements for
{\em \optParamsAllAP{}} and {\em \optParamsEachAP{}}
(average \SIrange{5.3}{5.4}{\decibel} and \SIrange{4.5}{5.0}{\decibel}),
{\em \optPerRegion{}} is highly affected
(average \SIrange{2.0}{6.2}{\decibel}), as it needs at least a certain number of measurements for each
of its regions for the optimization to converge.
\begin{figure}[b] \begin{figure}[b]
\input{gfx/wifi_model_error_num_fingerprints_method_5_0_90.tex} \input{gfx/wifi_model_error_num_fingerprints_method_5_0_90.tex}
\input{gfx/wifi_model_error_num_fingerprints_method_5_90_100.tex} \input{gfx/wifi_model_error_num_fingerprints_method_5_90_100.tex}
\label{fig:wifiNumFingerprints}%
\caption{% \caption{%
number of fingerprints Impact of reducing the number of reference measurements during optimization on {\em \optPerRegion{}}.
The model's cumulative error distribution is determined by comparing the its signal strength prediction against all 121 measurements.
While using only \SI{50}{\percent} of the 121 scans has barely an impact on the error,
30 measurements (\SI{25}{\percent}) are clearly insufficient.
}% }%
\label{fig:wifiNumFingerprints}%
\end{figure} \end{figure}
Figure \ref{fig:wifiNumFingerprints} depicts the impact of reducing the number of fingerprints Figure \ref{fig:wifiNumFingerprints} depicts the impact of reducing the number of reference measurements
for the {\em \optPerRegion{}} strategy. Only using 60 of the 121 fingerprints yields only a slightly during the optimization process for the {\em \optPerRegion{}} strategy.
increasing model error and still provides good results. While using only \SI{25}{\percent} of the reference The error is determined by using the (absolute) difference between expected signal strength and
measurements increases the error rapidly, \SI{75}{\percent} of all considered errors are still better the optimized model's corresponding prediction for all of the 121 reference measurements.
than using just empiric values without any reference measurements. %
Considering only 60 of the 121 scans (\SI{50}{\percent}) yields a slightly increasing model error and still provides good results.
While using only \SI{25}{\percent} of the reference measurements increases the error rapidly,
for \SI{75}{\percent} of the 121 considered cases the estimation is still better than using just empiric values without optimization.
The extremely large outlier depicted in the lower half of figure \ref{fig:wifiNumFingerprints} (red line) relates to one
sub-model with only one assigned reference measurement, where the optimized result is unable to predict values
for the rest of the sub-model's region. \todo{versteht man das?}
Additionally we examined the impact of skipping reference measurements for difficult locations Additionally we examined the impact of skipping reference measurements for difficult locations
like aforementioned staircases, surrounded by concrete. While this slightly decreases the like staircases, surrounded by steel-enforced concrete. While this slightly decreases the
estimation error for all other positions, the error within those locations is dramatically estimation error for all other positions (hallway, etc) as expected, the error within the skipped locations is dramatically
increasing (see lower half of figure \ref{fig:wifiNumFingerprints}). It is thus highly recommended increasing (see lower half of figure \ref{fig:wifiNumFingerprints}). It is thus highly recommended
to include such locations. to also perform reference measurements for locations, that are expected to strongly deviate (signal strength)
from their surroundings.
%leaving out fingerprints for model 1
% 25%: cnt(1128) min(0.007439) max(27.804710) range(27.797272) med(4.404236) avg(5.449720) stdDev(4.470373)
% 50%: cnt(1128) min(0.006027) max(27.732193) range(27.726166) med(4.367859) avg(5.437861) stdDev(4.475426)
% 100%: cnt(1128) min(0.000282) max(27.705376) range(27.705093) med(4.272881) avg(5.411202) stdDev(4.493495)
% noStair%: cnt(1128) min(0.000801) max(27.209221) range(27.208420) med(4.333328) avg(5.459918) stdDev(4.459484)
%leaving out fingerprints for model 2
% 25%: cnt(1128) min(0.000320) max(29.752560) range(29.752239) med(3.837357) avg(5.027578) stdDev(4.617191)
% 50%: cnt(1128) min(0.015305) max(34.152130) range(34.136826) med(3.627090) avg(4.635868) stdDev(4.135866)
% 100%: cnt(1128) min(0.000488) max(25.687740) range(25.687252) med(3.319756) avg(4.441193) stdDev(3.912525)
% noStair%: cnt(1128) min(0.017693) max(25.687740) range(25.670048) med(3.304321) avg(4.507620) stdDev(3.957071)
%leaving out fingerprints for model 3
% 25%: cnt(1128) min(0.003242) max(39.470978) range(39.467735) med(3.371758) avg(4.977330) stdDev(5.213937)
% 50%: cnt(1128) min(0.002808) max(30.113415) range(30.110607) med(2.941238) avg(4.015042) stdDev(3.696969)
% 100%: cnt(1128) min(0.000557) max(16.813850) range(16.813293) med(3.056915) avg(3.813013) stdDev(3.062580)
% noStair%: cnt(1128) min(0.002518) max(30.370636) range(30.368118) med(3.016884) avg(3.983101) stdDev(3.508327)
%leaving out fingerprints for model 4
% 25%: cnt(1128) min(0.000000) max(62.233345) range(62.233345) med(2.502831) avg(5.432897) stdDev(8.664582)
% 50%: cnt(1128) min(0.000000) max(56.843803) range(56.843803) med(1.543137) avg(2.937506) stdDev(4.417061)
% 100%: cnt(1128) min(0.000046) max(33.175812) range(33.175766) med(1.537933) avg(2.441976) stdDev(2.793499)
% noStair%: cnt(1128) min(0.000000) max(62.233345) range(62.233345) med(1.493668) avg(2.744918) stdDev(4.428092)
%leaving out fingerprints for model 5
% 25%: cnt(1128) min(0.000000) max(62.620842) range(62.620842) med(2.140709) avg(6.257105) stdDev(11.638572)
% 50%: cnt(1128) min(0.000000) max(57.371948) range(57.371948) med(1.357452) avg(2.982217) stdDev(5.877471)
% 100%: cnt(1128) min(0.000000) max(14.837151) range(14.837151) med(1.251358) avg(1.989277) stdDev(2.189072)
% noStair%: cnt(1128) min(0.000000) max(62.233345) range(62.233345) med(1.143669) avg(2.316189) stdDev(4.164822)
@@ -198,8 +245,8 @@
at location $\mPosVec$ returned from the to-be-examined prediction model. at location $\mPosVec$ returned from the to-be-examined prediction model.
For all comparisons we use a constant uncertainty $\sigma = $\SI{8}{\decibel}. For all comparisons we use a constant uncertainty $\sigma = $\SI{8}{\decibel}.
The quality of the estimated location is determined by comparing the estimation The quality of the estimated location is determined by using the Euclidean distance between estimation
$\mPosVec^*$ with the pedestrian's ground truth position at the time the scan $\mRssiVec$ $\mPosVec^*$ and the pedestrian's ground truth position at the time the scan $\mRssiVec$
has been received. has been received.
@@ -226,18 +273,20 @@
\begin{figure}[b] \begin{figure}[b]
\input{gfx/modelPerformance_meter.tex} \input{gfx/modelPerformance_meter.tex}
\label{fig:modelPerformance}
\caption{ \caption{
Error between ground truth and estimation using \refeq{eq:bestWiFiPos} depending Error between ground truth and estimation using \refeq{eq:bestWiFiPos} depending
on the underlying signal strength prediction model on the underlying signal strength prediction model.
Extremely high errors between the \SIrange{90}{100}{\percent} quartile are related to bad \docWIFI{}
coverage within outdoor areas (see figure \ref{fig:wifiIndoorOutdoor}).
} }
\label{fig:modelPerformance}
\end{figure} \end{figure}
%To estimate the overall performance of the prediction models, we compare the position estimation %To estimate the overall performance of the prediction models, we compare the position estimation
%for each \docWIFI{} measurement within the recorded paths (3756 \docAPshort{} scans in total) %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. %against the corresponding ground-truth, which indicates the absolute 3D error in meter.
The position estimation for each \docWIFI{} measurement within the recorded walks (3756 \docAPshort{} scans in total) The position estimation for each \docWIFI{} measurement within the recorded walks (3756 scans in total)
is compared against its corresponding ground-truth, indicating the absolute 3D error. is compared against its corresponding ground-truth, indicating the 3D error.
The resulting cumulative error distribution can be seen in figure \ref{fig:modelPerformance}. The resulting cumulative error distribution 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. The quality of the location estimation directly scales with the quality of the signal strength prediction model.
However, as discussed earlier, the maximal estimation error might increase for some setups. However, as discussed earlier, the maximal estimation error might increase for some setups.
@@ -252,13 +301,13 @@
\begin{figure}[t] \begin{figure}[t]
\input{gfx/wifiMultimodality.tex} \input{gfx/wifiMultimodality.tex}
\label{fig:wifiMultimodality}
\caption{ \caption{
Location probability \refeq{eq:bestWiFiPos} for three scans. Higher color intensities are more likely. 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). Ideally, places near the ground truth (black) are highly highly probable (green).
Often, other locations are just as likely as the ground truth (blue), 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). or the location with the highest probability does not match at all (red).
} }
\label{fig:wifiMultimodality}
\end{figure} \end{figure}
Figure \ref{fig:wifiMultimodality} depicts aforementioned issues of multimodal (blue) or wrong (red) location Figure \ref{fig:wifiMultimodality} depicts aforementioned issues of multimodal (blue) or wrong (red) location
@@ -318,13 +367,13 @@
\begin{figure} \begin{figure}
\input{gfx/wifiCompare_normalVsExp_cross.tex} \input{gfx/wifiCompare_normalVsExp_cross.tex}
\input{gfx/wifiCompare_normalVsExp_meter.tex} \input{gfx/wifiCompare_normalVsExp_meter.tex}
\label{fig:normalVsExponential}
\caption{ \caption{
Comparison between normal- (black) and exponential-distribution (red) for \refeq{eq:wifiProb}. Comparison between normal- (black) and exponential-distribution (red) for \refeq{eq:wifiProb}.
While misclassifications are slightly reduced (upper chart), While misclassifications are slightly reduced (upper chart),
the median error between ground-truth and estimation (lower chart) increases by the median error between ground-truth and estimation (lower chart) increases by
about \SI{1}{\meter}. about \SI{1}{\meter}.
} }
\label{fig:normalVsExponential}
\end{figure} \end{figure}

0
tex/chapters/interoduction.tex Normal file → Executable file
View File

0
tex/chapters/introduction.tex Normal file → Executable file
View File

0
tex/chapters/relatedwork.tex Normal file → Executable file
View File

0
tex/chapters/system.tex Normal file → Executable file
View File

12
tex/chapters/work.tex Normal file → Executable file
View File

@@ -100,12 +100,12 @@
\begin{figure}[t!] \begin{figure}[t!]
\input{gfx/wifiop_show_optfunc_params} \input{gfx/wifiop_show_optfunc_params}
\label{fig:wifiOptFuncTXPEXP}
\caption{ \caption{
The average error (in \SI{}{\decibel}) between all reference measurements and corresponding model predictions The average error (in \SI{}{\decibel}) between all reference measurements and corresponding model predictions
for one \docAPshort{} dependent on \docTXP{} \mTXP{} and \docEXP{} \mPLE{} for one \docAPshort{} dependent on \docTXP{} \mTXP{} and \docEXP{} \mPLE{}
[known position $\mPosAPVec{}$, fixed \mWAF{}] denotes a convex function. [known position $\mPosAPVec{}$, fixed \mWAF{}] denotes a convex function.
} }
\label{fig:wifiOptFuncTXPEXP}
\end{figure} \end{figure}
For systems that demand a higher accuracy, one can choose a compromise between fingerprinting and For systems that demand a higher accuracy, one can choose a compromise between fingerprinting and
@@ -138,12 +138,12 @@
\begin{figure}[t!] \begin{figure}[t!]
\input{gfx/wifiop_show_optfunc_pos_yz} \input{gfx/wifiop_show_optfunc_pos_yz}
\label{fig:wifiOptFuncPosYZ}
\caption{ \caption{
The average error (in \SI{}{\decibel}) between reference measurements and model predictions 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{}] 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. usually denotes a non-convex function with multiple [here: two] local minima.
} }
\label{fig:wifiOptFuncPosYZ}
\end{figure} \end{figure}
Such functions demand for optimization algorithms, that are able to deal with non-convex functions, Such functions demand for optimization algorithms, that are able to deal with non-convex functions,
@@ -186,6 +186,9 @@
axis-aligned bounding box. This approach allows a distinction between in- and outdoor-regions axis-aligned bounding box. This approach allows a distinction between in- and outdoor-regions
or locations that are expected to highly differ from their surroundings. or locations that are expected to highly differ from their surroundings.
\todo{AP wird in einer region nur dann beruecksichtigt, wenn mindestanzahl an messungen vorhanden ist!}
\todo{das heißt aber, dass an unterschiedlichen stellen unterschiedlich viele APs verglichen werden. das geht ned. deshalb feste -100}
\subsection{\docWIFI{} quality factor} \subsection{\docWIFI{} quality factor}
@@ -244,7 +247,10 @@
a very small delay (micro- to milliseconds). Such measurements may be grouped using some aggregate a very small delay (micro- to milliseconds). Such measurements may be grouped using some aggregate
function like average, median or maximum. function like average, median or maximum.
Furthermore, VAP grouping can be used to suppress unlikely observations: If a physical hardware is known
to provide six virtual networks, it is unlikely to only see one of those networks. This is likely due to
temporal effects and/or multipath signal propagation and the received signal strength will often be far from
the normal average. It thus makes sense to just omit such unlikely observations, focusing on the remaining, stable ones.

0
tex/egbib.bib Normal file → Executable file
View File

2
tex/gfx/build.sh Normal file → Executable file
View File

@@ -1,4 +1,4 @@
for file in *.gp for file in *.gp
do do
gnuplot $file; gnuplot "$file";
done done

0
tex/make.sh Normal file → Executable file
View File

0
tex/misc/functions.tex Normal file → Executable file
View File

0
tex/misc/keywords.tex Normal file → Executable file
View File

0
wifi/EvalWiFi.h Normal file → Executable file
View File

0
wifi/EvalWiFiConvex.h Normal file → Executable file
View File

71
wifi/EvalWiFiGround.h Normal file → Executable file
View File

@@ -30,6 +30,7 @@
#include "../plots/PlotErrTime.h" #include "../plots/PlotErrTime.h"
#include "../plots/PlotErrFunc.h" #include "../plots/PlotErrFunc.h"
#include "../plots/PlotWiFiGroundProb.h" #include "../plots/PlotWiFiGroundProb.h"
#include <Indoor/debug/PlotWifiMeasurements.h>
//#include "../CSV.h" //#include "../CSV.h"
#include <unordered_set> #include <unordered_set>
@@ -46,6 +47,7 @@ private:
public: public:
PlotWiFiGroundProb* groundProb; PlotWiFiGroundProb* groundProb;
PlotWifiMeasurements plotWifi;
public: public:
@@ -55,25 +57,84 @@ public:
obs = new WiFiObserverFree(8.0, *mdl); obs = new WiFiObserverFree(8.0, *mdl);
groundProb = new PlotWiFiGroundProb(map, settings); groundProb = new PlotWiFiGroundProb(map, settings);
// must be 34
std::cout << "Model APs: " << mdl->getAllAPs().size() << std::endl;
int i = 0; (void) i;
} }
void show(const std::string walkFile, const int idx = -1) { void show(const std::string walkFile, const std::vector<int> gtIndices) {
Offline::FileReader reader(walkFile); Offline::FileReader reader(walkFile);
Offline::FileReader::GroundTruth gt = reader.getGroundTruth(map, gtIndices);
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
int cnt = 0; int cnt = 0;
for (const auto& entry : reader.getWiFiGroupedByTime()) { WiFiMeasurements mes;
const WiFiMeasurements& mes = entry.data;
groundProb->show(*obs, mes); //std::vector<int> indices = {260, 270,271,272, 280};
//std::vector<int> indices = {270,271,272};
for (size_t i = 0; i < reader.getWiFiGroupedByTime().size(); ++i) {
//for (int i : indices) {
//mal nur zeigen welche regionen aus sicht von D8:84:66:4A:4B:C0 wahrscheinlich sind
//beim VAP grouping mitzählen wieviele APs contributen.. wenns nur einer ist, dann vlt lieber löschen???
const auto& entry = reader.getWiFiGroupedByTime()[i];
const WiFiMeasurements& _newMes = entry.data;
std::cout << _newMes.asString() << std::endl;
WiFiMeasurements newMes = vap.group(_newMes);
//newMes.remove(MACAddress("D8:84:66:4A:4B:C0"));
// WiFiMeasurement leap = *(newMes.getForMac(MACAddress("D8:84:66:4A:4B:C0")));
// newMes.entries.clear();
// newMes.entries.push_back(leap);
//std::cout << newMes.entries.front().getAP().getMAC().asString() << ":" << newMes.entries.front().getRSSI() << std::endl;
//newMes.entries.erase(newMes.entries.begin());
// MACAddress mac("D8:84:66:4A:4B:C0");
// const WiFiMeasurement* xxx = newMes.getForMac(mac);
// if (xxx) {
// std::cout << xxx->getRSSI() << std::endl;
// } else {
// std::cout << "MISSING" << std::endl;
// }
// mes = WiFiMeasurements::mix(mes, newMes, 2);
mes = newMes;
plotWifi.add(newMes);
plotWifi.plot();
Point3 p3 = gt.get(mes.entries.front().getTimestamp());
K::GnuplotPoint3 gp3(p3.x, p3.y, p3.z);
groundProb->getPlot().cpoints.clear();
groundProb->getPlot().points.add(gp3);
const Timestamp ts = newMes.entries.front().getTimestamp();
groundProb->show(*obs, mes, ts);
groundProb->plotMe(); groundProb->plotMe();
//if (++cnt > 70) {break;} //if (++cnt > 70) {break;}
std::this_thread::sleep_for(std::chrono::milliseconds(2)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
//groundProb->update(); //groundProb->update();
groundProb->plotMe(); groundProb->plotMe();
int i = 0; (void) i; int i = 0; (void) i;
sleep(1000);
} }
void add(const std::string walkFile, const int idx, const float hue) { void add(const std::string walkFile, const int idx, const float hue) {

48
wifi/EvalWiFiPathMethods.h Normal file → Executable file
View File

@@ -242,7 +242,7 @@ public:
// error calculation // error calculation
auto funcOrig = [&] (const float* params) -> double { return errFuncOrig(params, mes); }; auto funcOrig = [&] (const float* params) -> double { return errFuncOrig(params, mes); };
auto funcOther = [&] (const float* params) -> double { return errFuncOther(params, mes); }; auto funcOther = [&] (const float* params) -> double { return errFuncSingleProb(params, mes); }; // ADJUST HERE
// parameters (x,y,z); // parameters (x,y,z);
float paramsOrig[3] = {0,0,0}; float paramsOrig[3] = {0,0,0};
@@ -536,6 +536,52 @@ private:
} }
/** TESTING */
double errFuncSingleProb(const float* params, const WiFiMeasurements& mes) {
// crop z to 1 meter
//params[2] = std::round(params[2]);
// suggested position
const Point3 pos_m(params[0], params[1], params[2]);
int cnt = 0;
double error = 0;
//const auto comp = [] (const WiFiMeasurement& m1, const WiFiMeasurement& m2) {return m1.getRSSI() < m2.getRSSI();};
//const auto& min = std::min_element(mes.entries.begin(), mes.entries.end(), comp);
// calculate error for above position using the currently available measurements
for (const WiFiMeasurement& m : mes.entries) {
// skip non-FHWS APs
if (!LeHelper::isFHWS_AP(m.getAP().getMAC())) {continue;}
// get model's rssi for the given location
const float rssi_model = wiModel->getRSSI(m.getAP().getMAC(), pos_m);
// skip APs unknown to the model
if (rssi_model != rssi_model) {
std::cout << "unknown ap: " << m.getAP().getMAC().asString() << std::endl;
continue;
}
// get scan's rssi
const float rssi_scan = m.getRSSI();
++cnt;
error += std::pow(std::abs(rssi_scan - rssi_model),2);
}
if (cnt == 0) {return 1e-50;}
double errorAvg = std::pow((error / cnt), 1.0/2.0);
double prob = Distribution::Normal<double>::getProbability(0, 4, errorAvg);
const double err = -prob;
return err;
}
double getVeto(const Point3& pos_m, const WiFiMeasurements& obs) const { double getVeto(const Point3& pos_m, const WiFiMeasurements& obs) const {

4
wifi/EvalWiFiPaths.h Normal file → Executable file
View File

@@ -95,7 +95,9 @@ public:
pef.getPlot().getKey().setPosition(K::GnuplotKey::Hor::RIGHT, K::GnuplotKey::Ver::BOTTOM); pef.getPlot().getKey().setPosition(K::GnuplotKey::Hor::RIGHT, K::GnuplotKey::Ver::BOTTOM);
pef.getPlot().getKey().setWidthIncrement(7); pef.getPlot().getKey().setWidthIncrement(7);
pef.getPlot().getAxisY().setLabelOffset(2.5, 0); pef.getPlot().getAxisY().setLabelOffset(2.5, 0);
pef.getPlot().getAxisY().setTicsStep(0, 25, 95); //pef.getPlot().getAxisY().setTicsStep(0, 25, 95);
pef.getPlot().getAxisY().setTicsStep({0, 25, 50, 75, 95});
pef.getPlot().getAxisX().setTicsLabelFormat("%h m"); // CHECK!
// MANUAL AXIS RANGE SETTINGS // MANUAL AXIS RANGE SETTINGS
pef.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0,25)); pef.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0,25));