【问题标题】:Building a Timeline from Lossy Time Stamps从有损时间戳构建时间线
【发布时间】:2021-10-15 21:52:42
【问题描述】:

我正在使用 Velodyne 的一款名为 VLP-16 的产品(该手册可从他们的网站获得详细信息),并且我正在尝试为其发送的数据构建时间表。它发送的数据通过 UDP 传输(UDP 数据包可能出现乱序),每个数据包都带有 32 位微秒值的时间戳。微秒值与 UTC 时间同步。这意味着时间戳将在 UTC 时间的每个小时后回绕回零。由于 UDP 数据包在技术上可能出现乱序,因此很难知道一个数据包可能属于什么时间。

这里有一段代码可以概括地描述手头的问题:

struct LidarPacket
{
  uint32_t microsecond;

  /* other data */
};

struct LidarTimelineEntry
{
  uint32_t hour;
  LidarPacket packet;
};

using LidarTimeline = std::vector<LidarTimelineEntry>;

void InsertAndSort(LidarTimeline& timeline, uint32_t hour, const LidarPacket&);

void OnLidarPacket(LidarTimeline &timeline, LidarPacket& newestPacket)
{
  /* Where to insert 'newestPacket'? */
}

最简单的方法是假设数据包按顺序排列。

void OnLidarPacket(LidarTimeline &timeline, LidarPacket& newestPacket)
{
  if (timeline.empty()) {
    timeline.emplace_back(LidarTimelineEntry{0, newestPacket});
    return;
  }

  auto &lastEntry = timeline.back();

  if (newestPacket.microsecond < lastEntry.packet.microsecond) {
    InsertAndSort(timeline, lastEntry.hour + 1, newestPacket);
  } else {
    InsertAndSort(timeline, lastEntry.hour, newestPacket);
  }
}

即使一个数据包出现故障,这种方法也会失败。一种更稳健的方法是还检查是否在接近一小时结束时发生换行。

bool NearEndOfHour(const LidarPacket& lidarPacket)
{
  const uint32_t packetDuration = 1344; // <- approximate duration of one packet.

  const uint32_t oneHour = 3600000000; // <- one hour in microseconds

  return (lidarPacket.microsecond < packetDuration) || (lidarPacket.microsecond > (oneHour - packetDuration));
}

void OnLidarPacket(LidarTimeline &timeline, LidarPacket& newestPacket)
{
  if (timeline.empty()) {
    timeline.emplace_back(LidarTimelineEntry{0, newestPacket});
    return;
  }

  auto &lastEntry = timeline.back();

  if ((newestPacket.microsecond < lastEntry.packet.microsecond) && NearEndOfHour(lastEntry.packet)) {
    InsertAndSort(timeline, lastEntry.hour + 1, newestPacket);
  } else {
    InsertAndSort(timeline, lastEntry.hour, newestPacket);
  }
}

但很难说这是否真的会削减它。根据来自 UDP 流的微秒标记数据构建多小时时间线的最佳方法是什么?

不必用 C++ 回答

【问题讨论】:

  • 围绕您的程序当前 UTC 时间定义一个时间窗口,例如前后 10 分钟。丢弃未出现在窗口中的数据包。将确实出现在窗口中的数据包分配给正确的时间。时间窗口定义了 UDP 数据包可以合理延迟的最长时间,并且还允许发送方和接收方之间的时钟漂移。您可以根据 UDP 流的可靠性使用滑动和/或可变大小的窗口来改进这一点。
  • @RichardCritten 我喜欢这种方法。一个问题,不过。 UTC 时间窗口必须以秒和微秒的形式定义(否则,接近小时边界的时间窗口会溢出)。您如何将微秒时间戳与完整的 sec/usec 时间戳进行比较?我能想到的唯一方法是捕获接收数据包的时间,并将secs附加到数据包的usec

标签: c++ time udp lidar


【解决方案1】:

我最终采用的方法如下:

  1. 如果时间线为空,将时间点添加到时间线hour=0
  2. 否则,创建三个可能的时间点。一个使用最后一个时间点的小时,一个使用最后一个时间点的前一小时,最后一个小时后的最后一个小时。
  3. 计算所有这些时间点与上一个时间点的绝对差值(使用 64 位整数)。
  4. 选择与上一个时间点的绝对差值最小的小时。

这种方法通过了以下测试:

uint32_t inputTimes[] = { 0, 750, 250 };
// gets sorted to:
uint32_t outputTimes[] = { 0, 250, 750 };
int32_t outputHours[] = { 0, 0, 0 };
uint32_t inputTimes[] = { 1500, oneHour - 500, 250 };
// gets sorted to:
uint32_t outputTimes[] = { oneHour - 500, 250, 1500 };
int32_t outputHours[] = { -1, 0, 0 };
uint32_t inputTimes[] = { oneHour - 500, 1500, 250 };
// gets sorted to:
uint32_t outputTimes[] = { oneHour - 500, 250, 1500 };
int32_t outputHours[] = { 0, 1, 1 };

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 2016-06-16
    • 2015-08-02
    • 1970-01-01
    • 2013-10-04
    • 1970-01-01
    相关资源
    最近更新 更多