2017-07-31 91 views
1

我知道已經有關於使用Python中的快速傅立葉變換(FFT)方法的幾個問題,但不幸的是沒有人能幫助我與我的問題:二維FFT頻移

我希望使用python來計算給定二維信號f的快速傅里葉變換,即f(x,y)。 Pythons的文檔有很多幫助,可以解決FFT帶來的一些問題,但我最終的頻率稍微偏移了一些,而我預計它會顯示頻率。這裏是我的Python代碼:

from scipy.fftpack import fft, fftfreq, fftshift 
import matplotlib.pyplot as plt 
import numpy as np 
import math 

fq = 3.0 # frequency of signal to be sampled 
N = 100.0 # Number of sample points within interval, on which signal is considered 
x = np.linspace(0, 2.0 * np.pi, N) # creating equally spaced vector from 0 to 2pi, with spacing 2pi/N 
y = x 
xx, yy = np.meshgrid(x, y) # create 2D meshgrid 
fnc = np.sin(2 * np.pi * fq * xx) # create a signal, which is simply a sine function with frequency fq = 3.0, modulating the x(!) direction 
ft = np.fft.fft2(fnc) # calculating the fft coefficients 

dx = x[1] - x[0] # spacing in x (and also y) direction (real space) 
sampleFrequency = 2.0 * np.pi/dx 
nyquisitFrequency = sampleFrequency/2.0 

freq_x = np.fft.fftfreq(ft.shape[0], d = dx) # return the DFT sample frequencies 
freq_y = np.fft.fftfreq(ft.shape[1], d = dx) 

freq_x = np.fft.fftshift(freq_x) # order sample frequencies, such that 0-th frequency is at center of spectrum 
freq_y = np.fft.fftshift(freq_y) 

half = len(ft)/2 + 1 # calculate half of spectrum length, in order to only show positive frequencies 

plt.imshow(
    2 * abs(ft[:half,:half])/half, 
    aspect = 'auto', 
    extent = (0, freq_x.max(), 0, freq_y.max()), 
    origin = 'lower', 
    interpolation = 'nearest', 
) 
plt.grid() 
plt.colorbar() 
plt.show() 

什麼運行它時,我得到了這一點,就是:

FFT of signal

現在你看,在X方向的頻率是不完全在fq = 3,但稍微向左移動。爲什麼是這樣? 我會認爲是有事實做,這是FFT使用對稱參數的算法和

half = len(ft)/2 + 1 

被用在合適的地方顯示的頻率。但我不太明白確切的問題是什麼以及如何解決它。

編輯:我也嘗試過使用更高的採樣頻率(N = 10000.0),但這並沒有解決問題,而是將頻率偏移得太偏右。所以我很確定這個問題不是採樣頻率。

注:我意識到泄漏效應導致非物理振幅的事實,但在本文中,我主要關注正確的頻率。

+0

作爲你虎視眈眈h顯示,頻域是量化的 - 似乎你的「問題」是量子不是以你的信號頻率爲中心的。這是JTWIW。你認爲FFT應該神奇地知道輸入有單個頻率分量嗎?如果你想讓它更好的居中,你可以增加樣本數量,或者調整間距。 – barny

+0

當然,FFT不會「神奇地」知道輸入具有單一頻率分量,但正如您所建議的那樣,可以預料,隨着採樣頻率的增加,這種對中會有所改善。我也用「N」來模擬這個數字,它高出幾個數量級(N = 10000.0),這使得頻率稍微偏離了右邊。這使我得出這樣的結論:這裏不是抽樣頻率的問題。 – Alienbash

+0

因此,編輯這個問題的研究,而不是留下可能的答覆者浪費他們的時間,想知道你做了哪些其他的研究,而沒有打擾到這個問題。或者不打擾他們浪費時間。 – barny

回答

1

,我發現了一些問題

您使用2 * np.pi兩次,你應該選擇使用linspace或ARG正弦波作爲弧度之一,如果你想要週期

另外np.linspace默認爲一個不錯的整數endpoint=True,爲您提供的101,而不是100

fq = 3.0 # frequency of signal to be sampled 
N = 100 # Number of sample points within interval, on which signal is considered 
x = np.linspace(0, 1, N, endpoint=False) # creating equally spaced vector from 0 to 2pi, with spacing 2pi/N 
y = x 
xx, yy = np.meshgrid(x, y) # create 2D meshgrid 
fnc = np.sin(2 * np.pi * fq * xx) # create a signal, which is simply a sine function with frequency fq = 3.0, modulating the x(!) direction 

您可以檢查這些問題加分:

len(x) 
Out[228]: 100 

plt.plot(fnc[0]) 

固定linspace端點意味着現在你有一個甚至數FFT箱讓您在half

matshow()似乎有更好的默認值降+ 1,你extent = (0, freq_x.max(), 0, freq_y.max()),imshow似乎FUBAR的FFT二元編號

from scipy.fftpack import fft, fftfreq, fftshift 
import matplotlib.pyplot as plt 
import numpy as np 
import math 

fq = 3.0 # frequency of signal to be sampled 
N = 100 # Number of sample points within interval, on which signal is considered 
x = np.linspace(0, 1, N, endpoint=False) # creating equally spaced vector from 0 to 2pi, with spacing 2pi/N 
y = x 
xx, yy = np.meshgrid(x, y) # create 2D meshgrid 
fnc = np.sin(2 * np.pi * fq * xx) # create a signal, which is simply a sine function with frequency fq = 3.0, modulating the x(!) direction 

plt.plot(fnc[0]) 

ft = np.fft.fft2(fnc) # calculating the fft coefficients 

#dx = x[1] - x[0] # spacing in x (and also y) direction (real space) 
#sampleFrequency = 2.0 * np.pi/dx 
#nyquisitFrequency = sampleFrequency/2.0 
# 
#freq_x = np.fft.fftfreq(ft.shape[0], d=dx) # return the DFT sample frequencies 
#freq_y = np.fft.fftfreq(ft.shape[1], d=dx) 
# 
#freq_x = np.fft.fftshift(freq_x) # order sample frequencies, such that 0-th frequency is at center of spectrum 
#freq_y = np.fft.fftshift(freq_y) 

half = len(ft) // 2 # calculate half of spectrum length, in order to only show positive frequencies 

plt.matshow(
      2 * abs(ft[:half, :half])/half, 
      aspect='auto', 
      origin='lower' 
      ) 
plt.grid() 
plt.colorbar() 
plt.show() 

放大的情節: enter image description here

+0

非常感謝您的努力!這實際上解決了這個問題。 「matshow()」在這裏似乎是合適的選擇。 – Alienbash

+0

這會引發另一個問題:當僅使用'matshow()'而不是'imshow()'時,使用'fftfreq'和'fftshift'多餘的問題不是所有的麻煩嗎? – Alienbash

+0

是的,這些calcs是未使用的,將它們評論出來 – f5r5e5d