使用 MatplotlibAnimation 进行 Arduino Live Serial Plotting 变慢

Posted

技术标签:

【中文标题】使用 MatplotlibAnimation 进行 Arduino Live Serial Plotting 变慢【英文标题】:Arduino Live Serial Plotting with a MatplotlibAnimation gets slow 【发布时间】:2017-05-04 08:07:51 【问题描述】:

我正在制作一个实时绘图仪来显示来自 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()

在情节中得到一个好的响应时间,但是当我绘制超过 20 分钟时,反应时间增加到大约 1 分钟。 IE。用新值更新图表需要 1 分钟。我也尝试过使用 PyQtGraph,但这从一开始就被延迟了。

除了超过 20 分钟的延迟之外,我在情节中遇到了一些过冲和下冲。

有什么帮助吗?

【问题讨论】:

我认为问题在于 xaryar 变量在一段时间后变得巨大。您可以尝试使用列表推导并改为执行列表的动态读取。 20 分钟后,您最好停止绘图,因为超过 1000 万个连接点的绘图将变得完全不可读。 @Jalo 谢谢。我看到变量太大了。问题是我需要再次重新绘制所有值,因为我每次都在清除绘图以免使其内存过载。我会降低采样频率:-) 您尝试管理的数据太多,无法在每次迭代时动态绘制所有历史数据。对于更简单的方法,我会将每次迭代时接收到的数据存储在一个文件中以供进一步分析,同时仅绘制最后 N 次迭代。 【参考方案1】:

如 cmets 中所述,您做错了两件事:

您不断将传入的数据附加到您的数组中,一段时间后这些数据会变得很大 您清除轴并在每次迭代时创建一个新的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。还有很多关于 SO 的问题已经回答了你的问题。例如,this answer 包含使代码正常运行所需的所有元素。

【讨论】:

【参考方案2】:

正如 cmets 所提到的,由于它们的大小,从数组中读取自然会变慢。波特率为 9600 时,我在 xaryar 变量中每秒获得大约 130 个串行读数和时间戳; 20 分钟后得到 156000 的大小。将波特率降低到 2400 会将变量的长度降低到 36000,并且可以很容易地重新绘制。

【讨论】:

以上是关于使用 MatplotlibAnimation 进行 Arduino Live Serial Plotting 变慢的主要内容,如果未能解决你的问题,请参考以下文章

Matplotlib animation.FuncAnimation() 动画错过第一帧?

Tkinter 回调异常:matplotlib 动画

matplotlib animation.save 不生成视频

可视化篇:流式数据监控(python)

使用 Crypto++ 进行 RSA 编码并使用 c# RSACryptoServiceProvider 进行解码

AES GCM 使用 web 微妙加密进行加密并使用颤振加密进行解密