Ответ 1
FFTW является "самым быстрым преобразованием Фурье на западе" и имеет некоторые оболочки Java:
Надеюсь, что это поможет!
так как я не хочу делать это сам по себе, я ищу хорошую реализацию FFT для java. Сначала я использовал этот здесь FFT Princeton, но он использует объекты, и мой профилировщик сказал мне, что это не очень быстро из-за этого факта. Поэтому я снова искал googled и нашел это: FFT Columbia, который быстрее. Может быть, один из вас, ребята, знает другую реализацию FFT? Я хотел бы иметь "лучший", потому что мое приложение должно обрабатывать огромное количество звуковых данных, а пользователям не нравится ждать...; -)
С уважением.
FFTW является "самым быстрым преобразованием Фурье на западе" и имеет некоторые оболочки Java:
Надеюсь, что это поможет!
Поздно к партии - здесь, как чистое Java-решение для тех, где JNI не является опцией. JTransforms
Я написал функцию для FFT в Java: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29
Это в общедоступном домене, поэтому вы можете использовать эти функции везде (личные или бизнес-проекты). Просто напишите мне в титрах и отправьте мне только ссылку на вашу работу, и вы в порядке.
Это абсолютно надёжно. Я проверил его выход на Mathematica FFT, и они всегда были правильными до 15-й десятичной цифры. Я думаю, что это очень хорошая реализация FFT для Java. Я написал его на версии 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 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 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;
}
}
Я изучаю использование SSTJ для БПФ в Java. Он может перенаправлять через JNI FFTW, если библиотека доступна или будет использовать чистую реализацию Java, если нет.
Я думаю, это зависит от того, что вы обрабатываете. Если вы рассчитываете БПФ на большую длительность, вы можете обнаружить, что это занимает некоторое время, в зависимости от того, сколько частот вы хотите. Однако в большинстве случаев для аудио считается нестационарным (то есть среднее значение сигналов и вариация меняются со временем), поэтому беря один большой БПФ (Периодограмма PSD) не является точным представлением. В качестве альтернативы вы можете использовать короткое временное преобразование Фурье, посредством чего вы разбиваете сигнал на более мелкие кадры и вычисляете БПФ. Размер кадра варьируется в зависимости от того, насколько быстро изменяется статистика, для речи обычно 20-40 мс, для музыки я предполагаю, что она немного выше.
Этот метод хорош, если вы сэмплируете из микрофона, потому что он позволяет вам буферизовать каждый кадр за раз, вычислять fft и давать то, что чувствует пользователь, - это взаимодействие в реальном времени. Потому что 20 мс быстр, потому что мы не можем ощутить разницу во времени, которая небольшая.
Я разработал небольшую контрольную метку, чтобы проверить разницу между C-библиотеками FFTW и KissFFT на речевом сигнале. Да FFTW очень оптимизирован, но когда вы берете только короткие фреймы, обновляете данные для пользователя и используете только небольшой размер fft, они оба очень похожи. Вот пример того, как реализовать библиотеки KissFFT в Android, используя LibGdx в играх badlogic. Я реализовал эту библиотеку, используя перекрывающиеся кадры в Android-приложении, которое я разработал несколько месяцев назад под названием "Улучшение речи для Android" .