added measurement grouping for beacons

had to change the parameter boundaries of the wifi optimizer to be able to use it for bluetooth... this should be refactored to something more generic..
some minor changes in ble
This commit is contained in:
mail@toni-fetzer.de
2019-06-10 16:57:02 +02:00
parent 8d37e94647
commit 96c63ac3ec
11 changed files with 1020 additions and 661 deletions

View File

@@ -28,217 +28,217 @@
*/
class WiFiModelLogDistCeiling : public WiFiModel {
static constexpr const char* name = "WifiModelLDC";
static constexpr const char* name = "WifiModelLDC";
public:
/** parameters describing one AP to the model */
struct APEntry {
/** parameters describing one AP to the model */
struct APEntry {
Point3 position_m; // the AP's position (in meter)
float txp; // sending power (-40)
float exp; // path-loss-exponent (~2.0 - 4.0)
float waf; // attenuation per ceiling/floor (~-8.0)
Point3 position_m; // the AP's position (in meter)
float txp; // sending power (-40)
float exp; // path-loss-exponent (~2.0 - 4.0)
float waf; // attenuation per ceiling/floor (~-8.0)
/** ctor */
APEntry(const Point3 position_m, const float txp, const float exp, const float waf) :
position_m(position_m), txp(txp), exp(exp), waf(waf) {;}
/** ctor */
APEntry(const Point3 position_m, const float txp, const float exp, const float waf) :
position_m(position_m), txp(txp), exp(exp), waf(waf) {;}
};
};
private:
/** map of all APs (and their parameters) known to the model */
std::unordered_map<MACAddress, APEntry> accessPoints;
/** map of all APs (and their parameters) known to the model */
std::unordered_map<MACAddress, APEntry> accessPoints;
// /** position (height) of all ceilings (in meter) */
// std::vector<float> ceilingsAtHeight_m;
Floorplan::Ceilings ceilings;
Floorplan::Ceilings ceilings;
public:
/** ctor with floorplan (needed for ceiling position) */
WiFiModelLogDistCeiling(const Floorplan::IndoorMap* map) : ceilings(map) {
/** ctor with floorplan (needed for ceiling position) */
WiFiModelLogDistCeiling(const Floorplan::IndoorMap* map) : ceilings(map) {
// sanity checks
Assert::isTrue(map->floors.size() >= 1, "map has no floors?!");
// sanity checks
Assert::isTrue(map->floors.size() >= 1, "map has no floors?!");
}
}
/** 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 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;
for (const auto it : accessPoints) {aps.push_back(AccessPoint(it.first));}
return aps;
}
/** get a list of all APs known to the model */
std::vector<AccessPoint> getAllAPs() const {
std::vector<AccessPoint> aps;
for (const auto it : accessPoints) {aps.push_back(AccessPoint(it.first));}
return aps;
}
/** load AP information from the floorplan. use the given fixed TXP/EXP/WAF for all APs */
void loadAPs(const Floorplan::IndoorMap* map, const float txp = -40.0f, const float exp = 2.5f, const float waf = -8.0f, const bool assertSafe = true) {
/** load AP information from the floorplan. use the given fixed TXP/EXP/WAF for all APs */
void loadAPs(const Floorplan::IndoorMap* map, const float txp = -40.0f, const float exp = 2.5f, const float waf = -8.0f, const bool assertSafe = true) {
for (const Floorplan::Floor* floor : map->floors) {
for (const Floorplan::AccessPoint* ap : floor->accesspoints) {
const APEntry ape(ap->getPos(floor), txp, exp, waf);
addAP(MACAddress(ap->mac), ape, assertSafe);
}
}
for (const Floorplan::Floor* floor : map->floors) {
for (const Floorplan::AccessPoint* ap : floor->accesspoints) {
const APEntry ape(ap->getPos(floor), txp, exp, waf);
addAP(MACAddress(ap->mac), ape, assertSafe);
}
}
}
}
/**
* load AP information from the floorplan.
* use the given fixed TXP/EXP/WAF for all APs.
* usually txp,exp,waf are checked for a sane range. if you know what you are doing, set assertSafe to false!
*/
void loadAPs(const Floorplan::IndoorMap* map, const VAPGrouper& vg, const float txp = -40.0f, const float exp = 2.5f, const float waf = -8.0f, const bool assertSafe = true) {
/**
* load AP information from the floorplan.
* use the given fixed TXP/EXP/WAF for all APs.
* usually txp,exp,waf are checked for a sane range. if you know what you are doing, set assertSafe to false!
*/
void loadAPs(const Floorplan::IndoorMap* map, const VAPGrouper& vg, const float txp = -40.0f, const float exp = 2.5f, const float waf = -8.0f, const bool assertSafe = true) {
for (const Floorplan::Floor* floor : map->floors) {
for (const Floorplan::AccessPoint* ap : floor->accesspoints) {
const APEntry ape(ap->getPos(floor), txp, exp, waf);
const MACAddress mac = vg.getBaseMAC(MACAddress(ap->mac));
Log::add("WiModLDC", "AP added! given: " + ap->mac + " -> after VAP: " + mac.asString());
addAP(MACAddress(mac), ape, assertSafe);
}
}
for (const Floorplan::Floor* floor : map->floors) {
for (const Floorplan::AccessPoint* ap : floor->accesspoints) {
const APEntry ape(ap->getPos(floor), txp, exp, waf);
const MACAddress mac = vg.getBaseMAC(MACAddress(ap->mac));
Log::add("WiModLDC", "AP added! given: " + ap->mac + " -> after VAP: " + mac.asString());
addAP(MACAddress(mac), ape, assertSafe);
}
}
}
}
/**
* 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 APEntry& params, const bool assertSafe = true) {
/**
* 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 APEntry& params, const bool assertSafe = true) {
// sanity check
if (assertSafe) {
Assert::isBetween(params.waf, -99.0f, 0.0f, "WAF out of bounds [-99:0]");
Assert::isBetween(params.txp, -50.0f, -30.0f, "TXP out of bounds [-50:-30]");
Assert::isBetween(params.exp, 1.0f, 4.0f, "EXP out of bounds [1:4]");
}
// sanity check
if (assertSafe) {
Assert::isBetween(params.waf, -99.0f, 0.0f, "WAF out of bounds [-99:0]");
Assert::isBetween(params.txp, -65.0f, -30.0f, "TXP out of bounds [-65:-30]");
Assert::isBetween(params.exp, 1.0f, 5.0f, "EXP out of bounds [1:5]");
}
Assert::equal(accessPoints.find(accessPoint), accessPoints.end(), "AccessPoint already present! VAP-Grouping issue?");
Assert::equal(accessPoints.find(accessPoint), accessPoints.end(), "AccessPoint already present! VAP-Grouping issue?");
// add
accessPoints.insert( std::pair<MACAddress, APEntry>(accessPoint, params) );
// add
accessPoints.insert( std::pair<MACAddress, APEntry>(accessPoint, params) );
}
}
/**
* 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);
}
/**
* 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();
}
/** remove all added APs */
void clear() {
accessPoints.clear();
}
/** does the model know the given AP? */
bool knowsAP(const MACAddress& accessPoint) {
/** does the model know the given AP? */
bool knowsAP(const MACAddress& accessPoint) {
// try to get the corresponding parameters
const auto it = accessPoints.find(accessPoint);
// try to get the corresponding parameters
const auto it = accessPoints.find(accessPoint);
// AP known?
return (it != accessPoints.end());
// AP known?
return (it != accessPoints.end());
}
}
float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const override {
float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const override {
// try to get the corresponding parameters
const auto it = accessPoints.find(accessPoint);
// try to get the corresponding parameters
const auto it = accessPoints.find(accessPoint);
// AP unknown? -> NAN
if (it == accessPoints.end()) {return NAN;}
// AP unknown? -> NAN
if (it == accessPoints.end()) {return NAN;}
// the access-points' parameters
const APEntry& params = it->second;
// the access-points' parameters
const APEntry& params = it->second;
// free-space (line-of-sight) RSSI
const float distance_m = position_m.getDistance(params.position_m);
const float rssiLOS = LogDistanceModel::distanceToRssi(params.txp, params.exp, distance_m);
// free-space (line-of-sight) RSSI
const float distance_m = position_m.getDistance(params.position_m);
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.numCeilingsBetweenFloat(position_m, params.position_m);
//const float wafLoss = params.waf * ceilings.numCeilingsBetweenLinearInt(position_m, params.position_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.numCeilingsBetweenFloat(position_m, params.position_m);
//const float wafLoss = params.waf * ceilings.numCeilingsBetweenLinearInt(position_m, params.position_m);
// combine
const float res = rssiLOS + wafLoss;
// combine
const float res = rssiLOS + wafLoss;
// sanity check
Assert::isNotNaN(res, "detected NaN within WiFiModelLogDistCeiling::getRSSI()");
// sanity check
Assert::isNotNaN(res, "detected NaN within WiFiModelLogDistCeiling::getRSSI()");
// ok
return res;
// ok
return res;
}
}
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
// set my type
dst->SetAttribute("type", "WiFiModelLogDistCeiling");
// 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 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);
}
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 {
void readFromXML(XMLDoc* doc, XMLElem* src) override {
// check type
if (std::string("WiFiModelLogDistCeiling") != src->Attribute("type")) {throw Exception("invalid model type");}
// check type
if (std::string("WiFiModelLogDistCeiling") != src->Attribute("type")) {throw Exception("invalid model type");}
accessPoints.clear();
ceilings.clear();
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("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);
}
XML_FOREACH_ELEM_NAMED("ceiling", xceil, src) {
const float atHeight_m = xceil->FloatAttribute("atHeight");
ceilings.addCeiling(atHeight_m);
}
Log::add(name, "loaded " + std::to_string(accessPoints.size()) + " APs");
Log::add(name, "loaded " + std::to_string(accessPoints.size()) + " APs");
}
}
};