Add parameters for map matching
This commit is contained in:
parent
d89b171f49
commit
e5830b0116
@ -33,7 +33,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
|
|
||||||
RouteParameters::RouteParameters()
|
RouteParameters::RouteParameters()
|
||||||
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
|
: zoom_level(18), print_instructions(false), alternate_route(true), geometry(true),
|
||||||
compression(true), deprecatedAPI(false), uturn_default(false), check_sum(-1), num_results(1)
|
compression(true), deprecatedAPI(false), uturn_default(false), classify(false),
|
||||||
|
matching_beta(-1.0), gps_precision(-1.0), check_sum(-1), num_results(1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +84,12 @@ void RouteParameters::setInstructionFlag(const bool flag) { print_instructions =
|
|||||||
|
|
||||||
void RouteParameters::setService(const std::string &service_string) { service = service_string; }
|
void RouteParameters::setService(const std::string &service_string) { service = service_string; }
|
||||||
|
|
||||||
|
void RouteParameters::setClassify(const bool flag) { classify = flag; }
|
||||||
|
|
||||||
|
void RouteParameters::setMatchingBeta(const double beta) { matching_beta = beta; }
|
||||||
|
|
||||||
|
void RouteParameters::setGPSPrecision(const double precision) { gps_precision = precision; }
|
||||||
|
|
||||||
void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
|
void RouteParameters::setOutputFormat(const std::string &format) { output_format = format; }
|
||||||
|
|
||||||
void RouteParameters::setJSONpParameter(const std::string ¶meter)
|
void RouteParameters::setJSONpParameter(const std::string ¶meter)
|
||||||
|
@ -49,6 +49,12 @@ struct RouteParameters
|
|||||||
|
|
||||||
void setAllUTurns(const bool flag);
|
void setAllUTurns(const bool flag);
|
||||||
|
|
||||||
|
void setClassify(const bool classify);
|
||||||
|
|
||||||
|
void setMatchingBeta(const double beta);
|
||||||
|
|
||||||
|
void setGPSPrecision(const double precision);
|
||||||
|
|
||||||
void setDeprecatedAPIFlag(const std::string &);
|
void setDeprecatedAPIFlag(const std::string &);
|
||||||
|
|
||||||
void setChecksum(const unsigned check_sum);
|
void setChecksum(const unsigned check_sum);
|
||||||
@ -80,6 +86,9 @@ struct RouteParameters
|
|||||||
bool compression;
|
bool compression;
|
||||||
bool deprecatedAPI;
|
bool deprecatedAPI;
|
||||||
bool uturn_default;
|
bool uturn_default;
|
||||||
|
bool classify;
|
||||||
|
double matching_beta;
|
||||||
|
double gps_precision;
|
||||||
unsigned check_sum;
|
unsigned check_sum;
|
||||||
short num_results;
|
short num_results;
|
||||||
std::string service;
|
std::string service;
|
||||||
|
@ -171,7 +171,8 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
|||||||
{
|
{
|
||||||
osrm::json::Object subtrace;
|
osrm::json::Object subtrace;
|
||||||
|
|
||||||
subtrace.values["confidence"] = sub.confidence;
|
if (route_parameters.classify)
|
||||||
|
subtrace.values["confidence"] = sub.confidence;
|
||||||
|
|
||||||
if (route_parameters.geometry)
|
if (route_parameters.geometry)
|
||||||
{
|
{
|
||||||
@ -230,11 +231,18 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
|||||||
return 400;
|
return 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
// call the actual map matching
|
// setup logging if enabled
|
||||||
if (osrm::json::Logger::get())
|
if (osrm::json::Logger::get())
|
||||||
osrm::json::Logger::get()->initialize("matching");
|
osrm::json::Logger::get()->initialize("matching");
|
||||||
|
|
||||||
|
// call the actual map matching
|
||||||
Matching::SubMatchingList sub_matchings;
|
Matching::SubMatchingList sub_matchings;
|
||||||
search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps, sub_matchings);
|
search_engine_ptr->map_matching(candidates_lists,
|
||||||
|
input_coords,
|
||||||
|
input_timestamps,
|
||||||
|
route_parameters.matching_beta,
|
||||||
|
route_parameters.gps_precision,
|
||||||
|
sub_matchings);
|
||||||
|
|
||||||
if (1 > sub_matchings.size())
|
if (1 > sub_matchings.size())
|
||||||
{
|
{
|
||||||
@ -245,17 +253,20 @@ template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
|
|||||||
for (auto& sub : sub_matchings)
|
for (auto& sub : sub_matchings)
|
||||||
{
|
{
|
||||||
// classify result
|
// classify result
|
||||||
double trace_length = sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
|
if (route_parameters.classify)
|
||||||
TraceClassification classification = classify(trace_length,
|
|
||||||
sub.length,
|
|
||||||
(sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
|
|
||||||
if (classification.first == ClassifierT::ClassLabel::POSITIVE)
|
|
||||||
{
|
{
|
||||||
sub.confidence = classification.second;
|
double trace_length = sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
|
||||||
}
|
TraceClassification classification = classify(trace_length,
|
||||||
else
|
sub.length,
|
||||||
{
|
(sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
|
||||||
sub.confidence = 1-classification.second;
|
if (classification.first == ClassifierT::ClassLabel::POSITIVE)
|
||||||
|
{
|
||||||
|
sub.confidence = classification.second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sub.confidence = 1-classification.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(sub.nodes.size() > 1);
|
BOOST_ASSERT(sub.nodes.size() > 1);
|
||||||
|
@ -75,67 +75,42 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
SearchEngineData &engine_working_data;
|
SearchEngineData &engine_working_data;
|
||||||
|
|
||||||
// FIXME this value should be a table based on samples/meter (or samples/min)
|
// FIXME this value should be a table based on samples/meter (or samples/min)
|
||||||
constexpr static const double beta = 10.0;
|
constexpr static const double default_beta = 10.0;
|
||||||
constexpr static const double sigma_z = 4.07;
|
constexpr static const double default_sigma_z = 4.07;
|
||||||
constexpr static const double log_sigma_z = std::log(sigma_z);
|
|
||||||
constexpr static const double log_2_pi = std::log(2 * M_PI);
|
constexpr static const double log_2_pi = std::log(2 * M_PI);
|
||||||
|
|
||||||
constexpr static double emission_probability(const double distance)
|
// closures to precompute log -> only simple floating point operations
|
||||||
|
struct EmissionLogProbability
|
||||||
{
|
{
|
||||||
return (1. / (std::sqrt(2. * M_PI) * sigma_z)) *
|
double sigma_z;
|
||||||
std::exp(-0.5 * std::pow((distance / sigma_z), 2.));
|
double log_sigma_z;
|
||||||
}
|
|
||||||
|
|
||||||
constexpr static double transition_probability(const float d_t, const float beta)
|
EmissionLogProbability(const double sigma_z)
|
||||||
|
: sigma_z(sigma_z)
|
||||||
|
, log_sigma_z(std::log(sigma_z))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
double operator()(const double distance) const
|
||||||
|
{
|
||||||
|
return -0.5 * (log_2_pi + (distance / sigma_z) * (distance / sigma_z)) - log_sigma_z;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct TransitionLogProbability
|
||||||
{
|
{
|
||||||
return (1. / beta) * std::exp(-d_t / beta);
|
double beta;
|
||||||
}
|
double log_beta;
|
||||||
|
TransitionLogProbability(const double beta)
|
||||||
|
: beta(beta)
|
||||||
|
, log_beta(std::log(beta))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
constexpr static double log_emission_probability(const double distance)
|
double operator()(const double d_t) const
|
||||||
{
|
{
|
||||||
return -0.5 * (log_2_pi + (distance / sigma_z) * (distance / sigma_z)) - log_sigma_z;
|
return -log_beta - d_t / beta;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
constexpr static double log_transition_probability(const float d_t, const float beta)
|
|
||||||
{
|
|
||||||
return -std::log(beta) - d_t / beta;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: needs to be estimated from the input locations
|
|
||||||
// FIXME These values seem wrong. Higher beta for more samples/minute? Should be inverse
|
|
||||||
// proportional.
|
|
||||||
// samples/min and beta
|
|
||||||
// 1 0.49037673
|
|
||||||
// 2 0.82918373
|
|
||||||
// 3 1.24364564
|
|
||||||
// 4 1.67079581
|
|
||||||
// 5 2.00719298
|
|
||||||
// 6 2.42513007
|
|
||||||
// 7 2.81248831
|
|
||||||
// 8 3.15745473
|
|
||||||
// 9 3.52645392
|
|
||||||
// 10 4.09511775
|
|
||||||
// 11 4.67319795
|
|
||||||
// 21 12.55107715
|
|
||||||
// 12 5.41088180
|
|
||||||
// 13 6.47666590
|
|
||||||
// 14 6.29010734
|
|
||||||
// 15 7.80752112
|
|
||||||
// 16 8.09074504
|
|
||||||
// 17 8.08550528
|
|
||||||
// 18 9.09405065
|
|
||||||
// 19 11.09090603
|
|
||||||
// 20 11.87752824
|
|
||||||
// 21 12.55107715
|
|
||||||
// 22 15.82820829
|
|
||||||
// 23 17.69496773
|
|
||||||
// 24 18.07655652
|
|
||||||
// 25 19.63438911
|
|
||||||
// 26 25.40832185
|
|
||||||
// 27 23.76001877
|
|
||||||
// 28 28.43289797
|
|
||||||
// 29 32.21683062
|
|
||||||
// 30 34.56991141
|
|
||||||
|
|
||||||
double get_network_distance(const PhantomNode &source_phantom,
|
double get_network_distance(const PhantomNode &source_phantom,
|
||||||
const PhantomNode &target_phantom) const
|
const PhantomNode &target_phantom) const
|
||||||
@ -231,9 +206,10 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
std::vector<bool> breakage;
|
std::vector<bool> breakage;
|
||||||
|
|
||||||
const Matching::CandidateLists &candidates_list;
|
const Matching::CandidateLists &candidates_list;
|
||||||
|
const EmissionLogProbability& emission_log_probability;
|
||||||
|
|
||||||
HiddenMarkovModel(const Matching::CandidateLists &candidates_list)
|
HiddenMarkovModel(const Matching::CandidateLists &candidates_list, const EmissionLogProbability& emission_log_probability)
|
||||||
: breakage(candidates_list.size()), candidates_list(candidates_list)
|
: breakage(candidates_list.size()), candidates_list(candidates_list), emission_log_probability(emission_log_probability)
|
||||||
{
|
{
|
||||||
for (const auto &l : candidates_list)
|
for (const auto &l : candidates_list)
|
||||||
{
|
{
|
||||||
@ -271,7 +247,7 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
for (auto s = 0u; s < viterbi[initial_timestamp].size(); ++s)
|
for (auto s = 0u; s < viterbi[initial_timestamp].size(); ++s)
|
||||||
{
|
{
|
||||||
viterbi[initial_timestamp][s] =
|
viterbi[initial_timestamp][s] =
|
||||||
log_emission_probability(candidates_list[initial_timestamp][s].second);
|
emission_log_probability(candidates_list[initial_timestamp][s].second);
|
||||||
parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
|
parents[initial_timestamp][s] = std::make_pair(initial_timestamp, s);
|
||||||
pruned[initial_timestamp][s] =
|
pruned[initial_timestamp][s] =
|
||||||
viterbi[initial_timestamp][s] < Matching::MINIMAL_LOG_PROB;
|
viterbi[initial_timestamp][s] < Matching::MINIMAL_LOG_PROB;
|
||||||
@ -297,6 +273,7 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Provides the debug interface for introspection tools
|
||||||
struct DebugInfo
|
struct DebugInfo
|
||||||
{
|
{
|
||||||
DebugInfo(const osrm::json::Logger* logger)
|
DebugInfo(const osrm::json::Logger* logger)
|
||||||
@ -419,11 +396,17 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
void operator()(const Matching::CandidateLists &candidates_list,
|
void operator()(const Matching::CandidateLists &candidates_list,
|
||||||
const std::vector<FixedPointCoordinate> &trace_coordinates,
|
const std::vector<FixedPointCoordinate> &trace_coordinates,
|
||||||
const std::vector<unsigned> &trace_timestamps,
|
const std::vector<unsigned> &trace_timestamps,
|
||||||
|
const double matching_beta,
|
||||||
|
const double gps_precision,
|
||||||
Matching::SubMatchingList &sub_matchings) const
|
Matching::SubMatchingList &sub_matchings) const
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(candidates_list.size() > 0);
|
BOOST_ASSERT(candidates_list.size() > 0);
|
||||||
|
|
||||||
HiddenMarkovModel model(candidates_list);
|
// TODO replace default values with table lookup based on sampling frequency
|
||||||
|
EmissionLogProbability emission_log_probability(gps_precision > 0 ? gps_precision : default_sigma_z);
|
||||||
|
TransitionLogProbability transition_log_probability(matching_beta > 0 ? matching_beta : default_beta);
|
||||||
|
|
||||||
|
HiddenMarkovModel model(candidates_list, emission_log_probability);
|
||||||
|
|
||||||
unsigned initial_timestamp = model.initialize(0);
|
unsigned initial_timestamp = model.initialize(0);
|
||||||
if (initial_timestamp == Matching::INVALID_STATE)
|
if (initial_timestamp == Matching::INVALID_STATE)
|
||||||
@ -464,7 +447,7 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
{
|
{
|
||||||
// how likely is candidate s_prime at time t to be emitted?
|
// how likely is candidate s_prime at time t to be emitted?
|
||||||
const double emission_pr =
|
const double emission_pr =
|
||||||
log_emission_probability(candidates_list[t][s_prime].second);
|
emission_log_probability(candidates_list[t][s_prime].second);
|
||||||
double new_value = prev_viterbi[s] + emission_pr;
|
double new_value = prev_viterbi[s] + emission_pr;
|
||||||
if (current_viterbi[s_prime] > new_value)
|
if (current_viterbi[s_prime] > new_value)
|
||||||
continue;
|
continue;
|
||||||
@ -483,7 +466,7 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
if (d_t > 500)
|
if (d_t > 500)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const double transition_pr = log_transition_probability(d_t, beta);
|
const double transition_pr = transition_log_probability(d_t);
|
||||||
new_value += transition_pr;
|
new_value += transition_pr;
|
||||||
|
|
||||||
debug.add_transition_info(prev_unbroken_timestamp, t, s, s_prime,
|
debug.add_transition_info(prev_unbroken_timestamp, t, s, s_prime,
|
||||||
|
@ -41,7 +41,8 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
|
|||||||
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
|
api_call = qi::lit('/') >> string[boost::bind(&HandlerT::setService, handler, ::_1)] >>
|
||||||
*(query) >> -(uturns);
|
*(query) >> -(uturns);
|
||||||
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
|
query = ('?') >> (+(zoom | output | jsonp | checksum | location | hint | timestamp | u | cmp |
|
||||||
language | instruction | geometry | alt_route | old_API | num_results));
|
language | instruction | geometry | alt_route | old_API | num_results |
|
||||||
|
matching_beta | gps_precision | classify));
|
||||||
|
|
||||||
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
|
zoom = (-qi::lit('&')) >> qi::lit('z') >> '=' >>
|
||||||
qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
qi::short_[boost::bind(&HandlerT::setZoomLevel, handler, ::_1)];
|
||||||
@ -64,6 +65,12 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
|
|||||||
stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
stringwithDot[boost::bind(&HandlerT::addHint, handler, ::_1)];
|
||||||
timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
|
timestamp = (-qi::lit('&')) >> qi::lit("t") >> '=' >>
|
||||||
qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
|
qi::uint_[boost::bind(&HandlerT::addTimestamp, handler, ::_1)];
|
||||||
|
matching_beta = (-qi::lit('&')) >> qi::lit("matching_beta") >> '=' >>
|
||||||
|
qi::short_[boost::bind(&HandlerT::setMatchingBeta, handler, ::_1)];
|
||||||
|
gps_precision = (-qi::lit('&')) >> qi::lit("gps_precision") >> '=' >>
|
||||||
|
qi::short_[boost::bind(&HandlerT::setGPSPrecision, handler, ::_1)];
|
||||||
|
classify = (-qi::lit('&')) >> qi::lit("classify") >> '=' >>
|
||||||
|
qi::bool_[boost::bind(&HandlerT::setClassify, handler, ::_1)];
|
||||||
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
|
u = (-qi::lit('&')) >> qi::lit("u") >> '=' >>
|
||||||
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
|
qi::bool_[boost::bind(&HandlerT::setUTurn, handler, ::_1)];
|
||||||
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
|
uturns = (-qi::lit('&')) >> qi::lit("uturns") >> '=' >>
|
||||||
@ -85,7 +92,7 @@ template <typename Iterator, class HandlerT> struct APIGrammar : qi::grammar<Ite
|
|||||||
|
|
||||||
qi::rule<Iterator> api_call, query;
|
qi::rule<Iterator> api_call, query;
|
||||||
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
|
qi::rule<Iterator, std::string()> service, zoom, output, string, jsonp, checksum, location,
|
||||||
hint, timestamp, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
|
hint, timestamp, matching_beta, gps_precision, classify, stringwithDot, stringwithPercent, language, instruction, geometry, cmp, alt_route, u,
|
||||||
uturns, old_API, num_results;
|
uturns, old_API, num_results;
|
||||||
|
|
||||||
HandlerT *handler;
|
HandlerT *handler;
|
||||||
|
Loading…
Reference in New Issue
Block a user