簡體   English   中英

如何從Python中獲取FFT的時間/頻率

[英]How to get time/freq from FFT in Python

我在管理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軸=頻率,Y軸=幅度,Z軸=時間(不可見)

根據我對代碼的理解,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]

不需要可視化,結果應該只是上面列出的數組(或散列/字典)。

繼@Paul R的回答, scipy.signal.spectrogramscipy信號處理模塊中頻譜圖功能

上述鏈接的示例如下:

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

在此輸入圖像描述

看起來您正在嘗試實施頻譜圖 ,這是一系列功率譜估計,通常通過一系列(通常是重疊的)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

編輯:哦,所以它似乎返回值,但它們根本不適合音頻文件。 盡管它們可以用作頻譜圖上的幅度,但它們不適用於那些在許多音樂播放器中可以看到的經典視聽器。 我也嘗試了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的提示嗎? 基本上,我們顯然已經從上面的代碼中獲得了所有我們需要的,只是如何讓它返回正常值? 忽略mimx因為這些只是調整數組中的值以適應mi..mx間隔 - 這將用於可視化用法。 如果我是正確的,那么這段代碼中的spectrum返回數組,這些數組包含來自freqs數組的每個頻率的幅度,這些頻率根據t數組按時出現,但該值如何工作 - 如果它返回這些奇怪的值,它是否真的是幅度如果是,如何將其轉換為dBs例如。

tl; dr我需要像音樂播放器一樣的可視化器輸出,但它不應該實時工作,我只想要數據,但值不適合wav文件。

Edit2:我注意到還有一個問題。 對於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,這是它沒有返回正確值的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM