huge commit
- worked on about everything - grid walker using plugable modules - wifi models - new distributions - worked on geometric data-structures - added typesafe timestamps - worked on grid-building - added sensor-classes - added sensor analysis (step-detection, turn-detection) - offline data reader - many test-cases
This commit is contained in:
172
sensors/radio/VAPGrouper.h
Normal file
172
sensors/radio/VAPGrouper.h
Normal file
@@ -0,0 +1,172 @@
|
||||
#ifndef VAPGROUPER_H
|
||||
#define VAPGROUPER_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <cmath>
|
||||
|
||||
#include "../../math/Median.h"
|
||||
|
||||
#include "WiFiMeasurements.h"
|
||||
|
||||
class VAPGrouper {
|
||||
|
||||
public:
|
||||
|
||||
/** the mode denotes the algorithm that is used for grouping VAPs together */
|
||||
enum class Mode {
|
||||
|
||||
/** 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:
|
||||
|
||||
/** 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);
|
||||
|
||||
}
|
||||
|
||||
// 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::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 {
|
||||
|
||||
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 {
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user