Java 减少FFT的处理时间

Java 减少FFT的处理时间,java,android,performance,fft,Java,Android,Performance,Fft,我目前正在为Android开发Java。为了实现一种频率查看器,我尝试实现FFT 事实上我能做到,但显示器一点也不流畅。 为了检查代码每个部分的处理时间,我添加了一些跟踪,事实上,在我的复杂阵列上应用FFT大约需要300毫秒,它拥有4096个元素。我需要不到100毫秒的时间,因为我的线程(显示频率)每100毫秒刷新一次。为了使FFT结果只包含1028个元素,我减少了初始数组,它可以工作,但结果不推荐使用 有人有主意吗 我使用了默认的fft.java和Complex.java类,这些类可以在int

我目前正在为Android开发Java。为了实现一种频率查看器,我尝试实现FFT

事实上我能做到,但显示器一点也不流畅。 为了检查代码每个部分的处理时间,我添加了一些跟踪,事实上,在我的复杂阵列上应用FFT大约需要300毫秒,它拥有4096个元素。我需要不到100毫秒的时间,因为我的线程(显示频率)每100毫秒刷新一次。为了使FFT结果只包含1028个元素,我减少了初始数组,它可以工作,但结果不推荐使用

有人有主意吗

我使用了默认的fft.java和Complex.java类,这些类可以在internet上找到

作为参考,我计算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);
int bytesPerSample=2;
复合体[]x=新复合体[bufferSize/2];
for(int index=0;indexsample+=v我不懂Java,但您在输入数据和复杂值数组之间进行转换的方法似乎非常复杂。您正在构建两个复杂数据数组,其中只需要一个

而且闻起来你的复数实值和虚值都是双精度的。这是你需要的,而且ARMs在双精度运算中速度非常慢。有基于单精度浮点的复杂类吗

第三,通过用零填充复数的虚部,对真实数据执行复数fft。虽然结果是正确的,但马上就要做两倍的工作(除非例程足够聪明,我怀疑这一点)。如果可能,对数据执行实fft,节省一半时间

正如Simon所说,还有避免垃圾收集和内存分配的整个问题

另外,看起来您的FFT没有准备步骤。这意味着例程FFT.FFT()每次都计算复指数。FFT计算中最长的部分是计算复指数,这是一个遗憾,因为对于任何给定的FFT长度,指数都是常数。它们根本不依赖于您的输入数据。在实时世界中,我们使用FFT例程,每次计算一次指数他启动了程序,然后实际的fft本身将常量数组作为其输入之一。不知道您的fft类是否可以执行类似的操作

如果你最终选择了FFTW,那么你必须习惯于从Java调用C代码NEON,ARM对SSE、AVX和Altivec的回答。值得仔细阅读它们的发行说明以进行检查。此外,我强烈怀疑,如果您要求FFTW对单精度浮点而不是双精度浮点执行FFT,FFTW将只能提供显著的加速

谷歌运气

--编辑--


我的意思当然是“祝你好运”。快给我一个真正的键盘,这些触摸屏不可靠…

首先,谢谢你的回答。 我跟着他们做了两个测试:

  • 首先,我用float替换了复杂类中使用的double。结果只是稍微好一点,但还不够

  • 然后我重写了fft方法,不再使用复数,而是一个二维浮点数组。对于这个数组的每一行,第一列包含实部,第二列包含虚部。 我还更改了代码,以便在onCreate方法上仅实例化一次浮点数组

结果…是最糟糕的!!现在需要500多毫秒而不是300毫秒。 我不知道现在该怎么办

你可以在初始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;
}
//计算x[]的FFT,假设其长度为2的幂
公共静态复数[]fft(复数[]x){
int N=x.长度;
//基本情况
如果(N==1)返回新的复数[]{x[0]};
//基2 Cooley-Tukey FFT
如果(N%2!=0){抛出新的RuntimeException(“N不是2的幂:“+N”);}
//偶数项fft
络合物[]偶数=新络合物[N/2];
对于(int k=0;k