我正在尝试使用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(),但没有任何区别。

最佳答案

您看到的问题是,由于代码在周期内每次延迟开始时都在循环中使用实时时间-因此,由于OS多任务处理,在未定时代码和抖动上花费的时间会累积,从而将总周期减少到您想要实现。

要大大提高计时精度,请使用以下事实:每个循环应在应开始的时间段(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/

10-12 18:50