#ifndef WIFIQUALITYANALYZER_H #define WIFIQUALITYANALYZER_H #include "WiFiMeasurements.h" #include #ifdef WITH_DEBUG_PLOT #include #include #include #endif class WiFiQualityAnalyzer { private: int historySize = 3; std::vector history; float quality = 0; #ifdef WITH_DEBUG_PLOT K::Gnuplot gp; K::GnuplotPlot plot; K::GnuplotPlotElementLines line1; K::GnuplotPlotElementLines line2; int gpX = 0; #endif public: WiFiQualityAnalyzer() { #ifdef WITH_DEBUG_PLOT plot.add(&line1); plot.add(&line2); plot.setTitle("WiFi Quality"); #endif } /** attach the current measurement and infer the quality */ void add(const WiFiMeasurements& mes) { // update the history history.push_back(mes); while(history.size() > historySize) { history.erase(history.begin()); } // recalculate update(); } /** get a quality score for the WiFi */ float getQuality() const { return quality; } private: /** re-calculate the current quality */ void update() { const float qCnt = getQualityByCount(); const float qAvgdB = getQualityByAvgDB(); quality = qAvgdB; #ifdef WITH_DEBUG_PLOT line1.add(K::GnuplotPoint2(gpX,qAvgdB)); line1.setTitle("dB"); line1.getStroke().setWidth(2); line2.add(K::GnuplotPoint2(gpX,qCnt)); line2.setTitle("visible"); while(line1.size() > 50) {line1.remove(0);} while(line2.size() > 50) {line2.remove(0);} ++gpX; gp.draw(plot); gp.flush(); #endif } /** score [0:1] based on the average sig-strength. the higher the better */ float getQualityByAvgDB() const { // stats float sum = 0; float sum2 = 0; float cnt = 0; for (const WiFiMeasurements& mes : history) { for (const WiFiMeasurement& m : mes.entries) { const float rssi = m.getRSSI(); sum += rssi; sum2 += rssi*rssi; ++cnt; } } // average sig strength const float avg = sum/cnt; const float avg2 = sum2/cnt; const float stdDev = std::sqrt(avg2 - avg*avg); // avg rssi score const float minRSSI = -85; const float maxRSSI = -70; float score1 = (avg-minRSSI) / (maxRSSI-minRSSI); // min = 0; max = 1 if (score1 > 1) {score1 = 1;} if (score1 < 0) {score1 = 0;} //const float score1 = 1.0 - std::exp(-0.07 * (avg-minRSSI)); // std dev score const float score2 = 1.0 - std::exp(-1.0 * stdDev); return score1 * score2; } /** quality score [0:1] according to the number of seen APs */ float getQualityByCount() const { // distinct macs std::unordered_set macs; for (const WiFiMeasurements& mes : history) { for (const WiFiMeasurement& m : mes.entries) { macs.insert(m.getAP().getMAC()); } } // number of distinct macs const int cnt = macs.size(); // see function plot. function between [0.0:1.0] has 0.5 around 7 seen APs return 1.0 - std::exp(-0.1 * cnt); } }; #endif // WIFIQUALITYANALYZER_H