Split trace if timestamp delta is over threshold
Even when matching is not broken we split the trace, if the sampling frequency goes below 2 samples/minute.
This commit is contained in:
parent
d8d46e0f3e
commit
0d879ed290
@ -63,7 +63,7 @@ constexpr static const double IMPOSSIBLE_LOG_PROB = -std::numeric_limits<double>
|
|||||||
constexpr static const double MINIMAL_LOG_PROB = -std::numeric_limits<double>::max();
|
constexpr static const double MINIMAL_LOG_PROB = -std::numeric_limits<double>::max();
|
||||||
constexpr static const unsigned INVALID_STATE = std::numeric_limits<unsigned>::max();
|
constexpr static const unsigned INVALID_STATE = std::numeric_limits<unsigned>::max();
|
||||||
constexpr static const unsigned MAX_BROKEN_STATES = 6;
|
constexpr static const unsigned MAX_BROKEN_STATES = 6;
|
||||||
constexpr static const unsigned MAX_BROKEN_TIME = 180;
|
constexpr static const unsigned MAX_BROKEN_TIME = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements a hidden markov model map matching algorithm
|
// implements a hidden markov model map matching algorithm
|
||||||
@ -285,9 +285,7 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void initialize(const HiddenMarkovModel& model,
|
void initialize(const Matching::CandidateLists& candidates_list)
|
||||||
unsigned initial_timestamp,
|
|
||||||
const Matching::CandidateLists& candidates_list)
|
|
||||||
{
|
{
|
||||||
// json logger not enabled
|
// json logger not enabled
|
||||||
if (!logger)
|
if (!logger)
|
||||||
@ -304,16 +302,8 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
state.values["coordinate"] = osrm::json::make_array(
|
state.values["coordinate"] = osrm::json::make_array(
|
||||||
candidates_list[t][s].first.location.lat / COORDINATE_PRECISION,
|
candidates_list[t][s].first.location.lat / COORDINATE_PRECISION,
|
||||||
candidates_list[t][s].first.location.lon / COORDINATE_PRECISION);
|
candidates_list[t][s].first.location.lon / COORDINATE_PRECISION);
|
||||||
if (t < initial_timestamp)
|
|
||||||
{
|
|
||||||
state.values["viterbi"] = osrm::json::clamp_float(Matching::IMPOSSIBLE_LOG_PROB);
|
state.values["viterbi"] = osrm::json::clamp_float(Matching::IMPOSSIBLE_LOG_PROB);
|
||||||
state.values["pruned"] = 0u;
|
state.values["pruned"] = 0u;
|
||||||
}
|
|
||||||
else if (t == initial_timestamp)
|
|
||||||
{
|
|
||||||
state.values["viterbi"] = osrm::json::clamp_float(model.viterbi[t][s]);
|
|
||||||
state.values["pruned"] = static_cast<unsigned>(model.pruned[t][s]);
|
|
||||||
}
|
|
||||||
timestamps.values.push_back(state);
|
timestamps.values.push_back(state);
|
||||||
}
|
}
|
||||||
states.values.push_back(timestamps);
|
states.values.push_back(timestamps);
|
||||||
@ -350,18 +340,20 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_viterbi(const unsigned t,
|
void set_viterbi(const std::vector<std::vector<double>>& viterbi,
|
||||||
const std::vector<double>& current_viterbi,
|
const std::vector<std::vector<bool>>& pruned)
|
||||||
const std::vector<bool>& current_pruned)
|
|
||||||
{
|
{
|
||||||
// json logger not enabled
|
// json logger not enabled
|
||||||
if (!logger)
|
if (!logger)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto s_prime = 0u; s_prime < current_viterbi.size(); ++s_prime)
|
for (auto t = 0u; t < viterbi.size(); t++)
|
||||||
{
|
{
|
||||||
osrm::json::get(*object, "states", t, s_prime, "viterbi") = osrm::json::clamp_float(current_viterbi[s_prime]);
|
for (auto s_prime = 0u; s_prime < viterbi[t].size(); ++s_prime)
|
||||||
osrm::json::get(*object, "states", t, s_prime, "pruned") = static_cast<unsigned>(current_pruned[s_prime]);
|
{
|
||||||
|
osrm::json::get(*object, "states", t, s_prime, "viterbi") = osrm::json::clamp_float(viterbi[t][s_prime]);
|
||||||
|
osrm::json::get(*object, "states", t, s_prime, "pruned") = static_cast<unsigned>(pruned[t][s_prime]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -415,7 +407,7 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
}
|
}
|
||||||
|
|
||||||
DebugInfo debug(osrm::json::Logger::get());
|
DebugInfo debug(osrm::json::Logger::get());
|
||||||
debug.initialize(model, initial_timestamp, candidates_list);
|
debug.initialize(candidates_list);
|
||||||
|
|
||||||
unsigned breakage_begin = std::numeric_limits<unsigned>::max();
|
unsigned breakage_begin = std::numeric_limits<unsigned>::max();
|
||||||
std::vector<unsigned> split_points;
|
std::vector<unsigned> split_points;
|
||||||
@ -424,7 +416,51 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
prev_unbroken_timestamps.push_back(initial_timestamp);
|
prev_unbroken_timestamps.push_back(initial_timestamp);
|
||||||
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
for (auto t = initial_timestamp + 1; t < candidates_list.size(); ++t)
|
||||||
{
|
{
|
||||||
|
// breakage recover has removed all previous good points
|
||||||
|
bool trace_split = prev_unbroken_timestamps.size() < 1;
|
||||||
|
|
||||||
|
// use temporal information if available to determine a split
|
||||||
|
if (trace_timestamps.size() > 0)
|
||||||
|
{
|
||||||
|
trace_split =
|
||||||
|
trace_split ||
|
||||||
|
(trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
|
||||||
|
Matching::MAX_BROKEN_TIME);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace_split = trace_split || (t - prev_unbroken_timestamps.back() >
|
||||||
|
Matching::MAX_BROKEN_STATES);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trace_split)
|
||||||
|
{
|
||||||
|
unsigned split_index = t;
|
||||||
|
if (breakage_begin != std::numeric_limits<unsigned>::max())
|
||||||
|
{
|
||||||
|
split_index = breakage_begin;
|
||||||
|
breakage_begin = std::numeric_limits<unsigned>::max();
|
||||||
|
}
|
||||||
|
split_points.push_back(split_index);
|
||||||
|
|
||||||
|
// note: this preserves everything before split_index
|
||||||
|
model.clear(split_index);
|
||||||
|
unsigned new_start = model.initialize(split_index);
|
||||||
|
// no new start was found -> stop viterbi calculation
|
||||||
|
if (new_start == Matching::INVALID_STATE)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev_unbroken_timestamps.clear();
|
||||||
|
prev_unbroken_timestamps.push_back(new_start);
|
||||||
|
// Important: We potentially go back here!
|
||||||
|
// However since t > new_start >= breakge_begin
|
||||||
|
// we can only reset trace_coordindates.size() times.
|
||||||
|
t = new_start+1;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned prev_unbroken_timestamp = prev_unbroken_timestamps.back();
|
unsigned prev_unbroken_timestamp = prev_unbroken_timestamps.back();
|
||||||
|
|
||||||
const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
|
const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
|
||||||
const auto &prev_pruned = model.pruned[prev_unbroken_timestamp];
|
const auto &prev_pruned = model.pruned[prev_unbroken_timestamp];
|
||||||
const auto &prev_unbroken_timestamps_list = candidates_list[prev_unbroken_timestamp];
|
const auto &prev_unbroken_timestamps_list = candidates_list[prev_unbroken_timestamp];
|
||||||
@ -487,58 +523,18 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
debug.add_viterbi(t, current_viterbi, current_pruned);
|
|
||||||
|
|
||||||
if (model.breakage[t])
|
if (model.breakage[t])
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
|
|
||||||
|
|
||||||
// save start of breakage -> we need this as split point
|
// save start of breakage -> we need this as split point
|
||||||
if (t < breakage_begin)
|
if (t < breakage_begin)
|
||||||
{
|
{
|
||||||
breakage_begin = t;
|
breakage_begin = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
|
||||||
|
|
||||||
// remove both ends of the breakage
|
// remove both ends of the breakage
|
||||||
prev_unbroken_timestamps.pop_back();
|
prev_unbroken_timestamps.pop_back();
|
||||||
|
|
||||||
bool trace_split = prev_unbroken_timestamps.size() < 1;
|
|
||||||
|
|
||||||
// use temporal information to determine a split if available
|
|
||||||
if (trace_timestamps.size() > 0)
|
|
||||||
{
|
|
||||||
trace_split =
|
|
||||||
trace_split ||
|
|
||||||
(trace_timestamps[t] - trace_timestamps[prev_unbroken_timestamps.back()] >
|
|
||||||
Matching::MAX_BROKEN_TIME);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
trace_split = trace_split || (t - prev_unbroken_timestamps.back() >
|
|
||||||
Matching::MAX_BROKEN_STATES);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we reached the beginning of the trace and it is still broken
|
|
||||||
// -> split the trace here
|
|
||||||
if (trace_split)
|
|
||||||
{
|
|
||||||
split_points.push_back(breakage_begin);
|
|
||||||
// note: this preserves everything before breakage_begin
|
|
||||||
model.clear(breakage_begin);
|
|
||||||
unsigned new_start = model.initialize(breakage_begin);
|
|
||||||
// no new start was found -> stop viterbi calculation
|
|
||||||
if (new_start == Matching::INVALID_STATE)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
prev_unbroken_timestamps.clear();
|
|
||||||
prev_unbroken_timestamps.push_back(new_start);
|
|
||||||
// Important: We potentially go back here!
|
|
||||||
// However since t+1 > new_start >= breakge_begin
|
|
||||||
// we can only reset trace_coordindates.size() times.
|
|
||||||
t = new_start;
|
|
||||||
breakage_begin = std::numeric_limits<unsigned>::max();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -546,6 +542,8 @@ template <class DataFacadeT> class MapMatching final
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug.set_viterbi(model.viterbi, model.pruned);
|
||||||
|
|
||||||
if (prev_unbroken_timestamps.size() > 0)
|
if (prev_unbroken_timestamps.size() > 0)
|
||||||
{
|
{
|
||||||
split_points.push_back(prev_unbroken_timestamps.back() + 1);
|
split_points.push_back(prev_unbroken_timestamps.back() + 1);
|
||||||
|
Loading…
Reference in New Issue
Block a user