blob: e69efb01f46ac3645f22953675ce42f215922bd5 [file] [log] [blame]
/*
* 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;
}
}
}
}
}