python - numpy.fft 的有限精度低于某个值
问题描述
我正在尝试计算 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()
解决方案
IEEE 双精度浮点数(您的计算机 CPU 可能在硬件中支持的)具有大约 15 位十进制数字的精度。这是因为只有 53 位尾数(或有效位)。FFT 算法将此误差界限(或量化噪声)增加 O(N*Log(N)),其中 N 是 FFT 长度。
因此,为了获得更高的精度(更低的本底噪声),您可能必须找到或编写自己的 FFT,该 FFT 在内部使用四精度或任意精度算术,并以该格式获取和输入您的数据。
例如,您可以尝试使用 python 的mpmath 包对 FFT 进行编码,然后选择您的精度。
推荐阅读
- python - Django计算含税总价
- asp.net - 如何在没有任何 web 服务和 webapi 的情况下从网站访问和编辑 HTML
- ios - 在 UIImageView 中加载 gif 图像时减少内存消耗
- c# - ListView 在单击时显示模式的详细信息
- merge - 处理多个查询作为一个结果
- excel - 从多个 Excel 文件复制数据
- ionic3 - Ionic 应用程序大小超过 60MB
- c# - 从 Xml 克隆一个节点并在没有 Xml NS 验证的其他地方使用它
- ios - 表格视图单元格中的 uicollection 视图出现错误:索引超出范围,为什么?
- javascript - 浏览器在附加版本控制后也没有选择最新代码?