2012-12-17 108 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的處理隊列不會影響您的數據採樣的精度。