143 lines
4.0 KiB
C++
143 lines
4.0 KiB
C++
/*
|
||
* © 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 WIFIPROBABILITYGRID_H
|
||
#define WIFIPROBABILITYGRID_H
|
||
|
||
#include <fstream>
|
||
|
||
#include "../../math/distribution/Normal.h"
|
||
#include "../../data/Timestamp.h"
|
||
|
||
#include "WiFiGridNode.h"
|
||
#include "WiFiProbability.h"
|
||
|
||
#include <unordered_set>
|
||
|
||
/**
|
||
* probability is calculated by comparing pre-calculated wifi-signal-strengths
|
||
* attached to each grid-node with a given WiFiMeasurements data structure
|
||
*/
|
||
template <typename Node> class WiFiObserverGrid : public WiFiProbability {
|
||
|
||
|
||
private:
|
||
|
||
/** base-sigma to use for comparison */
|
||
float sigma = 8.0f;
|
||
|
||
/** additional sigma-per-second (measurement age) to*/
|
||
float sigmaPerSecond = 3;
|
||
|
||
std::unordered_set<MACAddress> knownAPs;
|
||
|
||
public:
|
||
|
||
/** ctor with uncertainty */
|
||
WiFiObserverGrid(const float sigma) : sigma(sigma) {
|
||
|
||
//StaticAssert::AinheritsB<Node, WiFiGridNode>();
|
||
|
||
for (const AccessPoint& ap : Node::getMapAPs()) {
|
||
knownAPs.insert(ap.getMAC());
|
||
}
|
||
|
||
Assert::isFalse(knownAPs.empty(), "no APs known to the grid nodes?!");
|
||
|
||
}
|
||
|
||
/**
|
||
* get the given GridNode's probability.
|
||
* compares the predicted signal-strengths stored on the given node
|
||
* with the provided WiFi measurements
|
||
*/
|
||
double getProbability(const Node& n, const Timestamp curTime, const WiFiMeasurements& obs) const {
|
||
|
||
// compile-time sanity check. Node must be a subclass off WiFiGridNode
|
||
//StaticAssert::AinheritsB<Node, WiFiGridNode>();
|
||
|
||
double prob = 1;
|
||
int numMatchingAPs = 0;
|
||
|
||
// after some runtime, check whether the wifi timestamps make sense
|
||
// those must not be zero, otherwise something is wrong!
|
||
if (!obs.entries.empty()) {
|
||
Assert::isFalse(curTime.ms() > 10000 && obs.entries.front().getTimestamp().isZero(), "WiFiMeasurement timestamp is 0. this does not make sense...");
|
||
}
|
||
|
||
// process each observed measurement
|
||
for (const WiFiMeasurement& measurement : obs.entries) {
|
||
|
||
// if an AP is not known to any of the nodes, just skip it
|
||
if (knownAPs.find(measurement.getAP().getMAC()) == knownAPs.end()) {
|
||
continue;}
|
||
|
||
// determine the age for this measurement
|
||
const Timestamp age = curTime - measurement.getTimestamp();
|
||
|
||
// sigma grows with measurement age
|
||
float sigma = this->sigma + this->sigmaPerSecond * age.sec();
|
||
|
||
// the RSSI from the scan
|
||
const float measuredRSSI = measurement.getRSSI();
|
||
|
||
// the RSSI from the model (if available!)
|
||
float modelRSSI = n.getRSSI(measurement.getAP().getMAC());
|
||
|
||
// if no model RSSI is available, that means,
|
||
// the AP in question is not / only barely visible at this location
|
||
// assume a very low signal-strength and increase the sigma
|
||
if (modelRSSI == 0) {
|
||
modelRSSI = -100;
|
||
sigma *= 2;
|
||
}
|
||
|
||
// compare both
|
||
const double p = Distribution::Normal<double>::getProbability(measuredRSSI, sigma, modelRSSI);
|
||
//const double p = Distribution::Region<double>::getProbability(measuredRSSI, sigma, modelRSSI);
|
||
|
||
// adjust using log
|
||
//prob += std::log(p);
|
||
prob *= p;
|
||
|
||
++numMatchingAPs;
|
||
|
||
}
|
||
|
||
// sanity check
|
||
//Assert::isTrue(numMatchingAPs > 0, "not a single measured AP was matched against known ones. coding error? model error?");
|
||
|
||
// as not every node has the same number of visible/matching APs
|
||
// we MUST return something like the average probability
|
||
return prob;
|
||
//return std::pow(prob, 1.0/3.0);
|
||
|
||
}
|
||
|
||
/** gnuplot debug dump */
|
||
void dump(Grid<Node>& grid, const Timestamp curTime, const WiFiMeasurements& obs, const std::string& fileName) {
|
||
|
||
std::ofstream out(fileName);
|
||
out << "splot '-' with points palette\n";
|
||
|
||
for (const Node& n : grid) {
|
||
const float p = getProbability(n, curTime, obs);
|
||
out << n.x_cm << " " << n.y_cm << " " << n.z_cm << " " << p << "\n";
|
||
}
|
||
out << "e\n";
|
||
|
||
out.close();
|
||
|
||
}
|
||
|
||
};
|
||
|
||
#endif // WIFIPROBABILITYGRID_H
|