blob: d684302938fbf1174b0b697ac6342fc81c8d1600 [file] [log] [blame]
/******************************************************************************
*
* Copyright 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include "fft.h"
/* ----------------------------------------------------------------------------
* FFT processing
* -------------------------------------------------------------------------- */
/**
* Tables
*
* T_N[0..N-1] =
* { cos(-2Pi i/N) + j sin(-2Pi i/N),
* cos(-2Pi 2i/N) + j sin(-2Pi 2i/N) } , N=15, 45, 90
*
* T_N[0..N/2-1] =
* cos(-2Pi i/N) + j sin(-2Pi i/N) , N=10, 20, ...
*/
struct fft_bf2_twiddles {
int n2;
const struct fft_complex* t;
};
struct fft_bf3_twiddles {
int n3;
const struct fft_complex (*t)[2];
};
static const struct fft_bf2_twiddles twiddles_10 = {
.n2 = 10 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00},
{8.0901699e-01, -5.8778525e-01},
{3.0901699e-01, -9.5105652e-01},
{-3.0901699e-01, -9.5105652e-01},
{-8.0901699e-01, -5.8778525e-01},
}};
static const struct fft_bf2_twiddles twiddles_20 = {
.n2 = 20 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00},
{9.5105652e-01, -3.0901699e-01},
{8.0901699e-01, -5.8778525e-01},
{5.8778525e-01, -8.0901699e-01},
{3.0901699e-01, -9.5105652e-01},
{6.1232340e-17, -1.0000000e+00},
{-3.0901699e-01, -9.5105652e-01},
{-5.8778525e-01, -8.0901699e-01},
{-8.0901699e-01, -5.8778525e-01},
{-9.5105652e-01, -3.0901699e-01},
}};
static const struct fft_bf2_twiddles twiddles_30 = {
.n2 = 30 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00},
{9.7814760e-01, -2.0791169e-01},
{9.1354546e-01, -4.0673664e-01},
{8.0901699e-01, -5.8778525e-01},
{6.6913061e-01, -7.4314483e-01},
{5.0000000e-01, -8.6602540e-01},
{3.0901699e-01, -9.5105652e-01},
{1.0452846e-01, -9.9452190e-01},
{-1.0452846e-01, -9.9452190e-01},
{-3.0901699e-01, -9.5105652e-01},
{-5.0000000e-01, -8.6602540e-01},
{-6.6913061e-01, -7.4314483e-01},
{-8.0901699e-01, -5.8778525e-01},
{-9.1354546e-01, -4.0673664e-01},
{-9.7814760e-01, -2.0791169e-01},
}};
static const struct fft_bf2_twiddles twiddles_40 = {
.n2 = 40 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.8768834e-01, -1.5643447e-01},
{9.5105652e-01, -3.0901699e-01}, {8.9100652e-01, -4.5399050e-01},
{8.0901699e-01, -5.8778525e-01}, {7.0710678e-01, -7.0710678e-01},
{5.8778525e-01, -8.0901699e-01}, {4.5399050e-01, -8.9100652e-01},
{3.0901699e-01, -9.5105652e-01}, {1.5643447e-01, -9.8768834e-01},
{6.1232340e-17, -1.0000000e+00}, {-1.5643447e-01, -9.8768834e-01},
{-3.0901699e-01, -9.5105652e-01}, {-4.5399050e-01, -8.9100652e-01},
{-5.8778525e-01, -8.0901699e-01}, {-7.0710678e-01, -7.0710678e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.9100652e-01, -4.5399050e-01},
{-9.5105652e-01, -3.0901699e-01}, {-9.8768834e-01, -1.5643447e-01},
}};
static const struct fft_bf2_twiddles twiddles_60 = {
.n2 = 60 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9452190e-01, -1.0452846e-01},
{9.7814760e-01, -2.0791169e-01}, {9.5105652e-01, -3.0901699e-01},
{9.1354546e-01, -4.0673664e-01}, {8.6602540e-01, -5.0000000e-01},
{8.0901699e-01, -5.8778525e-01}, {7.4314483e-01, -6.6913061e-01},
{6.6913061e-01, -7.4314483e-01}, {5.8778525e-01, -8.0901699e-01},
{5.0000000e-01, -8.6602540e-01}, {4.0673664e-01, -9.1354546e-01},
{3.0901699e-01, -9.5105652e-01}, {2.0791169e-01, -9.7814760e-01},
{1.0452846e-01, -9.9452190e-01}, {2.8327694e-16, -1.0000000e+00},
{-1.0452846e-01, -9.9452190e-01}, {-2.0791169e-01, -9.7814760e-01},
{-3.0901699e-01, -9.5105652e-01}, {-4.0673664e-01, -9.1354546e-01},
{-5.0000000e-01, -8.6602540e-01}, {-5.8778525e-01, -8.0901699e-01},
{-6.6913061e-01, -7.4314483e-01}, {-7.4314483e-01, -6.6913061e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.6602540e-01, -5.0000000e-01},
{-9.1354546e-01, -4.0673664e-01}, {-9.5105652e-01, -3.0901699e-01},
{-9.7814760e-01, -2.0791169e-01}, {-9.9452190e-01, -1.0452846e-01},
}};
static const struct fft_bf2_twiddles twiddles_80 = {
.n2 = 80 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9691733e-01, -7.8459096e-02},
{9.8768834e-01, -1.5643447e-01}, {9.7236992e-01, -2.3344536e-01},
{9.5105652e-01, -3.0901699e-01}, {9.2387953e-01, -3.8268343e-01},
{8.9100652e-01, -4.5399050e-01}, {8.5264016e-01, -5.2249856e-01},
{8.0901699e-01, -5.8778525e-01}, {7.6040597e-01, -6.4944805e-01},
{7.0710678e-01, -7.0710678e-01}, {6.4944805e-01, -7.6040597e-01},
{5.8778525e-01, -8.0901699e-01}, {5.2249856e-01, -8.5264016e-01},
{4.5399050e-01, -8.9100652e-01}, {3.8268343e-01, -9.2387953e-01},
{3.0901699e-01, -9.5105652e-01}, {2.3344536e-01, -9.7236992e-01},
{1.5643447e-01, -9.8768834e-01}, {7.8459096e-02, -9.9691733e-01},
{6.1232340e-17, -1.0000000e+00}, {-7.8459096e-02, -9.9691733e-01},
{-1.5643447e-01, -9.8768834e-01}, {-2.3344536e-01, -9.7236992e-01},
{-3.0901699e-01, -9.5105652e-01}, {-3.8268343e-01, -9.2387953e-01},
{-4.5399050e-01, -8.9100652e-01}, {-5.2249856e-01, -8.5264016e-01},
{-5.8778525e-01, -8.0901699e-01}, {-6.4944805e-01, -7.6040597e-01},
{-7.0710678e-01, -7.0710678e-01}, {-7.6040597e-01, -6.4944805e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.5264016e-01, -5.2249856e-01},
{-8.9100652e-01, -4.5399050e-01}, {-9.2387953e-01, -3.8268343e-01},
{-9.5105652e-01, -3.0901699e-01}, {-9.7236992e-01, -2.3344536e-01},
{-9.8768834e-01, -1.5643447e-01}, {-9.9691733e-01, -7.8459096e-02},
}};
static const struct fft_bf2_twiddles twiddles_90 = {
.n2 = 90 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9756405e-01, -6.9756474e-02},
{9.9026807e-01, -1.3917310e-01}, {9.7814760e-01, -2.0791169e-01},
{9.6126170e-01, -2.7563736e-01}, {9.3969262e-01, -3.4202014e-01},
{9.1354546e-01, -4.0673664e-01}, {8.8294759e-01, -4.6947156e-01},
{8.4804810e-01, -5.2991926e-01}, {8.0901699e-01, -5.8778525e-01},
{7.6604444e-01, -6.4278761e-01}, {7.1933980e-01, -6.9465837e-01},
{6.6913061e-01, -7.4314483e-01}, {6.1566148e-01, -7.8801075e-01},
{5.5919290e-01, -8.2903757e-01}, {5.0000000e-01, -8.6602540e-01},
{4.3837115e-01, -8.9879405e-01}, {3.7460659e-01, -9.2718385e-01},
{3.0901699e-01, -9.5105652e-01}, {2.4192190e-01, -9.7029573e-01},
{1.7364818e-01, -9.8480775e-01}, {1.0452846e-01, -9.9452190e-01},
{3.4899497e-02, -9.9939083e-01}, {-3.4899497e-02, -9.9939083e-01},
{-1.0452846e-01, -9.9452190e-01}, {-1.7364818e-01, -9.8480775e-01},
{-2.4192190e-01, -9.7029573e-01}, {-3.0901699e-01, -9.5105652e-01},
{-3.7460659e-01, -9.2718385e-01}, {-4.3837115e-01, -8.9879405e-01},
{-5.0000000e-01, -8.6602540e-01}, {-5.5919290e-01, -8.2903757e-01},
{-6.1566148e-01, -7.8801075e-01}, {-6.6913061e-01, -7.4314483e-01},
{-7.1933980e-01, -6.9465837e-01}, {-7.6604444e-01, -6.4278761e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.4804810e-01, -5.2991926e-01},
{-8.8294759e-01, -4.6947156e-01}, {-9.1354546e-01, -4.0673664e-01},
{-9.3969262e-01, -3.4202014e-01}, {-9.6126170e-01, -2.7563736e-01},
{-9.7814760e-01, -2.0791169e-01}, {-9.9026807e-01, -1.3917310e-01},
{-9.9756405e-01, -6.9756474e-02},
}};
static const struct fft_bf2_twiddles twiddles_120 = {
.n2 = 120 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9862953e-01, -5.2335956e-02},
{9.9452190e-01, -1.0452846e-01}, {9.8768834e-01, -1.5643447e-01},
{9.7814760e-01, -2.0791169e-01}, {9.6592583e-01, -2.5881905e-01},
{9.5105652e-01, -3.0901699e-01}, {9.3358043e-01, -3.5836795e-01},
{9.1354546e-01, -4.0673664e-01}, {8.9100652e-01, -4.5399050e-01},
{8.6602540e-01, -5.0000000e-01}, {8.3867057e-01, -5.4463904e-01},
{8.0901699e-01, -5.8778525e-01}, {7.7714596e-01, -6.2932039e-01},
{7.4314483e-01, -6.6913061e-01}, {7.0710678e-01, -7.0710678e-01},
{6.6913061e-01, -7.4314483e-01}, {6.2932039e-01, -7.7714596e-01},
{5.8778525e-01, -8.0901699e-01}, {5.4463904e-01, -8.3867057e-01},
{5.0000000e-01, -8.6602540e-01}, {4.5399050e-01, -8.9100652e-01},
{4.0673664e-01, -9.1354546e-01}, {3.5836795e-01, -9.3358043e-01},
{3.0901699e-01, -9.5105652e-01}, {2.5881905e-01, -9.6592583e-01},
{2.0791169e-01, -9.7814760e-01}, {1.5643447e-01, -9.8768834e-01},
{1.0452846e-01, -9.9452190e-01}, {5.2335956e-02, -9.9862953e-01},
{2.8327694e-16, -1.0000000e+00}, {-5.2335956e-02, -9.9862953e-01},
{-1.0452846e-01, -9.9452190e-01}, {-1.5643447e-01, -9.8768834e-01},
{-2.0791169e-01, -9.7814760e-01}, {-2.5881905e-01, -9.6592583e-01},
{-3.0901699e-01, -9.5105652e-01}, {-3.5836795e-01, -9.3358043e-01},
{-4.0673664e-01, -9.1354546e-01}, {-4.5399050e-01, -8.9100652e-01},
{-5.0000000e-01, -8.6602540e-01}, {-5.4463904e-01, -8.3867057e-01},
{-5.8778525e-01, -8.0901699e-01}, {-6.2932039e-01, -7.7714596e-01},
{-6.6913061e-01, -7.4314483e-01}, {-7.0710678e-01, -7.0710678e-01},
{-7.4314483e-01, -6.6913061e-01}, {-7.7714596e-01, -6.2932039e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.3867057e-01, -5.4463904e-01},
{-8.6602540e-01, -5.0000000e-01}, {-8.9100652e-01, -4.5399050e-01},
{-9.1354546e-01, -4.0673664e-01}, {-9.3358043e-01, -3.5836795e-01},
{-9.5105652e-01, -3.0901699e-01}, {-9.6592583e-01, -2.5881905e-01},
{-9.7814760e-01, -2.0791169e-01}, {-9.8768834e-01, -1.5643447e-01},
{-9.9452190e-01, -1.0452846e-01}, {-9.9862953e-01, -5.2335956e-02},
}};
static const struct fft_bf2_twiddles twiddles_160 = {
.n2 = 160 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9922904e-01, -3.9259816e-02},
{9.9691733e-01, -7.8459096e-02}, {9.9306846e-01, -1.1753740e-01},
{9.8768834e-01, -1.5643447e-01}, {9.8078528e-01, -1.9509032e-01},
{9.7236992e-01, -2.3344536e-01}, {9.6245524e-01, -2.7144045e-01},
{9.5105652e-01, -3.0901699e-01}, {9.3819134e-01, -3.4611706e-01},
{9.2387953e-01, -3.8268343e-01}, {9.0814317e-01, -4.1865974e-01},
{8.9100652e-01, -4.5399050e-01}, {8.7249601e-01, -4.8862124e-01},
{8.5264016e-01, -5.2249856e-01}, {8.3146961e-01, -5.5557023e-01},
{8.0901699e-01, -5.8778525e-01}, {7.8531693e-01, -6.1909395e-01},
{7.6040597e-01, -6.4944805e-01}, {7.3432251e-01, -6.7880075e-01},
{7.0710678e-01, -7.0710678e-01}, {6.7880075e-01, -7.3432251e-01},
{6.4944805e-01, -7.6040597e-01}, {6.1909395e-01, -7.8531693e-01},
{5.8778525e-01, -8.0901699e-01}, {5.5557023e-01, -8.3146961e-01},
{5.2249856e-01, -8.5264016e-01}, {4.8862124e-01, -8.7249601e-01},
{4.5399050e-01, -8.9100652e-01}, {4.1865974e-01, -9.0814317e-01},
{3.8268343e-01, -9.2387953e-01}, {3.4611706e-01, -9.3819134e-01},
{3.0901699e-01, -9.5105652e-01}, {2.7144045e-01, -9.6245524e-01},
{2.3344536e-01, -9.7236992e-01}, {1.9509032e-01, -9.8078528e-01},
{1.5643447e-01, -9.8768834e-01}, {1.1753740e-01, -9.9306846e-01},
{7.8459096e-02, -9.9691733e-01}, {3.9259816e-02, -9.9922904e-01},
{6.1232340e-17, -1.0000000e+00}, {-3.9259816e-02, -9.9922904e-01},
{-7.8459096e-02, -9.9691733e-01}, {-1.1753740e-01, -9.9306846e-01},
{-1.5643447e-01, -9.8768834e-01}, {-1.9509032e-01, -9.8078528e-01},
{-2.3344536e-01, -9.7236992e-01}, {-2.7144045e-01, -9.6245524e-01},
{-3.0901699e-01, -9.5105652e-01}, {-3.4611706e-01, -9.3819134e-01},
{-3.8268343e-01, -9.2387953e-01}, {-4.1865974e-01, -9.0814317e-01},
{-4.5399050e-01, -8.9100652e-01}, {-4.8862124e-01, -8.7249601e-01},
{-5.2249856e-01, -8.5264016e-01}, {-5.5557023e-01, -8.3146961e-01},
{-5.8778525e-01, -8.0901699e-01}, {-6.1909395e-01, -7.8531693e-01},
{-6.4944805e-01, -7.6040597e-01}, {-6.7880075e-01, -7.3432251e-01},
{-7.0710678e-01, -7.0710678e-01}, {-7.3432251e-01, -6.7880075e-01},
{-7.6040597e-01, -6.4944805e-01}, {-7.8531693e-01, -6.1909395e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.3146961e-01, -5.5557023e-01},
{-8.5264016e-01, -5.2249856e-01}, {-8.7249601e-01, -4.8862124e-01},
{-8.9100652e-01, -4.5399050e-01}, {-9.0814317e-01, -4.1865974e-01},
{-9.2387953e-01, -3.8268343e-01}, {-9.3819134e-01, -3.4611706e-01},
{-9.5105652e-01, -3.0901699e-01}, {-9.6245524e-01, -2.7144045e-01},
{-9.7236992e-01, -2.3344536e-01}, {-9.8078528e-01, -1.9509032e-01},
{-9.8768834e-01, -1.5643447e-01}, {-9.9306846e-01, -1.1753740e-01},
{-9.9691733e-01, -7.8459096e-02}, {-9.9922904e-01, -3.9259816e-02},
}};
static const struct fft_bf2_twiddles twiddles_180 = {
.n2 = 180 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9939083e-01, -3.4899497e-02},
{9.9756405e-01, -6.9756474e-02}, {9.9452190e-01, -1.0452846e-01},
{9.9026807e-01, -1.3917310e-01}, {9.8480775e-01, -1.7364818e-01},
{9.7814760e-01, -2.0791169e-01}, {9.7029573e-01, -2.4192190e-01},
{9.6126170e-01, -2.7563736e-01}, {9.5105652e-01, -3.0901699e-01},
{9.3969262e-01, -3.4202014e-01}, {9.2718385e-01, -3.7460659e-01},
{9.1354546e-01, -4.0673664e-01}, {8.9879405e-01, -4.3837115e-01},
{8.8294759e-01, -4.6947156e-01}, {8.6602540e-01, -5.0000000e-01},
{8.4804810e-01, -5.2991926e-01}, {8.2903757e-01, -5.5919290e-01},
{8.0901699e-01, -5.8778525e-01}, {7.8801075e-01, -6.1566148e-01},
{7.6604444e-01, -6.4278761e-01}, {7.4314483e-01, -6.6913061e-01},
{7.1933980e-01, -6.9465837e-01}, {6.9465837e-01, -7.1933980e-01},
{6.6913061e-01, -7.4314483e-01}, {6.4278761e-01, -7.6604444e-01},
{6.1566148e-01, -7.8801075e-01}, {5.8778525e-01, -8.0901699e-01},
{5.5919290e-01, -8.2903757e-01}, {5.2991926e-01, -8.4804810e-01},
{5.0000000e-01, -8.6602540e-01}, {4.6947156e-01, -8.8294759e-01},
{4.3837115e-01, -8.9879405e-01}, {4.0673664e-01, -9.1354546e-01},
{3.7460659e-01, -9.2718385e-01}, {3.4202014e-01, -9.3969262e-01},
{3.0901699e-01, -9.5105652e-01}, {2.7563736e-01, -9.6126170e-01},
{2.4192190e-01, -9.7029573e-01}, {2.0791169e-01, -9.7814760e-01},
{1.7364818e-01, -9.8480775e-01}, {1.3917310e-01, -9.9026807e-01},
{1.0452846e-01, -9.9452190e-01}, {6.9756474e-02, -9.9756405e-01},
{3.4899497e-02, -9.9939083e-01}, {6.1232340e-17, -1.0000000e+00},
{-3.4899497e-02, -9.9939083e-01}, {-6.9756474e-02, -9.9756405e-01},
{-1.0452846e-01, -9.9452190e-01}, {-1.3917310e-01, -9.9026807e-01},
{-1.7364818e-01, -9.8480775e-01}, {-2.0791169e-01, -9.7814760e-01},
{-2.4192190e-01, -9.7029573e-01}, {-2.7563736e-01, -9.6126170e-01},
{-3.0901699e-01, -9.5105652e-01}, {-3.4202014e-01, -9.3969262e-01},
{-3.7460659e-01, -9.2718385e-01}, {-4.0673664e-01, -9.1354546e-01},
{-4.3837115e-01, -8.9879405e-01}, {-4.6947156e-01, -8.8294759e-01},
{-5.0000000e-01, -8.6602540e-01}, {-5.2991926e-01, -8.4804810e-01},
{-5.5919290e-01, -8.2903757e-01}, {-5.8778525e-01, -8.0901699e-01},
{-6.1566148e-01, -7.8801075e-01}, {-6.4278761e-01, -7.6604444e-01},
{-6.6913061e-01, -7.4314483e-01}, {-6.9465837e-01, -7.1933980e-01},
{-7.1933980e-01, -6.9465837e-01}, {-7.4314483e-01, -6.6913061e-01},
{-7.6604444e-01, -6.4278761e-01}, {-7.8801075e-01, -6.1566148e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.2903757e-01, -5.5919290e-01},
{-8.4804810e-01, -5.2991926e-01}, {-8.6602540e-01, -5.0000000e-01},
{-8.8294759e-01, -4.6947156e-01}, {-8.9879405e-01, -4.3837115e-01},
{-9.1354546e-01, -4.0673664e-01}, {-9.2718385e-01, -3.7460659e-01},
{-9.3969262e-01, -3.4202014e-01}, {-9.5105652e-01, -3.0901699e-01},
{-9.6126170e-01, -2.7563736e-01}, {-9.7029573e-01, -2.4192190e-01},
{-9.7814760e-01, -2.0791169e-01}, {-9.8480775e-01, -1.7364818e-01},
{-9.9026807e-01, -1.3917310e-01}, {-9.9452190e-01, -1.0452846e-01},
{-9.9756405e-01, -6.9756474e-02}, {-9.9939083e-01, -3.4899497e-02},
}};
static const struct fft_bf2_twiddles twiddles_240 = {
.n2 = 240 / 2,
.t = (const struct fft_complex[]){
{1.0000000e+00, -0.0000000e+00}, {9.9965732e-01, -2.6176948e-02},
{9.9862953e-01, -5.2335956e-02}, {9.9691733e-01, -7.8459096e-02},
{9.9452190e-01, -1.0452846e-01}, {9.9144486e-01, -1.3052619e-01},
{9.8768834e-01, -1.5643447e-01}, {9.8325491e-01, -1.8223553e-01},
{9.7814760e-01, -2.0791169e-01}, {9.7236992e-01, -2.3344536e-01},
{9.6592583e-01, -2.5881905e-01}, {9.5881973e-01, -2.8401534e-01},
{9.5105652e-01, -3.0901699e-01}, {9.4264149e-01, -3.3380686e-01},
{9.3358043e-01, -3.5836795e-01}, {9.2387953e-01, -3.8268343e-01},
{9.1354546e-01, -4.0673664e-01}, {9.0258528e-01, -4.3051110e-01},
{8.9100652e-01, -4.5399050e-01}, {8.7881711e-01, -4.7715876e-01},
{8.6602540e-01, -5.0000000e-01}, {8.5264016e-01, -5.2249856e-01},
{8.3867057e-01, -5.4463904e-01}, {8.2412619e-01, -5.6640624e-01},
{8.0901699e-01, -5.8778525e-01}, {7.9335334e-01, -6.0876143e-01},
{7.7714596e-01, -6.2932039e-01}, {7.6040597e-01, -6.4944805e-01},
{7.4314483e-01, -6.6913061e-01}, {7.2537437e-01, -6.8835458e-01},
{7.0710678e-01, -7.0710678e-01}, {6.8835458e-01, -7.2537437e-01},
{6.6913061e-01, -7.4314483e-01}, {6.4944805e-01, -7.6040597e-01},
{6.2932039e-01, -7.7714596e-01}, {6.0876143e-01, -7.9335334e-01},
{5.8778525e-01, -8.0901699e-01}, {5.6640624e-01, -8.2412619e-01},
{5.4463904e-01, -8.3867057e-01}, {5.2249856e-01, -8.5264016e-01},
{5.0000000e-01, -8.6602540e-01}, {4.7715876e-01, -8.7881711e-01},
{4.5399050e-01, -8.9100652e-01}, {4.3051110e-01, -9.0258528e-01},
{4.0673664e-01, -9.1354546e-01}, {3.8268343e-01, -9.2387953e-01},
{3.5836795e-01, -9.3358043e-01}, {3.3380686e-01, -9.4264149e-01},
{3.0901699e-01, -9.5105652e-01}, {2.8401534e-01, -9.5881973e-01},
{2.5881905e-01, -9.6592583e-01}, {2.3344536e-01, -9.7236992e-01},
{2.0791169e-01, -9.7814760e-01}, {1.8223553e-01, -9.8325491e-01},
{1.5643447e-01, -9.8768834e-01}, {1.3052619e-01, -9.9144486e-01},
{1.0452846e-01, -9.9452190e-01}, {7.8459096e-02, -9.9691733e-01},
{5.2335956e-02, -9.9862953e-01}, {2.6176948e-02, -9.9965732e-01},
{2.8327694e-16, -1.0000000e+00}, {-2.6176948e-02, -9.9965732e-01},
{-5.2335956e-02, -9.9862953e-01}, {-7.8459096e-02, -9.9691733e-01},
{-1.0452846e-01, -9.9452190e-01}, {-1.3052619e-01, -9.9144486e-01},
{-1.5643447e-01, -9.8768834e-01}, {-1.8223553e-01, -9.8325491e-01},
{-2.0791169e-01, -9.7814760e-01}, {-2.3344536e-01, -9.7236992e-01},
{-2.5881905e-01, -9.6592583e-01}, {-2.8401534e-01, -9.5881973e-01},
{-3.0901699e-01, -9.5105652e-01}, {-3.3380686e-01, -9.4264149e-01},
{-3.5836795e-01, -9.3358043e-01}, {-3.8268343e-01, -9.2387953e-01},
{-4.0673664e-01, -9.1354546e-01}, {-4.3051110e-01, -9.0258528e-01},
{-4.5399050e-01, -8.9100652e-01}, {-4.7715876e-01, -8.7881711e-01},
{-5.0000000e-01, -8.6602540e-01}, {-5.2249856e-01, -8.5264016e-01},
{-5.4463904e-01, -8.3867057e-01}, {-5.6640624e-01, -8.2412619e-01},
{-5.8778525e-01, -8.0901699e-01}, {-6.0876143e-01, -7.9335334e-01},
{-6.2932039e-01, -7.7714596e-01}, {-6.4944805e-01, -7.6040597e-01},
{-6.6913061e-01, -7.4314483e-01}, {-6.8835458e-01, -7.2537437e-01},
{-7.0710678e-01, -7.0710678e-01}, {-7.2537437e-01, -6.8835458e-01},
{-7.4314483e-01, -6.6913061e-01}, {-7.6040597e-01, -6.4944805e-01},
{-7.7714596e-01, -6.2932039e-01}, {-7.9335334e-01, -6.0876143e-01},
{-8.0901699e-01, -5.8778525e-01}, {-8.2412619e-01, -5.6640624e-01},
{-8.3867057e-01, -5.4463904e-01}, {-8.5264016e-01, -5.2249856e-01},
{-8.6602540e-01, -5.0000000e-01}, {-8.7881711e-01, -4.7715876e-01},
{-8.9100652e-01, -4.5399050e-01}, {-9.0258528e-01, -4.3051110e-01},
{-9.1354546e-01, -4.0673664e-01}, {-9.2387953e-01, -3.8268343e-01},
{-9.3358043e-01, -3.5836795e-01}, {-9.4264149e-01, -3.3380686e-01},
{-9.5105652e-01, -3.0901699e-01}, {-9.5881973e-01, -2.8401534e-01},
{-9.6592583e-01, -2.5881905e-01}, {-9.7236992e-01, -2.3344536e-01},
{-9.7814760e-01, -2.0791169e-01}, {-9.8325491e-01, -1.8223553e-01},
{-9.8768834e-01, -1.5643447e-01}, {-9.9144486e-01, -1.3052619e-01},
{-9.9452190e-01, -1.0452846e-01}, {-9.9691733e-01, -7.8459096e-02},
{-9.9862953e-01, -5.2335956e-02}, {-9.9965732e-01, -2.6176948e-02},
}};
static const struct fft_bf3_twiddles twiddles_15 = {
.n3 = 15 / 3,
.t = (const struct fft_complex[][2]){
{{1.0000000e+0, -0.0000000e+0}, {1.0000000e+0, -0.0000000e+0}},
{{9.1354546e-1, -4.0673664e-1}, {6.6913061e-1, -7.4314483e-1}},
{{6.6913061e-1, -7.4314483e-1}, {-1.0452846e-1, -9.9452190e-1}},
{{3.0901699e-1, -9.5105652e-1}, {-8.0901699e-1, -5.8778525e-1}},
{{-1.0452846e-1, -9.9452190e-1}, {-9.7814760e-1, 2.0791169e-1}},
{{-5.0000000e-1, -8.6602540e-1}, {-5.0000000e-1, 8.6602540e-1}},
{{-8.0901699e-1, -5.8778525e-1}, {3.0901699e-1, 9.5105652e-1}},
{{-9.7814760e-1, -2.0791169e-1}, {9.1354546e-1, 4.0673664e-1}},
{{-9.7814760e-1, 2.0791169e-1}, {9.1354546e-1, -4.0673664e-1}},
{{-8.0901699e-1, 5.8778525e-1}, {3.0901699e-1, -9.5105652e-1}},
{{-5.0000000e-1, 8.6602540e-1}, {-5.0000000e-1, -8.6602540e-1}},
{{-1.0452846e-1, 9.9452190e-1}, {-9.7814760e-1, -2.0791169e-1}},
{{3.0901699e-1, 9.5105652e-1}, {-8.0901699e-1, 5.8778525e-1}},
{{6.6913061e-1, 7.4314483e-1}, {-1.0452846e-1, 9.9452190e-1}},
{{9.1354546e-1, 4.0673664e-1}, {6.6913061e-1, 7.4314483e-1}},
}};
static const struct fft_bf3_twiddles twiddles_45 = {
.n3 = 45 / 3,
.t = (const struct fft_complex[][2]){
{{1.0000000e+0, -0.0000000e+0}, {1.0000000e+0, -0.0000000e+0}},
{{9.9026807e-1, -1.3917310e-1}, {9.6126170e-1, -2.7563736e-1}},
{{9.6126170e-1, -2.7563736e-1}, {8.4804810e-1, -5.2991926e-1}},
{{9.1354546e-1, -4.0673664e-1}, {6.6913061e-1, -7.4314483e-1}},
{{8.4804810e-1, -5.2991926e-1}, {4.3837115e-1, -8.9879405e-1}},
{{7.6604444e-1, -6.4278761e-1}, {1.7364818e-1, -9.8480775e-1}},
{{6.6913061e-1, -7.4314483e-1}, {-1.0452846e-1, -9.9452190e-1}},
{{5.5919290e-1, -8.2903757e-1}, {-3.7460659e-1, -9.2718385e-1}},
{{4.3837115e-1, -8.9879405e-1}, {-6.1566148e-1, -7.8801075e-1}},
{{3.0901699e-1, -9.5105652e-1}, {-8.0901699e-1, -5.8778525e-1}},
{{1.7364818e-1, -9.8480775e-1}, {-9.3969262e-1, -3.4202014e-1}},
{{3.4899497e-2, -9.9939083e-1}, {-9.9756405e-1, -6.9756474e-2}},
{{-1.0452846e-1, -9.9452190e-1}, {-9.7814760e-1, 2.0791169e-1}},
{{-2.4192190e-1, -9.7029573e-1}, {-8.8294759e-1, 4.6947156e-1}},
{{-3.7460659e-1, -9.2718385e-1}, {-7.1933980e-1, 6.9465837e-1}},
{{-5.0000000e-1, -8.6602540e-1}, {-5.0000000e-1, 8.6602540e-1}},
{{-6.1566148e-1, -7.8801075e-1}, {-2.4192190e-1, 9.7029573e-1}},
{{-7.1933980e-1, -6.9465837e-1}, {3.4899497e-2, 9.9939083e-1}},
{{-8.0901699e-1, -5.8778525e-1}, {3.0901699e-1, 9.5105652e-1}},
{{-8.8294759e-1, -4.6947156e-1}, {5.5919290e-1, 8.2903757e-1}},
{{-9.3969262e-1, -3.4202014e-1}, {7.6604444e-1, 6.4278761e-1}},
{{-9.7814760e-1, -2.0791169e-1}, {9.1354546e-1, 4.0673664e-1}},
{{-9.9756405e-1, -6.9756474e-2}, {9.9026807e-1, 1.3917310e-1}},
{{-9.9756405e-1, 6.9756474e-2}, {9.9026807e-1, -1.3917310e-1}},
{{-9.7814760e-1, 2.0791169e-1}, {9.1354546e-1, -4.0673664e-1}},
{{-9.3969262e-1, 3.4202014e-1}, {7.6604444e-1, -6.4278761e-1}},
{{-8.8294759e-1, 4.6947156e-1}, {5.5919290e-1, -8.2903757e-1}},
{{-8.0901699e-1, 5.8778525e-1}, {3.0901699e-1, -9.5105652e-1}},
{{-7.1933980e-1, 6.9465837e-1}, {3.4899497e-2, -9.9939083e-1}},
{{-6.1566148e-1, 7.8801075e-1}, {-2.4192190e-1, -9.7029573e-1}},
{{-5.0000000e-1, 8.6602540e-1}, {-5.0000000e-1, -8.6602540e-1}},
{{-3.7460659e-1, 9.2718385e-1}, {-7.1933980e-1, -6.9465837e-1}},
{{-2.4192190e-1, 9.7029573e-1}, {-8.8294759e-1, -4.6947156e-1}},
{{-1.0452846e-1, 9.9452190e-1}, {-9.7814760e-1, -2.0791169e-1}},
{{3.4899497e-2, 9.9939083e-1}, {-9.9756405e-1, 6.9756474e-2}},
{{1.7364818e-1, 9.8480775e-1}, {-9.3969262e-1, 3.4202014e-1}},
{{3.0901699e-1, 9.5105652e-1}, {-8.0901699e-1, 5.8778525e-1}},
{{4.3837115e-1, 8.9879405e-1}, {-6.1566148e-1, 7.8801075e-1}},
{{5.5919290e-1, 8.2903757e-1}, {-3.7460659e-1, 9.2718385e-1}},
{{6.6913061e-1, 7.4314483e-1}, {-1.0452846e-1, 9.9452190e-1}},
{{7.6604444e-1, 6.4278761e-1}, {1.7364818e-1, 9.8480775e-1}},
{{8.4804810e-1, 5.2991926e-1}, {4.3837115e-1, 8.9879405e-1}},
{{9.1354546e-1, 4.0673664e-1}, {6.6913061e-1, 7.4314483e-1}},
{{9.6126170e-1, 2.7563736e-1}, {8.4804810e-1, 5.2991926e-1}},
{{9.9026807e-1, 1.3917310e-1}, {9.6126170e-1, 2.7563736e-1}},
}};
/**
* FFT 5 Points template
* s Sign -1: Forward 1: Inverse
* x, y Input and output coefficients, of size 5xn
* n Number of interleaved transform to perform
*/
static inline void xfft_5(const float s, const struct fft_complex* x,
struct fft_complex* y, int n) {
static const float cos1 = 0.3090169944; /* cos(-2Pi 1/5) */
static const float cos2 = -0.8090169944; /* cos(-2Pi 2/5) */
static const float sin1 = -0.9510565163; /* sin(-2Pi 1/5) */
static const float sin2 = -0.5877852523; /* sin(-2Pi 2/5) */
for (int i = 0; i < n; i++, x++, y += 5) {
struct fft_complex s14 = {x[1 * n].re + x[4 * n].re,
x[1 * n].im + x[4 * n].im};
struct fft_complex d14 = {x[1 * n].re - x[4 * n].re,
x[1 * n].im - x[4 * n].im};
struct fft_complex s23 = {x[2 * n].re + x[3 * n].re,
x[2 * n].im + x[3 * n].im};
struct fft_complex d23 = {x[2 * n].re - x[3 * n].re,
x[2 * n].im - x[3 * n].im};
y[0].re = x[0].re + s14.re + s23.re;
y[0].im = x[0].im + s14.im + s23.im;
y[1].re = x[0].re + s14.re * cos1 + s * d14.im * sin1 + s23.re * cos2 +
s * d23.im * sin2;
y[1].im = x[0].im + s14.im * cos1 - s * d14.re * sin1 + s23.im * cos2 -
s * d23.re * sin2;
y[2].re = x[0].re + s14.re * cos2 + s * d14.im * sin2 + s23.re * cos1 -
s * d23.im * sin1;
y[2].im = x[0].im + s14.im * cos2 - s * d14.re * sin2 + s23.im * cos1 +
s * d23.re * sin1;
y[3].re = x[0].re + s14.re * cos2 - s * d14.im * sin2 + s23.re * cos1 +
s * d23.im * sin1;
y[3].im = x[0].im + s14.im * cos2 + s * d14.re * sin2 + s23.im * cos1 -
s * d23.re * sin1;
y[4].re = x[0].re + s14.re * cos1 - s * d14.im * sin1 + s23.re * cos2 -
s * d23.im * sin2;
y[4].im = x[0].im + s14.im * cos1 + s * d14.re * sin1 + s23.im * cos2 +
s * d23.re * sin2;
}
}
/**
* FFT Butterfly 3 Points template
* s Sign -1: Forward 1: Inverse
* x, y Input and output coefficients
* twiddles Twiddles factors, determine size of transform
* n Number of interleaved transforms
*/
static inline void xfft_bf3(const float s,
const struct fft_bf3_twiddles* twiddles,
const struct fft_complex* x, struct fft_complex* y,
int n) {
int n3 = twiddles->n3;
const struct fft_complex(*w0)[2] = twiddles->t;
const struct fft_complex(*w1)[2] = w0 + n3, (*w2)[2] = w1 + n3;
const struct fft_complex *x0 = x, *x1 = x0 + n * n3, *x2 = x1 + n * n3;
struct fft_complex *y0 = y, *y1 = y0 + n3, *y2 = y1 + n3;
for (int i = 0; i < n; i++, y0 += 3 * n3, y1 += 3 * n3, y2 += 3 * n3) {
for (int j = 0; j < n3; j++, x0++, x1++, x2++) {
y0[j].re = x0->re + x1->re * w0[j][0].re + s * x1->im * w0[j][0].im +
x2->re * w0[j][1].re + s * x2->im * w0[j][1].im;
y0[j].im = x0->im + x1->im * w0[j][0].re - s * x1->re * w0[j][0].im +
x2->im * w0[j][1].re - s * x2->re * w0[j][1].im;
y1[j].re = x0->re + x1->re * w1[j][0].re + s * x1->im * w1[j][0].im +
x2->re * w1[j][1].re + s * x2->im * w1[j][1].im;
y1[j].im = x0->im + x1->im * w1[j][0].re - s * x1->re * w1[j][0].im +
x2->im * w1[j][1].re - s * x2->re * w1[j][1].im;
y2[j].re = x0->re + x1->re * w2[j][0].re + s * x1->im * w2[j][0].im +
x2->re * w2[j][1].re + s * x2->im * w2[j][1].im;
y2[j].im = x0->im + x1->im * w2[j][0].re - s * x1->re * w2[j][0].im +
x2->im * w2[j][1].re - s * x2->re * w2[j][1].im;
}
}
}
/**
* FFT Butterfly 2 Points template
* s Sign -1: Forward 1: Inverse
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static inline void xfft_bf2(const float s,
const struct fft_bf2_twiddles* twiddles,
const struct fft_complex* x, struct fft_complex* y,
int n) {
int n2 = twiddles->n2;
const struct fft_complex* w = twiddles->t;
const struct fft_complex *x0 = x, *x1 = x0 + n * n2;
struct fft_complex *y0 = y, *y1 = y0 + n2;
for (int i = 0; i < n; i++, y0 += 2 * n2, y1 += 2 * n2) {
for (int j = 0; j < n2; j++, x0++, x1++) {
y0[j].re = x0->re + x1->re * w[j].re + s * x1->im * w[j].im;
y0[j].im = x0->im + x1->im * w[j].re - s * x1->re * w[j].im;
y1[j].re = x0->re - x1->re * w[j].re - s * x1->im * w[j].im;
y1[j].im = x0->im - x1->im * w[j].re + s * x1->re * w[j].im;
}
}
}
/**
* Forward FFT 5 Points
* x, y Input and output coefficients, of size 5xn
* n Number of interleaved transform to perform
*/
static void ffft_5(const struct fft_complex* x, struct fft_complex* y, int n) {
xfft_5(-1, x, y, n);
}
/**
* Inverse FFT 5 Points
* x, y Input and output coefficients, of size 5xn
* n Number of interleaved transform to perform
*/
static void ifft_5(const struct fft_complex* x, struct fft_complex* y, int n) {
xfft_5(1, x, y, n);
}
/**
* Forward FFT Butterfly 3 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ffft_bf3(const struct fft_bf3_twiddles* twiddles,
const struct fft_complex* x, struct fft_complex* y,
int n) {
xfft_bf3(-1, twiddles, x, y, n);
}
/**
* Inverse FFT Butterfly 3 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ifft_bf3(const struct fft_bf3_twiddles* twiddles,
const struct fft_complex* x, struct fft_complex* y,
int n) {
xfft_bf3(1, twiddles, x, y, n);
}
/**
* Forward FFT Butterfly 2 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ffft_bf2(const struct fft_bf2_twiddles* twiddles,
const struct fft_complex* x, struct fft_complex* y,
int n) {
xfft_bf2(-1, twiddles, x, y, n);
}
/**
* InverseIFFT Butterfly 2 Points
* twiddles Twiddles factors, determine size of transform
* x, y Input and output coefficients
* n Number of interleaved transforms
*/
static void ifft_bf2(const struct fft_bf2_twiddles* twiddles,
const struct fft_complex* x, struct fft_complex* y,
int n) {
xfft_bf2(1, twiddles, x, y, n);
}
/**
* Perform FFT
* inverse True on inverse transform else forward
* x, y0, y1 Input, and 2 scratch buffers of size `n`
* n Number of points 30, 40, 60, 80, 90, 120, 160, 180, 240
* return The buffer `y0` or `y1` that hold the result
*
* Input `x` can be the same as the `y0` second scratch buffer
*/
struct fft_complex* fft(bool inverse, const struct fft_complex* x, int n,
struct fft_complex* y0, struct fft_complex* y1) {
static const struct fft_bf3_twiddles* twiddles_bf3[] = {&twiddles_15,
&twiddles_45};
static const struct fft_bf2_twiddles* twiddles_bf2[][3] = {
{&twiddles_10, &twiddles_30, &twiddles_90},
{&twiddles_20, &twiddles_60, &twiddles_180},
{&twiddles_40, &twiddles_120},
{&twiddles_80, &twiddles_240},
{&twiddles_160}};
struct fft_complex* y[2] = {y1, y0};
int i2, i3, is = 0;
/* The number of points `n` can be decomposed as :
*
* n = 5^1 * 3^n3 * 2^n2
*
* for n = 40, 80, 160 n3 = 0, n2 = [3..5]
* n = 30, 60, 120, 240 n3 = 1, n2 = [1..4]
* n = 90, 180 n3 = 2, n2 = [1..2]
*
* Note that the expression `n & (n-1) == 0` is equivalent
* to the check that `n` is a power of 2. */
(inverse ? ifft_5 : ffft_5)(x, y[is], n /= 5);
for (i3 = 0; n & (n - 1); i3++, is ^= 1)
(inverse ? ifft_bf3 : ffft_bf3)(twiddles_bf3[i3], y[is], y[is ^ 1], n /= 3);
for (i2 = 0; n > 1; i2++, is ^= 1)
(inverse ? ifft_bf2 : ffft_bf2)(twiddles_bf2[i2][i3], y[is], y[is ^ 1],
n >>= 1);
return y[is];
}