gps时间同步 —— 纳秒级高精度
需求:ubuntu系统,写个c++代码。实现实时收毫秒数,定时检查所收毫秒数与当前时间系统差,若超过2秒,则将当前所收到的毫秒数设置为系统时间。
可参考的代码:
double seconds = pva->gps_week * SECONDS_PER_WEEK + pva->gps_seconds
详细说明:
收一个毫秒数,这个毫秒数是收一个从1980年开始到现在的一个周数,加从本周日到现在的秒数。
写一个函数嵌套到已有的大代码里,转换成当前时间,然后设置为系统时间。
每隔一段时间进行检查,检查的方式是将收到的毫秒数与当前系统时间进行对比,如果差得比较多,就执行更新系统时间。
需要做的是:
-
保存最近的GPS时间:每次接收到新的GPS时间时,保存最新的GPS周数和秒数。
-
定期检查并调整系统时间:可以在这个文件中加入一个定时任务或者循环,定期检查保存的GPS时间和系统时间的差异,如果差异超过阈值(比如2秒),则调用相应的系统调用或命令来更新系统时间。
由于老代码
通常位于更复杂的项目中,你可能需要考虑以下几点:
- 线程安全:如果
老代码
是多线程的,确保任何新加入的代码也遵循相同的线程安全规则。 - 性能影响:频繁地检查和更新系统时间可能会影响程序的性能,尤其是如果更新系统时间的操作较为耗时的话。
- 错误处理:考虑到网络延迟或其他因素,GPS时间可能偶尔会出现异常值,需要有适当的错误处理机制。
-
#include <iostream> #include <chrono> #include <ctime> #include <thread> #include <signal.h> #include <sys/time.h> struct GPS_Time { uint16_t gps_week; uint32_t gps_millisecs; }; // 接收GPS时间 void receive_gps_time(GPS_Time& pva) { pva.gps_week = 2000; // 测试用的定值 pva.gps_millisecs = 123456; // 测试用的定值 } // 将GPS时间转换为UTC时间,并保留毫秒级精度 struct timespec gps_to_utc(const GPS_Time& pva) { const std::time_t gps_epoch = 315964800; std::time_t gps_time = gps_epoch + static_cast<std::time_t>(pva.gps_week * 604800); long gps_time_millisecs = static_cast<long>(pva.gps_millisecs); struct timespec ts; ts.tv_sec = gps_time + gps_time_millisecs / 1000; ts.tv_nsec = (gps_time_millisecs % 1000) * 1000000; return ts; } // 直接用clock_settime函数,设置系统时间,注意需要root权限 void set_system_time(const struct timespec& ts) { if (clock_settime(CLOCK_REALTIME, &ts) == -1) { perror("clock_settime"); } } // 检查并更新系统时间 void check_and_set_system_time() { GPS_Time pva; receive_gps_time(pva); struct timespec utc_time = gps_to_utc(pva); std::time_t current_time = std::time(nullptr); // 获取当前时间的毫秒部分 struct timespec current_timespec; clock_gettime(CLOCK_REALTIME, ¤t_timespec); long current_millisecs = current_timespec.tv_nsec / 1000000 + current_timespec.tv_sec * 1000L; // 将UTC时间转换为毫秒 long utc_millisecs = utc_time.tv_nsec / 1000000 + utc_time.tv_sec * 1000; if (std::abs(utc_millisecs - current_millisecs) > 2000) { std::cout << "Time difference is more than 2 seconds, setting system time." << std::endl; set_system_time(utc_time); } } // 退出处理 bool should_exit = false; void signal_handler(int signal) { should_exit = true; } int main() { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); while (!should_exit) { check_and_set_system_time(); std::this_thread::sleep_for(std::chrono::seconds(60)); // 每分钟检查一次 } return 0; }
附录1:不能用的方案
方案:新建一个gpstime.txt里存储着时间,其信息格式是2024-7-15 15:40:00,写一个名为update_time.sh的脚本,用来做时间同步:功能是每隔5秒就去gpstime.txt里获取信息,然后更新系统时间
原因:延迟性
附录2:GPS时间同步 和 ntp时间同步对比
问题:从gps获得毫秒级时间,同步到系统来做时间同步 和 ntp设置上位机ip来做时间同步,哪个比较靠谱?
同步系统时间的方式各有优劣,这主要取决于你的应用场景、可用资源以及对时间精确度的需求。下面是两种方法的一些考量:
1. 从GPS获取毫秒级时间进行同步
优点:
- 高精度: GPS提供了高度精确的时间信息,通常误差在几十纳秒到几微秒之间,非常适合需要高时间精度的应用场景,如卫星通信、金融交易系统等。
- 自主性: 不依赖网络连接,适用于野外作业、移动平台等网络不稳定或不可用的环境。
- 稳定性: GPS作为外部独立时钟源,相比依赖网络的时间同步服务,更不容易受网络延迟、拥塞等因素影响。
缺点:
- 硬件需求: 需要额外的GPS接收模块,增加了设备成本和安装复杂度。
- 系统集成: 需要在软件层面实现GPS信号接收和时间转换逻辑,增加了软件开发的工作量。
2. 使用NTP设置上位机IP做时间同步
优点:
- 易于部署: 大多数操作系统都内置了NTP客户端,配置简单,仅需指定NTP服务器地址即可。
- 成本低: 不需要额外硬件设备,只要网络连通即可。
- 广泛支持: NTP服务器遍布全球,容易找到可靠的时钟源,且适合大规模网络内的时间同步。
缺点:
- 精度限制: NTP在互联网上的典型精度约为毫秒级,虽然对于许多应用已足够,但对于高精度需求可能不够。
- 依赖网络: 网络状况直接影响同步效果,如延迟、丢包都会降低同步精度。
- 安全风险: 开放的网络接口可能面临安全攻击。
结论
选择哪种方式取决于你的具体需求:
- 如果你的应用场景对时间精度有极高要求,且可以接受额外的硬件成本和开发工作,直接从GPS获取时间并同步可能是更可靠的选择。
- 对于大多数通用场景,尤其是那些对成本敏感、不直接接触GPS信号或对时间精度要求不高(毫秒级足够)的情况,使用NTP服务进行时间同步会是更简便、经济的选择。