#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 *** */ map ReferencePoint:: get_all_measurements_sorted() const { map all ; for (vector::const_iterator i = requests.begin() ; i != requests.end() ; ++i) { unordered_map measurements = (*i)->get_measurements() ; for (unordered_map::const_iterator j = measurements.begin() ; j != measurements.end() ; ++j) if (! all.insert(*j).second) all[j->first].merge(j->second) ; } return all ; } /* *** Operations *** */ float ReferencePoint::ss_square_distance(const Request &source) const { assert(! requests.empty()) ; const unordered_map &request_measurements = source.get_measurements() ; map request_measurements_sorted( request_measurements.begin(), request_measurements.end()) ; map all_measurements_sorted = get_all_measurements_sorted() ; complete_with_dummy_measurements(all_measurements_sorted, request_measurements_sorted) ; return compute_ss_square_distance(all_measurements_sorted, request_measurements_sorted) ; } /** * APs that have not captured a Request must not have too much weight in * the computation. Thus, in the measurements lists we compare, we add * missing APs with a very low SS value. * Both lists can be completed, depending of the APs they contain. */ void ReferencePoint::complete_with_dummy_measurements( map &measurements1, map &measurements2) const { assert(! measurements1.empty()) ; assert(! measurements2.empty()) ; Measurement dummy ; dummy.add_ss(-98) ; // FIXME: should be the smallest possible value for (map::const_iterator i = measurements1.begin() ; i != measurements1.end() ; ++i) if (measurements2.find(i->first) == measurements2.end()) { dummy.set_ap(&Stock::get_ap(i->first)) ; measurements2[i->first] = dummy ; } for (map::const_iterator i = measurements2.begin() ; i != measurements2.end() ; ++i) if (measurements1.find(i->first) == measurements1.end()) { dummy.set_ap(&Stock::get_ap(i->first)) ; measurements1[i->first] = dummy ; } } /** * Both lists must have the same size: you should call * complete_with_dummy_measurements() before * compute_ss_square_distance(). */ float ReferencePoint::compute_ss_square_distance( map &measurements1, map &measurements2) const { assert(measurements1.size() == measurements2.size()) ; float distance = 0 ; for (map::const_iterator i1 = measurements1.begin() ; i1 != measurements1.end() ; ++i1) { map::const_iterator i2 = measurements2.find(i1->first) ; assert(i2 != measurements2.end()) ; distance += i1->second.ss_square_distance( i2->second) ; } return distance ; } /** * @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 ap_freq = ap.get_frequency() ; double const_term = ap.get_antenna_gain() - 20 * log10(4 * M_PI) + 20 * log10(PosUtil::LIGHT_SPEED / ap_freq) + ap.get_trx_power() ; 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 ; } /** * @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() ; /* * Compute an index for each 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::const_iterator request = requests.begin() ; request != requests.end() ; ++request) { const unordered_map &measurements = (*request)->get_measurements() ; unordered_map::const_iterator measurement = measurements.find(ap_mac) ; if (measurement != measurements.end()) { float distance = this->distance(ap.get_coordinates()) ; double ss = measurement->second.get_average_ss() ; float mobile_gain = (*request)->get_mobile()->get_antenna_gain() ; friis_idx_sum += (const_term + mobile_gain - ss) / (10 * log10(distance)) ; ++nb_indexes ; } } return friis_idx_sum ; } /* *** Operators *** */ const 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 << (Point3D) rp << '\n' ; // List of requests if (rp.requests.empty()) os << "No request." << '\n' ; else for (vector::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(source)) ; }