/* * Copyright (C) 2015 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. */ package org.drrickorang.loopback; /** * This class computes FFT of inputting data. * Note: this part of code is originally from another project, so there's actually multiple copies * of this code. Should somehow merge these copies in the future. Also, no modification on * naming has been made, but naming should be changed once we merge all copies. */ public class FFT { private int m; private double[] cos; // precomputed cosine tables for FFT private double[] sin; // precomputed sine tables for FFT private final int mFFTSamplingSize; FFT(int FFTSamplingSize) { mFFTSamplingSize = FFTSamplingSize; setUpFFT(); } /** This function is only called in constructor to set up variables needed for computing FFT. */ private void setUpFFT() { m = (int) (Math.log(mFFTSamplingSize) / Math.log(2)); // Make sure n is a power of 2 if (mFFTSamplingSize != (1 << m)) throw new RuntimeException("FFT sampling size must be power of 2"); // precomputed tables cos = new double[mFFTSamplingSize / 2]; sin = new double[mFFTSamplingSize / 2]; for (int i = 0; i < mFFTSamplingSize / 2; i++) { cos[i] = Math.cos(-2 * Math.PI * i / mFFTSamplingSize); sin[i] = Math.sin(-2 * Math.PI * i / mFFTSamplingSize); } } /** * Do FFT, and store the result's real part to "x", imaginary part to "y". */ public void fft(double[] x, double[] y, int sign) { int i, j, k, n1, n2, a; double c, s, t1, t2; // Bit-reverse j = 0; n2 = mFFTSamplingSize / 2; for (i = 1; i < mFFTSamplingSize - 1; i++) { n1 = n2; while (j >= n1) { j = j - n1; n1 = n1 / 2; } j = j + n1; if (i < j) { t1 = x[i]; x[i] = x[j]; x[j] = t1; t1 = y[i]; y[i] = y[j]; y[j] = t1; } } // FFT n1 = 0; n2 = 1; for (i = 0; i < m; i++) { n1 = n2; n2 = n2 + n2; a = 0; for (j = 0; j < n1; j++) { c = cos[a]; s = sign * sin[a]; a += 1 << (m - i - 1); for (k = j; k < mFFTSamplingSize; k = k + n2) { t1 = c * x[k + n1] - s * y[k + n1]; t2 = s * x[k + n1] + c * y[k + n1]; x[k + n1] = x[k] - t1; y[k + n1] = y[k] - t2; x[k] = x[k] + t1; y[k] = y[k] + t2; } } } } }