The open source OpenXR runtime
at main 103 lines 3.9 kB view raw
1// Copyright 2022, Collabora, Ltd. 2// Copyright 2024, Jan Schmidt 3// SPDX-License-Identifier: BSL-1.0 4/*! 5 * @file 6 * @brief Helpers to estimate offsets between clocks 7 * @author Mateo de Mayo <mateo.demayo@collabora.com> 8 * @ingroup aux_math 9 */ 10 11#pragma once 12 13#include "xrt/xrt_defines.h" 14#include "util/u_time.h" 15 16#ifdef __cplusplus 17extern "C" { 18#endif 19 20/*! 21 * Helper to estimate the offset between two clocks using exponential smoothing. 22 * 23 * Given a sample from two timestamp domains A and B that should have been 24 * sampled as close as possible, together with an estimate of the offset between 25 * A clock and B clock (or zero), it applies a smoothing average on the 26 * estimated offset and returns @p a in B clock. 27 * 28 * This estimator can be used when clock observations are arriving with a low 29 * delay and small jitter, or when accuracy is less important (on the order of 30 * the jitter that is present). It is very computationally cheap. 31 * 32 * @param freq About how many times per second this function is called. Helps setting a good decay value. 33 * @param a Timestamp in clock A of the event 34 * @param b Timestamp in clock B of the event 35 * @param[in,out] inout_a2b Pointer to the current offset estimate from A to B, or 0 if unknown. 36 * Value pointed-to will be updated. 37 * @return timepoint_ns @p a in B clock 38 */ 39static inline timepoint_ns 40m_clock_offset_a2b(float freq, timepoint_ns a, timepoint_ns b, time_duration_ns *inout_a2b) 41{ 42 // This formulation of exponential filtering uses a fixed-precision integer for the 43 // alpha value and operates on the delta between the old and new a2b to avoid 44 // precision / overflow problems. 45 46 // Totally arbitrary way of computing alpha, if you have a better one, replace it 47 const time_duration_ns alpha = 1000 * (1.0 - 12.5 / freq); // Weight to put on accumulated a2b 48 time_duration_ns old_a2b = *inout_a2b; 49 time_duration_ns got_a2b = b - a; 50 time_duration_ns new_a2b; 51 if (old_a2b == 0) { // a2b has not been set yet 52 new_a2b = got_a2b; 53 } else { 54 new_a2b = ((old_a2b - got_a2b) * alpha) / 1000 + got_a2b; 55 } 56 *inout_a2b = new_a2b; 57 return a + new_a2b; 58} 59 60/*! 61 * Helper to estimate the offset between two clocks using a windowed 62 * minimum-skew estimation plus exponential smoothing. The algorithm 63 * tracks the smallest offset within the window, on the theory that 64 * minima represent samples with the lowest transmission delay and jitter. 65 * 66 * More computationally intensive than the simple m_clock_offset_a2b estimator, 67 * but can estimate a clock with accuracy in the microsecond range 68 * even in the presence of 10s of milliseconds of jitter. 69 * 70 * Based on the approach in Dominique Fober, Yann Orlarey, Stéphane Letz. 71 * Real Time Clock Skew Estimation over Network Delays. [Technical Report] GRAME. 2005. 72 * https://hal.science/hal-02158803/document 73 */ 74struct m_clock_windowed_skew_tracker; 75 76/*! 77 * Allocate a struct m_clock_windowed_skew_tracker with a 78 * window of @param window_samples samples. 79 */ 80struct m_clock_windowed_skew_tracker * 81m_clock_windowed_skew_tracker_alloc(const size_t window_samples); 82void 83m_clock_windowed_skew_tracker_reset(struct m_clock_windowed_skew_tracker *t); 84void 85m_clock_windowed_skew_tracker_destroy(struct m_clock_windowed_skew_tracker *t); 86 87void 88m_clock_windowed_skew_tracker_push(struct m_clock_windowed_skew_tracker *t, 89 const timepoint_ns local_ts, 90 const timepoint_ns remote_ts); 91 92bool 93m_clock_windowed_skew_tracker_to_local(struct m_clock_windowed_skew_tracker *t, 94 const timepoint_ns remote_ts, 95 timepoint_ns *local_ts); 96bool 97m_clock_windowed_skew_tracker_to_remote(struct m_clock_windowed_skew_tracker *t, 98 const timepoint_ns local_ts, 99 timepoint_ns *remote_ts); 100 101#ifdef __cplusplus 102} 103#endif