This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/sensors/radio/WiFiQualityAnalyzer.h
2018-10-25 11:50:12 +02:00

150 lines
3.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © Copyright 2014 Urheberrechtshinweis
* Alle Rechte vorbehalten / All Rights Reserved
*
* Programmcode ist urheberrechtlich geschuetzt.
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
* Keine Verwendung ohne explizite Genehmigung.
* (vgl. § 106 ff UrhG / § 97 UrhG)
*/
#ifndef WIFIQUALITYANALYZER_H
#define WIFIQUALITYANALYZER_H
#include "WiFiMeasurements.h"
#include <unordered_set>
#ifdef WITH_DEBUG_PLOT
#include <KLib/misc/gnuplot/Gnuplot.h>
#include <KLib/misc/gnuplot/GnuplotPlot.h>
#include <KLib/misc/gnuplot/GnuplotPlotElementLines.h>
#endif
class WiFiQualityAnalyzer {
private:
int historySize = 3;
std::vector<WiFiMeasurements> 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<MACAddress> 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