python - Python 中的 while 循环计时不准确

标签 python raspberry-pi

我正在尝试使用 Raspberry Pi 3 B+ 以高采样率记录数据。为了达到固定的采样率,我延迟了 while 循环,但我总是得到比我指定的少一点的采样率。

对于 2500 Hz,我得到 ~2450 Hz

对于 5000 Hz,我得到 ~4800 Hz

对于 10000 Hz,我得到 ~9300 Hz

这是我用来延迟 while 循环的代码:

import time

count=0
while True:
    sample_rate=5000

    time_start=time.perf_counter()
    count+=1
    while (time.perf_counter()-time_start) < (1/sample_rate):
        pass

    if count == sample_rate:
        print(1/(time.perf_counter()-time_start))
        count=0

我也尝试更新到 Python 3.7 并使用了 time.perf_counter_ns(),但它并没有什么不同。

最佳答案

您看到的问题是因为您的代码在循环中每次启动周期持续时间的每个延迟时都使用实时时间 - 因此在未计时代码中花费的时间和由于操作系统多任务处理引起的抖动累积,减少了整体低于您想要达到的目标。

为了大大提高计时精度,使用每个循环“应该”在它应该开始之后的周期 (1/sample_rate) 结束的事实 - 并将该开始时间保持为绝对计算而不是实时,并且等到绝对开始时间之后的那段时间,然后时间就没有漂移了。

我将您的时间放入 timing_orig 并将我使用绝对时间的修改后的代码放入 timing_new - 结果如下。

import time

def timing_orig(ratehz,timefun=time.clock):
    count=0
    while True:
        sample_rate=ratehz

        time_start=timefun()
        count+=1
        while (timefun()-time_start) < (1.0/sample_rate):
            pass

        if count == ratehz:
            break

def timing_new(ratehz,timefun=time.clock):
    count=0
    delta = (1.0/ratehz)
    # record the start of the sequence of timed periods
    time_start=timefun()
    while True:
        count+=1
        # this period ends delta from "now" (now is the time_start PLUS  a number of deltas)
        time_next = time_start+delta
        # wait until the end time has passed
        while timefun()<time_next:
            pass
        # calculate the idealised "now" as delta from the start of this period
        time_start = time_next
        if count == ratehz:
            break

def timing(functotime,ratehz,ntimes,timefun=time.clock):
    starttime = timefun()
    for n in range(int(ntimes)):
        functotime(ratehz,timefun)
    endtime = timefun()
#   print endtime-starttime
    return ratehz*ntimes/(endtime-starttime)

if __name__=='__main__':
    print "new 5000",timing(timing_new,5000.0,10.0)
    print "old 5000",timing(timing_orig,5000.0,10.0)
    print "new 10000",timing(timing_new,10000.0,10.0)
    print "old 10000",timing(timing_orig,10000.0,10.0)
    print "new 50000",timing(timing_new,50000.0,10.0)
    print "old 50000",timing(timing_orig,50000.0,10.0)
    print "new 100000",timing(timing_new,100000.0,10.0)
    print "old 100000",timing(timing_orig,100000.0,10.0)

结果:

new 5000 4999.96331002
old 5000 4991.73952992
new 10000 9999.92662005
old 10000 9956.9314274
new 50000 49999.6477761
old 50000 49591.6104893
new 100000 99999.2172809
old 100000 94841.227219

注意我没有使用 time.sleep() 因为它引入了太多的抖动。另请注意,即使这个最小的示例在我的 Windows 笔记本电脑上显示了非常准确的计时,甚至高达 100khz,如果您将更多代码放入循环中而不是执行时间,计时将相应地运行缓慢。

抱歉,我使用的 Python 2.7 没有非常方便的 time.perf_counter() 函数 - 为每个对 timing() 的调用添加一个额外的参数 timefun=time.perf_counter()

关于python - Python 中的 while 循环计时不准确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50471895/

相关文章:

linux - 将Raspberry Pi中的权限文件夹更改为R权限

python - Raspberry Pi 3 上的 OpenCV 多 USB 摄像头

python - 有关 AppEngine 处理程序正则表达式的帮助?

用于名称标准化的 Python RegEx

python - 抓取和监控 +1000 个网站

ffmpeg - 具有 ffmpeg 和低带宽的 rtl_fm 流

python - 如何判断 Pandas 数据框中的列是否属于日期时间类型?如何判断列是否为数字?

python - 如何渲染 svg 文件的*部分*?

python - 如何在 Raspbian Buster 上使用 headless Firefox 设置 Selenium

compiler-errors - 如何在64位RaspberryPi中编译32位ARM?