2012-05-19 3 views
2

Я хочу построить частотный спектр музыкального файла (как, например, в Audacity). Следовательно, я хочу, чтобы частота в Герце по оси х и амплитуда (или децибел) на оси у.Как нарисовать частотный спектр из преобразования Фурье

Я разделяю песню (около 20 миллионов образцов) на блоки по 4096 выборок за раз. Эти блоки приведут к комплексным числам 2049 (N/2 + 1) (синусоидальная и косинусная -> реальная и мнимая часть). Итак, теперь у меня есть эти тысячи индивидуальных 2049-массивов, как их объединить?

Допустим, что я делаю FFT 5000 раз, в результате получается 5000 массивов 2049 комплексных чисел. Имею ли я все значения 5000 массивов, а затем беру величину объединенного массива 2049? Затем я присваиваю ось х с частотой выборки песен/2 (например: 22050 для файла 44100 Гц)?

Любая информация будет appriciated

ответ

2

Что применения вы используете для этого? Я предполагаю, что вы не делаете это вручную, так вот пример Matlab:

>> fbins = fs/N * (0:(N/2 - 1)); % Where N is the number of fft samples

теперь вы можете выполнить

>> plot(fbins, abs(fftOfSignal(1:N/2)))

Stolen

редактировать: проверить это http://www.codeproject.com/Articles/9388/How-to-implement-the-FFT-algorithm

+0

Я пишу свою собственную программу на С ++. Можете ли вы объяснить пример выше. Что такое 0: и 1: meen и что такое fs? – goocreations

+0

fs = частота выборки, 0: x = все шаги от нуля до x, то же самое для 1: N/2. абс = абсолютное значение. Концом является график (x, y), поэтому fbins - это x, а остальное - y – chwi

+0

В следующий раз оставьте ссылку на pastebin со своим C-кодом, мне немного любопытно, как вы это решите :) – chwi

1

Обычно вы берете только один из массивов , что соответствует моменту времени музыки, в которой вас интересует. Вы вычислили бы журнал величины каждого сложного элемента массива. Постройте результаты N/2 как значения Y и масштабируйте ось X от 0 до Fs/2 (где Fs - частота дискретизации).

+0

Спасибо, но я не просто хочу, чтобы на секунду или около того, но на всю песню. – goocreations

+0

Если длина БПФ равна N, почему вы строите только N/2? – Anita

+0

Для строго реального ввода данных вторая половина результата FFT представляет собой только сопряженное зеркало первой половины (например, избыточное). Половина над N/2 полезна только (разная), если данные временной области сложны (как реальные, так и мнимые компоненты отличны от нуля). – hotpaw2

2

Возможно, это неверно, но, насколько мне известно, у вас есть 2 способа получить спектр всей песни.

1) Сделайте один БПФ на всей песне, что даст вам очень хорошее частотное разрешение, но на практике неэффективно, и вам не нужно такое разрешение в любом случае.

2) Разделите его на небольшие куски (например, 4096 образцов блоков, как вы сказали), получите БПФ для каждого из них и усредняйте спектры. Вы будете компрометировать частотное разрешение, но сделайте расчет более управляемым (а также уменьшите дисперсию спектра). Ссылка Wilhelmsen описывает, как вычислить БПФ на C++, и я думаю, что некоторая библиотека уже существует для этого, как FFTW (но мне никогда не удалось ее скомпилировать, чтобы быть справедливым =)).

Чтобы получить спектр амплитуды, усредняйте энергию (квадрат величины) по всему, что вы куски для каждого отдельного бункера. Чтобы получить результат в дБ, всего 10 * log10 - результаты. Это, конечно, предполагает, что вас не интересует фазовый спектр. Я думаю, что это известно как Barlett's method.

Я хотел бы сделать что-то вроде этого:

// At this point you have the FFT chunks 

float sum[N/2+1]; 

// For each bin 
for (int binIndex = 0; binIndex < N/2 + 1; binIndex++) 
{ 
    for (int chunkIndex = 0; chunkIndex < chunkNb; chunkIndex++) 
    { 
     // Get the magnitude of the complex number 
     float magnitude = FFTChunk[chunkIndex].bins[binIndex].real * FFTChunk[chunkIndex].bins[binIndex].real 
      + FFTChunk[chunkIndex].bins[binIndex].im * FFTChunk[chunkIndex].bins[binIndex].im; 

     magnitude = sqrt(magnitude); 

     // Add the energy 
     sum[binIndex] += magnitude * magnitude; 
    } 

    // Average the energy; 
    sum[binIndex] /= chunkNb; 
} 

// Then get the values in decibel 
for (int binIndex = 0; binIndex < N/2 + 1; binIndex++) 
{ 
    sum[binIndex] = 10 * log10f(sum[binIndex]); 
} 

Надеется, что это отвечает на ваш вопрос.

Edit: пост GoZ даст вам много информации по этому вопросу =)

+0

Я пытаюсь реализовать это для Java. Я не понимаю, почему вы только перебираете N/2, а не N? – Stefan

2

Wow Я написал нагрузку об этом совсем недавно.

Я даже превратил его в сообщение в блоге here.

Мое объяснение склоняется к спектрограммам, но так же легко отобразить диаграмму, как вы описываете!

+0

Веб-сайт не работает. Показывает ошибку в подключении к базе данных – CyprUS