Two dimensional FFT using python results in slightly shifted frequency

╄→гoц情女王★ 提交于 2020-01-15 03:14:47

问题


I know there have been several questions about using the Fast Fourier Transform (FFT) method in python, but unfortunately none of them could help me with my problem:

I want to use python to calculate the Fast Fourier Transform of a given two dimensional signal f, i.e. f(x,y). Pythons documentation helps a lot, solving a few issues, which the FFT brings with it, but i still end up with a slightly shifted frequency compared to the frequency i expect it to show. Here is my python code:

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

And what i get out of this when running it, is:

Now you see that the frequency in x direction is not exactly at fq = 3, but slightly shifted to the left. Why is this? I would assume that is has to do with the fact, that FFT is an algorithm using symmetry arguments and

half = len(ft) / 2 + 1

is used to show the frequencies at the proper place. But I don't quite understand what the exact problem is and how to fix it.

Edit: I have also tried using a higher sampling frequency (N = 10000.0), which did not solve the issue, but instead shifted the frequency slightly too far to the right. So i am pretty sure that the problem is not the sampling frequency.

Note: I'm aware of the fact, that the leakage effect leads to unphysical amplitudes here, but in this post I am primarily interested in the correct frequencies.


回答1:


I found a number of issues

you use 2 * np.pi twice, you should choose one of either linspace or the arg to sine as radians if you want a nice integer number of cycles

additionally np.linspace defaults to endpoint=True, giving you an extra point for 101 instead of 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

you can check these issues:

len(x)
Out[228]: 100

plt.plot(fnc[0])

fixing the linspace endpoint now means you have an even number of fft bins so you drop the + 1 in the half calc

matshow() appears to have better defaults, your extent = (0, freq_x.max(), 0, freq_y.max()), in imshow appears to fubar the fft bin numbering

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

zoomed the plot:



来源:https://stackoverflow.com/questions/45425355/two-dimensional-fft-using-python-results-in-slightly-shifted-frequency

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!