如何在快速傅立叶变换中正确地缩放频率轴?

2024-04-27 09:49:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试一些简单正弦函数的FFT示例代码。下面是代码

import numpy as np
from matplotlib import pyplot as plt

N = 1024
limit = 10
x = np.linspace(-limit, limit, N)
dx = x[1] - x[0]
y = np.sin(2 * np.pi * 5 * x) + np.sin(2 * np.pi * x)
Y = np.abs(np.fft.fft(y) ** 2)
z = fft.fftshift(np.fft.fftfreq(N, dx))
plt.plot(z[int(N/2):], Y[int(N/2):])
plt.show()

根据给定的函数formula,很明显在频率1和频率5处应该有两个峰值。但是,当我运行这段代码时,我得到了下面的图。在

enter image description here

很明显,尖峰并不是它们应该出现的地方。另外,我注意到频率缩放对点数N以及我做的limit的间隔限制很敏感。作为一个例子,设置N = 2048给出了下面的图。在

在               enter image description here

正如你所见,尖峰的位置已经改变了。现在保持N = 1024并设置limit = 100也会改变结果。在

在               enter image description here

如何使频率轴始终正确缩放?


Tags: 函数代码importfftasnppiplt
1条回答
网友
1楼 · 发布于 2024-04-27 09:49:57

^{}按以下顺序返回频率范围:从最低到最高的正频率,然后按绝对值的相反顺序返回负频率。(您通常只想绘制一半,就像您在代码中所做的那样。)请注意,函数实际上只需要知道很少的数据:只需知道样本的数量和它们在时域中的间距。在

^{}执行实际(快速)傅立叶变换。它对输入采样做了同样的假设,即它是等距的,并以与fftfreq相同的顺序输出傅立叶分量。它不关心实际的频率值:采样间隔不是作为参数传入的。在

但是它接受复数。实际上,这种情况很少见。输入通常是实数的样本,如上例所示。在这种情况下,傅里叶变换有一个特殊的性质:它在频域中是对称的,即对f和{}具有相同的值。由于这个原因,绘制频谱的两部分通常没有意义,因为它们包含相同的信息。在

有一个频率非常突出:f = 0。它是对信号平均值的测量,信号从零开始的偏移量。在fft返回的频谱和{}的频率范围中,它位于第一个数组索引处。如果两个频率的一半都是负的,那么这两个频率的一半都可以左移。在

^{}就是这样。然而,如果你只画出一半的光谱,那么你最好不要费心去做这个。虽然如果你做了,你必须移动两个阵列:频率和傅里叶分量。在你的代码中,你只改变了频率。这就是为什么峰值出现在了频谱的错误一侧:你绘制了Fourier分量,表示频率的正半部分相对于负半部分,所以右边的峰值实际上是接近于零的,而不是在远端。在

你真的不需要依赖那些在频率上运行的功能。仅根据fftfreq的文档就可以直接生成它们的范围:

from numpy.fft import fft
from numpy import arange, linspace, sin, pi as π
from matplotlib import pyplot

def FFT(t, y):
    n = len(t)
    Δ = (max(t) - min(t)) / (n-1)
    k = int(n/2)
    f = arange(k) / (n*Δ)
    Y = abs(fft(y))[:k]
    return (f, Y)

t = linspace(-10, +10, num=1024)
y = sin(2*π * 5*t) + sin(2*π * t)
(f, Y) = FFT(t, y)
pyplot.plot(f, Y)
pyplot.show()

注意,Numpy还为实值数据的常见用例提供专用函数^{}^{}。在

相关问题 更多 >