时间基础:UTC时间、系统时间、硬件时间、时间戳的本质
做多传感器融合,第一个绕不开的坎儿就是时间。
说实话,我早年做项目时,在这上面栽过不少跟头。两台设备明明同时采集数据,回放一看,时间轴对不上。你说气不气人?后来我才明白——时间这东西,看似简单,其实门道很深。
UTC时间:全球统一的“尺子”
先聊聊UTC。全称是Coordinated Universal Time,协调世界时。
说白了,它就是全世界通用的时间基准。不管你在北京、纽约还是南极,UTC时间都是一样的。我习惯把它想象成一把“国际标准尺”——各地的时间都是拿这把尺子量出来的。
关键点:UTC不依赖时区。北京时间是UTC+8,纽约时间是UTC-5。但UTC本身,永远不变。
我在项目中遇到过一个问题:两个传感器,一个设了北京时间,一个设了格林威治时间。结果数据对齐时差了8个小时。嗯,从那以后,我所有设备都强制用UTC记录原始时间,显示时再转换。
系统时间:操作系统里的“钟”
系统时间,就是你的Linux或Windows系统当前认为的时间。
它从1970年1月1日0点(UTC)开始计数,单位是秒。这个起点,我们叫它Unix纪元。你想想看,每次你调用time()函数,拿到的就是一个从那个时刻到现在的秒数。
// 获取系统时间示例
#include <time.h>
time_t now = time(NULL);
printf("当前系统时间戳: %ld\n", now);
// 输出类似: 当前系统时间戳: 1698765432
系统时间有个特点——它可以被修改。用户手动调时间、NTP同步、甚至程序里用settimeofday()都能改。所以,它不太可靠。
注意:系统时间可能发生跳变。如果NTP发现系统时间偏差太大,会直接“咔”一下调回来。你的时间戳可能突然倒退或前进几秒。这在传感器融合里是灾难。
硬件时间:主板上的“守夜人”
硬件时间,也叫RTC时间。它由主板上的纽扣电池供电,独立运行。
哪怕你关机、拔电源,它还在走。我经常把它比作一个“守夜人”——不管系统怎么折腾,它默默记着时间。
在嵌入式设备里,硬件时间通常是一个独立的RTC芯片。比如DS3231、PCF8563这些。它们精度不错,但也会漂移。我测过一块DS3231,常温下一天漂个1-2秒,温度变化大时更明显。
| 时间类型 | 存储位置 | 断电保持 | 可修改性 | 典型精度 |
|---|---|---|---|---|
| UTC时间 | 标准定义 | — | — | 原子钟级 |
| 系统时间 | 内存/内核 | 否 | 容易 | 微秒级 |
| 硬件时间 | RTC芯片 | 是 | 较难 | 秒级 |
系统启动时,会从硬件时间读取初始值。之后,系统时间靠CPU定时器维持。所以你会发现:刚开机时系统时间和硬件时间一致,跑着跑着就有偏差了。
时间戳的本质:一个数字而已
时间戳是什么?说白了,就是一个数字。
它代表从某个固定起点到现在的时长。最常见的是Unix时间戳——从1970-01-01 00:00:00 UTC到现在的秒数。
// 时间戳示例
// 1698765432 这个数字代表什么?
// 它代表:从1970年1月1日0点,到2023年10月31日12点37分12秒,一共过去了1698765432秒
时间戳的好处是:它是一个单调递增的数字。比较两个时间戳,谁大谁就晚。做差值,就知道间隔多久。非常适合计算机处理。
但要注意精度问题。我见过有人用float存时间戳,结果精度不够,两个相邻事件的时间戳居然相等。你想想看,这数据还能用吗?
我的建议:时间戳尽量用64位整数存储。微秒级精度的话,用uint64_t,单位选微秒。这样到公元2920年都不会溢出。
它们之间的关系
画个图就清楚了。我习惯用这个逻辑来理解:
你看这个图就明白了。UTC在最上面,是基准。系统时间从硬件时间初始化,然后独立运行。时间戳则是所有时间的数字表达形式。
做传感器融合时,我个人的习惯是:
- 所有传感器原始数据,统一用UTC时间戳记录
- 系统内部处理,用单调递增的本地时间戳
- 硬件时间只做备份和启动初始化
避坑指南
我曾经踩过一个坑:用gettimeofday()获取时间戳做同步,结果NTP一跳,时间戳往回走了几百毫秒。两个传感器的数据直接乱套了。
后来我改用clock_gettime(CLOCK_MONOTONIC, ...)。这个时钟是单调递增的,不受系统时间调整影响。虽然它不直接对应UTC,但做相对时间同步足够了。
重要提醒:绝对不要用系统时间做高精度同步。用单调时钟(CLOCK_MONOTONIC)做相对时间,用PTP或GPS的PPS信号做绝对时间对齐。
嗯,时间基础就聊这么多。记住一句话:UTC是尺子,系统时间是显示器,硬件时间是备份,时间戳是数字。搞清楚了这些,后面做同步采样才不至于翻车。
小技巧:调试时,我习惯在日志里同时打印系统时间和单调时钟。一旦发现两者差值异常增大,就知道NTP又跳了。这招帮我抓过不少bug。