2

私は現在、Android用のJavaに取り組んでいます。一種の周波数ビューアを実現するために、FFT を実装しようとしています。

実際にはできましたが、表示がまったく流動的ではありません。コードの各部分の処理時間を確認するためにいくつかのトレースを追加しました。実際には、FFT が 4096 要素を所有する複雑な配列に適用されるのに約 300 ミリ秒かかります。また、(周波数を表示する) スレッドは 100 ミリ秒ごとに更新されるため、100 ミリ秒未満で完了する必要があります。FFT の結果が 1028 要素のみを所有するように、最初の配列を減らしました。これは機能しますが、結果は非推奨です。

誰かがアイデアを持っていますか?

インターネットで見つけられるデフォルトの fft.java および Complex.java クラスを使用しました。

情報については、FFT を計算する私のコードは次のとおりです。

int bytesPerSample = 2;
Complex[] x = new Complex[bufferSize/2] ;

for (int index = 0 ; index < bufferReadResult - bytesPerSample + 1; index += bytesPerSample)
{
// 16BITS = 2BYTES

    float asFloat = Float.intBitsToFloat(asInt);


    double sample = 0;
    for (int b = 0; b < bytesPerSample; b++) {
        int v = buffer[index + b];
        if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                v &= 0xFF;
        }
                        sample += v << (b * 8);
     }

    double sample32 = 100 * (sample / 32768.0); // don't know the use of this compute...
    x[index/bytesPerSample] = new Complex(sample32, 0);
}


    Complex[] tx = new Complex[1024]; // size = 2048 

///// reduction of the size of the signal in order to improve the fft traitment time
for (int i = 0; i < x.length/4; i++)
{

    tx[i] = new Complex(x[i*4].re(), 0);

 }

// Signal retrieval thanks to the FFT
fftRes = FFT.fft(tx);
4

3 に答える 3

0

まず、すべての回答に感謝します。私はそれらに従い、2つのテストを行いました:

  • まず、Complex クラスで使用されている double を float に置き換えます。結果は少し良くなりましたが、十分ではありません。

  • 次に、Complex を使用しないように fft メソッドを書き直しましたが、代わりに 2 次元 float 配列を使用しました。この配列の各行について、最初の列には実部が含まれ、2 番目の列には虚部が含まれます。また、float 配列を onCreate メソッドで 1 回だけインスタンス化するために、コードを変更しました。

そして結果は…最悪!! 300 ミリ秒ではなく 500 ミリ秒を少し超える時間がかかるようになりました。私は今何をすべきかわかりません。

最初の fft 関数の下にあり、次に私が書き直したものがあります。ご協力いただきありがとうございます。

// compute the FFT of x[], assuming its length is a power of 2
public static Complex[] fft(Complex[] x) {
    int N = x.length;

    // base case
    if (N == 1) return new Complex[] { x[0] };

    // radix 2 Cooley-Tukey FFT
    if (N % 2 != 0) { throw new RuntimeException("N is not a power of 2 : " + N); }

    // fft of even terms
    Complex[] even = new Complex[N/2];
    for (int k = 0; k < N/2; k++) {
        even[k] = x[2*k];
    }
    Complex[] q = fft(even);

    // fft of odd terms
    Complex[] odd  = even;  // reuse the array
    for (int k = 0; k < N/2; k++) {
        odd[k] = x[2*k + 1];
    }
    Complex[] r = fft(odd);

    // combine
    Complex[] y = new Complex[N];
    for (int k = 0; k < N/2; k++) {
        double kth = -2 * k * Math.PI / N;
        Complex wk = new Complex(Math.cos(kth), Math.sin(kth));
        y[k]       = q[k].plus(wk.times(r[k]));
        y[k + N/2] = q[k].minus(wk.times(r[k]));
    }

    return y;
}

public static float[][] fftf(float[][] x) {
    /**
     *  x[][0] = real part
     *  x[][1] = imaginary part
     */

    int N = x.length;

    // base case
    if (N == 1) return new float[][] { x[0] };

    // radix 2 Cooley-Tukey FFT
    if (N % 2 != 0) { throw new RuntimeException("N is not a power of 2 : " + N); }

    // fft of even terms
    float[][] even = new float[N/2][2];
    for (int k = 0; k < N/2; k++) {
        even[k] = x[2*k];
    }
    float[][] q = fftf(even);

    // fft of odd terms
    float[][] odd  = even;  // reuse the array
    for (int k = 0; k < N/2; k++) {
        odd[k] = x[2*k + 1];
    }
    float[][] r = fftf(odd);

    // combine
    float[][] y = new float[N][2];
    double kth, wkcos, wksin    ;
    for (int k = 0; k < N/2; k++) {
        kth = -2 * k * Math.PI / N;
        //Complex wk = new Complex(Math.cos(kth), Math.sin(kth));
        wkcos = Math.cos(kth)   ;   // real part
        wksin = Math.sin(kth)   ;   // imaginary part

        //  y[k]       = q[k].plus(wk.times(r[k]));
        y[k][0] = (float) (q[k][0] + wkcos * r[k][0] - wksin * r[k][1]);
        y[k][1] = (float) (q[k][1] + wkcos * r[k][1] + wksin * r[k][0]);

        //  y[k + N/2] = q[k].minus(wk.times(r[k]));
        y[k + N/2][0] = (float) (q[k][0] - (wkcos * r[k][0] - wksin * r[k][1]));
        y[k + N/2][1] = (float) (q[k][1] - (wkcos * r[k][1] + wksin * r[k][0]));
    }

    return y;
}
于 2013-04-01T14:37:14.890 に答える
0

実際、私はすべてを理解していないと思います。

  • まず、Math.cos と Math.sin について: 毎回計算しないようにするにはどうすればよいですか? 値全体を 1 回だけインスタンス化し (たとえば、配列に格納する)、計算ごとに使用する必要があるということですか?
  • 次に、N % 2 についてですが、実際にはあまり役に立ちません。関数を呼び出す前にテストを行うことができました。
  • 第三に、Simon のアドバイスについて: 私は彼の言ったこととあなたの言ったことを混ぜ合わせました。それが彼の提案したものではなかったとしたら、それは何だったのでしょう?
  • 少なくとも、私は FFT の専門家ではないので、「本物の FFT」を作るとはどういう意味ですか? 私の虚数部が役に立たないということですか?コードの後半で、各周波数の大きさを計算するため、sqrt(real[i]*real[i] + imag[i]*imag[i]) となるため、そうである場合はわかりません。そして、私の虚数部はゼロに等しくないと思います...

ありがとう !

于 2013-04-01T22:31:24.223 に答える