Java中可靠且快速的FFT

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3287518/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 19:24:40  来源:igfitidea点击:

Reliable and fast FFT in Java

javafft

提问by InsertNickHere

since I don't want to do it on my own, I am searching for a good FFT implementation for java. First I used this one here FFT Princetonbut it uses objects and my profiler told me, that its not really fast due to this fact. So I googled again and found this one: FFT Columbiawhich is faster. Maybe one of you guys know another FFT implementation? I'd like to have the "best" one because my app has to process a huge amount of sound data, and users don't like waiting... ;-)

因为我不想自己做,所以我正在为 java 寻找一个好的 FFT 实现。首先我在这里使用了这个FFT 普林斯顿,但它使用了对象,我的分析器告诉我,由于这个事实,它并不是很快。所以我再次用谷歌搜索并找到了这个:更快的FFT Columbia。也许你们中的一个人知道另一种 FFT 实现?我想要“最好的”,因为我的应用程序必须处理大量的声音数据,而用户不喜欢等待......;-)

Regards.

问候。

采纳答案by Kieren Johnstone

FFTW is the 'fastest fourier transform in the west', and has some Java wrappers:

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

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

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

Hope that helps!

希望有帮助!

回答by Jay R.

I'm looking into using SSTJfor FFTs in Java. It can redirect via JNI to FFTWif the library is available or will use a pure Java implementation if not.

我正在研究在 Java 中使用SSTJ进行 FFT。如果库可用,它可以通过 JNI 重定向到FFTW,否则将使用纯 Java 实现。

回答by basszero

Late to the party - here as a pure java solution for those when JNI is not an option.JTransforms

迟到了——这里是一个纯 Java 解决方案,适用于那些无法选择 JNI 的人。J变换

回答by alcor

I wrote a function for the FFT in Java: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

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

It's in the Public Domain so you can use those functions everywhere (personal or business projects too). Just cite me in the credits and send me just a link of your work, and you're ok.

它属于公共领域,因此您可以在任何地方使用这些功能(个人或商业项目也是如此)。只需在学分中引用我,然后将您的作品链接发送给我,您就可以了。

It is completely reliable. I've checked its output against the Mathematica's FFT and they were always correct until the 15th decimal digit. I think it's a very good FFT implementation for Java. I wrote it on the J2SE 1.6 version, and tested it on the J2SE 1.5-1.6 version.

这是完全可靠的。我已经根据 Mathematica 的 FFT 检查了它的输出,它们在第 15 位十进制数字之前总是正确的。我认为这是一个非常好的 Java FFT 实现。我是在J2SE 1.6版本上写的,在J2SE 1.5-1.6版本上测试过。

If you count the number of instruction (it's a lot much simpler than a perfect computational complexity function estimation) you can clearly see that this version is great even if it's not optimized at all. I'm planning to publish the optimized version if there are enough requests.

如果您计算指令的数量(它比完美的计算复杂度函数估计要简单得多),您可以清楚地看到这个版本很棒,即使它根本没有优化。如果有足够的请求,我计划发布优化版本。

Let me know if it was useful, and tell me any comment you like.

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

I share the same code right here:

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

/**
* @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;
  }
}

回答by digiphd

I guess it depends on what you are processing. If you are calculating the FFT over a large duration you might find that it does take a while depending on how many frequency points you are wanting. However, in most cases for audio it is considered non-stationary (that is the signals mean and variance changes to much over time), so taking one large FFT (Periodogram PSDestimate) is not an accurate representation. Alternatively you could use Short-time Fourier transform, whereby you break the signal up into smaller frames and calculate the FFT. The frame size varies depending on how quickly the statistics change, for speech it is usually 20-40ms, for music I assume it is slightly higher.

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

This method is good if you are sampling from the microphone, because it allows you to buffer each frame at a time, calculate the fft and give what the user feels is "real time" interaction. Because 20ms is quick, because we can't really perceive a time difference that small.

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

I developed a small bench mark to test the difference between FFTW and KissFFT c-libraries on a speech signal. Yes FFTW is highly optimised, but when you are taking only short-frames, updating the data for the user, and using only a small fft size, they are both very similar. Here is an example on how to implement the KissFFT libraries in Androidusing LibGdx by badlogic games. I implemented this library using overlapping frames in an Android App I developed a few months ago called Speech Enhancement for Android.

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