Неожиданное поведение numpy.fft.fft с высокоточными числами - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть следующий код ... Обратите внимание на две строки под # генерировать синусоиду.Один использует более высокое значение точности для 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.. enter image description here

Однако, если вы запустите код с более высокой точностью 6.283185307179586, равной 2. * numpy.pi, вы получите неожиданный результат ниже ... реальногочасть в корне неверна ... амплитуды далеко, это не симметрично, это не имеет никакого смысла.enter image description here

Я в растерянности относительно того, что вызывает это.У кого-нибудь есть идеи?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Как сказал @Cris Luengo, вам нужно взглянуть на шкалу оси Y, чтобы точно сравнить два графика.Еще один способ сделать это - отобразить обе вещи, которые вы пытаетесь сравнить, на одном и том же рисунке, как я сделал ниже.

Величина БПФ отображается с использованием логарифмической шкалы, иСовершенно очевидно, что использование меньшего числа значащих пи действительно приводит к снижению точности результата.Большинство значений не точно равны нулю, как и следовало ожидать при использовании чисел с плавающей запятой, но использование более значимых цифр дает улучшение на много порядков, что не сразу видно, когда БПФ отображаются отдельно.overlayed fft for various precisions

используемый код:

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()
0 голосов
/ 26 февраля 2019

Это вполне ожидаемое поведение.Компьютеры используют вычисления с плавающей запятой, которые по своей сути неточны.

Обратите внимание на ось Y для вашего реального результата.Если бы не было никакой числовой погрешности, реальный компонент был бы тождественно 0. С вашим результатом «более высокой точности» действительная часть почти идентична 0 (1e-14 очень близко к точности поплавков двойной точности).С более низкой точностью действительная часть становится намного больше (хотя все еще намного, намного меньше, чем мнимая часть).Из-за больших чисел также больше структуры (т. Е. Ошибка определяется не ошибками округления, а фактической характеристикой ваших входных данных, периодом, который немного короче идеального).

...