[Positioner] Add AutocalibrationMesh (refactored)

Refactor pieces of Autocalibration into the new class
AutocalibrationMesh, in order to allow the addition of new
autocalibration sub-classes.
This commit is contained in:
Matteo Cypriani 2013-07-08 13:19:04 -04:00
parent b436526d40
commit 2ac9cc2c1d
7 changed files with 420 additions and 324 deletions

View File

@ -44,6 +44,7 @@ set(OWLPS_POSITIONER_CLASSES_SRC_FILES
capturepointsreadercsv.cc
area.cc
autocalibration.cc
autocalibrationmesh.cc
building.cc
calibrationrequest.cc
cartographyalgorithm.cc

View File

@ -14,15 +14,12 @@
#include "autocalibration.hh"
#include "capturepoint.hh"
#include "stock.hh"
#include "configuration.hh"
#include "posexcept.hh"
#include <map>
#include <string>
#include <iostream>
#include <sstream>
using namespace std ;
@ -36,8 +33,9 @@ uint32_t Autocalibration::nb_virtual_mobiles = 0 ;
/* *** Operations *** */
/**
* The reference point P we want to generate will end-up containing
* The reference point P we want to generate will end up containing
* as many calibration requests as the total number of CPs.
* For each of these requests, we consider a transmitter TRX (which is
* a virtual mobile located in P) and a receiver RX (the current CP).
@ -68,7 +66,10 @@ void Autocalibration::generate_reference_point()
/* Generate the SS(s) for each CP */
for (rx = Stock::cps.begin() ; rx != Stock::cps.end() ; ++rx)
generate_ss() ;
{
if (init_ss_generation())
generate_ss() ;
}
assert(! measurements.empty()) ;
/* Create the virtual mobile */
@ -86,7 +87,11 @@ void Autocalibration::generate_reference_point()
}
void Autocalibration::generate_ss()
/**
* @returns `true` if the SS can be generated.
* @returns `false` in case of error.
*/
bool Autocalibration::init_ss_generation()
{
/* Update the mobile's attributes */
vmob_gain += rx->second.get_antenna_gain() / Stock::cps.size() ;
@ -96,153 +101,16 @@ void Autocalibration::generate_ss()
* to generate */
const Point3D &rx_coord = rx->second.get_coordinates() ;
if (rx_coord.get_z() != point.get_z())
return ;
return false ;
/* Compute the origin angle P-RX-O */
Point3D origin(rx_coord) ;
origin.set_x(rx_coord.get_x() + 10) ;
origin_angle = rx_coord.angle_2d(point, origin) ;
if (point.get_y() > rx_coord.get_y())
origin_angle = -origin_angle ;
/* Choose the nearest CP(s) in angle */
sort_reference_cps() ;
// We need at least one reference CP:
if (sorted_negative_angles.empty() && sorted_positive_angles.empty())
throw autocalibration_error("Not enough CPs in coverage!") ;
/* Compute the angle weight of the reference CPs */
weight_cps() ;
/* Compute the SS that would be received from a mobile at a
* distance of RX-P, in the direction of each reference CP */
compute_ss() ;
return true ;
}
/**
* The reference (transmitter) CPs are first filtered (floor, coverage),
* then sorted according to their angles with RX and P.
* This function is a simple wrapper around compute_single_packet_ss()
* and compute_multi_packet_ss(), depending on the configuration.
*/
void Autocalibration::sort_reference_cps()
{
const Point3D &rx_coord = rx->second.get_coordinates() ;
sorted_negative_angles.clear() ;
sorted_positive_angles.clear() ;
for (unordered_map<string, CapturePoint>::const_iterator
ref = Stock::cps.begin() ; ref != Stock::cps.end() ; ++ref)
{
if (ref == rx)
continue ;
/* Skip the CP if it is not at the same floor than the
* receiver CP */
const Point3D &ref_coord = ref->second.get_coordinates() ;
if (ref_coord.get_z() != rx_coord.get_z())
continue ;
/* Skip the CP if it is not in coverage with the receiver CP */
float coverage =
rx->second.received_calibration_from_cp(ref->second) ;
if (coverage < 1) // Less than 1% coverage is ridiculous!
continue ;
/* Angle P-RX-REF */
double angle = rx_coord.angle_2d(point, ref_coord) ;
/* Weight in the CPs' list according to coverage and angle */
double weight = angle / coverage ;
/* Note: this weight is used only to sort the CPs, it has nothing
to do with the angle weight (see weight_cps()) used to compute
the SSs. */
/* Create the list entry */
pair<double,
unordered_map<string, CapturePoint>::const_iterator>
angle_cp(angle, ref) ;
pair<double, pair<double,
unordered_map<string, CapturePoint>::const_iterator> >
weight_angle_cp(weight, angle_cp) ;
/* Rotate the CP's coordinates to know the angle direction */
Point3D ref_coord_r(ref_coord) ;
ref_coord_r.rotate_2d(rx_coord, origin_angle) ;
// Insert the CP in the right list, according to the direction:
if (ref_coord_r.get_y() < rx_coord.get_y())
sorted_negative_angles.insert(weight_angle_cp) ;
else
sorted_positive_angles.insert(weight_angle_cp) ;
}
}
void Autocalibration::weight_cps()
{
/* Retrieve the reference CPs & angles */
ref_cps.clear() ;
map<double, pair<double,
unordered_map<string, CapturePoint>::const_iterator> >
::const_iterator s ;
s = sorted_negative_angles.begin() ;
if (s != sorted_negative_angles.end())
init_cp(s) ;
s = sorted_positive_angles.begin() ;
if (s != sorted_positive_angles.end())
init_cp(s) ;
/* Weight the CPs */
if (ref_cps.size() == 1)
ref_cps[0].weight = 100 ;
else if (ref_cps.size() == 2)
weight_2_cps() ;
else
{
ostringstream oss ;
oss << "We should not be here... error when sorting the reference"
<< " CPs? (" << ref_cps.size() << " CPs sorted)" ;
throw autocalibration_error(oss.str()) ;
}
}
void Autocalibration::init_cp(
map<double, pair<double, unordered_map<
string, CapturePoint>::const_iterator> >::const_iterator s)
{
struct cp ref ;
ref.cp = &s->second.second->second ;
ref.angle = s->second.first ; // Angle P-REF-RX
ref_cps.push_back(ref) ;
}
void Autocalibration::weight_2_cps()
{
assert(ref_cps.size() > 1) ;
/* Compute the angle REF1-RX-REF2 */
double reference_angle = ref_cps[0].angle + ref_cps[1].angle ;
/* Note: the reference angle must be the sum of the two angles
P-RX-REF1 and P-RX-REF2 instead of simply REF1-RX-REF2, to allow
the angle to be within [0;360[° instead of [0;180[°. This is needed
if P-RX-REF1 or P-RX-REF2 are greater than 90°, otherwise the
weights would be wrong. */
/* Weight the two CPs */
if (reference_angle == 0)
ref_cps[0].weight = ref_cps[1].weight = 50 ;
else
{
ref_cps[0].weight = ref_cps[0].angle * 100 / reference_angle ;
if (ref_cps[0].weight > 100)
ref_cps[0].weight = 100 ;
ref_cps[1].weight = 100 - ref_cps[0].weight ;
}
}
void Autocalibration::compute_ss()
{
if (Configuration::
@ -251,120 +119,3 @@ void Autocalibration::compute_ss()
else
compute_single_packet_ss(0) ;
}
void Autocalibration::compute_multi_packet_ss()
{
const cp &ref1 = ref_cps[0] ;
const ReferencePoint &ref1_rp =
Stock::get_reference_point(ref1.cp->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() ;
for (cr = ref1_cr.begin() ; cr != ref1_cr.end() ; ++cr)
{
rx_measurement = (*cr)->get_measurement(rx_mac) ;
if (rx_measurement)
break ;
}
// The selected reference CPs are in coverage of RX, therefore
// we should always find a measurement of RX in ref1_rp
assert(rx_measurement) ;
/* Generate the SS for each packet */
bool packet_generated = false ;
for (pkt_id_t pkt_id = 1 ; pkt_id <= (*cr)->get_nb_packets() ;
++pkt_id)
if (compute_single_packet_ss(pkt_id))
packet_generated = true ;
if (! packet_generated)
{
if (Configuration::is_configured("verbose"))
cerr << "No packet has been generated for RX CP " << rx_mac
<< "... failing back to single packet request. Calibration"
<< " request involved : " << **cr << "\n" ;
compute_single_packet_ss(0) ;
}
}
/**
* @param pkt_id The number of the packet to create. Must be 0 if all
* the generated reference points contain only one packet.
*/
bool 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_cps.size() ; ++i)
{
double tmp_ss = compute_weighted_ss(i, pkt_id, point_dst) ;
if (tmp_ss > 0) // error
return false ;
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_cp(&rx->second) ;
return true ;
}
/**
* @param cp_idx The index of the CP in #ref_cps.
* @param pkt_id The number of the packet to generate, or 0 if we
* generate only one packet per reference point.
* @param 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 cp_idx, pkt_id_t pkt_id, float point_dst)
{
const cp &ref = ref_cps[cp_idx] ;
const ReferencePoint &rp =
Stock::get_reference_point(ref.cp->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_cp(rx_mac) ;
else
{
friis_idx = rp.friis_index_for_cp(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.cp->get_trx_power() +
ref.cp->get_antenna_gain() -
10 * friis_idx * log10(point_dst) ;
return ss * ref.weight / 100 ;
}

View File

@ -15,81 +15,45 @@
#ifndef _OWLPS_POSITIONING_AUTOCALIBRATION_HH_
#define _OWLPS_POSITIONING_AUTOCALIBRATION_HH_
class CapturePoint ;
class Point3D ;
#include "measurement.hh"
#include <vector>
#include <unordered_map>
/// Generates reference points from autocalibration measurements
/// Base class for the autocalibration methods
class Autocalibration
{
private:
struct cp
{
const CapturePoint *cp ;
float weight ; // Weight of the CP in percents
float angle ;
} ;
/// Current CP to generate a SS for
std::unordered_map<std::string, CapturePoint>::const_iterator rx ;
/// Angle P-RX-O, O being the origin of the trigonometric circle
float origin_angle ;
/// Selected transmitter CPs
std::vector<cp> ref_cps ;
/// Angles of the transmitter CPs (before M on the trigonometric
/// circle)
/**
* Note that the angles are stored in absolute value.
*/
std::multimap<double,
std::pair<double,
std::unordered_map<
std::string, CapturePoint>::const_iterator> >
sorted_negative_angles ;
/// Angles of the transmitter CPs (after M on the trigonometric circle)
std::multimap<double,
std::pair<double,
std::unordered_map<
std::string, CapturePoint>::const_iterator> >
sorted_positive_angles ;
/// Characteristics of the virtual mobile
double vmob_gain, vmob_pow ;
/// Generated measurements' list
std::unordered_map<std::string, Measurement> measurements ;
/// Initialises a struct cp with the values from `s`
void init_cp(
std::map<double, std::pair<double, std::unordered_map<
std::string, CapturePoint>::const_iterator> >::const_iterator s) ;
protected:
/// Number of generated "virtual" mobiles
static uint32_t nb_virtual_mobiles ;
/// Characteristics of the virtual mobile
double vmob_gain, vmob_pow ;
/// Work to do before actually generating a SS with generate_ss()
bool init_ss_generation(void) ;
protected:
/// The coordinates of the reference point to generate
const Point3D &point ;
/// Current CP to generate a SS for
std::unordered_map<std::string, CapturePoint>::const_iterator rx ;
/// Generated measurements' list
std::unordered_map<std::string, Measurement> measurements ;
/// Generates the SSs for all the CPs
void generate_ss(void) ;
/// Sorts the reference CPs for a receiver CP
void sort_reference_cps(void) ;
/// Computes the weight of the selected CP(s)
void weight_cps(void) ;
/// Weights two CPs according to their angles
void weight_2_cps(void) ;
/**
* Once the preliminary work done, this function should call
* compute_ss() to actually compute the signal strength.
*/
virtual void generate_ss(void) = 0 ;
/// Computes the SS of the virtual mobile
void compute_ss(void) ;
/// Computes a SS with several packets in it
void compute_multi_packet_ss(void) ;
virtual void compute_multi_packet_ss(void) = 0 ;
/// Computes a SS with only one packet in it
bool compute_single_packet_ss(pkt_id_t pkt_id) ;
/// Computes a SS according to the weight of the CP
double compute_weighted_ss(
unsigned int cp_idx, pkt_id_t pkt_id, float point_dst) ;
virtual bool compute_single_packet_ss(pkt_id_t pkt_id) = 0 ;
public:
Autocalibration(const Point3D &_point): point(_point) {}
@ -99,4 +63,3 @@ public:
} ;
#endif // _OWLPS_POSITIONING_AUTOCALIBRATION_HH_

View File

@ -0,0 +1,297 @@
/*
* This file is part of the Owl Positioning System (OwlPS) project.
* It is subject to the copyright notice and license terms in the
* COPYRIGHT.t2t file found in the top-level directory of this
* distribution and at
* http://code.lm7.fr/p/owlps/source/tree/master/COPYRIGHT.t2t
* No part of the OwlPS Project, including this file, may be copied,
* modified, propagated, or distributed except according to the terms
* contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
* distributed along with this file, either separately or by replacing
* this notice by the COPYRIGHT.t2t file's contents.
*/
#include "autocalibrationmesh.hh"
#include "point3d.hh"
#include "capturepoint.hh"
#include "stock.hh"
#include "configuration.hh"
#include "posexcept.hh"
#include <map>
#include <string>
#include <iostream>
#include <sstream>
using namespace std ;
/* *** Operations *** */
void AutocalibrationMesh::generate_ss()
{
/* Compute the origin angle P-RX-O */
const Point3D &rx_coord = rx->second.get_coordinates() ;
Point3D origin(rx_coord) ;
origin.set_x(rx_coord.get_x() + 10) ;
origin_angle = rx_coord.angle_2d(point, origin) ;
if (point.get_y() > rx_coord.get_y())
origin_angle = -origin_angle ;
/* Choose the nearest CP(s) in angle */
sort_reference_cps() ;
// We need at least one reference CP:
if (sorted_negative_angles.empty() && sorted_positive_angles.empty())
throw autocalibration_error("Not enough CPs in coverage!") ;
/* Compute the angle weight of the reference CPs */
weight_cps() ;
/* Compute the SS that would be received from a mobile at a
* distance of RX-P, in the direction of each reference CP */
compute_ss() ;
}
/**
* The reference (transmitter) CPs are first filtered (floor, coverage),
* then sorted according to their angles with RX and P.
*/
void AutocalibrationMesh::sort_reference_cps()
{
const Point3D &rx_coord = rx->second.get_coordinates() ;
sorted_negative_angles.clear() ;
sorted_positive_angles.clear() ;
for (unordered_map<string, CapturePoint>::const_iterator
ref = Stock::cps.begin() ; ref != Stock::cps.end() ; ++ref)
{
if (ref == rx)
continue ;
/* Skip the CP if it is not at the same floor than the
* receiver CP */
const Point3D &ref_coord = ref->second.get_coordinates() ;
if (ref_coord.get_z() != rx_coord.get_z())
continue ;
/* Skip the CP if it is not in coverage with the receiver CP */
float coverage =
rx->second.received_calibration_from_cp(ref->second) ;
if (coverage < 1) // Less than 1% coverage is ridiculous!
continue ;
/* Angle P-RX-REF */
double angle = rx_coord.angle_2d(point, ref_coord) ;
/* Weight in the CPs' list according to coverage and angle */
double weight = angle / coverage ;
/* Note: this weight is used only to sort the CPs, it has nothing
to do with the angle weight (see weight_cps()) used to compute
the SSs. */
/* Create the list entry */
pair<double,
unordered_map<string, CapturePoint>::const_iterator>
angle_cp(angle, ref) ;
pair<double, pair<double,
unordered_map<string, CapturePoint>::const_iterator> >
weight_angle_cp(weight, angle_cp) ;
/* Rotate the CP's coordinates to know the angle direction */
Point3D ref_coord_r(ref_coord) ;
ref_coord_r.rotate_2d(rx_coord, origin_angle) ;
// Insert the CP in the right list, according to the direction:
if (ref_coord_r.get_y() < rx_coord.get_y())
sorted_negative_angles.insert(weight_angle_cp) ;
else
sorted_positive_angles.insert(weight_angle_cp) ;
}
}
void AutocalibrationMesh::weight_cps()
{
/* Retrieve the reference CPs & angles */
ref_cps.clear() ;
map<double, pair<double,
unordered_map<string, CapturePoint>::const_iterator> >
::const_iterator s ;
s = sorted_negative_angles.begin() ;
if (s != sorted_negative_angles.end())
init_cp(s) ;
s = sorted_positive_angles.begin() ;
if (s != sorted_positive_angles.end())
init_cp(s) ;
/* Weight the CPs */
if (ref_cps.size() == 1)
ref_cps[0].weight = 100 ;
else if (ref_cps.size() == 2)
weight_2_cps() ;
else
{
ostringstream oss ;
oss << "We should not be here... error when sorting the reference"
<< " CPs? (" << ref_cps.size() << " CPs sorted)" ;
throw autocalibration_error(oss.str()) ;
}
}
void AutocalibrationMesh::init_cp(
map<double, pair<double, unordered_map<
string, CapturePoint>::const_iterator> >::const_iterator s)
{
struct cp ref ;
ref.cp = &s->second.second->second ;
ref.angle = s->second.first ; // Angle P-REF-RX
ref_cps.push_back(ref) ;
}
void AutocalibrationMesh::weight_2_cps()
{
assert(ref_cps.size() > 1) ;
/* Compute the angle REF1-RX-REF2 */
double reference_angle = ref_cps[0].angle + ref_cps[1].angle ;
/* Note: the reference angle must be the sum of the two angles
P-RX-REF1 and P-RX-REF2 instead of simply REF1-RX-REF2, to allow
the angle to be within [0;360[° instead of [0;180[°. This is needed
if P-RX-REF1 or P-RX-REF2 are greater than 90°, otherwise the
weights would be wrong. */
/* Weight the two CPs */
if (reference_angle == 0)
ref_cps[0].weight = ref_cps[1].weight = 50 ;
else
{
ref_cps[0].weight = ref_cps[0].angle * 100 / reference_angle ;
if (ref_cps[0].weight > 100)
ref_cps[0].weight = 100 ;
ref_cps[1].weight = 100 - ref_cps[0].weight ;
}
}
void AutocalibrationMesh::compute_multi_packet_ss()
{
const cp &ref1 = ref_cps[0] ;
const ReferencePoint &ref1_rp =
Stock::get_reference_point(ref1.cp->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() ;
for (cr = ref1_cr.begin() ; cr != ref1_cr.end() ; ++cr)
{
rx_measurement = (*cr)->get_measurement(rx_mac) ;
if (rx_measurement)
break ;
}
// The selected reference CPs are in coverage of RX, therefore
// we should always find a measurement of RX in ref1_rp
assert(rx_measurement) ;
/* Generate the SS for each packet */
bool packet_generated = false ;
for (pkt_id_t pkt_id = 1 ; pkt_id <= (*cr)->get_nb_packets() ;
++pkt_id)
if (compute_single_packet_ss(pkt_id))
packet_generated = true ;
if (! packet_generated)
{
if (Configuration::is_configured("verbose"))
cerr << "No packet has been generated for RX CP " << rx_mac
<< "... failing back to single packet request. Calibration"
<< " request involved : " << **cr << "\n" ;
compute_single_packet_ss(0) ;
}
}
/**
* @param pkt_id The number of the packet to create. Must be 0 if all
* the generated reference points contain only one packet.
*/
bool AutocalibrationMesh::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_cps.size() ; ++i)
{
double tmp_ss = compute_weighted_ss(i, pkt_id, point_dst) ;
if (tmp_ss > 0) // error
return false ;
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_cp(&rx->second) ;
return true ;
}
/**
* @param cp_idx The index of the CP in #ref_cps.
* @param pkt_id The number of the packet to generate, or 0 if we
* generate only one packet per reference point.
* @param point_dst The distance RX-P.
*
* @returns The weighted SS value in dBm, or 1 in case of error.
*/
double AutocalibrationMesh::compute_weighted_ss(
unsigned int cp_idx, pkt_id_t pkt_id, float point_dst)
{
const cp &ref = ref_cps[cp_idx] ;
const ReferencePoint &rp =
Stock::get_reference_point(ref.cp->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_cp(rx_mac) ;
else
{
friis_idx = rp.friis_index_for_cp(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.cp->get_trx_power() +
ref.cp->get_antenna_gain() -
10 * friis_idx * log10(point_dst) ;
return ss * ref.weight / 100 ;
}

View File

@ -0,0 +1,83 @@
/*
* This file is part of the Owl Positioning System (OwlPS) project.
* It is subject to the copyright notice and license terms in the
* COPYRIGHT.t2t file found in the top-level directory of this
* distribution and at
* http://code.lm7.fr/p/owlps/source/tree/master/COPYRIGHT.t2t
* No part of the OwlPS Project, including this file, may be copied,
* modified, propagated, or distributed except according to the terms
* contained in the COPYRIGHT.t2t file; the COPYRIGHT.t2t file must be
* distributed along with this file, either separately or by replacing
* this notice by the COPYRIGHT.t2t file's contents.
*/
#ifndef _OWLPS_POSITIONING_AUTOCALIBRATIONMESH_HH_
#define _OWLPS_POSITIONING_AUTOCALIBRATIONMESH_HH_
class CapturePoint ;
class Point3D ;
#include "autocalibration.hh"
#include <vector>
#include <unordered_map>
/// Generates reference points in a mesh
class AutocalibrationMesh: public Autocalibration
{
protected:
struct cp
{
const CapturePoint *cp ;
float weight ; // Weight of the CP in percents
float angle ;
} ;
/// Angle P-RX-O, O being the origin of the trigonometric circle
float origin_angle ;
/// Selected transmitter CPs
std::vector<cp> ref_cps ;
/// Angles of the transmitter CPs (before M on the trigonometric
/// circle)
/**
* Note that the angles are stored in absolute value.
*/
std::multimap<double,
std::pair<double,
std::unordered_map<
std::string, CapturePoint>::const_iterator> >
sorted_negative_angles ;
/// Angles of the transmitter CPs (after M on the trigonometric circle)
std::multimap<double,
std::pair<double,
std::unordered_map<
std::string, CapturePoint>::const_iterator> >
sorted_positive_angles ;
/// Initialises a struct cp with the values from `s`
void init_cp(
std::map<double, std::pair<double, std::unordered_map<
std::string, CapturePoint>::const_iterator> >::const_iterator s) ;
/// Generates the SSs for all the CPs
void generate_ss(void) ;
/// Sorts the reference CPs for a receiver CP
void sort_reference_cps(void) ;
/// Computes the weight of the selected CP(s)
void weight_cps(void) ;
/// Weights two CPs according to their angles
void weight_2_cps(void) ;
/// Computes a SS with several packets in it
void compute_multi_packet_ss(void) ;
/// Computes a SS with only one packet in it
bool compute_single_packet_ss(pkt_id_t pkt_id) ;
/// Computes a SS according to the weight of the CP
double compute_weighted_ss(
unsigned int cp_idx, pkt_id_t pkt_id, float point_dst) ;
public:
AutocalibrationMesh(const Point3D &_point): Autocalibration(_point) {}
} ;
#endif // _OWLPS_POSITIONING_AUTOCALIBRATIONMESH_HH_

View File

@ -17,6 +17,7 @@
#include "posexcept.hh"
#include "area.hh"
#include "csvstringreader.hh"
#include "autocalibrationmesh.hh"
#include <iostream>
@ -503,7 +504,7 @@ void Stock::generate_reference_points_list()
*/
void Stock::generate_reference_point(const Point3D &coord)
{
Autocalibration ac(coord) ;
AutocalibrationMesh ac(coord) ;
try
{
ac.generate_reference_point() ;

View File

@ -15,7 +15,6 @@
#ifndef _OWLPS_POSITIONING_STOCK_HH_
#define _OWLPS_POSITIONING_STOCK_HH_
#include "autocalibration.hh"
#include "building.hh"
#include "waypoint.hh"
#include "mobile.hh"
@ -30,6 +29,7 @@
class Stock
{
friend class Autocalibration ;
friend class AutocalibrationMesh ;
private:
/// List of known Building