had to change the parameter boundaries of the wifi optimizer to be able to use it for bluetooth... this should be refactored to something more generic.. some minor changes in ble
104 lines
3.4 KiB
C++
104 lines
3.4 KiB
C++
#ifndef BEACONFINGERPRINT_H
|
|
#define BEACONFINGERPRINT_H
|
|
|
|
#include "../../../geo/Point3.h"
|
|
#include "../BeaconMeasurements.h"
|
|
|
|
#include <unordered_map>
|
|
|
|
/**
|
|
* denotes a beacon fingerprint:
|
|
* known position and 1-n measurements [ble-advertisment-scan on all channels] conducted at this position
|
|
*
|
|
* if more than one measurement is conducted, each AP is contained more than once!
|
|
*/
|
|
struct BeaconFingerprint {
|
|
|
|
|
|
/** real-world-position that was measured */
|
|
Point3 pos_m;
|
|
|
|
/** seen APs at the given location */
|
|
BeaconMeasurements measurements;
|
|
|
|
/** ctor */
|
|
BeaconFingerprint() {;}
|
|
|
|
/** ctor */
|
|
BeaconFingerprint(const Point3 pos_m) : pos_m(pos_m) {;}
|
|
|
|
/** ctor */
|
|
BeaconFingerprint(const Point3 pos_m, const BeaconMeasurements& measurements) : pos_m(pos_m), measurements(measurements) {;}
|
|
|
|
|
|
/** as each AP might be contained more than once (scanned more than once), group them by MAC and use the average RSSI */
|
|
BeaconMeasurements average() {
|
|
|
|
// group scans by MAC (all measurements for one AP)
|
|
std::unordered_map<MACAddress, BeaconMeasurements> group;
|
|
for (BeaconMeasurement& bm : measurements.entries) {
|
|
group[bm.getBeacon().getMAC()].entries.push_back(bm);
|
|
}
|
|
|
|
// create the output that contains the AP's average
|
|
BeaconMeasurements res;
|
|
for (auto& it : group) {
|
|
const BeaconMeasurements& apMeasurements = it.second;
|
|
BeaconMeasurement avg = apMeasurements.entries.front(); // average starts with a copy of the first entry (to get all data-fields beside the rssi)
|
|
for (int i = 1; i < (int)apMeasurements.entries.size(); ++i) { // sum up all other entries [1:end]
|
|
avg.setRssi(avg.getRSSI() + apMeasurements.entries[i].getRSSI());
|
|
}
|
|
avg.setRssi(avg.getRSSI() / apMeasurements.entries.size());
|
|
res.entries.push_back(avg); // add to output
|
|
}
|
|
|
|
// done
|
|
return res;
|
|
|
|
}
|
|
|
|
/** get all measurements for the given MAC */
|
|
std::vector<BeaconMeasurement> getAllForMAC(const MACAddress& mac) const {
|
|
std::vector<BeaconMeasurement> res;
|
|
for (const BeaconMeasurement& m : measurements.entries) {
|
|
if (m.getBeacon().getMAC() == mac) {res.push_back(m);}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/** serialize */
|
|
void write(std::ostream& out) const {
|
|
out << "pos: " << pos_m.x << " " << pos_m.y << " " << pos_m.z << "\n";
|
|
out << "num: " << measurements.entries.size() << "\n";
|
|
for (const BeaconMeasurement& bm : measurements.entries) {
|
|
out << bm.getTimestamp().ms() << " " << bm.getBeacon().getMAC().asString() << " " << bm.getRSSI() << "\n";
|
|
}
|
|
}
|
|
|
|
/** deserialize */
|
|
void read(std::istream& inp) {
|
|
std::string tmp;
|
|
|
|
// read the position
|
|
inp >> tmp; if ("pos:" != tmp) {throw "error";}
|
|
inp >> pos_m.x >> pos_m.y >> pos_m.z;
|
|
|
|
// number of entries
|
|
inp >> tmp; if ("num:" != tmp) {throw "error";}
|
|
int numEntries; inp >> numEntries;
|
|
|
|
// read the entries
|
|
for (int i = 0; i < numEntries; ++i) {
|
|
uint64_t ms; inp >> ms;
|
|
std::string mac; inp >> mac;
|
|
float rssi; inp >> rssi;
|
|
BeaconMeasurement bm(Timestamp::fromMS(ms), Beacon(MACAddress(mac)), rssi);
|
|
measurements.entries.push_back(bm);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
|
|
#endif // BEACONFINGERPRINT_H
|