Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Цифровой Фильтр на ATmega
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему
Страницы: 1, 2
_Ie0nid
Добрый день, давно не заходил с проблемами. КТо может помочь куском кода к цифровому фильтру для Codevision. Даже с чего начать не знаю, куда не сунусь везде только формулы да теория. Хочу попробовать отфильтровать сигнал снятый с ацп Atmegи, и преобразовать на выход с помощью ШИМ и RC цепи
Genadi Zawidowski
Радиолюбительская конструкция.
haker_fox
Цитата(_Ie0nid @ Sep 16 2009, 13:18) *
куда не сунусь везде только формулы да теория.

А без формул и теории в фильтрации и делать нечего... А формулы переложить на язык программирование дело десятое... Поправьте, если ошибаюсь.
SasaVitebsk
Боюсь, что меня сейчас поколотят, но попробую облегчить вам жизнь. smile.gif
1) Берём прогу расчёта фильтров, которую я приложил.
2) Рисуем фильтр с нужными параметрами.
3) Садимся и вручную округляем коэффициенты до ближайшего двоичного (если непонятно как, то спрашивайте - поясню)
4) Переписываем (на бумаге) формулу каждого звена ч/з сдвиги
5) объединяем сдвиги и получаем общую прогу.
6) Я обычно, проверяю АЧХ полученной проги на IBM, чтобы исключить ошибки.

Правда такова, что фильтрация фильтром 2-4 порядка, часто бывает лаконичнее, эфективнее, красивее и, однозначно менее затратно по ресурсам чем скользящее усреднение.

Так, например, фильтр Y(i) = X(i) + 0.875Y(i-1) - X(i-1) прекрасно убирает постоянную составляющую. Иногда использовал такое свойство фильтра, как коэффициент передачи. Например требуется ослабить сигнал, либо наоборот его усилить.

Конечно, если более-менее сложная задача, то я сначала полностью моделирую процесс и обязательно его визуализирую. На всех этапах. Далее отрабатываю все формулы на модели. Потом уже переношу всё это на однокристалку. Для меня так проще.
Могу чего-нибудь на простом примере показать.
MrYuran
Цитата(SasaVitebsk @ Sep 16 2009, 11:30) *
1) Берём прогу расчёта фильтров, которую я приложил.

А для КИХ есть что-то подобное?
БИХ не всегда подходит из-за длинных "хвостов"
Хотя при том же порядке фильтрует намного лучше.

У меня дома валяется что-то подобное, но вся проблема в вычислении коэффициентов передачи.
Неплохо было бы автоматизировать
SasaVitebsk
Цитата(MrYuran @ Sep 16 2009, 10:39) *
Неплохо было бы автоматизировать

Тоже вот подумываю.... Тока всё чё то руки не доходят... laughing.gif

В той проге, что я выложил можно править коэффициенты и смотреть результирующий график. Это очень удобно. Иногда расчётное значение весьма сложное получается, сначала пробуешь обрезать лишнее и смотришь на результат. smile.gif
Есть конечно и QED, но как то не сложилось ... smile.gif
ZVE
Цитата(SasaVitebsk @ Sep 16 2009, 10:30) *
Могу чего-нибудь на простом примере показать.

Да покажите пример пожалуйста. Например приведенный Вами же фильтр который убирает постоянку.
Думаю топикстартеру будет полезно, да и многим другим тоже(в том числе и мне rolleyes.gif ).
Заранее благодарю.
Legotron
Цитата(MrYuran @ Sep 16 2009, 11:39) *
А для КИХ есть что-то подобное?

А почему бы не использовать Matlab?
Там есть и КИХ и БИХ. Плюс есть ФЧХ и картинка с полюсами! Плюс всё можно качественно промоделировать.
Сергей Борщ
Цитата(Legotron @ Sep 17 2009, 16:04) *
А почему бы не использовать Matlab?
Может потому, что он стоит немалых для любителя денег?
Есть бесплатная альтернатива - SciLab, но в нем нет таких красивых и удобных надстроек.
Serhiy_UA
Много лет назад экспериментировал на ATmega16 со звуковыми частотами. То же АЦП-цифровой фильтр-ШИМ-RC. Строил НЧ и ВЧ фильтры с БИХ, с аккумулятором сумм до 32-бит, а также коэффициентами до 16-бит. Фильтры в итоге всегда самовозбуждались. Тема по прежнему актуальна.
Кто либо построил и реально использовал такие фильтры, есть ли положительные результаты, чем рассчитывали коэффициенты?
SasaVitebsk
Цитата(ZVE @ Sep 17 2009, 14:18) *
Да покажите пример пожалуйста....

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

Представим себе, что у нас входной сигнал 1200 Гц. Мы его принимаем на АЦП AVR. В связи с тем, что АЦП AVR работает лишь с положительным сигналом, нам пришлось его пропустить ч/з разделительный конденсатор и выставить резисторами 0.5 от опорного напряжения (типичный случай). В результате мы получаем синус от 0 до 1.1V(опора) max, что составит 0-1023 в единицах АЦП. Но для дальнейших расчтётов нам лучше работать с сигналом имеющим знак. Можно, не мудрствуя лукаво вычесть 512 и получить сигнал +/- 512. Но, резистивный делитель может быть сыставлен не совсем точно (например 0.6V) и в результате мы получим сдвинутый сигнал и соответственно постоянную составляющую в нём. Плюс, допустим мы хотим зарезать сетевые помехи (50 и 100 Гц) и какие-то высокочастотные помехи (например 5кГц). Короче мы решили слегка фильтрануть сигнал для уменьшения воздействия внешних помех. Допустим амплитудная характеристика нам важна только относительная. Ну к примеру идёт манипуляция по принципу есть сигнал/нет сигнала. smile.gif Таким образом надо его выделить и обработать пиковым детектором. smile.gif Скажем частота может плавать незначительно.

Берём прогу, что я приложил в прошлом посте (спасибо автору) и строим полосовой фильтр. (clip1)

Теперь немного о дробной арифметике.
Все знают что если 1 поделить на 2 то получим 0.5. Если ещё раз разделить = 0.25. Что такое деление на 2 - сдвиг вправо на 1 разряд. Таким образом если себе представить дробную часть, то двочное число 1000000B = 0.5, 01000000B = 0.25, 01100000B = 0.25+0125 = 0.375. Из этого понятно, что умножение на дробные коэффициенты можно представить как сдвиги и сложения. Желательно подобрать такие коэффициенты, чтобы число этих операций было минимальным при допустимой погрешности вычислений. Понятно также, что если у нас сигнал 10 бит, то сдвиги на 8-9 разрядов практически не внесут значимых результатов. Надо также учитывать, что фильтр может искажать сигнал по амплитуде. Для этого желательно следить за амплитудным значением на графике АЧХ. Для простоты картины можно отталкиваться от того, что сумма коэффициентов должна быть равна 1. Если это не так, то результирующий сигнал увеличится либо уменьшится. Часто это бывает непринципиально или даже желательно.

Исходя из этого "подкорректируем" коэффициенты X фильтра и перерисуем график воспользовавшись программой. (clip2)
Поступим аналогично с Y. (clip3)
После построения графика - видим что размах полезного сигнала изменился в 1.3 раза. Можно, естественно, подобрать коэффициенты более точно, но для поставленной задачи нам это ни к чему.

Теперь перенесём это на бумагу.
Теперь поясню, для тех кто непонимает, что это за X, Y, i. smile.gif
Надо понимать, что фильтр состоит из звеньев (в данном фильтре 1 звено). Звенья независимы. Выходные данные первого звена - входные второго. И так далее.
В данном контексте будем считать так:
X входные данные первого звена (сигнал с АЦП)
Y выходные данные первого звена (выход фильтра). Если у нас более одного звена, то Y это входные данные второго звена.
(i) текущее значение
(i-1) предыдущее значение (значение полученное в предыдущей выборке)
(i-2) значение полученное 2 выборки назад и т.д.
Я упрощу выражение и вместо X(i-1) буду писать X1 и так далее.

Итак X коэфф. фильтра будут выглядеть так:
0.0625*(X0+X4)-0.125*X2 = ((X0+X4)>>4)-(X2>>3)

Y коэф. будут выглядеть так
-(-1.875*Y1+2*Y2-1.0625*Y3+0.3125*Y4) = 1.875*Y1-2*Y2+1.0625*Y3-0.3125Y4 = 2*Y1-0.125*Y1-2*Y2+Y3+0.0625*Y3-0.3125*Y4
= (Y1<<1)-(Y1>>3)-(Y2<<1)+Y3+(Y3>>4)-(Y4>>2)-(Y4>>4)

Итого общая формула (1):
Y0 = ((X0+X4)>>4)-(X2>>3)+(Y1<<1)-(Y1>>3)-(Y2<<1)+Y3+(Y3>>4)-(Y4>>2)-(Y4>>4)

Для понимания дальнейшего я перепишу по другому первых 2 члена
((X0+X4)>>4)-(X2>>3) = ((X0+X4)>>1)-X2)>>3
По сути это вынос множителя за скобки и математически ничего не даёт. На самом деле это уменьшает объём вычислений и повышает их точность.

Давайте перепишем полученную формулу фильтра (1) с учётом последнего замечания, но не ввиде формулы, а в виде последовательности вычислений.
Для этого введём временную переменную Temp и будем выбирать равные коэф. сдвигов. Я в коментах буду указывать номер члена формулы (1) которые я взял.
В результате получим:

Temp = (X0+X4+Y3-Y4)>>1; // все члены со сдвигом 4 = 1,7,9
Temp += (-X2-Y1); // ... 3 = 2,4 Естественно лучше записать Temp -= X2+Y1;
Temp >>= 1;
Temp += (-Y4); // .... 2 = 8 Опять таки Temp -= Y4;
Temp >>= 2; // Поскольку у нас нет членов со сдвигом >>1
Temp += (Y1<<1)-(Y2<<1)+Y3;

Из получившейся проги видно что результирующий коэфф. действительно будет более 1 так как в последней строчки получим 1 а в предпоследней ещё 1/4, но это просто так, для проверки себя.
Я не буду сейчас писать кольцевой буфер для входных значений фильтра. Чтобы было понятней что я делаю. Кстати если используем ФНЧ или ФВЧ, то там вообще это без надобности. Тем не менее, я часто пишу кольцевой буфер с отладочными целями, чтобы в процессе отладки увидеть как работает фильтр и некоторые его звенья. После завершения отладки - могу выкинуть, либо сохранить.

Итак, будет выглядеть так:

X4=X3; // Новый сэмпл сдвигает значения
X3=X2;
X2=X1;
X1=X0;
X0=ADCH;
Temp = (X0+X4+Y3-Y4)>>1; // все члены со сдвигом 4 = 1,7,9
Temp += (-X2-Y1); // ... 3 = 2,4 Естественно лучше записать Temp -= X2+Y1;
Temp >>= 1;
Temp += (-Y4); // .... 2 = 8 Опять таки Temp -= Y4;
Temp >>= 2; // Поскольку у нас нет членов со сдвигом >>1
Temp += (Y1<<1)-(Y2<<1)+Y3;
Y4=Y3; // Новый сэмпл сдвигает значения
Y3=Y2;
Y2=Y1;
Y1=Y0;
Y0=Temp;

Ну вот и всё.
На последок хотелось бы отметить что имеет значение разрядность чисел. Бывает, при сложных фильтрах, где малые коэффициенты происходит потеря точности, которая сводит на нет весь результат. Особенно если пользовать 8 бит данные. Часто бывает, при пограничных значениях (близких к максимому или минимому) что происходит потеря точности из-за переполнений и в этом случае достаточно использовать повышенную разрядность только переменной Temp.
Но в этом смысле преимущество Си просто фантастическое.
Представим что я написал этот фильтр для разрядности АЦП 8 бит. Тогда объявление переменных следующее:
int8_t X0,X1,X2,X3,X4,Y1,Y2,Y3,Y4,Temp;
Представим, что в процессе работы/наладки, я пришёл к выводу, что мне надо повысить разрядность до 10 бит.
Исправления будут следующие:
1) В строке объявления переменных надо исправить uint8_t на uint16_t (2 символа)
2) в строке программы изменить ADCH на ADC (1 символ)
3) В строке инициализации АЦП убрать (1<<ADLAR) (ещё 10 символов)
Итого исправления 13 символов. Тот кто пишет на ассемблере может оценить объём работы необходимый для перевода такого фильтра с 8 на 16 бит.



Цитата(Serhiy_UA @ Sep 17 2009, 16:19) *
Много лет назад экспериментировал на ATmega16 со звуковыми частотами. То же АЦП-цифровой фильтр-ШИМ-RC. Строил НЧ и ВЧ фильтры с БИХ, с аккумулятором сумм до 32-бит, а также коэффициентами до 16-бит. Фильтры в итоге всегда самовозбуждались. Тема по прежнему актуальна.
Кто либо построил и реально использовал такие фильтры, есть ли положительные результаты, чем рассчитывали коэффициенты?

Собственно цифровые фильтры хороши именно тем, что без разницы на чем они считаются. Mega16/ARM/PIC - при тех же коэффициентах и разрядностях работать будут одинаково. По моему очевидно, что ATMega не разрабатывалась для обработки звука. Для этого есть более удобные процы. Я работал со звуком только в рамках телефонной линии. При выборке 8кГц и верхней частоте 3.4кГц требуется, для удовлетворительного качества, АЦП разрядностью 14 бит. При этом для обработки двух потоков приходится греметь всеми костями ATMega на частоте 16МГц. Пробовал обеспечить вывод разными способами, в том числе и ШИМом. Понятно что 14 бит ШИМ на 8кГц даёт сотни МГц поэтому упрощали до 8 бит. Даже при 8 бит для получения приемлемого сигнала, требовалась выходная обвеска сопоставимая с размерами изделия. Причём настройка-регулировка была бы непростая.
Короче из всех вариантов этот был самым отвратительным. Существуют внешние цапы, в том числе звуковые, в том числе с нелинейной характеристикой и встроенными цифровыми фильтрами. Стоят - копейки. С фильтрами проблем не было. Правда, как я говорил обработка была весьма топорная.
Goodefine
Цитата(SasaVitebsk @ Sep 17 2009, 22:45) *
...Основная цель будет - показать, что всё не так уж страшно...

Спасибо за пример. Так красиво все расписали, что решил руками потрогать. То ли что не так, то ли руки неровные.. smile.gif
По-порядку. Система такая: несколько сигналов (16 штук, от 300 до 1800 Гц, амплитуда каждого 0,45В) через сумматор на ОУ с питанием -+15В (плюс добавляется постоянка 7,5В и инвертируется вторым ОУ, им же приводится к диапазону 0-5В вся сумма сигналов). Оцифровку ведет мега48 с частотой 8кГц, ЦАП 8 бит на 2R-R матрице.
Схема:
Нажмите для просмотра прикрепленного файла
Вкратце работает так: каждые 125мкс переполняется таймер, за ним автотриггером срабатывает запуск преобразования. По окончании преобразования в прерывании ставится флаг, по которому в основном цикле и работаем. Обновлять ЦАП можно и в прерывании, но джиттера нет и в основном цикле по флагу.
Взял Вашу реализацию фильтра без переделок, благо частоты близкие...
Так вот, если по флагу делать ЦАП без преобразований [PORTD = (unsigned char) ((X0+512)/4);] то получается:
Нажмите для просмотра прикрепленного файла
Т.е. все нормально. Даже амплитуды все совпадают. Это при любом количестве сигналов (фильтр при этом продолжает просчитываться)...
Далее переходим к использованию фильтра
Код:
Код
volatile unsigned char fl_adc_result;
int X0,X1,X2,X3,X4,Y0,Y1,Y2,Y3,Y4,Temp;
...
if(fl_adc_result)
        { PORTB|=(1<<0); //debug time
            
            X4=X3; // Новый сэмпл сдвигает значения
            X3=X2;
            X2=X1;
            X1=X0;
            X0=ADCW-512;
            /*
            Temp = (X0+X4+Y3-Y4)>>1; // все члены со сдвигом 4 = 1,7,9
            Temp += (-X2-Y1); // ... 3 = 2,4 Естественно лучше записать Temp -= X2+Y1;
            Temp >>= 1;
            Temp += (-Y4); // .... 2 = 8 Опять таки Temp -= Y4;
            Temp >>= 2; // Поскольку у нас нет членов со сдвигом >>1
            Temp += (Y1<<1)-(Y2<<1)+Y3;
                        */
            Temp = (X0+X4+Y3-Y4)/2; // все члены со сдвигом 4 = 1,7,9
            Temp -= X2+Y1; // ... 3 = 2,4 Естественно лучше записать Temp -= X2+Y1;
            Temp /= 2;
            Temp -= Y4; // .... 2 = 8 Опять таки Temp -= Y4;
            Temp /= 4; // Поскольку у нас нет членов со сдвигом >>1
            Temp += (Y1-Y2)*2+Y3;

            Y4=Y3; // Новый сэмпл сдвигает значения
            Y3=Y2;
            Y2=Y1;
            Y1=Y0;
            Y0=Temp;            
            
            //PORTD = (unsigned char) ((X0+512)/4); //без преобразования            
            
            PORTD= (unsigned char) ((Y0+512)/4);
            fl_adc_result=0;
            
        PORTB&=~(1<<0); //debug

        }

При этом, получается: когда сигналов нет, на выходе фильтра постоянка 2,5В. Как и на входе, т.е. вроде правильно. Но при подаче любого сигнала на вход, а также любой их комбинации, фильтр начинает "колбасить":
Нажмите для просмотра прикрепленного файла
Это продолжается и после отключения сигналов, т.е. Xi и/или Yi не сходятся sad.gif
Первая мысль была что компилятор (AVRGCC 4.3.2 Binutils 2.19 avr-libc 1.6.6, в протеусе не дебажится у меня) некорректно реализует сдвиги signed чисел. Потому сделал явно делением. Умный к0мпилятор и сам сдвиги сделает. Та же картина... Обрезание результата АЦП до 8-ми бит (дабы избежать переполнения) картины не меняет...
Что может быть не так в консерватории?...
AHTOXA
Скорее всего причина вот тут:
Код
    X0=ADCW-512;

Попробуйте заменить на
Код
    X0=(int)ADCW-512;
Goodefine
Цитата(AHTOXA @ Sep 19 2009, 00:24) *
Попробуйте заменить на
Код
    X0=(int)ADCW-512;

Картина та же...
AHTOXA
Тогда наоборот, замените в объявлении Xi, Yi и Temp int на unsigned int.
Ну и не вычитайте 512, конечно.
Goodefine
Я это уже проделывал. Основное отличие - фильтр начинает колбасить сразу же, еще до подачи сигналов...
AHTOXA
Да, засадаsmile.gif
А long пробовали?
Goodefine
Вот Long не пробовал, только сейчас - то же самое... Ща возьму гарантированно рабочий фильтр с флоат коэффициентами и посмотрю...
AHTOXA
Есть ещё одна мысль. Я не совсем понял, откуда взялся минус перед всеми игреками вот тут:
Цитата(SasaVitebsk @ Sep 18 2009, 01:45) *
Y коэф. будут выглядеть так
-(-1.875*Y1+2*Y2-1.0625*Y3+0.3125*Y4) =

Может его не надо?
Goodefine
Чет не едут у меня лыжи sad.gif С флоатами хрень какая-то - время выполнения короче чем int-ми.. Где-то засада (никогда их не пользую)...
Насчет минуса - появится если всю сумму Yi приравнять к нулю и вынести Y0... А правильно это или нет - надо глубже смотреть...
AHTOXA
Цитата(Goodefine @ Sep 19 2009, 04:52) *
Чет не едут у меня лыжи sad.gif С флоатами хрень какая-то - время выполнения короче чем int-ми.. Где-то засада (никогда их не пользую)...


Но хоть заработало? smile.gif

А с минусом оказывается всё в порядке, там в хелпе написано:
Цитата
y(n)=( a0*x(n)+a1*x(n-1)+a2*x(n-2) ) – ( b1*y(n-1) + b2*y(n-2) )
Goodefine
Цитата(AHTOXA @ Sep 19 2009, 02:16) *
Но хоть заработало? smile.gif

Не-а, не хочет он с включенной оптимизацией считать
Код
Y0=0.00625*(X0+X4)-0.125*X2 + 1.875*Y1-2*Y2 + 1.0625*Y3 -0.3125*Y4;

ну не может за 1,25мкс он это просчитать. Сходу не пойму где грабли sad.gif
А с выключенной - 129мкс, чуть более 125мкс sad.gif В любом случае 2,5В на выходе smile3046.gif
dimka76
Цитата(Goodefine @ Sep 19 2009, 03:43) *
Не-а, не хочет он с включенной оптимизацией считать
Код
Y0=0.00625*(X0+X4)-0.125*X2 + 1.875*Y1-2*Y2 + 1.0625*Y3 -0.3125*Y4;

ну не может за 1,25мкс он это просчитать. Сходу не пойму где грабли sad.gif
А с выключенной - 129мкс, чуть более 125мкс sad.gif В любом случае 2,5В на выходе smile3046.gif


А вы по ассемблеру посмотрите.
А с флоатами лучше не связываться.
Я как-то делал генератор синуса, так с флоатами амплитуду колебаний потехоньку возрастала , сделал с фиксированной точкой 1:15 и амплитуда четко стояла (сутки гонял).
SasaVitebsk
Эээээ...
Результат обсуждения меня не порадовал. laughing.gif

Я вам давал не теорию и не практику, а методику. Вы должны проследить и... сделать любой. А соответственно найти ошибки в моём. smile.gif Я ведь на бумаге всё это писал. Тем не менее там всё правильно... И нет никаких заморочек с компилятором.

1) Если вы посмотрите АЧХ фильтра, то вы поймёте что результат работы при строке
Код
X0=(int)ADCW-512;
и при строке
Код
X0=(int)ADCW;
должен быть одинаков! Фильтр вычитает постоянную составляющую.

2) Если бы я, для того чтобы проверить работу фильтра каждый раз ваял такую схему ... biggrin.gif
Нет конечно, респект и уважуха, но вы же всётаки прграммисты. smile.gif У них подход попроще .... biggrin.gif
Я написал для себя приложение в билдере по принципу ГКЧ и тестирую свой фильтр целиком, причём если надо, то использую нужные мне размерности переменных. Потом целиком эту прогу вырезаю и вставляю в IAR. Когда прочитал вашу бучу, то проанализировал.
Скажем так... smile.gif была неточность, но не в фильтре. Можно было и так как я выложил, но нужна небольшая коррекция. Вопрос какая?

Прикладываю фильтр, вырезанный из проги и результат тестирования. smile.gif
Код
    x4=x3;
    x3=x2;
    x2=x1;
    x1=x0;
    x0=ADC;

    y4=y3;
    y3=y2;
    y2=y1;
    y1=y0;

    tek16 = y1>>3;
    tek16 += x0+x2-y2;
    tek16 >>= 1;
    tek16 += x0+x2-x1+y1-y2;
    tek16 >>= 1;
    tek16 += y1-x1;

    y0 = tek16;


Затестите на своей чудо машинке. Ну и найдите причину хомута. sad.gif
Goodefine
Цитата(SasaVitebsk @ Sep 20 2009, 23:33) *
Эээээ...
Результат обсуждения меня не порадовал.Я вам давал не теорию и не практику, а методику. Вы должны проследить и... сделать любой. А соответственно найти ошибки в моём. Я ведь на бумаге всё это писал. Тем не менее там всё правильно...

Если Вы восприняли мой пост как критику в адрес своей методики, то спешу заверить, что это совершенно не так. Дело было поздно ночью, когда легко проглядеть ньюанс, подобный потерянному здесь... Тот случай - когда вроде все правильно, но не работает. Поэтому, собственно, вопрос и последовал...
Цитата(SasaVitebsk @ Sep 20 2009, 23:33) *
2) Если бы я, для того чтобы проверить работу фильтра каждый раз ваял такую схему ...
Нет конечно, респект и уважуха, но вы же всётаки прграммисты. У них подход попроще ....
Я написал для себя приложение в билдере по принципу ГКЧ ...

Ну, имхо, модель простейшая и ваяется быстро, при определенных навыках - copy/paste smile.gif Когда под рукой нет необходимого инструментария для работы с цифровыми фильтрами - так тоже неплохо - плюс время выполнения в железе оценить можно, и подумать сколько звеньев поставить получится...
Цитата(SasaVitebsk @ Sep 20 2009, 23:33) *
Когда прочитал вашу бучу, то проанализировал...

Подымать бучу и в мыслях не было, уж извините если так получилось..
Цитата(SasaVitebsk @ Sep 20 2009, 23:33) *
Скажем так... была неточность, но не в фильтре. Можно было и так как я выложил, но нужна небольшая коррекция. Вопрос какая?

Неточность легко ищется незамыленным глазом: читаем хелп:
Цитата
y(n)=( a0*x(n)+a1*x(n-1)+a2*x(n-2) ) – ( b1*y(n-1) + b2*y(n-2) )

И ключевая Ваша фраза:
Цитата
Я упрощу выражение и вместо X(i-1) буду писать X1 и так далее....

следование которой и привело к неточности: X(n-4) стал Х4, а Xn -> X0 (и т.д.). А привязка коэфф. не изменилась. В то время как X4 (если его номер рассматривать как порядковый номер следования отсчета во времени) на самом деле Xn. Иными словами перепутались коэффициенты с отсчетами. То же самое и с Yi. при этом следует еще учесть, что выход - это Y4. Тогда код фильтра будет такой:
Код
X4=X3;
X3=X2;
X2=X1;
X1=X0;
X0=(int)ADCW;

Y0=Y1;
Y1=Y2;
Y2=Y3;
Y3=Y4;

Temp = (X4+X0+Y1-Y0)>>1;
Temp -= X2+Y3;
Temp >>= 1;
Temp -= Y0;
Temp >>= 2;
Temp +=((Y3-Y2)<<1)+Y1;

Y4=Temp;

PORTD= (unsigned char) ((Y4+512)>>2);

Т.е. видно, что крайние Xi и Yi поменялись местами соответственно (X4<->X0,Y4<->Y0 и т.д.).
Цитата(SasaVitebsk @ Sep 20 2009, 23:33) *
Затестите на своей чудо машинке...

Затестил. работает. Только хочу заметить, что АЧХ фильтра не такая как на картинке - если верить модели, работает это скорее как ФВЧ, где - то от 400 Гц - далее подъем и спад до 3кГц почти не заметен...
А что касается первоначального фильтра - тоже работает, после исправлений - там частота резонанса около 1336,9 Гц... Откуда так точно? Все просто, иногда (не всегда) после снятия сигналов, фильтр звенит на этой частоте. Звон правда достаточно малый - амплитуда около 0,02В (одна градация ЦАПа). Спад АЧХ возле этой частоты заметен на глаз, что называтся... Вот как то так...
Еще раз спасибо Вам, что потратили свое время на очевидные объяснения..
SasaVitebsk
Цитата(Goodefine @ Sep 21 2009, 16:45) *
Затестил. работает. Только хочу заметить, что АЧХ фильтра не такая как на картинке - если верить модели, работает это скорее как ФВЧ, где - то от 400 Гц - далее подъем и спад до 3кГц почти не заметен...


smile.gif
Так я и выбрал фильтр собственно весьма пологий. Да ещё и всего-лишь 3-его порядка.
Мне кажется, что людям было-бы интересно узнать сколько "завесил" такой фильтр. Сколько он отъел ресурсов.

Я, в свою очередь хотел бы отметить, что полосовой фильтр 5-го порядка легко реализуется на 1.8МГц при частоте выборки 6800 вместе с ФНЧ и перемножением сигнала. smile.gif AVR при этом кушает менее 1ма.
_Ie0nid
здраствуйте, простите за то что долго не было, и за глупые вопросы.

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

Первое: мне объясняли принцип действия цифрового фильтра и она заключается в следующем. Допустим первая выборка равна 8, вторая 8, затем третья равная 10, четвертая равная 8, и пятая снова 8. Если на третью приходилась высокочастотная составляющая, и мы ее в соответствующем такте уменьшаем с соответствующим коэффициентом усиления (например отрицательным), то поучается ФНЧ. Если я не прав то поправьте пожалуйста, потому как:,

второе: судя по рисункам которые приводятся в книгах, и по формуле которую привел SASAVITEBSK (за что огромное спасибо, навила хоть на мысли),

Y(i) = X(i) + 0.875Y(i-1) - X(i-1),

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

третье: Я примерно прикинул формулу на бумажке, она действительно убирает постоянную составляющую, если сигнал постоянный, каждая последующая выборка на выходе будет стремится к нулю. Крутизна фильтра я так понимаю определяется количеством членов формулы (полинома?). А вот коэффициент ослабления? И потом как синтезировать такую формулу исходя из нужного фильтра. Например ФНЧ, или ФВЧ.

И наконец, четвертое. В схемах фильтра нарисован сумматор, можете объяснить его физический смысл. Если мы складываем два аналоговых сигнала с разными частотами (например две палки спектра), мы получаем сигнал с этими двумя палками. Если мы складываем выборки в разные такты мы получаем просто число. Или же весь смысл этого сумматора (и вообще всех кубиков в структуре фильтра) в том, чтобы подобрать такую формулу, чтобы она выполняла нужную для нас манипуляцию с выборками (то есть нужную АЧХ).
Заранее спасибо.
SasaVitebsk
Цитата(_Ie0nid @ Sep 22 2009, 07:58) *
Вы привели формулу, которую я пытался понять с помощью каких то физических принципов, в результате натыкался на точно такие же формулы.

Если вы пытаетесь разобраться в теории, тем более в теории цифровой фильтрации задавая простые вопросы на форуме, то это тупик. Здесь вы единственное, что можете узнать это название книги и имя автора. А далее - только читать. Если не понимаете - берёте другую книгу, читаете несколько раз и так до момента просветления. smile.gif
Цитата
Первое: мне объясняли принцип действия цифрового фильтра и она заключается в следующем. Допустим первая выборка равна 8, вторая 8, затем третья равная 10, четвертая равная 8, и пятая снова 8. Если на третью приходилась высокочастотная составляющая, и мы ее в соответствующем такте уменьшаем с соответствующим коэффициентом усиления (например отрицательным), то поучается ФНЧ. Если я не прав то поправьте пожалуйста, потому как:,

bb-offtopic.gif
Попытка на пальцах объяснить теорию, насчитывающую тома - это глупость. Вы уж извините, не хочу никого обидеть. Я не являюсь знатоком теории фильтрации, но тем не менее убеждён, что попытка упрощения до уровня домохозяйки, даёт только ложные представления. Результат мы видим повсеместно, когда комбайнёты и директора колхозов становятся руководителями страны. Хотите стать проффессионалом в своём деле - попробуйте им стать.
Цитата
второе: судя по рисункам которые приводятся в книгах, и по формуле которую привел SASAVITEBSK (за что огромное спасибо, навила хоть на мысли),

Y(i) = X(i) + 0.875Y(i-1) - X(i-1),

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

В той программе, которую я выкладывал - есть HELP, как это не странно. Там есть формула. А то что выше я привёл как прикол. Она как раз не очень ложится на теорию. Тем не менее действительно работает. Я её выдрал из какого-то апнота TI. Её АЧХ можно посмотреть той же прогой, что я прикладывал.
Цитата
третье: Я примерно прикинул формулу на бумажке, она действительно убирает постоянную составляющую, если сигнал постоянный, каждая последующая выборка на выходе будет стремится к нулю. Крутизна фильтра я так понимаю определяется количеством членов формулы (полинома?). А вот коэффициент ослабления? И потом как синтезировать такую формулу исходя из нужного фильтра. Например ФНЧ, или ФВЧ.

Формула определяется не типом сигнала, а типом выбранного фильтра. Например в той проге которую я приложил используется фильтр Батерворта. Если запустить знаменитый QED2000, то там этих фильтров - море. А в теории ещё больше. Каждый фильтр имеет свои особенности. Например некоторые имеют минимальные фазовые искажения и т.д. Формула для каждого из этих фильтров уже определена задолго до того, как вы задумались на эту тему. Сама формула представляет собой полином. Прикладная же задача состоит в том, чтобы исходя из характеристик фильтра и частоты дискретезации выбрать коэффициенты полинома и подставить в уже готовую формулу. В этом, как правило помогают готовые программы. Например та же QED или та, что привёл я. Я же рассказывал методику как довести коэффициенты до программы. smile.gif То есть всё это теории ни грамма не касается. Ни каким боком.
Цитата
И наконец, четвертое. В схемах фильтра нарисован сумматор, можете объяснить его физический смысл. Если мы складываем два аналоговых сигнала с разными частотами (например две палки спектра), мы получаем сигнал с этими двумя палками. Если мы складываем выборки в разные такты мы получаем просто число. Или же весь смысл этого сумматора (и вообще всех кубиков в структуре фильтра) в том, чтобы подобрать такую формулу, чтобы она выполняла нужную для нас манипуляцию с выборками (то есть нужную АЧХ).
Заранее спасибо.

Книги и ещё раз книги.
Goodefine
Цитата(SasaVitebsk @ Sep 21 2009, 23:27) *
Мне кажется, что людям было-бы интересно узнать сколько "завесил" такой фильтр. Сколько он отъел ресурсов...

При уровне оптимизации -03 (по скорости) тело фильтра занимает 68 байт и выполняется, при тактовой частоте 16384000 Гц примерно за 3мкс. При периоде в 125мкс (8000кГц) это занимает не более 2.5% процессорного времени. Откуда видно, что при снижении тактовой до 1Мгц еще не менее 50% времени останется... При оптимизации по размеру, время незначительно увеличивается, а размер незначительно уменьшается. Ток потребления неизвестен (модель), но существуют широкие возможности для его уменьшения

Цитата(_Ie0nid @ Sep 22 2009, 07:58) *
...И наконец, четвертое. В схемах фильтра нарисован сумматор, можете объяснить его физический смысл...

Сумматором можете не заморачиваться. Он там только для того, чтобы арифметически правильно сложить сигналы с разными частотами....
MrYuran
Цитата(_Ie0nid @ Sep 22 2009, 08:58) *

Учите матчасть.
Кстати, цифровыми методами можно синтезировать физически нереализуемый фильтр rolleyes.gif
Так что физический смысл в цифровой фильтрации искать бесполезно.

Кстати, забавная задачка на вшивость, на которой я засыпался на зачёте:
Входной аналоговый сигнал -> АЦП -> ЦАП -> Выходной аналоговый сигнал
Как будут различаться спектры входного и выходного сигнала?
(для простоты, разрядность и частота дискретизации ЦАП и АЦП совпадают)
_Ie0nid
РАЗОБРАЛСЯ, тут еще на работе мне паренек здорово подсказал, так что большое спасибо всем за помощь.
Fix
Подскажите, пожалуйста. что представляет собой кольцевой буфер для входных значений фильтра (полосового)?
DRUID3
Цитата(Fix @ Dec 27 2009, 20:27) *
Подскажите, пожалуйста. что представляет собой кольцевой буфер для входных значений фильтра (полосового)?

Допустим Вы хотите сделать кольцевой буфер размера N на основе массива(можно еще на основе связанного списка, это просто - указатель последнего элемента должен указывать на первый, но он намного "тяжеловеснее" чем на основе массива). Функция которая отвечает за запись и/или чтение из буфера дожна при этом обеспечивать кольцевую адресацию. Тоесть достигнув элемента массива N-1(т.к. в C адресация начинается с "0") начать запись вновь с "0"-го элемента.

"Счетчик" сбрасывают многими конструкциями. if(i=N){i=0}, i=i%N или i=(i)&(N). Последний случай - это наложение маски. Работает очень быстро - но только для порядка из ряда целой степени двойки. Первый - предполагает ветвление - потому, как-бы, чисто теоретически - это не хорошо для кэша(а автомат-способ его работы у каждого процессора свой). Но лучше посмотреть, что наваял компилятор в ассемблерном листинге - т.е.есть ли ветвление вообще.

Для многих типов DSP можно инициализировать счетчик как кольцевой, он представляет из себя отдельный автомат - т.е. работает без затрат производительности.

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

P.S.: Сам кольцевой буфер проистекает от формулы свертки (это той, что по-идее должен знать каждый второкурсник ВТУЗа biggrin.gif biggrin.gif biggrin.gif ) - потому форма АЧХ(полосовой или какой иной) при этом никакой рояли не играет...

P.P.S.: исправил очепятку! Ибо знаю по-себе в какой ступор они приводят начинающих biggrin.gif ...
Xenia
Цитата(DRUID3 @ Dec 28 2009, 01:26) *
"Счетчик" сбрасывают многими конструкциями. if(i=N){N=0}, i=i%N или i=(i)&(N). Последний случай - это наложение маски. Работает очень быстро - но только для порядка из ряда целой степени двойки.

Всё правильно. Только дополню, что существует особый случай, когда кольцевой буфер работает особенно изящно и быстро - это случай, когда он расчитан на 256 элементов. В этом случае, достаточно сделать "счетчик" цикла типа unsigned char, чтобы всё заработало само собой. Ведь в один байт число, большее чем 255 не запихнешь, поэтому такой счетчик будет "автоматически" сбрасываться при переполнении.
Кольцевые буферы на 256 элементов оказываются очень удобным инструментом не только для означенной цели, но и для буферизации приема и передачи по UART и USB, т.е. когда прием или получение приходят по прерыванию (UART) или когда отправлять по одному байту неэффективно (USB).
Примечание: у некоторых дурных компиляторов (кажется для MSP430) тип char трактуется как 2 байта, тогда ищите там другой однобайтный тип.
rezident
Цитата(Xenia @ Dec 28 2009, 04:01) *
Примечание: у некоторых дурных компиляторов (кажется для MSP430) тип char трактуется как 2 байта, тогда ищите там другой однобайтный тип.
Это про CodeComposer Studio для серии TMS320.
Xenia
rezident
А однобайтный тип там есть?
V_G
Вообще кольцевой буфер легко реализуется, если его длина не только 256, но и 2n. Просто в адресе (смещении от начала массива) маскируете n младших бит

Про БИХ еще добавлю, если топикстартер еще не получил внятный ответ. Более-менее серьезные БИХ фильтры не возбуждаются только при расчетах в формате double. Это легко увидеть в Матлабе, введя округление до желаемого типа данных. А про целый формат и говорить нечего, только простейший аналог однозвенного RC-фильтра. Так что в целых - только КИХ-фильтры!
rezident
Цитата(Xenia @ Dec 29 2009, 00:28) *
А однобайтный тип там есть?
Да какая разница? "Затачивание" на типы переменных, без явной проверки на выход за границы массива это потенциальный источник большого количества глюков программ. Именно такие уязвимости часто используют хакеры. Ваш совет считаю "вредным". В крайнем случае можно делать так, как V_G написал - маскировать старшие биты счетчика/индекса, урезая его разрядность. Но при этом остается проблема атомарности доступа к его значению.
Fix
При расчете коэффициентов полосового фильтра с помощью программы ciirf1, рекомендованной SasaVitebsk, и при расчете в MatLab получаются совершенно разные их значения , ciirf1 постоянно дает значение a1=0 и a3=0, почему?
V_G
Существуют разные алгоритмы синтеза фильтров и разные способы реализации одних и тех же требований к фильтрам. В том же Матлабе вы можете получить одинаковую амплитуду лепестков в полосе задержания (equiripple) или спадающую. Тут главное, чтобы результирующая ЧХ удовлетворяла. И чтобы было меньше негативное влияние округления (в Матлабе, повторю, можно увидеть отличия от расчетных характеристик при различных способах округления на различных этапах расчетов). Каким будет при этом a1, a3, не знаю. Есть одно строгое требование к коэффициентам КИХ: их сумма должна быть равна коэффициенту передачи на постоянном токе. Т.е. нулю для ФВЧ и ПФ.
mdmitry
Добавлю, что АЧХ фильтра и ФЧХ связаны между собой. В filterdesign MATLAB можно варьировать (оптимизировать) характеристики фильтра.
SasaVitebsk
Цитата(Fix @ Dec 30 2009, 14:48) *
... рекомендованной SasaVitebsk ...

Боже упаси. smile.gif

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

При выборе и обкатке своих фильтров я моделирую их поведение более сложно. Ну а на чёрную иногда ...

smile.gif

Я просто привёл пример, чтобы начинающие программисты не боялись применять такую технологию как цифровая фильтрация.
Serhiy_UA
Цитата(SasaVitebsk @ Dec 31 2009, 00:35) *
...Существует большое количество других программ. Например QED...


Спасибо, очень интересный ресурс с QED. Кстати его адрес
http://www.kanecomputing.co.uk/mds_qedesign_lite.htm

Может не по теме, но там мощно..
http://www.kanecomputing.co.uk/
Rst7
Цитата
Всё правильно. Только дополню, что существует особый случай, когда кольцевой буфер работает особенно изящно и быстро - это случай, когда он расчитан на 256 элементов. В этом случае, достаточно сделать "счетчик" цикла типа unsigned char, чтобы всё заработало само собой.


Правильные пацаны работают прямо с указателями, а не индексами, и в таком случае даже буфер размещают с адреса, кратного 256, и тогда можно прямо младший байт указателя насиловать, не трогая старший. Ну или, если применяется операция and, то тоже можно выбрать правильный адрес начала буфера для уменьшения оверхеда. Второй совет, кстати, куда более универсальный, практически архитектурно-независимый.
galjoen
Цитата(SasaVitebsk @ Sep 17 2009, 22:45) *
Temp = (X0+X4+Y3-Y4)>>1; // все члены со сдвигом 4 = 1,7,9
Temp += (-X2-Y1); // ... 3 = 2,4 Естественно лучше записать Temp -= X2+Y1;
Temp >>= 1;
Temp += (-Y4); // .... 2 = 8 Опять таки Temp -= Y4;
Temp >>= 2; // Поскольку у нас нет членов со сдвигом >>1
Temp += (Y1<<1)-(Y2<<1)+Y3;

Если уж речь идёт о ATmega, то почему бы не использовать вместо этого извращения умножение командами mul...fmuls? Тогда при изменении коэффициентов не придётся каждый раз переписывать код программы. А небольшое увеличение времени (если оно ешё будет) тут, как я понял, совершенно не критично.

Я делал что-то подобное (не помню как оно научно называется) без обратных связей. Т.е. все элементы Y=0. Но с FIFO 256 слов. И умножал на коэффициенты в форме с плавающей запятой. Только была одна хитрость. Порядок у моих самодельных флоатов был представлен в виде кодов 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80. Т.е., если сначала перемножить мантисы, а затем умножить командой mul полученную мантису на порядок, получалось собственно число.
Мне пришлось сделать таким образом т.к. коэффициенты были заранее неизвестны. Они вычислялись и уточнялись в процессе работы. И с быстродействием проблеммы были. Деление 16/16 из-за этого тоже пришлось переделать - меньше 60 тактов получилось.
Rioi
Все знают о существовании таких файлов:
1) AVR201: Using the AVR® Hardware Multiplier
2) AVR223: Digital Filters with AVR
все знают, и молчат..., короче- двадцать команд на одно умножение с накоплением?:

Код
mac16x16_32:
    clr    r2
    muls    r23, r21    ; (signed)ah * (signed)bh
    add    r18, r0
    adc    r19, r1
    mul    r22, r20    ; al * bl
    add    r16, r0
    adc    r17, r1
    adc    r18, r2
    adc    r19, r2
    mulsu    r23, r20    ; (signed)ah * bl
    sbc    r19, r2
    add    r17, r0
    adc    r18, r1
    adc    r19, r2
    mulsu    r21, r22    ; (signed)bh * al
    sbc    r19, r2
    add    r17, r0
    adc    r18, r1
    adc    r19, r2
    ret

fmac16x16_32:
    clr    r2
    fmuls    r23, r21    ; ( (signed)ah * (signed)bh ) << 1
    add    r18, r0
    adc    r19, r1
    fmul    r22, r20    ; ( al * bl ) << 1
    adc    r18, r2
    adc    r19, r2
    add    r16, r0
    adc    r17, r1
    adc    r18, r2
    adc    r19, r2
    fmulsu    r23, r20    ; ( (signed)ah * bl ) << 1
    sbc    r19, r2
    add    r17, r0
    adc    r18, r1
    adc    r19, r2
    fmulsu    r21, r22    ; ( (signed)bh * al ) << 1
    sbc    r19, r2
    add    r17, r0
    adc    r18, r1
    adc    r19, r2
    ret


А теперь для сравнения SAM3S (более удобный проц) :

"The SMLAL instruction interprets the values from Rn and Rm as two’s complement signed inte-
gers. It multiplies these integers, adds the 64-bit result to the 64-bit signed integer contained in
RdHi and RdLo, and writes the result back to RdHi and RdLo."

Код
    SMLAL       R4, R5, R3, R8  ; Signed (R5,R4) = (R5,R4) + R3 x R8

Вы рекомендуете использовать mul...fmuls ?...
galjoen
Цитата(Rioi @ Jan 6 2010, 13:21) *
А теперь для сравнения SAM3S (более удобный проц) :

1. Тема называется "Цифровой Фильтр на ATmega".
2. При умножении 8*16 (как в примере от SasaVitebsk) команд будет в 4 раза меньше.
SasaVitebsk
Цитата(Rioi @ Jan 6 2010, 14:21) *
все знают, и молчат..., короче- двадцать команд на одно умножение с накоплением?:

У меня в HART модеме при декодировании делается:
ФВЧ 2 порядка (убирается постоянная составляющая)
АРУ
ФНЧ 5 порядка (прямоугольник приводится к синусу ( более-менее ))
перемножение со сдвигом фазы относительно несущей
ФНЧ 5 порядка (само преобразование)
+
Разбор на биты/байты и передача.

Всё прерывание влазит в 550 тактов по максимуму. На чистом Си.

То есть надо понимать, смотря какая задача ставится. Одно дело работа со звуком, а другое детектирование DTMF для примера.
Конечно на ARM намного приятнее работать с такими вещами, но знания лишними не бывают. Писать "наотмашь", не беспакоясь за такты это хорошо, но в привычку входит. smile.gif

Для тех кто ковыряется иногда с малыми кристалами типа PIC/AVR/MSP написал прогу для подбора коэффициентов фильтра. Разбора на сдвиги короче. smile.gif
Если какие вопросы - пишите подправлю.
DRUID3
Забавная информация к размышлению для тех кто пишет алгоритмы ЦОС для "больших" ЭВМ (в том числе и старших ARM)...
Rst7
Цитата
Забавная информация к размышлению


Информация кагбэ намекает нам, что многостадийные конвейеры в процессорах - унылое гуано. Особенно доставляет то, что это отлично проявилось на пузырьке smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.