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/VAPGrouper.h
kazu 06e0e0a5aa fixed some potential issues with MAC addresses
added corresponding test-cases
switched to newer version of tinyxml due to some issues
adjusted affected code-parts accordingly
for better re-use, moved ceiling-calculation to a new class
some minor fixes
new helper methods
worked on wifi-opt
2017-03-20 11:19:57 +01:00

189 lines
4.4 KiB
C++

#ifndef VAPGROUPER_H
#define VAPGROUPER_H
#include <vector>
#include <unordered_map>
#include <cmath>
#include "../../math/Stats.h"
#include "../../misc/Debug.h"
#include "WiFiMeasurements.h"
class VAPGrouper {
public:
/** the mode denotes the algorithm that is used for grouping VAPs together */
enum class Mode {
/** do NOT group */
DISABLED,
/** group VAPs by setting the MAC's last digit to zero */
LAST_MAC_DIGIT_TO_ZERO,
};
/** describes how to calculate the final signal-strengh of the VAP-grouped entry */
enum class Aggregation {
/** use the average signal-strength of all grouped APs */
AVERAGE,
/** use the median signal-strength of all grouped APs */
MEDIAN,
/** use the maximum signal-strength of all grouped APs */
MAXIMUM,
};
private:
static constexpr const char* name = "VAPGrp";
/** the mode to use for grouping VAPs */
const Mode mode;
/** the signal-strength aggregation algorithm to use */
const Aggregation agg;
public:
/** ctor */
VAPGrouper(const Mode mode, const Aggregation agg) : mode(mode), agg(agg) {
}
/** get a vap-grouped version of the given input */
WiFiMeasurements group(const WiFiMeasurements& original) const {
// first, group all VAPs into a vector [one vector per VAP-group]
std::unordered_map<MACAddress, std::vector<WiFiMeasurement>> grouped;
for (const WiFiMeasurement& m : original.entries) {
// the vap-base-mac this entry belongs to
const MACAddress baseMAC = getBaseMAC(m.getAP().getMAC());
grouped[baseMAC].push_back(m);
}
// output
WiFiMeasurements result;
// perform aggregation on each VAP-group
for (auto it : grouped) {
const MACAddress& base = it.first;
const std::vector<WiFiMeasurement>& vaps = it.second;
// group all VAPs into one measurement
const WiFiMeasurement groupedMeasurement = groupVAPs(base, vaps);
// add it to the result-vector
result.entries.push_back(groupedMeasurement);
}
Log::add(name, "grouped " + std::to_string(original.entries.size()) + " measurements into " + std::to_string(result.entries.size()), true);
// done
return result;
}
/** get the VAP-base-MAC-Address that is the same for all APs that belong to a VAP-Group */
MACAddress getBaseMAC(const MACAddress& mac) const {
switch(mode) {
case Mode::DISABLED: return mac;
case Mode::LAST_MAC_DIGIT_TO_ZERO: return lastMacDigitToZero(mac);
default: throw Exception("unsupported vap-grouping mode given");
}
}
private:
/** combine all of the given VAPs into one entry using the configured aggregation method */
WiFiMeasurement groupVAPs(const MACAddress& baseMAC, const std::vector<WiFiMeasurement>& vaps) const {
// the resulting entry is an AP with the base-MAC all of the given VAPs have in common
const AccessPoint baseAP(baseMAC);
// the resultign timestamp
const Timestamp baseTS = vaps.front().getTimestamp();
// calculate the rssi using the configured aggregate function
float rssi = NAN;
switch(agg) {
case Aggregation::AVERAGE: rssi = getAVG(vaps); break;
case Aggregation::MEDIAN: rssi = getMedian(vaps); break;
case Aggregation::MAXIMUM: rssi = getMax(vaps); break;
default: throw Exception("unsupported vap-aggregation method");
}
// create the result measurement
return WiFiMeasurement(baseAP, rssi, baseTS);
}
private:
/** get the average signal strength */
inline float getAVG(const std::vector<WiFiMeasurement>& vaps) const {
float rssi = 0;
for (const WiFiMeasurement& vap : vaps) {
rssi += vap.getRSSI();
}
return rssi / vaps.size();
}
/** get the median signal strength */
inline float getMedian(const std::vector<WiFiMeasurement>& vaps) const {
Stats::Median<float> median;
for (const WiFiMeasurement& vap : vaps) {
median.add(vap.getRSSI());
}
return median.get();
}
/** get the maximum signal strength */
inline float getMax(const std::vector<WiFiMeasurement>& vaps) const {
Stats::Maximum<float> max;
for (const WiFiMeasurement& vap : vaps) {
max.add(vap.getRSSI());
}
return max.get();
// float max = -9999999;
// for (const WiFiMeasurement& vap : vaps) {
// if (vap.getRSSI() > max) {max = vap.getRSSI();}
// }
// return max;
}
private:
/** convert the MAC by setting the last (right-most) digit to zero (0) */
static inline MACAddress lastMacDigitToZero(const MACAddress& mac) {
std::string str = mac.asString();
str.back() = '0';
return MACAddress(str);
}
};
#endif // VAPGROUPER_H