changes from the laptop
- some should be the same as previous commit (sorry!) - some should be new: LINT checks, ...?
This commit is contained in:
@@ -45,6 +45,11 @@ public:
|
||||
;
|
||||
}
|
||||
|
||||
/** equals? */
|
||||
bool operator == (const AccessPoint& o) {
|
||||
return (o.mac == mac) && (o.ssid == ssid);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** get the AP's MAC address */
|
||||
|
||||
@@ -23,8 +23,8 @@ struct WiFiMeasurements {
|
||||
}
|
||||
|
||||
/** get the measurements for the given MAC [if available] otherwise null */
|
||||
WiFiMeasurement* getForMac(const MACAddress& mac) {
|
||||
for (WiFiMeasurement& m : entries) {
|
||||
const WiFiMeasurement* getForMac(const MACAddress& mac) const {
|
||||
for (const WiFiMeasurement& m : entries) {
|
||||
if (m.getAP().getMAC() == mac) {
|
||||
return &m;
|
||||
}
|
||||
|
||||
@@ -27,15 +27,26 @@ private:
|
||||
/** the map's floorplan */
|
||||
Floorplan::IndoorMap* map;
|
||||
|
||||
std::vector<AccessPoint> allAPs;
|
||||
|
||||
bool useError = false;
|
||||
|
||||
public:
|
||||
|
||||
WiFiObserverFree(const float sigma, WiFiModel& model) : sigma(sigma), model(model) {
|
||||
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;
|
||||
double error = 0;
|
||||
|
||||
int numMatchingAPs = 0;
|
||||
|
||||
// process each measured AP
|
||||
@@ -50,7 +61,6 @@ public:
|
||||
// NaN? -> AP not known to the model -> skip
|
||||
if (modelRSSI != modelRSSI) {continue;}
|
||||
|
||||
|
||||
// the scan's RSSI
|
||||
const float scanRSSI = entry.getRSSI();
|
||||
|
||||
@@ -60,24 +70,81 @@ public:
|
||||
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, -30.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 = Distribution::Normal<double>::getProbability(modelRSSI, sigma, scanRSSI);
|
||||
double local = Distribution::Exponential<double>::getProbability(0.1, std::abs(modelRSSI-scanRSSI));
|
||||
|
||||
// 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;
|
||||
#warning "TODO"
|
||||
}
|
||||
|
||||
// update probability
|
||||
prob *= Distribution::Normal<double>::getProbability(modelRSSI, sigma, scanRSSI);
|
||||
//prob *= Distribution::Region<double>::getProbability(modelRSSI, sigma, scanRSSI);
|
||||
prob *= local;
|
||||
|
||||
++numMatchingAPs;
|
||||
|
||||
}
|
||||
|
||||
// sanity check
|
||||
//Assert::isTrue(numMatchingAPs > 0, "not a single measured AP was matched against known ones. coding error? model error?");
|
||||
//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);
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
|
||||
#include "../AccessPoint.h"
|
||||
#include "../../../geo/Point3.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
#include "../../../data/XMLserialize.h"
|
||||
|
||||
|
||||
/**
|
||||
* interface for signal-strength prediction models.
|
||||
@@ -10,7 +15,7 @@
|
||||
* the model is passed a MAC-address of an AP in question, and a position.
|
||||
* hereafter the model returns the RSSI for this AP at the questioned location.
|
||||
*/
|
||||
class WiFiModel {
|
||||
class WiFiModel : public XMLserialize {
|
||||
|
||||
public:
|
||||
|
||||
@@ -31,6 +36,7 @@ public:
|
||||
*/
|
||||
virtual float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // WIFIMODEL_H
|
||||
|
||||
32
sensors/radio/model/WiFiModelFactory.h
Normal file
32
sensors/radio/model/WiFiModelFactory.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef WIFIMODELFACTORY_H
|
||||
#define WIFIMODELFACTORY_H
|
||||
|
||||
|
||||
#include "WiFiModel.h"
|
||||
#include "../../../floorplan/v2/Floorplan.h"
|
||||
|
||||
/**
|
||||
* this class can instantiate WiFiModels based on serialized XML files
|
||||
*/
|
||||
class WiFiModelFactory {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::IndoorMap* map;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor. needs the floorplan for some models */
|
||||
WiFiModelFactory(Floorplan::IndoorMap* map) : map(map) {
|
||||
;
|
||||
}
|
||||
|
||||
/** parse model from XML file */
|
||||
WiFiModel* loadXML(const std::string& file);
|
||||
|
||||
/** parse model from XML node */
|
||||
WiFiModel* readFromXML(XMLDoc* doc, XMLElem* src);
|
||||
|
||||
};
|
||||
|
||||
#endif // WIFIMODELFACTORY_H
|
||||
42
sensors/radio/model/WiFiModelFactoryImpl.h
Normal file
42
sensors/radio/model/WiFiModelFactoryImpl.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef WIFIMODELFACTORYIMPL_H
|
||||
#define WIFIMODELFACTORYIMPL_H
|
||||
|
||||
#include "WiFiModelFactory.h"
|
||||
#include "WiFiModelLogDist.h"
|
||||
#include "WiFiModelLogDistCeiling.h"
|
||||
#include "WiFiModelPerFloor.h"
|
||||
#include "WiFiModelPerBBox.h"
|
||||
|
||||
WiFiModel* WiFiModelFactory::loadXML(const std::string& file) {
|
||||
|
||||
XMLDoc doc;
|
||||
XMLserialize::assertOK(doc.LoadFile(file.c_str()), doc, "error while loading file");
|
||||
XMLElem* root = doc.FirstChildElement("root");
|
||||
|
||||
return readFromXML(&doc, root);
|
||||
|
||||
}
|
||||
|
||||
WiFiModel* WiFiModelFactory::readFromXML(XMLDoc* doc, XMLElem* src) {
|
||||
|
||||
// each model attaches its "type" during serialization
|
||||
const std::string type = src->Attribute("type");
|
||||
|
||||
WiFiModel* mdl = nullptr;
|
||||
|
||||
// create an instance for the model
|
||||
if (type == "WiFiModelLogDist") {mdl = new WiFiModelLogDist();}
|
||||
else if (type == "WiFiModelLogDistCeiling") {mdl = new WiFiModelLogDistCeiling(map);}
|
||||
else if (type == "WiFiModelPerFloor") {mdl = new WiFiModelPerFloor(map);}
|
||||
else if (type == "WiFiModelPerBBox") {mdl = new WiFiModelPerBBox(map);}
|
||||
else {throw Exception("invalid model type given: " + type);}
|
||||
|
||||
// load the model from XML
|
||||
mdl->readFromXML(doc, src);
|
||||
|
||||
// done
|
||||
return mdl;
|
||||
|
||||
}
|
||||
|
||||
#endif // WIFIMODELFACTORYIMPL_H
|
||||
@@ -77,6 +77,14 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
throw Exception("not yet implemented");
|
||||
}
|
||||
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
throw Exception("not yet implemented");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // WIFIMODELLOGDIST_H
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "../VAPGrouper.h"
|
||||
#include "../../../misc/Debug.h"
|
||||
|
||||
#include "../../../data/XMLserialize.h"
|
||||
|
||||
/**
|
||||
* signal-strength estimation using log-distance model
|
||||
* including ceilings between AP and position
|
||||
@@ -52,6 +54,13 @@ public:
|
||||
|
||||
}
|
||||
|
||||
/** get the entry for the given mac. exception if missing */
|
||||
const APEntry& getAP(const MACAddress& mac) const {
|
||||
const auto& it = accessPoints.find(mac);
|
||||
if (it == accessPoints.end()) {throw Exception("model does not contain an entry for " + mac.asString());}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/** get a list of all APs known to the model */
|
||||
std::vector<AccessPoint> getAllAPs() const {
|
||||
std::vector<AccessPoint> aps;
|
||||
@@ -109,6 +118,14 @@ public:
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* make the given AP (and its parameters) known to the model
|
||||
* usually txp,exp,waf are checked for a sane range. if you know what you are doing, set assertSafe to false!
|
||||
*/
|
||||
void addAP(const MACAddress& accessPoint, const Point3 pos_m, const float txp, const float exp, const float waf, const bool assertSafe = true) {
|
||||
addAP(accessPoint, APEntry(pos_m, txp, exp, waf), assertSafe);
|
||||
}
|
||||
|
||||
/** remove all added APs */
|
||||
void clear() {
|
||||
accessPoints.clear();
|
||||
@@ -130,7 +147,8 @@ public:
|
||||
const float rssiLOS = LogDistanceModel::distanceToRssi(params.txp, params.exp, distance_m);
|
||||
|
||||
// WAF loss (params.waf is a negative value!) -> WAF loss is also a negative value
|
||||
const float wafLoss = params.waf * ceilings.numCeilingsBetween(position_m, params.position_m);
|
||||
//const float wafLoss = params.waf * ceilings.numCeilingsBetween(position_m, params.position_m);
|
||||
const float wafLoss = params.waf * ceilings.numCeilingsBetweenFloat(position_m, params.position_m);
|
||||
|
||||
// combine
|
||||
const float res = rssiLOS + wafLoss;
|
||||
@@ -143,6 +161,59 @@ public:
|
||||
|
||||
}
|
||||
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
|
||||
// set my type
|
||||
dst->SetAttribute("type", "WiFiModelLogDistCeiling");
|
||||
|
||||
for (const auto& it : accessPoints) {
|
||||
const MACAddress& mac = it.first;
|
||||
const APEntry& ape = it.second;
|
||||
XMLElem* xap = doc->NewElement("ap");
|
||||
xap->SetAttribute("mac", mac.asString().c_str());
|
||||
xap->SetAttribute("px", ape.position_m.x);
|
||||
xap->SetAttribute("py", ape.position_m.y);
|
||||
xap->SetAttribute("pz", ape.position_m.z);
|
||||
xap->SetAttribute("txp", ape.txp);
|
||||
xap->SetAttribute("exp", ape.exp);
|
||||
xap->SetAttribute("waf", ape.waf);
|
||||
dst->InsertEndChild(xap);
|
||||
}
|
||||
|
||||
for (const float atHeight_m : ceilings.getCeilings()) {
|
||||
XMLElem* xceil = doc->NewElement("ceiling");
|
||||
xceil->SetAttribute("atHeight", atHeight_m);
|
||||
dst->InsertEndChild(xceil);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
|
||||
// check type
|
||||
if (std::string("WiFiModelLogDistCeiling") != src->Attribute("type")) {throw Exception("invalid model type");}
|
||||
|
||||
accessPoints.clear();
|
||||
ceilings.clear();
|
||||
|
||||
XML_FOREACH_ELEM_NAMED("ap", xap, src) {
|
||||
MACAddress mac = MACAddress(xap->Attribute("mac"));
|
||||
APEntry ape(
|
||||
Point3(xap->FloatAttribute("px"), xap->FloatAttribute("py"), xap->FloatAttribute("pz")),
|
||||
xap->FloatAttribute("txp"),
|
||||
xap->FloatAttribute("exp"),
|
||||
xap->FloatAttribute("waf")
|
||||
);
|
||||
accessPoints.insert( std::make_pair(mac, ape) );
|
||||
}
|
||||
|
||||
XML_FOREACH_ELEM_NAMED("ceiling", xceil, src) {
|
||||
const float atHeight_m = xceil->FloatAttribute("atHeight");
|
||||
ceilings.addCeiling(atHeight_m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
164
sensors/radio/model/WiFiModelPerBBox.h
Normal file
164
sensors/radio/model/WiFiModelPerBBox.h
Normal file
@@ -0,0 +1,164 @@
|
||||
#ifndef WIFIMODELPERBBOX_H
|
||||
#define WIFIMODELPERBBOX_H
|
||||
|
||||
|
||||
#include "../AccessPoint.h"
|
||||
#include "../../../geo/Point3.h"
|
||||
#include "../../../geo/BBoxes3.h"
|
||||
#include <vector>
|
||||
|
||||
#include "WiFiModelFactory.h"
|
||||
|
||||
/**
|
||||
* FOR TESTING
|
||||
*
|
||||
* this model allows using a different sub-models
|
||||
* identified by a bound-box to reduce the error
|
||||
*/
|
||||
class WiFiModelPerBBox : public WiFiModel {
|
||||
|
||||
struct ModelForBBoxes {
|
||||
|
||||
WiFiModel* mdl;
|
||||
BBoxes3 bboxes;
|
||||
|
||||
/** ctor */
|
||||
ModelForBBoxes(WiFiModel* mdl, BBoxes3 bboxes) : mdl(mdl), bboxes(bboxes) {;}
|
||||
|
||||
/** does this entry apply to the given position? */
|
||||
bool matches(const Point3 pt) const {
|
||||
if (bboxes.get().empty()) {throw Exception("no bbox(es) given for model!");}
|
||||
return bboxes.contains(pt);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Floorplan::IndoorMap* map;
|
||||
|
||||
/** all contained models [one per bbox] */
|
||||
std::vector<ModelForBBoxes> models;
|
||||
|
||||
public:
|
||||
|
||||
WiFiModelPerBBox(Floorplan::IndoorMap* map) : map(map) {
|
||||
;
|
||||
}
|
||||
|
||||
/** dtor */
|
||||
virtual ~WiFiModelPerBBox() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** get a list of all APs known to the model */
|
||||
std::vector<AccessPoint> getAllAPs() const override {
|
||||
std::vector<AccessPoint> res;
|
||||
for (const ModelForBBoxes& sub : models) {
|
||||
for (const AccessPoint& ap : sub.mdl->getAllAPs()) {
|
||||
if (std::find(res.begin(), res.end(), ap) == res.end()) {
|
||||
res.push_back(ap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void add(WiFiModel* mdl, const BBoxes3 bboxes) {
|
||||
if (bboxes.get().empty()) {throw Exception("no bbox(es) given for model!");}
|
||||
ModelForBBoxes mfb(mdl, bboxes);
|
||||
models.push_back(mfb);
|
||||
}
|
||||
|
||||
float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const override {
|
||||
|
||||
for (const ModelForBBoxes& mfb : models) {
|
||||
if (mfb.matches(position_m)) {return mfb.mdl->getRSSI(accessPoint, position_m);}
|
||||
}
|
||||
|
||||
return -120;
|
||||
|
||||
}
|
||||
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
|
||||
// check type
|
||||
if (std::string("WiFiModelPerBBox") != src->Attribute("type")) {throw Exception("invalid model type");}
|
||||
|
||||
models.clear();
|
||||
|
||||
// model factory [create models based on XMl content]
|
||||
WiFiModelFactory fac(map);
|
||||
|
||||
// parse all contained models [one per floor]
|
||||
XML_FOREACH_ELEM_NAMED("entry", xentry, src) {
|
||||
|
||||
// all bboxes
|
||||
BBoxes3 bboxes;
|
||||
XML_FOREACH_ELEM_NAMED("bbox", xbbox, xentry) {
|
||||
|
||||
const float x1 = xbbox->FloatAttribute("x1");
|
||||
const float y1 = xbbox->FloatAttribute("y1");
|
||||
const float z1 = xbbox->FloatAttribute("z1");
|
||||
|
||||
const float x2 = xbbox->FloatAttribute("x2");
|
||||
const float y2 = xbbox->FloatAttribute("y2");
|
||||
const float z2 = xbbox->FloatAttribute("z2");
|
||||
|
||||
const BBox3 bbox(Point3(x1,y1,z1), Point3(x2,y2,z2));
|
||||
bboxes.add(bbox);
|
||||
|
||||
}
|
||||
|
||||
// node for the model
|
||||
XMLElem* xmodel = xentry->FirstChildElement("model");
|
||||
|
||||
// let the factory instantiate the model
|
||||
WiFiModel* mdl = fac.readFromXML(doc, xmodel);
|
||||
|
||||
// add
|
||||
models.push_back(ModelForBBoxes(mdl, bboxes));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
|
||||
// set my type
|
||||
dst->SetAttribute("type", "WiFiModelPerBBox");
|
||||
|
||||
for (const ModelForBBoxes& mfb : models) {
|
||||
|
||||
// all models
|
||||
XMLElem* xentry = doc->NewElement("entry"); {
|
||||
|
||||
// each bbox
|
||||
for (const BBox3& bbox : mfb.bboxes.get()) {
|
||||
XMLElem* xbbox = doc->NewElement("bbox"); {
|
||||
|
||||
xbbox->SetAttribute("x1", bbox.getMin().x);
|
||||
xbbox->SetAttribute("y1", bbox.getMin().y);
|
||||
xbbox->SetAttribute("z1", bbox.getMin().z);
|
||||
|
||||
xbbox->SetAttribute("x2", bbox.getMax().x);
|
||||
xbbox->SetAttribute("y2", bbox.getMax().y);
|
||||
xbbox->SetAttribute("z2", bbox.getMax().z);
|
||||
|
||||
}; xentry->InsertFirstChild(xbbox);
|
||||
}
|
||||
|
||||
// the corresponding model
|
||||
XMLElem* xmodel = doc->NewElement("model"); {
|
||||
mfb.mdl->writeToXML(doc, xmodel);
|
||||
}; xentry->InsertEndChild(xmodel);
|
||||
|
||||
}; dst->InsertEndChild(xentry);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // WIFIMODELPERBBOX_H
|
||||
122
sensors/radio/model/WiFiModelPerFloor.h
Normal file
122
sensors/radio/model/WiFiModelPerFloor.h
Normal file
@@ -0,0 +1,122 @@
|
||||
#ifndef WIFIMODELPERFLOOR_H
|
||||
#define WIFIMODELPERFLOOR_H
|
||||
|
||||
#include "../AccessPoint.h"
|
||||
#include "../../../geo/Point3.h"
|
||||
#include <vector>
|
||||
|
||||
#include "WiFiModelFactory.h"
|
||||
|
||||
/**
|
||||
* FOR TESTING
|
||||
*
|
||||
* this model allows using a different sub-models for each floor to reduce the error
|
||||
*/
|
||||
class WiFiModelPerFloor : public WiFiModel {
|
||||
|
||||
struct ModelForFloor {
|
||||
|
||||
float fromZ;
|
||||
float toZ;
|
||||
WiFiModel* mdl;
|
||||
|
||||
/** ctor */
|
||||
ModelForFloor(const float fromZ, const float toZ, WiFiModel* mdl) : fromZ(fromZ), toZ(toZ), mdl(mdl) {;}
|
||||
|
||||
/** does this entry apply to the given z-position? */
|
||||
bool matches(const float z) const {
|
||||
return (fromZ <= z && z < toZ);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Floorplan::IndoorMap* map;
|
||||
|
||||
/** all contained models [one per floor] */
|
||||
std::vector<ModelForFloor> models;
|
||||
|
||||
public:
|
||||
|
||||
WiFiModelPerFloor(Floorplan::IndoorMap* map) : map(map) {
|
||||
;
|
||||
}
|
||||
|
||||
/** dtor */
|
||||
virtual ~WiFiModelPerFloor() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** get a list of all APs known to the model */
|
||||
std::vector<AccessPoint> getAllAPs() const override {
|
||||
return models.front().mdl->getAllAPs();
|
||||
}
|
||||
|
||||
void add(WiFiModel* mdl, const Floorplan::Floor* floor) {
|
||||
ModelForFloor mff(floor->atHeight, floor->atHeight+floor->height, mdl);
|
||||
models.push_back(mff);
|
||||
}
|
||||
|
||||
float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const override {
|
||||
|
||||
for (const ModelForFloor& mff : models) {
|
||||
if (mff.matches(position_m.z)) {return mff.mdl->getRSSI(accessPoint, position_m);}
|
||||
}
|
||||
|
||||
return -120;
|
||||
|
||||
}
|
||||
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
|
||||
// check type
|
||||
if (std::string("WiFiModelPerFloor") != src->Attribute("type")) {throw Exception("invalid model type");}
|
||||
|
||||
models.clear();
|
||||
|
||||
// model factory [create models based on XMl content]
|
||||
WiFiModelFactory fac(map);
|
||||
|
||||
// parse all contained models [one per floor]
|
||||
XML_FOREACH_ELEM_NAMED("floor", xfloor, src) {
|
||||
|
||||
// floor params
|
||||
const float z1 = xfloor->FloatAttribute("z1");
|
||||
const float z2 = xfloor->FloatAttribute("z2");
|
||||
|
||||
// node for the model
|
||||
XMLElem* xmodel = xfloor->FirstChildElement("model");
|
||||
|
||||
// let the factory instantiate the model
|
||||
WiFiModel* mdl = fac.readFromXML(doc, xmodel);
|
||||
|
||||
// add
|
||||
models.push_back(ModelForFloor(z1, z2, mdl));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
|
||||
// set my type
|
||||
dst->SetAttribute("type", "WiFiModelPerFloor");
|
||||
|
||||
for (const ModelForFloor& mff : models) {
|
||||
|
||||
XMLElem* xfloor = doc->NewElement("floor"); {
|
||||
xfloor->SetAttribute("z1", mff.fromZ);
|
||||
xfloor->SetAttribute("z2", mff.toZ);
|
||||
XMLElem* xmodel = doc->NewElement("model"); {
|
||||
mff.mdl->writeToXML(doc, xmodel);
|
||||
}; xfloor->InsertEndChild(xmodel);
|
||||
}; dst->InsertEndChild(xfloor);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // WIFIMODELPERFLOOR_H
|
||||
8
sensors/radio/model/WiFiModels.h
Normal file
8
sensors/radio/model/WiFiModels.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef WIFIMODELS_H
|
||||
#define WIFIMODELS_H
|
||||
|
||||
#include "WiFiModel.h"
|
||||
#include "WiFiModelFactory.h"
|
||||
#include "WiFiModelFactoryImpl.h"
|
||||
|
||||
#endif // WIFIMODELS_H
|
||||
@@ -29,6 +29,8 @@ struct WiFiFingerprint {
|
||||
/** ctor */
|
||||
WiFiFingerprint(const Point3 pos_m) : pos_m(pos_m) {;}
|
||||
|
||||
/** ctor */
|
||||
WiFiFingerprint(const Point3 pos_m, const WiFiMeasurements& measurements) : pos_m(pos_m), measurements(measurements) {;}
|
||||
|
||||
|
||||
/** as each AP might be contained more than once (scanned more than once), group them by MAC and use the average RSSI */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <fstream>
|
||||
|
||||
#include "WiFiFingerprint.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* helper class to load and save fingerprints.
|
||||
|
||||
Reference in New Issue
Block a user