IoTで使うPython入門 Step4-Python3ソケット⑤DMM 34461A連続描画
連載の第3回でDMMの測定データの連続読み出し、第4回でグラフの描画を扱いました。ここでは、二つを合体させます。
- 連続読み出しは、止まることなく続ける。最大どのくらいまで変数にデータを保存できるかわからないが、読んだデータを変数dataに追加していく
- dataから値を読み出してグラフを書いていく。こちらもどんどんグラフを描いていく
つまり、二つのプログラムを独立して同時に走らせるようにしたいので、threadingライブラリを導入します。
●プログラム
データの読み出しは、
p2 = threading.Thread(target = dataAcquition)
グラフは、
p1 = threading.Thread(target = plotter)
の二つのスレッドを作ります。データの読み出しスレッドを先に起動し、少しデータが溜まったらグラフのスレッドを起動します。
plotter()とdataAcquition()の両方の関数で、global dataとして同じ変数を読み書きをしています。同時にアクセスが行われることが考えられますが、セマフォなどを使った調停はとっていません。plotter()は読み出しだけで、dataAcquition()はデータの追加だけなので、たまたまうまく動いているのかもしれません。
import socket import time from matplotlib.lines import Line2D import matplotlib.pyplot as plt import matplotlib.animation as animation import threading data = [] class Scope: def __init__(self, ax, maxt=10, dt=0.2): self.ax = ax self.dt = dt self.maxt = maxt self.tdata = [0] self.ydata = [2.49] self.line = Line2D(self.tdata, self.ydata) self.ax.add_line(self.line) self.ax.set_ylim(0, 3) self.ax.set_xlim(0, self.maxt) def update(self, i): global data lastt = self.tdata[-1] if lastt > self.tdata[0] + self.maxt: # reset the arrays #print('reset time(xscale)') self.tdata = [self.tdata[-1]] self.ydata = [self.ydata[-1]] self.ax.set_xlim(self.tdata[0], self.tdata[0] + self.maxt) self.ax.figure.canvas.draw() t = self.tdata[-1] + self.dt self.tdata.append(t) try: #print('read data length ', len(data)) self.ydata.append(data[i]) except: data = data #print('tdata ', self.tdata[i] , 'ydata ', self.ydata[i]) #print(data) self.line.set_data(self.tdata, self.ydata) return self.line, def plotter(): global data print(len(data), 'read\n-----') fig, ax = plt.subplots() scope = Scope(ax) ani = animation.FuncAnimation(fig, scope.update, interval=2, blit=True) plt.show() #w = animation.PillowWriter(fps=20) #ani.save('animation_test.gif', writer=w) def dataAcquition(): ipAddr = "K-34461A-16054.local" ports = 5025 global data message = '*RST;*CLS\n'\ 'CONF:VOLT:DC 10, MAX;\n'\ 'SENS:VOLT:DC:APER 20E-6;\n'\ 'VOLT:DC:NPLC MIN;\n'\ 'VOLT:DC:ZERO:AUTO OFF;\n'\ 'VOLT:DC:NULL:STAT OFF;\n'\ '\n'\ 'TRIG:SOURce IMMediate;\n'\ 'TRIG:COUNt INFinity;\n'\ 'TRIG:DEL 0;\n'\ 'FORMat ASCii;\n' with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect((ipAddr, ports)) s.send(message.encode()) s.send(b'*OPC?\n') while s.recv(2): # 1=ready s.send(b'INIT\n') print('init') break while 1: try: s.send(b'DATA:POIN?\n') cc = (str(s.recv(6))[3:-3]) print('new data is ', cc) m = 'R? ' + cc + '\n' s.send(m.encode()) s1 = str(s.recv(2))[3:4] # digit s2 = int(s.recv(int(s1))) # read data count time.sleep(0.1) # need wait s3 = str(s.recv(s2 + 1))[2:-3] # b' \n' deleted s4 = s3.split(',') f = [float(f) for f in s4] #print(f, '\ntotal ', len(f), 'read\n-----') data = data + f print(len(data), 'total\n-----') time.sleep(0.5) except KeyboardInterrupt: print('CTRL-C') break p1 = threading.Thread(target = plotter) p2 = threading.Thread(target = dataAcquition) p2.start() time.sleep(1) p1.start() print('\n-----start----- ')
グラフを保存する
w = animation.PillowWriter(fps=20) ani.save('animation_test.gif', writer=w) |
は、2画面記録しますが、以降の更新された画面をGIFファイルに書き込んでくれません。plt.show()は、ずっとデータを更新してグラフを描画します。しかし、データの読み取りのほうが早く、グラフの描画は1桁ぐらい遅いです。
Pythonが変数の消費するメモリがどこくらいまで許されるのかわかりませんが、いつかは、破たんしてプログラムは止まってしまうでしょう。
プログラムの中断は、CTRL-Sで画面の更新を止め、10秒以上経過後にCTRL-Cを押します。
実行例です。DMMの入力には、50Hzぐらいの発振器の出力をつないでいます。