使用numpython的谱图
我需要用numpy制作光谱图。我把1s的音频分成0.02s的块。然后我使用numpy计算FFT,并将其放回一幅图像中。结果很差 以下是使用matplotlib specgram函数生成的光谱图: 这是我的“光谱图”: 这是我的密码:使用numpython的谱图,python,numpy,fft,spectrogram,Python,Numpy,Fft,Spectrogram,我需要用numpy制作光谱图。我把1s的音频分成0.02s的块。然后我使用numpy计算FFT,并将其放回一幅图像中。结果很差 以下是使用matplotlib specgram函数生成的光谱图: 这是我的“光谱图”: 这是我的密码: spect_frags = [] transform = [] for x in range(0, 8000, 160): spect_frags.append(spect_sample[x:x + 160]) for sample in spect_f
spect_frags = []
transform = []
for x in range(0, 8000, 160):
spect_frags.append(spect_sample[x:x + 160])
for sample in spect_frags:
transform.append(abs(np.fft.fft(sample).real)[0:np.fft.fft(sample).real.size//4])
我削减了3/4的频率,因为我现在不需要它们。
我不知道为什么在分辨率上有如此多的差异。如何改进?频谱图MCVE
您可以使用以下代码重新创建specgram
的粗略估计值:
import numpy as np
from scipy.io import wavfile
from scipy import fft
import matplotlib.pyplot as plt
# Read some sample file (replace with your data):
rate, data = wavfile.read('./data/aaaah.wav')
# rate=48000, data.shape=(46447, 2) ~ almost 1s of stereo signal
# Spectrogram estimation:
N = 256
S = []
for k in range(0, data.shape[0]+1, N):
x = fft.fftshift(fft.fft(data[k:k+N,0], n=N))[N//2:N]
# assert np.allclose(np.imag(x*np.conj(x)), 0)
Pxx = 10*np.log10(np.real(x*np.conj(x)))
S.append(Pxx)
S = np.array(S)
# Frequencies:
f = fft.fftshift(fft.fftfreq(N, d=1/rate))[N//2:N]
# array([ 0. , 187.5, 375. , ..., 23625. , 23812.5])
# Spectrogram rendering:
plt.imshow(S.T, origin='lower')
它输出:
渲染时:
此MCVE与specgram不同,因为轴应缩放以正确反映时间和频率,并且没有移动窗口。更准确地说:
- x轴表示长度的时间索引
李>N=256
- y轴是正半平面FFT索引(
),请注意使用N//2=128
在fftshift
之后组合频谱李>FFT
- 使用采样率和
可获得真实频率,在fftfreq
中,其范围为0到1,因为此方法不一定知道信号采样率李>specgram
- 没有窗口重叠(使用独立的连续通道),这就是为什么MCVE比specgram稍微不平滑的原因
abs(np.fft.fft(sample).real)
您没有使用复数的范数,但是由于.real
调用,您完全删除了复数部分
您应该使用:
然后使用abs
将complex
类型转换为float
(或者只保留real
部分,因为complex部分必须为空)。最后,您可以使用十进制对数进行缩放
健康检查
您可以检查FFT的结果是否确实是复杂类型,并带有一个有意义的复杂部分(删除它会导致信息丢失):
共轭产物确实有一个空的复杂部分(但仍然是复杂的类型):
通过断言以下内容,您可以确保这始终是正确的(健全性检查):
assert np.allclose(np.imag(x*np.conj(x)), 0)
频谱图
您可以使用以下代码重新创建specgram
的粗略估计值:
import numpy as np
from scipy.io import wavfile
from scipy import fft
import matplotlib.pyplot as plt
# Read some sample file (replace with your data):
rate, data = wavfile.read('./data/aaaah.wav')
# rate=48000, data.shape=(46447, 2) ~ almost 1s of stereo signal
# Spectrogram estimation:
N = 256
S = []
for k in range(0, data.shape[0]+1, N):
x = fft.fftshift(fft.fft(data[k:k+N,0], n=N))[N//2:N]
# assert np.allclose(np.imag(x*np.conj(x)), 0)
Pxx = 10*np.log10(np.real(x*np.conj(x)))
S.append(Pxx)
S = np.array(S)
# Frequencies:
f = fft.fftshift(fft.fftfreq(N, d=1/rate))[N//2:N]
# array([ 0. , 187.5, 375. , ..., 23625. , 23812.5])
# Spectrogram rendering:
plt.imshow(S.T, origin='lower')
它输出:
渲染时:
此MCVE与specgram不同,因为轴应缩放以正确反映时间和频率,并且没有移动窗口。更准确地说:
- x轴表示长度的时间索引
N=256
李>
- y轴是正半平面FFT索引(
N//2=128
),请注意使用fftshift
在FFT
之后组合频谱李>
- 使用采样率和
fftfreq
可获得真实频率,在specgram
中,其范围为0到1,因为此方法不一定知道信号采样率李>
- 没有窗口重叠(使用独立的连续通道),这就是为什么MCVE比specgram
稍微不平滑的原因
功率估算
还要注意的是,取复数的实部与取大小不同。主要是,当你写作时:
abs(np.fft.fft(sample).real)
您没有使用复数的范数,但是由于.real
调用,您完全删除了复数部分
您应该使用:
然后使用abs
将complex
类型转换为float
(或者只保留real
部分,因为complex部分必须为空)。最后,您可以使用十进制对数进行缩放
健康检查
您可以检查FFT的结果是否确实是复杂类型,并带有一个有意义的复杂部分(删除它会导致信息丢失):
共轭产物确实有一个空的复杂部分(但仍然是复杂的类型):
通过断言以下内容,您可以确保这始终是正确的(健全性检查):
assert np.allclose(np.imag(x*np.conj(x)), 0)
你在记录结果吗?看起来matplotlib是一个合适的MCVE。制作一个随机数据集,并展示如何生成这两个图像。此外,请记住,您需要应用窗口功能以获得相同的结果。是否可以添加有关输入和所需输出的更多详细信息。同时发布您使用的完整代码,包括对matplotlib的调用,该调用似乎是您想要的输出。在显示结果之前尝试获取对数是否获取结果日志?看起来matplotlib是一个合适的MCVE。制作一个随机数据集,并展示如何生成这两个图像。此外,请记住,您需要应用窗口功能以获得相同的结果。是否可以添加有关输入和所需输出的更多详细信息。同时发布您使用的完整代码,包括对matplotlib的调用,这似乎是您想要的输出。在显示结果之前,请尝试使用对数
assert np.allclose(np.imag(x*np.conj(x)), 0)