Что не так с моим фильтром нижних частот? - PullRequest
2 голосов
/ 03 марта 2011

У меня есть массив образцов int в диапазоне от 32766 до -32767.В части попыток создать детектор огибающей я написал фильтр нижних частот, но он, похоже, не справляется с этой задачей.Пожалуйста, имейте в виду, что я пытаюсь отфильтровать весь массив за один раз (без буферов).

Это не потоковая передача, а применение к записанному аудио для последующего воспроизведения.Это написано на C. Пример аргумента отсечения будет 0,5.

void lopass(int *input, float cutoff, int *output) 
{

float sample = 0;

for (int i=1 ; i < (1430529-10); i++) // we will go through all except the last 10 samples 
{
    for (int j = i; j < (i+10); j++) { // only do this for a WINDOW of a hundred samples

        float _in = (float)input[j];
        float _out = (float)output[j-1];

         sample = (cutoff * _in) + (32766 - (32766*cutoff)) * _out;

    }

    output[i] = (int)sample;
}

}

Я думал, что запусту свой оператор фильтрации в окне из 10 выборок.Он не только очень медленный, но на самом деле он мало что делает, но, похоже, снижает общую амплитуду.\

Если у вас есть какие-либо советы или предложения (или код!) О том, как сделать это правильно, это было бы здорово!

Ответы [ 4 ]

6 голосов
/ 03 марта 2011

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

sample = 0;
for (int j=i; j<i+10; j++)
    sample += input[j];
output[i] = sample / 10;

В нынешнем виде это просто усредняет,без указания среза - это означает, что он имеет фиксированную (и довольно медленную) кривую среза.Отсечка регулируется только числом отсчетов в окне.

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

sample = 0;
for (j=0; j<10; j++)
   sample += input[i+j] * coefficients[j];
output[i] = sample;

Количество выборок в вашем окне обычно не является входом в процесс проектирования, а скорее является выходом.Вы начинаете с определения частоты среза (в виде доли от частоты дискретизации) и ширины среза, и на основе этих значений вы вычисляете необходимый размер окна.

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

Время EE было довольнохорошая статья о дизайне фильтров несколько лет назад.

2 голосов
/ 03 марта 2011

Арифметика в фильтре выглядит неправильно, и, как уже указывалось @pmg, вы неправильно сохраняете выходные значения. Вероятно, должно быть:

void lopass(int *input, float cutoff, int *output) 
{
    float sample = 0.0f;

    output[0] = 0.0f;

    for (int i = 1 ; i < (1430529 - 10); i++)
    {
        for (int j = i; j < (i + 10); j++)
        { 
            float _in = (float)input[j];
            float _out = (float)output[j-1];

            sample = (cutoff * _in) + (1.0f - cutoff) * _out;

            output[i] = (int)sample;
        }
    }
}

Есть еще несколько незначительных проблем, которые нужно исправить, но это должно по крайней мере работать как довольно грубый однополюсный рекурсивный (IIR) фильтр.

2 голосов
/ 03 марта 2011

Не знаю, актуально ли это, но в вашем коде внутренний цикл ничего не делает

for (j=???; j<???; j++) {
  sample = ???;
}

- это то же самое, что и

// for (j=???; j<???; j++) {
  sample = ???; // for last j
// }
0 голосов
/ 04 марта 2011

Это разбитый фильтр с движущимся окном из 10 сэмплов во внутреннем цикле (где вы фактически используете только последний сэмпл из 10), когда в своих комментариях вы говорите, что хотите 100 сэмплов в окне прямоугольного фильтра.

Первая ошибка даст вам частоту смены фильтра в 10 раз выше.

...