3

我正在使用 National Instruments 板进行数据采集的项目。我有用于执行任务的功能 C 代码,但想使用 Python,因此 GUI 编程不那么痛苦。在我的 C 代码中,我使用 API 调用 setTimer,它定期引发 WM_TIMER 事件。Tk 循环中是否有类似的机制?我尝试使用以下代码。

def DAQ(self):
    if self.do_DAQ:
        result = self.myDAQ.getData()
        currTime = time.time() - self.start_time
        self.time_label.config(text="{:.1f} seconds".format(currTime))
        self.volt_label.config(text="{:.4f} volts".format(result))
        self.time_data[self.i] = currTime
        self.volt_data[self.i] = result
        self.i += 1
        self.after(1962, self.DAQ)

after() 中的神奇“1962”是通过反复试验确定的,以提供大约 2 秒的延迟,但时间片会根据队列中的其他内容而漂移。有没有办法让我的时间片更准确?具体来说,我可以强制 Tk 在队列中的其他事情之前执行我的 DAQ 事件吗?

4

2 回答 2

3

这是我在评论中所说的一个快速示例:

import Tkinter as tk
import threading
import random
import time
from Queue import Queue, Empty

root = tk.Tk()
time_label = tk.Label(root, text='<unknown> seconds')
volt_label = tk.Label(root, text='<unknown> volts')
time_label.pack()
volt_label.pack()

def DAQ(q):
    while True:
        q.put((time.time(), random.randrange(100)))
        time.sleep(2)

def update_data(queue, root):
    try:
        timestamp, volts = queue.get_nowait()
    except Empty:
        pass
    else:
        time_label.config(text='{:.1f} seconds'.format(timestamp))
        volt_label.config(text='{:.4f} volts'.format(volts))
    root.after(100, update_data, queue, root)

data_queue = Queue()
t = threading.Thread(target=DAQ, args=(data_queue,))
t.daemon = True
t.start()
update_data(data_queue, root)
root.mainloop()

显然,上面的 DAQ() 函数只是真实事物的替身。关键是,正如@ballsdotballs 在他们的回答中所建议的那样,您可以在 DAQ 线程中以您想要的任何速率进行采样,将值添加到队列中,然后以更合适的速率更新 GUI。

于 2012-12-18T00:13:37.333 回答
3

我实际上使用 PyDAQmx 用 Python 做 NIDAQmx。我们以 20kHz 的频率获取数据(通过在 NI 板上设置时钟定时器,并将数据以 10Hz 的 2000 块为单位流式传输到文件中)。

如果时间精度很重要,我强烈建议将您的 GUI 过程与数据采集过程分开。

如果您只想每 2 秒记录一次数据,您可以将 NIDAQ 上的采样时钟设置为 1000,缓冲区大小为 1000,并使用AutoRegisterEveryNSamplesEvent回调为每个其他缓冲区写入最后一个数据索引(应该每两秒)到一个文件或将其通过管道传输到您的 GUI 进程。这将确保您的 GUI 处理队列不会影响数据采样的精度。

于 2012-12-18T00:04:12.973 回答