まず、私はPythonが初めてです。私は長年の MatLab ユーザー (コンピューター科学者ではなくエンジニア) であり、Python、NumPy、SciPy などを自分のワークフローに取り込もうとするプロセスを開始しています。ですから、素晴らしいプログラミング言語とは何かについての私の明らかな無知を許してください!
最初の試みとして、開発中のセンサーと対話するアプリケーションを構築することにしました。センサーの解像度はマイクロ秒 (500 マイクロ秒ごとに 512 個の高エネルギー「ピクセル」と 512 個の低エネルギー「ピクセル」からのデータ) ですが、I/O はブロックされます。デバイスを継続的にポーリングするので、GUI の応答性を維持するためにスレッド化が重要であることはわかっています (GUI は最終的に別のデバイスとのシリアル通信も統合し、センサー データで動作する画像処理サブルーチンを備えています)。センサーからのこれらの「リアルタイム」データをプロットするために、MatPlotLib のスレッド化されたインスタンスを作成しました。センサーと個別に通信するモジュールを作成し、Python でそれを行う方法を知っていることを確認しましたが、ここでは単純に「シミュレーション」から始めます。低エネルギーの「ピクセル」に対しては 8 から 12 の間の 512 の乱数を生成し、高エネルギーの「ピクセル」に対しては 90 から 110 の間の 512 の乱数を生成することにより、データの それがスレッド化されたものです。ここの多くの例から作業して、ブリッティングを使用して MatPlotLib で十分に高速な画面更新を取得することも学びました-しかし、問題は、使用しない限り、スレッド化されたプロセスを20ミリ秒スリープ状態にするtime.sleep(0.02)
、GUI が応答しません。これは、MatPlotLib からのインタラクティブな X、Y データ ポイント フィードバックが機能せず、「停止」ボタンを使用してプロセスを中断できないため、確認できます。これより長いtime.sleep(0.02)
と、GUI の操作がさらにスムーズになりますが、「データ レート」が犠牲になります。これより遅いtime.sleep(0.02)
と、GUI が応答しなくなります。なぜだかよくわかりません。代わりにGUIqwtを使用しようとしましたが、MatPlotLibを放棄する前にここで質問すると思いました。それが問題であるかどうかさえわからないからです。スレッドを 20 ミリ秒スリープ状態にすると、センサー アレイから少なくとも 40 行の潜在的なデータが失われるのではないかと心配しています (40 行 * 500us/行 = 20 ミリ秒)。
現在のコードは次のとおりです。
import time, random, sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class ApplicationWindow(QMainWindow):
def __init__(self, parent = None):
QMainWindow.__init__(self, parent)
self.thread = Worker()
self.create_main_frame()
self.create_status_bar()
self.connect(self.thread, SIGNAL("finished()"), self.update_UI)
self.connect(self.thread, SIGNAL("terminated()"), self.update_UI)
self.connect(self.startButton, SIGNAL("clicked()"), self.start_acquisition)
self.connect(self.stopButton, SIGNAL("clicked()"), self.stop_acquisition)
self.thread.pixel_list.connect(self.update_figure)
def create_main_frame(self):
self.main_frame = QWidget()
self.dpi = 100
self.width = 10
self.height = 8
self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
self.axes = self.fig.add_subplot(111)
self.axes.axis((0,512,0,120))
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.main_frame)
self.canvas.updateGeometry()
self.canvas.draw()
self.background = None
self.lE_line, = self.axes.plot(range(512), [0 for i in xrange(512)], animated=True)
self.hE_line, = self.axes.plot(range(512), [0 for i in xrange(512)], animated=True)
self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
self.startButton = QPushButton(self.tr("&Start"))
self.stopButton = QPushButton(self.tr("&Stop"))
layout = QGridLayout()
layout.addWidget(self.canvas, 0, 0)
layout.addWidget(self.mpl_toolbar, 1, 0)
layout.addWidget(self.startButton, 2, 0)
layout.addWidget(self.stopButton, 2, 1)
self.main_frame.setLayout(layout)
self.setCentralWidget(self.main_frame)
self.setWindowTitle(self.tr("XRTdev Interface"))
def create_status_bar(self):
self.status_text = QLabel("I am a status bar. I need a status to show!")
self.statusBar().addWidget(self.status_text, 1)
def start_acquisition(self):
self.thread.exiting = False
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.thread.render()
def stop_acquisition(self):
self.thread.exiting = True
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()
def update_figure(self, lE, hE):
if self.background == None:
self.background = self.canvas.copy_from_bbox(self.axes.bbox)
self.canvas.restore_region(self.background)
self.lE_line.set_ydata(lE)
self.hE_line.set_ydata(hE)
self.axes.draw_artist(self.lE_line)
self.axes.draw_artist(self.hE_line)
self.canvas.blit(self.axes.bbox)
def update_UI(self):
self.startButton.setEnabled(True)
self.stopButton.setEnabled(False)
self.cleanup_UI()
def cleanup_UI(self):
self.background = None
self.axes.clear()
self.canvas.draw()
class Worker(QThread):
pixel_list = pyqtSignal(list, list)
def __init__(self, parent = None):
QThread.__init__(self, parent)
self.exiting = False
def __del__(self):
self.exiting = True
self.wait()
def render(self):
self.start()
def run(self):
# simulate I/O
n = random.randrange(100,200)
while not self.exiting and n > 0:
lE = [random.randrange(5,16) for i in xrange(512)]
hE = [random.randrange(80,121) for i in xrange(512)]
self.pixel_list.emit(lE, hE)
time.sleep(0.02)
n -= 1
def main():
app = QApplication(sys.argv)
form = ApplicationWindow()
form.show()
app.exec_()
if __name__ == "__main__":
main()
おそらく私の問題は、MatPlotLib や PyQT4 でもなく、スレッドの実装方法にあるのでしょう。私が指摘したように、私はこれに慣れておらず、学んでいます。そして、GUIqwt がこれらの問題のいずれかに対処するかどうかさえわかりませんが、GUI での「リアルタイム」プロットに MatPlotLib よりも高速なものを使用するための多くの推奨事項をここで見たことは知っています。これについて助けてくれてありがとう!