树莓派3上用C实现实时数值积分,clock()计时偏差问题求助
问题根源分析
你遇到的核心问题是对clock()函数的用途理解有误——clock()统计的是你的进程实际占用CPU的时间,而不是墙上时钟(实际流逝的时间)。
当你的代码执行文件读写这类I/O操作时,进程会进入等待状态(比如等待磁盘响应、内存页加载),这段时间CPU会被调度给其他进程,clock()不会统计这段等待时间。所以你累加的elapsed_time其实只是你的代码在CPU上跑的总时间,自然会比实际流逝的时间少,而且偏差比例完全取决于你的进程等待I/O的时间占比:文件操作越多,等待时间越长,偏差就越大;修改无关代码可能改变了CPU执行和I/O等待的时间比例,所以偏差比例会波动。
解决方案:使用单调墙上时钟计时
对于实时动态系统(比如你的反馈控制器),你需要统计实际流逝的时间,推荐用Linux系统的clock_gettime()函数,搭配CLOCK_MONOTONIC时钟类型——这是一个从系统启动开始单调递增的时钟,不会受系统时间调整(比如NTP同步)的影响,精度能达到纳秒级,完全满足实时计算的需求。
代码示例替换
首先引入头文件:
#include <time.h>
初始化部分:
// 初始化单调时钟的起始时间 struct timespec prev_ts; clock_gettime(CLOCK_MONOTONIC, &prev_ts); static double elapsed_time = 0.0;
循环中的计时逻辑:
while(1) { struct timespec current_ts; clock_gettime(CLOCK_MONOTONIC, ¤t_ts); // 计算时间步长dt:秒数差 + 纳秒转秒 double dt = (current_ts.tv_sec - prev_ts.tv_sec) + (double)(current_ts.tv_nsec - prev_ts.tv_nsec) / 1e9; // 累加总流逝时间 elapsed_time += dt; printf("elapsed_time : %lf\n", elapsed_time); // 更新上一次的时间戳 prev_ts = current_ts; // 你的业务逻辑:反馈控制计算、文件读写等 // do something... }
编译注意事项
在树莓派上编译时,部分旧版本的GCC可能需要链接实时库,编译命令加上-lrt参数:
gcc your_code.c -o your_program -lrt
不过新版本的Linux系统中,clock_gettime()已经集成到标准C库中,可能不需要额外链接。
额外说明
- 如果你需要更高的实时性,还可以考虑
CLOCK_MONOTONIC_RAW(绕过内核时间调整,精度更高),但CLOCK_MONOTONIC已经足够满足大多数实时控制场景。 - 避免使用
gettimeofday(),它的精度是微秒级,而且可能受系统时间修改影响,不适合实时系统的时间间隔测量。
内容的提问来源于stack exchange,提问作者FaresGargouri
相关产品推荐
相关产品推荐

