如何设置 STFT 参数以可视化啄木鸟/锯齿信号?​​​

信息处理 fft Python 声音 stft
2022-02-10 02:54:45

我一直想使用 FFT 和频谱图来使用 python 来表征声音及其频率。

最近我在他的工作中记录了一只啄木鸟。

啄木鸟 Wav 文件

为了知道在哪里看,我将声音与Onlinegenerator.com生成的锯齿波进行了比较。我认为 17 Hz 很合适。

17 Hz 锯齿波形文件

使用生成的文件检查代码效果很好。

但遗憾的是,我无法在 DFT/FFT 或使用以下代码生成的频谱图中找到频率。无论我尝试哪种设置,我都无法正确显示低于 20 Hz 的频率。没有主要信号切断或切断。只有 23 Hz 的信号,似乎是连续的。

​from scipy import signal
import scipy.io.wavfile as wav
import matplotlib.pyplot as plt
import numpy as np

​# Read WAV File
the_file = 'IMG_0710_short.wav'
samplerate, samples = wav.read(the_file)

#samples_left = samples[:,0]
samples = samples[:,1] # reduce to right channel

timevec = range(len(samples)) # Time vector for plot
timevec = [x / samplerate for x in timevec]
t_max =timevec[-1]

​# Lineplot of Signal
dpi = 200
plt.rcParams['figure.dpi']= dpi

plt.plot(timevec,samples)
plt.title(the_file)
plt.ylabel('Amplitude [-]')
plt.xlabel('Time [sec]')

​# STFT Settings
nperseg  = 0.5 * samplerate # Window Size 1
noverlap = nperseg*0.95 # Overlap
nfft     = 1 * samplerate # STFT 2
window   = 'hann' # Window Type

timespan = [0, 2] # Calculation Window
fromm = int(len(samples)/t_max*timespan[0])
too   = int(len(samples)/t_max*timespan[1])

f, t, Zxx = signal.stft(samples[fromm:too], samplerate, nperseg=nperseg, window=window, noverlap=noverlap, nfft=nfft)
t = t + timespan[0]
cmap=plt.cm.nipy_spectral
vmin = 10
vmax = 18
fig = plt.figure(figsize=(7, 5))
pcm = plt.pcolormesh(t, f, np.log(np.abs(Zxx)), cmap=cmap, vmin=vmin, vmax=vmax)

plt.ylim(0,50)
fig.colorbar(pcm)
plt.title(the_file)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')

# FFT
​n = len(samples) # length of the signal
k = np.arange(n)
T = n/samplerate
frq = k/T # two sides frequency range
frq = frq[range(int((n/2)))] # one side frequency range

Y = np.fft.fft(samples, norm='ortho')#/n # fft computing and normalization
Y = Y[range(int(n/2))]

fig, ax = plt.subplots(2, 1)
ax[0].plot(timevec,samples) # plotting the signal
ax[0].set_xlabel('Time')
ax[0].set_ylabel('Amplitude')
ax[1].plot(frq,abs(Y),'r') # plotting the spectrum
ax[1].set_xlabel('Frequency (Hz)')
ax[1].set_ylabel('|Y(freq)|')
ax[1].set_xlim(0,50)

啄木鸟与 17Hz

信号和 FFT

我需要如何设置 stft 参数才能正确显示啄木鸟光谱?或者这里的 stft 是否存在根本问题?

1个回答

您的第一个问题是您的轴混淆了。

您的“17 Hz”图片非常清楚地显示了这一点。红条是来自信号的脉冲。条形图应表示脉冲(频率范围广),但您的轴表示它们是跨时间的。

这应该是这样的:

在此处输入图像描述 请注意,这些条形图是沿着频率轴的,而不是像你的那样沿着时间轴。

这是你的啄木鸟录音:

在此处输入图像描述

它也包含条形图。但是,它们没有那么宽,并且更接近(强度)背景噪声。

条形以略高于 20Hz 的频率重复 - 您可以在最后一个图中看到频率约为 23Hz(蓝色示波器样式图下方的红线图。)

您的 0.95 重叠相当于大约 40Hz 的时间分辨率。您需要更高的重叠度(可能为 0.99)来分隔条形。

您可以将录音降采样到 11025 Hz 采样率。这将使您获得更好的频率分辨率并更快地计算频谱图。您可以这样做,因为您对 4500Hz 以上的信号并没有太大的兴趣。