【发布时间】: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。