#ifndef EVALWIFIOPTRESULT_H #define EVALWIFIOPTRESULT_H #include "Indoor/sensors/radio/setup/WiFiOptimizer.h" #include "Indoor/sensors/radio/setup/WiFiFingerprint.h" #include "Indoor/sensors/radio/setup/WiFiFingerprints.h" #include "Indoor/sensors/radio/setup/WiFiOptimizer.h" #include "Indoor/sensors/radio/VAPGrouper.h" #include "Indoor/sensors/offline/FileReader.h" #include "Indoor/floorplan/v2/Floorplan.h" #include "Indoor/floorplan/v2/FloorplanReader.h" #include "Indoor/floorplan/v2/FloorplanHelper.h" #include "Indoor/floorplan/v2/FloorplanCeilings.h" #include "Indoor/grid/factory/v2/Helper.h" #include #include #include #include #include #include #include #include #include #include "Structs.h" #include "plots/Plotty.h" #include "plots/PlotErrTime.h" #include "plots/PlotErrFunc.h" #include "Settings.h" /** plot results of the wifi optimization */ class EvalWiFiOptResult { Floorplan::IndoorMap* map; VAPGrouper vap; public: /** ctor */ EvalWiFiOptResult(const std::string& mapFile) : vap(Settings::WiFiModel::vg_eval) { map = Floorplan::Reader::readFromFile(mapFile); } /** * plot the error for every fingerprint */ template Plotty* showErrorPerFingerprint(const std::string& modelParamsXML, const WiFiFingerprints& fps) { Plotty* plot = new Plotty(map); plot->settings.obstacles = true; plot->settings.outline = false; plot->settings.stairs = false; plot->settings.outlineColorCustom = true; plot->settings.outlineColor = K::GnuplotColor::fromRGB(0,0,0); plot->buildFloorplan(); plot->equalXY(); plot->gp << "unset border\n"; plot->splot.getAxisX().setTicsVisible(false); plot->splot.getAxisY().setTicsVisible(false); plot->splot.getAxisZ().setTicsVisible(false); plot->setScale(1.5, 1.5); // the sig strength model Model model(map); model.loadXML(modelParamsXML); // WiFiModelLogDistCeiling model(map); // model.loadXML(modelParamsXML); // combine position and error struct ErrPoint { Point3 pos; float err; ErrPoint(const Point3 pos, const float err) : pos(pos), err(err) {;} }; std::vector errors; // process each location for (const WiFiFingerprint& fp : fps.getFingerprints()) { // estimate error for this location K::Statistics errAbs; // vap grouping const WiFiMeasurements mes = vap.group(fp.measurements); // process each measured AP for (const WiFiMeasurement& m : mes.entries) { // fingerprint RSSI const float scan_rssi = m.getRSSI(); // model RSSI const float model_rssi = model.getRSSI(m.getAP().getMAC(), fp.pos_m); // AP unknown -> skip if (model_rssi != model_rssi) {continue;} // update error const float err = model_rssi - scan_rssi; errAbs.add(std::abs(err)); } // enqueue AVG error //errors.push_back(ErrPoint(fp.pos_m, errAbs.getAvg())); // enqueue MAX error errors.push_back(ErrPoint(fp.pos_m, errAbs.getMax())); } // interpolated error points std::vector errorsInt; K::Statistics errStats; const float oz = 1.3; const float ss = 4.0; for (Floorplan::Floor* floor : map->floors) { for (float y = -20; y < 70; y+=ss) { for (float x = -10; x < 130; x+=ss) { const Point3 pos(x,y,floor->atHeight+oz); float errSum = 0; float distSum = 0; int cnt = 0; float minDist = 99999; for (const ErrPoint& ep : errors) { if (ep.pos.z != pos.z) {continue;} const float dist = ep.pos.getDistance(pos); //if (dist > 4.0) {continue;} //const float imp = 1.0 / (std::pow((dist+0.01)/4.0, 3)); //errSum += ep.err * imp; //distSum += imp; if (dist < minDist) { errSum = ep.err; distSum = 1.0; minDist = dist; } ++cnt; } // limit estimations to the floorplan's outline bool contained = false; for (Floorplan::FloorOutlinePolygon* poly : floor->outline) { HelperPoly hp(*poly); if (hp.contains(pos.xy()*100)) { if (poly->method == Floorplan::OutlineMethod::ADD) { contained = true; } else { //contained = false; break; } } } if (distSum == 0) {continue;} if (!contained) {continue;} const float err = errSum/distSum; // add errStats.add(err); errorsInt.push_back(ErrPoint(pos, err)); } } } const float minErr = 0.0;//errStats.getMin(); const float maxErr = 20.0;//errStats.getQuantile(0.9); //plot->splot.setTitle("max error: " + std::to_string(errStats.getMax()) + " dB"); // draw interpolated errors between min/max for (const ErrPoint& ep : errorsInt) { float factor = (ep.err - minErr) / (maxErr-minErr); if (factor > 1) {factor = 1;} if (factor < 0) {factor = 0;} // hsv green->yellow->red // const float h = 90 * (1 - std::pow(factor, 1.0)); // K::GnuplotColor color = K::GnuplotColor::fromHSV(h, 255, 255); // hsv white->red const float sat = 255 * factor; K::GnuplotColor color = K::GnuplotColor::fromHSV(0, sat, 255); K::GnuplotObjectPolygon* poly = new K::GnuplotObjectPolygon( K::GnuplotFill(K::GnuplotFillStyle::SOLID, color), K::GnuplotStroke::NONE() ); const float s = ss/2; poly->add(K::GnuplotCoordinate3(ep.pos.x-s, ep.pos.y-s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST)); poly->add(K::GnuplotCoordinate3(ep.pos.x+s, ep.pos.y-s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST)); poly->add(K::GnuplotCoordinate3(ep.pos.x+s, ep.pos.y+s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST)); poly->add(K::GnuplotCoordinate3(ep.pos.x-s, ep.pos.y+s, ep.pos.z-oz, K::GnuplotCoordinateSystem::FIRST)); poly->close(); poly->setZIndex(ep.pos.z - 1.5); plot->splot.getObjects().add(poly); } plot->splot.getObjects().reOrderByZIndex(); plot->plot(); return plot; } }; #endif // EVALWIFIOPTRESULT_H