时间戳比定时器更短的同步定时器
sync timer with shorter timestamp than timer
Hy 我有两个设备 A 和 B 都使用 64 位定时器。一个刻度等于 1ns。我想同步两个计时器的漂移。我已经知道 A 和 B 之间的延迟。通常我会经常将 A 的当前时间发送到 B。在 B 中,我会添加传播延迟并将此值用作同步 B 的比较值。在我的情况下,我只能发送每 100ms 降低定时器的 32 位。我试图用 A 的部分简单地替换 B 的下半部分,但只要没有 32 位溢出,这个工作就可以了。有没有办法检测这种溢出?溢出示例(定时器短路):
定时器 B: 0x00FF
定时器A:0x010A
=> 0x0A 到 B
替换导致
计时器 B 0x000A 而不是计时器 B 0x010A。
所以我需要检测 A 中是否已经发生了 B 中没有发生的溢出。
下溢示例(定时器短路):
定时器 B: 0x0205
定时器A:0x01F6
=> 0xF6 => 计时器 B:0x02F6 而不是 0x01F6
在这种情况下,计时器 B 比计时器 A 快。
这是我用来找出 timera
的最接近可能值的方法,给定 timerb
,message
中 timera
的 32 个低位,以及delay
:
中的预期传播延迟
#include <stdint.h>
int64_t expected_timera(const int64_t timerb,
const uint32_t message,
const uint32_t delay)
{
const int64_t timer1 = (timerb / INT64_C(4294967296)) * INT64_C(4294967296)
+ (int64_t)message + (int64_t)delay;
const int64_t timer0 = timer1 - INT64_C(4294967296);
const int64_t timer2 = timer1 + INT64_C(4294967296);
const uint64_t delta0 = timerb - timer0;
const uint64_t delta1 = (timer1 > timerb) ? timer1 - timerb : timerb - timer1;
const uint64_t delta2 = timer2 - timerb;
if (delta0 < delta1)
return (delta0 < delta2) ? timer0 : timer2;
else
return (delta1 <= delta2) ? timer1 : timer2;
}
就个人而言,我还会使用线性调整从实际计时器 B 计算 timerb
:
static volatile int64_t real_timer_b; /* Actual timer b */
static int64_t timerb_real; /* real_timer_b at last sync time */
static int64_t timerb_offset; /* timera at last sync time */
static int32_t timerb_scale; /* Q30 scale factor (0,2) */
static inline int64_t timerb(void)
{
return ((int64_t)(int32_t)(real_timer_b - timerb_real) * (int64_t)timerb_scale) / INT64_C(1073741824) + timerb_offset;
}
有 timerb_real = 0
、timerb_offset = 0
和 timerb_scale = 1073741824
、timerb() == real_timer_b
。
当timera > timerb()
时,需要增加timerb_scale
。当timera < timerb()
时,需要减少timerb_scale
。您不想每 100 毫秒计算一次精确值,因为传播延迟中的抖动会直接影响 timerb()
;你想在几(几十)秒内慢慢调整它。作为奖励,您可以保持 timerb()
单调,而不会突然向前或向后跳跃。
Network Time Protocol 实现做的事情非常相似,您可能会在那里找到进一步的实现帮助。
Hy 我有两个设备 A 和 B 都使用 64 位定时器。一个刻度等于 1ns。我想同步两个计时器的漂移。我已经知道 A 和 B 之间的延迟。通常我会经常将 A 的当前时间发送到 B。在 B 中,我会添加传播延迟并将此值用作同步 B 的比较值。在我的情况下,我只能发送每 100ms 降低定时器的 32 位。我试图用 A 的部分简单地替换 B 的下半部分,但只要没有 32 位溢出,这个工作就可以了。有没有办法检测这种溢出?溢出示例(定时器短路):
定时器 B: 0x00FF
定时器A:0x010A
=> 0x0A 到 B 替换导致 计时器 B 0x000A 而不是计时器 B 0x010A。
所以我需要检测 A 中是否已经发生了 B 中没有发生的溢出。
下溢示例(定时器短路):
定时器 B: 0x0205
定时器A:0x01F6
=> 0xF6 => 计时器 B:0x02F6 而不是 0x01F6
在这种情况下,计时器 B 比计时器 A 快。
这是我用来找出 timera
的最接近可能值的方法,给定 timerb
,message
中 timera
的 32 个低位,以及delay
:
#include <stdint.h>
int64_t expected_timera(const int64_t timerb,
const uint32_t message,
const uint32_t delay)
{
const int64_t timer1 = (timerb / INT64_C(4294967296)) * INT64_C(4294967296)
+ (int64_t)message + (int64_t)delay;
const int64_t timer0 = timer1 - INT64_C(4294967296);
const int64_t timer2 = timer1 + INT64_C(4294967296);
const uint64_t delta0 = timerb - timer0;
const uint64_t delta1 = (timer1 > timerb) ? timer1 - timerb : timerb - timer1;
const uint64_t delta2 = timer2 - timerb;
if (delta0 < delta1)
return (delta0 < delta2) ? timer0 : timer2;
else
return (delta1 <= delta2) ? timer1 : timer2;
}
就个人而言,我还会使用线性调整从实际计时器 B 计算 timerb
:
static volatile int64_t real_timer_b; /* Actual timer b */
static int64_t timerb_real; /* real_timer_b at last sync time */
static int64_t timerb_offset; /* timera at last sync time */
static int32_t timerb_scale; /* Q30 scale factor (0,2) */
static inline int64_t timerb(void)
{
return ((int64_t)(int32_t)(real_timer_b - timerb_real) * (int64_t)timerb_scale) / INT64_C(1073741824) + timerb_offset;
}
有 timerb_real = 0
、timerb_offset = 0
和 timerb_scale = 1073741824
、timerb() == real_timer_b
。
当timera > timerb()
时,需要增加timerb_scale
。当timera < timerb()
时,需要减少timerb_scale
。您不想每 100 毫秒计算一次精确值,因为传播延迟中的抖动会直接影响 timerb()
;你想在几(几十)秒内慢慢调整它。作为奖励,您可以保持 timerb()
单调,而不会突然向前或向后跳跃。
Network Time Protocol 实现做的事情非常相似,您可能会在那里找到进一步的实现帮助。