worked on signal-strength-estimation
add this information to grid nodes evaluate this information new test-cases
This commit is contained in:
27
sensors/radio/LocatedAccessPoint.h
Normal file
27
sensors/radio/LocatedAccessPoint.h
Normal 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
|
||||
84
sensors/radio/WiFiGridEstimator.h
Normal file
84
sensors/radio/WiFiGridEstimator.h
Normal 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
|
||||
123
sensors/radio/WiFiGridNode.h
Normal file
123
sensors/radio/WiFiGridNode.h
Normal 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
|
||||
100
sensors/radio/WiFiObservation.h
Normal file
100
sensors/radio/WiFiObservation.h
Normal 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
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
};
|
||||
18
sensors/radio/model/WiFiModel.h
Normal file
18
sensors/radio/model/WiFiModel.h
Normal 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
|
||||
31
sensors/radio/model/WiFiModelLogDist.h
Normal file
31
sensors/radio/model/WiFiModelLogDist.h
Normal 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
|
||||
Reference in New Issue
Block a user