私は Python に比較的慣れていないので、大規模な多次元配列を回転させるための最適化されたコードを探しています。次のコードでは、16X600000 32 ビットの浮動小数点多次元配列があり、タイマーによると、クアッド コアの acer Windows 8 タブレットでコンテンツを回転させるのに約 30 ミリ秒かかります。配列の回転に必要な時間を短縮できる場合は、いくつかの Cython ルーチンまたは同様のものを使用することを検討していました。
最終的に、このコードは、VisPy パッケージに基づく高速データ プロット グラフの y 軸値を格納するために使用され、32 ビット float 配列が OpenGL ルーチンに渡されます。できれば1ms以下を実現したいです。
コメント、推奨事項、またはサンプル コードをいただければ幸いです。
import sys, timeit
from threading import Thread
from PyQt4 import QtGui
import numpy as np
m = 16 # Number of signals.
n = 600000 # Number of samples per signal.
y = 0.0 * np.random.randn(m, n).astype(np.float32)
Running = False
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('Start', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
global Running, thread, thrTest
if Running == True:
Running = False
self.button.setText('Start')
thrTest.isRunning = False
print ('stop')
else:
Running = True
self.button.setText('Stop')
thrTest = testThread()
thread = Thread(target=thrTest.run, daemon=True )
thread.start()
print ("Start")
class testThread(Thread):
def __init__(self):
self.isRunning = True
def run(self):
print('Test: Thread Started')
while self.isRunning == True:
start_time = timeit.default_timer()
y[:, :-1] = y[:, 1:]
elapsed = timeit.default_timer() - start_time
print ('Time (s)= ' + str(elapsed))
print('Test: Closed Thread')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
アップデート
私がやろうとしていることについて正確に混乱していると思うので、もう少し詳しく説明しようと思います.
最終的な目標は、信号値を表すグラフに線を引く、高速なリアルタイム データ ロギング デバイスを用意することです。複数のチャネルと、少なくとも 1 ミリ秒のサンプリング レートと、可能な限り多くの録音時間が存在します。この VisPy の例から始めました。新しいデータを配列に書き込み、それを OpenGL に送信する例のコードは、一番下のOn_Timer
関数にあります。このコードを少し変更して、OpenGL キャンバスを Qt gui に統合し、イーサネット ソケットを介して Arduino Mega からデータを取得するコードを追加しました。
現在、サンプリングレート約1ms、フレームレート約30Hz、記録時間約14秒で16ラインのリアルタイムグラフを作成できます。チャネル数または記録の長さをこれ以上増やそうとすると、イーサネット ポートから 1 ミリ秒で入ってくるデータの流れに追いつけないため、プログラムが動作を停止します。
y[:, :-1] = y[:, 1:]
これについて私が見つけることができる最大の原因は、ルーチンを使用してデータ バッファー シフトを完了するのにかかる時間です。もともと私は、誰かが同じことをより効率的な方法で行う方法を知っていることを期待して、この関数が時間を計っているベンチマーク コードを提出しました。この行の目的は、配列全体を 1 インデックス左にシフトし、次のコード行で右側の最初のスロットに新しいデータを書き込むことです。
以下に、変更したグラフ更新ルーチンを示します。最初にキューから新しいデータを取得して一時配列にアンパックし、次にメイン バッファー配列の内容をシフトし、最後に新しいデータをメイン配列の最後のスロットにコピーします。キューが空になると、OpenGL が表示を更新するように update 関数が呼び出されます。
def on_timer(self, event):
"""Add some data at the end of each signal (real-time signals)."""
k=1
s = struct.Struct('>16H')
AdrArray = 0.0 * np.random.randn(16,1).astype(np.float32)
if not q.qsize() == 0:
while q.qsize() > 0:
print (q.qsize())
print ('iin ' + str(datetime.datetime.now()))
AdrArray[:,0]= s.unpack_from(q.get(), offset=4)
y[:, :-1] = y[:, 1:]
y[:, -1:] = .002*AdrArray
print ('out ' + str(datetime.datetime.now()))
self.program['a_position'].set_data(y.ravel().astype(np.float32))
self.update()