在 scipy 中重现 sox 频谱图
Reproduce sox spectrogram in scipy
例如我有一个带有语音的 wav 文件。
我可以用 sox 创建漂亮的频谱图可视化:
wget https://google.github.io/tacotron/publications/tacotron2/demos/romance_gt.wav
sox romance_gt.wav -n spectrogram -o spectrogram.png
如何在 python 中重现此频谱图?
这里是使用 scipy.signal.spectrogram
的例子
input_file = 'temp/romance_gt.wav'
fs, x = wavfile.read(input_file)
print('fs', fs)
print('x.shape', x.shape)
f, t, Sxx = signal.spectrogram(x, fs)
print('f.shape', f.shape)
print('t.shape', t.shape)
print('Sxx.shape', Sxx.shape)
plt.pcolormesh(t, f, Sxx)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.savefig('spectrogram_scipy.png')
但看起来有些参数不对或有什么东西坏了:
注意 sox 生成的图中颜色条的比例。单位是 dBFS:相对于满量程的分贝。要使用 SciPy 和 Matplotlib 重现绘图,您需要缩放值以使最大值为 1,然后取值的对数以转换为 dB。
这是您脚本的修改版本,其中包括对 spectrogram
和 pcolormesh
参数的各种调整,创建类似于 sox 输出的图。
import numpy as np
from scipy.io import wavfile
from scipy import signal
import matplotlib.pyplot as plt
input_file = 'romance_gt.wav'
fs, x = wavfile.read(input_file)
print('fs', fs)
print('x.shape', x.shape)
nperseg = 1025
noverlap = nperseg - 1
f, t, Sxx = signal.spectrogram(x, fs,
nperseg=nperseg,
noverlap=noverlap,
window='hann')
print('f.shape', f.shape)
print('t.shape', t.shape)
print('Sxx.shape', Sxx.shape)
plt.pcolormesh(1000*t, f/1000, 10*np.log10(Sxx/Sxx.max()),
vmin=-120, vmax=0, cmap='inferno')
plt.ylabel('Frequency [kHz]')
plt.xlabel('Time [ms]')
plt.colorbar()
plt.savefig('spectrogram_scipy.png')
我将 Sxx
除以 Sxx.max()
以说明 dBFS 的 "full-scale" 方面。我调整了 spectrogram
的 nperseg
和 noverlap
参数,以提供高于频率和时间轴默认值的分辨率。我使用 window='hann'
来匹配 sox 的默认行为。 (您可以在 http://sox.sourceforge.net/sox.html 找到 sox 频谱图的详细信息。)我还在 pcolormesh
中使用 vmin=-120
和 vmax=0
来匹配 sox 频谱图使用的默认范围。
情节如下:
"inferno" 颜色图不像 sox 图中使用的那样强烈。有关替代色图,请参阅 "Choosing Colormaps in Matplotlib" 上的教程。
例如我有一个带有语音的 wav 文件。
我可以用 sox 创建漂亮的频谱图可视化:
wget https://google.github.io/tacotron/publications/tacotron2/demos/romance_gt.wav
sox romance_gt.wav -n spectrogram -o spectrogram.png
如何在 python 中重现此频谱图?
这里是使用 scipy.signal.spectrogram
的例子input_file = 'temp/romance_gt.wav'
fs, x = wavfile.read(input_file)
print('fs', fs)
print('x.shape', x.shape)
f, t, Sxx = signal.spectrogram(x, fs)
print('f.shape', f.shape)
print('t.shape', t.shape)
print('Sxx.shape', Sxx.shape)
plt.pcolormesh(t, f, Sxx)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.savefig('spectrogram_scipy.png')
但看起来有些参数不对或有什么东西坏了:
注意 sox 生成的图中颜色条的比例。单位是 dBFS:相对于满量程的分贝。要使用 SciPy 和 Matplotlib 重现绘图,您需要缩放值以使最大值为 1,然后取值的对数以转换为 dB。
这是您脚本的修改版本,其中包括对 spectrogram
和 pcolormesh
参数的各种调整,创建类似于 sox 输出的图。
import numpy as np
from scipy.io import wavfile
from scipy import signal
import matplotlib.pyplot as plt
input_file = 'romance_gt.wav'
fs, x = wavfile.read(input_file)
print('fs', fs)
print('x.shape', x.shape)
nperseg = 1025
noverlap = nperseg - 1
f, t, Sxx = signal.spectrogram(x, fs,
nperseg=nperseg,
noverlap=noverlap,
window='hann')
print('f.shape', f.shape)
print('t.shape', t.shape)
print('Sxx.shape', Sxx.shape)
plt.pcolormesh(1000*t, f/1000, 10*np.log10(Sxx/Sxx.max()),
vmin=-120, vmax=0, cmap='inferno')
plt.ylabel('Frequency [kHz]')
plt.xlabel('Time [ms]')
plt.colorbar()
plt.savefig('spectrogram_scipy.png')
我将 Sxx
除以 Sxx.max()
以说明 dBFS 的 "full-scale" 方面。我调整了 spectrogram
的 nperseg
和 noverlap
参数,以提供高于频率和时间轴默认值的分辨率。我使用 window='hann'
来匹配 sox 的默认行为。 (您可以在 http://sox.sourceforge.net/sox.html 找到 sox 频谱图的详细信息。)我还在 pcolormesh
中使用 vmin=-120
和 vmax=0
来匹配 sox 频谱图使用的默认范围。
情节如下:
"inferno" 颜色图不像 sox 图中使用的那样强烈。有关替代色图,请参阅 "Choosing Colormaps in Matplotlib" 上的教程。