我在管理FFT数据方面遇到了一些问题。我正在寻找很多关于如何进行FFT的例子,但我无法从他们中获得我想要的东西。我有一个44kHz采样率的随机波形文件,我希望每X ms得到N次谐波的幅度,让我们说100ms就足够了。我试过这段代码:
import scipy.io.wavfile as wavfile
import numpy as np
import pylab as pl
rate, data = wavfile.read("sound.wav")
t = np.arange(len(data[:,0]))*1.0/rate
p = 20*np.log10(np.abs(np.fft.rfft(data[:2048, 0])))
f = np.linspace(0, rate/2.0, len(p))
pl.plot(f, p)
pl.xlabel("Frequency(Hz)")
pl.ylabel("Power(dB)")
pl.show()
这是我使用的最后一个例子,我发现它在stackoverflow上的某个地方。问题是,这需要我想要的幅度,获得频率,但根本没有时间。据我所知,FFT分析是3D,这是"合并"所有谐波的结果。我明白了:
X-axis = Frequency, Y-axis = Magnitude, Z-axis = Time (invisible)
根据我对代码的理解,t是时间 - 似乎是这样,但代码中不需要 - 我们可能会需要它。 p是功率(或幅度)的数组,但它似乎是每个频率f的所有幅度的平均值,即频率阵列。我不想要平均/合并值,我想要每X毫秒的N次谐波幅度。
长话短说,我们可以得到:所有频率的1个数量。
我们想要:所有N个频率的大小,包括存在一定幅度的时间。
结果应该看起来像这个数组:[时间,频率,幅度] 所以最后如果我们想要3个谐波,它看起来像是:
[0,100,2.85489] #100Hz harmonic has 2.85489 amplitude on 0ms
[0,200,1.15695] #200Hz ...
[0,300,3.12215]
[100,100,1.22248] #100Hz harmonic has 1.22248 amplitude on 100ms
[100,200,1.58758]
[100,300,2.57578]
[200,100,5.16574]
[200,200,3.15267]
[200,300,0.89987]
不需要可视化,结果应该只是上面列出的数组(或哈希/词典)。
答案 0 :(得分:5)
继@Paul R的回答,scipy.signal.spectrogram
是spectrogram function中的scipy's signal processing module。
以上链接的示例如下:
from scipy import signal
import matplotlib.pyplot as plt
# Generate a test signal, a 2 Vrms sine wave whose frequency linearly
# changes with time from 1kHz to 2kHz, corrupted by 0.001 V**2/Hz of
# white noise sampled at 10 kHz.
fs = 10e3
N = 1e5
amp = 2 * np.sqrt(2)
noise_power = 0.001 * fs / 2
time = np.arange(N) / fs
freq = np.linspace(1e3, 2e3, N)
x = amp * np.sin(2*np.pi*freq*time)
x += np.random.normal(scale=np.sqrt(noise_power), size=time.shape)
#Compute and plot the spectrogram.
f, t, Sxx = signal.spectrogram(x, fs)
plt.pcolormesh(t, f, Sxx)
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()
答案 1 :(得分:4)
您似乎正在尝试实施spectrogram,这是一系列功率谱估算,通常通过一系列(通常是重叠的)FFT实现。由于您只有一个FFT(频谱),因此您还没有时间维度。将FFT代码放在循环中,每次迭代处理一个样本块(例如1024),连续块之间重叠50%。然后,生成的光谱序列将是时间v频率v幅度的3D阵列。
我不是一个Python人,但我可以给你一些伪代码,这些代码应该足以让你编码:
N = length of data input
N_FFT = no of samples per block (== FFT size, e.g. 1024)
i = 0 ;; i = index of spectrum within 3D output array
for block_start = 0 to N - block_start
block_end = block_start + N_FFT
get samples from block_start .. block_end
apply window function to block (e.g. Hamming)
apply FFT to windowed block
calculate magnitude spectrum (20 * log10( re*re + im*im ))
store spectrum in output array at index i
block_start += N_FFT / 2 ;; NB: 50% overlap
i++
end
答案 2 :(得分:0)
编辑哦,所以它似乎会返回值,但它们根本不适合音频文件。尽管它们可以用作频谱图上的幅度,但它们不适用于那些在许多音乐播放器中可以看到的经典视听器。我也尝试使用matplotlib的pylab进行频谱图,但结果是一样的。
import os
import wave
import pylab
import math
from numpy import amax
from numpy import amin
def get_wav_info(wav_file,mi,mx):
wav = wave.open(wav_file, 'r')
frames = wav.readframes(-1)
sound_info = pylab.fromstring(frames, 'Int16')
frame_rate = wav.getframerate()
wav.close()
spectrum, freqs, t, im = pylab.specgram(sound_info, NFFT=1024, Fs=frame_rate)
n = 0
while n < 20:
for index,power in enumerate(spectrum[n]):
print("%s,%s,%s" % (n,int(round(t[index]*1000)),math.ceil(power*100)/100))
n += 1
get_wav_info("wave.wav",1,20)
如何获得可视化中可用的dB的提示?
基本上,我们显然已经从上面的代码中获得了所有我们需要的,只是如何让它返回正常值?忽略mi
和mx
,因为它们只是调整数组中的值以适应mi..mx间隔 - 这将用于可视化用法。如果我是正确的,那么此代码中的spectrum
将返回包含freqs
数组中每个频率的幅度的数组数组,这些数据根据t
数组按时出现,但值如何work - 如果它返回这些奇怪的值,它是否真的是幅度,如果是,例如如何将其转换为dBs。
tl; dr我需要像音乐播放器一样的可视化器输出,但它不应该实时工作,我只想要数据,但值不适合wav文件。
编辑2:我注意到还有一个问题。对于90秒的wav,t
数组包含的时间直到175.x,考虑到frame_rate
与wav文件的关系是正确的,这似乎很奇怪。所以现在我们有两个问题:spectrum
似乎没有返回正确的值(如果我们得到正确的时间它可能会适合)并且t
似乎返回wav的两倍时间。
已修复:案例已完全解决。
import os
import pylab
import math
from numpy import amax
from numpy import amin
from scipy.io import wavfile
frame_rate, snd = wavfile.read(wav_file)
sound_info = snd[:,0]
spectrum, freqs, t, im = pylab.specgram(sound_info,NFFT=1024,Fs=frame_rate,noverlap=5,mode='magnitude')
Specgram需要稍微调整,我只用scipy.io库(而不是wave库)加载了一个通道。同样没有模式设置为幅度,它返回10log10而不是20log10,这就是它没有返回正确值的原因。