[Positioner] Autocalibration: signed angles

This commit changes the way the APs are selected. Until now, the two
most acute angles were selected. Now, the angles are signed, i.e. we
differentiate the APs that are before the point to generate on the
trigonometric circle, and those that are after.

Some more refactoring was achieved, and some bugs fixed.
This commit is contained in:
Matteo Cypriani 2012-05-01 16:23:27 +02:00
parent 291ef457f5
commit 300c338023
2 changed files with 196 additions and 134 deletions

View File

@ -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<string, AccessPoint>::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<double,
unordered_map<string, AccessPoint>::const_iterator>
@ -129,35 +138,68 @@ void Autocalibration::choose_reference_aps()
pair<double, pair<double,
unordered_map<string, AccessPoint>::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<double, pair<double,
unordered_map<string, AccessPoint>::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<double, pair<double, unordered_map<
string, AccessPoint>::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<CalibrationRequest*> &ref1_cr =
ref1_rp.get_requests() ;
/* Search for the first measurement made by RX in ref1_rp */
const Measurement *rx_measurement = NULL ;
vector<CalibrationRequest*>::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 ;
}

View File

@ -10,7 +10,8 @@
class AccessPoint ;
class Point3D ;
class Measurement ;
#include "measurement.hh"
#include <boost/tr1/unordered_map.hpp>
@ -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<std::string, AccessPoint>::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<ap> 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<double,
std::pair<double,
std::tr1::unordered_map<
std::string, AccessPoint>::const_iterator> >
sorted_angles ;
sorted_negative_angles ;
/// Angles of the transmitter APs (after M on the trigonometric circle)
std::multimap<double,
std::pair<double,
std::tr1::unordered_map<
std::string, AccessPoint>::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<double, std::pair<double, std::tr1::unordered_map<
std::string, AccessPoint>::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_