如何在Python中从FFT中获取时间/频率

如何在Python中从FFT中获取时间/频率,python,numpy,matplotlib,scipy,fft,Python,Numpy,Matplotlib,Scipy,Fft,我在管理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[:

我在管理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的,这是所有谐波的“合并”结果。我明白了:

从我对代码的理解来看,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]

不需要可视化,结果应该是上面列出的数组(或哈希/字典)。

看起来您正在尝试实现一个,这是一个功率谱估计序列,通常由一系列(通常重叠)FFT实现。因为只有一个FFT(频谱),所以还没有时间维度。将FFT代码放入循环中,每次迭代处理一个采样块(例如1024个),连续块之间有50%的重叠。然后,生成的光谱序列将是时间-频率-幅度的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

在@Paul R的回答之后,
scipy.signal.spectrogram
是一个例子

上述链接的示例如下所示:

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()

编辑:哦,看来这会返回值,但它们根本不适合音频文件。即使它们可以在频谱图上用作震级,它们也无法在许多音乐播放器中看到的经典音频可视化工具中工作。我还尝试了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)

Specgram需要一些调整,我用scipy.io库(而不是wave库)只加载了一个通道。同样,如果没有将模式设置为“幅值”,它将返回10log10而不是20log10,这就是它没有返回正确值的原因。

快速傅里叶变换(FFT)算法计算序列的离散傅里叶变换(DFT)或其逆。傅里叶分析将信号从其原始域(通常是时间或空间)转换为频域表示,反之亦然。我认为,一旦你对原始信号进行傅里叶变换,你就不应该得到时间。它被转换到频域。类似地,当你们对频域信号应用傅里叶逆变换时,你们会得到时域信号。在这里多读一读。谢谢你的评论,虽然你向我解释了算法是如何工作的,但我仍然不知道是否有可能从中获得这样的输出,或者它是否需要完全不同的方式。如果不使用FFT,如何分别得到我描述的输出。知道一点FFT是如何工作的并不能解决这个问题。。如果我逆傅里叶变换,我会得到时域信号,但那是原始信号,不是吗?除此之外,我仍然不知道从哪里可以得到这三个值。我知道你的意思,我可以确认spectrogram就是我要找的。然而,作为一个新手,我不知道如何做到这一点。有人给我一些提示或完整的例子吗?从f、t和Sxx中获得我需要的所有三个值非常容易。问题将是导入wav文件到它,然后它应该工作顺利。然而,我认为scipy库可以兼容所有组件,但事实并非如此。从scipy.io读取wavfile.read从wav生成一个ndarray,但不能作为signal.spectrogram的输入,即使上面代码中的x也是ndarray。我完全不知道,因为文档似乎没有显示与scipy.io.wavfile.read的任何连接
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')