diff --git a/owlps-positioner/src/autocalibration.cc b/owlps-positioner/src/autocalibration.cc index 319aa46..1d4d5bc 100644 --- a/owlps-positioner/src/autocalibration.cc +++ b/owlps-positioner/src/autocalibration.cc @@ -54,7 +54,7 @@ void Autocalibration::generate_reference_point() vmob_gain = 0 ; vmob_pow = 0 ; - /* Generate a SS per AP */ + /* Generate the SS(s) for each AP */ for (unordered_map::const_iterator rx = Stock::aps.begin() ; rx != Stock::aps.end() ; ++rx) generate_ss() ; @@ -80,17 +80,19 @@ void Autocalibration::generate_ss() vmob_gain += rx->second.get_antenna_gain() / Stock::aps.size() ; vmob_pow += rx->second.get_trx_power() / Stock::aps.size() ; - /* Skip the AP if it is not at the good level (floor) */ + /* Skip the RX AP if it is not at the same floor as the point + * to generate */ const Point3D &rx_coord = rx->second.get_coordinates() ; if (rx_coord.get_z() != point.get_z()) return ; - /* Choose the 2 nearest APs in angle */ - choose_reference_aps() ; - if (sorted_angles.size() < 2) + /* Choose the nearest AP(s) in angle */ + sort_reference_aps() ; + // We need at least one reference AP: + if (sorted_negative_angles.empty() && sorted_positive_angles.empty()) throw autocalibration_error("Not enough APs in coverage!") ; - /* Compute the angle weight of the 2 reference APs */ + /* Compute the angle weight of the reference APs */ weight_aps() ; /* Compute the SS that would be received from a mobile at a @@ -99,7 +101,11 @@ void Autocalibration::generate_ss() } -void Autocalibration::choose_reference_aps() +/** + * The reference (transmitter) APs are first filtered (floor, coverage), + * then sorted according to their angles with RX and P. + */ +void Autocalibration::sort_reference_aps() { const Point3D &rx_coord = rx->second.get_coordinates() ; @@ -109,7 +115,7 @@ void Autocalibration::choose_reference_aps() if (ref == rx) continue ; - // Skip the AP if it is not at the same level (floor) than the + // Skip the AP if it is not at the same floor than the // receiver AP: const Point3D &ref_coord = ref->second.get_coordinates() ; if (ref_coord.get_z() != rx_coord.get_z()) @@ -121,7 +127,10 @@ void Autocalibration::choose_reference_aps() if (coverage < 1) // Less than 1% coverage is ridiculous! continue ; - double angle = rx_coord.angle_2d(point, ref_coord) ; + Point3D ref_coord_r(ref_coord) ; + ref_coord_r.rotate_2d(rx_coord, angle_p) ; + + double angle = rx_coord.angle_2d(point, ref_coord_r) ; double weight = angle / coverage ; pair::const_iterator> @@ -129,35 +138,68 @@ void Autocalibration::choose_reference_aps() pair::const_iterator> > weight_angle_ap(weight, angle_ap) ; - sorted_angles.insert(weight_angle_ap) ; + if (ref_coord_r.get_y() < rx_coord.get_y()) + sorted_negative_angles.insert(weight_angle_ap) ; + else + sorted_positive_angles.insert(weight_angle_ap) ; } } void Autocalibration::weight_aps() { + /* Retrieve the reference APs & angles */ map::const_iterator> > - ::const_iterator s = sorted_angles.begin() ; - // Angle REF1-RX-P - double ref1_angle = s->second.first ; - ref1 = &s->second.second->second ; - ++s ; - ref2 = &s->second.second->second ; + ::const_iterator s ; + s = sorted_negative_angles.begin() ; + if (s != sorted_negative_angles.end()) + init_ap(s) ; + s = sorted_positive_angles.begin() ; + if (s != sorted_positive_angles.end()) + init_ap(s) ; - // Angle REF1-RX-REF2 + /* Weight the APs */ + if (ref_aps.size() == 1) + ref_aps[0].weight = 100 ; + else if (ref_aps.size() == 2) + weight_2_aps() ; + else + throw autocalibration_error( + "We should not be here... error when sorting the reference APs?") ; +} + + +void Autocalibration::init_ap( + map::const_iterator> >::const_iterator s) +{ + struct ap ref ; + ref.ap = &s->second.second->second ; + ref.angle = s->second.first ; // Angle REF-RX-P + ref_aps.push_back(ref) ; +} + + +void Autocalibration::weight_2_aps() +{ + assert(ref_aps.size() > 1) ; + + /* Compute the angle REF1-RX-REF2 */ const Point3D &rx_coord = rx->second.get_coordinates() ; - const Point3D &ref1_coord = ref1->get_coordinates() ; - const Point3D &ref2_coord = ref2->get_coordinates() ; + const Point3D &ref1_coord = ref_aps[0].ap->get_coordinates() ; + const Point3D &ref2_coord = ref_aps[1].ap->get_coordinates() ; double reference_angle = rx_coord.angle_2d(ref1_coord, ref2_coord) ; + + /* Weight the two APs */ if (reference_angle == 0) - ref1_percent = ref2_percent = 50 ; + ref_aps[0].weight = ref_aps[1].weight = 50 ; else { - ref1_percent = ref1_angle * 100 / reference_angle ; - if (ref1_percent > 100) - ref1_percent = 100 ; - ref2_percent = 100 - ref1_percent ; + ref_aps[0].weight = ref_aps[0].angle * 100 / reference_angle ; + if (ref_aps[0].weight > 100) + ref_aps[0].weight = 100 ; + ref_aps[1].weight = 100 - ref_aps[0].weight ; } } @@ -166,114 +208,108 @@ void Autocalibration::compute_ss() { if (Configuration:: bool_value("positioning.generate-single-packet-reference-points")) - compute_single_packet_ss() ; + compute_single_packet_ss(0) ; else compute_multi_packet_ss() ; } -void Autocalibration::compute_single_packet_ss() -{ - const ReferencePoint - &ref1_rp = Stock::get_reference_point(ref1->get_coordinates()), - &ref2_rp = Stock::get_reference_point(ref2->get_coordinates()) ; - const string &rx_mac = rx->second.get_mac_addr() ; - - /* Friis indexes for REF1 & REF2 */ - float ref1_friis_idx = ref1_rp.friis_index_for_ap(rx_mac) ; - float ref2_friis_idx = ref2_rp.friis_index_for_ap(rx_mac) ; - - /* SS for REF1 & REF2 */ - // Constant term - double common_ss = rx->second.friis_constant_term() ; - // Distance RX-P - const Point3D &rx_coord = rx->second.get_coordinates() ; - float point_dst = rx_coord.distance(point) ; - double ref1_ss = - common_ss + - ref1->get_trx_power() + - ref1->get_antenna_gain() - - 10 * ref1_friis_idx * log10(point_dst) ; - double ref2_ss = - common_ss + - ref2->get_trx_power() + - ref2->get_antenna_gain() - - 10 * ref2_friis_idx * log10(point_dst) ; - - /* Compute the consolidated SS */ - ref1_ss = ref1_ss * ref1_percent / 100 ; - ref2_ss = ref2_ss * ref2_percent / 100 ; - double rx_ss = ref1_ss + ref2_ss ; - - /* Create the measurement, add it to the list */ - Measurement m(&rx->second) ; - m.add_ss(1, rx_ss) ; - measurements[rx_mac] = m ; -} - - void Autocalibration::compute_multi_packet_ss() { - const ReferencePoint - &ref1_rp = Stock::get_reference_point(ref1->get_coordinates()), - &ref2_rp = Stock::get_reference_point(ref2->get_coordinates()) ; - + const ap &ref1 = ref_aps[0] ; + const ReferencePoint &ref1_rp = + Stock::get_reference_point(ref1.ap->get_coordinates()) ; const vector &ref1_cr = ref1_rp.get_requests() ; + + /* Search for the first measurement made by RX in ref1_rp */ const Measurement *rx_measurement = NULL ; vector::const_iterator cr ; - const string &rx_mac = rx->second.get_mac_addr() ; - - // Search for the first measurement made by RX in ref1_rp - for (cr = ref1_cr.begin() ; - ! rx_measurement && cr != ref1_cr.end() ; ++cr) + for (cr = ref1_cr.begin() ; ! rx_measurement && cr != ref1_cr.end() ; + ++cr) rx_measurement = (*cr)->get_measurement(rx_mac) ; // The selected reference APs are in coverage of RX, therefore // we should always find a measurement of RX in ref1_rp assert(rx_measurement) ; - for (pkt_id_t pkt_id = 1 ; pkt_id < (*cr)->get_nb_packets() ; + /* Generate the SS for each packet */ + for (pkt_id_t pkt_id = 1 ; pkt_id <= (*cr)->get_nb_packets() ; ++pkt_id) - { - /* Friis indexes for REF1 & REF2 */ - float ref1_friis_idx = - ref1_rp.friis_index_for_ap(rx->second.get_mac_addr(), - pkt_id) ; - if (ref1_friis_idx == 0) - continue ; // The packet pkt_id does not exist in ref1_rp - float ref2_friis_idx = - ref2_rp.friis_index_for_ap(rx->second.get_mac_addr(), - pkt_id) ; - if (ref2_friis_idx == 0) - continue ; // The packet pkt_id does not exist in ref2_rp - - /* SS for REF1 & REF2 */ - // Constant term - double common_ss = rx->second.friis_constant_term() ; - // Distance RX-P - const Point3D &rx_coord = rx->second.get_coordinates() ; - float point_dst = rx_coord.distance(point) ; - double ref1_ss = - common_ss + - ref1->get_trx_power() + - ref1->get_antenna_gain() - - 10 * ref1_friis_idx * log10(point_dst) ; - double ref2_ss = - common_ss + - ref2->get_trx_power() + - ref2->get_antenna_gain() - - 10 * ref2_friis_idx * log10(point_dst) ; - - /* Compute the consolidated SS */ - ref1_ss = ref1_ss * ref1_percent / 100 ; - ref2_ss = ref2_ss * ref2_percent / 100 ; - double rx_ss = ref1_ss + ref2_ss ; - - /* Create the measurement, add it to the list */ - Measurement m(&rx->second) ; - m.add_ss(pkt_id, rx_ss) ; - measurements[rx_mac] = m ; - } + compute_single_packet_ss(pkt_id) ; +} + + +/** + * @arg pkt_id The number of the packet to create. Must be 0 if all + * the generated reference points contain only one packet. + */ +void Autocalibration::compute_single_packet_ss(pkt_id_t pkt_id) +{ + /* Distance RX-P */ + const Point3D &rx_coord = rx->second.get_coordinates() ; + float point_dst = rx_coord.distance(point) ; + + /* Compute the consolidated SS */ + double rx_ss = 0 ; + for (unsigned int i = 0 ; i < ref_aps.size() ; ++i) + { + double tmp_ss = compute_weighted_ss(i, pkt_id, point_dst) ; + if (tmp_ss > 0) // error + return ; + rx_ss += tmp_ss ; + } + + /* Add the SS to the measurements' list */ + const string &rx_mac = rx->second.get_mac_addr() ; + // 0 is not a valid packet ID, so we use 1 if we generate only one + // packet per reference point: + if (pkt_id == 0) + pkt_id = 1 ; + // The Measurement measurements[rx_mac] is created if needed: + measurements[rx_mac].add_ss(pkt_id, rx_ss) ; + // Useful only if the measurement was just created, but it is not + // worth a test: + measurements[rx_mac].set_ap(&rx->second) ; +} + + +/** + * @arg ap_idx The index of the AP in #ref_aps. + * @arg pkt_id The number of the packet to generate, or 0 if we generate + * only one packet per reference point. + * @arg point_dst The distance RX-P. + * + * @returns The weighted SS value in dBm, or 1 in case of error. + */ +double Autocalibration::compute_weighted_ss( + unsigned int ap_idx, pkt_id_t pkt_id, float point_dst) +{ + const ap &ref = ref_aps[ap_idx] ; + const ReferencePoint &rp = + Stock::get_reference_point(ref.ap->get_coordinates()) ; + + /* Friis index */ + const string &rx_mac = rx->second.get_mac_addr() ; + float friis_idx ; + if (pkt_id == 0) + friis_idx = rp.friis_index_for_ap(rx_mac) ; + else + { + friis_idx = rp.friis_index_for_ap(rx_mac, pkt_id) ; + if (friis_idx == 0) + return 1 ; // The packet pkt_id does not exist in rp + } + + /* SS */ + // Constant term + double common_ss = rx->second.friis_constant_term() ; + double ss = + common_ss + + ref.ap->get_trx_power() + + ref.ap->get_antenna_gain() - + 10 * friis_idx * log10(point_dst) ; + + return ss * ref.weight / 100 ; } diff --git a/owlps-positioner/src/autocalibration.hh b/owlps-positioner/src/autocalibration.hh index 08c2f97..7b9347d 100644 --- a/owlps-positioner/src/autocalibration.hh +++ b/owlps-positioner/src/autocalibration.hh @@ -10,7 +10,8 @@ class AccessPoint ; class Point3D ; -class Measurement ; + +#include "measurement.hh" #include @@ -21,18 +22,35 @@ class Measurement ; class Autocalibration { private: + struct ap + { + const AccessPoint *ap ; + float weight ; // Weight of the AP in percents + float angle ; + } ; + /// Current AP to generate a SS for std::tr1::unordered_map::const_iterator rx ; + /// Angle P-RX-O, O being the origin of the trigonometric circle + float angle_p ; /// Selected transmitter APs - const AccessPoint *ref1, *ref2 ; - /// Weights of the selected transmitter APs - double ref1_percent, ref2_percent ; - /// Angles of the transmitter APs + std::vector ref_aps ; + /// \brief Angles of the transmitter APs (before M on the trigonometric + /// circle) + /** + * Note that the angles are stored in absolute value. + */ std::multimap::const_iterator> > - sorted_angles ; + sorted_negative_angles ; + /// Angles of the transmitter APs (after M on the trigonometric circle) + std::multimap::const_iterator> > + sorted_positive_angles ; /// Characteristics of the virtual mobile double vmob_gain, vmob_pow ; /// Generated measurements' list @@ -45,24 +63,32 @@ protected: /// The coordinates of the reference point to generate const Point3D &point ; + /// Generates the SSs for all the APs + void generate_ss(void) ; + /// Sorts the reference APs for a receiver AP + void sort_reference_aps(void) ; + /// Computes the weight of the selected AP(s) + void weight_aps(void) ; + void init_ap( + std::map::const_iterator> >::const_iterator s) ; + /// Weights two APs according to their angles + void weight_2_aps(void) ; + /// Computes the SS of the virtual mobile + void compute_ss(void) ; + /// Computes a SS with only one packet in it + void compute_single_packet_ss(pkt_id_t pkt_id) ; + /// Computes a SS according to the weight of the AP + double compute_weighted_ss( + unsigned int ap_idx, pkt_id_t pkt_id, float point_dst) ; + /// Computes a SS with several packets in it + void compute_multi_packet_ss(void) ; + public: Autocalibration(const Point3D &_point): point(_point) {} /// Generates a single reference point void generate_reference_point(void) ; - /// Generates the SSs for all the APs - void generate_ss(void) ; - /// Chooses the reference APs for a receiver AP - void choose_reference_aps(void) ; - /// Weihgts the selected APs according to their angles - void weight_aps(void) ; - /// Computes the SS of the virtual mobile - void compute_ss(void) ; - /// Computes a SS with only one packet in it - void compute_single_packet_ss(void) ; - /// Computes a SS with several packets in it - void compute_multi_packet_ss(void) ; - } ; #endif // _OWLPS_POSITIONING_AUTOCALIBRATION_HH_