2012-12-17 54 views
3

我正在使用National Instruments主板进行数据采集。我有功能C代码来完成任务,但想使用Python,所以GUI编程不那么痛苦。在我的C代码中,我使用API​​调用setTimer,它定期提出一个WM_TIMER事件。 Tk循环中是否有类似的机制?我尝试使用下面的代码。使用Python进行数据采集

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) 

在神奇的“1962年”后()被反复试验来确定给予约2秒的延迟,但时间片漂移取决于还有什么是在队列中。有什么办法可以做到这一点,所以我的时间片更精确?具体而言,我可以强制Tk在队列中的其他事情之前执行我的DAQ事件吗?

+1

您可能想要修改这个标题 - 这个问题实际上并不是真的与数据采集有关,而是像TK事件循环的准确计时那样。您可能希望以您喜欢的速率在单独的线程中进行数据采集,并让您的GUI每隔n个时钟轮询一次队列以获取新数据。 – Iguananaut

回答

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() 

显然,上述数据采集()函数只是一个替身真实的东西。关键是,正如@ballsdotballs在他们的回答中所建议的那样,您可以在DAQ线程中以任意比例进行采样,将值添加到队列中,然后以更合适的速率更新GUI。

+0

感谢你和@ballsdotballs。当我回到办公室时,我会进入多线程。对不起,如此密集。 t.daemon = True会做什么? –

+0

@CarlHoutman'daemon'标志仅仅意味着当只剩下非主线程时程序应该退出。这只是为了确保它不会等待线程中无尽的while循环完成。根据您的代码的实现方式,可能需要也可能不需要。 – Iguananaut

3

我实际上用Python使用PyDAQmx来完成NIDAQmx。我们以20kHz的频率采集数据(通过在NI板上设置时钟定时器,并以10hz的大块数据流传输数据)。

如果时间精度很重要,我强烈建议将您的GUI过程从数据采集过程中分离出来。

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