Python 为什么不使用Scipy的FFT代码中的结果与Scipy FFT不相似?

Python 为什么不使用Scipy的FFT代码中的结果与Scipy FFT不相似?,python,numpy,matplotlib,scipy,fft,Python,Numpy,Matplotlib,Scipy,Fft,下面的FFT代码没有给出与Python的scipy库类似的结果。但我不知道这段代码出了什么问题 import numpy as np import matplotlib.pyplot as plt #from scipy.fftpack import fft def omega(p, q): return np.exp((-2j * np.pi * p) / q) def fft(x): N = len(x) if N <= 1: return x even =

下面的FFT代码没有给出与Python的
scipy
库类似的结果。但我不知道这段代码出了什么问题

import numpy as np
import matplotlib.pyplot as plt
#from scipy.fftpack import fft

def omega(p, q):
   return np.exp((-2j * np.pi * p) / q)

def fft(x):
   N = len(x)
   if N <= 1: return x
   even = fft(x[0::2])
   odd = fft(x[1::2])
   combined = [0] * N
   for k in range(N//2):
     combined[k] = even[k] + omega(k,N) * odd[k]
     combined[k + N//2] = even[k] - omega(k,N) * odd[k]
   return combined

 N = 600
 T = 1.0 / 800.0
 x = np.linspace(0, N*T, N)
 #y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(80.0 * 2.0*np.pi*x)
 y = np.sin(50.0 * 2.0*np.pi*x)
 xf = np.linspace(0.0, 1.0/(2.0*T), N//2)
 yf = fft(y)
 yfa = 2.0/N * np.abs(yf[0:N//2])
 plt.plot(xf, yfa)
 plt.show()
将numpy导入为np
将matplotlib.pyplot作为plt导入
#从scipy.fftpack导入fft
defω(p,q):
返回np.exp((-2j*np.pi*p)/q)
def fft(x):
N=len(x)
如果N以上所有评论,即舍入错误和实现正确性,都是正确的,但是您遗漏了一件重要的事情。。。只有当采样数
N
为2的幂时,FFT Cooley和Tukey原始算法才有效。你注意到了吗

对于您当前的输入
N=600
,您的输出与numpy/scipy之间存在巨大差异。但是现在,让我们使用2的幂,在本例中,
N=2**9=512
,它给出

np.allclose(yfa,yfa_sp)
>>> True
太好了!这一次的输出是相同的,可以验证输入信号
y
的其他2次幂(尼奎斯特标准除外)大小。对于深入的解释,您可以阅读的公认答案,以理解为什么numpy/scipy fft函数可以允许所有
N
(当
N
是二的幂时效率最高,当
N
为素数时效率最低),而不是像您应该的那样处理此错误,例如

if np.log2(N) % 1 > 0:
    raise ValueError('size of input y must be a power of 2') 
正如评论中所建议的,如果信号的大小不能如此容易地修改,零填充肯定是解决这种采样问题的方法


希望这能有所帮助。

您已经正确地实现了,但还没有完全优化。FFT基本上是函数的能量。所以你可能会得到一点大小的失真。如果要查看实际实现,请参阅绘制scipy版本。差异应该相当小。根据您的排序和优化计算的方式,舍入误差将在不同的地方出现。@Yacoba:噢,非常感谢您的详细解释。这对我来说非常有用……如果你的信号长度不合适,你可以简单地加上零,直到它是二的幂:一个域中的零填充会导致双域中的sinc插值。
if np.log2(N) % 1 > 0:
    raise ValueError('size of input y must be a power of 2')