owlps/owlps-positioning/src/referencepoint.cc

333 lines
8.4 KiB
C++

/*
* This file is part of the Owl Positioning System (OwlPS).
* OwlPS is a project of the University of Franche-Comté
* (Université de Franche-Comté), France.
*/
#include "referencepoint.hh"
#include "measurement.hh"
#include "calibrationrequest.hh"
#include "stock.hh"
using namespace std ;
using std::tr1::unordered_map ;
/* *** Constructors *** */
/**
* Clears #requests, but does not deallocate the values pointed by
* the elements into it.
*/
ReferencePoint::~ReferencePoint()
{
requests.clear() ;
}
/* *** Accessors *** */
double ReferencePoint::
average_measurements(const std::string &mac_transmitter) const
{
unordered_map<string, Measurement> measurements(
get_all_measurements(mac_transmitter)) ;
double avg = 0 ;
int n_ss = 0 ;
for (unordered_map<string, Measurement>::const_iterator i =
measurements.begin() ;
i != measurements.end() ; ++i)
{
avg += i->second.get_average_ss() ;
++n_ss ;
}
return (avg / n_ss) ;
}
unordered_map<string, Measurement> ReferencePoint::
get_all_measurements() const
{
unordered_map<string, Measurement> all ;
for (vector<CalibrationRequest*>::const_iterator i = requests.begin() ;
i != requests.end() ; ++i)
{
unordered_map<string, Measurement> measurements =
(*i)->get_measurements() ;
for (unordered_map<string, Measurement>::const_iterator j =
measurements.begin() ; j != measurements.end() ; ++j)
if (! all.insert(*j).second)
all[j->first].merge(j->second) ;
}
return all ;
}
unordered_map<string, Measurement> ReferencePoint::
get_all_measurements(const string &mac_transmitter) const
{
unordered_map<string, Measurement> all ;
vector<CalibrationRequest*> requests_trx(
get_requests(mac_transmitter)) ;
for (vector<CalibrationRequest*>::const_iterator i =
requests_trx.begin() ;
i != requests_trx.end() ; ++i)
{
unordered_map<string, Measurement> measurements =
(*i)->get_measurements() ;
for (unordered_map<string, Measurement>::const_iterator j =
measurements.begin() ; j != measurements.end() ; ++j)
if (! all.insert(*j).second)
all[j->first].merge(j->second) ;
}
return all ;
}
/**
* @param mac_transmitter The MAC address of the transmitting mobile.
* @return A vector containing all the requests sent by the mobile.
* The returned vector is empty if no request was sent by the mobile.
*/
const vector<CalibrationRequest*> ReferencePoint::
get_requests(const string &mac_transmitter) const
{
vector<CalibrationRequest*> res ;
for (vector<CalibrationRequest*>::const_iterator i = requests.begin() ;
i != requests.end() ; ++i)
if ((*i)->get_mobile()->get_mac_addr() == mac_transmitter)
res.push_back(*i) ;
return res ;
}
/**
* Note that the requests pointed by the elements of #requests are
* actually deleted from the Stock.
*/
void ReferencePoint::delete_requests()
{
#ifndef NDEBUG
int stock_nb_requests = Stock::nb_calibration_requests() ;
#endif // NDEBUG
for (vector<CalibrationRequest*>::iterator r = requests.begin() ;
r != requests.end() ; ++r)
Stock::delete_calibration_request(**r) ;
assert(Stock::nb_calibration_requests() ==
stock_nb_requests - requests.size()) ;
requests.clear() ;
}
/**
* Note that the requests pointed by the elements of #requests are
* actually deleted from the Stock.
* @returns \em true if at least one request was deleted.
* @returns \em false if the ReferencePoint was left untouched.
*/
bool ReferencePoint::delete_generated_requests(void)
{
unsigned int nb_requests = requests.size() ;
vector<CalibrationRequest*>::iterator r = requests.begin() ;
while (r != requests.end())
{
assert(*r) ;
unordered_map<std::string, AccessPoint>::const_iterator ap ;
if ((*r)->get_mobile() == NULL)
goto delete_request ;
for (ap = Stock::get_aps().begin() ; ap != Stock::get_aps().end() ;
++ap)
if ((*r)->get_mobile()->get_mac_addr() ==
ap->second.get_mac_addr())
break ;
if (ap != Stock::get_aps().end()) // r still associated with an AP
{
++r ;
continue ; // Do not delete r
}
// r is not assotiated with an AP, delete it
delete_request:
Stock::delete_calibration_request(**r) ;
r = requests.erase(r) ;
}
return nb_requests != requests.size() ;
}
/* *** Operations *** */
/**
* Before to compute the distance, all the measurements containted in
* #requests are put together, as if it was one big request.
*
* Note: to compute the distance between two requests, one should use
* Request::ss_square_distance().
*/
float ReferencePoint::ss_square_distance(const Request &source) const
{
assert(! requests.empty()) ;
unordered_map<string, Measurement>
source_measurements(source.get_measurements()),
all_measurements(get_all_measurements()) ;
PosUtil::complete_with_dummy_measurements(
all_measurements, source_measurements) ;
return PosUtil::ss_square_distance(
all_measurements, source_measurements) ;
}
/**
* @param ap_mac The MAC address of the AccessPoint to work on.
* @returns The Friis index associated to the AccessPoint.
* @returns 0 if the AP is unknown at this ReferencePoint.
*/
float ReferencePoint::
friis_index_for_ap(const string &ap_mac) const
{
const AccessPoint &ap = Stock::get_ap(ap_mac) ;
double const_term = ap.friis_constant_term() ;
int nb_friis_idx = 0 ;
double friis_idx_sum =
friis_indexes_for_ap(ap, const_term, nb_friis_idx) ;
if (nb_friis_idx == 0)
return 0 ;
return friis_idx_sum / nb_friis_idx ;
}
/**
* Computes a Friis index for the distance AP-ReferencePoint, based on
* the measurements of this AP that are present in the ReferencePoint.
* @param ap The AccessPoint to work on.
* @param const_term The "constant" part of the computation.
* @param nb_indexes (result) The number of indexes computed.
* @return The sum of all Friis indexes for the AccessPoint.
* @returns 0 if the AP is unknown at this ReferencePoint.
*/
float ReferencePoint::friis_indexes_for_ap(
const AccessPoint &ap,
const double &const_term,
int &nb_indexes) const
{
nb_indexes = 0 ;
double friis_idx_sum = 0 ;
const string &ap_mac = ap.get_mac_addr() ;
float distance = this->distance(ap.get_coordinates()) ;
/*
* Compute an index for the AP's Measurement in each Request in the
* ReferencePoint. The Friis index for the AP is the average of all
* these indexes (we do not compute the average in this function).
*/
for (vector<CalibrationRequest*>::const_iterator request =
requests.begin() ; request != requests.end() ; ++request)
{
const unordered_map<string, Measurement> &measurements =
(*request)->get_measurements() ;
unordered_map<string, Measurement>::const_iterator measurement =
measurements.find(ap_mac) ;
if (measurement != measurements.end())
{
double ss = measurement->second.get_average_ss() ;
assert((*request)->get_mobile()) ;
float mobile_gain =
(*request)->get_mobile()->get_antenna_gain() ;
float mobile_pow =
(*request)->get_mobile()->get_trx_power() ;
friis_idx_sum +=
(const_term + mobile_gain + mobile_pow - ss)
/ (10 * log10(distance)) ;
++nb_indexes ;
}
}
return friis_idx_sum ;
}
/* *** Operators *** */
ReferencePoint& ReferencePoint::operator=(const ReferencePoint &source)
{
if (this == &source)
return *this ;
this->Point3D::operator=(source) ;
requests = source.requests ;
return *this ;
}
bool ReferencePoint::operator==(const ReferencePoint &source) const
{
if (this == &source)
return true ;
return
this->Point3D::operator==(source) &&
requests == source.requests ;
}
ostream &operator<<(ostream &os, const ReferencePoint &rp)
{
// Coordinates
os << static_cast<Point3D>(rp) ;
// List of requests
if (rp.requests.empty())
os << "\nNo request." << '\n' ;
else
for (vector<CalibrationRequest*>::const_iterator
i = rp.requests.begin() ;
i != rp.requests.end() ; ++i)
os << '\n' << **i ;
return os ;
}
/**
* This is a simple call to hash_value(Point3D), because we do not want
* to take care of the CalibrationRequest list to hash the
* ReferencePoint.
*/
size_t hash_value(const ReferencePoint &source)
{
return hash_value(static_cast<Point3D>(source)) ;
}