我以前从未处理过音频信号,对信号处理知之甚少。尽管如此,我需要使用matplotlib库的pyplot.specgram
函数来表示音频信号。以下是我的做法。
import matplotlib.pyplot as plt
import scipy.io.wavfile as wavfile
rate, frames = wavfile.read("song.wav")
plt.specgram(frames)
我得到的结果是下面这个漂亮的频谱图:
![enter image description here](https://istack.dev59.com/yvaSP.webp)
我以前从未处理过音频信号,对信号处理知之甚少。尽管如此,我需要使用matplotlib库的pyplot.specgram
函数来表示音频信号。以下是我的做法。
import matplotlib.pyplot as plt
import scipy.io.wavfile as wavfile
rate, frames = wavfile.read("song.wav")
plt.specgram(frames)
正如其他人所指出的,您需要指定采样率,否则您将得到一个标准化频率(介于0和1之间)和采样索引(0到80k)。幸运的是,这很简单:
plt.specgram(frames, Fs=rate)
扩展Nukolas的答案,结合我的更改matplotlib中绘图比例的方法和timedelta的智能轴标签,我们不仅可以在频率轴上获取kHz,还可以在时间轴上获取分钟和秒。
import matplotlib.pyplot as plt
import scipy.io.wavfile as wavfile
cmap = plt.get_cmap('viridis') # this may fail on older versions of matplotlib
vmin = -40 # hide anything below -40 dB
cmap.set_under(color='k', alpha=None)
rate, frames = wavfile.read("song.wav")
fig, ax = plt.subplots()
pxx, freq, t, cax = ax.specgram(frames[:, 0], # first channel
Fs=rate, # to get frequency axis in Hz
cmap=cmap, vmin=vmin)
cbar = fig.colorbar(cax)
cbar.set_label('Intensity dB')
ax.axis("tight")
# Prettify
import matplotlib
import datetime
ax.set_xlabel('time h:mm:ss')
ax.set_ylabel('frequency kHz')
scale = 1e3 # KHz
ticks = matplotlib.ticker.FuncFormatter(lambda x, pos: '{0:g}'.format(x/scale))
ax.yaxis.set_major_formatter(ticks)
def timeTicks(x, pos):
d = datetime.timedelta(seconds=x)
return str(d)
formatter = matplotlib.ticker.FuncFormatter(timeTicks)
ax.xaxis.set_major_formatter(formatter)
plt.show()
结果:
首先,光谱图是一个随时间变化的信号频谱内容的表示方式 - 这是一个以频率域为基础的时域波形(例如正弦波、文件“song.wav”或其他任意波形-即振幅随时间变化)的表达。
频率值(y轴,赫兹)完全取决于您的波形(“song.wav”)的采样频率,并且范围从“0”到“采样频率/ 2”,其中上限是“奈奎斯特频率”或“折叠频率” (https://en.wikipedia.org/wiki/Aliasing#Folding)。 如果未明确指定输入波形的采样频率,则matplotlib specgram函数将自动确定其采样频率,该波形的采样频率定义为1/dt,其中dt是波形的离散采样之间的时间间隔。 您可以通过Fs ='采样率'选项传递给specgram函数来手动定义它。 如果您找出并自己将这些变量传递给specgram函数,会更容易理解发生了什么。
时间值(x轴,秒)纯粹取决于您的“song.wav”的长度。 如果使用较大的窗口长度来计算每个光谱片段(想象一下-单个垂直排列并水平平铺以创建光谱图像的光谱)可能会注意到一些空白或填充。
为了使绘图中的轴更直观,使用x轴和y轴标签,并且您还可以使用类似于这里的方法缩放轴值(即更改单位)。
最重要的是-尽量用代码详细解释:下面是我的示例。
import matplotlib.pyplot as plt
import numpy as np
# generate a 5Hz sine wave
fs = 50
t = np.arange(0, 5, 1.0/fs)
f0 = 5
phi = np.pi/2
A = 1
x = A * np.sin(2 * np.pi * f0 * t +phi)
nfft = 25
# plot x-t, time-domain, i.e. source waveform
plt.subplot(211)
plt.plot(t, x)
plt.xlabel('time')
plt.ylabel('amplitude')
# plot power(f)-t, frequency-domain, i.e. spectrogram
plt.subplot(212)
# call specgram function, setting Fs (sampling frequency)
# and nfft (number of waveform samples, defining a time window,
# for which to compute the spectra)
plt.specgram(x, Fs=fs, NFFT=nfft, noverlap=5, detrend='mean', mode='psd')
plt.xlabel('time')
plt.ylabel('frequency')
plt.show()
5Hz_spectrogram:
5Hz频谱图: