如何实现高速、一致的采样?

Gar*_*ber 4 python

要考虑的应用类型是示波器或高速数据记录器。我有一个检索所需信息的函数,我只需要计算如何一遍又一遍地、非常快速且高精度地调用它。

time.sleep() 有限制,我不认为这是要走的路。

我已经研究了内置的事件调度程序,但我认为它不够精确并且不能完全满足我的需求。

对此的要求是:

  • 高速采样。10ms 是最多的要求。
  • 高精度间隔。在 10ms 时,10% 的误差是可以接受的 (±1ms)。
  • 相当低的 CPU 使用率,在 10 毫秒时可以接受一些负载,但对于 100 毫秒及以上的时间间隔,它应该小于 ~5%。我知道这是主观的,我想我的意思是占用 CPU 是不可接受的。
  • 理想情况下,定时器将以间隔时间初始化,然后在需要时启动。然后应以正确的间隔一遍又一遍地调用所需的函数,直到计时器停止。
  • 它只会(不是必须)只在 Windows 机器上运行。

是否有满足这些要求的现有库?我不想重新发明轮子,但如果必须的话,我可能会使用 Windows 多媒体计时器 (winmm.dll)。对此有何评论/建议?

Gar*_*ber 5

我知道我回答我自己的问题迟到了,但希望它会帮助某人。

我为 Windows Multimedia Timer 编写了一个包装器,纯粹是为了测试。它似乎运行良好,但代码没有经过全面测试,也没有优化。

mmtimer.py:

from ctypes import *
from ctypes.wintypes import UINT
from ctypes.wintypes import DWORD

timeproc = WINFUNCTYPE(None, c_uint, c_uint, DWORD, DWORD, DWORD)
timeSetEvent = windll.winmm.timeSetEvent
timeKillEvent = windll.winmm.timeKillEvent


class mmtimer:
    def Tick(self):
        self.tickFunc()

        if not self.periodic:
            self.stop()

    def CallBack(self, uID, uMsg, dwUser, dw1, dw2):
        if self.running:
            self.Tick()

    def __init__(self, interval, tickFunc, stopFunc=None, resolution=0, periodic=True):
        self.interval = UINT(interval)
        self.resolution = UINT(resolution)
        self.tickFunc = tickFunc
        self.stopFunc = stopFunc
        self.periodic = periodic
        self.id = None
        self.running = False
        self.calbckfn = timeproc(self.CallBack)

    def start(self, instant=False):
        if not self.running:
            self.running = True
            if instant:
                self.Tick()

            self.id = timeSetEvent(self.interval, self.resolution,
                                   self.calbckfn, c_ulong(0),
                                   c_uint(self.periodic))

    def stop(self):
        if self.running:
            timeKillEvent(self.id)
            self.running = False

            if self.stopFunc:
                self.stopFunc()
Run Code Online (Sandbox Code Playgroud)

定期测试代码:

from mmtimer import mmtimer
import time

def tick():
    print("{0:.2f}".format(time.clock() * 1000))

t1 = mmtimer(10, tick)
time.clock()
t1.start(True)
time.sleep(0.1)
t1.stop()
Run Code Online (Sandbox Code Playgroud)

以毫秒为单位的输出:

0.00
10.40
20.15
29.91
39.68
50.43
60.19
69.96
79.72
90.46
100.23
Run Code Online (Sandbox Code Playgroud)

一键测试代码:

from mmtimer import mmtimer
import time

def tick():
    print("{0:.2f}".format(time.clock() * 1000))

t1 = mmtimer(150, tick, periodic=False)
time.clock()
t1.start()
Run Code Online (Sandbox Code Playgroud)

以毫秒为单位的输出:

150.17
Run Code Online (Sandbox Code Playgroud)

从结果中可以看出,它非常准确。然而,这只是使用,time.clock()所以用一小撮盐把它们拿走。

在使用 10 毫秒定期计时器进行的长时间测试中,我的旧双代码 3GHz 机器上的 CPU 使用率约为 3% 或更少。机器似乎也在空闲时使用它,所以我想说额外的 CPU 使用率是最低的。