在 Python 中计算频率区间的值

信息处理 fft 频率 Python scipy
2022-01-19 01:57:18

我必须使用 FFT 来确定信号内波的周期。在信号的 10000 点窗口上应用 FFT 后,我得到如下信息:

在此处输入图像描述

我不明白的是FFT应该返回频率,但是如果输入的是具有相同频率的较长信号,则FFT返回的频率值会发生变化。

那么对于一个长度为 N 的数组,FFT 的结果总是 N/2(去掉对称部分之后),我如何解释这些返回值来得到主频的周期呢?

fft在python中使用scipy提供的函数。

编辑:

一些答案指出了采样频率。我不明白每秒的样本数与周期性模式的大小有什么关系,FFT返回频率对吗?然后对于指定的频率 f,我可以做到t=1/f,然后t将是 300 点。这意味着我们每 300 点就有一个重复模式,我不确定这一点。总而言之,我有一个周期信号,我需要确定周期T0 在此处输入图像描述

3个回答

这就是离散傅里叶变换(即应用于采样信号的傅里叶变换理论)的工作原理。N如果你的输入有 length ,你会得到一个 length 的输出N,并且在移除对称部分之后,你得到的是跨越频率 0(DC 分量)到 Nyquist 频率($\frac{ F_s}{2}$)。

出于同样的原因,您的信号具有的点越多(假设对于固定采样率 $F_s$),您的 FFT 输出的分辨率就越高,因为输出中每个频率区间之间的间距为:$$ \frac{F_s/2 }{N/2} = \frac{F_s}{N} $$


更新:

无论采样频率如何,FFT 都会为具有 $N$ 个样本的输入返回 $N$ 个数据点。我们所说的是输出的所有点都散布在上:$[0;2\pi]$ 以弧度/样本表示,或者有时表示为 $[0;1]$ 以周期/样本(称为归一化频率)。所有这些 bin 对应于每个样本之间可能有多少个周期或振荡。您最多可以在每个样本之间测量半个周期(对于真实信号)。通常只需知道采样率,就可以将其转换回频率。

所以确实,如果你的信号更长,你就会有更长的输出。现在我要指出的是,如果您的信号更长但使用相同的 $F_s$ 记录,即它实际上持续时间更长,那么您将解决更小的频率(因为您总共有更多时间,这会在频域)。也就是说,这些 bin 在频域中彼此更接近($\Delta f = F_s/N = 1/T$ 变小)。因此,基本上,无论采样率如何,您记录的时间越长,您在频域中获得的分辨率就越高。

总而言之,如果您不知道 $F_s$ 垃圾箱的位置(移除对称部分后):

  • 跨度$[0,0.5]$,间隔$1/N$,单位为cycle/sample,或
  • span $[0,\pi]$,间隔$2\pi/N$,单位为弧度/样本

然后,如果您知道 $F_s$,只需转换回Hertz,知道它必须跨越 $[0, F_s/2]$。

就像你说的,去除对称部分后,结果将有大约 $N/2$ 个点。您必须计算对应于第 n 个 bin $f_n$ 的频率: $$f_n = \dfrac{n\cdot F_s}{N}$$

由于您使用的是 Python,因此您可以使用fftfreq函数(它返回负频率而不是高于奈奎斯特的频率)来完成。但是,这是一个如何手动执行的示例:

from __future__ import division
import numpy as np
import matplotlib.pyplot as plt

T = 10  # Duration in seconds
f0 = 100  # Fundamental frequency
Fs = 1000  # Sampling frequency

# Time domain signal
t = np.arange(0, T*Fs)/Fs
x = np.sin(2*np.pi*f0*t)
N = x.size

# DFT
X = np.fft.fft(x)
X_db = 20*np.log10(2*np.abs(X)/N)
#f = np.fft.fftfreq(N, 1/Fs)
f = np.arange(0, N)*Fs/N

plt.plot(f, X_db)
plt.grid()
plt.show()

在此处输入图像描述

如果您使用的是无单位样本(没有给出采样率),那么

T = N/k

其中 T 是样本中的周期长度,N 是样本中的 FFT 长度,k 是感兴趣的 FFT 结果 bin 索引,例如存在局部(或附近)幅度(幅度)峰值的结果 bin。请注意,k 应该使得 k <= N/2,否则您正在查看给定严格真实输入的重复复共轭结果。