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:
276
sensors/beacon/BeaconMeasurementGrouper.h
Normal file
276
sensors/beacon/BeaconMeasurementGrouper.h
Normal file
@@ -0,0 +1,276 @@
|
||||
#ifndef BEACONMEASUREMENTGROUPER_H
|
||||
#define BEACONMEASUREMENTGROUPER_H
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <cmath>
|
||||
|
||||
#include "../../math/Stats.h"
|
||||
|
||||
#include "../../misc/Debug.h"
|
||||
|
||||
#include "BeaconMeasurements.h"
|
||||
|
||||
class BeaconMeasurementGrouper {
|
||||
|
||||
public:
|
||||
|
||||
/** the mode denotes the algorithm that is used for grouping VAPs together */
|
||||
enum class Mode {
|
||||
|
||||
/** do NOT group */
|
||||
DISABLED,
|
||||
|
||||
/** group VAPs by setting the MAC's last digit to zero */
|
||||
LAST_MAC_DIGIT_TO_ZERO,
|
||||
|
||||
};
|
||||
|
||||
/** describes how to calculate the final signal-strengh of the VAP-grouped entry */
|
||||
enum class Aggregation {
|
||||
|
||||
/** use the average signal-strength of all grouped APs */
|
||||
AVERAGE,
|
||||
|
||||
/** use the median signal-strength of all grouped APs */
|
||||
MEDIAN,
|
||||
|
||||
/** use the maximum signal-strength of all grouped APs */
|
||||
MAXIMUM,
|
||||
|
||||
/** use std-dev around the signal-strength average of all grouped APs. NOTE not directly useful but for debug! */
|
||||
STD_DEV,
|
||||
|
||||
};
|
||||
|
||||
/** how to determine the grouped timestamp */
|
||||
enum class TimeAggregation {
|
||||
|
||||
/** use the smallest timestamp among all grouped APs */
|
||||
MINIMUM,
|
||||
|
||||
/** use the average timestamp among all grouped APs */
|
||||
AVERAGE,
|
||||
|
||||
/** use the maximum timestamp among all grouped APs */
|
||||
MAXIMUM,
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
static constexpr const char* name = "BLEGrp";
|
||||
|
||||
/** the mode to use for grouping VAPs */
|
||||
const Mode mode;
|
||||
|
||||
/** the signal-strength aggregation algorithm to use */
|
||||
const Aggregation rssiAgg;
|
||||
|
||||
/** how to aggreage the grouped time */
|
||||
const TimeAggregation timeAgg;
|
||||
|
||||
/** respect only outputs with at-least X occurences of one physical hardware [can be used to prevent issues] */
|
||||
int minOccurences;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
BeaconMeasurementGrouper(const Mode mode, const Aggregation rssiAgg, const TimeAggregation timeAgg = TimeAggregation::AVERAGE, const int minOccurences = 2) :
|
||||
mode(mode), rssiAgg(rssiAgg), timeAgg(timeAgg), minOccurences(minOccurences) {
|
||||
;
|
||||
}
|
||||
|
||||
/** set the number of needed occurences per VAP-group to be accepted */
|
||||
void setMinOccurences(const int min) {
|
||||
this->minOccurences = min;
|
||||
}
|
||||
|
||||
/** get a vap-grouped version of the given input */
|
||||
BeaconMeasurements group(const BeaconMeasurements& original) const {
|
||||
|
||||
// first, group all VAPs into a vector [one vector per VAP-group]
|
||||
// by using the modified MAC address that all VAPs have in common
|
||||
std::unordered_map<MACAddress, std::vector<BeaconMeasurement>> grouped;
|
||||
|
||||
for (const BeaconMeasurement& m : original.entries) {
|
||||
|
||||
// the vap-base-mac this entry belongs to
|
||||
const MACAddress baseMAC = getBaseMAC(m.getBeacon().getMAC());
|
||||
grouped[baseMAC].push_back(m);
|
||||
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_LOG
|
||||
std::stringstream vals;
|
||||
vals << std::fixed;
|
||||
vals.precision(1);
|
||||
#endif
|
||||
|
||||
// to-be-constructed output
|
||||
BeaconMeasurements result;
|
||||
int skipped = 0;
|
||||
|
||||
// perform aggregation on each VAP-group
|
||||
for (auto it : grouped) {
|
||||
|
||||
const MACAddress& base = it.first;
|
||||
const std::vector<BeaconMeasurement>& vaps = it.second;
|
||||
|
||||
// remove entries that do not satify the min-occurences metric
|
||||
if ((int)vaps.size() < minOccurences) {++skipped; continue;}
|
||||
|
||||
// group all VAPs into one measurement
|
||||
const BeaconMeasurement groupedMeasurement = groupVAPs(base, vaps, rssiAgg, timeAgg);
|
||||
|
||||
// get corresponding std-dev for debug
|
||||
#ifdef WITH_DEBUG_LOG
|
||||
const BeaconMeasurement groupedStdDev = groupVAPs(base, vaps, Aggregation::STD_DEV, timeAgg);
|
||||
vals << groupedMeasurement.getRSSI() << "±";
|
||||
vals << groupedStdDev.getRSSI() << " ";
|
||||
#endif
|
||||
|
||||
// add it to the result-vector
|
||||
result.entries.push_back(groupedMeasurement);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// debug
|
||||
#ifdef WITH_DEBUG_LOG
|
||||
Log::add(name,
|
||||
"grouped " + std::to_string(original.entries.size()) + " measurements " +
|
||||
"into " + std::to_string(result.entries.size()) + " [omitted: " + std::to_string(skipped) + "]" +
|
||||
" Stats:[" + vals.str() + "]",
|
||||
true
|
||||
);
|
||||
#endif
|
||||
|
||||
// done
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/** get the VAP-base-MAC-Address that is the same for all APs that belong to a VAP-Group */
|
||||
MACAddress getBaseMAC(const MACAddress& mac) const {
|
||||
|
||||
switch(mode) {
|
||||
case Mode::DISABLED: return mac;
|
||||
case Mode::LAST_MAC_DIGIT_TO_ZERO: return lastMacDigitToZero(mac);
|
||||
default: throw Exception("unsupported vap-grouping mode given");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct FieldRSSI {
|
||||
static float get(const BeaconMeasurement& m) { return m.getRSSI(); }
|
||||
};
|
||||
struct FieldTS {
|
||||
static Timestamp get(const BeaconMeasurement& m) { return m.getTimestamp(); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** combine all of the given VAPs into one entry using the configured aggregation method */
|
||||
static BeaconMeasurement groupVAPs(const MACAddress& baseMAC, const std::vector<BeaconMeasurement>& vaps, Aggregation aggRssi, TimeAggregation aggTime) {
|
||||
|
||||
// the resulting entry is an AP with the base-MAC all of the given VAPs have in common
|
||||
const Beacon baseAP(baseMAC);
|
||||
|
||||
// calculate the rssi using the configured aggregate function
|
||||
float rssi = NAN;
|
||||
switch(aggRssi) {
|
||||
case Aggregation::AVERAGE: rssi = getAVG<float, FieldRSSI>(vaps); break;
|
||||
case Aggregation::MEDIAN: rssi = getMedian(vaps); break;
|
||||
case Aggregation::MAXIMUM: rssi = getMax<float, FieldRSSI>(vaps); break;
|
||||
case Aggregation::STD_DEV: rssi = getStdDev<float, FieldRSSI>(vaps); break;
|
||||
default: throw Exception("unsupported rssi-aggregation method");
|
||||
}
|
||||
|
||||
// calculate the time using the configured aggregate function
|
||||
Timestamp baseTS;
|
||||
switch(aggTime) {
|
||||
case TimeAggregation::MINIMUM: baseTS = getMin<Timestamp, FieldTS>(vaps); break;
|
||||
case TimeAggregation::AVERAGE: baseTS = getAVG<Timestamp, FieldTS>(vaps); break;
|
||||
case TimeAggregation::MAXIMUM: baseTS = getMax<Timestamp, FieldTS>(vaps); break;
|
||||
default: throw Exception("unsupported time-aggregation method");
|
||||
}
|
||||
|
||||
|
||||
// create the result measurement
|
||||
return BeaconMeasurement(baseTS, baseAP, rssi);
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** get the average signal strength */
|
||||
template <typename T, typename Field> static inline T getAVG(const std::vector<BeaconMeasurement>& vaps) {
|
||||
|
||||
Stats::Average<T> avg;
|
||||
for (const BeaconMeasurement& vap : vaps) {
|
||||
avg.add(Field::get(vap));
|
||||
}
|
||||
return avg.get();
|
||||
|
||||
}
|
||||
|
||||
/** get the std-dev around the average */
|
||||
template <typename T, typename Field> static inline T getStdDev(const std::vector<BeaconMeasurement>& vaps) {
|
||||
|
||||
Stats::Variance<T> var;
|
||||
for (const BeaconMeasurement& vap : vaps) {
|
||||
var.add(Field::get(vap));
|
||||
}
|
||||
return var.getStdDev();
|
||||
|
||||
}
|
||||
|
||||
/** get the median signal strength */
|
||||
static inline float getMedian(const std::vector<BeaconMeasurement>& vaps) {
|
||||
|
||||
Stats::Median<float> median;
|
||||
for (const BeaconMeasurement& vap : vaps) {
|
||||
median.add(vap.getRSSI());
|
||||
}
|
||||
return median.get();
|
||||
|
||||
}
|
||||
|
||||
/** get the maximum value */
|
||||
template <typename T, typename Field> static inline T getMax(const std::vector<BeaconMeasurement>& vaps) {
|
||||
|
||||
Stats::Maximum<T> max;
|
||||
for (const BeaconMeasurement& vap : vaps) {
|
||||
max.add(Field::get(vap));
|
||||
}
|
||||
return max.get();
|
||||
|
||||
}
|
||||
|
||||
/** get the minimum value */
|
||||
template <typename T, typename Field> static inline T getMin(const std::vector<BeaconMeasurement>& vaps) {
|
||||
|
||||
Stats::Minimum<T> min;
|
||||
for (const BeaconMeasurement& vap : vaps) {
|
||||
min.add(Field::get(vap));
|
||||
}
|
||||
return min.get();
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/** convert the MAC by setting the last (right-most) digit to zero (0) */
|
||||
static inline MACAddress lastMacDigitToZero(const MACAddress& mac) {
|
||||
std::string str = mac.asString();
|
||||
str.back() = '0';
|
||||
return MACAddress(str);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // BEACONMEASUREMENTGROUPER_H
|
||||
@@ -22,12 +22,12 @@ struct BeaconMeasurements {
|
||||
|
||||
std::vector<BeaconMeasurement> entries;
|
||||
|
||||
/** remove entries older then 3000 ms*/
|
||||
/** remove entries older then 1000 ms*/
|
||||
void removeOld(const Timestamp latestTS) {
|
||||
|
||||
std::vector<BeaconMeasurement>::iterator it;
|
||||
for (it = entries.begin(); it != entries.end(); ++it){
|
||||
if(latestTS - it->getTimestamp() > Timestamp::fromMS(1000*3)){
|
||||
if(latestTS - it->getTimestamp() > Timestamp::fromMS(1000)){
|
||||
entries.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include "BeaconProbability.h"
|
||||
#include "BeaconMeasurements.h"
|
||||
#include "model/BeaconModel.h"
|
||||
#include "../../math/Distributions.h"
|
||||
#include "../../math/distribution/Normal.h"
|
||||
#include "../../data/Timestamp.h"
|
||||
|
||||
#include "../../floorplan/v2/Floorplan.h"
|
||||
@@ -29,7 +29,7 @@ class BeaconObserverFree : public BeaconProbability {
|
||||
|
||||
private:
|
||||
|
||||
const float sigma = 8.0f;
|
||||
const float sigma = 10.0f;
|
||||
const float sigmaPerSecond = 3.0f;
|
||||
|
||||
/** the RSSI prediction model */
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
// updating the beacons sended txp if available
|
||||
if(entry.getBeacon().getTXP() != 0.0f){
|
||||
//TODO: check if this works
|
||||
model.updateBeacon(entry);
|
||||
//model.updateBeacon(entry);
|
||||
}
|
||||
|
||||
// get the model's RSSI (if possible!)
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "../BeaconMeasurement.h"
|
||||
#include "../../../geo/Point3.h"
|
||||
|
||||
#include "../../../data/XMLserialize.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
@@ -23,13 +25,16 @@
|
||||
* 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 BeaconModel {
|
||||
class BeaconModel : public XMLserialize {
|
||||
|
||||
public:
|
||||
|
||||
// /** get the given access-point's RSSI at the provided location */
|
||||
// virtual float getRSSI(const LocatedAccessPoint& ap, const Point3 p) = 0;
|
||||
|
||||
/** dtor */
|
||||
virtual ~BeaconModel() {;}
|
||||
|
||||
/** get a list of all APs known to the model */
|
||||
virtual std::vector<Beacon> getAllBeacons() const = 0;
|
||||
|
||||
|
||||
@@ -59,8 +59,8 @@ public:
|
||||
void addAP(const MACAddress& beacon, 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]");
|
||||
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
|
||||
beacons.insert( std::pair<MACAddress, APEntry>(beacon, params) );
|
||||
|
||||
@@ -12,12 +12,16 @@
|
||||
#define BEACONMODELLOGDISTCEILING_H
|
||||
|
||||
#include "../../../floorplan/v2/Floorplan.h"
|
||||
#include "../../../floorplan/v2/FloorplanCeilings.h"
|
||||
|
||||
#include "../../../Assertions.h"
|
||||
#include "BeaconModel.h"
|
||||
#include "../../radio/model/LogDistanceModel.h"
|
||||
#include "../BeaconMeasurement.h"
|
||||
|
||||
#include "../../../data/XMLserialize.h"
|
||||
#include "../../../misc/Debug.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
@@ -26,6 +30,8 @@
|
||||
*/
|
||||
class BeaconModelLogDistCeiling : public BeaconModel {
|
||||
|
||||
static constexpr const char* name = "BLEModelLDC";
|
||||
|
||||
public:
|
||||
|
||||
/** parameters describing one beacon to the model */
|
||||
@@ -48,21 +54,17 @@ private:
|
||||
std::unordered_map<MACAddress, APEntry> beacons;
|
||||
|
||||
/** position (height) of all ceilings (in meter) */
|
||||
std::vector<float> ceilingsAtHeight_m;
|
||||
//std::vector<float> ceilingsAtHeight_m;
|
||||
Floorplan::Ceilings ceilings;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor with floorplan (needed for ceiling position) */
|
||||
BeaconModelLogDistCeiling(const Floorplan::IndoorMap* map) {
|
||||
BeaconModelLogDistCeiling(const Floorplan::IndoorMap* map) : ceilings(map){
|
||||
|
||||
// sanity checks
|
||||
Assert::isTrue(map->floors.size() >= 1, "map has no floors?!");
|
||||
|
||||
// position of all ceilings
|
||||
for (Floorplan::Floor* f : map->floors) {
|
||||
ceilingsAtHeight_m.push_back(f->atHeight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** get a list of all beacons known to the model */
|
||||
@@ -101,8 +103,8 @@ public:
|
||||
|
||||
// sanity check
|
||||
Assert::isBetween(params.waf, -99.0f, 0.0f, "WAF out of bounds [-99:0]");
|
||||
Assert::isBetween(params.txp, -90.0f, -30.0f, "TXP out of bounds [-50:-30]");
|
||||
Assert::isBetween(params.exp, 1.0f, 4.0f, "EXP out of bounds [1:4]");
|
||||
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(beacons.find(beacon), beacons.end(), "AccessPoint already present!");
|
||||
|
||||
@@ -144,74 +146,135 @@ 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 * numCeilingsBetween(position_m, params.position_m);
|
||||
const float wafLoss = params.waf * ceilings.numCeilingsBetweenFloat(position_m, params.position_m);
|
||||
|
||||
// combine
|
||||
return rssiLOS + wafLoss;
|
||||
const float res = rssiLOS + wafLoss;
|
||||
|
||||
// sanity check
|
||||
Assert::isNotNaN(res, "detected NaN within WiFiModelLogDistCeiling::getRSSI()");
|
||||
|
||||
// ok
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
void writeToXML(XMLDoc* doc, XMLElem* dst) override {
|
||||
|
||||
// set my type
|
||||
dst->SetAttribute("type", "BeaconModelLogDistCeiling");
|
||||
|
||||
protected:
|
||||
|
||||
FRIEND_TEST(LogDistanceCeilingModelBeacon, numCeilings);
|
||||
FRIEND_TEST(LogDistanceCeilingModelBeacon, numCeilingsFloat);
|
||||
|
||||
|
||||
/** get the number of ceilings between z1 and z2 */
|
||||
float numCeilingsBetweenFloat(const Point3 pos1, const Point3 pos2) const {
|
||||
|
||||
|
||||
const float zMin = std::min(pos1.z, pos2.z);
|
||||
const float zMax = std::max(pos1.z, pos2.z);
|
||||
|
||||
float cnt = 0;
|
||||
|
||||
for (const float z : ceilingsAtHeight_m) {
|
||||
if (zMin < z && zMax > z) {
|
||||
const float dmax = zMax - z;
|
||||
cnt += (dmax > 1) ? (1) : (dmax);
|
||||
}
|
||||
for (const auto& it : beacons) {
|
||||
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);
|
||||
}
|
||||
|
||||
return cnt;
|
||||
for (const float atHeight_m : ceilings.getCeilings()) {
|
||||
XMLElem* xceil = doc->NewElement("ceiling");
|
||||
xceil->SetAttribute("atHeight", atHeight_m);
|
||||
dst->InsertEndChild(xceil);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** get the number of ceilings between z1 and z2 */
|
||||
int numCeilingsBetween(const Point3 pos1, const Point3 pos2) const {
|
||||
void readFromXML(XMLDoc* doc, XMLElem* src) override {
|
||||
|
||||
int cnt = 0;
|
||||
const float zMin = std::min(pos1.z, pos2.z);
|
||||
const float zMax = std::max(pos1.z, pos2.z);
|
||||
// check type
|
||||
if (std::string("BeaconModelLogDistCeiling") != src->Attribute("type")) {throw Exception("invalid model type");}
|
||||
|
||||
#ifdef WITH_ASSERTIONS
|
||||
beacons.clear();
|
||||
ceilings.clear();
|
||||
|
||||
static int numNear = 0;
|
||||
static int numFar = 0;
|
||||
for (const float z : ceilingsAtHeight_m) {
|
||||
const float diff = std::min( std::abs(z-zMin), std::abs(z-zMax) );
|
||||
if (diff < 0.1) {++numNear;} else {++numFar;}
|
||||
}
|
||||
if ((numNear + numFar) > 150000) {
|
||||
Assert::isTrue(numNear < numFar*0.1,
|
||||
"many requests to the WiFiModel address nodes (very) near to a ground! \
|
||||
due to rounding issues, determining the number of floors between AP and point-in-question is NOT possible! \
|
||||
expect very wrong outputs! \
|
||||
consider adding the person's height to the questioned positions: p += Point3(0,0,1.3) "
|
||||
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")
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (const float z : ceilingsAtHeight_m) {
|
||||
if (zMin < z && zMax > z) {++cnt;}
|
||||
beacons.insert( std::make_pair(mac, ape) );
|
||||
}
|
||||
|
||||
return cnt;
|
||||
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(beacons.size()) + " APs");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//protected:
|
||||
|
||||
// FRIEND_TEST(LogDistanceCeilingModelBeacon, numCeilings);
|
||||
// FRIEND_TEST(LogDistanceCeilingModelBeacon, numCeilingsFloat);
|
||||
|
||||
|
||||
// /** get the number of ceilings between z1 and z2 */
|
||||
// float numCeilingsBetweenFloat(const Point3 pos1, const Point3 pos2) const {
|
||||
|
||||
|
||||
// const float zMin = std::min(pos1.z, pos2.z);
|
||||
// const float zMax = std::max(pos1.z, pos2.z);
|
||||
|
||||
// float cnt = 0;
|
||||
|
||||
// for (const float z : ceilingsAtHeight_m) {
|
||||
// if (zMin < z && zMax > z) {
|
||||
// const float dmax = zMax - z;
|
||||
// cnt += (dmax > 1) ? (1) : (dmax);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return cnt;
|
||||
|
||||
// }
|
||||
|
||||
// /** get the number of ceilings between z1 and z2 */
|
||||
// int numCeilingsBetween(const Point3 pos1, const Point3 pos2) const {
|
||||
|
||||
// int cnt = 0;
|
||||
// const float zMin = std::min(pos1.z, pos2.z);
|
||||
// const float zMax = std::max(pos1.z, pos2.z);
|
||||
|
||||
//#ifdef WITH_ASSERTIONS
|
||||
|
||||
// static int numNear = 0;
|
||||
// static int numFar = 0;
|
||||
// for (const float z : ceilingsAtHeight_m) {
|
||||
// const float diff = std::min( std::abs(z-zMin), std::abs(z-zMax) );
|
||||
// if (diff < 0.1) {++numNear;} else {++numFar;}
|
||||
// }
|
||||
// if ((numNear + numFar) > 150000) {
|
||||
// Assert::isTrue(numNear < numFar*0.1,
|
||||
// "many requests to the WiFiModel address nodes (very) near to a ground! \
|
||||
// due to rounding issues, determining the number of floors between AP and point-in-question is NOT possible! \
|
||||
// expect very wrong outputs! \
|
||||
// consider adding the person's height to the questioned positions: p += Point3(0,0,1.3) "
|
||||
// );
|
||||
// }
|
||||
//#endif
|
||||
|
||||
// for (const float z : ceilingsAtHeight_m) {
|
||||
// if (zMin < z && zMax > z) {++cnt;}
|
||||
// }
|
||||
|
||||
// return cnt;
|
||||
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* denotes a wifi fingerprint:
|
||||
* known position and 1-n measurements [wifi-scan on all channels] conducted at this position
|
||||
* denotes a beacon fingerprint:
|
||||
* known position and 1-n measurements [ble-advertisment-scan on all channels] conducted at this position
|
||||
*
|
||||
* if more than one measurement is conducted, each AP is contained more than once!
|
||||
*/
|
||||
struct WiFiFingerprint {
|
||||
struct BeaconFingerprint {
|
||||
|
||||
|
||||
/** real-world-position that was measured */
|
||||
@@ -22,13 +22,13 @@ struct WiFiFingerprint {
|
||||
BeaconMeasurements measurements;
|
||||
|
||||
/** ctor */
|
||||
WiFiFingerprint() {;}
|
||||
BeaconFingerprint() {;}
|
||||
|
||||
/** ctor */
|
||||
WiFiFingerprint(const Point3 pos_m) : pos_m(pos_m) {;}
|
||||
BeaconFingerprint(const Point3 pos_m) : pos_m(pos_m) {;}
|
||||
|
||||
/** ctor */
|
||||
WiFiFingerprint(const Point3 pos_m, const BeaconMeasurements& measurements) : pos_m(pos_m), measurements(measurements) {;}
|
||||
BeaconFingerprint(const Point3 pos_m, const BeaconMeasurements& 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 */
|
||||
|
||||
@@ -59,8 +59,8 @@ public:
|
||||
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]");
|
||||
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) );
|
||||
|
||||
@@ -119,8 +119,8 @@ public:
|
||||
// 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]");
|
||||
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?");
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#ifndef WIFIOPTIMIZER_H
|
||||
#define WIFIOPTIMIZER_H
|
||||
|
||||
#include "../../beacon/setup/BeaconFingerprint.h"
|
||||
#include "WiFiFingerprints.h"
|
||||
#include "WiFiOptimizerStructs.h"
|
||||
#include "../VAPGrouper.h"
|
||||
@@ -70,6 +71,20 @@ namespace WiFiOptimizer {
|
||||
|
||||
}
|
||||
|
||||
/** 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()) {
|
||||
|
||||
@@ -126,9 +126,9 @@ namespace WiFiOptimizer {
|
||||
/** we add some constraints to the parameter range */
|
||||
bool outOfRange() const {
|
||||
return (waf > 0) ||
|
||||
(txp < -50) ||
|
||||
(txp > -30) ||
|
||||
(exp > 4) ||
|
||||
(txp < -65) ||
|
||||
(txp > -45) ||
|
||||
(exp > 5) ||
|
||||
(exp < 1);
|
||||
}
|
||||
|
||||
@@ -185,12 +185,12 @@ namespace WiFiOptimizer {
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
LogDistCeiling(Floorplan::IndoorMap* map, const VAPGrouper& vg, const Mode mode = Mode::QUALITY) : Base(vg), map(map), mode(mode) {
|
||||
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) {
|
||||
LogDistCeiling(Floorplan::IndoorMap* map, const VAPGrouper& vg, const WiFiFingerprints& fps, const Mode mode = Mode::MEDIUM) : Base(vg), map(map), mode(mode) {
|
||||
addFingerprints(fps);
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ namespace WiFiOptimizer {
|
||||
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);
|
||||
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;
|
||||
@@ -269,8 +269,8 @@ namespace WiFiOptimizer {
|
||||
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(-65, -45), // txp
|
||||
LeOpt::MinMax(1, 5), // exp
|
||||
LeOpt::MinMax(-15, -0), // waf
|
||||
};
|
||||
|
||||
@@ -373,10 +373,10 @@ namespace WiFiOptimizer {
|
||||
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 > 5) {err += 999999;}
|
||||
if (params->exp < 1.0) {err += 999999;}
|
||||
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user