Java中可靠,快速的FFT

Ins*_*ere 52 java fft

因为我不想自己做,所以我正在为java寻找一个很好的FFT实现.首先我在这里使用了这个FFT普林斯顿,但是它使用了物体而我的探测器告诉我,由于这个事实它并不是很快.所以我再次搜索并发现了这一点:FFT哥伦比亚更快.也许你们其中一个人知道另一个FFT实现?我想拥有"最好的",因为我的应用程序必须处理大量的声音数据,用户不喜欢等待... ;-)

问候.

Kie*_*one 30

FFTW是"西方最快的傅立叶变换",并且有一些Java包装器:

http://www.fftw.org/download.html

希望有所帮助!

  • apache-commons的FastFourierTransformer类怎么样? (5认同)
  • 请注意,FFTW受GPL许可证保护.(非限制版本,限制较少的许可证) (4认同)

bas*_*ero 18

迟到了 - 这里作为纯粹的Java解决方案,适用于JNI不可选的人.JTransforms


alc*_*cor 12

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

它位于公共域中,因此您可以在任何地方使用这些功能(个人或商业项目).只需在信用卡中引用我,然后向我发送您工作的链接,您就可以了.

它完全可靠.我已经根据Mathematica的FFT检查了它的输出,它们总是正确的,直到第15个十进制数字.我认为这是一个非常好的Java实现.我在J2SE 1.6版本上编写了它,并在J2SE 1.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;
  }
}
Run Code Online (Sandbox Code Playgroud)


dig*_*phd 5

我想这取决于您正在处理的内容。如果您在长时间内计算 FFT,您可能会发现它确实需要一段时间,具体取决于您想要的频率点数量。然而,在大多数情况下,音频被认为是非平稳的(即信号均值和方差随时间变化很大),因此采用一个大的 FFT(周期图 PSD估计)并不是一种准确的表示。或者,您可以使用短时傅立叶变换,将信号分解为更小的帧并计算 FFT。帧大小取决于统计数据变化的速度,对于语音,通常为 20-40 毫秒,对于音乐,我认为它略高。

如果您从麦克风采样,这种方法很好,因为它允许您一次缓冲每一帧,计算 fft 并给用户感觉是“实时”交互。因为 20ms 很快,因为我们无法真正感知到那么小的时差。

我开发了一个小基准来测试语音信号上 FFTW 和 KissFFT c 库之间的差异。是的 FFTW 是高度优化的,但是当您只拍摄短帧、为用户更新数据并且仅使用较小的 fft 大小时,它们都非常相似。下面是一个关于如何通过 badlogic 游戏使用 LibGdx在 Android 中实现KissFFT 库的示例。我在几个月前开发的名为Speech Enhancement for Android的 Android 应用程序中使用重叠帧实现了这个库。