From 0d160f8b23512087bb3bbfc7b793feeb491ad506 Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Fri, 22 Jul 2011 11:29:30 +0200 Subject: [PATCH] [Positioning] Add option generate-reference-points The self-calibration is here! There is certainly some things to fix, but the big step is made. --- owlps-positioning/cfg/owlps-positioning.cfg | 4 + owlps-positioning/src/input.cc | 3 + owlps-positioning/src/stock.cc | 197 ++++++++++++++++++++ owlps-positioning/src/stock.hh | 3 + owlps-positioning/src/userinterface.cc | 4 + 5 files changed, 211 insertions(+) diff --git a/owlps-positioning/cfg/owlps-positioning.cfg b/owlps-positioning/cfg/owlps-positioning.cfg index 294a580..3bbfcfa 100644 --- a/owlps-positioning/cfg/owlps-positioning.cfg +++ b/owlps-positioning/cfg/owlps-positioning.cfg @@ -63,6 +63,10 @@ csv-file = /tmp/owlps-positioning.log # request is compared directly to each calibration request. #radar-average-reference-points = false +# Generate reference points from the (auto)calibration requests +# received. +#generate-reference-points = false + # This option allows the calibration requests sent during the # positioning phase to be added to the calibration request's list. They # are added to the calibration requests read by InputDataReader during diff --git a/owlps-positioning/src/input.cc b/owlps-positioning/src/input.cc index e736ab3..58ad95f 100644 --- a/owlps-positioning/src/input.cc +++ b/owlps-positioning/src/input.cc @@ -130,6 +130,9 @@ const Request& Input::get_next_request() const { calibration_request->reference_point_delete_requests() ; Stock::store_calibration_request(*calibration_request) ; + if (Configuration:: + bool_value("positioning.generate-reference-points")) + Stock::regenerate_reference_points() ; } } } diff --git a/owlps-positioning/src/stock.cc b/owlps-positioning/src/stock.cc index cd7b6f6..e14002a 100644 --- a/owlps-positioning/src/stock.cc +++ b/owlps-positioning/src/stock.cc @@ -360,6 +360,203 @@ closest_reference_point(const Request &request) } +/** + * Each reference point P we want to generate will end-up containing + * as many calibration requests as the total number of APs. + * For each of these requests, we consider a transmitter TRX (which is + * a virtual mobile) and a receiver RX (the current AP). + * To generate the signal strength (SS) received in P by RX from TRX, + * we first select two reference APs REF1 and REF2. Then, we average + * the real measurements REF1->RX and REF2->RX, weighting in function + * of the angles REF-RX-TRX and the distance from RX to TRX to compute + * the SS. + * Hope this is clear enough… + */ +void Stock::regenerate_reference_points() +{ + assert(! aps.empty()) ; + assert(! reference_points.empty()) ; + + /* Delete calibration requests that do not come from the APs */ + unordered_set::iterator rp = reference_points.begin() ; + while (rp != reference_points.end()) + { + ReferencePoint rp_copy(*rp) ; + if (rp_copy.delete_generated_requests()) // rp_copy was modified + { + rp = reference_points.erase(rp) ; + // Reinsert the modified copy if it still contains at least + // one CalibrationRequest: + if (! rp_copy.get_requests().empty()) + reference_points.insert(rp_copy) ; + /* __Note on the above insert__ + * From the boost::unordered documentation: + * "insert is only allowed to invalidate iterators when the + * insertion causes the load factor to be greater than or + * equal to the maximum load factor." + * In our case, we always remove an element prior to insert, + * so the load factor will never change; therefore insert() + * should be safe here. + */ + } + else // rp_copy was not modified + ++rp ; + } + + if (reference_points.size() < 3) + { + if (Configuration::is_configured("verbose")) + cerr + << reference_points.size() << " true reference points is" + << " not enough to generate reference points.\n" ; + return ; + } + + /* Generate RPs */ + if (! Configuration::is_configured("positioning.minmax-start") || + ! Configuration::is_configured("positioning.minmax-stop")) + throw missing_configuration( + "You must define the deployment area in order to generate" + " reference points.") ; + Point3D start( + Configuration::string_value("positioning.minmax-start")) ; + Point3D stop( + Configuration::string_value("positioning.minmax-stop")) ; + float step = 0.5 ; // FIXME + float z = 1 ; // FIXME + for (float x = start.get_x() ; x <= stop.get_x() ; x += step) + for (float y = start.get_y() ; y <= stop.get_y() ; y += step) + //for (float z = start.get_z() ; z <= stop.get_z() ; z += step) + { + Point3D current_point(x,y,z) ; + + for (unordered_map::const_iterator + rx = aps.begin() ; rx != aps.end() ; ++rx) + { + /* Choose the 2 nearest APs in angle */ + const Point3D &rx_coord = + rx->second.get_coordinates() ; + multimap::const_iterator> + sorted_angles ; + for (unordered_map::const_iterator + ref = aps.begin() ; ref != aps.end() ; ++ref) + { + if (ref == rx) + continue ; + const Point3D &ref_coord = + ref->second.get_coordinates() ; + double angle = + rx_coord.angle(current_point, ref_coord) ; + pair::const_iterator> + angle_ap(angle, ref) ; + sorted_angles.insert(angle_ap) ; + } + assert(sorted_angles.size() > 1) ; + + /* Compute the angle weight of the 2 reference APs */ + map::const_iterator> + ::const_iterator s = sorted_angles.begin() ; + // Angle REF1-RX-P + double ref1_angle = s->first ; + const AccessPoint &ref1 = s->second->second ; + ++s ; + const AccessPoint &ref2 = s->second->second ; + + // Angle REF1-RX-REF2 + const Point3D &ref1_coord = ref1.get_coordinates() ; + const Point3D &ref2_coord = ref2.get_coordinates() ; + double reference_angle = + rx_coord.angle(ref1_coord, ref2_coord) ; + double ref1_percent, ref2_percent ; + if (reference_angle == 0) + ref1_percent = ref2_percent = 50 ; + else + { + ref1_percent = ref1_angle * 100 / reference_angle ; + if (ref1_percent > 100) + ref1_percent = 100 ; + ref2_percent = 100 - ref1_percent ; + } + + /* Compute the SS that would be received from a mobile at + * distance of RX-P, in the direction of each reference AP */ + // Distance RX-P + float current_point_dst = + rx_coord.distance(current_point) ; + // Constants & common data + double wavelength = + static_cast(PosUtil::LIGHT_SPEED) / + rx->second.get_frequency() ; + double common_ss = + rx->second.get_antenna_gain() + + 20 * log10(wavelength) - + 20 * log10(4 * M_PI) ; + // SS for REF1 + const ReferencePoint &ref1_rp = + get_reference_point(ref1_coord) ; + double friis_index = + ref1_rp.friis_index_for_ap(rx->second.get_mac_addr()) ; + double ref1_ss = + common_ss + + ref1.get_trx_power() + + ref1.get_antenna_gain() - + 10 * friis_index * log10(current_point_dst) ; + // SS for REF2 + const ReferencePoint &ref2_rp = + get_reference_point(ref2_coord) ; + friis_index = + ref2_rp.friis_index_for_ap(rx->second.get_mac_addr()) ; + double ref2_ss = + common_ss + + ref2.get_trx_power() + + ref2.get_antenna_gain() - + 10 * friis_index * log10(current_point_dst) ; + + /* Compute the SS */ + ref1_ss = ref1_ss * ref1_percent / 100 ; + ref2_ss = ref2_ss * ref2_percent / 100 ; + double rx_ss = (ref1_ss + ref2_ss) / 2 ; + + /* Create the timestamp */ + Timestamp time_sent ; + time_sent.now() ; + + /* Create the virtual mobile */ + string vmob_mac(PosUtil::int_to_mac(nb_virtual_mobiles++)) ; + float vmob_gain = + ref1.get_antenna_gain() * ref1_percent / 100 + + ref2.get_antenna_gain() * ref2_percent / 100 ; + float vmob_pow = + ref1.get_trx_power() * ref1_percent / 100 + + ref2.get_trx_power() * ref2_percent / 100 ; + Mobile vmob("", vmob_mac, vmob_gain, vmob_pow) ; + const Mobile &mobile = find_create_mobile(vmob) ; + + /* Create the measurement list */ + Measurement m(&rx->second) ; + m.add_ss(rx_ss) ; + unordered_map measurements ; + measurements[rx->second.get_mac_addr()] = m ; + + /* Get/create the reference point */ + const ReferencePoint &rp = + find_create_reference_point(current_point) ; + + /* Create the calibration request */ + CalibrationRequest cr(OWL_REQUEST_GENERATED) ; + cr.set_time_sent(time_sent) ; + cr.set_mobile(&mobile) ; + cr.set_measurements(measurements) ; + cr.set_reference_point(&rp) ; + store_calibration_request(cr) ; + } + } +} + + /* *** CalibrationRequest operations *** */ diff --git a/owlps-positioning/src/stock.hh b/owlps-positioning/src/stock.hh index 3562083..dd8cb91 100644 --- a/owlps-positioning/src/stock.hh +++ b/owlps-positioning/src/stock.hh @@ -126,6 +126,9 @@ public: /// strength space) to a given Request static const ReferencePoint& closest_reference_point(const Request &request) ; + /// \brief Generates reference points from the reference points + /// corresponding to APs + static void regenerate_reference_points(void) ; //@} /** @name CalibrationRequest operations */ diff --git a/owlps-positioning/src/userinterface.cc b/owlps-positioning/src/userinterface.cc index 377d9cd..a0be735 100644 --- a/owlps-positioning/src/userinterface.cc +++ b/owlps-positioning/src/userinterface.cc @@ -193,6 +193,10 @@ void UserInterface::fill_positioning_options() " before to compute the SS distance." " The default is false, i.e the positioning request is compared" " directly to each calibration request.") + ("positioning.generate-reference-points", + po::value()->default_value(false), + "Generate reference points from the (auto)calibration requests" + " received.") ("positioning.accept-new-calibration-requests", po::value()->default_value(false), "Add the calibration requests received during the run-time to"