180 lines
4.8 KiB
C++
180 lines
4.8 KiB
C++
#pragma once
|
|
|
|
#include <array>
|
|
#include <vector>
|
|
|
|
#include <Indoor/math/stats/Statistics.h>
|
|
|
|
|
|
#include <Indoor/data/Timestamp.h>
|
|
#include <Indoor/sensors/offline/FileReader.h>
|
|
#include <Indoor/sensors/radio/model/LogDistanceModel.h>
|
|
|
|
#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<typename T>
|
|
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<typename T, int Size>
|
|
std::vector<T> asVector(const std::array<T, Size>& src)
|
|
{
|
|
std::vector<T> result;
|
|
result.assign(src.begin(), src.end());
|
|
return result;
|
|
}
|
|
|
|
struct WifiMeas {
|
|
Timestamp ts;
|
|
std::array<float, 4> ftmDists;
|
|
std::array<float, 4> rssiDists;
|
|
|
|
WifiMeas()
|
|
: ts(Timestamp::fromMS(0)), ftmDists{ NAN, NAN, NAN, NAN }, rssiDists{ NAN, NAN, NAN, NAN }
|
|
{ }
|
|
|
|
int numSucessMeas() const {
|
|
int count = 0;
|
|
|
|
if (!isnan(ftmDists[0])) count++;
|
|
if (!isnan(ftmDists[1])) count++;
|
|
if (!isnan(ftmDists[2])) count++;
|
|
if (!isnan(ftmDists[3])) count++;
|
|
|
|
return count;
|
|
}
|
|
|
|
};
|
|
|
|
template<typename T>
|
|
struct CombinedStats {
|
|
Stats::Statistics<T> ftm;
|
|
Stats::Statistics<T> rssi;
|
|
};
|
|
|
|
template<typename T>
|
|
void printErrorStats(std::ostream& stream, const CombinedStats<T>& 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<typename T>
|
|
void printErrorStats(const CombinedStats<T>& errorStats)
|
|
{
|
|
return printErrorStats(std::cout, errorStats);
|
|
}
|
|
|
|
|
|
static std::vector<WifiMeas> filterOfflineData(const Offline::FileReader& fr)
|
|
{
|
|
std::vector<WifiMeas> 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<std::string> 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();
|
|
}
|
|
}; |