summaryrefslogtreecommitdiff
path: root/LoopbackApp/app/src/main/java/org/drrickorang/loopback/FFT.java
blob: e69efb01f46ac3645f22953675ce42f215922bd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
 * 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;
                }
            }
        }
    }
}