/* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* class to correct an offboard timestamp in microseconds into a local timestamp, removing timing jitter caused by the transport. It takes the offboard_usec timestamp which is a timestamp provided in a protocol from a remote device, and the time of arrival of the message in local microseconds. It returns an improved estimate of the time that the message was generated on the remote system in the local time domain The algorithm assumes two things: 1) the data did not come from the future in our local time-domain 2) the data is not older than max_lag_ms in our local time-domain It works by estimating the transport lag by looking for the incoming packet that had the least lag, and converging on the offset that is associated with that lag */ #include #include "JitterCorrection.h" // constructor JitterCorrection::JitterCorrection(uint16_t _max_lag_ms, uint16_t _convergence_loops) : max_lag_ms(_max_lag_ms), convergence_loops(_convergence_loops) {} /* correct an offboard timestamp in microseconds into a local timestamp, removing timing jitter caused by the transport. Return a value in microseconds since boot in the local time domain */ uint64_t JitterCorrection::correct_offboard_timestamp_usec(uint64_t offboard_usec, uint64_t local_usec) { int64_t diff_us = int64_t(local_usec) - int64_t(offboard_usec); if (!initialised || diff_us < link_offset_usec) { // this message arrived from the remote system with a // timestamp that would imply the message was from the // future. We know that isn't possible, so we adjust down the // correction value link_offset_usec = diff_us; initialised = true; } int64_t estimate_us = offboard_usec + link_offset_usec; if (estimate_us + (max_lag_ms*1000U) < int64_t(local_usec)) { // this implies the message came from too far in the past. clamp the lag estimate // to assume the message had maximum lag estimate_us = local_usec - (max_lag_ms*1000U); link_offset_usec = estimate_us - offboard_usec; } if (min_sample_counter == 0) { min_sample_us = diff_us; } min_sample_counter++; if (diff_us < min_sample_us) { min_sample_us = diff_us; } if (min_sample_counter == convergence_loops) { // we have the requested number of samples of the transport // lag for convergence. To account for long term clock drift // we set the diff we will use in future to this value link_offset_usec = min_sample_us; min_sample_counter = 0; } return uint64_t(estimate_us); } /* correct an offboard timestamp in microseconds into a local timestamp, removing timing jitter caused by the transport. Return a value in milliseconds since boot in the local time domain */ uint32_t JitterCorrection::correct_offboard_timestamp_msec(uint32_t offboard_ms, uint32_t local_ms) { return correct_offboard_timestamp_usec(offboard_ms*1000ULL, local_ms*1000ULL) / 1000ULL; }