FFT - Применение окна к данным PCM

В настоящее время я пытаюсь воспроизвести функцию getSpectrum аудиобиблиотеки FMOD. Эта функция считывает данные PCM текущего воспроизводимого буфера, применяет окно к этим данным и применяет FFT для получения спектра.

Он возвращает массив чисел с плавающей запятой, где каждое число с плавающей запятой находится в диапазоне от 0 до 1 дБ (10.0f * ( float)log10(val) * 2.0f).

Я не уверен, что я делаю, это то, что я должен делать, поэтому я объясню это:

Во-первых, я получаю данные PCM в буфере размером 4096 байт. Согласно документации, данные PCM состоят из выборок, представляющих собой пару данных слева-направо.

данные

В моем случае я работаю с 16-битными образцами, как на изображении выше. Итак, если я хочу работать только с левым каналом, я сохраняю данные левого PCM в коротком массиве, делая:

short *data = malloc(4096);
FMOD_Sound_ReadData(sound, (void *)data, 4096, &read);  

Итак, если выборка = 4 байта, у меня есть 1024 выборки, т.е. 1024 коротких, представляющих левый канал, и 1024 коротких, представляющих правый канал.

Чтобы выполнить БПФ, мне нужно иметь массив с плавающей запятой и применить окно (Ханнинг) к моим данным:

float hanningWindow(short in, size_t i, size_t s)
{
    return in*0.5f*(1.0f-cos(2.0f*M_PI*(float)(i)/(float)(s-1.0f)));
}

whew in — входные данные, i — позиция в массиве и s — размер массива (1024).

Чтобы получить только левый канал:

float *input = malloc(1024*sizeof(float));
for (i = 0; i < 1024; i++)
    input[i] = hanningWindow(data[i*2], i, 1024);

Затем я выполняю БПФ благодаря kiss_fft (от реального к сложному). Я получаю kiss_fft_cpx *ouput (массив комплексов) размером 1024/2+1 = 513.

Я рассчитываю амплитуду каждой частоты с помощью:

kiss_fft_cpx   c = output[i];
float          amp = sqrt(c.r*c.r + c.i*c.i);

рассчитать в дБ:

amp = 10.0f * (float)log10(amp) * 2.0f;

amp не находится между 0 и 1. Я не знаю, где я должен нормализовать свои данные (в данных PCM или в конце). Также я не уверен, как я применяю свое окно к данным PCM.

Вот результат, который я получаю от песни от 0 до 20 кГц по сравнению с результатом функции getSpectrum. (для прямоугольного окна)

результаты

             My Result                         getSpectrum Result

Как я могу добиться того же результата?


person Lowip    schedule 10.03.2012    source источник
comment
Что касается скорости, вам действительно следует хранить коэффициенты окна Ханна, а не вычислять их каждый раз из триггера.   -  person Mark Borgerding    schedule 10.03.2012
comment
нет необходимости принимать sqrt. Примечание: 20*log10(sqrt(x)) == 10*log10(x)   -  person Mark Borgerding    schedule 10.03.2012


Ответы (1)


Вы немного запутались в логарифмических (дБ) шкалах - вы не получаете диапазон от 0 до 1 дБ, вы получаете обычно диапазон 96 дБ для 16-битного звука, где верхний и нижний пределы несколько произвольны, например. От 0 до -96 дБ, или от 96 дБ до 0 дБ, или любой другой диапазон, который вам нравится, в зависимости от различных факторов. Вероятно, вам просто нужно сместить и масштабировать график спектрограммы с помощью подходящего смещения и коэффициента, чтобы учесть это.

(Примечание: диапазон 96 дБ исходит из формулы 20 * log10(2^16), где 16 — количество бит.)

person Paul R    schedule 10.03.2012
comment
Спасибо за ваш ответ, но как ни странно, при применении 20 * log10(amp) я получаю значения до 120. Это может быть из-за (плавающего) приведения, которое я делаю, но не уверен в этом. - person Lowip; 10.03.2012
comment
На самом деле имеет значение только диапазон — дБ — это отношение относительно некоторого условного эталона 0 дБ — вам просто нужно посмотреть на минимальные/максимальные значения, которые вы получаете, и соответствующим образом сдвинуть/масштабировать, чтобы получить разумный диапазон интенсивности на спектрограмме. - person Paul R; 10.03.2012
comment
Окно Ханна выше умножается на среднее значение 0,5. Также максимальное значение 16-битных данных со знаком равно 2^15-1, а не 2^16. Снижение -6 дБ для каждого из этих половинных значений шкалы устанавливает пиковое значение дБ на уровне 84 дБ. - person Mark Borgerding; 10.03.2012