2012-02-06 16:44:09 +01:00
|
|
|
/*
|
|
|
|
* This file is part of the Owl Positioning System (OwlPS).
|
|
|
|
* OwlPS is a project of the University of Franche-Comté
|
|
|
|
* (Université de Franche-Comté), France.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2008-04-11 10:11:29 +02:00
|
|
|
#include "measurement.hh"
|
2010-06-02 12:37:43 +02:00
|
|
|
#include "posexcept.hh"
|
2012-03-02 10:54:34 +01:00
|
|
|
#include "configuration.hh"
|
2009-12-11 13:52:21 +01:00
|
|
|
|
2011-10-28 17:13:04 +02:00
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
|
2010-01-04 17:10:42 +01:00
|
|
|
using namespace std ;
|
|
|
|
|
|
|
|
|
2009-12-11 13:52:21 +01:00
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/* *** Constructors *** */
|
2009-12-11 13:52:21 +01:00
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/**
|
|
|
|
* Note that values pointed by #ap are not deleted.
|
2010-01-07 16:26:13 +01:00
|
|
|
*/
|
2009-12-11 13:52:21 +01:00
|
|
|
Measurement::~Measurement()
|
|
|
|
{
|
|
|
|
ss_list.clear() ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-02-28 12:17:20 +01:00
|
|
|
/* *** Read accessors *** */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @returns The SS of the packet number \em pkt_id.
|
|
|
|
* @returns 0 if the packet ID does not exist in the SS list.
|
|
|
|
*/
|
|
|
|
ss_t Measurement::get_ss(pkt_id_t pkt_id) const
|
|
|
|
{
|
|
|
|
std::map<pkt_id_t, ss_t>::const_iterator ss = ss_list.find(pkt_id) ;
|
|
|
|
if (ss == ss_list.end())
|
|
|
|
return 0 ;
|
|
|
|
return ss->second ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/* *** Write accessors *** */
|
2009-12-11 13:52:21 +01:00
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/**
|
2011-10-28 17:13:04 +02:00
|
|
|
* @param packet_id The sequence number of the packet in the request,
|
|
|
|
* as sent by the mobile.
|
2010-02-05 11:02:24 +01:00
|
|
|
* @param ss_dbm The signal strength to add to #ss_list (in dBm).
|
2010-01-16 12:23:07 +01:00
|
|
|
*/
|
2011-10-28 17:13:04 +02:00
|
|
|
void Measurement::
|
2011-12-30 19:52:51 +01:00
|
|
|
add_ss(const pkt_id_t packet_id, const ss_t ss_dbm)
|
2009-12-11 13:52:21 +01:00
|
|
|
{
|
2011-10-28 17:13:04 +02:00
|
|
|
// Add the new value (in dBm) along with the packet identifier:
|
2011-12-30 19:52:51 +01:00
|
|
|
pair<pkt_id_t, ss_t> packet(make_pair(packet_id, ss_dbm)) ;
|
2011-10-28 17:13:04 +02:00
|
|
|
if (! ss_list.insert(packet).second)
|
|
|
|
{
|
|
|
|
cerr
|
|
|
|
<< "Cannot insert the packet (#" << packet_id << ", "
|
|
|
|
<< static_cast<int_fast16_t>(ss_dbm) << " dBm)\n" ;
|
|
|
|
return ;
|
|
|
|
}
|
2010-02-05 11:02:24 +01:00
|
|
|
|
2012-02-03 11:55:24 +01:00
|
|
|
// Update the average & variance with the new value:
|
|
|
|
update_average(ss_dbm) ;
|
2010-01-07 16:34:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-10-28 17:13:04 +02:00
|
|
|
/**
|
|
|
|
* Add an SS list to the current Measurement's SS list.
|
|
|
|
* If the new SS list contains a packet with the same ID, the old one
|
|
|
|
* is overwritten.
|
|
|
|
*/
|
|
|
|
void Measurement::
|
2011-12-30 19:52:51 +01:00
|
|
|
add_ss_list(const map<pkt_id_t, ss_t> &_ss_list)
|
2010-01-07 16:34:31 +01:00
|
|
|
{
|
2011-10-28 17:13:04 +02:00
|
|
|
// We cannot use insert() here because we want to overwrite the
|
|
|
|
// previous values with the same ID, if any.
|
2011-12-30 19:52:51 +01:00
|
|
|
for (map<pkt_id_t, ss_t>::const_iterator
|
2011-10-28 17:13:04 +02:00
|
|
|
i = _ss_list.begin() ; i != _ss_list.end() ; ++i)
|
|
|
|
ss_list[i->first] = i->second ;
|
2010-01-07 16:34:31 +01:00
|
|
|
|
2012-02-03 11:55:24 +01:00
|
|
|
recalculate_average() ;
|
2010-06-02 12:37:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2011-12-30 18:27:30 +01:00
|
|
|
* Merge consists of adding the SS values of \em source to #ss_list. It
|
|
|
|
* is possible only if the #ap of the two Measurement are identical.
|
2010-06-02 12:37:43 +02:00
|
|
|
* @throw cannot_merge if the AP of the two Measurement are different.
|
|
|
|
*/
|
|
|
|
void Measurement::merge(const Measurement &source)
|
|
|
|
{
|
|
|
|
if (ap != source.ap)
|
|
|
|
throw cannot_merge(
|
|
|
|
"error when trying to merge measurements, APs are different") ;
|
|
|
|
|
|
|
|
add_ss_list(source.ss_list) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/**
|
|
|
|
* - #ap is not deleted, only initialised to NULL.
|
|
|
|
* - #ss_list is cleared.
|
2012-06-19 17:56:10 +02:00
|
|
|
* - average and variance variables are reset to 0.
|
2010-01-07 16:34:31 +01:00
|
|
|
*/
|
|
|
|
void Measurement::clear()
|
|
|
|
{
|
|
|
|
ss_list.clear() ;
|
2012-02-03 11:55:24 +01:00
|
|
|
average_dbm = 0 ;
|
|
|
|
average_mw = 0 ;
|
2012-06-19 17:13:27 +02:00
|
|
|
variance_mw = 0 ;
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_dbm = 0 ;
|
2012-06-19 17:13:27 +02:00
|
|
|
variance_mw_m2 = 0 ;
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_dbm_m2 = 0 ;
|
2012-06-19 17:17:10 +02:00
|
|
|
variance_size = 0 ;
|
2010-01-07 16:34:31 +01:00
|
|
|
ap = NULL ;
|
2009-12-11 13:52:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-02-05 11:02:24 +01:00
|
|
|
/* *** Operations *** */
|
|
|
|
|
|
|
|
|
2012-03-02 10:54:34 +01:00
|
|
|
float Measurement::similarity(const Measurement &source) const
|
|
|
|
{
|
2012-03-05 13:53:48 +01:00
|
|
|
assert(! ss_list.empty()) ;
|
|
|
|
assert(! source.ss_list.empty()) ;
|
|
|
|
|
2012-03-02 10:54:34 +01:00
|
|
|
string algorithm(
|
|
|
|
Configuration::string_value("positioning.ss-similarity")) ;
|
|
|
|
|
|
|
|
if (algorithm == "mean")
|
|
|
|
return ss_square_distance(source) ;
|
|
|
|
|
|
|
|
if (algorithm == "interval")
|
2012-06-19 17:13:27 +02:00
|
|
|
return 1 / nb_in_interval(source, get_std_deviation_mw()) ;
|
2012-03-06 12:27:15 +01:00
|
|
|
/* Note: this score ranges from 0 (excluded) to 1 (obviously). */
|
|
|
|
|
|
|
|
if (algorithm == "interval2")
|
|
|
|
{
|
2012-06-19 17:13:27 +02:00
|
|
|
float std_dev = get_std_deviation_mw() ;
|
2012-03-06 12:27:15 +01:00
|
|
|
float interval1 = nb_in_interval(source, 0.674 * std_dev) ;
|
|
|
|
float interval2 = nb_in_interval(source, std_dev) ;
|
|
|
|
/* Explanation: with a normal distribution, we normally have:
|
|
|
|
* - 68% of the values within the interval
|
|
|
|
* [mean-std.dev.;mean+std.dev.], and
|
|
|
|
* - 50% of the value within the interval
|
|
|
|
* [mean-.674*std.dev.;mean+.674*std.dev.] */
|
|
|
|
|
|
|
|
float percent1 = interval1 * 100 / source.get_nb_ss() ;
|
|
|
|
float percent2 = interval2 * 100 / source.get_nb_ss() ;
|
|
|
|
|
|
|
|
return (percent1 - 50) * (percent1 - 50) +
|
|
|
|
(percent2 - 68) * (percent2 - 68) ;
|
|
|
|
/* Note: this distance (score) ranges from 0 (with
|
|
|
|
* percent1==50 and percent2==68) to 7124 (with percent1
|
|
|
|
* and percent2==0). */
|
|
|
|
}
|
2012-03-02 10:54:34 +01:00
|
|
|
|
|
|
|
throw bad_configuration(
|
|
|
|
"Bad SS similarity algorithm name \""+ algorithm +"\"!") ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-05 13:53:48 +01:00
|
|
|
unsigned int Measurement::
|
|
|
|
nb_in_interval(const Measurement &source, float bound) const
|
|
|
|
{
|
|
|
|
unsigned int nb_values = 0 ;
|
|
|
|
|
|
|
|
for (map<pkt_id_t, ss_t>::const_iterator ss =
|
|
|
|
source.ss_list.begin() ; ss != source.ss_list.end() ; ++ss)
|
|
|
|
if (PosUtil::is_in_interval(average_dbm, bound, ss->second))
|
|
|
|
++nb_values ;
|
|
|
|
|
|
|
|
return nb_values ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-03 11:55:24 +01:00
|
|
|
void Measurement::recalculate_average()
|
2010-02-05 11:02:24 +01:00
|
|
|
{
|
2012-02-03 11:55:24 +01:00
|
|
|
average_dbm = 0 ;
|
|
|
|
average_mw = 0 ;
|
2012-06-19 17:13:27 +02:00
|
|
|
variance_mw = 0 ;
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_dbm = 0 ;
|
2012-06-19 17:13:27 +02:00
|
|
|
variance_mw_m2 = 0 ;
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_dbm_m2 = 0 ;
|
2012-06-19 17:17:10 +02:00
|
|
|
variance_size = 0 ;
|
2010-02-05 11:02:24 +01:00
|
|
|
|
2011-12-30 19:52:51 +01:00
|
|
|
for (map<pkt_id_t, ss_t>::const_iterator
|
2011-10-28 17:13:04 +02:00
|
|
|
i = ss_list.begin() ; i != ss_list.end() ; ++i)
|
2012-02-03 11:55:24 +01:00
|
|
|
update_average(i->second) ;
|
|
|
|
}
|
2010-02-05 11:02:24 +01:00
|
|
|
|
2012-02-03 11:55:24 +01:00
|
|
|
|
|
|
|
void Measurement::update_average(ss_t ss_dbm)
|
|
|
|
{
|
2012-06-19 17:17:10 +02:00
|
|
|
++variance_size ;
|
|
|
|
assert(variance_size <= ss_list.size()) ;
|
|
|
|
|
2012-02-03 11:55:24 +01:00
|
|
|
// Convert the new SS in mW:
|
2012-02-09 14:49:36 +01:00
|
|
|
float ss_mw = pow(10, static_cast<float>(ss_dbm) / 10.0) ;
|
2012-02-03 11:55:24 +01:00
|
|
|
|
|
|
|
// Update the average:
|
2012-06-19 17:56:10 +02:00
|
|
|
float delta_mw = ss_mw - average_mw ;
|
|
|
|
average_mw += delta_mw / variance_size ;
|
2012-02-03 11:55:24 +01:00
|
|
|
average_dbm = 10.0 * log10(average_mw) ;
|
2012-06-19 17:56:10 +02:00
|
|
|
float delta_dbm = ss_dbm - average_dbm ;
|
2012-02-03 11:55:24 +01:00
|
|
|
|
|
|
|
// Update the variance:
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_mw_m2 += delta_mw * (ss_mw - average_mw) ;
|
|
|
|
variance_dbm_m2 += delta_dbm * (ss_dbm - average_dbm) ;
|
2012-06-19 17:17:10 +02:00
|
|
|
if (variance_size > 1)
|
2012-06-19 17:56:10 +02:00
|
|
|
{
|
|
|
|
variance_mw = variance_mw_m2 / (variance_size - 1) ;
|
|
|
|
variance_dbm = variance_dbm_m2 / (variance_size - 1) ;
|
|
|
|
}
|
2010-02-05 11:02:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-01-16 12:23:07 +01:00
|
|
|
/* *** Operators *** */
|
2009-12-11 13:52:21 +01:00
|
|
|
|
|
|
|
|
2011-07-30 20:38:42 +02:00
|
|
|
Measurement& Measurement::operator=(const Measurement &m)
|
2009-12-11 17:56:31 +01:00
|
|
|
{
|
|
|
|
if (this == &m)
|
|
|
|
return *this ;
|
|
|
|
|
|
|
|
ap = m.ap ;
|
|
|
|
ss_list = m.ss_list ;
|
2012-02-03 11:55:24 +01:00
|
|
|
average_dbm = m.average_dbm ;
|
|
|
|
average_mw = m.average_mw ;
|
2012-06-19 17:13:27 +02:00
|
|
|
variance_mw = m.variance_mw ;
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_dbm = m.variance_mw ;
|
2012-06-19 17:13:27 +02:00
|
|
|
variance_mw_m2 = m.variance_mw_m2 ;
|
2012-06-19 17:56:10 +02:00
|
|
|
variance_dbm_m2 = m.variance_mw_m2 ;
|
2012-06-19 17:17:10 +02:00
|
|
|
variance_size = m.variance_size ;
|
2009-12-11 17:56:31 +01:00
|
|
|
|
|
|
|
return *this ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-07 16:26:13 +01:00
|
|
|
bool Measurement::operator==(const Measurement &m) const
|
2009-12-11 17:56:31 +01:00
|
|
|
{
|
|
|
|
if (this == &m)
|
|
|
|
return true ;
|
|
|
|
|
|
|
|
return
|
|
|
|
ap == m.ap &&
|
2012-02-03 11:55:24 +01:00
|
|
|
ss_list == m.ss_list ;
|
2009-12-11 17:56:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-10-28 17:13:04 +02:00
|
|
|
const string Measurement::to_csv() const
|
|
|
|
{
|
|
|
|
ostringstream csv_line ;
|
|
|
|
|
|
|
|
if (ss_list.empty())
|
|
|
|
return "" ;
|
|
|
|
|
|
|
|
string mac_ap("") ;
|
|
|
|
if (ap)
|
|
|
|
mac_ap = ap->get_mac_addr() ;
|
|
|
|
|
2011-12-30 19:52:51 +01:00
|
|
|
for (map<pkt_id_t, ss_t>::const_iterator
|
2011-10-28 17:13:04 +02:00
|
|
|
i = ss_list.begin() ; i != ss_list.end() ; ++i)
|
|
|
|
{
|
|
|
|
if (i != ss_list.begin())
|
|
|
|
csv_line << ';' ;
|
|
|
|
csv_line
|
|
|
|
<< mac_ap << ';'
|
|
|
|
<< i->first << ';'
|
|
|
|
<< static_cast<int_fast16_t>(i->second) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
return csv_line.str() ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-04-30 11:36:55 +02:00
|
|
|
ostream &operator<<(ostream &os, const Measurement &m)
|
2008-04-11 10:11:29 +02:00
|
|
|
{
|
2010-01-11 19:40:45 +01:00
|
|
|
// MAC address
|
2010-01-06 01:18:14 +01:00
|
|
|
os
|
2011-10-28 17:13:04 +02:00
|
|
|
<< "AP: " << (m.ap ? m.ap->get_mac_addr() : "Unknown_AP")
|
2010-01-06 01:18:14 +01:00
|
|
|
<< ": " ;
|
2010-01-04 16:37:18 +01:00
|
|
|
|
|
|
|
// List of SS
|
2010-02-26 13:09:45 +01:00
|
|
|
if (m.ss_list.empty())
|
2009-12-14 15:45:16 +01:00
|
|
|
os << "No values" ;
|
2008-04-15 12:19:15 +02:00
|
|
|
else
|
2011-12-30 19:52:51 +01:00
|
|
|
for (map<pkt_id_t, ss_t>::const_iterator
|
2011-10-28 17:13:04 +02:00
|
|
|
i = m.ss_list.begin() ; i != m.ss_list.end() ; ++i)
|
2008-04-15 12:19:15 +02:00
|
|
|
{
|
2011-10-28 17:13:04 +02:00
|
|
|
if (i != m.ss_list.begin())
|
|
|
|
os << ';' ;
|
|
|
|
os << static_cast<int_fast16_t>(i->second)
|
|
|
|
<< '(' << i->first << ')' ;
|
2008-04-15 12:19:15 +02:00
|
|
|
}
|
2012-06-19 17:56:10 +02:00
|
|
|
os << " [AVG_dBm=" << m.average_dbm
|
|
|
|
<< ";VAR_dBm=" << m.variance_dbm
|
|
|
|
<< ";STD_dBm=" << m.get_std_deviation_dbm()
|
|
|
|
<< ";AVG_mW=" << m.average_mw
|
|
|
|
<< ";VAR_mW=" << m.variance_mw
|
|
|
|
<< ";STD_mW=" << m.get_std_deviation_mw()
|
|
|
|
<< "]" ;
|
2009-05-29 13:46:49 +02:00
|
|
|
|
2010-01-04 16:37:18 +01:00
|
|
|
return os ;
|
2008-04-11 10:11:29 +02:00
|
|
|
}
|