更快地绘制实时音频信号

时间:2018-02-09 00:56:17

标签: python-3.x matplotlib real-time

我有一段代码可以从笔记本电脑的音频插孔中获取实时音频信号,并在进行一些基本过滤后绘制图形。我面临的问题是,随着程序的运行,实时绘图变得越来越慢。

有什么建议让这种绘图更快并以恒定速率进行?我认为动画功能会使它更快,但无法根据我的要求制定

import pyaudio
import numpy as np
import time
import matplotlib.pyplot as plt
import scipy.io.wavfile
from scipy.signal import butter, lfilter
import wave

plt.rcParams["figure.figsize"] = 8,4

RATE = 44100
CHUNK = int(RATE/2) # RATE / number of updates per second
#Filter co-efficients 
nyq = 0.5 * RATE
low = 3000 / nyq
high = 6000 / nyq
b, a = butter(7, [low, high], btype='band')

#Figure structure
fig, (ax, ax2) =plt.subplots(nrows=2, sharex=True)
x = np.linspace(1, CHUNK, CHUNK)
extent = [x[0] - (x[1] - x[0]) / 2., x[-1] + (x[1] - x[0]) / 2., 0, 1]



def soundplot(stream):
    t1=time.time()
    data = np.array(np.fromstring(stream.read(CHUNK),dtype=np.int32))
    y1 = lfilter(b, a, data)
    ax.imshow(y1[np.newaxis, :], cmap="jet", aspect="auto")
    plt.xlim(extent[0], extent[1])
    plt.ylim(-50000000, 50000000)
    ax2.plot(x, y1)
    plt.pause(0.00001)
    plt.cla()  # which clears data but not axes
    y1 = []
    print(time.time()-t1)
if __name__=="__main__":
    p=pyaudio.PyAudio()
    stream=p.open(format=pyaudio.paInt32,channels=1,rate=RATE,input=True,
                  frames_per_buffer=CHUNK)
    for i in range(RATE):
        soundplot(stream)
    stream.stop_stream()
    stream.close()
    p.terminate()

1 个答案:

答案 0 :(得分:4)

评论有点长,因为你要求提出建议,我认为这是一个半完整的答案。如果您需要超出此处的想法,可以在线获取有关使用matplotlib进行实时绘图的更多信息和示例。该库不是为此设计的,但它是可能的。

第一步,分析代码。您可以使用

执行此操作
import cProfile
cProfile.run('soundplot(stream)')

这将显示大部分时间花在哪里。 如果不这样做,我会提供一些提示,但请注意,分析可能会显示其他原因。

首先,您希望消除函数soundplot中的冗余函数调用。以下两个都是不必要的:

plt.xlim(extent[0], extent[1])
plt.ylim(-50000000, 50000000)

可以在初始化代码中调用它们一次。 imshow会自动更新这些内容,但为了提高速度,您不应每次都调用它。相反,在一些初始化代码 outside 中,函数使用im=imshow(data, ...),其中数据的大小与您要绘制的大小相同(尽管可能不需要)。然后,在soundplot中使用im.set_data(y1[np.newaxis, :])。不必每次迭代都重新创建图像对象,这将极大地加快速度。

由于图像对象在每次迭代中都会保留,因此您还需要删除对cla()的调用,并将其替换为show()draw()以使图形绘制为更新的图像。您可以使用line.set_ydata(y)在第二轴上对该行执行相同操作。

请发布它运行的前后费率,如果有帮助请告诉我。

编辑:对类似代码进行一些快速分析表明速度提升100-500倍,主要来自删除cla()

另外看一下你的代码,它放慢速度的原因是第一个轴上没有调用cla。最终会在该轴上绘制数百张图像,从而减慢matplotlib的爬行速度。