Спектральный анализ с использованием БПФ, определение основной частоты

Мне нужно выполнить спектральный анализ простого файла wav. Вещи, которые я уже сделал:

Прочитать файл в массив байтов:

ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead = 0;

while ((bytesRead = audioStream.read(buffer)) != -1) {
    baos.write(buffer, 0, bytesRead);
}

fileByteArray = baos.toByteArray();

Затем я преобразовываю его в реальные значения (двойники). У меня есть образцы значений, хранящиеся в массиве double[].

Как я могу сделать БПФ этих выборок + оценить основную частоту?

Используя библиотеку JTranforms, я попробовал что-то вроде этого:

DoubleFFT_1D fft = new DoubleFFT_1D(reader.getSpectrum().getYvalues().length);
double[] x = reader.getSpectrum().getYvalues();
double[] frequencyArray = new double[x.lenght/2];
double[] amplitudeArray = new double[x.lenght/2];
fft.realForward(x);
int i=0;
for (int j = 0; j < x.length-2; j += 2) {
    i++;
    this.frequencyArray[i] = i;
    this.amplitudeArray[i] = Math.sqrt(Math.pow(doub[j],2) + Math.pow(doub[j + 1],2));
}

Это правильно?

Все предложения приветствуются ;)


person adash    schedule 14.05.2012    source источник
comment
Одна проблема заключается в том, что вы, похоже, не применяете подходящую оконную функцию до БПФ.   -  person Paul R    schedule 14.05.2012
comment
функция автокорреляции - еще один способ получения основной частоты.   -  person flies    schedule 14.05.2012


Ответы (2)


Вы должны использовать автокорреляцию, которую можно эффективно вычислить с помощью БПФ:

DoubleFFT_1D fft = new DoubleFFT_1D(reader.getSpectrum().getYvalues().length);
DoubleFFT_1D ifft = new DoubleFFT_1D(reader.getSpectrum().getYvalues().length);

fft.realForward(x);
for (int i = 0; i < x.length/2; i++) {
    x[2*i] = Math.sqrt(Math.pow(x[2*i],2) + Math.pow(x[2*i+1],2));
    x[2*i+1] = 0;
}
ifft.realInverse(x);
for (int i = 1; i < x.length; i++)
    x[i] /= x[0];
x[0] = 1.0;

Этот код дает вам список значений, для которых:

x[i]: корреляция с i сдвигами

Так, например, если у вас высокое значение (близкое к 1) для x[n], это означает, что у вас есть фундаментальный период сигнала: n*(1000/sampleRateHz) мсек. Это эквивалентно частоте: sampleRateHz/(1000*n)

person mostar    schedule 31.08.2012

Значения в массиве частот должны быть связаны с частотой дискретизации и длиной БПФ.

Вам все еще нужно будет решить проблему определения основной частоты по сравнению с пиковыми частотами. Для этого вы можете использовать алгоритм обнаружения/оценки высоты тона, которых существует множество (ищите исследовательские работы по этой теме).

person hotpaw2    schedule 14.05.2012