簡體   English   中英

使用NumPy FFT計算非整數頻率

[英]Calculate non-integer frequency with NumPy FFT

我想使用NumPy FFT計算周期時間序列的頻率。 例如,假設我的時間序列y定義如下:

import numpy as np
freq = 12.3
x = np.arange(10000)
y = np.cos(x * 2 * np.pi * freq / 10000)

如果頻率是整數,則可以使用np.argmax(np.abs(np.fft.fft(y))) 但是,如果頻率不是整數,如何更精確地計算頻率?

編輯:為澄清起見,我們不應該知道如何生成時間序列y 上面的代碼片段只是一個非整數頻率如何出現的人工示例。 顯然,如果我們已經知道生成時間序列的函數,則不需要FFT即可確定頻率。

您需要給信號更多的分辨率

import numpy as np
freq = 12.3
x = np.arange(100000)  # 10 times more resolution
y = np.cos(x * 2 * np.pi * freq / 10000)  # don't change this

print(np.argmax(np.abs(np.fft.fft(y))) / 10)  # divide by 10
# 12.3

x的數據點數量必須是y除以的數量的10倍。 您可以獲得類似的效果:

x = np.arange(10000)
y = np.cos(x * 2 * np.pi * freq / 1000)

print(np.argmax(np.abs(np.fft.fft(y))) / 10) 
# 12.3

如果要用兩位小數查找頻率,則分辨率需要提高100倍。

freq = 12.34
x = np.arange(10000)  
y = np.cos(x * 2 * np.pi * freq / 100)  # 100 times more resolution

print(np.argmax(np.abs(np.fft.fft(y))) / 100)  # divide by 100
# 12.34

您可以在計算FFT之前用零填充數據。

例如,這是您的原始計算。 它找到頻率為12.0時最大幅度的傅立葉系數:

In [84]: freq = 12.3

In [85]: x = np.arange(10000)

In [86]: y = np.cos(x * 2 * np.pi * freq / 10000)

In [87]: f = np.fft.fft(y)

In [88]: k = np.argmax(np.abs(f))

In [89]: np.fft.fftfreq(len(f), d=1/10000)[k]
Out[89]: 12.0

現在重新計算傅立葉變換,但是將輸入的長度填充為原始長度的六倍(您可以根據需要調整該因子)。 對於填充信號,最大幅度的傅立葉系數與頻率12.333相關:

In [90]: f = np.fft.fft(y, 6*len(y))

In [91]: k = np.argmax(np.abs(f))

In [92]: np.fft.fftfreq(len(f), d=1/10000)[k]
Out[92]: 12.333333333333332

這是說明填充信號效果的圖。 信號與上述信號不同; 我使用了更短的信號來使用不同的值,以使其更容易看到效果。 瓣的形狀沒有改變,但是采樣頻率的點數增加了。

情節

該圖由以下腳本生成:

import numpy as np
import matplotlib.pyplot as plt

fs = 10
T = 1.4
t = np.arange(T*fs)/fs

freq = 2.6
y = np.cos(2*np.pi*freq*t)

fy = np.fft.fft(y)
magfy = np.abs(fy)
freqs = np.fft.fftfreq(len(fy), d=1/fs)
plt.plot(freqs, magfy, 'd', label='no padding')

for (factor, markersize) in [(2, 9), (16, 4)]:
    fy_padded = np.fft.fft(y, factor*len(y))
    magfy_padded = np.abs(fy_padded)
    freqs_padded = np.fft.fftfreq(len(fy_padded), d=1/fs)
    plt.plot(freqs_padded, magfy_padded, '.', label='padding factor %d' % factor,
             alpha=0.5, markersize=markersize)

plt.xlabel('Frequency')
plt.ylabel('Magnitude of Fourier Coefficient')
plt.grid()
plt.legend(framealpha=1, shadow=True)

plt.show()

如果S / N允許,您可以嘗試使用插值或零填充(等效於整個矢量插值)來潛在地改善頻率估計。 Sinc核插值比拋物線插值更准確。

暫無
暫無

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

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