реклама на сайте
подробности

 
 
6 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> Цифровой Фильтр на ATmega, Цифровой Фильтр на ATmega
_Ie0nid
сообщение Sep 16 2009, 04:18
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 30
Регистрация: 20-09-08
Пользователь №: 40 344



Добрый день, давно не заходил с проблемами. КТо может помочь куском кода к цифровому фильтру для Codevision. Даже с чего начать не знаю, куда не сунусь везде только формулы да теория. Хочу попробовать отфильтровать сигнал снятый с ацп Atmegи, и преобразовать на выход с помощью ШИМ и RC цепи
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Sep 16 2009, 04:50
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 1 504
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Радиолюбительская конструкция.

Сообщение отредактировал Genadi Zawidowski - Sep 16 2009, 05:02
Go to the top of the page
 
+Quote Post
haker_fox
сообщение Sep 16 2009, 06:36
Сообщение #3


Познающий...
******

Группа: Свой
Сообщений: 2 562
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125



Цитата(_Ie0nid @ Sep 16 2009, 13:18) *
куда не сунусь везде только формулы да теория.

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


--------------------
Желаю всем гармонии с самими собой!
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Sep 16 2009, 07:30
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 704
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



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

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

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

Конечно, если более-менее сложная задача, то я сначала полностью моделирую процесс и обязательно его визуализирую. На всех этапах. Далее отрабатываю все формулы на модели. Потом уже переношу всё это на однокристалку. Для меня так проще.
Могу чего-нибудь на простом примере показать.
Прикрепленные файлы
Прикрепленный файл  ciirf1.zip ( 263.7 килобайт ) Кол-во скачиваний: 698
 
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Sep 16 2009, 07:39
Сообщение #5


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 587
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(SasaVitebsk @ Sep 16 2009, 11:30) *
1) Берём прогу расчёта фильтров, которую я приложил.

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

У меня дома валяется что-то подобное, но вся проблема в вычислении коэффициентов передачи.
Неплохо было бы автоматизировать


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Sep 16 2009, 08:14
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 704
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(MrYuran @ Sep 16 2009, 10:39) *
Неплохо было бы автоматизировать

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

В той проге, что я выложил можно править коэффициенты и смотреть результирующий график. Это очень удобно. Иногда расчётное значение весьма сложное получается, сначала пробуешь обрезать лишнее и смотришь на результат. smile.gif
Есть конечно и QED, но как то не сложилось ... smile.gif
Go to the top of the page
 
+Quote Post
ZVE
сообщение Sep 17 2009, 11:18
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 28
Регистрация: 19-11-07
Из: Vinnitsa, UA
Пользователь №: 32 472



Цитата(SasaVitebsk @ Sep 16 2009, 10:30) *
Могу чего-нибудь на простом примере показать.

Да покажите пример пожалуйста. Например приведенный Вами же фильтр который убирает постоянку.
Думаю топикстартеру будет полезно, да и многим другим тоже(в том числе и мне rolleyes.gif ).
Заранее благодарю.
Go to the top of the page
 
+Quote Post
Legotron
сообщение Sep 17 2009, 13:04
Сообщение #8


инопланетянин
***

Группа: Свой
Сообщений: 236
Регистрация: 24-12-06
Из: Питер
Пользователь №: 23 832



Цитата(MrYuran @ Sep 16 2009, 11:39) *
А для КИХ есть что-то подобное?

А почему бы не использовать Matlab?
Там есть и КИХ и БИХ. Плюс есть ФЧХ и картинка с полюсами! Плюс всё можно качественно промоделировать.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 17 2009, 13:17
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 7 966
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Legotron @ Sep 17 2009, 16:04) *
А почему бы не использовать Matlab?
Может потому, что он стоит немалых для любителя денег?
Есть бесплатная альтернатива - SciLab, но в нем нет таких красивых и удобных надстроек.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Serhiy_UA
сообщение Sep 17 2009, 13:19
Сообщение #10


Знающий
****

Группа: Свой
Сообщений: 714
Регистрация: 23-10-08
Из: next to Odessa
Пользователь №: 41 112



Много лет назад экспериментировал на ATmega16 со звуковыми частотами. То же АЦП-цифровой фильтр-ШИМ-RC. Строил НЧ и ВЧ фильтры с БИХ, с аккумулятором сумм до 32-бит, а также коэффициентами до 16-бит. Фильтры в итоге всегда самовозбуждались. Тема по прежнему актуальна.
Кто либо построил и реально использовал такие фильтры, есть ли положительные результаты, чем рассчитывали коэффициенты?
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Sep 17 2009, 19:45
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 2 704
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(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 бит для получения приемлемого сигнала, требовалась выходная обвеска сопоставимая с размерами изделия. Причём настройка-регулировка была бы непростая.
Короче из всех вариантов этот был самым отвратительным. Существуют внешние цапы, в том числе звуковые, в том числе с нелинейной характеристикой и встроенными цифровыми фильтрами. Стоят - копейки. С фильтрами проблем не было. Правда, как я говорил обработка была весьма топорная.
Эскизы прикрепленных изображений
Прикрепленное изображение
Прикрепленное изображение
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
Goodefine
сообщение Sep 18 2009, 21:08
Сообщение #12


Местный
***

Группа: Свой
Сообщений: 208
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581



Цитата(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-ми бит (дабы избежать переполнения) картины не меняет...
Что может быть не так в консерватории?...


--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Sep 18 2009, 21:24
Сообщение #13


фанат дивана
******

Группа: Свой
Сообщений: 3 274
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Скорее всего причина вот тут:
Код
    X0=ADCW-512;

Попробуйте заменить на
Код
    X0=(int)ADCW-512;


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Goodefine
сообщение Sep 18 2009, 21:38
Сообщение #14


Местный
***

Группа: Свой
Сообщений: 208
Регистрация: 6-08-07
Из: Приднестровье, Тирасполь
Пользователь №: 29 581



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

Картина та же...


--------------------
Любой, заслуживающий внимания, опыт приобретается себе в убыток...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Sep 18 2009, 22:12
Сообщение #15


фанат дивана
******

Группа: Свой
Сообщений: 3 274
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Тогда наоборот, замените в объявлении Xi, Yi и Temp int на unsigned int.
Ну и не вычитайте 512, конечно.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post

6 страниц V   1 2 3 > » 
Reply to this topicStart new topic
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2017 - 04:45
Рейтинг@Mail.ru


Страница сгенерированна за 0.05337 секунд с 7
ELECTRONIX ©2004-2016