Niedawno znalazłem ten znakomity PDF na Construction of a high performance FFTs przez Eric Postpischil. Po samodzielnym opracowaniu kilku FFT wiem, jak trudno konkurować z bibliotekami komercyjnymi. Uwierz mi, że masz się dobrze, jeśli twój FFT jest tylko 4x wolniejszy niż Intel lub FFTW, a nie 40x! Możesz jednak rywalizować, a oto jak.
Podsumowując ten artykuł, autor stwierdza, że FFT Radix2 są proste, ale nieefektywne, najbardziej wydajną konstrukcją jest FFT. Jeszcze bardziej wydajną metodą jest Radix8, jednak często nie pasuje do rejestrów na CPU, więc Radix4 jest preferowany.
FFT można budować etapami, więc aby obliczyć FFT 1024 point można wykonać 10 etapów Radix2 FFT (jako 2^10 - 1024) lub 5 etapów Radix4 FFT (4^5 = 1024) . Można nawet obliczyć FFT o 1024 punktach w etapach 8 * 4 * 4 * 4 * 2, jeśli tak zdecydujesz.Mniejsza liczba etapów oznacza mniejszą liczbę odczytów i zapisów w pamięci (wąskim gardłem dla wydajności FFT jest przepustowość pamięci), dlatego dynamiczne wybieranie radixów 4, 8 lub wyższych jest koniecznością. Etap Radix4 jest szczególnie wydajny, ponieważ wszystkie wagi wynoszą 1 + 0i, 0 + 1i, -1 + 0i, 0-1i, a kod motyla Radix4 można zapisać tak, aby zmieścił się całkowicie w pamięci podręcznej.
Po drugie, każdy etap w FFT nie jest taki sam. Pierwszy stopień wagi jest równy 1 + 0i. nie ma sensu obliczanie tego ciężaru, a nawet pomnożenie przez niego, ponieważ jest to pomnożenie złożone przez 1, więc pierwszy etap można wykonać bez ciężarków. Ostatni etap może być również traktowany inaczej i może być użyty do przeprowadzenia Decymacji w Czasie (odwrócenie bitowe). Dokument Erica Postpischila obejmuje to wszystko.
Wagi można wstępnie obliczyć i zapisać w tabeli. Obliczenia sin/cos zajmują około 100-150 cykli każdy na sprzęcie x86, więc ich wstępne obliczenia mogą zaoszczędzić 10-20% całkowitego czasu obliczeń, ponieważ dostęp do pamięci jest w tym przypadku szybszy niż obliczenia procesora. Używanie szybkich algorytmów do obliczania sincos w jednym przejściu jest szczególnie korzystne (zauważ, że cos jest równe sqrt (1.0 - sinus * sinus), lub przy użyciu wyszukiwań tabel, cos jest po prostu przesunięciem fazowym sinusa).
W końcu, gdy masz już super usprawnioną implementację FFT, możesz wykorzystać wektoryzację SIMD do obliczenia 4x operacji zmiennoprzecinkowych lub 2x podwójnych operacji zmiennoprzecinkowych na cykl w ramach procedury motylkowej, aby uzyskać kolejną poprawę prędkości o 100-300%. Biorąc wszystkie powyższe, będziesz miał całkiem sprytny i szybki FFT!
Aby przejść dalej, można przeprowadzić optymalizację w locie, zapewniając różne implementacje etapów FFT skierowanych do określonych architektur procesorów. Rozmiar pamięci podręcznej, liczba rejestrów, zestawy instrukcji SSE/SSE2/3/4 itp. Różnią się w zależności od maszyny, dlatego wybór jednego rozmiaru pasuje do wszystkich podejść jest często bity przez ukierunkowane procedury. W FFTW na przykład wiele mniejszych rozmiarów FFT to wysoce zoptymalizowane rozwijane (bez pętli) implementacje ukierunkowane na konkretną architekturę. Łącząc te mniejsze konstrukcje (takie jak procedury RadixN), możesz wybrać najszybszą i najlepszą procedurę dla danego zadania.
Jeśli nie musisz sam tego pisać w celach związanych ze zrozumieniem, FFTW (http://www.fftw.org/) jest świetną biblioteką. Jest to samonastawna, superszybka i niezawodna implementacja, którą możesz nazwać z C++ dobrze (zobacz http://www.fftw.org/faq/section2.html#cplusplus). –
Bardzo lubiłem FFTReal. http://ldesoras.free.fr/prod.html –
Dlaczego piszesz własną implementację zamiast używać jednej z niezliczonych bibliotek tam, które prawdopodobnie są szybsze, lepiej przetestowane, dokładniejsze i mają więcej funkcji? – PlasmaHH