DSP - фильтрация частот с помощью DFT

Я пытаюсь реализовать 8-полосный эквалайзер на основе DFT с единственной целью обучения. Чтобы доказать, что моя реализация DFT работает, я подал аудиосигнал, проанализировал его, а затем повторно синтезировал его без каких-либо изменений в частотном спектре. Все идет нормально.

Я использую так называемый «стандартный способ вычисления ДПФ» - корреляцию. Этот метод вычисляет действительную и мнимую части длины как N / 2 + 1 отсчетов. Чтобы ослабить частоту, я просто делаю:

float atnFactor = 0.6;
Re[k] *= atnFactor;
Im[k] *= atnFactor;

где «k» - это индекс в диапазоне от 0 до N / 2, но после ресинтеза я получаю слегка искаженный сигнал, особенно на низких частотах.

Частота дискретизации входного сигнала составляет 44,1 кГц, и, поскольку мне нужен только 8-полосный эквалайзер, я загружаю DFT по 16 отсчетов за раз, поэтому у меня есть 8 частотных бинов, с которыми можно поиграть.

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

Заранее спасибо.


person Trap    schedule 20.05.2010    source источник


Ответы (1)


ДПФ и БПФ по существу одинаковы для целей этого вопроса.

Чтобы ослабить частотный элемент (или «полосу») в массиве, преобразованном БПФ, вам необходимо умножить действительную и мнимую составляющие на один и тот же коэффициент, а также умножить действительную и мнимую составляющие соответствующего отрицательного частотный бункер. БПФ создает преобразованную пару массивов, где первая половина значений представляет собой положительные частотные составляющие, а вторая половина - отрицательные частотные составляющие.

Вот упрощенный пример кода для фильтра нижних частот, который объясняет, что я имею в виду:

// fftsize = size of fft window
int halfFFTsize = fftsize / 2;
float lowpassFreq1 = 1000.0;
float lowpassFreq2 = 2000.0;
for (int i = 0; i < halfFFTsize; i++)
{
    int ineg = fftsize - 1 - i; // index of neg. freq.
    float freq = (float)i * (44100.0F / (float)halfFFTsize);
    if (freq >= lowpassFreq2)
    {
        real[i] = 0;
        imag[i] = 0;
        real[ineg] = 0;
        imag[ineg] = 0;
    }
    else if (freq >= lowpassFreq1)
    {
        float mult = 1.0 - ((freq - lowpassFreq1) / 
            (lowpassFreq2 - lowpassFreq1));
        real[i] *= mult;
        imag[i] *= mult;
        real[ineg] *= mult;
        imag[ineg] *= mult;
    }

}

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

Я думаю, что искажение, которое вы видите, является результатом очень маленького размера окна, которое вы используете - это особенно актуально, если вы не используете подход окна Хеннинга для восстановления исходного сигнала.

Попробуйте запустить свой код с более типичным размером окна (например, 1024). 8-полосный эквалайзер обычно не использует окно БПФ с 8 ячейками. Как правило, настройки 8 ползунков будут использоваться для вычисления кривой функции, соединяющей 8 точек в частотной области, а затем эта функция будет использоваться для установки амплитуды бинов для гораздо большего, более детализированного набора частот.

Еще один момент: интервалы частот равномерно делят доступный диапазон, поэтому независимо от размера вашего окна более половины интервалов покрывают частоты, которые не слышны человеческому уху. Вот почему полосы, охватываемые эквалайзером, обычно масштабируются логарифмически (например, 100 Гц, 1 кГц и 10 кГц для типичного 3-полосного эквалайзера) и, таким образом, не применяются к равному количеству частотных бинов < / em>.

В случае окна из 8 элементов, равномерно разнесенных, ослабление 5 из 8 наверняка не вызовет слышимого эффекта, кроме искажения слышимых частот.

person MusiGenesis    schedule 20.05.2010
comment
+1. Ваше последнее предложение особенно важно. Фильтрация путем установки значений в частотной области равными нулю, по сути, является применением квадратного фильтра, который вызовет значительный звон (феномен Гиббса) в частотной характеристике. Имейте в виду, что установка значения в дискретной частотной области на ноль влияет только на отклик на этой точной частоте. Частотная характеристика между частотными выборками будет сильно колебаться с фильтром из кирпичной стены. Я предлагаю вам ознакомиться с учебными пособиями по проектированию полосовых КИХ. - person Jason B; 20.05.2010
comment
@Jason: у вас есть ссылки на какие-нибудь хорошие уроки по созданию фильтров? Я ненадолго погрузился в фильтры кодирования, подобные приведенному выше образцу, но дальше этого я не продвинулся. - person MusiGenesis; 20.05.2010
comment
О, я думаю, вы удалили это предложение, но вы также изменили свой код, чтобы показать более постепенное изменение полосы пропускания. - person Jason B; 20.05.2010
comment
@Jason: Я уверен, что с моей версией с ограниченным доступом все еще есть некоторые проблемы, и я был бы очень благодарен за любую информацию, которая у вас есть по этому поводу. Я использовал подобные фильтры в программном синтезаторе, но не на основе каких-либо реальных знаний о том, что я делал. - person MusiGenesis; 20.05.2010
comment
ccrma.stanford.edu/~jos/sasp/FIR_Digital_Filter_Design look.html неплохо, но я лично не пользовался многими онлайн-уроками, так как у меня есть много учебников. Вероятно, самый простой метод - это метод проектирования окон, но в настоящее время я просто использую оптимальные методы проектирования фильтров, такие как Parks-McClellan, для создания фильтров. Этот алгоритм довольно сложен, но широко доступен. Он выведет коэффициенты КИХ-фильтра на основе ряда введенных вами входных параметров. - person Jason B; 20.05.2010
comment
ccrma.stanford.edu/~jos/sasp/Generalized_Window_Method.html дает Пошаговая инструкция по способу оформления окон. - person Jason B; 20.05.2010
comment
Если у вас есть доступ к MATLAB, изучите функцию Remez (или firpm в более новых версиях). Если у вас нет MATLAB, я думаю, что у октавы такие же возможности. Много времени я просто использую MATLAB или Octave для создания коэффициентов фильтра, поскольку они имеют хорошие функции проектирования оптимальных фильтров, а затем использую фильтр в программе на C или C ++. - person Jason B; 20.05.2010
comment
Если я вас правильно понял, мне не нужно было бы изменять какие-либо отрицательные частотные элементы, поскольку я вычисляю ДПФ с использованием корреляции и получаю два массива Re [] и Im [], которые имеют длину N / 2 отсчета. Я прав? - person Trap; 21.05.2010
comment
Если вы получаете только N / 2 сложных выборок, вы не выполняете полное ДПФ, которое определено для возврата того же количества таких же выборок, что и входные. Иногда вычисляется только половина отсчетов, поскольку для реальных входных сигналов отрицательная половина является зеркальным отображением положительной половины. Однако, если вы хотите отфильтровать и повторно синтезировать, вам необходимо использовать все частотные выборки. - person Jason B; 21.05.2010