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 unsigned INVALID_STATE = std::numeric_limits<unsigned>::max();
 | 
			
		||||
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
 | 
			
		||||
@ -285,9 +285,7 @@ template <class DataFacadeT> class MapMatching final
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void initialize(const HiddenMarkovModel& model,
 | 
			
		||||
                        unsigned initial_timestamp,
 | 
			
		||||
                        const Matching::CandidateLists& candidates_list)
 | 
			
		||||
        void initialize(const Matching::CandidateLists& candidates_list)
 | 
			
		||||
        {
 | 
			
		||||
            // json logger not enabled
 | 
			
		||||
            if (!logger)
 | 
			
		||||
@ -304,16 +302,8 @@ template <class DataFacadeT> class MapMatching final
 | 
			
		||||
                    state.values["coordinate"] = osrm::json::make_array(
 | 
			
		||||
                        candidates_list[t][s].first.location.lat / 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["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]);
 | 
			
		||||
                    }
 | 
			
		||||
                    state.values["viterbi"] = osrm::json::clamp_float(Matching::IMPOSSIBLE_LOG_PROB);
 | 
			
		||||
                    state.values["pruned"] = 0u;
 | 
			
		||||
                    timestamps.values.push_back(state);
 | 
			
		||||
                }
 | 
			
		||||
                states.values.push_back(timestamps);
 | 
			
		||||
@ -350,18 +340,20 @@ template <class DataFacadeT> class MapMatching final
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void add_viterbi(const unsigned t,
 | 
			
		||||
                         const std::vector<double>& current_viterbi,
 | 
			
		||||
                         const std::vector<bool>& current_pruned)
 | 
			
		||||
        void set_viterbi(const std::vector<std::vector<double>>& viterbi,
 | 
			
		||||
                         const std::vector<std::vector<bool>>& pruned)
 | 
			
		||||
        {
 | 
			
		||||
            // json logger not enabled
 | 
			
		||||
            if (!logger)
 | 
			
		||||
                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]);
 | 
			
		||||
                osrm::json::get(*object, "states", t, s_prime, "pruned") = static_cast<unsigned>(current_pruned[s_prime]);
 | 
			
		||||
                for (auto s_prime = 0u; s_prime < viterbi[t].size(); ++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());
 | 
			
		||||
        debug.initialize(model, initial_timestamp, candidates_list);
 | 
			
		||||
        debug.initialize(candidates_list);
 | 
			
		||||
 | 
			
		||||
        unsigned breakage_begin = std::numeric_limits<unsigned>::max();
 | 
			
		||||
        std::vector<unsigned> split_points;
 | 
			
		||||
@ -424,7 +416,51 @@ template <class DataFacadeT> class MapMatching final
 | 
			
		||||
        prev_unbroken_timestamps.push_back(initial_timestamp);
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
            const auto &prev_viterbi = model.viterbi[prev_unbroken_timestamp];
 | 
			
		||||
            const auto &prev_pruned = model.pruned[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])
 | 
			
		||||
            {
 | 
			
		||||
                BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
 | 
			
		||||
 | 
			
		||||
                // save start of breakage -> we need this as split point
 | 
			
		||||
                if (t < breakage_begin)
 | 
			
		||||
                {
 | 
			
		||||
                    breakage_begin = t;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                BOOST_ASSERT(prev_unbroken_timestamps.size() > 0);
 | 
			
		||||
 | 
			
		||||
                // remove both ends of the breakage
 | 
			
		||||
                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
 | 
			
		||||
            {
 | 
			
		||||
@ -546,6 +542,8 @@ template <class DataFacadeT> class MapMatching final
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        debug.set_viterbi(model.viterbi, model.pruned);
 | 
			
		||||
 | 
			
		||||
        if (prev_unbroken_timestamps.size() > 0)
 | 
			
		||||
        {
 | 
			
		||||
            split_points.push_back(prev_unbroken_timestamps.back() + 1);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user