使用Python获取数据

使用Python获取数据,python,user-interface,nidaqmx,Python,User Interface,Nidaqmx,我正在做一个项目,使用国家仪器委员会来进行数据采集。我有用于执行任务的功能性C代码,但我想使用Python,因此GUI编程不那么痛苦。在我的C代码中,我使用API调用setTimer,它定期引发WM_定时器事件。Tk循环中是否有类似的机制?我尝试使用以下代码 def DAQ(self): if self.do_DAQ: result = self.myDAQ.getData() currTime = time.time() - self.start_tim

我正在做一个项目,使用国家仪器委员会来进行数据采集。我有用于执行任务的功能性C代码,但我想使用Python,因此GUI编程不那么痛苦。在我的C代码中,我使用API调用setTimer,它定期引发WM_定时器事件。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事件吗?

我实际上使用PyDAQmx使用Python执行NIDAQmx。我们以20kHz的频率采集数据(通过在NI板上设置时钟计时器,并以10hz的频率将数据以2000个数据块的形式传输到一个文件中)

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


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

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

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()
将Tkinter作为tk导入
导入线程
随机输入
导入时间
从队列导入队列,为空
root=tk.tk()
time\u label=tk.label(根,文本='seconds')
volt\u label=tk.label(根,文本='volts')
时间标签包()
volt_标签包()
def DAQ(q):
尽管如此:
q、 put((time.time(),random.randrange(100)))
时间。睡眠(2)
def更新_数据(队列,根):
尝试:
timestamp,volts=queue.get_nowait()
除空外:
通过
其他:
time_label.config(文本=“{.1f}秒”。格式(时间戳))
volt_label.config(文本=“{.4f}volts.”格式(volts))
root.after(100,更新_数据,队列,根)
数据队列=队列()
线程(目标=DAQ,参数=(数据队列,)
t、 daemon=True
t、 开始()
更新数据(数据队列,根)
root.mainloop()

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

您可能需要修改此标题——问题实际上与数据采集无关,而是与TK事件循环的准确计时有关。您可能希望以自己喜欢的速率在单独的线程中进行数据采集,并让GUI每隔n个时钟点轮询一个队列以获取新数据。多亏了您和@ballsdotball。当我回到办公室时,我将进入多线程。对不起,太密集了。t.daemon=True做什么?@CarlHoutman
daemon
标志只意味着程序应该在只剩下非主线程时退出。这只是为了确保它不会挂起等待线程中无尽的while循环完成。根据代码的实现方式,可能需要也可能不需要。