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/WiFiProbabilityFree.h
2018-10-25 11:50:12 +02:00

184 lines
5.1 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © 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 WIFIPROBABILITYFREE_H
#define WIFIPROBABILITYFREE_H
#include "WiFiProbability.h"
#include "model/WiFiModel.h"
#include "../../math/distribution/Normal.h"
#include "../../math/distribution/Region.h"
#include "../../math/distribution/Exponential.h"
#include "VAPGrouper.h"
#include "../../floorplan/v2/Floorplan.h"
#include <unordered_map>
/**
* compare WiFi-Measurements within predictions of a given model.
* predictions are just based on the distance to the access-point.
*/
class WiFiObserverFree : public WiFiProbability {
public:
enum class EvalDist {
NORMAL_DISTIRBUTION,
CAPPED_NORMAL_DISTRIBUTION,
EXPONENTIAL,
};
private:
const float sigma;
const float sigmaPerSecond = 3.0f;
/** the RSSI prediction model */
WiFiModel& model;
/** the map's floorplan */
Floorplan::IndoorMap* map;
std::vector<AccessPoint> allAPs;
bool useError = false;
EvalDist dist;
public:
WiFiObserverFree(const float sigma, WiFiModel& model, EvalDist dist = EvalDist::NORMAL_DISTIRBUTION) : sigma(sigma), model(model), dist(dist) {
allAPs = model.getAllAPs();
}
void setUseError(const bool useError) {
this->useError = useError;
}
double getProbability(const Point3& pos_m, const Timestamp curTime, const WiFiMeasurements& obs) const {
double prob = 1.0;
//double prob = 0;
int numMatchingAPs = 0;
// process each measured AP
for (const WiFiMeasurement& entry : obs.entries) {
// sanity check
Assert::isFalse(entry.getTimestamp().isZero(), "wifi measurement without timestamp. coding error?");
// get the model's RSSI (if possible!)
const float modelRSSI = model.getRSSI(entry.getAP().getMAC(), pos_m);
// NaN? -> AP not known to the model -> skip
if (modelRSSI != modelRSSI) {continue;}
// the scan's RSSI
const float scanRSSI = entry.getRSSI();
// the measurement's age
const Timestamp age = curTime - entry.getTimestamp();
Assert::isTrue(age.ms() >= 0, "found a negative wifi measurement age. this does not make sense");
Assert::isTrue(age.ms() <= 60000, "found a 60 second old wifi measurement. maybe there is a coding error?");
Assert::isBetween(scanRSSI, -100.0f, -20.0f, "scan-rssi out of range");
//Assert::isBetween(modelRSSI, -160.0f, -10.0f, "model-rssi out of range");
// sigma grows with measurement age
const float sigma = this->sigma + this->sigmaPerSecond * age.sec();
// probability for this AP
double local = NAN;
switch (dist) {
case EvalDist::NORMAL_DISTIRBUTION:
local = Distribution::Normal<double>::getProbability(modelRSSI, sigma, scanRSSI); break;
case EvalDist::CAPPED_NORMAL_DISTRIBUTION:
local = Distribution::Region<double>::getProbability(modelRSSI, sigma, scanRSSI); break;
case EvalDist::EXPONENTIAL:
local = Distribution::Exponential<double>::getProbability(0.05, std::abs(modelRSSI-scanRSSI)); break;
default: throw Exception("unsupported distribution");
}
// also add the error value? [location is OK but model is wrong]
if (useError) {
local = 0.95 * local + 0.05 * (1.0-local);
//local = 0.95 * local + 0.05;
}
// update probability
prob *= local;
++numMatchingAPs;
}
// sanity check
//Assert::isTrue(numMatchingAPs > 0, "not a single measured AP was matched against known ones. coding error? model error?");
return prob;
}
/**
* for some locations it might make sense to also look at APs
* that have NOT been discovered by the smartphone but SHOULD
* be very well receivable at a location.
* such locations can be opted-out by using this veto-probability
*/
double getVeto(const Point3& pos_m, const Timestamp curTime, const WiFiMeasurements& obs) const {
(void) curTime;
struct APR {
AccessPoint ap;
float rssi;
APR(const AccessPoint& ap, const float rssi) : ap(ap), rssi(rssi) {;}
};
std::vector<APR> all;
for (const AccessPoint& ap : allAPs) {
const float rssi = model.getRSSI(ap.getMAC(), pos_m);
if (rssi != rssi) {continue;} // unknown to the model
all.push_back(APR(ap, rssi));
}
// stort by RSSI
auto comp = [&] (const APR& apr1, const APR& apr2) {return apr1.rssi > apr2.rssi;};
std::sort(all.begin(), all.end(), comp);
int numVetos = 0;
for (int i = 0; i < 3; ++i) {
const APR& apr = all[i];
const WiFiMeasurement* mes = obs.getForMac(apr.ap.getMAC());
const float rssiScan = (mes) ? (mes->getRSSI()) : (-100);
const float rssiModel = apr.rssi;
const float diff = std::abs(rssiScan - rssiModel);
if (diff > 20) {++numVetos;}
}
if (numVetos == 0) {return 0.70;}
if (numVetos == 1) {return 0.29;}
else {return 0.01;}
}
template <typename Node> double getProbability(const Node& n, const Timestamp curTime, const WiFiMeasurements& obs, const int age_ms = 0) const {
return this->getProbability(n.inMeter() + Point3(0,0,1.3), curTime, obs);
}
};
#endif // WIFIPROBABILITYFREE_H