Преобразование БПФ в спектрограмму

У меня есть аудиофайл, и я выполняю итерацию через файл и беру на каждый шаг 512 образцов, а затем передаю их через БПФ.

У меня есть данные как блок длиной 514 (с использованием IPP ippsFFTFwd_RToCCS_32f_I) с чередованием реальных и мнимых компонентов.

Моя проблема в том, что мне делать с этими сложными числами, как только я их получу? На данный момент я делаю для каждого значения

const float realValue   = buffer[(y * 2) + 0];
const float imagValue   = buffer[(y * 2) + 1];
const float value       = sqrt( (realValue * realValue) + (imagValue * imagValue) );

Это дает что-то немного полезное, но я бы предпочел каким-то образом получить значения в диапазоне от 0 до 1. Проблема с ним выше в том, что пики в конечном итоге возвращаются примерно на 9 или более. Это означает, что вещи становятся злобно насыщенными, а затем появляются другие части спектрограммы, которые едва проявляются, несмотря на то, что они кажутся довольно сильными, когда я запускаю аудио через спектральную аудиторию. Я полностью признаю, что не уверен на 100%, что данные, возвращаемые БПФ (кроме того, что он представляет значения частоты 512-образного длинного блока, который я передаю). Особенно я не понимаю, что именно представляет собой число compex.

Любые советы и помощь будут высоко оценены!

Изменить: просто уточнить. Моя большая проблема заключается в том, что возвращаемые значения FFT не имеют смысла, даже если вы не знаете, что такое масштаб. Может ли кто-нибудь указать мне на разработку этой шкалы?

Edit2: Я получаю действительно приятные результаты, выполняя следующие действия:

size_t count2   = 0;
size_t max2     = kFFTSize + 2;
while( count2 < max2 )
{
    const float realValue   = buffer[(count2) + 0];
    const float imagValue   = buffer[(count2) + 1];
    const float value   = (log10f( sqrtf( (realValue * realValue) + (imagValue * imagValue) ) * rcpVerticalZoom ) + 1.0f) * 0.5f;
    buffer[count2 >> 1] = value;
    count2 += 2;
}

На мой взгляд, это даже выглядит лучше, чем большинство других реализаций спектрограмм, на которые я смотрел.

Есть ли что-то БОЛЬШОЕ неправильно с тем, что я делаю?

Ответ 1

Обычная вещь, чтобы сделать все видимые БПФ - это взять логарифм величины.

Итак, положение выходного буфера сообщает вам, какая частота была обнаружена. Величина (норма L2) комплексного номера сообщает вам, насколько сильной была обнаруженная частота, а фаза (арктангенс) дает вам информацию, которая намного важнее в пространстве изображения, чем аудиопространство. Поскольку БПФ дискретно, частоты работают от 0 до частоты Найквиста. В изображениях первый термин (DC) обычно является самым большим, и поэтому хорошим кандидатом для использования в нормализации, если это ваша цель. Я не знаю, верно ли это для аудио (я сомневаюсь)

Ответ 2

Для каждого окна из 512 образцов вы вычисляете величину БПФ, как и вы. Каждое значение представляет собой величину соответствующей частоты, присутствующей в сигнале.

mag
 /\
 |
 |      !         !
 |      !    !    !
 +--!---!----!----!---!--> freq
 0          Fs/2      Fs

Теперь нам нужно выяснить частоты.

Поскольку входной сигнал имеет реальные значения, БПФ симметрично вокруг середины (компонент Найквиста), причем первый член является компонентом постоянного тока. Зная частоту дискретизации сигнала Fs, частота Найквиста равна Fs/2. И поэтому для индекса k соответствующая частота k*Fs/512

Итак, для каждого окна длиной 512 мы получаем величины на заданной частоте. Группа тех, кто над последовательными окнами формирует спектрограмму.

Ответ 3

Просто чтобы люди знали, что я много работал над этой проблемой. Главное, что я обнаружил, это то, что БПФ требует нормализации после этого.

Для этого вы усредняете все значения вашего векторного окна вместе, чтобы получить значение несколько меньше 1 (или 1, если вы используете прямоугольное окно). Затем вы делите это число на количество частотных бункеров, которые вы отправили преобразование БПФ.

Наконец, вы делите фактическое число, возвращаемое БПФ, на номер нормализации. Теперь значения амплитуды должны находиться в диапазоне от -Inf до 1. Журнал и т.д., Как вам угодно. Вы все равно будете работать с известным диапазоном.

Ответ 4

Есть несколько вещей, которые, я думаю, вы найдете полезными.

Прямая FT будет иметь тенденцию давать большие числа на выходе, чем на входе. Вы можете думать об этом, поскольку вся интенсивность на определенной частоте отображается в одном месте, а не распределяется через набор данных. Это имеет значение? Вероятно, не потому, что вы всегда можете масштабировать данные в соответствии с вашими потребностями. Однажды я написал партию FFT/IFFT с целым числом, и каждый проход требует масштабирования для предотвращения переполнения целых чисел.

Реальные данные, которые являются вашими данными, преобразуются в нечто почти сложное. Как оказалось, буфер [0] и буфер [n/2] являются реальными и независимыми. Существует хорошее обсуждение этого здесь.

Входные данные представляют собой значения интенсивности звука, принятые во времени, равномерно распределенные. Говорят, что они достаточно адекватны во временной области. Выходной сигнал FT, как говорят, находится в частотной области, поскольку горизонтальная ось является частотой. Вертикальная шкала остается интенсивной. Хотя это не очевидно из входных данных, на входе также присутствует информация о фазе. Хотя весь звук является синусоидальным, нет ничего, что фиксирует фазы синусоидальных волн. Эта фазовая информация появляется в частотной области как фазы отдельных комплексных чисел, но часто нам это неинтересно (и часто мы тоже делаем!). Это просто зависит от того, что вы делаете. Расчет

const float value = sqrt((realValue * realValue) + (imagValue * imagValue));

извлекает информацию об интенсивности, но отбрасывает информацию о фазе. Взятие логарифма по существу просто уменьшает большие пики.

Надеюсь, что это будет полезно.

Ответ 5

Если вы получаете странные результаты, то одна вещь, которую нужно проверить, - это документация для библиотеки FFT, чтобы посмотреть, как упаковывается выход. В некоторых подпрограммах используется упакованный формат, где реальные/мнимые значения чередуются, или они могут начинаться с элемента N/2 и обтекать.

Для проверки работоспособности я бы предложил создать выборочные данные с известными характеристиками, например, Fs/2, Fs/4 (Fs = частота выборки) и сравнить результат процедуры FFT с тем, что вы ожидаете. Попробуйте создать синус и косинус на той же частоте, поскольку они должны иметь одинаковую величину в спектре, но иметь разные фазы (т.е. RealValue/imagValue будет отличаться, но сумма квадратов должна быть одинаковой.

Если вы намереваетесь использовать FFT, то вам действительно нужно знать, как это работает математически, иначе вы, вероятно, столкнетесь с другими странными проблемами, такими как сглаживание.