Arduino Live Serial Plotting with a MatplotlibAnimation 变慢
Arduino Live Serial Plotting with a MatplotlibAnimation gets slow
我正在制作一个实时绘图仪来显示来自 Arduino 传感器的模拟变化。 Arduino 以 9600 的波特率向串口打印一个值。Python 代码如下所示:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial
import time
ser = serial.Serial("com3", 9600)
ser.readline()
optimal_frequency = 100
fig = plt.figure(figsize=(6, 6))
ax1 = fig.add_subplot(1, 1, 1)
# the following arrays must be initialized outside the loop
xar = []
yar = []
print(time.ctime())
def animate(i):
global b, xar, yar # otherwise a
for i in range(optimal_frequency):
a = str(ser.readline(), 'utf-8')
try:
b = float(a)
except ValueError:
ser.readline()
xar.append(str(time.time()))
yar.append(b)
ax1.clear()
ax1.plot(xar, yar)
ani = animation.FuncAnimation(fig, animate, interval=optimal_frequency)
plt.show()
A 在绘图中获得了不错的响应时间,但是当我绘制超过 20 分钟时,反应时间增加到大约 1 分钟。 IE。图表需要 1 分钟才能更新为新值。我也尝试过使用 PyQtGraph,但从一开始就延迟了。
除了超过 20 分钟的延迟外,我在情节中出现了一些过冲和下冲。
有什么帮助吗?
如评论中所述,您做错了两件事:
- 您不断将传入数据附加到数组,一段时间后这些数据会变得很大
- 您清除轴并在每次迭代时创建一个新的
ax.plot()
。
你想做的是:
在初始化函数中,创建一个空的 Line2D 对象
def init():
line, = ax.plot([], [], lw=2)
return line,
然后在您的更新函数 (animate()
) 中,您使用 line.set_data()
来更新您的点的坐标。但是,为了保持性能,您必须将数组的大小保持在合理的大小,因此当新数据进来时您将不得不删除旧数据
def animate(i):
(...)
xar.append(str(time.time()))
yar.append(b)
line.set_data(xar, yar)
return line,
查看一些教程like this one. There are also plenty of questions on SO that already answers your question. For instance, this answer 包含让您的代码正常工作所需的所有元素。
正如评论中提到的那样,由于数组很大,读取数组的速度自然会变慢。波特率为 9600 时,我在 xar 和 yar 变量中每秒获得大约 130 个串行读数和时间戳; 20 分钟后大小为 156000。将波特率降低到 2400 会将变量的长度减少到 36000,这可以很容易地重新绘制。
我正在制作一个实时绘图仪来显示来自 Arduino 传感器的模拟变化。 Arduino 以 9600 的波特率向串口打印一个值。Python 代码如下所示:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import serial
import time
ser = serial.Serial("com3", 9600)
ser.readline()
optimal_frequency = 100
fig = plt.figure(figsize=(6, 6))
ax1 = fig.add_subplot(1, 1, 1)
# the following arrays must be initialized outside the loop
xar = []
yar = []
print(time.ctime())
def animate(i):
global b, xar, yar # otherwise a
for i in range(optimal_frequency):
a = str(ser.readline(), 'utf-8')
try:
b = float(a)
except ValueError:
ser.readline()
xar.append(str(time.time()))
yar.append(b)
ax1.clear()
ax1.plot(xar, yar)
ani = animation.FuncAnimation(fig, animate, interval=optimal_frequency)
plt.show()
A 在绘图中获得了不错的响应时间,但是当我绘制超过 20 分钟时,反应时间增加到大约 1 分钟。 IE。图表需要 1 分钟才能更新为新值。我也尝试过使用 PyQtGraph,但从一开始就延迟了。
除了超过 20 分钟的延迟外,我在情节中出现了一些过冲和下冲。
有什么帮助吗?
如评论中所述,您做错了两件事:
- 您不断将传入数据附加到数组,一段时间后这些数据会变得很大
- 您清除轴并在每次迭代时创建一个新的
ax.plot()
。
你想做的是:
在初始化函数中,创建一个空的 Line2D 对象
def init():
line, = ax.plot([], [], lw=2)
return line,
然后在您的更新函数 (animate()
) 中,您使用 line.set_data()
来更新您的点的坐标。但是,为了保持性能,您必须将数组的大小保持在合理的大小,因此当新数据进来时您将不得不删除旧数据
def animate(i):
(...)
xar.append(str(time.time()))
yar.append(b)
line.set_data(xar, yar)
return line,
查看一些教程like this one. There are also plenty of questions on SO that already answers your question. For instance, this answer 包含让您的代码正常工作所需的所有元素。
正如评论中提到的那样,由于数组很大,读取数组的速度自然会变慢。波特率为 9600 时,我在 xar 和 yar 变量中每秒获得大约 130 个串行读数和时间戳; 20 分钟后大小为 156000。将波特率降低到 2400 会将变量的长度减少到 36000,这可以很容易地重新绘制。