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:
@@ -23,88 +23,88 @@ class WiFiModelLogDist : public WiFiModel {
|
||||
|
||||
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)
|
||||
Point3 position_m; // the AP's position (in meter)
|
||||
float txp; // sending power (-40)
|
||||
float exp; // path-loss-exponent (~2.0 - 4.0)
|
||||
|
||||
/** ctor */
|
||||
APEntry(const Point3 position_m, const float txp, const float exp) :
|
||||
position_m(position_m), txp(txp), exp(exp) {;}
|
||||
/** ctor */
|
||||
APEntry(const Point3 position_m, const float txp, const float exp) :
|
||||
position_m(position_m), txp(txp), exp(exp) {;}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
WiFiModelLogDist() {
|
||||
;
|
||||
}
|
||||
/** ctor */
|
||||
WiFiModelLogDist() {
|
||||
;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
/** make the given AP (and its parameters) known to the model */
|
||||
void addAP(const MACAddress& accessPoint, const APEntry& params) {
|
||||
/** make the given AP (and its parameters) known to the model */
|
||||
void addAP(const MACAddress& accessPoint, const APEntry& params) {
|
||||
|
||||
// sanity check
|
||||
Assert::isBetween(params.txp, -50.0f, -30.0f, "TXP out of bounds [-90:-30]");
|
||||
Assert::isBetween(params.exp, 1.0f, 4.0f, "EXP out of bounds [1:4]");
|
||||
// sanity check
|
||||
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]");
|
||||
|
||||
// add
|
||||
accessPoints.insert( std::pair<MACAddress, APEntry>(accessPoint, params) );
|
||||
// add
|
||||
accessPoints.insert( std::pair<MACAddress, APEntry>(accessPoint, params) );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** 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());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
virtual float getRSSI(const MACAddress& accessPoint, const Point3 position_m) const override {
|
||||
virtual 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);
|
||||
|
||||
// done
|
||||
return rssiLOS;
|
||||
// done
|
||||
return rssiLOS;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
throw Exception("not yet implemented");
|
||||
}
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
throw Exception("not yet implemented");
|
||||
}
|
||||
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
throw Exception("not yet implemented");
|
||||
}
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
throw Exception("not yet implemented");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#ifndef WIFIOPTIMIZER_H
|
||||
#define WIFIOPTIMIZER_H
|
||||
|
||||
#include "../../beacon/setup/BeaconFingerprint.h"
|
||||
#include "WiFiFingerprints.h"
|
||||
#include "WiFiOptimizerStructs.h"
|
||||
#include "../VAPGrouper.h"
|
||||
@@ -19,65 +20,79 @@
|
||||
|
||||
namespace WiFiOptimizer {
|
||||
|
||||
enum class Mode {
|
||||
FAST,
|
||||
MEDIUM,
|
||||
QUALITY,
|
||||
};
|
||||
enum class Mode {
|
||||
FAST,
|
||||
MEDIUM,
|
||||
QUALITY,
|
||||
};
|
||||
|
||||
|
||||
/** base-class for all WiFiOptimizers */
|
||||
class Base {
|
||||
/** base-class for all WiFiOptimizers */
|
||||
class Base {
|
||||
|
||||
protected:
|
||||
protected:
|
||||
|
||||
/** each MAC-Adress has several position->rssi entries */
|
||||
std::unordered_map<MACAddress, std::vector<RSSIatPosition>> apMap;
|
||||
/** each MAC-Adress has several position->rssi entries */
|
||||
std::unordered_map<MACAddress, std::vector<RSSIatPosition>> apMap;
|
||||
|
||||
/** how to handle virtual access points [group, not-group, ..] */
|
||||
const VAPGrouper vg;
|
||||
/** how to handle virtual access points [group, not-group, ..] */
|
||||
const VAPGrouper vg;
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Base(const VAPGrouper vg) : vg(vg) {;}
|
||||
/** ctor */
|
||||
Base(const VAPGrouper vg) : vg(vg) {;}
|
||||
|
||||
/** get a list of all to-be-optimized access-points (given by their mac-address) */
|
||||
virtual std::vector<MACAddress> getAllMACs() const {
|
||||
std::vector<MACAddress> res;
|
||||
for (const auto& it : apMap) {res.push_back(it.first);}
|
||||
return res;
|
||||
}
|
||||
/** get a list of all to-be-optimized access-points (given by their mac-address) */
|
||||
virtual std::vector<MACAddress> getAllMACs() const {
|
||||
std::vector<MACAddress> res;
|
||||
for (const auto& it : apMap) {res.push_back(it.first);}
|
||||
return res;
|
||||
}
|
||||
|
||||
/** get all [VAPGrouped, Averaged] fingerprints for the given mac */
|
||||
virtual const std::vector<RSSIatPosition>& getFingerprintsFor(const MACAddress& mac) {
|
||||
const auto& it = apMap.find(mac);
|
||||
if (it == apMap.end()) {throw Exception("mac not found: " + mac.asString());}
|
||||
return it->second;
|
||||
}
|
||||
/** get all [VAPGrouped, Averaged] fingerprints for the given mac */
|
||||
virtual const std::vector<RSSIatPosition>& getFingerprintsFor(const MACAddress& mac) {
|
||||
const auto& it = apMap.find(mac);
|
||||
if (it == apMap.end()) {throw Exception("mac not found: " + mac.asString());}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/** add a new fingerprint to the optimizer as data-source */
|
||||
virtual void addFingerprint(const WiFiFingerprint& fp) {
|
||||
/** add a new fingerprint to the optimizer as data-source */
|
||||
virtual void addFingerprint(const WiFiFingerprint& fp) {
|
||||
|
||||
// group the fingerprint's measurements by VAP (if configured)
|
||||
const WiFiMeasurements measurements = vg.group(fp.measurements);
|
||||
// group the fingerprint's measurements by VAP (if configured)
|
||||
const WiFiMeasurements measurements = vg.group(fp.measurements);
|
||||
|
||||
// add each available AP to its slot (lookup map)
|
||||
for (const WiFiMeasurement& m : measurements.entries) {
|
||||
const RSSIatPosition rap(fp.pos_m, m.getRSSI());
|
||||
apMap[m.getAP().getMAC()].push_back(rap);
|
||||
}
|
||||
// add each available AP to its slot (lookup map)
|
||||
for (const WiFiMeasurement& m : measurements.entries) {
|
||||
const RSSIatPosition rap(fp.pos_m, m.getRSSI());
|
||||
apMap[m.getAP().getMAC()].push_back(rap);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** add new fingerprints to the optimizer as data-source */
|
||||
virtual void addFingerprints(const WiFiFingerprints& fps) {
|
||||
for (const WiFiFingerprint& fp : fps.getFingerprints()) {
|
||||
addFingerprint(fp);
|
||||
}
|
||||
}
|
||||
/** add a new bluetooth fingerprint to the optimizer as data-source */
|
||||
virtual void addFingerprint(const BeaconFingerprint& fp) {
|
||||
|
||||
};
|
||||
// group the fingerprint's measurements by VAP (if configured)
|
||||
//const BeaconMeasurements measurements = vg.group(fp.measurements);
|
||||
|
||||
// add each available AP to its slot (lookup map)
|
||||
for (const BeaconMeasurement& m : fp.measurements.entries) {
|
||||
const RSSIatPosition rap(fp.pos_m, m.getRSSI());
|
||||
apMap[m.getBeacon().getMAC()].push_back(rap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** add new fingerprints to the optimizer as data-source */
|
||||
virtual void addFingerprints(const WiFiFingerprints& fps) {
|
||||
for (const WiFiFingerprint& fp : fps.getFingerprints()) {
|
||||
addFingerprint(fp);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -37,355 +37,355 @@
|
||||
|
||||
namespace WiFiOptimizer {
|
||||
|
||||
/**
|
||||
* optimize access-point parameters,
|
||||
* given several fingerprints using the log-dist-ceiling model
|
||||
*/
|
||||
struct LogDistCeiling : public Base {
|
||||
/**
|
||||
* optimize access-point parameters,
|
||||
* given several fingerprints using the log-dist-ceiling model
|
||||
*/
|
||||
struct LogDistCeiling : public Base {
|
||||
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
/**
|
||||
* resulting optimization stats for one AP
|
||||
*/
|
||||
struct Stats {
|
||||
/**
|
||||
* resulting optimization stats for one AP
|
||||
*/
|
||||
struct Stats {
|
||||
|
||||
/** average model<->scan error after optimzing */
|
||||
float error_db;
|
||||
/** average model<->scan error after optimzing */
|
||||
float error_db;
|
||||
|
||||
/** number of fingerprints [= locations] that were used for optimzing */
|
||||
int usedFingerprins;
|
||||
/** number of fingerprints [= locations] that were used for optimzing */
|
||||
int usedFingerprins;
|
||||
|
||||
/** resulting model<->scan error after optimzing for each individual fingerprints [= location] */
|
||||
std::vector<ErrorAtPosition> errors;
|
||||
/** resulting model<->scan error after optimzing for each individual fingerprints [= location] */
|
||||
std::vector<ErrorAtPosition> errors;
|
||||
|
||||
/** get the location where the model estimation reaches the highest negative value [model estimation too low] */
|
||||
ErrorAtPosition getEstErrorMaxNeg() const {
|
||||
auto cmpErrAtPos = [] (const ErrorAtPosition& a, const ErrorAtPosition& b) {return a.getError_db() < b.getError_db();};
|
||||
return *std::min_element(errors.begin(), errors.end(), cmpErrAtPos);
|
||||
}
|
||||
/** get the location where the model estimation reaches the highest negative value [model estimation too low] */
|
||||
ErrorAtPosition getEstErrorMaxNeg() const {
|
||||
auto cmpErrAtPos = [] (const ErrorAtPosition& a, const ErrorAtPosition& b) {return a.getError_db() < b.getError_db();};
|
||||
return *std::min_element(errors.begin(), errors.end(), cmpErrAtPos);
|
||||
}
|
||||
|
||||
/** get the location where the model estimation reaches the highest positive value [model estimation too high] */
|
||||
ErrorAtPosition getEstErrorMaxPos() const {
|
||||
auto cmpErrAtPos = [] (const ErrorAtPosition& a, const ErrorAtPosition& b) {return a.getError_db() < b.getError_db();};
|
||||
return *std::max_element(errors.begin(), errors.end(), cmpErrAtPos);
|
||||
}
|
||||
/** get the location where the model estimation reaches the highest positive value [model estimation too high] */
|
||||
ErrorAtPosition getEstErrorMaxPos() const {
|
||||
auto cmpErrAtPos = [] (const ErrorAtPosition& a, const ErrorAtPosition& b) {return a.getError_db() < b.getError_db();};
|
||||
return *std::max_element(errors.begin(), errors.end(), cmpErrAtPos);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
using APFilter = std::function<bool(const Stats& stats, const MACAddress& mac)>;
|
||||
using APFilter = std::function<bool(const Stats& stats, const MACAddress& mac)>;
|
||||
|
||||
static inline bool NONE(const Stats& stats, const MACAddress& mac) {
|
||||
(void) stats; (void) mac;
|
||||
return false;
|
||||
}
|
||||
static inline bool NONE(const Stats& stats, const MACAddress& mac) {
|
||||
(void) stats; (void) mac;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool MIN_2_FPS(const Stats& stats, const MACAddress& mac) {
|
||||
(void) mac;
|
||||
return stats.usedFingerprins < 2;
|
||||
}
|
||||
static inline bool MIN_2_FPS(const Stats& stats, const MACAddress& mac) {
|
||||
(void) mac;
|
||||
return stats.usedFingerprins < 2;
|
||||
}
|
||||
|
||||
static inline bool MIN_5_FPS(const Stats& stats, const MACAddress& mac) {
|
||||
(void) mac;
|
||||
return stats.usedFingerprins < 5;
|
||||
}
|
||||
static inline bool MIN_5_FPS(const Stats& stats, const MACAddress& mac) {
|
||||
(void) mac;
|
||||
return stats.usedFingerprins < 5;
|
||||
}
|
||||
|
||||
static inline bool MIN_10_FPS(const Stats& stats, const MACAddress& mac) {
|
||||
(void) mac;
|
||||
return stats.usedFingerprins < 10;
|
||||
}
|
||||
static inline bool MIN_10_FPS(const Stats& stats, const MACAddress& mac) {
|
||||
(void) mac;
|
||||
return stats.usedFingerprins < 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** parameters for one AP when using the LogDistCeiling model */
|
||||
struct APParams {
|
||||
/** parameters for one AP when using the LogDistCeiling model */
|
||||
struct APParams {
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
float txp;
|
||||
float exp;
|
||||
float waf;
|
||||
float txp;
|
||||
float exp;
|
||||
float waf;
|
||||
|
||||
/** ctor */
|
||||
APParams() {;}
|
||||
/** ctor */
|
||||
APParams() {;}
|
||||
|
||||
/** ctor */
|
||||
APParams(float x, float y, float z, float txp, float exp, float waf) : x(x), y(y), z(z), txp(txp), exp(exp), waf(waf) {;}
|
||||
/** ctor */
|
||||
APParams(float x, float y, float z, float txp, float exp, float waf) : x(x), y(y), z(z), txp(txp), exp(exp), waf(waf) {;}
|
||||
|
||||
Point3 getPos() const {return Point3(x,y,z);}
|
||||
Point3 getPos() const {return Point3(x,y,z);}
|
||||
|
||||
std::string asString() const {
|
||||
std::stringstream ss;
|
||||
ss << "Pos:" << getPos().asString() << " TXP:" << txp << " EXP:" << exp << " WAF:" << waf;
|
||||
return ss.str();
|
||||
}
|
||||
std::string asString() const {
|
||||
std::stringstream ss;
|
||||
ss << "Pos:" << getPos().asString() << " TXP:" << txp << " EXP:" << exp << " WAF:" << waf;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/** we add some constraints to the parameter range */
|
||||
bool outOfRange() const {
|
||||
return (waf > 0) ||
|
||||
(txp < -50) ||
|
||||
(txp > -30) ||
|
||||
(exp > 4) ||
|
||||
(exp < 1);
|
||||
}
|
||||
/** we add some constraints to the parameter range */
|
||||
bool outOfRange() const {
|
||||
return (waf > 0) ||
|
||||
(txp < -65) ||
|
||||
(txp > -45) ||
|
||||
(exp > 5) ||
|
||||
(exp < 1);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
/** add MAC-info to params */
|
||||
struct APParamsMAC {
|
||||
MACAddress mac;
|
||||
APParams params;
|
||||
APParamsMAC(const MACAddress mac, const APParams& params) : mac(mac), params(params) {;}
|
||||
};
|
||||
/** add MAC-info to params */
|
||||
struct APParamsMAC {
|
||||
MACAddress mac;
|
||||
APParams params;
|
||||
APParamsMAC(const MACAddress mac, const APParams& params) : mac(mac), params(params) {;}
|
||||
};
|
||||
|
||||
struct OptResultStats {
|
||||
K::Statistics<float> avgApErrors; // contains one average-error per optimized AP
|
||||
K::Statistics<float> singleFPErrors; // contains one error for each fingerprint<->ap SIGNED
|
||||
K::Statistics<float> singleFPErrorsAbs; // contains one error for each fingerprint<->ap ABSOLUTE
|
||||
struct OptResultStats {
|
||||
K::Statistics<float> avgApErrors; // contains one average-error per optimized AP
|
||||
K::Statistics<float> singleFPErrors; // contains one error for each fingerprint<->ap SIGNED
|
||||
K::Statistics<float> singleFPErrorsAbs; // contains one error for each fingerprint<->ap ABSOLUTE
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
class APParamsList {
|
||||
class APParamsList {
|
||||
|
||||
std::vector<APParamsMAC> lst;
|
||||
std::vector<APParamsMAC> lst;
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
APParamsList(const std::vector<APParamsMAC>& lst) : lst(lst) {
|
||||
/** ctor */
|
||||
APParamsList(const std::vector<APParamsMAC>& lst) : lst(lst) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/** get the list */
|
||||
const std::vector<APParamsMAC>& get() const {
|
||||
return lst;
|
||||
}
|
||||
/** get the list */
|
||||
const std::vector<APParamsMAC>& get() const {
|
||||
return lst;
|
||||
}
|
||||
|
||||
/** get params for the given mac [if known, otherwise nullptr] */
|
||||
const APParamsMAC* get (const MACAddress& mac) const {
|
||||
for (const APParamsMAC& ap : lst) {
|
||||
if (ap.mac == mac) {return ≈}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
/** get params for the given mac [if known, otherwise nullptr] */
|
||||
const APParamsMAC* get (const MACAddress& mac) const {
|
||||
for (const APParamsMAC& ap : lst) {
|
||||
if (ap.mac == mac) {return ≈}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
Floorplan::IndoorMap* map;
|
||||
Floorplan::IndoorMap* map;
|
||||
|
||||
Mode mode = Mode::QUALITY;
|
||||
Mode mode = Mode::QUALITY;
|
||||
|
||||
const char* name = "WiFiOptLDC";
|
||||
const char* name = "WiFiOptLDC";
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
LogDistCeiling(Floorplan::IndoorMap* map, const VAPGrouper& vg, const Mode mode = Mode::QUALITY) : Base(vg), map(map), mode(mode) {
|
||||
;
|
||||
}
|
||||
/** ctor */
|
||||
LogDistCeiling(Floorplan::IndoorMap* map, const VAPGrouper& vg, const Mode mode = Mode::MEDIUM) : Base(vg), map(map), mode(mode) {
|
||||
;
|
||||
}
|
||||
|
||||
/** ctor */
|
||||
LogDistCeiling(Floorplan::IndoorMap* map, const VAPGrouper& vg, const WiFiFingerprints& fps, const Mode mode = Mode::QUALITY) : Base(vg), map(map), mode(mode) {
|
||||
addFingerprints(fps);
|
||||
}
|
||||
/** ctor */
|
||||
LogDistCeiling(Floorplan::IndoorMap* map, const VAPGrouper& vg, const WiFiFingerprints& fps, const Mode mode = Mode::MEDIUM) : Base(vg), map(map), mode(mode) {
|
||||
addFingerprints(fps);
|
||||
}
|
||||
|
||||
/** optimize all known APs */
|
||||
APParamsList optimizeAll(APFilter filter, OptResultStats* dst = nullptr) const {
|
||||
/** optimize all known APs */
|
||||
APParamsList optimizeAll(APFilter filter, OptResultStats* dst = nullptr) const {
|
||||
|
||||
// sanity check
|
||||
Assert::isFalse(getAllMACs().empty(), "no APs found for optimization! call addFingerprint() first!");
|
||||
// sanity check
|
||||
Assert::isFalse(getAllMACs().empty(), "no APs found for optimization! call addFingerprint() first!");
|
||||
|
||||
K::Statistics<float> avgErrors;
|
||||
K::Statistics<float> singleErrors;
|
||||
K::Statistics<float> singleErrorsAbs;
|
||||
K::Statistics<float> avgErrors;
|
||||
K::Statistics<float> singleErrors;
|
||||
K::Statistics<float> singleErrorsAbs;
|
||||
|
||||
std::vector<APParamsMAC> res;
|
||||
for (const MACAddress& mac : getAllMACs()) {
|
||||
std::vector<APParamsMAC> res;
|
||||
for (const MACAddress& mac : getAllMACs()) {
|
||||
|
||||
// perform optimization, get resulting parameters and optimization stats
|
||||
Stats stats;
|
||||
const APParams params = optimize(mac, stats);
|
||||
// perform optimization, get resulting parameters and optimization stats
|
||||
Stats stats;
|
||||
const APParams params = optimize(mac, stats);
|
||||
|
||||
// filter based on stats (option to ignore/filter some access-points)
|
||||
if (!filter(stats, mac)) {
|
||||
res.push_back(APParamsMAC(mac, params));
|
||||
//errSum += stats.error_db;
|
||||
//++errCnt;
|
||||
avgErrors.add(stats.error_db);
|
||||
for (const auto e : stats.errors) {
|
||||
singleErrors.add(e.getError_db());
|
||||
singleErrorsAbs.add(std::abs(e.getError_db()));
|
||||
}
|
||||
} else {
|
||||
Log::add(name, "ignoring opt-result for AP " + mac.asString() + " due to filter");
|
||||
//std::cout << "ignored due to filter!" << std::endl;
|
||||
}
|
||||
// filter based on stats (option to ignore/filter some access-points)
|
||||
if (!filter(stats, mac)) {
|
||||
res.push_back(APParamsMAC(mac, params));
|
||||
//errSum += stats.error_db;
|
||||
//++errCnt;
|
||||
avgErrors.add(stats.error_db);
|
||||
for (const auto e : stats.errors) {
|
||||
singleErrors.add(e.getError_db());
|
||||
singleErrorsAbs.add(std::abs(e.getError_db()));
|
||||
}
|
||||
} else {
|
||||
Log::add(name, "ignoring opt-result for AP " + mac.asString() + " due to filter");
|
||||
//std::cout << "ignored due to filter!" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//const float avgErr = errSum / errCnt;
|
||||
//Log::add(name, "optimized APs: " + std::to_string(errCnt));
|
||||
//Log::add(name, "average AP error is: " + std::to_string(avgErr) + " dB");
|
||||
Log::add(name, "optimization result: ");
|
||||
Log::add(name, " - AvgPerAP " + avgErrors.asString());
|
||||
Log::add(name, " - Single: " + singleErrors.asString());
|
||||
Log::add(name, " - SingleAbs: " + singleErrorsAbs.asString());
|
||||
//const float avgErr = errSum / errCnt;
|
||||
//Log::add(name, "optimized APs: " + std::to_string(errCnt));
|
||||
//Log::add(name, "average AP error is: " + std::to_string(avgErr) + " dB");
|
||||
Log::add(name, "optimization result: ");
|
||||
Log::add(name, " - AvgPerAP " + avgErrors.asString());
|
||||
Log::add(name, " - Single: " + singleErrors.asString());
|
||||
Log::add(name, " - SingleAbs: " + singleErrorsAbs.asString());
|
||||
|
||||
if (dst) {
|
||||
dst->avgApErrors = avgErrors;
|
||||
dst->singleFPErrors = singleErrors;
|
||||
dst->singleFPErrorsAbs = singleErrorsAbs;
|
||||
}
|
||||
if (dst) {
|
||||
dst->avgApErrors = avgErrors;
|
||||
dst->singleFPErrors = singleErrors;
|
||||
dst->singleFPErrorsAbs = singleErrorsAbs;
|
||||
}
|
||||
|
||||
// done
|
||||
return APParamsList(res);
|
||||
// done
|
||||
return APParamsList(res);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** optimize the given AP */
|
||||
APParams optimize(const MACAddress& mac, Stats& res) const {
|
||||
/** optimize the given AP */
|
||||
APParams optimize(const MACAddress& mac, Stats& res) const {
|
||||
|
||||
// starting parameters do not matter for the current optimizer!
|
||||
APParams params(0,0,0, -40, 2.5, -4.0);
|
||||
// starting parameters do not matter for the current optimizer!
|
||||
APParams params(0,0,0, -59, 3, -8.0);
|
||||
|
||||
// get all position->rssi measurements for this AP to compare them with the corresponding model estimations
|
||||
const std::vector<RSSIatPosition>& entries = apMap.find(mac)->second;
|
||||
// get all position->rssi measurements for this AP to compare them with the corresponding model estimations
|
||||
const std::vector<RSSIatPosition>& entries = apMap.find(mac)->second;
|
||||
|
||||
// log
|
||||
Log::add(name, "optimizing parameters for AP " + mac.asString() + " by using " + std::to_string(entries.size()) + " fingerprints", false);
|
||||
Log::tick();
|
||||
// log
|
||||
Log::add(name, "optimizing parameters for AP " + mac.asString() + " by using " + std::to_string(entries.size()) + " fingerprints", false);
|
||||
Log::tick();
|
||||
|
||||
// get the map's size
|
||||
const BBox3 mapBBox = FloorplanHelper::getBBox(map);
|
||||
// get the map's size
|
||||
const BBox3 mapBBox = FloorplanHelper::getBBox(map);
|
||||
|
||||
using LeOpt = K::NumOptAlgoRangeRandom<float>;
|
||||
const std::vector<LeOpt::MinMax> valRegion = {
|
||||
LeOpt::MinMax(mapBBox.getMin().x - 20, mapBBox.getMax().x + 20), // x
|
||||
LeOpt::MinMax(mapBBox.getMin().y - 20, mapBBox.getMax().y + 20), // y
|
||||
LeOpt::MinMax(mapBBox.getMin().z - 6, mapBBox.getMax().z + 6), // z
|
||||
LeOpt::MinMax(-50, -30), // txp
|
||||
LeOpt::MinMax(1, 4), // exp
|
||||
LeOpt::MinMax(-15, -0), // waf
|
||||
};
|
||||
using LeOpt = K::NumOptAlgoRangeRandom<float>;
|
||||
const std::vector<LeOpt::MinMax> valRegion = {
|
||||
LeOpt::MinMax(mapBBox.getMin().x - 20, mapBBox.getMax().x + 20), // x
|
||||
LeOpt::MinMax(mapBBox.getMin().y - 20, mapBBox.getMax().y + 20), // y
|
||||
LeOpt::MinMax(mapBBox.getMin().z - 6, mapBBox.getMax().z + 6), // z
|
||||
LeOpt::MinMax(-65, -45), // txp
|
||||
LeOpt::MinMax(1, 5), // exp
|
||||
LeOpt::MinMax(-15, -0), // waf
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
LeOpt opt(valRegion);
|
||||
LeOpt opt(valRegion);
|
||||
|
||||
switch(mode) {
|
||||
case Mode::FAST:
|
||||
opt.setPopulationSize(100);
|
||||
opt.setNumIerations(50);
|
||||
break;
|
||||
case Mode::MEDIUM:
|
||||
opt.setPopulationSize(200);
|
||||
opt.setNumIerations(100);
|
||||
break;
|
||||
case Mode::QUALITY:
|
||||
opt.setPopulationSize(1500);
|
||||
opt.setNumIerations(150);
|
||||
break;
|
||||
}
|
||||
switch(mode) {
|
||||
case Mode::FAST:
|
||||
opt.setPopulationSize(100);
|
||||
opt.setNumIerations(50);
|
||||
break;
|
||||
case Mode::MEDIUM:
|
||||
opt.setPopulationSize(200);
|
||||
opt.setNumIerations(100);
|
||||
break;
|
||||
case Mode::QUALITY:
|
||||
opt.setPopulationSize(1500);
|
||||
opt.setNumIerations(150);
|
||||
break;
|
||||
}
|
||||
|
||||
// error function
|
||||
auto func = [&] (const float* params) {
|
||||
return getErrorLogDistCeiling(mac, entries, params, nullptr);
|
||||
};
|
||||
// error function
|
||||
auto func = [&] (const float* params) {
|
||||
return getErrorLogDistCeiling(mac, entries, params, nullptr);
|
||||
};
|
||||
|
||||
opt.calculateOptimum(func, (float*) ¶ms);
|
||||
opt.calculateOptimum(func, (float*) ¶ms);
|
||||
|
||||
// using LeOpt = K::NumOptAlgoGenetic<float>;
|
||||
// LeOpt opt(6);
|
||||
// opt.setPopulationSize(750);
|
||||
// opt.setMaxIterations(50);
|
||||
// opt.setElitism(0.05f);
|
||||
// opt.setMutation(0.75f);
|
||||
// //opt.setValRange({0.5, 0.5, 0.5, 0.1, 0.1, 0.1});
|
||||
// opt.setValRegion(valRegion);
|
||||
// using LeOpt = K::NumOptAlgoGenetic<float>;
|
||||
// LeOpt opt(6);
|
||||
// opt.setPopulationSize(750);
|
||||
// opt.setMaxIterations(50);
|
||||
// opt.setElitism(0.05f);
|
||||
// opt.setMutation(0.75f);
|
||||
// //opt.setValRange({0.5, 0.5, 0.5, 0.1, 0.1, 0.1});
|
||||
// opt.setValRegion(valRegion);
|
||||
|
||||
// K::NumOptAlgoDownhillSimplex<float, 6> opt;
|
||||
// opt.setMaxIterations(100);
|
||||
// opt.setNumRestarts(10);
|
||||
// K::NumOptAlgoDownhillSimplex<float, 6> opt;
|
||||
// opt.setMaxIterations(100);
|
||||
// opt.setNumRestarts(10);
|
||||
|
||||
opt.calculateOptimum(func, (float*) ¶ms);
|
||||
res.error_db = getErrorLogDistCeiling(mac, entries, (float*)¶ms, &res);
|
||||
res.usedFingerprins = entries.size();
|
||||
opt.calculateOptimum(func, (float*) ¶ms);
|
||||
res.error_db = getErrorLogDistCeiling(mac, entries, (float*)¶ms, &res);
|
||||
res.usedFingerprins = entries.size();
|
||||
|
||||
Log::tock();
|
||||
Log::add(name, mac.asString() + ": " + params.asString() + " @ " + std::to_string(res.error_db) +" dB err");
|
||||
Log::tock();
|
||||
Log::add(name, mac.asString() + ": " + params.asString() + " @ " + std::to_string(res.error_db) +" dB err");
|
||||
|
||||
return params;
|
||||
return params;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
float getErrorLogDistCeiling(const MACAddress& mac, const std::vector<RSSIatPosition>& entries, const float* data, Stats* stats = nullptr) const {
|
||||
float getErrorLogDistCeiling(const MACAddress& mac, const std::vector<RSSIatPosition>& entries, const float* data, Stats* stats = nullptr) const {
|
||||
|
||||
const APParams* params = (APParams*) data;
|
||||
const APParams* params = (APParams*) data;
|
||||
|
||||
// some sanity checks
|
||||
if (params->outOfRange()) {return 1e10;}
|
||||
// some sanity checks
|
||||
if (params->outOfRange()) {return 1e10;}
|
||||
|
||||
// current position guess for the AP;
|
||||
const Point3 apPos_m = params->getPos();
|
||||
// current position guess for the AP;
|
||||
const Point3 apPos_m = params->getPos();
|
||||
|
||||
// add the AP [described by the current guess] to the signal-strength-prediction model
|
||||
// signal-strength-prediction-model...
|
||||
WiFiModelLogDistCeiling model(map);
|
||||
model.addAP(mac, WiFiModelLogDistCeiling::APEntry(apPos_m, params->txp, params->exp, params->waf));
|
||||
// add the AP [described by the current guess] to the signal-strength-prediction model
|
||||
// signal-strength-prediction-model...
|
||||
WiFiModelLogDistCeiling model(map);
|
||||
model.addAP(mac, WiFiModelLogDistCeiling::APEntry(apPos_m, params->txp, params->exp, params->waf));
|
||||
|
||||
float err = 0;
|
||||
int cnt = 0;
|
||||
float err = 0;
|
||||
int cnt = 0;
|
||||
|
||||
// process each measurement
|
||||
for (const RSSIatPosition& reading : entries) {
|
||||
// process each measurement
|
||||
for (const RSSIatPosition& reading : entries) {
|
||||
|
||||
// get the model-estimation for the fingerprint's position
|
||||
const float rssiModel = model.getRSSI(mac, reading.pos_m);
|
||||
// get the model-estimation for the fingerprint's position
|
||||
const float rssiModel = model.getRSSI(mac, reading.pos_m);
|
||||
|
||||
// difference between estimation and measurement
|
||||
const float diff = std::abs(rssiModel - reading.rssi);
|
||||
// difference between estimation and measurement
|
||||
const float diff = std::abs(rssiModel - reading.rssi);
|
||||
|
||||
// add error to stats object?
|
||||
if (stats) {
|
||||
stats->errors.push_back(ErrorAtPosition(reading.pos_m, reading.rssi, rssiModel));
|
||||
}
|
||||
// add error to stats object?
|
||||
if (stats) {
|
||||
stats->errors.push_back(ErrorAtPosition(reading.pos_m, reading.rssi, rssiModel));
|
||||
}
|
||||
|
||||
// adjust the error
|
||||
err += std::pow(std::abs(diff), 2.0);
|
||||
++cnt;
|
||||
// adjust the error
|
||||
err += std::pow(std::abs(diff), 2.0);
|
||||
++cnt;
|
||||
|
||||
// max distance penality
|
||||
// [unlikely to get a reading for this AP here!]
|
||||
if (apPos_m.getDistance(reading.pos_m) > 150) {err += 999999;}
|
||||
// max distance penality
|
||||
// [unlikely to get a reading for this AP here!]
|
||||
if (apPos_m.getDistance(reading.pos_m) > 150) {err += 999999;}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
err /= cnt;
|
||||
err = std::sqrt(err);
|
||||
err /= cnt;
|
||||
err = std::sqrt(err);
|
||||
|
||||
if (params->txp < -50) {err += 999999;}
|
||||
if (params->txp > -35) {err += 999999;}
|
||||
if (params->txp < -65) {err += 999999;}
|
||||
if (params->txp > -45) {err += 999999;}
|
||||
|
||||
if (params->exp > 3.5) {err += 999999;}
|
||||
if (params->exp < 1.0) {err += 999999;}
|
||||
if (params->exp > 5) {err += 999999;}
|
||||
if (params->exp < 1.0) {err += 999999;}
|
||||
|
||||
return err;
|
||||
return err;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user