/* * This file is part of the Owl Positioning System (OwlPS). * OwlPS is a project of the University of Franche-Comte * (Université de Franche-Comté), France. * * Copyright © Université de Franche-Comté 2007-2012. * * Corresponding author: Matteo Cypriani * *********************************************************************** * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL: * http://www.cecill.info * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided * only with a limited warranty and the software's authors, the holder * of the economic rights, and the successive licensors have only * limited liability. * * In this respect, the user's attention is drawn to the risks * associated with loading, using, modifying and/or developing or * reproducing the software by the user in light of its specific status * of free software, that may mean that it is complicated to manipulate, * and that also therefore means that it is reserved for developers and * experienced professionals having in-depth computer knowledge. Users * are therefore encouraged to load and test the software's suitability * as regards their requirements in conditions enabling the security of * their systems and/or data to be ensured and, more generally, to use * and operate it in the same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. * *********************************************************************** */ #include "referencepoint.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() ; } /* *** Read accessors *** */ double ReferencePoint:: average_measurements(const std::string &mac_transmitter) const { unordered_map measurements( get_all_measurements(mac_transmitter)) ; double avg = 0 ; int n_ss = 0 ; for (unordered_map::const_iterator i = measurements.begin() ; i != measurements.end() ; ++i) { avg += i->second.get_average_dbm() ; ++n_ss ; } return (avg / n_ss) ; } unordered_map ReferencePoint:: get_all_measurements() const { unordered_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 ; } unordered_map ReferencePoint:: get_all_measurements(const string &mac_transmitter) const { unordered_map all ; vector requests_trx( get_requests(mac_transmitter)) ; for (vector::const_iterator i = requests_trx.begin() ; i != requests_trx.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 ; } /** * @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 ReferencePoint:: get_requests(const string &mac_transmitter) const { vector res ; for (vector::const_iterator i = requests.begin() ; i != requests.end() ; ++i) if ((*i)->get_mobile()->get_mac_addr() == mac_transmitter) res.push_back(*i) ; return res ; } /* *** Write accessors *** */ void ReferencePoint::delete_request(const CalibrationRequest *r) { for (vector::iterator i = requests.begin() ; i != requests.end() ; ++i) if (*i == r) { requests.erase(i) ; return ; } } /** * 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::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::iterator r = requests.begin() ; while (r != requests.end()) { assert(*r) ; unordered_map::const_iterator ap ; if ((*r)->get_mobile() == NULL) goto delete_request ; // Check if the request was sent by an AP 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 was sent by an AP { ++r ; continue ; // Do not delete r } // r is not associated 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 similarity, all the measurements containted in * #requests are put together, as if it was one big request. * * Note: to compute the similarity between two requests, one should use * Request::similarity(). */ float ReferencePoint::similarity(const Request &source) const { assert(! requests.empty()) ; unordered_map source_measurements(source.get_measurements()) ; unordered_map all_measurements(get_all_measurements()) ; PosUtil::complete_with_dummy_measurements( all_measurements, source_measurements) ; return PosUtil::similarity( 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 sum for the distance AP-ReferencePoint, * based on the measurements of this AP that are present in the * ReferencePoint. To obtain the real (averaged) Friis index, one * has to divide the returned sum by the number of indexes. * * @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. * * @returns 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::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 ss = measurement->second.get_average_dbm() ; 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 ; } /** * Computes a Friis index for the distance AP-ReferencePoint, based on a * given packet (\em pkt_id), of a measurement of this AP present in the * ReferencePoint. This measurement is the first found in the * ReferencePoint. This works well when we keep only one calibration * request per reference point. * * @param ap_mac The MAC address of the AccessPoint to work on. * @param pkt_id The packet ID to look for. * * @returns The Friis index for this AP and packet. * @returns 0 if the AP is unknown at this ReferencePoint, or if there * is no packet with the wanted ID. */ float ReferencePoint:: friis_index_for_ap(const string &ap_mac, pkt_id_t pkt_id) const { const AccessPoint &ap = Stock::get_ap(ap_mac) ; double const_term = ap.friis_constant_term() ; float distance = this->distance(ap.get_coordinates()) ; float friis_idx = 0 ; 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()) continue ; ss_t ss = measurement->second.get_ss(pkt_id) ; if (ss == 0) continue ; assert((*request)->get_mobile()) ; float mobile_gain = (*request)->get_mobile()->get_antenna_gain() ; float mobile_pow = (*request)->get_mobile()->get_trx_power() ; friis_idx = (const_term + mobile_gain + mobile_pow - ss) / (10 * log10(distance)) ; break ; } return friis_idx ; } /* *** 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(rp) ; // List of requests if (rp.requests.empty()) os << "\nNo 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)) ; }