在 Python 中绘制语音频域中的傅立叶

Plot Fourier in Frequency domain of Voice in Python

我的情节面临一个非常奇怪的问题。我的代码记录了我从麦克风发出的声音,然后绘制了一些图。时域语音图、频域图和频谱图。问题是我在频域中的情节似乎并不真实。例如看看我的情节。

所以在这张唱片中,我会说 'one, two, three, four' 或类似的话。时域图确实有意义。我眼中的频谱图也很有意义,因为最响亮的傅里叶幅度处于正常人声频率~100 Hz。

问题是

我在频域图中的短时傅立叶变换,似乎以非常高的幅度绘制非常高的频率,而人类声音频率 1-1000 的值为零。

那么可能出了什么问题? 下面我给出我的代码

import matplotlib.pyplot as plt
import numpy as np
import scipy.fft
import sounddevice as sd
from scipy import signal, fft

Fs = 8000  # Sampling frequency
duration = 5  # Recording duration in seconds
voice = sd.rec(frames=duration * Fs, samplerate=Fs, channels=1, dtype='int16')  # Capture the voice
# frames indicate  indirectly the duration of record, dtype is 16 bits per sample.
sd.wait()  # close after recording finish
time = np.linspace(0, len(voice - 1) / Fs, len(voice - 1))  # split x axis in voice-1 points
# points have 1/Fs distance each other
plt.plot(voice / len(voice))
plt.ylabel('Voice amplitude')
plt.xlabel('No of sample')
plt.title("Voice Signal with respect to sample number")
plt.show()
plt.plot(time, voice / len(voice))  # plot in seconds
plt.title("Voice Signal")
plt.xlabel("Time [seconds]")
plt.ylabel("Voice amplitude")
plt.show()
plt.plot((10**3)*time, voice / len(voice))  # plot in milliseconds
plt.title("Voice Signal")
plt.xlabel("Time [milliseconds]")
plt.ylabel("Voice amplitude")
plt.show()
N = len(voice)
# Fourier transform
F = scipy.fft.fft(voice) / N
#f = np.linspace(0, Fs - Fs / N, N)
f = fft.fftfreq(n=N, d=1 / Fs)[:N // 2]
#f = np.linspace(0, 4000, N//2)
plt.plot(f, abs(F[0:N // 2]))
plt.title("FFT of the signal")
plt.xlabel('Frequency')
plt.ylabel('Power of Frequency')
plt.show()
Voice = voice.flatten()  # formatting Voice 2-D array to numpy 1-D array
print(Voice)
freq, t, stft = signal.spectrogram(Voice, Fs, mode='complex')
#Sxx, freq, t = plt.specgram(Voice, Fs=Fs, mode='magnitude')
print(stft)
print(freq)
print(t)
plt.pcolormesh(t, freq, abs(stft), shading='gouraud')
plt.title('Spectrogramm using STFT amplitude')
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [seconds]')
plt.show()

使用 2D 数组 voice(最有可能是 Nx1,用于单声道记录),scipy.fft.fft 最终计算出一批长度为 1 的 N 个一维 FFT。由于序列 1 的 FFT value 是一个恒等式,您在第二张图中看到的是时域信号前半部分的绝对值。

尝试在一维阵列(单通道)上计算 FFT,例如:

F = scipy.fft.fft(voice[:,0]) / N