#define BREAK raise(SIGTRAP); #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/floorplan/v2/Floorplan.h" #include "Indoor/floorplan/v2/FloorplanReader.h" #include "Indoor/floorplan/v2/FloorplanHelper.h" #include #include #include #include #include #include #include "Settings.h" #include "EvalCompareOpt.h" #include "EvalCompareOpt2.h" #include "EvalApOpt.h" #include "EvalData.h" #include "EvalWiFiSigStrength.h" #include "pf/EvalWalk.h" #include "EvalWifiOptResult.h" #include "wifi/EvalWiFiConvex.h" #include "wifi/EvalWiFiGround.h" #include "wifi/EvalWiFi.h" #include "wifi/EvalWiFiPaths.h" #include "wifi/EvalWiFiPathMethods.h" #include "plots/PlotErrFunc.h" // build plots for the paper void paperOutputs() { Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap); // show optimization behaviour if (1 == 0) { EvalWiFiConvex eval(map, Settings::fCalib); eval.showParams(); //eval.showPos(); eval.showPosZ(); return; } // show fingerprints as plot if (1 == 0){ EvalWiFiSigStrength sig(Settings::fMap, Settings::fCalib); Plotty* p = new Plotty(map); p->writeCodeTo(Settings::fPathGFX + "compare-wifi-in-out.gp"); p->writeEpsTex(Settings::fPathGFX + "compare-wifi-in-out.tex", K::GnuplotSize(8.6, 4.7)); p->settings.floors = {0}; p->settings.maxZ = 1; p->settings.outlineColor = K::GnuplotColor::fromRGB(170,170,170); p->buildFloorplan(); sig.forPaperNN(p, MACAddress("d8:84:66:4a:23:d0")); p->equalXY(); p->setView(0,0); p->setScale(3.45, 3.45, -0.005, -0.04); p->addRectangleW(Point3(62.5, 24, 0), Point3(72, 35, 0), K::GnuplotColor::fromRGB(0,0,0), 3, true); // small p->addRectangleW(Point3(8.0, 39.75, 0), Point3(72, 43.75, 0), K::GnuplotColor::fromRGB(0,0,0), 3, true); // big p->noFrame(); p->plot(); delete p; } // 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) { #include "bboxes.h" Plotty pt(map); pt.settings.outline = false; pt.buildFloorplan(); // coloring K::GnuplotColor cH = K::GnuplotColor::fromRGB(220,220,220); K::GnuplotColor cO = K::GnuplotColor::fromRGB(0,128,0); K::GnuplotColor cI = K::GnuplotColor::fromRGB(190,190,190); // floor 0 pt.addBBoxes(bboxes0H, cH); pt.addBBoxes(bboxes0O, cO); pt.addBBoxes(bboxes0I, cI); // floor 1 pt.addBBoxes(bboxes1H, cH); pt.addBBoxes(bboxes1O, cO); pt.addBBoxes(bboxes1I, cI); // floor 2 pt.addBBoxes(bboxes2H, cH); // floor 3 pt.addBBoxes(bboxes3H, cH); pt.plot(); int i = 0; (void) i; } // perform varios AP-param optimizations // generate error plot showing the performance of each // save the resulting wifi-models to XML for later re-use during the walk-eval <<<<<< !!!! if (1 == 0) { // // use walks? // std::vector>> calibWalks = { // std::make_pair(Settings::path1a, Settings::GroundTruth::path1), // std::make_pair(Settings::path1b, Settings::GroundTruth::path1), // std::make_pair(Settings::path2a, Settings::GroundTruth::path2), // std::make_pair(Settings::path2b, Settings::GroundTruth::path2), // }; // EvalCompareOpt2 opt1(Settings::fMap, calibWalks); // all combined auto removeNone = [] (const WiFiFingerprint& fp) -> bool {return false;}; // per floor auto only0th = [] (const WiFiFingerprint& fp) -> bool {return std::abs(fp.pos_m.z - (1.3)) > 0.1;}; auto only1st = [] (const WiFiFingerprint& fp) -> bool {return std::abs(fp.pos_m.z - (4+1.3)) > 0.1;}; auto only2nd = [] (const WiFiFingerprint& fp) -> bool {return std::abs(fp.pos_m.z - (4+3.4+1.3)) > 0.1;}; auto only3rd = [] (const WiFiFingerprint& fp) -> bool {return std::abs(fp.pos_m.z - (4+3.4+3.4+1.3)) > 0.1;}; // per bbox #include "bboxes.h" auto only0H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes0H.contains(fp.pos_m);}; auto only0O = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes0O.contains(fp.pos_m);}; auto only0I = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes0I.contains(fp.pos_m);}; auto only1H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes1H.contains(fp.pos_m);}; auto only1O = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes1O.contains(fp.pos_m);}; auto only1I = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes1I.contains(fp.pos_m);}; auto only2H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes2H.contains(fp.pos_m);}; auto only3H = [&] (const WiFiFingerprint& fp) -> bool {return !bboxes3H.contains(fp.pos_m);}; // use fingerprints? EvalCompareOpt2 opt1(Settings::fMap, Settings::fCalib, removeNone); // optimize using all floors EvalCompareOpt2::Result s1 = opt1.fixedPosFixedParamsForAll(); //BREAK; EvalCompareOpt2::Result s2 = opt1.fixedPosOptParamsForAll(); //BREAK; EvalCompareOpt2::Result s3 = opt1.fixedPosOptParamsForEach(); //BREAK; EvalCompareOpt2::Result s4 = opt1.optPosOptParamsForEach(); //BREAK; // optimize per floor EvalCompareOpt2 opt_f0(Settings::fMap, Settings::fCalib, only0th); EvalCompareOpt2::Result sf0 = opt_f0.optPosOptParamsForEach(); EvalCompareOpt2 opt_f1(Settings::fMap, Settings::fCalib, only1st); EvalCompareOpt2::Result sf1 = opt_f1.optPosOptParamsForEach(); EvalCompareOpt2 opt_f2(Settings::fMap, Settings::fCalib, only2nd); EvalCompareOpt2::Result sf2 = opt_f2.optPosOptParamsForEach(); EvalCompareOpt2 opt_f3(Settings::fMap, Settings::fCalib, only3rd); EvalCompareOpt2::Result sf3 = opt_f3.optPosOptParamsForEach(); // optimize per bbox EvalCompareOpt2 opt_0H(Settings::fMap, Settings::fCalib, only0H); EvalCompareOpt2::Result sf0H = opt_0H.optPosOptParamsForEach(); EvalCompareOpt2 opt_0O(Settings::fMap, Settings::fCalib, only0O); EvalCompareOpt2::Result sf0O = opt_0O.optPosOptParamsForEach(); EvalCompareOpt2 opt_0I(Settings::fMap, Settings::fCalib, only0I); EvalCompareOpt2::Result sf0I = opt_0I.optPosOptParamsForEach(); EvalCompareOpt2 opt_1H(Settings::fMap, Settings::fCalib, only1H); EvalCompareOpt2::Result sf1H = opt_1H.optPosOptParamsForEach(); EvalCompareOpt2 opt_1O(Settings::fMap, Settings::fCalib, only1O); EvalCompareOpt2::Result sf1O = opt_1O.optPosOptParamsForEach(); EvalCompareOpt2 opt_1I(Settings::fMap, Settings::fCalib, only1I); EvalCompareOpt2::Result sf1I = opt_1I.optPosOptParamsForEach(); EvalCompareOpt2 opt_2H(Settings::fMap, Settings::fCalib, only2H); EvalCompareOpt2::Result sf2H = opt_2H.optPosOptParamsForEach(); EvalCompareOpt2 opt_3H(Settings::fMap, Settings::fCalib, only3H); EvalCompareOpt2::Result sf3H = opt_3H.optPosOptParamsForEach(); // save models to file s1.model.saveXML(Settings::wifiAllFixed); s2.model.saveXML(Settings::wifiAllOptPar); s3.model.saveXML(Settings::wifiEachOptPar); s4.model.saveXML(Settings::wifiEachOptParPos); sf0.model.saveXML(Settings::wifiEachOptParPos_only0th); sf1.model.saveXML(Settings::wifiEachOptParPos_only1st); sf2.model.saveXML(Settings::wifiEachOptParPos_only2nd); sf3.model.saveXML(Settings::wifiEachOptParPos_only3rd); // fancy combined model WiFiModelPerFloor wmpf(map); wmpf.add(&sf0.model, map->floors[0]); wmpf.add(&sf1.model, map->floors[1]); wmpf.add(&sf2.model, map->floors[2]); wmpf.add(&sf3.model, map->floors[3]); wmpf.saveXML(Settings::wifiEachOptParPos_multimodel); // ultra fancy combined model WiFiModelPerBBox wmbb(map); wmbb.add(&sf0H.model, bboxes0H); wmbb.add(&sf0O.model, bboxes0O); wmbb.add(&sf0I.model, bboxes0I); wmbb.add(&sf1H.model, bboxes1H); wmbb.add(&sf1O.model, bboxes1O); wmbb.add(&sf1I.model, bboxes1I); wmbb.add(&sf2H.model, bboxes2H); wmbb.add(&sf3H.model, bboxes3H); wmbb.saveXML(Settings::wifiEachOptParPos_perBBox); PlotErrFunc pef("\\small{error (dB)}", "\\small{fingerprints (\\%)}"); pef.add("\\small{empiric}", &s1.errSingle); pef.add("\\small{real pos, opt params}", &s2.errSingle); pef.add("\\small{real pos, opt params [per AP]}", &s3.errSingle); pef.add("\\small{opt pos, opt params [per AP]}", &s4.errSingle); pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5)); pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-methods.tex"); pef.writeCodeTo(Settings::fPathGFX + "wifi-opt-error-hist-methods.gp"); pef.getGP() << "set key right bottom width -4 samplen 0.5\n"; pef.getGP() << "set rmargin 0.4\n"; pef.getGP() << "set tmargin 0.4\n"; pef.plot(); int i = 0; (void) i; //return; //sleep(1000); } /** plot wifi eval results */ if (1 == 0) { WiFiFingerprints fps; fps.load(Settings::fCalib); EvalWiFiOptResult eval1(Settings::fMap); eval1.showErrorPerFingerprint(Settings::wifiEachOptParPos, fps); EvalWiFiOptResult eval2(Settings::fMap); eval2.showErrorPerFingerprint(Settings::wifiAllFixed, fps); // advanced model [1 model per floor] EvalWiFiOptResult evalfloor(Settings::fMap); evalfloor.showErrorPerFingerprint(Settings::wifiEachOptParPos_only0th, fps); evalfloor.showErrorPerFingerprint(Settings::wifiEachOptParPos_only1st, fps); evalfloor.showErrorPerFingerprint(Settings::wifiEachOptParPos_only2nd, fps); evalfloor.showErrorPerFingerprint(Settings::wifiEachOptParPos_only3rd, fps); evalfloor.showErrorPerFingerprint(Settings::wifiEachOptParPos_multimodel, fps); // more advanved model [1 model per bbox-region] EvalWiFiOptResult evalBBox(Settings::fMap); evalBBox.showErrorPerFingerprint(Settings::wifiEachOptParPos_perBBox, fps); int i = 0; (void) i; } // 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); K::Statistics s1 = e1.optPosOptParamsForEach().errAbs; K::Statistics s2 = e2.optPosOptParamsForEach().errAbs; K::Statistics s3 = e3.optPosOptParamsForEach().errAbs; K::Statistics 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); pef.getGP().setTerminal("epslatex", K::GnuplotSize(8.5, 5)); pef.getGP().setOutput(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.tex"); pef.writeCodeTo(Settings::fPathGFX + "wifi-opt-error-hist-stair-outdoor.gp"); pef.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); } } void testWAF() { Floorplan::Ceilings ceilings; ceilings.addCeiling(3); ceilings.addCeiling(6); ceilings.addCeiling(9); ceilings.addCeiling(12); K::Gnuplot gp; K::GnuplotPlot gplot; K::GnuplotPlotElementLines lines; gplot.add(&lines); const Point3 posAP(0, 0, 8); for (float z = 0; z < 15; z += 0.1) { const Point3 posMe(0, 0, z); float factor = ceilings.numCeilingsBetweenFloat(posAP, posMe); lines.add({z, factor}); } gp.draw(gplot); gp.flush(); sleep(1000); } void showFingerprintsFor(const std::string& mapFile, const std::string& fpFile, const std::string& smac) { WiFiFingerprints calib(fpFile); VAPGrouper vap(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE); for (WiFiFingerprint& fp : calib.getFingerprints()) { fp.measurements = vap.group(fp.measurements); } const MACAddress mac(smac); Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(mapFile); Plotty p(map); p.buildFloorplan(); std::vector fps = calib.getFingerprintsFor(mac); for (const WiFiFingerprint& fp : fps) { if (fp.measurements.entries.size() != 1) {throw "123";} const float rssi = fp.measurements.entries[0].getRSSI(); const float s = (rssi-100) / (-40 - -100); const Color c = Color::fromHSV(s*100, 255, 255); p.addFloorRect(fp.pos_m, 3, c); } p.plot(); sleep(1); } void showModelFor(const std::string& mapFile, const std::string& modelXml, const std::string& smac) { Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(mapFile); WiFiModelFactory fac(map); WiFiModel* model = fac.loadXML(modelXml); const MACAddress mac(smac); Plotty p(map); p.buildFloorplan(); const float ss = 2.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+1.3); // 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; } } } if (!contained) {continue;} const float rssi = model->getRSSI(mac, pos); const float s = (rssi-100) / (-40 - -100); const Color c = Color::fromHSV(s*100, 255, 255); p.addFloorRect(pos, 3, c); } } } p.plot(); sleep(1); } int main(void) { Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap); //testWAF(); //paperOutputs(); return 0; //showFingerprintsFor(Settings::fMap, Settings::fCalib, "D8:84:66:4A:4A:D0"); //showModelFor(Settings::fMap, Settings::wifiEachOptParPos_multimodel, "D8:84:66:4A:4A:D0"); //showFingerprintsFor(Settings::fMap, Settings::fCalib, "D8:84:66:4A:4A:E0"); //showModelFor(Settings::fMap, Settings::wifiEachOptParPos_multimodel, "D8:84:66:4A:4A:E0"); // calib error in/out if (1 == 0) { // outdoor only bool ignoreStaircases = true; bool ignoreOutdoor = false; bool ignoreIndoor = true; EvalCompareOpt opt1(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor); EvalCompareOpt::Result s1 = opt1.optPosOptParamsForEach(); std::cout << s1.errAbs.asString() << std::endl; // stairs only ignoreStaircases = false; ignoreOutdoor = true; ignoreIndoor = true; EvalCompareOpt opt3(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor); EvalCompareOpt::Result s3 = opt3.optPosOptParamsForEach(); std::cout << s3.errAbs.asString() << std::endl; // indoor only ignoreStaircases = true; ignoreOutdoor = true; ignoreIndoor = false; EvalCompareOpt opt2(Settings::fMap, Settings::fCalib, ignoreStaircases, ignoreOutdoor, ignoreIndoor); EvalCompareOpt::Result s2 = opt2.optPosOptParamsForEach(); std::cout << s2.errAbs.asString() << std::endl; } // prob on ground if (1 == 0) { EvalWiFiGround eval(map, Settings::wifiEachOptParPos_multimodel); //eval.show(Settings::path1a); eval.show(Settings::path2a); int i = 0; (void) i; } // walks if (1 == 0) { Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(Settings::fMap);; EvalWalk walk(map); walk.walk1(); return 0; } // test gps within data files if (1 == 0) { EvalData::dumpGPSforPath(Settings::path1a); BREAK; EvalData::dumpGPSforPath(Settings::path1b); BREAK; EvalData::dumpGPSforPath(Settings::path2a); BREAK; EvalData::dumpGPSforPath(Settings::path2b); BREAK; } // eval average signal-strength per AP if (1 == 0) { EvalWiFiSigStrength ewss(Settings::fMap, Settings::fCalib); ewss.perAP_avg(); } // test wifi within data files if (1 == 0) { //EvalWiFi ew1(Settings::fMap, Settings::path1a, Settings::GroundTruth::path1); EvalWiFi ew1(Settings::fMap, Settings::path1a, Settings::GroundTruth::path1); //ew1.fixedParams(-40, 2.5, -8); BREAK; //ew1.fixedParams(-64.5905, 1.25988, -2.47863); BREAK; //ew1.fixedParams(-59.4903,1.52411,-3.25077); BREAK; //ew1.load(Settings::wifiEachOptParPos); ew1.load(Settings::wifiAllFixed, "empirc"); //ew1.load(Settings::wifiAllOptPar, "opt params all APs"); //ew1.load(Settings::wifiEachOptPar, "opt params each AP"); ew1.load(Settings::wifiEachOptParPos, "normal model"); ew1.load(Settings::wifiEachOptParPos_multimodel, "model per floor"); ew1.load(Settings::wifiEachOptParPos_perBBox, "model per region"); //ew1.load(Settings::wifiEachOptParPos_only1st, "everything opt"); //ew1.writeTeX("path1"); sleep(1000); } if (1 == 1) { std::vector files = { Settings::path1a, Settings::path1b, Settings::path2a, Settings::path2b, Settings::path_toni_all_1a, Settings::path_toni_all_1b, Settings::path_toni_all_2a, Settings::path_toni_all_2b, Settings::path_toni_inst_1a, Settings::path_toni_inst_1b, Settings::path_toni_inst_2a, Settings::path_toni_inst_2b, Settings::path_toni_inst_3a, Settings::path_toni_inst_3b, }; std::vector> gtIndices = { Settings::GroundTruth::path1, Settings::GroundTruth::path1, Settings::GroundTruth::path2, Settings::GroundTruth::path2, Settings::GroundTruth::path_toni_all_1, Settings::GroundTruth::path_toni_all_1, Settings::GroundTruth::path_toni_all_2, Settings::GroundTruth::path_toni_all_2, Settings::GroundTruth::path_toni_inst_1, Settings::GroundTruth::path_toni_inst_1, Settings::GroundTruth::path_toni_inst_2, Settings::GroundTruth::path_toni_inst_2, Settings::GroundTruth::path_toni_inst_3, Settings::GroundTruth::path_toni_inst_3, }; // EvalWiFiPaths ewp(Settings::fMap); // ewp.loadModel(Settings::wifiAllFixed, "empirc"); // ewp.walks(files, gtIndices); // ewp.loadModel(Settings::wifiEachOptParPos, "normal model"); // ewp.walks(files, gtIndices); // ewp.loadModel(Settings::wifiEachOptParPos_multimodel, "model per floor"); // ewp.walks(files, gtIndices); // ewp.loadModel(Settings::wifiEachOptParPos_perBBox, "model per region"); // ewp.walks(files, gtIndices); EvalWiFiPathMethods ewpm(Settings::fMap); ewpm.loadModel(Settings::wifiEachOptParPos_perBBox, "model per region", "original", "alternative"); ewpm.walks(files, gtIndices); // export for paper // using errFuncOtherExponential and only path1a, path1b //ewpm.writeGP(Settings::fPathGFX, "normalVsExp"); sleep(10000); } // run earthmapping //testMapEarthReg(fMap); if (1 == 0) { EvalApOpt eval(Settings::fMap, Settings::fCalib); eval.optAll(); } // 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); 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(); } // compare leaving out fingerprints 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); K::Statistics s1 = e1.optPosOptParamsForEach().errAbs; K::Statistics s2 = e2.optPosOptParamsForEach().errAbs; K::Statistics s3 = e3.optPosOptParamsForEach().errAbs; K::Statistics s4 = e4.optPosOptParamsForEach().errAbs; PlotErrFunc pef("error (dB)", "fingerprints (%)"); pef.add("floor + stairs + out", &s1); pef.add("floor + out", &s2); pef.add("floor + stairs", &s3); pef.add("floor", &s4); pef.plot(); } }