所以这是交易,我有一个模块通过串口以9600波特发送数据,我正在使用matplotlib实时绘制数据。我写了这段代码
#! python
############ import section ###################
import serial
import struct
import numpy as np
import matplotlib.pyplot as plt
###############################################
############ Serial Configuration #############
com = serial.Serial(14,9600)
print ("Successfully opened " + com.portstr)
###############################################
def get_new_values():
s = com.read(20)
raw_data = struct.unpack('!BBBBBBBBBBBBBBBBBBBB', s)
j = 0;
norm_data = []
for i in range(0,20,2):
big_byte = raw_data[i+1]+(raw_data[i]*256)
norm_data.append(big_byte)
j = j+1
return norm_data
x = range(0,10,1)
y = get_new_values()
plt.ion()
line, = plt.plot(x,y)
while(1):
a = get_new_values()
line.set_ydata(a)
plt.draw()
com.close()
print ("Port Closed Successfully")
我得到20个字节,然后产生10个大字节(2个字节的数据在传输时被分成两个1字节值)。但我只是注意到我没有从中得到实时值。如果重要的话,我在Windows 7家庭基本。
有什么理由发生这种情况?
修改
此外,每当我点击情节时,它就会挂起。
答案 0 :(得分:1)
我知道下面的代码对于您的简单问题来说似乎很长且过于复杂,但手动优化通常是更多的代码和更多潜在的错误。这就是为什么过早优化几乎总是一个错误。
在__init__
中,它设置绘图,设置轴,画布,线条(它以屏幕上绘制的线条开始)和动画前背景的参考。另外__init__
注册回调以处理调整大小和关闭。调整窗口大小时,需要on_resize
回调来更新背景(用于blit)。 on_close
回调使用锁来更新运行状态。我没有用这个来消除所有竞争条件,但是这可以防止因尝试对终止的Tk应用程序进行blit而导致_tkinter.TclError
。我只用Tk测试过,而且只用一台机器测试过。 YMMV,我愿意接受建议。
在run
方法中,我添加了对canvas.flush_events()
的调用。如果您尝试拖动窗口并调整其大小,这应该使绘图窗口不会挂起。此方法中的while循环调用self.get_new_values()
来设置绘图中的数据。然后使用配置的方法更新绘图。如果self.blit
为真,则使用canvas.blit
,否则使用pyplot.draw
。
变量spf
(每帧样本数)控制在帧中绘制的样本数。您可以在get_new_values
的实现中使用它来确定要读取的字节数(例如,每个样本2个字节的2 * self.spf
)。我将默认设置为120,如果您的数据速率为每秒600个样本,则为每秒5帧。您必须找到最大化吞吐量与图表中时间分辨率的最佳点,同时还要跟上传入的数据。
将数据读入NumPy数组而不是使用Python列表可能会加快处理速度。此外,它还可让您轻松访问用于下采样和分析信号的工具。您可以直接从字节字符串读入NumPy数组,但请确保您获得正确的结束:
>>> data = b'\x01\xff' #big endian 256 + 255 = 511
>>> np.little_endian #my machine is little endian
True
>>> y = np.fromstring(data, dtype=np.uint16); y #so this is wrong
array([65281], dtype=uint16)
>>> if np.little_endian: y = y.byteswap()
>>> y #fixed
array([511], dtype=uint16)
代码:
from __future__ import division
from matplotlib import pyplot
import threading
class Main(object):
def __init__(self, samples_per_frame=120, blit=True):
self.blit = blit
self.spf = samples_per_frame
pyplot.ion()
self.ax = pyplot.subplot(111)
self.line, = self.ax.plot(range(self.spf), [-1] * self.spf)
self.ax.axis([0, self.spf, 0, 65536])
pyplot.draw()
self.canvas = self.ax.figure.canvas
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
self.canvas.mpl_connect('resize_event', self.on_resize)
self.canvas.mpl_connect('close_event', self.on_close)
self.lock = threading.Lock()
self.run()
def get_new_values(self):
import time
import random
#simulate receiving data at 9600 bps (no cntrl/crc)
time.sleep(2 * self.spf * 8 / 9600)
y = [random.randrange(65536) for i in range(self.spf)]
self.line.set_ydata(y)
def on_resize(self, event):
self.line.set_ydata([-1] * self.spf)
pyplot.draw()
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
def on_close(self, event):
with self.lock:
self.running = False
def run(self):
with self.lock:
self.running = True
while self.running:
self.canvas.flush_events()
with self.lock:
self.get_new_values()
if self.running:
if self.blit:
#blit for a higher frame rate
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
else:
#versus a regular draw
pyplot.draw()
if __name__ == '__main__':
Main(samples_per_frame=120, blit=True)