我目前正在为 Android 开发 Java。我尝试实现 FFT 以实现一种频率查看器。
实际上我能够做到这一点,但显示根本不流畅。 我添加了一些跟踪来检查代码每个部分的处理时间,事实是 FFT 需要大约 300 毫秒才能应用于我的复杂数组,该数组拥有 4096 个元素。我需要它花费少于 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);
最佳答案
我不懂Java,但你在输入数据和复杂值数组之间进行转换的方式似乎非常复杂。您正在构建两个复杂数据数组,其中只需要一个。
而且,你的复数实值和虚值听起来像是双倍的。这远远超出了你的需求,而且 ARM 在 double 运算上速度非常慢。是否有基于单精度 float 的复杂类?
第三,您通过用零填充复数的虚部来对实际数据执行复数 fft。虽然结果是正确的,但工作量是原来的两倍(除非例程足够聪明来发现这一点,我对此表示怀疑)。如果可能的话,对您的数据执行真正的 fft 并节省一半的时间。
正如西蒙所说,整个问题是避免垃圾收集和内存分配。
此外,您的 FFT 似乎没有准备步骤。这意味着例程 FFT.fft() 每次都在计算复指数。 FFT 计算的最长部分是计算复指数,这很遗憾,因为对于任何给定的 FFT 长度,指数都是常数。它们根本不依赖于您的输入数据。在实时世界中,我们使用 FFT 例程,在程序开始时计算一次指数,然后实际的 fft 本身将该常量数组作为其输入之一。不知道你的FFT类是否可以做类似的事情。
如果您最终确实使用了 FFTW 之类的东西,那么您将不得不习惯于从 Java 调用 C 代码。还要确保您获得支持(我认为)NEON 的版本,NEON 是 ARM 对 SSE、AVX 和 Altivec 的回应。值得仔细阅读他们的发行说明来检查。另外,我强烈怀疑,如果您要求 FFTW 对单精度 float 而不是 double 执行 FFT,FFTW 只能提供显着的加速。
谷歌运气好!
--编辑--
我的意思当然是“祝你好运”。快给我一个真正的键盘,这些触摸屏键盘不可靠......
关于java - 减少FFT的处理时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15734029/