[Positioning] Add option generate-reference-points

The self-calibration is here! There is certainly some things to fix, but
the big step is made.
This commit is contained in:
Matteo Cypriani 2011-07-22 11:29:30 +02:00
parent 3c00c3bb19
commit 0d160f8b23
5 changed files with 211 additions and 0 deletions

View File

@ -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

View File

@ -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() ;
}
}
}

View File

@ -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<ReferencePoint>::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<string, AccessPoint>::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<double,
unordered_map<string, AccessPoint>::const_iterator>
sorted_angles ;
for (unordered_map<string, AccessPoint>::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<double,
unordered_map<string, AccessPoint>::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<double,
unordered_map<string, AccessPoint>::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<double>(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<string, Measurement> 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 *** */

View File

@ -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 */

View File

@ -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<bool>()->default_value(false),
"Generate reference points from the (auto)calibration requests"
" received.")
("positioning.accept-new-calibration-requests",
po::value<bool>()->default_value(false),
"Add the calibration requests received during the run-time to"