current code and TeX. code fine?!?!?!
This commit is contained in:
@@ -58,7 +58,7 @@ ADD_DEFINITIONS(
|
||||
-fstack-protector-all
|
||||
|
||||
-g3
|
||||
-O0
|
||||
-O2
|
||||
-march=native
|
||||
|
||||
-DWITH_TESTS
|
||||
|
||||
0
EvalApOpt.h
Normal file → Executable file
0
EvalApOpt.h
Normal file → Executable file
0
EvalCompareOpt.h
Normal file → Executable file
0
EvalCompareOpt.h
Normal file → Executable file
9
EvalCompareOpt2.h
Normal file → Executable file
9
EvalCompareOpt2.h
Normal file → Executable file
@@ -317,6 +317,15 @@ public:
|
||||
const MACAddress mac(ap->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
|
||||
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
|
||||
|
||||
0
EvalData.h
Normal file → Executable file
0
EvalData.h
Normal file → Executable file
0
EvalWiFiSigStrength.h
Normal file → Executable file
0
EvalWiFiSigStrength.h
Normal file → Executable file
0
EvalWifiOptResult.h
Normal file → Executable file
0
EvalWifiOptResult.h
Normal file → Executable file
19
Settings.h
Normal file → Executable file
19
Settings.h
Normal file → Executable file
@@ -6,10 +6,11 @@
|
||||
|
||||
namespace Settings {
|
||||
|
||||
const std::string pathData = "/apps/android/workspace/OTHER2017/data/";
|
||||
const std::string pathWalks = "/apps/android/workspace/OTHER2017/data/";
|
||||
const std::string pathWalksToni = "/apps/android/workspace/OTHER2017/data/toni/";
|
||||
const std::string pathWiFi = "/apps/android/workspace/OTHER2017/data/wifi/";
|
||||
const std::string pathbase = "/mnt/vm/paper/OTHER2017/";
|
||||
const std::string pathData = pathbase + "/data/";
|
||||
const std::string pathWalks = pathbase + "/data/";
|
||||
const std::string pathWalksToni = pathbase + "/data/toni/";
|
||||
const std::string pathWiFi = pathbase + "/data/wifi/";
|
||||
|
||||
// GPS walks
|
||||
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 fMap = "/apps/android/workspace/IndoorMap/maps/SHL38_no_elev.xml";
|
||||
const std::string fCalib = "/apps/android/workspace/OTHER2017/data/wifi_fp_all.dat";
|
||||
const std::string fMap = pathbase + "/data/SHL38_no_elev.xml";
|
||||
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;
|
||||
|
||||
namespace IMU {
|
||||
const float turnSigma = 1.25;//1.5;
|
||||
const float stepLength = 0.70+0.3;
|
||||
const float stepSigma = 0.10;
|
||||
const float stepSigma = 0.15 + 0.10;
|
||||
const float absHeadSigma = 20;
|
||||
}
|
||||
|
||||
|
||||
0
TestMapEarthReg.h
Normal file → Executable file
0
TestMapEarthReg.h
Normal file → Executable file
231
main.cpp
Normal file → Executable file
231
main.cpp
Normal file → Executable file
@@ -248,7 +248,7 @@ void errorPlotAllModels(Floorplan::IndoorMap* map) {
|
||||
|
||||
std::vector<K::Statistics<float>> errors = errorStatAllModels(map);
|
||||
|
||||
PlotErrFunc plot("", "fingerprints (%)");
|
||||
PlotErrFunc plot("", "reference measurements (%)");
|
||||
plot.getPlot().getAxisX().setTicsLabelFormat("%h dB");
|
||||
plot.add("\\noOptEmpiric{}", &errors[0]);
|
||||
plot.add("\\optParamsAllAP{}", &errors[1]);
|
||||
@@ -275,14 +275,15 @@ void errorPlotAllModels(Floorplan::IndoorMap* map) {
|
||||
// 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().getAxisY().setLabelOffset(3.0 - 0.75, 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.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 95));
|
||||
//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.getPlot().getAxisX().setTicsStep(4); // 4dB
|
||||
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 */
|
||||
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().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 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().getAxisY().setLabelOffset(3.0 - 0.7,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.getPlot().getAxisY().setRange(K::GnuplotAxis::Range(0, 90));
|
||||
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.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.writePlotToFile(Settings::fPathGFX + "/" + name + "_0_90.gp");
|
||||
plot.plot();
|
||||
|
||||
// changes
|
||||
plot.getPlot().getKey().setVisible(false);
|
||||
plot.getPlot().getAxisY().setLabel("");
|
||||
|
||||
plot.setYRange(90, 100, 1);
|
||||
plot.getPlot().getAxisY().setTicsStep(2);
|
||||
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
|
||||
void paperOutputs() {
|
||||
|
||||
@@ -666,13 +673,15 @@ void paperOutputs() {
|
||||
// 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) {
|
||||
if (1 == 1) {
|
||||
rebuildAllModels(map, 0);
|
||||
/** detailled error analysis for above optimization routine */
|
||||
|
||||
errorPlotAllModels(map);
|
||||
}
|
||||
|
||||
|
||||
// leaving out fingerprints and the effects on all optimization strategies
|
||||
if (1 == 0) {
|
||||
|
||||
rebuildAllModels(map,4);
|
||||
@@ -686,6 +695,13 @@ void paperOutputs() {
|
||||
|
||||
// analyze all 5 opt strategies. skip the empiric one: stats0[0]
|
||||
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);
|
||||
errorPlotNumFingerprints(
|
||||
{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
|
||||
if(1==0){
|
||||
// // error histogram all pos, all params, between in/out/stair, in/out, in/stair, in
|
||||
// if(1==0){
|
||||
|
||||
EvalCompareOpt e1(Settings::fMap, Settings::fCalib, false, false, false);
|
||||
EvalCompareOpt e2(Settings::fMap, Settings::fCalib, true, false, false);
|
||||
EvalCompareOpt e3(Settings::fMap, Settings::fCalib, false, true, false);
|
||||
EvalCompareOpt e4(Settings::fMap, Settings::fCalib, true, true, false);
|
||||
// EvalCompareOpt e1(Settings::fMap, Settings::fCalib, false, false, false);
|
||||
// EvalCompareOpt e2(Settings::fMap, Settings::fCalib, true, false, false);
|
||||
// EvalCompareOpt e3(Settings::fMap, Settings::fCalib, false, true, false);
|
||||
// EvalCompareOpt e4(Settings::fMap, Settings::fCalib, true, true, false);
|
||||
|
||||
K::Statistics<float> s1 = e1.optPosOptParamsForEach().errAbs;
|
||||
K::Statistics<float> s2 = e2.optPosOptParamsForEach().errAbs;
|
||||
K::Statistics<float> s3 = e3.optPosOptParamsForEach().errAbs;
|
||||
K::Statistics<float> s4 = e4.optPosOptParamsForEach().errAbs;
|
||||
// K::Statistics<float> s1 = e1.optPosOptParamsForEach().errAbs;
|
||||
// K::Statistics<float> s2 = e2.optPosOptParamsForEach().errAbs;
|
||||
// K::Statistics<float> s3 = e3.optPosOptParamsForEach().errAbs;
|
||||
// K::Statistics<float> s4 = e4.optPosOptParamsForEach().errAbs;
|
||||
|
||||
PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
||||
pef.add("\\small{floor + stairs + out}", &s1);
|
||||
pef.add("\\small{floor + out}", &s2);
|
||||
pef.add("\\small{floor + stairs}", &s3);
|
||||
pef.add("\\small{floor}", &s4);
|
||||
// PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}");
|
||||
// pef.add("\\small{floor + stairs + out}", &s1);
|
||||
// pef.add("\\small{floor + out}", &s2);
|
||||
// pef.add("\\small{floor + stairs}", &s3);
|
||||
// pef.add("\\small{floor}", &s4);
|
||||
|
||||
pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5));
|
||||
pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.tex");
|
||||
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";
|
||||
pef.plot();
|
||||
// pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5));
|
||||
// pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.tex");
|
||||
// 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";
|
||||
// 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::GnuplotPlot gplot;
|
||||
K::GnuplotPlotElementLines lines; gplot.add(&lines);
|
||||
K::GnuplotPlotElementLines ceils; gplot.add(&ceils);
|
||||
|
||||
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) {
|
||||
|
||||
const Point3 posMe(0, 0, z);
|
||||
//float factor = ceilings.numCeilingsBetweenLinearInt(posAP, posMe);
|
||||
float factor = ceilings.numCeilingsBetweenFloat(posAP, posMe);
|
||||
|
||||
lines.add({z, factor});
|
||||
|
||||
}
|
||||
@@ -813,7 +810,7 @@ void testWAF() {
|
||||
gp.draw(gplot);
|
||||
gp.flush();
|
||||
|
||||
sleep(1000);
|
||||
sleep(10);
|
||||
|
||||
|
||||
}
|
||||
@@ -900,6 +897,10 @@ int main(void) {
|
||||
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);
|
||||
|
||||
//testWAF();
|
||||
//sleep(1);
|
||||
|
||||
//const float rssi = LogDistanceModel::distanceToRssi(-100, 0, 999);
|
||||
//int i = 0; (void) i;
|
||||
|
||||
//paperOutputs(); return 0;
|
||||
|
||||
@@ -908,11 +909,41 @@ int main(void) {
|
||||
//showFingerprintsFor(Settings::fMap, Settings::fCalib, "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);
|
||||
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
|
||||
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) {
|
||||
|
||||
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::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;
|
||||
|
||||
}
|
||||
|
||||
// walks
|
||||
if (1 == 0) {
|
||||
if (1 == 1) {
|
||||
Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);;
|
||||
EvalWalk walk(map);
|
||||
walk.walk1();
|
||||
//EvalWalk walk(map);
|
||||
//walk.walk1();
|
||||
EvalWalk::walkEverything(map);
|
||||
EvalWalk::walkEverythingBuildStats(map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1069,21 +1109,24 @@ int main(void) {
|
||||
|
||||
std::cout << "num scans: " << numScans << std::endl;
|
||||
|
||||
if (1 == 1) {
|
||||
|
||||
EvalWiFiPaths ewp(Settings::fMap);
|
||||
ewp.loadModel(Settings::wifiAllFixed, "\\noOptEmpiric{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
EvalWiFiPaths ewp(Settings::fMap);
|
||||
ewp.loadModel(Settings::wifiAllFixed, "\\noOptEmpiric{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
ewp.loadModel(Settings::wifiEachOptParPos, "\\optParamsPosEachAP{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
ewp.loadModel(Settings::wifiEachOptParPos, "\\optParamsPosEachAP{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "\\optPerFloor{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "\\optPerFloor{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "\\optPerRegion{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "\\optPerRegion{}");
|
||||
ewp.walks(files, gtIndices);
|
||||
|
||||
ewp.writeGP(Settings::fPathGFX, "modelPerformance");
|
||||
ewp.writeGP(Settings::fPathGFX, "modelPerformance");
|
||||
|
||||
}
|
||||
|
||||
// examine various modifications
|
||||
if (1 == 0) {
|
||||
@@ -1114,27 +1157,27 @@ int main(void) {
|
||||
}
|
||||
|
||||
|
||||
// compare wifi opt methods
|
||||
if (1 == 0) {
|
||||
// // compare wifi opt methods
|
||||
// if (1 == 0) {
|
||||
|
||||
const bool ignoreStaircases = false;
|
||||
const bool ignoreOutdoor = false;
|
||||
const bool ignoreIndoor = false;
|
||||
EvalCompareOpt opt(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
|
||||
// const bool ignoreStaircases = false;
|
||||
// const bool ignoreOutdoor = false;
|
||||
// const bool ignoreIndoor = false;
|
||||
// EvalCompareOpt opt(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor);
|
||||
|
||||
EvalCompareOpt::Result s1 = opt.fixedPosFixedParamsForAll(); //BREAK;
|
||||
EvalCompareOpt::Result s2 = opt.fixedPosOptParamsForAll(); //BREAK;
|
||||
EvalCompareOpt::Result s3 = opt.fixedPosOptParamsForEach(); //BREAK;
|
||||
EvalCompareOpt::Result s4 = opt.optPosOptParamsForEach(); //BREAK;
|
||||
// EvalCompareOpt::Result s1 = opt.fixedPosFixedParamsForAll(); //BREAK;
|
||||
// EvalCompareOpt::Result s2 = opt.fixedPosOptParamsForAll(); //BREAK;
|
||||
// EvalCompareOpt::Result s3 = opt.fixedPosOptParamsForEach(); //BREAK;
|
||||
// EvalCompareOpt::Result s4 = opt.optPosOptParamsForEach(); //BREAK;
|
||||
|
||||
PlotErrFunc pef("error (dB)", "fingerprints (%)");
|
||||
pef.add("empiric", &s1.errAbs);
|
||||
pef.add("real pos, opt params [same for all]", &s2.errAbs);
|
||||
pef.add("real pos, opt params [for each]", &s3.errAbs);
|
||||
pef.add("opt pos, opt params [for each]", &s4.errAbs);
|
||||
pef.plot();
|
||||
// PlotErrFunc pef("error (dB)", "fingerprints (%)");
|
||||
// pef.add("empiric", &s1.errAbs);
|
||||
// pef.add("real pos, opt params [same for all]", &s2.errAbs);
|
||||
// pef.add("real pos, opt params [for each]", &s3.errAbs);
|
||||
// pef.add("opt pos, opt params [for each]", &s4.errAbs);
|
||||
// pef.plot();
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
// compare leaving out fingerprints
|
||||
if (1 == 0) {
|
||||
|
||||
0
old/main.h
Normal file → Executable file
0
old/main.h
Normal file → Executable file
398
pf/EvalWalk.h
Normal file → Executable file
398
pf/EvalWalk.h
Normal file → Executable file
@@ -44,6 +44,15 @@
|
||||
#include <Indoor/sensors/offline/FileReader.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 {
|
||||
|
||||
Grid<MyGridNode>* grid;
|
||||
@@ -53,6 +62,8 @@ class EvalWalk : public Offline::Listener {
|
||||
|
||||
Plotty plotty;
|
||||
PlotWifiMeasurements plotWifi;
|
||||
PlotErrTime pet;
|
||||
PlotErrFunc pef;
|
||||
|
||||
Offline::FileReader reader;
|
||||
Offline::FilePlayer player;
|
||||
@@ -74,11 +85,15 @@ class EvalWalk : public Offline::Listener {
|
||||
|
||||
EarthMapping em;
|
||||
|
||||
std::string walkName;
|
||||
|
||||
float absHead = 0;
|
||||
|
||||
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";
|
||||
grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm);
|
||||
@@ -108,8 +123,8 @@ public:
|
||||
pf->setTransition( std::unique_ptr<PFTrans>( new PFTrans(grid)) );
|
||||
|
||||
// resampling step?
|
||||
//pf->setNEffThreshold(0.15);
|
||||
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) );
|
||||
pf->setNEffThreshold(0.02);
|
||||
pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>>(new K::ParticleFilterResamplingSimple<MyState>()) );
|
||||
|
||||
//pf->setNEffThreshold(0.75);
|
||||
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.10)) );
|
||||
@@ -117,9 +132,9 @@ public:
|
||||
//pf->setNEffThreshold(0.75);
|
||||
//pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>>(new K::ParticleFilterResamplingPercent<MyState>(0.05)) );
|
||||
|
||||
K::ParticleFilterResamplingNEff<MyState>* res = new K::ParticleFilterResamplingNEff<MyState>(0.75, 0.05);
|
||||
pf->setNEffThreshold(1.0);
|
||||
pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingNEff<MyState>>(res) );
|
||||
// K::ParticleFilterResamplingNEff<MyState>* res = new K::ParticleFilterResamplingNEff<MyState>(0.75, 0.05);
|
||||
// pf->setNEffThreshold(1.0);
|
||||
// pf->setResampling( std::unique_ptr<K::ParticleFilterResamplingNEff<MyState>>(res) );
|
||||
|
||||
// move during resampling. NOT ALLOWED!
|
||||
// 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() {
|
||||
|
||||
// path1
|
||||
@@ -211,7 +431,7 @@ public:
|
||||
++curCtrl.numStepsSinceLastTransition;
|
||||
}
|
||||
gotSensorData(ts);
|
||||
curCtrl.activityNew = actDetect.add(ts, data);
|
||||
actDetect.add(ts, data);
|
||||
}
|
||||
|
||||
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 {
|
||||
std::cout << "WIFI" << std::endl;
|
||||
curObs.wifi = data;
|
||||
//curObs.wifi = WiFiMeasurements::mix(curObs.wifi, data);
|
||||
#ifdef PLOT_WIFI
|
||||
plotWifi.add(Settings::WiFiModel::vg_eval.group(data));
|
||||
plotWifi.plot();
|
||||
#endif
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -300,12 +524,48 @@ private:
|
||||
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) */
|
||||
void filterUpdate() {
|
||||
|
||||
++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);
|
||||
|
||||
std::cout << "update" << std::endl;
|
||||
@@ -319,22 +579,23 @@ private:
|
||||
|
||||
const Point3 curGT = groundTruthLive.get(lastTransition);
|
||||
|
||||
plotty.setCurEst(curEst.position.inMeter());
|
||||
plotty.setGroundTruth(curGT);
|
||||
|
||||
if (updateCount > 4) {
|
||||
// start the error-over-time plot after some filter updates
|
||||
if (updateCount > 12) {
|
||||
|
||||
// error between ground-truth and estimation
|
||||
const float estRealErr = curEst.position.inMeter().getDistance(curGT);
|
||||
statsErr.add(estRealErr);
|
||||
|
||||
#ifdef PLOT_ERROR_FUNC
|
||||
pef.clear();
|
||||
pef.add("", &statsErr);
|
||||
pef.plot();
|
||||
#endif
|
||||
|
||||
#ifdef PLOT_ERROR_TIME
|
||||
// timed error
|
||||
pet.addErr(lastTransition, estRealErr);
|
||||
pet.addB(lastTransition, getNumFHWSAPs(curObs.wifi));
|
||||
pet.plot();
|
||||
#endif
|
||||
|
||||
// update estimated path
|
||||
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
|
||||
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();
|
||||
|
||||
|
||||
98
pf/PF.h
Normal file → Executable file
98
pf/PF.h
Normal file → Executable file
@@ -98,7 +98,8 @@ struct MyObservation {
|
||||
|
||||
// TODO: switch to a general activity enum/detector for barometer + accelerometer + ...?
|
||||
/** detected activity */
|
||||
ActivityButterPressure::Activity activity;
|
||||
//ActivityButterPressure::Activity activity;
|
||||
Activity activityNew = Activity::STANDING;
|
||||
|
||||
/** time of evaluation */
|
||||
Timestamp currentTime;
|
||||
@@ -119,9 +120,9 @@ struct MyControl {
|
||||
|
||||
// TODO: switch to a general activity enum/detector using barometer + accelerometer?
|
||||
/** 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 */
|
||||
void resetAfterTransition() {
|
||||
@@ -150,8 +151,10 @@ public:
|
||||
std::uniform_real_distribution<float> distHead(0, 2*M_PI);
|
||||
|
||||
for (K::Particle<MyState>& p : particles) {
|
||||
const int idx = distIdx(gen);
|
||||
const MyGridNode& node = (*grid)[idx];
|
||||
again:
|
||||
const int idx = distIdx(gen);
|
||||
const MyGridNode& node = (*grid)[idx];
|
||||
if (node.getNumNeighbors() != 8) {goto again;}
|
||||
p.state.position = node; // random position
|
||||
p.state.heading.direction = Heading(distHead(gen)); // random heading
|
||||
p.weight = 1.0 / particles.size(); // equal weight
|
||||
@@ -174,7 +177,7 @@ public:
|
||||
WalkModuleFavorZ<MyGridNode, MyState> modFavorZ;
|
||||
WalkModuleNodeImportance<MyGridNode, MyState> modImportance;
|
||||
WalkModuleFollowDestination<MyGridNode, MyState> modDestination;
|
||||
WalkModuleActivityControl<MyGridNode, MyState, MyControl> modActivity;
|
||||
//WalkModuleActivityControl<MyGridNode, MyState, MyControl> modActivity;
|
||||
|
||||
WalkModuleHeadingControl<MyGridNode, MyState, MyControl> modRelHead;
|
||||
WalkModuleAbsoluteHeadingControl<MyGridNode, MyState, MyControl> modAbsHead;
|
||||
@@ -183,7 +186,11 @@ 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(&modAbsHead);
|
||||
@@ -234,10 +241,9 @@ public:
|
||||
K::Particle<MyState>& p = particles[i];
|
||||
|
||||
// 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);
|
||||
std::normal_distribution<float> distTurn(0, 0.4);
|
||||
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
std::uniform_int_distribution<int> distIdx(0, n->getNumNeighbors()-1);
|
||||
@@ -246,9 +252,10 @@ public:
|
||||
}
|
||||
p.state.position = *n;
|
||||
|
||||
if (numTrans < 50) {
|
||||
p.state.heading.direction += distTurn(gen);
|
||||
dist_m += 0.5;
|
||||
if (numTrans < 70) {
|
||||
std::normal_distribution<float> distTurn(0, 0.3);
|
||||
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.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) {
|
||||
throw Exception("nan");
|
||||
}
|
||||
@@ -320,14 +332,31 @@ public:
|
||||
|
||||
double res = 0;
|
||||
|
||||
if (angularDiff > Angle::degToRad(90)) {res = 0.05;}
|
||||
else if (angularDiff > Angle::degToRad(45)) {res = 0.25;}
|
||||
else {res = 0.70;}
|
||||
if (angularDiff > Angle::degToRad(120)) {res = 0.30;}
|
||||
else {res = 0.70;}
|
||||
|
||||
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;
|
||||
|
||||
double evaluation(std::vector<K::Particle<MyState>>& particles, const MyObservation& _observation) override {
|
||||
@@ -343,7 +372,9 @@ public:
|
||||
|
||||
|
||||
wqa.add(wifiObs);
|
||||
const float quality = wqa.getQuality();
|
||||
float quality = wqa.getQuality();
|
||||
std::cout << "wifi quality: " << quality << std::endl;
|
||||
|
||||
|
||||
// GPS
|
||||
const GPSProbability gpsProb(em);
|
||||
@@ -353,7 +384,7 @@ public:
|
||||
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
|
||||
wiFiProbability.setUseError(false);
|
||||
wiFiProbability.setUseError(true);
|
||||
|
||||
//#pragma omp parallel for num_threads(3)
|
||||
for (int i = 0; i < Settings::numParticles; ++i) {
|
||||
@@ -362,16 +393,15 @@ public:
|
||||
|
||||
// WiFi free
|
||||
double pWiFi = wiFiProbability.getProbability(p.state.position.inMeter()+person, observation.currentTime, wifiObs);
|
||||
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 = Distribution::Exponential<double>::getProbability(0.20, -std::log(pWiFi));
|
||||
//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
|
||||
//const MyGridNode& node = grid->getNodeFor(p.state.position);
|
||||
@@ -379,9 +409,18 @@ public:
|
||||
//const double pWiFi = wiFiProbability.getProbability(node, observation.currentTime, wifiObs);
|
||||
|
||||
//const double pStair = 1;//getStairProb(p, observation.activity);
|
||||
const double pGPS = gpsProb.getProbability(p.state.position.inMeter(), observation.gps);
|
||||
const double pAbsHead = getAbsHead(p.state, observation);
|
||||
const double prob = pWiFi * pWiFiVeto;// * pAbsHead;
|
||||
double pGPS = gpsProb.getProbability(p.state.position.inMeter(), observation.gps);
|
||||
double pAbsHead = getAbsHead(p.state, observation);
|
||||
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?
|
||||
|
||||
@@ -392,6 +431,11 @@ public:
|
||||
// TESTING
|
||||
//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; // does NOT keep the weights returned by the transition step
|
||||
|
||||
|
||||
5
plots/PlotErrFunc.h
Normal file → Executable file
5
plots/PlotErrFunc.h
Normal file → Executable file
@@ -49,6 +49,11 @@ class PlotErrFunc {
|
||||
|
||||
public:
|
||||
|
||||
/** empty ctor */
|
||||
PlotErrFunc() {
|
||||
setYRange(0, 90, 5);
|
||||
}
|
||||
|
||||
/** ctor with x-axis label */
|
||||
PlotErrFunc(const std::string& xLabel, const std::string& yLabel) {
|
||||
gplot.getAxisX().setLabel(xLabel);
|
||||
|
||||
14
plots/PlotErrTime.h
Normal file → Executable file
14
plots/PlotErrTime.h
Normal file → Executable file
@@ -23,6 +23,11 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
/** empty ctor */
|
||||
PlotErrTime() {
|
||||
|
||||
}
|
||||
|
||||
/** ctor */
|
||||
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() {
|
||||
for (int i = 0; i < 8; ++i) {lineErr[i].clear();}
|
||||
lineB.clear();
|
||||
|
||||
24
plots/PlotWiFiGroundProb.h
Normal file → Executable file
24
plots/PlotWiFiGroundProb.h
Normal file → Executable file
@@ -67,16 +67,13 @@ public:
|
||||
}
|
||||
|
||||
/** 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);
|
||||
void show(const WiFiObserverFree& prob, const WiFiMeasurements& mes, const Timestamp ts) {
|
||||
|
||||
// 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);
|
||||
const double p = prob.getProbability(e.pos, ts, mes);
|
||||
if (p < min) {min = p;}
|
||||
if (p > max) {max = p;}
|
||||
}
|
||||
@@ -84,8 +81,11 @@ public:
|
||||
|
||||
// render
|
||||
for (Entry& e : pos) {
|
||||
const double p = prob.getProbability(e.pos, mes.entries.front().getTimestamp(), mes);
|
||||
const double f = (p-min) / diff * 255;
|
||||
const double p = prob.getProbability(e.pos, ts, mes);
|
||||
double f = (p-min) / diff * 255;
|
||||
if (f < 0) {f = 0;}
|
||||
if (f > 255) {f = 255;}
|
||||
|
||||
e.sum += p;
|
||||
e.cnt++;
|
||||
|
||||
@@ -93,10 +93,14 @@ public:
|
||||
const K::GnuplotColor c = K::GnuplotColor::fromHSV(0, f, 255);
|
||||
e.poly->getFill().setColor(c);
|
||||
e.max = f;
|
||||
|
||||
e.poly->setEnabled(f > 32);
|
||||
//}
|
||||
if (f < 0.1) {
|
||||
e.poly->setEnabled(false);
|
||||
}
|
||||
// if (f < 32) {
|
||||
// e.poly->setEnabled(false);
|
||||
// } else {
|
||||
// e.poly->setEnabled(true);
|
||||
// }
|
||||
|
||||
//plot.cpoints.add(K::GnuplotPoint3(pt.x, pt.y, pt.z), p);
|
||||
}
|
||||
|
||||
0
plots/Plotty.h
Normal file → Executable file
0
plots/Plotty.h
Normal file → Executable file
2
tex/bare_conf.tex
Normal file → Executable file
2
tex/bare_conf.tex
Normal file → Executable file
@@ -81,6 +81,8 @@
|
||||
%\usepackage{ulem}
|
||||
|
||||
|
||||
%\setcounter{figure}{0}
|
||||
%\renewcommand{\thefigure}{A\arabic{section}.\arabic{figure}}
|
||||
|
||||
|
||||
% replacement for the SI package
|
||||
|
||||
0
tex/chapters/abstract.tex
Normal file → Executable file
0
tex/chapters/abstract.tex
Normal file → Executable file
0
tex/chapters/conclusion.tex
Normal file → Executable file
0
tex/chapters/conclusion.tex
Normal file → Executable file
97
tex/chapters/experiments.tex
Normal file → Executable file
97
tex/chapters/experiments.tex
Normal file → Executable file
@@ -41,13 +41,13 @@
|
||||
\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.
|
||||
}
|
||||
\label{fig:referenceMeasurements}
|
||||
\end{figure}
|
||||
|
||||
% visible APs:
|
||||
@@ -56,12 +56,12 @@
|
||||
\begin{figure}[b]
|
||||
\centering
|
||||
\input{gfx/compare-wifi-in-out.tex}
|
||||
\label{fig:wifiIndoorOutdoor}
|
||||
\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).
|
||||
}
|
||||
\label{fig:wifiIndoorOutdoor}
|
||||
\end{figure}
|
||||
|
||||
Figure \ref{fig:wifiIndoorOutdoor} depicts the to-be-expected issues by examining the signal strength
|
||||
@@ -105,11 +105,11 @@
|
||||
\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.
|
||||
}
|
||||
\label{fig:wifiModelError}
|
||||
\end{figure}
|
||||
|
||||
% statds:
|
||||
@@ -135,30 +135,77 @@
|
||||
|
||||
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.
|
||||
Depending on the number of to-be-optimized model 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.
|
||||
Depending on the chosen model and thus the number of to-be-optimized parameters, more measurements are required.
|
||||
|
||||
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]
|
||||
\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
|
||||
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}
|
||||
|
||||
Figure \ref{fig:wifiNumFingerprints} depicts the impact of reducing the number of fingerprints
|
||||
for the {\em \optPerRegion{}} strategy. Only using 60 of the 121 fingerprints yields only a slightly
|
||||
increasing model error and still provides good results. While using only \SI{25}{\percent} of the reference
|
||||
measurements increases the error rapidly, \SI{75}{\percent} of all considered errors are still better
|
||||
than using just empiric values without any reference measurements.
|
||||
Figure \ref{fig:wifiNumFingerprints} depicts the impact of reducing the number of reference measurements
|
||||
during the optimization process for the {\em \optPerRegion{}} strategy.
|
||||
The error is determined by using the (absolute) difference between expected signal strength and
|
||||
the optimized model's corresponding prediction for all of the 121 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
|
||||
like aforementioned staircases, surrounded by concrete. While this slightly decreases the
|
||||
estimation error for all other positions, the error within those locations is dramatically
|
||||
like staircases, surrounded by steel-enforced concrete. While this slightly decreases the
|
||||
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
|
||||
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.
|
||||
For all comparisons we use a constant uncertainty $\sigma = $\SI{8}{\decibel}.
|
||||
|
||||
The quality of the estimated location is determined by comparing the estimation
|
||||
$\mPosVec^*$ with the pedestrian's ground truth position at the time the scan $\mRssiVec$
|
||||
The quality of the estimated location is determined by using the Euclidean distance between estimation
|
||||
$\mPosVec^*$ and the pedestrian's ground truth position at the time the scan $\mRssiVec$
|
||||
has been received.
|
||||
|
||||
|
||||
@@ -226,18 +273,20 @@
|
||||
|
||||
\begin{figure}[b]
|
||||
\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
|
||||
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}
|
||||
|
||||
%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)
|
||||
%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)
|
||||
is compared against its corresponding ground-truth, indicating the absolute 3D error.
|
||||
The position estimation for each \docWIFI{} measurement within the recorded walks (3756 scans in total)
|
||||
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 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.
|
||||
@@ -252,13 +301,13 @@
|
||||
|
||||
\begin{figure}[t]
|
||||
\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).
|
||||
}
|
||||
\label{fig:wifiMultimodality}
|
||||
\end{figure}
|
||||
|
||||
Figure \ref{fig:wifiMultimodality} depicts aforementioned issues of multimodal (blue) or wrong (red) location
|
||||
@@ -318,13 +367,13 @@
|
||||
\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}.
|
||||
}
|
||||
\label{fig:normalVsExponential}
|
||||
\end{figure}
|
||||
|
||||
|
||||
|
||||
0
tex/chapters/interoduction.tex
Normal file → Executable file
0
tex/chapters/interoduction.tex
Normal file → Executable file
0
tex/chapters/introduction.tex
Normal file → Executable file
0
tex/chapters/introduction.tex
Normal file → Executable file
0
tex/chapters/relatedwork.tex
Normal file → Executable file
0
tex/chapters/relatedwork.tex
Normal file → Executable file
0
tex/chapters/system.tex
Normal file → Executable file
0
tex/chapters/system.tex
Normal file → Executable file
14
tex/chapters/work.tex
Normal file → Executable file
14
tex/chapters/work.tex
Normal file → Executable file
@@ -100,12 +100,12 @@
|
||||
|
||||
\begin{figure}[t!]
|
||||
\input{gfx/wifiop_show_optfunc_params}
|
||||
\label{fig:wifiOptFuncTXPEXP}
|
||||
\caption{
|
||||
The average error (in \SI{}{\decibel}) between all reference measurements and corresponding model predictions
|
||||
for one \docAPshort{} dependent on \docTXP{} \mTXP{} and \docEXP{} \mPLE{}
|
||||
[known position $\mPosAPVec{}$, fixed \mWAF{}] denotes a convex function.
|
||||
}
|
||||
\label{fig:wifiOptFuncTXPEXP}
|
||||
\end{figure}
|
||||
|
||||
For systems that demand a higher accuracy, one can choose a compromise between fingerprinting and
|
||||
@@ -138,12 +138,12 @@
|
||||
|
||||
\begin{figure}[t!]
|
||||
\input{gfx/wifiop_show_optfunc_pos_yz}
|
||||
\label{fig:wifiOptFuncPosYZ}
|
||||
\caption{
|
||||
The average error (in \SI{}{\decibel}) between reference measurements and model predictions
|
||||
for one \docAPshort{} dependent on $y$- and $z$-position [fixed $x$, \mTXP{}, \mPLE{} and \mWAF{}]
|
||||
usually denotes a non-convex function with multiple [here: two] local minima.
|
||||
}
|
||||
\label{fig:wifiOptFuncPosYZ}
|
||||
\end{figure}
|
||||
|
||||
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
|
||||
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}
|
||||
|
||||
@@ -243,8 +246,11 @@
|
||||
When scanning for \docAPshort{}s one will thus receive several responses from the same hardware, all with
|
||||
a very small delay (micro- to milliseconds). Such measurements may be grouped using some aggregate
|
||||
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
0
tex/egbib.bib
Normal file → Executable file
2
tex/gfx/build.sh
Normal file → Executable file
2
tex/gfx/build.sh
Normal file → Executable file
@@ -1,4 +1,4 @@
|
||||
for file in *.gp
|
||||
do
|
||||
gnuplot $file;
|
||||
gnuplot "$file";
|
||||
done
|
||||
|
||||
0
tex/make.sh
Normal file → Executable file
0
tex/make.sh
Normal file → Executable file
0
tex/misc/functions.tex
Normal file → Executable file
0
tex/misc/functions.tex
Normal file → Executable file
0
tex/misc/keywords.tex
Normal file → Executable file
0
tex/misc/keywords.tex
Normal file → Executable file
0
wifi/EvalWiFi.h
Normal file → Executable file
0
wifi/EvalWiFi.h
Normal file → Executable file
0
wifi/EvalWiFiConvex.h
Normal file → Executable file
0
wifi/EvalWiFiConvex.h
Normal file → Executable file
71
wifi/EvalWiFiGround.h
Normal file → Executable file
71
wifi/EvalWiFiGround.h
Normal file → Executable file
@@ -30,6 +30,7 @@
|
||||
#include "../plots/PlotErrTime.h"
|
||||
#include "../plots/PlotErrFunc.h"
|
||||
#include "../plots/PlotWiFiGroundProb.h"
|
||||
#include <Indoor/debug/PlotWifiMeasurements.h>
|
||||
//#include "../CSV.h"
|
||||
|
||||
#include <unordered_set>
|
||||
@@ -46,6 +47,7 @@ private:
|
||||
public:
|
||||
|
||||
PlotWiFiGroundProb* groundProb;
|
||||
PlotWifiMeasurements plotWifi;
|
||||
|
||||
public:
|
||||
|
||||
@@ -55,25 +57,84 @@ public:
|
||||
obs = new WiFiObserverFree(8.0, *mdl);
|
||||
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::GroundTruth gt = reader.getGroundTruth(map, gtIndices);
|
||||
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||
|
||||
|
||||
|
||||
int cnt = 0;
|
||||
|
||||
for (const auto& entry : reader.getWiFiGroupedByTime()) {
|
||||
const WiFiMeasurements& mes = entry.data;
|
||||
groundProb->show(*obs, mes);
|
||||
WiFiMeasurements 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();
|
||||
|
||||
|
||||
//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->plotMe();
|
||||
int i = 0; (void) i;
|
||||
|
||||
sleep(1000);
|
||||
|
||||
}
|
||||
|
||||
void add(const std::string walkFile, const int idx, const float hue) {
|
||||
|
||||
48
wifi/EvalWiFiPathMethods.h
Normal file → Executable file
48
wifi/EvalWiFiPathMethods.h
Normal file → Executable file
@@ -242,7 +242,7 @@ public:
|
||||
|
||||
// error calculation
|
||||
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);
|
||||
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 {
|
||||
|
||||
|
||||
4
wifi/EvalWiFiPaths.h
Normal file → Executable file
4
wifi/EvalWiFiPaths.h
Normal file → Executable file
@@ -95,7 +95,9 @@ public:
|
||||
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);
|
||||
//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
|
||||
pef.getPlot().getAxisX().setRange(K::GnuplotAxis::Range(0,25));
|
||||
|
||||
Reference in New Issue
Block a user