Чтобы ответить на ваш вопрос напрямую: у вас правильная структура данных (т. Е. list
).Тем не менее, у вас также есть некоторые серьезные проблемы с Python / алгоритмом. Давайте начнем с проблем высокого уровня, а затем перейдем оттуда ...
Прежде всего, то, что у вас есть, наивноDFT, а не FFT .Вопрос помечен БПФ, хотя вы нигде не упоминаете БПФ в самом вопросе, поэтому, возможно, вы уже знаете это, но я подумал, что упомяну это для тех, кто не может этого сделать.БПФ работает в O(N log N)
.То, что у вас есть, работает в O(N^2)
.Большая разница.Они оба выводят одно и то же, так как оба являются преобразованиями Фурье (хотя масштабные коэффициенты могут отличать их с точки зрения реализации), но один из них быстрый (отсюда F FT).Использование наивного DFT обычно не приносит вам большой выгоды: мы используем FFT, потому что они эффективны в вычислительном отношении.Если бы это было не так, мы бы сделали все во временной области и покончили бы с этим!
Во-вторых, ваш отступ / алгоритм неверен. Вам необходимо иметь:
re = 0
im = 0
прямо перед каждым внутренним циклом.Кроме того, у вас должен быть этот раздел (который я изменил для корректности):
# re = re/N This is not a part of the definition, remove it
# im = im/N Also not a part of the definition, remove it
h = (re, im)
X.insert(k, h)
внутри первого цикла.
В-третьих, Python имеет встроенный типпредставлять комплексные числа. Итак, вы хотите:
# There are other (more idiomatic?) ways to create a complex number,
# but this probably looks natural to a Java dev
h = complex(re, im)
Итак, мои модификации, чтобы сделать DFT-код корректным (по определению Википедии), выглядят так:
import math
pi = math.pi
def dft(x):
X=[]
N = len(x)
for k in range(0,N):
re = 0
im = 0
for n in range(0,N):
phi = (2*pi*k*n)/N
re += (x[n]*math.cos(phi))
im -= (x[n]*math.sin(phi))
h = (re, im)
X.insert(k, complex(re, im))
return (X)
Наконец, в Python есть несколько чрезвычайно мощных встроенных и сторонних библиотек, и разумно воспользоваться ими. Хотя numpy
технически не встроен, он так широко используетсячто это также может быть (и я думаю, что на самом деле он поставляется с CPython на MacOS).numpy
будет быстрее, правильнее и будет иметь лучшую функциональность / поддержку / инструментарий, чем все, что вы собираетесь собрать вместе.БПФ уже давно решаемая проблема: нет смысла изобретать велосипед!Вы можете получить numpy
в своей экосистеме с простым pip install numpy
в вашей оболочке (да, это так просто, нет Maven, нет Gradle, нет ANT, нет чепухи!)
После исправлений, описанных выше, мыget:
import numpy as np
def pretty_print_result(x):
for item in x:
print(item)
numpy_result = np.fft.fft([1,2,3,4,5,6]) # <-- This is the most "Pythonic" thing to do imo!
our_result = dft([1,2,3,4,5,6])
print('Numpys: ')
pretty_print_result(numpy_result)
print()
print('Ours: ')
pretty_print_result(our_result)
вывод:
Numpys:
(21+0j)
(-3+5.19615242271j)
(-3+1.73205080757j)
(-3+3.10862446895e-15j)
(-3-1.73205080757j)
(-3-5.19615242271j)
Ours:
(21+0j)
(-3.000000000000001+5.196152422706631j)
(-2.999999999999996+1.7320508075688759j)
(-3-1.286250527486674e-14j)
(-3.0000000000000084-1.7320508075688812j)
(-3.000000000000009-5.196152422706645j)
Это тот же результат, за исключением некоторых махинаций с плавающей запятой.Опять же, numpy
почти наверняка будет более точным и быстрым, чем все, что вы собираетесь собирать вместе, и я не могу рекомендовать его достаточно для научных вычислений.
Быстрое сравнение скорости (после загрузки этого в IPython и сохранения измененной функции dft
в файле с именем test.py
):
In [1]: from test import dft
In [2]: import numpy as np
In [3]: %timeit np.fft.fft([1,2,3,4,5])
The slowest run took 9.24 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 12.5 µs per loop
In [4]: %timeit dft([1,2,3,4,5])
10000 loops, best of 3: 21.7 µs per loop
Хмм выглядит не так уж плохо.Это примерно в два раза быстрее.Но помните, что numpy
алгоритмически быстрее (ну ... он также запускает и собственный код), что означает, что с ростом входных данных сам коэффициент ускорения будет увеличиваться с ростом входных данных:
In [5]: %timeit np.fft.fft(range(1000))
10000 loops, best of 3: 130 µs per loop
In [6]: %timeit dft(range(1000))
1 loop, best of 3: 922 ms per loop
Теперь numpy
более чем в 1000 раз быстрее, и он будет становиться все быстрее и быстрее по сравнению с простой версией при увеличении размера ввода.
HTH!И удачи на вашем пути Python!