You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派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, &current_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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:39:07