使用numpython的谱图

使用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

我需要用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_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
    可获得真实频率,在
    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)
频谱图 您可以使用以下代码重新创建
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)