簡體   English   中英

什么是繪制實時串行數據的最有效的Python IPC機制?

[英]What is most efficient Python IPC mechanism for plotting real-time serial data?

從串行端口讀取數據到繪制該數據的單獨進程的最快Python機制是什么?

我正在實時繪制從串口讀取的eeg數據。 串行端口讀取和數據包拆包代碼工作正常,因為如果我讀取並存儲數據,然后再繪制存儲的數據,則看起來不錯。 像這樣:

注意:設備會生成測試正弦波進行調試

在此處輸入圖片說明

我正在使用pyQtGraph進行繪圖。 不能以與讀取串行數據相同的過程來更新繪圖,因為串行read()調用之間的微小延遲會導致串行緩沖區溢出並導致錯誤的校驗和。 pyQtGraph提供了在單獨的進程上呈現圖的規定,這很好,但是瓶頸似乎在進程間通信中。 我嘗試了Pipe()和Queue()的各種配置,所有這些配置都會導致圖形更新緩慢,閃爍。 到目前為止,從串行端口向圖形獲取新值的最流暢,最一致的方法似乎是通過共享內存,如下所示:

from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
from multiprocessing import Process, Array, Value, Pipe
from serial_interface import EEG64Board
from collections import deque

def serialLoop(arr):
    eeg = EEG64Board(port='/dev/ttyACM0')
    eeg.openSerial() 
    eeg.sendTest('1')        #Tells the eeg device to start sending data
    while True:
        data = eeg.readEEG() #Returns an array of the 8 latest values, one per channel
        if data != False:    #Returns False if bad checksum
            val.value = data[7] 

val = Value('d',0.0)
q = deque([],500)

def graphLoop():
    global val,q
    plt = pg.plot(q)
    while True:
        q.append(val.value)
        plt.plot(q,clear=True)
        QtGui.QApplication.processEvents()

serial_proc = Process(target=serialLoop, args=(val,), name='serial_proc')
serial_proc.start()

try:
    while True:
        graphLoop()
except KeyboardInterrupt:
    print('interrupted')

上面的代碼通過簡單地提取serialLoop記錄的最新值並將其附加到雙端隊列來執行實時繪圖。 盡管該圖平滑更新,但它僅捕獲了四分之一的值,如結果圖所示:

在此處輸入圖片說明

那么,您將建議哪種多進程或線程結構,然后在它們之間使用哪種形式的IPC?

更新:

我每秒接收2,000個樣本。 我在想,如果我以100 fps更新顯示並每幀添加20個新樣本,那我應該很好。 實現此目的的最佳Python多線程機制是什么?

這可能不是最有效的,但是下面的代碼可在一幅圖中達到100 fps,或在八幅圖中達到20 fps。 這個想法很簡單:共享一個數組,索引和鎖。 當具有鎖定時,串行填充數組並遞增索引,繪圖過程會定期在鎖定下定期從數組和遞減索引中獲取所有新值。

from pyqtgraph.Qt import QtGui
import pyqtgraph as pg
from multiprocessing import Process, Array, Value, Lock
from serial_interface import EEG64Board
from collections import deque

def serialLoop(arr,idx,lock):
    eeg = EEG64Board(port='/dev/ttyACM0')
    eeg.openSerial() 
    eeg.sendTest('1')        #Tells the eeg device to start sending data
    while True:
        data = eeg.readEEG() #Returns an array of the 8 latest values, one per channel
        if data != False:    #Returns False if bad checksum
            lock.acquire()
            for i in range(8):
                arr[i][idx.value] = data[i] 
            idx.value += 1
            lock.release()
    eeg.sendTest('2') 

arr = [Array('d',range(1024)) for i in range(8)]
idx = Value('i', 0)
q = [deque([],500) for i in range(8)]
iq = deque([],500)
lock = Lock()

lastUpdate = pg.ptime.time()
avgFps = 0.0

def graphLoop():
    global val,q,lock,arr,iq, lastUpdate, avgFps
    win = pg.GraphicsWindow()
    plt = list()
    for i in range(8):
        plt += [win.addPlot(row=(i+1), col=0, colspan=3)]
    #iplt = pg.plot(iq)
    counter = 0
    while True:
        lock.acquire()
        #time.sleep(.01)
        for i in range(idx.value):
            for j in range(8):
                q[j].append(arr[j][i])        
        idx.value = 0
        lock.release()
        for i in range(8):
            plt[i].plot(q[i],clear=True)
        QtGui.QApplication.processEvents()
        counter += 1

        now = pg.ptime.time()
        fps = 1.0 / (now - lastUpdate)
        lastUpdate = now
        avgFps = avgFps * 0.8 + fps * 0.2

serial_proc = Process(target=serialLoop, args=(arr,idx,lock), name='serial_proc')
serial_proc.start()

graphLoop()

serial_proc.terminate()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM