我正在尝试计算Python中某些信号的傅立叶变换。我希望通过快速傅立叶变换计算出的结果与根据定义计算出的结果一致。但是,使用numpy.fft计算的结果与预期值有出入。
信号未达到某个数值以下。在下图中,它约为10 ^ -16。对于其他信号,它们是可比较的值(从10 ^ -9到10 ^ -30)。在我的应用程序中,我需要更高的精度。
请确保我也测试了scipy.fftpack。尽管计算错误的值略有不同,但仍会出现相同的错误。 问题不取决于信号参数(长度,采样频率等)。
此限制的原因是什么?如果是Python / Numpy准确性,该如何改善?
# Fourier Transform
import numpy as np
import scipy.fftpack as fp
def gaussian_distribution(x,mean=0,variance=1):
return (1 / (np.sqrt(2*np.pi)*variance) ) * np.exp( -((x-mean)**2) / (2 * variance**2) )
def gaussian_fourier_transform(omega, mean=0, variance=1):
# http://mathworld.wolfram.com/FourierTransformGaussian.html
return np.exp(-2 * np.pi**2 * variance**2 * omega**2) * np.exp(-(2j)*np.pi*mean*omega)
## signal generation
signal_range = [-2**4, 2**4]
N = 2**8
x = np.linspace(signal_range[0],signal_range[1],N, dtype='float64')
y = gaussian_distribution(x)
## calculating result
framerate = N / (signal_range[1] - signal_range[0])
frequency_axis = np.linspace(0,framerate,N)
numpy_v = np.abs( np.fft.fft(y) )
numpy_v = numpy_v / numpy_v[0] # normalization
scipy_v = np.abs( fp.fft(y) )
scipy_v = scipy_v / scipy_v[0]
symbolical_v = gaussian_fourier_transform(frequency_axis)
# ploting
import matplotlib.lines as mlines
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot()
ax1.plot(frequency_axis[0: N//2], scipy_v[0: N//2], '.r')
ax1.plot(frequency_axis[0: N//2], numpy_v[0: N//2], '.b')
ax1.plot(frequency_axis[0: N//2], symbolical_v[0: N//2], 'g')
ax1.set_yscale('log')
ax1.grid(True)
blue_line = mlines.Line2D([], [], color='blue', marker='.', markersize=15, label='result calculated by numpy.fft')
red_line = mlines.Line2D([], [], color='red', marker='.', markersize=15, label='result calculated by scipy.fftpack')
green_line = mlines.Line2D([], [], color='green', marker='', markersize=15, label='result calculated by definition')
ax1.legend(handles=[blue_line, red_line, green_line])
fig.show()
答案 0 :(得分:1)
它是numerical issue。
NumPy和SciPy都使用基于PocketFFT的FFTPack的不同变体,属于{em> exact FFT的类别,其误差取决于机器误差ε和样本数N
。
我不确定这些库的确切依赖性是什么,但是您可以尝试pyFFTW,它们是FFTW的Python绑定,而might have则对机器错误的依赖性更好。
答案 1 :(得分:1)
IEEE双精度浮点数(计算机的CPU可能在硬件中支持的数字)的精度大约为15个十进制数字。这是由于只有53位的尾数(或有效位数)。 FFT算法将此误差范围(或量化噪声)增大O(N * Log(N)),其中N是FFT长度。
因此,为了获得更高的精度(较低的本底噪声),您可能必须查找或编写自己的FFT,该FFT内部使用四精度或任意精度算术,并且还以该格式获取和输入数据。 / p>
例如,您可以尝试使用python的mpmath package对FFT进行编码,然后选择精度。
答案 2 :(得分:0)
(类似于其他人已经说过的) 函数的离散傅立叶变换的每个点都取决于初始函数的每个点,这意味着相对误差与输入数据的最大幅度值成比例,并且在某种意义上是全局的。最常见的,就像你观察到的带有长尾和小尾的傅立叶变换在它们的尾部有很大的误差。 如果您的精度是固定的并且您不能进行(部分)解析计算,则无法解决此问题,但您可以使用任意精度库来提高精度。
但是如果进行卷积是您的最终目标,您可能会使用快速多极方法实现局部相对误差达到机器精度。这是否以及如何工作取决于您的内核函数。