#pragma once #include #include #include #include #include #include #include "Settings.h" static std::string timeForFilename(const std::time_t& time) { std::stringstream ss; ss << std::put_time(std::localtime(&time), "%F_%T"); // ISO 8601 without timezone information. auto s = ss.str(); std::replace(s.begin(), s.end(), ':', '-'); return s; } static std::string currentTimeForFilename() { auto time = std::time(nullptr); return timeForFilename(time); } static std::filesystem::path appendCurrentTimeToFilename(const std::filesystem::path& fileName) { return fileName.stem().string() + "_" + currentTimeForFilename() + fileName.extension().string(); } template inline std::filesystem::path appendFileSuffixToPath(const std::filesystem::path& path, T value) { std::string filename = path.stem().string() + "_" + std::to_string(value) + path.extension().string(); return path.parent_path() / filename; } static bool forceDirectories(const std::filesystem::path& path) { if (!std::filesystem::exists(path)) { return std::filesystem::create_directories(path); } return true; } template std::vector asVector(const std::array& src) { std::vector result; result.assign(src.begin(), src.end()); return result; } struct WifiMeas { Timestamp ts; std::array ftmDists; std::array rssiDists; WifiMeas() : ts(Timestamp::fromMS(0)), ftmDists{ NAN, NAN, NAN, NAN }, rssiDists{ NAN, NAN, NAN, NAN } { } int numSucessMeas() const { int count = 0; if (!std::isnan(ftmDists[0])) count++; if (!std::isnan(ftmDists[1])) count++; if (!std::isnan(ftmDists[2])) count++; if (!std::isnan(ftmDists[3])) count++; return count; } }; template struct CombinedStats { Stats::Statistics ftm; Stats::Statistics rssi; }; template void printErrorStats(std::ostream& stream, const CombinedStats& errorStats) { stream << "Walk error:" << "\n"; stream << "[m] " << std::setw(10) << "mean" << std::setw(10) << "stdDev" << std::setw(10) << "median" << std::setw(10) << "count" << "\n"; stream << "FTM " << std::setw(10) << errorStats.ftm.getAvg() << std::setw(10) << errorStats.ftm.getStdDev() << std::setw(10) << errorStats.ftm.getMedian() << std::setw(10) << errorStats.ftm.getCount() << "\n"; stream << "RSSI " << std::setw(10) << errorStats.rssi.getAvg() << std::setw(10) << errorStats.rssi.getStdDev() << std::setw(10) << errorStats.rssi.getMedian() << std::setw(10) << errorStats.rssi.getCount() << "\n"; stream << std::endl; } template void printErrorStats(const CombinedStats& errorStats) { return printErrorStats(std::cout, errorStats); } static std::vector filterOfflineData(const Offline::FileReader& fr) { std::vector result; WifiMeas currentItem; // parse each sensor-value within the offline data for (const Offline::Entry& e : fr.getEntries()) { if (e.type != Offline::Sensor::WIFI_FTM) { continue; } // TIME const Timestamp ts = Timestamp::fromMS(e.ts); // init last ts if (currentItem.ts.isZero()) { currentItem.ts = ts; } // new time step? if ((ts - currentItem.ts) > Timestamp::fromMS(10)) { result.push_back(currentItem); currentItem = {}; } currentItem.ts = ts; // DISTANCE auto ftm = fr.getWifiFtm()[e.idx].data; const MACAddress& mac = ftm.getAP().getMAC(); float ftm_offset = Settings::CurrentPath.NUCs.at(mac).ftm_offset; float ftmDist = ftm.getFtmDist() + ftm_offset; // in m; plus static offset float rssi_pathloss = Settings::CurrentPath.NUCs.at(mac).rssi_pathloss; float rssiDist = LogDistanceModel::rssiToDistance(-40, rssi_pathloss, ftm.getRSSI()); int nucIndex = Settings::nucIndex(mac); currentItem.ftmDists[nucIndex] = ftmDist; currentItem.rssiDists[nucIndex] = rssiDist; } return result; } struct CmdArguments { std::string executableFilename; std::vector arguments; CmdArguments() { } CmdArguments(int argc, char** argv) { if (argc > 0) { executableFilename = std::string(argv[0]); for (size_t i = 1; i < argc; i++) { arguments.push_back(std::string(argv[i])); } } } bool hasFlag(const std::string& arg) const { return std::find(arguments.begin(), arguments.end(), arg) != arguments.end(); } };