worked on signal-strength-estimation

add this information to grid nodes
evaluate this information
new test-cases
This commit is contained in:
2016-07-15 15:29:07 +02:00
parent 34e52cd7f0
commit 99ee95ce7b
21 changed files with 568 additions and 26 deletions

View File

@@ -0,0 +1,27 @@
#ifndef LOCATEDACCESSPOINT_H
#define LOCATEDACCESSPOINT_H
#include "AccessPoint.h"
#include "../../geo/Point3.h"
#include "../../floorplan/v2/Floorplan.h"
/**
* describes an access-point including its position
*/
class LocatedAccessPoint : public AccessPoint, public Point3 {
public:
/** ctor */
LocatedAccessPoint(const std::string& mac, const Point3 pos_m) : AccessPoint(mac, ""), Point3(pos_m) {
;
}
/** ctor */
LocatedAccessPoint(const Floorplan::AccessPoint& ap) : AccessPoint(ap.mac, ap.name), Point3(ap.pos) {
;
}
};
#endif // LOCATEDACCESSPOINT_H

View File

@@ -0,0 +1,84 @@
#ifndef WIFIGRIDESTIMATOR_H
#define WIFIGRIDESTIMATOR_H
#include "../../grid/Grid.h"
#include "model/WiFiModel.h"
#include "WiFiGridNode.h"
#include "../../Assertions.h"
#include <fstream>
/**
* estimates the signal-strength for all APs at a given GridNode
* and stores this precalculated value onto the node
*/
class WiFiGridEstimator {
public:
/**
* perform a signal-strength estimation for all of the given access points
* using the provided signal-strength prediction model.
* store the estimated strength onto each node.
* as nodes only provide a limited number of rssi-entries,
* store only the strongest ones.
*/
template <typename Node> static void estimate(Grid<Node>& grid, WiFiModel& mdl, const std::vector<LocatedAccessPoint> aps) {
// sanity checks
Assert::isTrue(Node::getMapAPs().empty(), "there are already some processed APs available!");
// attach the access-points to the shared node-vector
for (const LocatedAccessPoint& ap : aps) {
Node::getMapAPs().push_back(ap);
}
// process each node
for (Node& n : grid) {
// keep the strongest APs to attach to this node
std::vector<WiFiGridNodeAP> nodeAPs;
// process each AP
for (int apIdx = 0; apIdx < (int) aps.size(); ++apIdx) {
// estimate the signal-strength
const float rssi = mdl.getRSSI(aps[apIdx], n.inMeter());
// keep it
nodeAPs.push_back(WiFiGridNodeAP(apIdx, rssi));
}
// sort all APs by signal strength
auto comp = [] (const WiFiGridNodeAP& ap1, const WiFiGridNodeAP& ap2) {return ap1.getRSSI() > ap2.getRSSI();};
std::sort(nodeAPs.begin(), nodeAPs.end(), comp);
// attach the strongest X to the node
const int cnt = std::min( n.getMaxAPs(), (int) nodeAPs.size() );
for (int i = 0; i < cnt; ++i) {
n.strongestAPs[i] = nodeAPs[i];
}
}
}
/** gnuplot visualization dump for the given AP */
template <typename Node> static void dump(Grid<Node>& grid, const std::string& mac, const std::string& filename) {
std::ofstream out(filename);
out << "splot '-' with points palette \n";
for (Node& n : grid) {
out << n.x_cm << " " << n.y_cm << " " << n.z_cm << " " << n.getRSSI(mac) << "\n";
}
out << "e\n";
out.close();
}
};
#endif // WIFIGRIDESTIMATOR_H

View File

@@ -0,0 +1,123 @@
#ifndef WIFIGRIDNODE_H
#define WIFIGRIDNODE_H
#include <cstdint>
#include "AccessPoint.h"
/**
* rssi model-estimation for one AP, denoted by its index [among all APs present within the map]
* the signal strength is stored as uint8_t and allows a granularity of 0.25 dB between -40 and -103 dB
*/
struct WiFiGridNodeAP {
private:
static const int UNUSED_IDX = 255;
private:
/** access-point index -> max 255 APs/Map */
uint8_t idx;
/** access-point rssi */
uint8_t rssi;
public:
/** empty ctor */
WiFiGridNodeAP() : idx(UNUSED_IDX), rssi(0) {;}
/** ctor */
WiFiGridNodeAP(const int idx, const float rssi) : idx(idx), rssi(stretch(rssi)) {;}
/** is this entry valid/used? */
bool isValid() const {return idx != UNUSED_IDX;}
/** set AP and its signal strength */
void set(const int apIdx, const float rssi) {
this->idx = apIdx;
this->rssi = stretch(rssi);
}
/** get the predicted signal-strength */
float getRSSI() const {return unstretch(rssi);}
/** get the access-point's index */
int getAPIdx() const {return idx;}
private:
/** [-40:-103] -> [0:252] => this allows 0.25 steps */
static inline int8_t stretch(float rssi) {
if (rssi > -40) {rssi = -40;}
if (rssi < -103) {rssi = -103;}
return std::round((-rssi - 40) * 4);
}
/** [0:252] -> [-40:-103] */
static inline float unstretch(const float rssi) {
return -(rssi / 4.0f + 40.0f);
}
};// __attribute__((packed));
/**
* base-class for grid-nodes that contain wifi signal-strength estimations.
* such estimations are calculated offline and added to each node.
* this also allows for using very complex signal-strength estimation models
*/
template <int maxAccessPoints> struct WiFiGridNode {
/** contains the 10 strongest APs measureable at this position */
WiFiGridNodeAP strongestAPs[maxAccessPoints];
/** ctor */
WiFiGridNode() {;}
/** shared vector of all accesspoints the are present within the map. the IDX referes to this vector */
static std::vector<AccessPoint>& getMapAPs() {
static std::vector<AccessPoint> list;
return list;
}
/** get the maximum number of APs each node is able to store */
int getMaxAPs() const {return maxAccessPoints;}
/**
* get the RSSI for the given AP
* returns 0 if unknown
*/
float getRSSI(const std::string& mac) const {
return getRSSI(MACAddress(mac));
}
/**
* get the RSSI for the given AP
* returns 0 if unknown
*/
float getRSSI(const MACAddress mac) const {
for (const WiFiGridNodeAP ap : strongestAPs) {
if (!ap.isValid()) {break;} // reached the end
if (getMapAPs()[ap.getAPIdx()].mac == mac) {return ap.getRSSI();}
}
return 0;
}
/** get the number of access-points visible at this node */
int getNumVisibleAPs() const {
for (int i = 0; i < getMaxAPs(); ++i) {
if (!strongestAPs[i].isValid()) {return i;}
}
return getMaxAPs();
}
};// __attribute__((packed));
#endif // WIFIGRIDNODE_H

View File

@@ -0,0 +1,100 @@
#ifndef WIFIOBSERVATION_H
#define WIFIOBSERVATION_H
#include <vector>
#include <fstream>
#include "../MACAddress.h"
#include "../../math/Distributions.h"
/** observed one AP with the given signal strength */
struct WiFiObservationEntry {
/** AP's MAC address */
MACAddress mac;
/** AP's RSSI */
float rssi;
/** ctor */
WiFiObservationEntry(const MACAddress& mac, const float rssi) : mac(mac), rssi(rssi) {;}
};
/** all observed APs and their signal strength */
struct WiFiObservation {
/** one entry per AP */
std::vector<WiFiObservationEntry> entries;
};
class WiFiObserver {
private:
float sigma = 8.0f;
public:
/** ctor */
WiFiObserver(const float sigma) : sigma(sigma) {
;
}
/**
* get the given GridNode's probability based on the provided WiFi measurements
*/
template <typename Node> double getProbability(const Node& n, const WiFiObservation& obs, const int age_ms = 0) {
double prob = 0;
// sigma grows with measurement age
const double sigma = this->sigma * (1 + age_ms / 500.0f);
// process each observed AP
for (const WiFiObservationEntry& ap : obs.entries) {
// the RSSI from the scan
const float measuredRSSI = ap.rssi;
// the RSSI from the model (if available!)
const float modelRSSI = n.getRSSI(ap.mac);
// no model RSSI available?
if (modelRSSI == 0) {continue;}
// compare both
const double p = Distribution::Normal<double>::getProbability(measuredRSSI, sigma, modelRSSI);
// adjust using log
prob += std::log(p);
}
//return std::pow(std::exp(prob), 0.1);
return std::exp(prob);
}
/** gnuplot debug dump */
template <typename Node> void dump(Grid<Node>& grid, const WiFiObservation& 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, obs);
out << n.x_cm << " " << n.y_cm << " " << n.z_cm << " " << p << "\n";
}
out << "e\n";
out.close();
}
};
#endif // WIFIOBSERVATION_H

View File

@@ -13,9 +13,9 @@ public:
}
/** convert from a distance (in meter) to the expected RSSI */
static float distanceToRssi(const float txPower, const float pathLoss, const float distance) {
if (distance <= 1) {return txPower;}
return (txPower - (10 * pathLoss * std::log10(distance)));
static float distanceToRssi(const float txPower, const float pathLoss, const float distance_m) {
if (distance_m <= 1) {return txPower;}
return (txPower - (10 * pathLoss * std::log10(distance_m)));
}
};

View File

@@ -0,0 +1,18 @@
#ifndef WIFIMODEL_H
#define WIFIMODEL_H
#include "../LocatedAccessPoint.h"
/**
* interface for signal-strength prediction models
*/
class WiFiModel {
public:
/** get the given access-point's RSSI at the provided location */
virtual float getRSSI(const LocatedAccessPoint& ap, const Point3 p) = 0;
};
#endif // WIFIMODEL_H

View File

@@ -0,0 +1,31 @@
#ifndef WIFIMODELLOGDIST_H
#define WIFIMODELLOGDIST_H
#include "WiFiModel.h"
#include "LogDistanceModel.h"
/**
* signal-strength estimation using log-distance model
*/
class WiFiModelLogDist : public WiFiModel {
private:
float txp;
float exp;
public:
/** ctor */
WiFiModelLogDist(const float txp, const float exp) : txp(txp), exp(exp) {
;
}
/** get the given access-point's RSSI at the provided location */
float getRSSI(const LocatedAccessPoint& ap, const Point3 p) override {
return LogDistanceModel::distanceToRssi(txp, exp, ap.getDistance(p));
}
};
#endif // WIFIMODELLOGDIST_H