我遵循了这个不错的tutorial,并创建了一个实时频谱图来监视麦克风输入。该方法使用ImageItem,并在每次读取到图像的最后一列时进行拟合。
此方法工作流畅。但是,y比例是线性的,这不是理想的。
是否可以将y轴更改为对数刻度?我觉得这很困难,因为该物品是一张图片。
import numpy as np
import pyqtgraph as pg
import pyaudio
from PyQt5 import QtCore, QtGui
FS = 44100 #Hz
CHUNKSZ = 1024 #samples
class MicrophoneRecorder():
def __init__(self, signal):
self.signal = signal
self.p = pyaudio.PyAudio()
self.stream = self.p.open(format=pyaudio.paInt16,
channels=1,
rate=FS,
input=True,
frames_per_buffer=CHUNKSZ)
def read(self):
data = self.stream.read(CHUNKSZ, exception_on_overflow= False)
y = np.fromstring(data, 'int16')
self.signal.emit(y)
def close(self):
self.stream.stop_stream()
self.stream.close()
self.p.terminate()
class SpectrogramWidget(pg.PlotWidget):
read_collected = QtCore.pyqtSignal(np.ndarray)
def __init__(self):
super(SpectrogramWidget, self).__init__()
self.img = pg.ImageItem()
self.addItem(self.img)
self.img_array = np.zeros((1000, CHUNKSZ//2+1))
# bipolar colormap
pos = np.array([0., 1., 0.5, 0.25, 0.75])
color = np.array([[0,255,255,255], [255,255,0,255], [0,0,0,255], (0, 0, 255, 255), (255, 0, 0, 255)], dtype=np.ubyte)
cmap = pg.ColorMap(pos, color)
lut = cmap.getLookupTable(0.0, 1.0, 256)
# set colormap
self.img.setLookupTable(lut)
self.img.setLevels([-50,40])
# setup the correct scaling for y-axis
freq = np.arange((CHUNKSZ/2)+1)/(float(CHUNKSZ)/FS)
yscale = 1.0/(self.img_array.shape[1]/freq[-1])
self.img.scale((1./FS)*CHUNKSZ, yscale)
self.setLabel('left', 'Frequency', units='Hz')
# prepare window for later use
self.win = np.hanning(CHUNKSZ)
self.show()
def update(self, chunk):
# normalized, windowed frequencies in data chunk
spec = np.fft.rfft(chunk*self.win) / CHUNKSZ
# get magnitude
psd = abs(spec)
# convert to dB scale
psd = 20 * np.log10(psd)
# roll down one and replace leading edge with new data
self.img_array = np.roll(self.img_array, -1, 0)
self.img_array[-1:] = psd
self.img.setImage(self.img_array, autoLevels=False)
if __name__ == '__main__':
app = QtGui.QApplication([])
w = SpectrogramWidget()
w.read_collected.connect(w.update)
mic = MicrophoneRecorder(w.read_collected)
# time (seconds) between reads
interval = FS/CHUNKSZ
t = QtCore.QTimer()
t.timeout.connect(mic.read)
t.start(1000/interval) #QTimer takes ms
app.exec_()
mic.close()
非常感谢