Python 具有高精度数字的numpy.fft.fft的意外行为

Python 具有高精度数字的numpy.fft.fft的意外行为,python,numpy,fft,Python,Numpy,Fft,我有以下代码…注意#生成正弦曲线下的两行。其中一个使用了比另一个更高的2pi精度值,但它们仍应给出几乎相同的结果 import numpy as np import matplotlib.pyplot as plt t1 = np.arange(0., 1., .01) # generate sine curve y1 = np.sin(6.28318*5.*t1) #y1 = np.sin(6.283185307179586*5.*t1) # equivalent to np.sin

我有以下代码…注意#生成正弦曲线下的两行。其中一个使用了比另一个更高的2pi精度值,但它们仍应给出几乎相同的结果

import numpy as np
import matplotlib.pyplot as plt


t1 = np.arange(0., 1., .01)

# generate sine curve
y1 = np.sin(6.28318*5.*t1)  
#y1 = np.sin(6.283185307179586*5.*t1) # equivalent to np.sin(2*np.pi*t1)

# calculate the fft (no averaging!) of the time series
ffty = np.fft.fft(y1)

fig, ax_list = plt.subplots(3,1)
ax_list[0].plot(t1,y1, '.-')

ax_list[1].plot(ffty.real, '.-', label='Real Part')
ax_list[1].legend()

ax_list[2].plot(ffty.imag, '.-', label='Imag Part')
ax_list[2].legend()


plt.show()
如果以较低的精度6.28318运行代码,则会得到fft的预期结果。。。

但是,如果以更高的精度运行代码6.283185307179586,该精度等于2.*numpy.pi,则会得到以下意外结果。。。真实的部分是完全错误的…振幅太远了,它不是对称的,没有任何意义。


我不知道这是什么原因造成的。有人有什么想法吗?

这完全是意料之中的行为。计算机使用浮点计算,这本身就是不精确的


请注意实际结果的y轴。如果不存在数值不准确性,则实际分量相同为0。使用“更高精度”结果,实际零件几乎与0相同(1e-14非常接近双精度浮点的精度)。精度越低,实部就越大(尽管仍然比虚部小得多)。由于数字较大,结构也较多(即,误差不是由舍入误差给出的,而是由输入数据的实际特征给出的,周期比理想值略短)。

这完全是预期行为。计算机使用浮点计算,这本身就是不精确的


请注意实际结果的y轴。如果不存在数值不准确性,则实际分量相同为0。使用“更高精度”结果,实际零件几乎与0相同(1e-14非常接近双精度浮点的精度)。精度越低,实部就越大(尽管仍然比虚部小得多)。由于数字较大,结构也较多(即误差不是由舍入误差给出的,而是由输入数据的实际特征给出的,周期比理想值略短)。

正如@Cris Luengo所说,您需要查看y轴的比例,以准确比较两个图。另一种方法是在同一个图上绘制两个你想要比较的东西,正如我在下面所做的

FFT的大小是用对数刻度显示的,很明显,使用较少的pi有效数字确实会导致精度较低的结果。 大多数值并非如使用浮点数时所预期的那样完全为零,但使用更有效的数字会带来许多数量级的改进,这在单独绘制FFT时并不明显。

使用的代码:

import numpy as np
import matplotlib.pyplot as plt


t1 = np.arange(0., 1., .01)

values = {
'low':6.28318,
'higher':6.283185307179586,
'highest':2*numpy.pi,
}
styles = {
'low':'-',
'higher':'-',
'highest':'.-'
}

fig, ax_list = plt.subplots(3,1)
for name, tau in values.items():
    y1 = np.sin(tau*5.*t1)
    ffty = np.fft.fft(y1)

    ax_list[0].plot(t1,y1, styles[name], label=name)
    ax_list[1].plot(abs(ffty.real), styles[name],label=name)
    ax_list[2].plot(abs(ffty.imag), styles[name], label=name)

[ax.legend() for ax in ax_list]
ax_list[0].set_title('time domain')
ax_list[1].set_title('real part')
ax_list[2].set_title('imaginary part')
ax_list[1].set_yscale('log')
ax_list[2].set_yscale('log')
plt.draw()

正如@Cris Luengo所说的,你需要查看y轴的比例来准确地比较两个图。另一种方法是在同一个图上绘制两个你想要比较的东西,正如我在下面所做的

FFT的大小是用对数刻度显示的,很明显,使用较少的pi有效数字确实会导致精度较低的结果。 大多数值并非如使用浮点数时所预期的那样完全为零,但使用更有效的数字会带来许多数量级的改进,这在单独绘制FFT时并不明显。

使用的代码:

import numpy as np
import matplotlib.pyplot as plt


t1 = np.arange(0., 1., .01)

values = {
'low':6.28318,
'higher':6.283185307179586,
'highest':2*numpy.pi,
}
styles = {
'low':'-',
'higher':'-',
'highest':'.-'
}

fig, ax_list = plt.subplots(3,1)
for name, tau in values.items():
    y1 = np.sin(tau*5.*t1)
    ffty = np.fft.fft(y1)

    ax_list[0].plot(t1,y1, styles[name], label=name)
    ax_list[1].plot(abs(ffty.real), styles[name],label=name)
    ax_list[2].plot(abs(ffty.imag), styles[name], label=name)

[ax.legend() for ax in ax_list]
ax_list[0].set_title('time domain')
ax_list[1].set_title('real part')
ax_list[2].set_title('imaginary part')
ax_list[1].set_yscale('log')
ax_list[2].set_yscale('log')
plt.draw()

你的意思是,如果我在numpy.sin中使用numpy.pi来生成正弦波,然后将其放入numpy.fft.fft。。。然后对结果的真实部分胡言乱语…这是预期的行为?No@JWebster:这不是胡言乱语,而是舍入错误。你注意到y轴顶端的“1e-14”了吧?如果你真的希望双精度浮点计算是无错误的,你需要做更多的阅读。你可以从这里开始:@JWebster:好吧,如果这就是你想相信的,那就这样吧。祝你好运找到一个FFT工具,给你一些不同的东西。像我建议的那样设置轴的极限,然后再告诉我真实部分与零的区别。嗯……所以,也许这对我来说是一个可教的时刻。这是否意味着误差实际上是在“低精度”实部中存在5Hz的尖峰?正确的结果是“高精度”的情况,所有的值几乎都是零?我可以看到…我想我只是期待在5赫兹的峰值,所以当我没有看到他们。。。我还希望结果能反映在正频率和负频率上,但是,是的,这只是浮点数stuff@JWebster:是的,正弦具有纯假想的频谱。请注意,虚部越大,噪声方差越大——复值的幅值越大,因此舍入误差也越大。这就是为什么在第二种情况下,真实部分会出现峰值。在第一种情况下,因为你的周期比理想值稍小,信号并不完全是奇数,因此变换也不完全是假想的,它有一个小的实数分量,与空间域的小偶数分量相匹配。所以你是说,如果我在numpy.sin中使用numpy.pi来生成正弦波,然后把它输入numpy.fft.fft。。。然后对结果的真实部分胡言乱语…这是预期的行为?No@JWebster:这不是胡言乱语,而是舍入错误。你注意到y轴顶端的“1e-14”了吧?如果你真的希望双精度浮点计算是无错误的,你需要做更多的阅读。你可以从这里开始:@JWebster:好吧,如果这就是你想相信的,那就这样吧。祝你好运找到一个FFT工具,给你一些不同的东西。像我建议的那样设置轴的极限,然后再告诉我真实部分与零的区别。嗯……所以,也许这对我来说是一个可教的时刻。这是否意味着误差实际上是在“低精度”真实频率中存在5Hz的峰值