代码之家  ›  专栏  ›  技术社区  ›  InsertNickHere

Java中可靠快速的FFT[闭合]

  •  51
  • InsertNickHere  · 技术社区  · 14 年前

    FFT Princeton 但是它使用了对象,我的探查器告诉我,由于这个事实,它的速度不是很快。所以我又在谷歌上搜索了一下,找到了这个: FFT Columbia

    5 回复  |  直到 14 年前
        2
  •  21
  •   basszero    14 年前

    晚到聚会-这里作为一个纯java的解决方案,当JNI不是一个选项。 JTransforms

        3
  •  13
  •   alcor    8 年前

    我用Java为FFT编写了一个函数: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

    它在公共领域,所以你可以在任何地方使用这些功能(个人或商业项目也一样)。只要引用我的信用证和发送给我只是一个链接,你的工作,你没事。

    它是完全可靠的。我已经对照Mathematica的FFT检查了它的输出,它们一直正确到第15位小数。我认为这是一个非常好的FFT实现。我在j2se1.6版本上编写了它,并在j2se1.5-1.6版本上进行了测试。

    让我知道它是否有用,并告诉我任何你喜欢的评论。

    我在这里共享相同的代码:

    /**
    * @author Orlando Selenu
    *
    */
    public class FFTbase {
    /**
     * The Fast Fourier Transform (generic version, with NO optimizations).
     *
     * @param inputReal
     *            an array of length n, the real part
     * @param inputImag
     *            an array of length n, the imaginary part
     * @param DIRECT
     *            TRUE = direct transform, FALSE = inverse transform
     * @return a new array of length 2n
     */
    public static double[] fft(final double[] inputReal, double[] inputImag,
                               boolean DIRECT) {
        // - n is the dimension of the problem
        // - nu is its logarithm in base e
        int n = inputReal.length;
    
        // If n is a power of 2, then ld is an integer (_without_ decimals)
        double ld = Math.log(n) / Math.log(2.0);
    
        // Here I check if n is a power of 2. If exist decimals in ld, I quit
        // from the function returning null.
        if (((int) ld) - ld != 0) {
            System.out.println("The number of elements is not a power of 2.");
            return null;
        }
    
        // Declaration and initialization of the variables
        // ld should be an integer, actually, so I don't lose any information in
        // the cast
        int nu = (int) ld;
        int n2 = n / 2;
        int nu1 = nu - 1;
        double[] xReal = new double[n];
        double[] xImag = new double[n];
        double tReal, tImag, p, arg, c, s;
    
        // Here I check if I'm going to do the direct transform or the inverse
        // transform.
        double constant;
        if (DIRECT)
            constant = -2 * Math.PI;
        else
            constant = 2 * Math.PI;
    
        // I don't want to overwrite the input arrays, so here I copy them. This
        // choice adds \Theta(2n) to the complexity.
        for (int i = 0; i < n; i++) {
            xReal[i] = inputReal[i];
            xImag[i] = inputImag[i];
        }
    
        // First phase - calculation
        int k = 0;
        for (int l = 1; l <= nu; l++) {
            while (k < n) {
                for (int i = 1; i <= n2; i++) {
                    p = bitreverseReference(k >> nu1, nu);
                    // direct FFT or inverse FFT
                    arg = constant * p / n;
                    c = Math.cos(arg);
                    s = Math.sin(arg);
                    tReal = xReal[k + n2] * c + xImag[k + n2] * s;
                    tImag = xImag[k + n2] * c - xReal[k + n2] * s;
                    xReal[k + n2] = xReal[k] - tReal;
                    xImag[k + n2] = xImag[k] - tImag;
                    xReal[k] += tReal;
                    xImag[k] += tImag;
                    k++;
                }
                k += n2;
            }
            k = 0;
            nu1--;
            n2 /= 2;
        }
    
        // Second phase - recombination
        k = 0;
        int r;
        while (k < n) {
            r = bitreverseReference(k, nu);
            if (r > k) {
                tReal = xReal[k];
                tImag = xImag[k];
                xReal[k] = xReal[r];
                xImag[k] = xImag[r];
                xReal[r] = tReal;
                xImag[r] = tImag;
            }
            k++;
        }
    
        // Here I have to mix xReal and xImag to have an array (yes, it should
        // be possible to do this stuff in the earlier parts of the code, but
        // it's here to readibility).
        double[] newArray = new double[xReal.length * 2];
        double radice = 1 / Math.sqrt(n);
        for (int i = 0; i < newArray.length; i += 2) {
            int i2 = i / 2;
            // I used Stephen Wolfram's Mathematica as a reference so I'm going
            // to normalize the output while I'm copying the elements.
            newArray[i] = xReal[i2] * radice;
            newArray[i + 1] = xImag[i2] * radice;
        }
        return newArray;
    }
    
    /**
     * The reference bitreverse function.
     */
    private static int bitreverseReference(int j, int nu) {
        int j2;
        int j1 = j;
        int k = 0;
        for (int i = 1; i <= nu; i++) {
            j2 = j1 / 2;
            k = 2 * k + j1 - 2 * j2;
            j1 = j2;
        }
        return k;
      }
    }
    
        4
  •  4
  •   digiphd    12 年前

    我想这取决于你在处理什么。如果你在一个大的持续时间内计算FFT,你可能会发现它确实需要一段时间,这取决于你想要多少个频点。然而,在大多数情况下,对于音频,它被认为是非平稳的(即信号的均值和方差随时间变化很大),因此采用一个大的FFT( Periodogram PSD 估计)不是准确的表示。或者可以使用短时傅里叶变换,将信号分解为更小的帧并计算FFT。帧的大小取决于统计数据变化的速度,对于语音,通常是20-40ms,对于音乐,我认为稍高一些。

    KissFFT libraries in Android Speech Enhancement for Android .

        5
  •  4
  •   alcor    9 年前

    SSTJ 用于Java中的FFT。它可以通过JNI重定向到 FFTW 如果库可用,或者如果不可用,将使用纯Java实现。