//#include "main.h" #include "navMesh/mesh.h" #include "navMesh/filter.h" #include "Settings.h" #include "navMesh/meshPlotter.h" #include "Plotty.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Stats::Statistics run(Settings::DataSetup setup, int numFile, std::string folder) { // reading file Floorplan::IndoorMap* map = Floorplan::Reader::readFromFile(setup.map); Offline::FileReader fr(setup.training[numFile]); WiFiFingerprints fingerprints(setup.fingerprints); std::ifstream inp(setup.wifiModel, std::ifstream::binary); // ground truth std::vector gtPath; for(int i = 0; i < setup.numGTPoints; ++i){gtPath.push_back(i);} Interpolator gtInterpolator = fr.getGroundTruthPath(map, gtPath); Stats::Statistics errorStats; //calculate distance of path std::vector::InterpolatorEntry> gtEntries = gtInterpolator.getEntries(); double distance = 0; for(int i = 1; i < gtEntries.size(); ++i){ distance += gtEntries[i].value.getDistance(gtEntries[i-1].value); } std::cout << "Distance of Path: " << distance << std::endl; // error file const long int t = static_cast(time(NULL)); auto evalDir = std::experimental::filesystem::path(Settings::errorDir); evalDir.append(folder); if (!std::experimental::filesystem::exists(evalDir)) { std::experimental::filesystem::create_directory(evalDir); } std::ofstream errorFile; errorFile.open (evalDir.string() + "/" + std::to_string(numFile) + "_" + std::to_string(t) + ".csv"); // wifi // WiFiModelLogDistCeiling WiFiModel(map); // WiFiModelPerFloor WiFiModelPerFloor(map); // WiFiModelPerBBox WiFiModelPerBBox(map); WiFiModel* wifiModel = nullptr; // with optimization if(Settings::WiFiModel::optimize){ if (!inp.good() || (inp.peek()&&0) || inp.eof()) { Assert::isFalse(fingerprints.getFingerprints().empty(), "no fingerprints available!"); if (Settings::WiFiModel::useRegionalOpt) { // use a regional optimization scheme (one per floor) WiFiOptimizer::PerFloor opt(map, Settings::WiFiModel::vg_calib, WiFiOptimizer::Mode::QUALITY); WiFiOptimizer::LogDistCeiling ldc(map, Settings::WiFiModel::vg_calib, WiFiOptimizer::Mode::QUALITY); // add all fingerprints to the optimizer (optimizer will add them to the correct floor/model) for (const WiFiFingerprint& fp : fingerprints.getFingerprints()) { opt.addFingerprint(fp); } wifiModel = opt.optimizeAll(ldc.MIN_2_FPS); wifiModel->saveXML(setup.wifiModel); } else { /** NOTE: Funktioniert fürs Museum VIEL VIEL Besser */ // use one model per AP for the whole map wifiModel = new WiFiModelLogDistCeiling(map); WiFiOptimizer::LogDistCeiling opt(map, Settings::WiFiModel::vg_calib); for (const WiFiFingerprint& fp : fingerprints.getFingerprints()) { opt.addFingerprint(fp); } const WiFiOptimizer::LogDistCeiling::APParamsList res = opt.optimizeAll(opt.NONE); for (const WiFiOptimizer::LogDistCeiling::APParamsMAC& ap : res.get()) { const WiFiModelLogDistCeiling::APEntry entry(ap.params.getPos(), ap.params.txp, ap.params.exp, ap.params.waf); ((WiFiModelLogDistCeiling*)wifiModel)->addAP(ap.mac, entry); } wifiModel->saveXML(setup.wifiModel); } } else { // load WiFiModel from file. The factory will create the correct instance //WiFiModel->loadXML(setup.wifiModel); WiFiModelFactory fac(map); wifiModel = fac.loadXML(setup.wifiModel); } } else { // without optimization wifiModel = new WiFiModelLogDistCeiling(map); ((WiFiModelLogDistCeiling*)wifiModel)->loadAPs(map, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF); Assert::isFalse(wifiModel->getAllAPs().empty(), "no AccessPoints stored within the map.xml"); } // mesh NM::NavMeshSettings set; MyNavMesh mesh; MyNavMeshFactory fac(&mesh, set); fac.build(map); const Point3 srcPath0(26, 43, 7.5); const Point3 srcPath1(62, 38, 1.7); const Point3 srcPath2(62, 38, 1.8); const Point3 srcPath3(62, 38, 1.8); // add shortest-path to destination //const Point3 dst(51, 45, 1.7); //const Point3 dst(25, 45, 0); //NM::NavMeshDijkstra::stamp(mesh, dst); // debug show //MeshPlotter dbg; //dbg.addFloors(map); //dbg.addOutline(map); //dbg.addMesh(mesh); //dbg.addDijkstra(mesh); //dbg.draw(); Plotty plot(map); plot.buildFloorplan(); plot.setGroundTruth(gtPath); // particle-filter const int numParticles = 5000; //auto init = std::make_unique(&mesh, srcPath1); // known position auto init = std::make_unique(&mesh); // uniform distribution auto eval = std::make_unique(*wifiModel); auto trans = std::make_unique(mesh, *wifiModel); //auto resample = std::make_unique>(); auto resample = std::make_unique>(&mesh, Settings::KDE3D::gridSize, Settings::KDE3D::bandwidth); //auto resample = std::make_unique>(); //auto resample = std::make_unique>(); //auto estimate = std::make_unique>(map, 0.2, Point2(1,1)); auto estimate = std::make_unique>(); //auto estimate = std::make_unique>(); // setup MyFilter pf(numParticles, std::move(init)); pf.setEvaluation(std::move(eval)); pf.setTransition(std::move(trans)); pf.setResampling(std::move(resample)); pf.setEstimation(std::move(estimate)); pf.setNEffThreshold(0.85); // sensors MyControl ctrl; MyObservation obs; StepDetection sd; PoseDetection pd; TurnDetection td(&pd); RelativePressure relBaro; ActivityDetector act; relBaro.setCalibrationTimeframe( Timestamp::fromMS(5000) ); Timestamp lastTimestamp = Timestamp::fromMS(0); int i = 0; // parse each sensor-value within the offline data for (const Offline::Entry& e : fr.getEntries()) { const Timestamp ts = Timestamp::fromMS(e.ts); if (e.type == Offline::Sensor::WIFI) { obs.wifi = fr.getWiFiGroupedByTime()[e.idx].data; ctrl.wifi = fr.getWiFiGroupedByTime()[e.idx].data; } else if (e.type == Offline::Sensor::ACC) { if (sd.add(ts, fr.getAccelerometer()[e.idx].data)) { ++ctrl.numStepsSinceLastEval; } const Offline::TS& _acc = fr.getAccelerometer()[e.idx]; pd.addAccelerometer(ts, _acc.data); //simpleActivity walking / standing act.add(ts, fr.getAccelerometer()[e.idx].data); } else if (e.type == Offline::Sensor::GYRO) { const Offline::TS& _gyr = fr.getGyroscope()[e.idx]; const float delta_gyro = td.addGyroscope(ts, _gyr.data); ctrl.headingChangeSinceLastEval += delta_gyro; } else if (e.type == Offline::Sensor::BARO) { relBaro.add(ts, fr.getBarometer()[e.idx].data); obs.relativePressure = relBaro.getPressureRealtiveToStart(); obs.sigmaPressure = relBaro.getSigma(); //simpleActivity stairs up / down act.add(ts, fr.getBarometer()[e.idx].data); obs.activity = act.get(); } if (ctrl.numStepsSinceLastEval > 0) { obs.currentTime = ts; ctrl.currentTime = ts; // if(ctrl.numStepsSinceLastEval > 0){ // pf.updateTransitionOnly(&ctrl); // } MyState est = pf.update(&ctrl, obs); //pf.updateEvaluationOnly(obs); ctrl.afterEval(); Point3 gtPos = gtInterpolator.get(static_cast(ts.ms())) + Point3(0,0,0.1); lastTimestamp = ts; ctrl.lastEstimate = est.pos.pos; //plot //dbg.showParticles(pf.getParticles()); //dbg.setCurPos(est.pos.pos); //dbg.setGT(gtPos); //dbg.addEstimationNode(est.pos.pos); //dbg.addGroundTruthNode(gtPos); //dbg.setTimeInMinute(static_cast(ts.sec()) / 60, static_cast(static_cast(ts.sec())%60)); //dbg.draw(); plot.showParticles(pf.getParticles()); plot.setCurEst(est.pos.pos); plot.setGroundTruth(gtPos); plot.addEstimationNode(est.pos.pos); plot.setActivity((int) act.get()); plot.plot(); // error calc // float err_m = gtPos.getDistance(est.pos.pos); // errorStats.add(err_m); // errorFile << ts.ms() << " " << err_m << "\n"; //error calc with penalty for wrong floor double errorFactor = 3.0; Point3 gtPosError = Point3(gtPos.x, gtPos.y, errorFactor * gtPos.z); Point3 estError = Point3(est.pos.pos.x, est.pos.pos.y, errorFactor * est.pos.pos.z); float err_m = gtPosError.getDistance(estError); errorStats.add(err_m); errorFile << ts.ms() << " " << err_m << "\n"; //stuff for drawing // plot.gp << "set terminal png size 1280,720\n"; // plot.gp.setOutput("/tmp/videoSparkasse/" + std::to_string(i++) + ".png"); // int degree = ((30 - i) % 360); // if (degree < 0){degree += 360;} // plot.gp << "set view 63,"<< degree << "\n"; // plot.gp << "set autoscale xy\n"; // plot.gp << "set autoscale z\n"; // plot.plot(); } } // get someting on console std::cout << "Statistical Analysis Filtering: " << std::endl; std::cout << "Median: " << errorStats.getMedian() << " Average: " << errorStats.getAvg() << " Std: " << errorStats.getStdDev() << std::endl; // save the statistical data in file errorFile << "========================================================== \n"; errorFile << "Average of all statistical data: \n"; errorFile << "Median: " << errorStats.getMedian() << "\n"; errorFile << "Average: " << errorStats.getAvg() << "\n"; errorFile << "Standard Deviation: " << errorStats.getStdDev() << "\n"; errorFile << "75 Quantil: " << errorStats.getQuantile(0.75) << "\n"; errorFile.close(); /* plot in gp file */ std::ofstream plotFile; plotFile.open(evalDir.string() + "/" + std::to_string(numFile) + "_" + std::to_string(t) + ".gp"); plot.saveToFile(plotFile); plotFile.close(); //save also a png image, just for a better overview plot.printOverview(evalDir.string() + "/" + std::to_string(numFile) + "_" + std::to_string(t)); plot.plot(); plot.closeStream(); // //save file for radius_sub // std::ofstream radiusFile; // radiusFile.open(evalDir.string() + "/" + std::to_string(numFile) + "_" + std::to_string(t) + "_radius.csv"); // //provide the maximum value for radius_sub (kld * wifiquality) // double max = *std::max_element(((MyPFTrans*) pf.getTransition())->listRadiusSub.begin() , ((MyPFTrans*) pf.getTransition())->listRadiusSub.end()); // std::cout << "Max Value radius_sub: " << max << std::endl; // double sum = 0; // int pos = ((MyPFTrans*) pf.getTransition())->listRadiusSub.size() * 0.75; // double quantilValue = 0; // int num = 0; // for(double val : ((MyPFTrans*) pf.getTransition())->listRadiusSub){ // sum += val; // if(num == pos){quantilValue = val;} // ++num; // radiusFile << val << "\n"; // } // double avg = sum / num; // std::cout << "Average radius_sub: " << avg << std::endl; // std::cout << "75 Quantil radius_sub: " << quantilValue << std::endl; // radiusFile.close(); return errorStats; } int main(int argc, char** argv) { Stats::Statistics statsAVG; Stats::Statistics statsMedian; Stats::Statistics statsSTD; Stats::Statistics statsQuantil; Stats::Statistics tmp; std::string evaluationName = "museum/tmp"; for(int i = 0; i < 1; ++i){ //TODO: in transition die distance über KLD noch einkommentieren als Test // for(int j = 0; j < Settings::data.Path0.training.size(); ++j){ // tmp = run(Settings::data.Path0, j, evaluationName); // statsMedian.add(tmp.getMedian()); // statsAVG.add(tmp.getAvg()); // statsSTD.add(tmp.getStdDev()); // statsQuantil.add(tmp.getQuantile(0.75)); // } // for(int j = 0; j < Settings::data.Path1.training.size(); ++j){ // tmp = run(Settings::data.Path1, j, evaluationName); // statsMedian.add(tmp.getMedian()); // statsAVG.add(tmp.getAvg()); // statsSTD.add(tmp.getStdDev()); // statsQuantil.add(tmp.getQuantile(0.75)); // } // for(int j = 0; j < Settings::data.Path2.training.size(); ++j){ // tmp = run(Settings::data.Path2, j, evaluationName); // statsMedian.add(tmp.getMedian()); // statsAVG.add(tmp.getAvg()); // statsSTD.add(tmp.getStdDev()); // statsQuantil.add(tmp.getQuantile(0.75)); // } for(int j = 0; j < 1; ++j){ tmp = run(Settings::data.Path3, j, evaluationName); statsMedian.add(tmp.getMedian()); statsAVG.add(tmp.getAvg()); statsSTD.add(tmp.getStdDev()); statsQuantil.add(tmp.getQuantile(0.75)); } std::cout << "Iteration " << i << " completed" << std::endl;; } std::cout << "==========================================================" << std::endl; std::cout << "Average of all statistical data: " << std::endl; std::cout << "Median: " << statsMedian.getAvg() << std::endl; std::cout << "Average: " << statsAVG.getAvg() << std::endl; std::cout << "Standard Deviation: " << statsSTD.getAvg() << std::endl; std::cout << "75 Quantil: " << statsQuantil.getAvg() << std::endl; std::cout << "==========================================================" << std::endl; //EDIT THIS EDIT THIS EDIT THIS EDIT THIS EDIT THIS EDIT THIS EDIT THIS EDIT THIS std::ofstream finalStatisticFile; finalStatisticFile.open (Settings::errorDir + evaluationName + ".csv", std::ios_base::app); finalStatisticFile << "========================================================== \n"; finalStatisticFile << "Average of all statistical data: \n"; finalStatisticFile << "Median: " << statsMedian.getAvg() << "\n"; finalStatisticFile << "Average: " << statsAVG.getAvg() << "\n"; finalStatisticFile << "Standard Deviation: " << statsSTD.getAvg() << "\n"; finalStatisticFile << "75 Quantil: " << statsQuantil.getAvg() << "\n"; finalStatisticFile << "========================================================== \n"; finalStatisticFile.close(); //std::this_thread::sleep_for(std::chrono::seconds(60)); }