Python中的while循环计时不准确 [英] Inaccurate while loop timing in Python

查看:83
本文介绍了Python中的while循环计时不准确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to log data at with a high sampling rate using a Raspberry Pi 3 B+. In order to achieve a fixed sampling rate, I am delaying the while loop, but I always get a sample rate that is a little less than I specify.

对于 2500 Hz,我得到 ~2450 Hz

For 2500 Hz I get ~2450 Hz

对于 5000 Hz,我得到 ~4800 Hz

For 5000 Hz I get ~4800 Hz

对于 10000 Hz,我得到 ~9300 Hz

For 10000 Hz I get ~9300 Hz

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

Here is the code that I use to delay the while loop:

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(),但没有任何区别.

I have also tried updating to Python 3.7 and used time.perf_counter_ns(), but it does not make a difference.

推荐答案

您看到的问题是因为您的代码在循环中每次开始时都在使用实时时间,因为它在一段时间内开始每个延迟 - 所以花费的时间由于 OS 多任务处理而导致的不定时代码和抖动累积,从而将总体周期缩短到您想要实现的目标以下.

The problem you are seeing is because your code is using the real time each time in the loop when it starts each delay for the period duration - and so time spent in untimed code and jitter due to OS multitasking accumulates, reducing the overall period below what you want to achieve.

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

To greatly increase the timing accuracy, use the fact that each loop "should" finish at the period (1/sample_rate) after it should have started - and maintain that start time as an absolute calculation rather than the real time, and wait until the period after that absolute start time, and then there is no drift in the timing.

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

I put your timing into timing_orig and my revised code using absolute times into timing_new - and results are below.

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,但如果您在循环中放入的代码比执行时间多,计时运行也会相应变慢.

Note I didn't use time.sleep() because it introduced too much jitter. Also, note that even though this minimal example shows very accurate timing even up to 100khz on my Windows laptop, if you put more code into the loop than there is time to execute, the timing will run correspondingly slow.

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

Apologies I used Python 2.7 which doesn't have the very convenient time.perf_counter() function - add an extra parameter timefun=time.perf_counter() to each of the calls to timing()

这篇关于Python中的while循环计时不准确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆