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/WiFiProbabilityGrid.h
2018-07-11 19:08:48 +02:00

133 lines
3.7 KiB
C++

#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