matplotlib 从输入设备绘制实时频谱图

u3r8eeie  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(116)

我尝试从默认输入设备数据实时绘制光谱图。我使用matplotlib模块中的FuncAnimation绘制动画,但我不明白为什么绘图不使用缓冲区中的新数据更新。
这是我目前所知道的。

from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import numpy as np
import rtmixer
import math
import sounddevice as sd

FRAMES_PER_BUFFER = 512
NFFT = 4096
NOVERLAP = 128

window = 100000
downsample = 10  
channels = 1

def create_specgram(frame):
    global plotdata
    
    spec, freqs, t = plt.mlab.specgram(plotdata[:,-1], Fs=samplerate)
    xmin, xmax = np.min(t) - pad_xextent, np.max(t) + pad_xextent
    extent = xmin, xmax, freqs[0], freqs[-1]
    arr = np.flipud(10. * np.log10(spec))

    return arr, extent

def update_plot(frame):

    global plotdata

    while ringBuffer.read_available >= FRAMES_PER_BUFFER:
        read, buf1, buf2 = ringBuffer.get_read_buffers(FRAMES_PER_BUFFER)
        assert read == FRAMES_PER_BUFFER
        buffer = np.frombuffer(buf1, dtype='float32')
        buffer.shape = -1, channels
        buffer = buffer[::downsample]

        assert buffer.base.base == buf1
        shift = len(buffer)
        plotdata = np.roll(plotdata, -shift, axis=0)
        plotdata[-shift:, :] = buffer
        ringBuffer.advance_read_index(FRAMES_PER_BUFFER)

    arr, _  = create_specgram(frame)
    image.set_array(arr)
    return image,

device_info = sd.query_devices(device=None, kind='input')
samplerate = device_info['default_samplerate']

pad_xextent = (NFFT - NOVERLAP) / samplerate / 2
length = int(window * samplerate / (1000 * downsample))
plotdata = np.zeros((length, channels))

stream = rtmixer.Recorder(device=None, channels=channels, blocksize=FRAMES_PER_BUFFER,
                          latency='low', samplerate=samplerate)

ringbufferSize = 2**int(math.log2(3 * samplerate))

ringBuffer = rtmixer.RingBuffer(channels * stream.samplesize, ringbufferSize)

fig, ax = plt.subplots(figsize=(10, 5))
arr, extent = create_specgram(0)
image = plt.imshow(arr, animated=True, extent=extent, aspect='auto')
fig.colorbar(image)

ani = FuncAnimation(fig, update_plot, interval=1, blit=True, cache_frame_data=False)           

with stream:
    ringBuffer = rtmixer.RingBuffer(channels * stream.samplesize, ringbufferSize)
    action = stream.record_ringbuffer(ringBuffer)
    plt.show()

有人知道我哪里做错了吗?
我希望这样的东西从右向左移动。

这就是我得到的(我正在播放一些不同的东西,而不仅仅是噪音):

jaxagkaj

jaxagkaj1#

你的代码对我来说很好用,按照你描述的更新!
答案就在你的系统里。
我从控制台在Linux计算机下启动它,它在IDE(Spyder)中不工作,因为在那里,输出设置不允许启动一个单独的窗口。
小边注:你必须对色标设置限制,否则它会从起始值开始保持固定,在你的情况下是1。

相关问题