#ifndef BEACONFINGERPRINT_H #define BEACONFINGERPRINT_H #include "../../../geo/Point3.h" #include "../BeaconMeasurements.h" #include /** * denotes a wifi fingerprint: * known position and 1-n measurements [wifi-scan on all channels] conducted at this position * * if more than one measurement is conducted, each AP is contained more than once! */ struct WiFiFingerprint { /** real-world-position that was measured */ Point3 pos_m; /** seen APs at the given location */ BeaconMeasurements measurements; /** ctor */ WiFiFingerprint() {;} /** ctor */ WiFiFingerprint(const Point3 pos_m) : pos_m(pos_m) {;} /** ctor */ WiFiFingerprint(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 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 getAllForMAC(const MACAddress& mac) const { std::vector 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