[Python] 쓰기 전용 FFT(빠른 부립엽 변환) 등 광기

사용된 Numpy 함수 + 상수
from numpy import tile, interp, linspace, exp, r_, pi

DFT(느림)

def dft(x):return exp(-2j * pi * r_[:len(x)] / len(x))**r_[[r_[:len(x)]]].T @ x

FFT(2의 제곱 요소 제한)

def fft(x):return tile(fft(x[::2]), 2) + (r_[[[1],[-1]]] * (exp(-2j * pi * r_[:len(x) // 2] / len(x)) * fft(x[1::2]))).ravel() if len(x) > 1 else x

FFT(소수 제한 없음, 길이)

def fft(x):return interp(linspace(0, 1 << (len(f'{len(x) - 1:b}')), len(x)), r_[:1 << (len(f'{len(x) - 1:b}'))], fft(r_[x, [0] * ((1 << (len(f'{len(x) - 1:b}'))) - len(x))])) if ('1' in f'{len(x):b}' [1:]) else tile(fft(x[::2]), 2) + (r_[[[1], [-1]]] * (exp(-2j * pi * r_[:len(x) // 2] / len(x)) * fft(x[1::2]))).ravel() if len(x) > 1 else x

동작 확인

from numpy import sin, fft, random
import matplotlib.pyplot as plt

파형을 변환하다


주파수, 폭은 무작위 5$sin 달러파의 합성, $2048(=2^{11})$원소
n = 1 << 11
x = linspace(0, 2 * pi, n)
y = 0

for w in n / 2 * random.rand(5):
    y += random.rand() * sin(w * x)

plt.plot(x, y, lw = .3)

Numpy.fft.fft

%timeit fft.fft(y)
plt.plot(abs(fft.fft(y))**2)
9.01 µs ± 42.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

DFT

%timeit dft(y)
plt.plot(abs(dft(y))**2)
568 ms ± 899 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

FFT(2의 제곱 요소 제한)

%timeit fft(y)
plt.plot(abs(fft(y))**2)
51.2 ms ± 76.9 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

FFT(긴 모서리)

%timeit fft(y)
plt.plot(abs(fft(y))**2)
54.1 ms ± 159 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

총결산


넘피의 FFT가 너무 빨라!
출력은 일치하지만 FFT에서는 DFT의 약 10배 고속화일 뿐이라는 것을 확인할 수 있다.

좋은 웹페이지 즐겨찾기