web-dev-qa-db-ja.com

Javaで信頼できる高速FFT

私は自分でそれをしたくないので、Javaの良いFFT実装を探しています。最初に私はここでこれを使用しました FFT Princeton しかし、オブジェクトを使用し、プロファイラーはこの事実のために本当に速くないことを教えてくれました。だから私は再びグーグルでこれを見つけました: FFT Columbia これは速いです。たぶんあなたの誰かが別のFFT実装を知っていますか?私のアプリは膨大な量のサウンドデータを処理する必要があり、ユーザーは待つのが嫌なので、私は「最高の」ものが欲しいのです... ;-)

よろしく。

51
InsertNickHere

FFTWは「西で最も速いフーリエ変換」であり、Javaラッパーがあります。

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

お役に立てば幸いです!

31

パーティーに遅れて-ここでは純粋なJava JNIがオプションではない場合のソリューションとして。 JTransforms

18
basszero

JavaでFFTの関数を作成しました: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

Public Domainにあるため、これらの機能をどこでも使用できます(個人プロジェクトまたはビジネスプロジェクトも)。クレジットで私を引用し、あなたの作品のリンクを送ってください。あなたは大丈夫です。

完全に信頼できます。出力をMathematicaのFFTに対してチェックしましたが、15桁目までは常に正しい結果でした。 Java用の非常に優れたFFT実装だと思います。 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;
  }
}
11
alcor

処理している内容に依存すると思います。長時間にわたってFFTを計算する場合、必要な周波数ポイントの数によっては時間がかかることがあります。ただし、オーディオのほとんどの場合、非定常と見なされます(つまり、信号の平均と分散は時間とともに大きく変化します)。したがって、1つの大きなFFT( 周期表PSD 推定)を取得することは正確な​​表現ではありません。または、短時間フーリエ変換を使用して、信号をより小さなフレームに分割し、FFTを計算することもできます。フレームサイズは、統計の変化の速さによって異なります。音声の場合は通常20〜40ミリ秒、音楽の場合はわずかに高いと思われます。

この方法は、マイクからサンプリングする場合に適しています。これは、一度に各フレームをバッファリングし、fftを計算し、ユーザーが「リアルタイム」インタラクションであると感じるものを与えることができるためです。 20ミリ秒は速いので、それほど小さい時間差を実際に知覚することはできないからです。

音声信号でFFTWとKissFFT cライブラリの違いをテストするための小さなベンチマークを開発しました。はい、FFTWは非常に最適化されていますが、短いフレームのみを取得し、ユーザーのデータを更新し、小さなfftサイズのみを使用している場合、どちらも非常によく似ています。以下は、badlogicゲームでLibGdxを使用して AndroidのKissFFTライブラリ を実装する方法の例です。 Android数か月前に開発したアプリ Android用の音声拡張

4
digiphd

JavaのFFTで [〜#〜] sstj [〜#〜] の使用を検討しています。 JNI経由で [〜#〜] fftw [〜#〜] にリダイレクトできます。ライブラリが利用可能な場合、または利用できない場合は純粋なJava実装を使用します。

4
Jay R.