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