我正在尝试使用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/