329 lines
9.5 KiB
C++
Executable File
329 lines
9.5 KiB
C++
Executable File
#ifndef EVALWIFICONVEX_H
|
|
#define EVALWIFICONVEX_H
|
|
|
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
|
#include "Indoor/sensors/radio/setup/WiFiFingerprint.h"
|
|
#include "Indoor/sensors/radio/setup/WiFiFingerprints.h"
|
|
#include "Indoor/sensors/radio/setup/WiFiOptimizer.h"
|
|
#include "Indoor/sensors/radio/model/WiFiModels.h"
|
|
|
|
#include "Indoor/sensors/radio/VAPGrouper.h"
|
|
#include "Indoor/sensors/offline/FileReader.h"
|
|
|
|
#include "Indoor/floorplan/v2/Floorplan.h"
|
|
#include "Indoor/floorplan/v2/FloorplanReader.h"
|
|
#include "Indoor/floorplan/v2/FloorplanHelper.h"
|
|
#include "Indoor/floorplan/v2/FloorplanCeilings.h"
|
|
|
|
#include <KLib/misc/gnuplot/Gnuplot.h>
|
|
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
|
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
|
|
#include <KLib/misc/gnuplot/GnuplotSplotElementColorPoints.h>
|
|
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
|
#include <KLib/misc/gnuplot/GnuplotSplotElementMesh.h>
|
|
|
|
#include <KLib/math/statistics/Statistics.h>
|
|
|
|
//#include "../Structs.h"
|
|
#include "../plots/Plotty.h"
|
|
#include "../plots/PlotErrTime.h"
|
|
#include "../plots/PlotErrFunc.h"
|
|
#include "../Settings.h"
|
|
#include "../Helper.h"
|
|
|
|
#include <unordered_set>
|
|
#include <thread>
|
|
|
|
class EvalWiFiConvex {
|
|
|
|
private:
|
|
|
|
Floorplan::IndoorMap* map;
|
|
std::vector<APAtFloor> mapAPs;
|
|
WiFiFingerprints calib;
|
|
|
|
public:
|
|
|
|
/** ctor */
|
|
EvalWiFiConvex(Floorplan::IndoorMap* map, const std::string& fpFile) : map(map){
|
|
|
|
// all APs within the map
|
|
mapAPs = FloorplanHelper::getAPs(map);
|
|
|
|
// load fingerprints
|
|
calib = WiFiFingerprints(fpFile);
|
|
|
|
// VAP-group
|
|
VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::MEDIAN);
|
|
for (WiFiFingerprint& fp : calib.getFingerprints()) {
|
|
fp.measurements = vap.group(fp.measurements);
|
|
}
|
|
|
|
}
|
|
|
|
void showParams() {
|
|
|
|
K::Gnuplot gp;
|
|
K::GnuplotSplot splot;
|
|
K::GnuplotSplotElementMesh mesh; splot.add(&mesh);
|
|
|
|
//splot.setTitle("optimizing TXP and EXP}");
|
|
splot.getAxisX().setLabel("TXP (dBm)");
|
|
splot.getAxisX().setLabelOffset(-3.9, -1.9);
|
|
splot.getAxisX().setTicsStep(2.5);
|
|
splot.getAxisX().setTicsOffset(-1, -0.1);
|
|
|
|
splot.getAxisY().setLabel("EXP");
|
|
splot.getAxisY().setLabelOffset(-0.5, -0.6);
|
|
splot.getAxisY().setTicsOffset(-0.3, -0.5);
|
|
|
|
splot.getAxisZ().setLabel("error (dB)");
|
|
|
|
splot.getAxisCB().setTicsStep(4);
|
|
|
|
splot.getView().setCamera(55, 115);
|
|
splot.getAxisZ().setLabelRotation(90);
|
|
splot.setStringMod(new K::GnuplotStringModLaTeX());
|
|
|
|
std::string name = Settings::fPathGFX + "/wifiop_show_optfunc_params";
|
|
gp.setOutput(name + ".tex");
|
|
gp.setTerminal("epslatex", K::GnuplotSize(8.7, 5.0));
|
|
splot.getAxisZ().setTicsVisible(false);
|
|
splot.getAxisZ().setLabel("");
|
|
gp << "set palette defined (0 '#00ff00', 1 '#eeeeee', 9 '#222222')\n";
|
|
|
|
gp << "set margins 0,0,0,0\n";
|
|
gp << "set multiplot layout 1,1 scale 1.25, 1.4 offset 0.02, 0.05\n";
|
|
gp << "set colorbox horizontal user origin 0.03, 0.95 size 0.4, 0.03\n";
|
|
|
|
//p mac="D8:84:66:4A:23:F0" px="46" py="47.400002" pz="13.8" txp="-40" exp="2.6500001" waf="-6.5"/>
|
|
const MACAddress mac("D8:84:66:4A:23:F0");
|
|
const Point3 pos_m(46, 47.4, 13.8);
|
|
const float waf = -6;
|
|
|
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
|
|
|
for (float txp = -45; txp <= -35; txp += 0.5) {
|
|
for (float exp = 1.5; exp <= 3.5; exp += 0.05) {
|
|
|
|
WiFiModelLogDistCeiling model(map);
|
|
model.addAP(mac, pos_m, txp, exp, waf);
|
|
|
|
const K::Statistics<float> res = getError(mac, model, fps);
|
|
const float err = res.getAvg();
|
|
mesh.add(K::GnuplotPoint3(txp, exp, err));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
gp.draw(splot);
|
|
LeHelper::writeCode(name + ".gp", gp.getBuffer());
|
|
gp.flush();
|
|
|
|
//sleep(100);
|
|
|
|
}
|
|
|
|
|
|
// void showPos() {
|
|
|
|
// K::Gnuplot gp;
|
|
// K::GnuplotSplot splot;
|
|
// K::GnuplotSplotElementMesh mesh; splot.add(&mesh);
|
|
|
|
// //splot.setTitle("optimizing position");
|
|
// splot.getAxisX().setLabel("x-position (meter)");
|
|
// splot.getAxisY().setLabel("y-position (meter)");
|
|
// splot.getAxisZ().setLabel("error (dB)");
|
|
|
|
// splot.getAxisZ().setLabelRotation(90);
|
|
// splot.setStringMod(new K::GnuplotStringModLaTeX());
|
|
// gp << "set palette defined (0 '#00ff00', 1 '#eeeeee', 9 '#000000')\n";
|
|
|
|
// const MACAddress mac("D8:84:66:4A:23:F0");
|
|
// const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
|
|
|
// const Point3 pos_m(46, 47.4, 13.8);
|
|
// const float txp = -40;
|
|
// const float exp = 2.2;
|
|
// const float waf = -6;
|
|
|
|
// for (float ox = -10; ox <= +10; ox += 0.5) {
|
|
// for (float oy = -19; oy <= +8; oy += 0.5) {
|
|
|
|
// const Point3 pos = pos_m + Point3(ox, oy, 0);
|
|
|
|
// WiFiModelLogDistCeiling model(map);
|
|
// model.addAP(mac, pos, txp, exp, waf);
|
|
|
|
// const K::Statistics<float> res = getError(mac, model, fps);
|
|
// const float err = res.getAvg();
|
|
// mesh.add(K::GnuplotPoint3(pos.x, pos.y, err));
|
|
|
|
// }
|
|
// }
|
|
|
|
// gp.draw(splot);
|
|
// gp.flush();
|
|
|
|
// //sleep(100);
|
|
|
|
// }
|
|
|
|
void showPosZ() {
|
|
|
|
K::Gnuplot gp;
|
|
K::GnuplotSplot splot;
|
|
K::GnuplotSplotElementMesh mesh; splot.add(&mesh);
|
|
K::GnuplotSplotElementLines lines1; splot.add(&lines1); lines1.getStroke().setWidth(2); lines1.getStroke().setType(K::GnuplotDashtype::DOTTED);
|
|
K::GnuplotSplotElementLines lines2; splot.add(&lines2); lines2.getStroke().setWidth(2); lines2.getStroke().setType(K::GnuplotDashtype::DASHED);
|
|
K::GnuplotSplotElementLines lines3; splot.add(&lines3); lines3.getStroke().setWidth(2);
|
|
K::GnuplotSplotElementPoints points; splot.add(&points); points.setPointSize(1.5); points.setPointType(7);
|
|
|
|
//splot.setTitle("optimizing position");
|
|
splot.getAxisX().setLabel("y-pos (meter)");
|
|
splot.getAxisX().setLabelOffset(-0.9, -1.4);
|
|
splot.getAxisX().setTicsOffset(-0.9, 0);
|
|
splot.getAxisX().setTicsStep(25);
|
|
|
|
splot.getAxisY().setLabel("z-pos (meter)");
|
|
splot.getAxisY().setLabelOffset(0, -0.3);
|
|
splot.getAxisY().setTicsOffset(0, -0.5);
|
|
|
|
splot.getAxisY().setTicsStep(3);
|
|
|
|
//splot.getAxisZ().setLabel("error (dB)");
|
|
//splot.getAxisZ().setTicsStep(3);
|
|
//splot.getAxisZ().setLabelRotation(90);
|
|
splot.getAxisZ().setLabel("");
|
|
splot.getAxisZ().setTicsVisible(false);
|
|
splot.getAxisCB().setTicsStep(3);
|
|
|
|
|
|
std::string name = Settings::fPathGFX + "/wifiop_show_optfunc_pos_yz";
|
|
gp.setOutput(name + ".tex");
|
|
gp.setTerminal("epslatex", K::GnuplotSize(8.7, 5.0));
|
|
gp << "set palette defined (0 '#00ff00', 1 '#eeeeee', 9 '#222222')\n";
|
|
gp << "set margins 0,0,0,0\n";
|
|
gp << "set multiplot layout 1,1 scale 1.25,1.4 offset 0.02, 0.05\n";
|
|
gp << "set colorbox horizontal user origin 0.57, 0.95 size 0.4, 0.03\n";
|
|
|
|
// paper out
|
|
splot.setStringMod(new K::GnuplotStringModLaTeX());
|
|
splot.getView().setCamera(38, 109);
|
|
|
|
const MACAddress mac("D8:84:66:4A:23:F0");
|
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
|
|
|
const Point3 pos_m(46-15, 47.4-15, 13.8);
|
|
const float txp = -40;
|
|
const float exp = 2.2;
|
|
const float waf = -6;
|
|
|
|
const int steps = 35;
|
|
|
|
for (float sz = 0; sz < steps; ++sz) {
|
|
for (int sy = 0; sy < steps; ++sy) {
|
|
|
|
const float oz = -15.0f + 20.0f * sz / steps;
|
|
const float oy = -35.0f + 90.0f * sy / steps;
|
|
|
|
const Point3 pos = pos_m + Point3(0, oy, oz);
|
|
|
|
WiFiModelLogDistCeiling model(map);
|
|
model.addAP(mac, pos, txp, exp, waf);
|
|
|
|
const K::Statistics<float> res = getError(mac, model, fps);
|
|
const float err = res.getAvg();
|
|
const K::GnuplotPoint3 gp3(pos.y, pos.z, err);
|
|
mesh.add(gp3);
|
|
|
|
if (sy == 0) {lines1.add(gp3);}
|
|
if (sy == 17) {lines2.add(gp3);}
|
|
if (sz == 24) {lines3.add(gp3);}
|
|
|
|
if (sy == 9 && sz == 24) {points.add(gp3);}
|
|
if (sy == 26 && sz == 24) {points.add(gp3);}
|
|
|
|
}
|
|
}
|
|
|
|
gp.draw(splot);
|
|
LeHelper::writeCode(name + ".gp", gp.getBuffer());
|
|
gp.flush();
|
|
|
|
int i = 0; (void) i;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::vector<WiFiFingerprint> getFingerprints(const MACAddress& mac) {
|
|
|
|
// get all fingerprints where the given mac was seen
|
|
const std::vector<WiFiFingerprint> fps = calib.getFingerprintsFor(mac);
|
|
|
|
// sanity check
|
|
if (fps.size() < 5) {throw Exception("not enought fingerprints for AP " + mac.asString());}
|
|
|
|
return fps;
|
|
|
|
}
|
|
|
|
|
|
/** calculate the error for the given AP [mac + configured model] for all fingerprints for this mac */
|
|
K::Statistics<float> getError(const MACAddress& mac, const WiFiModelLogDistCeiling& model) {
|
|
|
|
// get all fingerprints where the given mac was seen
|
|
const std::vector<WiFiFingerprint> fps = getFingerprints(mac);
|
|
|
|
// fire
|
|
return getError(mac, model, fps);
|
|
|
|
}
|
|
|
|
/** calculate the error for the given AP [mac + configured model] for all of the given FPS */
|
|
K::Statistics<float> getError(const MACAddress& mac, const WiFiModelLogDistCeiling& model, const std::vector<WiFiFingerprint>& fps) {
|
|
|
|
K::Statistics<float> res;
|
|
|
|
// calculate the model error for each fingerprint
|
|
for (const WiFiFingerprint& fp : fps) {
|
|
|
|
// sanity checks
|
|
if (fp.measurements.entries.size() != 1) {throw Exception("invalid fingerprint");}
|
|
if (fp.measurements.entries.front().getAP().getMAC() != mac) {throw Exception("invalid fingerprint");}
|
|
|
|
// rssi prediction from the configured model
|
|
const float model_rssi = model.getRSSI(mac, fp.pos_m);
|
|
|
|
// sanity check
|
|
if (model_rssi != model_rssi) {throw Exception("model rssi not available for " + mac.asString());}
|
|
|
|
// rssi measured during scan at this location
|
|
const float scan_rssi = fp.measurements.entries.front().getRSSI();
|
|
|
|
// sanity check
|
|
if (scan_rssi < -100) {throw Exception("scan rssi out of range for " + mac.asString());}
|
|
if (scan_rssi > -35) {throw Exception("scan rssi out of range for " + mac.asString());}
|
|
|
|
// dB error
|
|
const float err = model_rssi - scan_rssi;
|
|
|
|
// quadratic
|
|
float aErr = std::pow(std::abs(err), 1);
|
|
|
|
res.add(aErr);
|
|
|
|
}
|
|
|
|
// done
|
|
return res;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif // EVALWIFICONVEX_H
|