Цифровой БИХ фильтр (IIR filter). Пример программы.
on 15.07.2012 at 22:31В предыдущей статье мы занимались разработкой фильтра с бесконечной импульсной характеристикой. В результате был получен готовый класс для фильтрации данных. Все казалось бы прекрасно, но… Но мне кажется, что этого недостаточно для дорогого читателя этого сайта :(. Для закрепления полученных знаний или просто так я решил написать еще одну статью, в которой будет дан конкретный пример работы с классом. За основу была взята статья «Работа со звуковыми файлами (libsndfile) (static link library)«. В этой статье (если кто не читал) описан способ работы со звуковыми «.wav» файлами используя библиотеку «libsndfile». Так вот, в этой статье я оставил строчку комментария, в которой было написано, что именно в том месте можно реализовать обработку звуковых данных. Итого, я переписал предыдущий код под наши нужды и получил следующий проект FilterIIR.
Стоит всего лишь скачать рабочий проект и запустить его в среде программирования Visual Studio 2005. Перейдем к разбору кода, ведь нас интересует алгоритм работы программы. Алгоритм следующий:
1. Открываем на чтение звуковой «.wav» файл (входной).
1 2 3 4 5 6 7 8 9 | // Open the input file if ((infile = sf_wchar_open(infilename, SFM_READ, &sfinfo)) == NULL) { printf("Not able to open input file %s.\n", infilename); puts(sf_strerror(NULL)); return 1; } |
2. Создаем новый звуковой «.wav» файл (выходной).
1 2 3 4 5 6 7 8 9 | // Open/create the output file if ((outfile = sf_wchar_open(outfilename, SFM_WRITE, &sfinfo)) == NULL) { printf("Not able to open/create output file %s : %s\n", outfilename, sf_strerror(NULL)); return 1; } |
3. Вызываем главную функцию-обработчик звуковых данных.
1 2 | // main sound processing function apply_iir_filter(infile, outfile, sfinfo); |
4.Закрываем входной (начальные звуковые данные) и выходной (обработанные звуковые данные) файлы.
1 2 3 | // cosing input and output files sf_close(infile); sf_close(outfile); |
Понятное дело, самое интересное содержит именно функция «apply_iir_filter». Её содержимое следующее:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | // main sound processing function static void apply_iir_filter(SNDFILE *infile, SNDFILE *outfile, SF_INFO info) { int channels = info.channels; CFilterIIRStream *cfiir = new CFilterIIRStream[channels]; float *buf = new float[channels*BLOCK_SIZE]; float *bufTmpChan = new float[BLOCK_SIZE]; int k, m, readcount, writecount; // initializing each instanse of the iir filter for (m = 0; m < channels; m++) cfiir[m].Init(CFilterIIRStream::HPF, static_cast(0.1*M_PI)); while ((readcount = static_cast(sf_readf_float(infile, buf, BLOCK_SIZE))) > 0) { // for each of channel for (m = 0; m < channels; m++) { // for each of sample (it can be a lot of channels...) for (k = 0 ; k < readcount ; k++) bufTmpChan[k] = buf[k*channels + m]; // processing data from single channel could be made here!!! cfiir[m].Process(bufTmpChan, readcount); // if processed value is out of the bounds - just clip it for (k = 0; k < cfiir[m].GetFilteredDataLength(); k++) { if(bufTmpChan[k] > 1.0f) bufTmpChan[k] = 1.0f; else if(bufTmpChan[k] < (-1.0f)) bufTmpChan[k] = -1.0f; } // pushing back processed data into original array for (k = 0; k < readcount; k++) buf[k*channels + m] = bufTmpChan[k]; } writecount = static_cast(sf_writef_float(outfile, buf, readcount)); } delete [] buf; delete [] bufTmpChan; delete [] cfiir; return; } |
Что же мы тут видим? Так как наш входной звуковой файл может содержать несколько каналов (моно, стерео, квадро…), соответственно нужно для каждого канала создать свой экземпляр фильтра, т.е. мы создаем массив фильтров размерности равной количеству каналов:
1 | CFilterIIRStream *cfiir = new CFilterIIRStream[channels]; |
Дальше мы инициализируем каждый из фильтров для каждого из каналов. В данном случае все фильтры мы настраивае одинаково:
1 2 3 | // initializing each instanse of the iir filter for (m = 0; m < channels; m++) cfiir[m].Init(CFilterIIRStream::HPF, static_cast(0.1*M_PI)); |
Как можно заметить из данных строк, этот фильтр пропускает высокие частоты, а низкие «обрезает». HPF — high-pass filter или же «фильтр высокую пропускает» в неточном, но правильном переводе.
Дальше идет цикл получения данных из входного файла, обработки данных методом «Process», усечение значений данных, если они выходят за рамки допустимых значений и запись результата в выходной файл. Где что вроде бы и так понятно. Если я ошибаюсь — говорите, пишите, кричите! Я допишу…:)
Головна частина
Завантажити вихідний код можна тут.
Обсуждение (5)
Просто и понятно. Думаю начинающим будет полезно. Я эту тему уже прошёл и даже написал приложение http://dfd-lab.com Если сочтёте за рекламу можете удалить мой коммент — я не в обиде. Но буду благодарен всем кто скачает, потестирует и пришлёт отзывы — от этого зависит качество самого приложения.
Спасибо.
Считаю, что ссылки по теме удалять было бы, как минимум, неразумно:)
Я же, напротив, в свободное время и сам проверю ваши труды и обязательно напишу отзывы!
Здравствуйте, классно сделано приложение. Наткнулся на вас и хочу использовать ваши наметки) подскажите, какой тип фильтра вы выбрали? Чебышев, Баттерворт..? какого порядка? И чем обусловлен выбор? Заранее спасибо за комментарий)
Спасибо за комментарий!
Формулы были честно взяты с просторов Интернета.
В этой реализации используется «биквадратный» фильтр второго порядка.
И вот, только что добавил мини-пост касательно Вашего вопроса.
Вам может быть интерестно.