Алгоритм сглаживания шумов АЦП микроконтроллера.

Обсуждаем контроллеры компании Atmel.
Ответить
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2314
Зарегистрирован: Вт янв 26, 2021 22:33:21

Сообщение Alex_641 »

если хочешь ?
Не спрашивай по ком звонит колокол, он звонит по тебе !
Реклама
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Это не я хочу, это вы хотите узнать причину зацикливания. Лишний элемент не может быть причиной, а вот чужое значение очень даже может...
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2314
Зарегистрирован: Вт янв 26, 2021 22:33:21

Сообщение Alex_641 »

хорошо.
Я попробую спрятать под спойлер. Если получится. Ещё не делал этого.

Добавлено after 1 minute 30 seconds:
Спойлер

Код: Выделить всё

/*******************************************************
Date    : 05.02.2023
Chip type               : ATtiny26
AVR Core Clock frequency: 4,000000 MHz
*******************************************************/

#include <alcd.h>
#include <delay.h>
#include <tiny26.h>
#define key PORTB.0     /// вход кнопка выкл. и переключение диаппазона 500/1000    
#define red PORTB.1     // питание красный светодиод индикация состояния акб
#define green PORTB.2   // питание зелёный светодиод индикация состояния акб
#define sw_off PORTB.3   // выход отключения питания 
#define l_h PORTB.4      //500/1000 
unsigned char i;   // вспомогательные переменные
unsigned int mass[20],z,tim,bat;
int a;


#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (0<<ADLAR)) // Voltage Reference: AREF pin


unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | ADC_VREF_TYPE;
delay_us(10);
ADCSR|=(1<<ADSC);
while ((ADCSR & (1<<ADIF))==0);
ADCSR|=(1<<ADIF);
return ADCW;
}

void main(void)
{
 
DDRA=(1<<DDA7) | (1<<DDA6) | (1<<DDA5) | (1<<DDA4) | (0<<DDA3) | (1<<DDA2) | (1<<DDA1) | (1<<DDA0);
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (1<<PORTB0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 3,906 kHz
TCCR0=(1<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 0,244 kHz
// Timer Period: 1,0486 s
PLLCSR=(0<<PCKE) | (0<<PLLE) | (0<<PLOCK);

TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<PWM1A) | (0<<PWM1B);
TCCR1B=(0<<CTC1) | (0<<PSR1) | (1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10);
TCNT1=0x00;
OCR1A=0x00;
OCR1B=0x00;
OCR1C=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<TOIE0);

// ADC initialization
// ADC Clock frequency: 62,500 kHz
// ADC Voltage Reference: AREF pin
//ADMUX=ADC_VREF_TYPE;
//ADCSR=(1<<ADEN) | (0<<ADSC) | (0<<ADFR) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);


// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTA Bit 0
// RD - PORTB Bit 7
// EN - PORTA Bit 1
// D4 - PORTA Bit 2
// D5 - PORTA Bit 4
// D6 - PORTA Bit 5
// D7 - PORTA Bit 6
// Characters/line: 16
sw_off=1; // удерживаем питание включенным ( защёлка механической кнопки на полевом ключе)
lcd_init(16);
lcd_gotoxy(0,0);  //инициализация лсд
lcd_putsf("U=500V "); //вывод на жки 
lcd_gotoxy(8,0);
lcd_putsf("R=");
lcd_gotoxy(0,1);
lcd_putsf("BAT=");
delay_ms(3000);
while (1)
      {
       
      for (i=0;i<20;i++) mass[i]=read_adc(9);  // +++++++++++++++++++++++++счтываем 20 значений ацп помещаем в массив mass
                         
      while (a>0)    // сортировка массива методом пузырька кол-во элементов 20    //+++++++++++++++расчёт измерений АЦП+++++++++++++++++++++
               {
                  for (i=0;i<20;i++)   // цикл 
                      {
                       a=0;             // флаг окончания сравнений сбросить
                        if (mass[i]>mass[i+1])  // если элемент меньше следующего то
                                       {
                                        z=mass[i];          // поменять
                                         mass[i]=mass[i+1]; // их
                                          mass[i+1]=z;      // местами
                                           a=1;             // установить флаг ( сортировка еще не закончена)
                                       }
                
                      }
               }
              lcd_putsf("BAT="); 
           TCNT1=0;// так надо ????????????????????????    
           z=0;    
           for (i=4;i<15;i++) z+=mass[i]; //суммируем 10 значений ( с 5-го по 14 )
            z=z/10; // находим среднее арифметическое
            lcd_gotoxy(10,0);// выводим значение на LCD
            lcd_putchar(z/100+48); //сотые 
            lcd_putchar((z%100)/10+48);// десятые
            lcd_putchar(z%10+48);  // единицы
            lcd_putsf("M  ");  // в конце выведенного числа буква "М" ( мегаом) с пробелами для затирания предыдущего показания
                                   // в дальнейшем буду исключать незначащие нули.
            
            if (key==0) {tim+=TCNT1; if (tim>10) sw_off=0; }//проверяем нажата ли кнопка если нажата более 2 сек отключаем питание
             
            else if (tim>1 && tim<5) {                                // если не нажата но счётчик времени нажатия не равен нулю значит было 
                                        tim=0;                        // отпускание кнопки и если время нажатия входит в пределы
                                        lcd_gotoxy(2,0);                   
                                         if (l_h==0) {l_h=1;lcd_putsf("1000V");} else {l_h=0;lcd_putsf("500V ");} // изменяем состояние выхода 500/1000 вольт
                                      };// 

           bat=read_adc(8); // замеряем напряжение на батарее питания
            lcd_gotoxy(1,4);  // выводим на табло
             lcd_putchar(bat/100+48); //вольт
              lcd_putsf(",");    
               lcd_putchar((bat%100)/10+48);// десятые   
                lcd_putchar(bat%10+48);  // единицы
                 lcd_putsf("V ");  
                
            if ( bat<334) {red=1;green=0;}   // если напруга акб < 6,6 В ( два лития ) зажеч красный потушить синий
            if (bat>333 && bat<360) {red=1;green=1;}// ну и так далее
            if ( bat>359) {red=0;green=1;}
               

      }
}

Не спрашивай по ком звонит колокол, он звонит по тебе !
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Зачем прятать? Всего то нужно показать объявление самого массива и то, что непосредственно за ним.
Ну либо тот же скрин с map-файла проекта.

Добавлено after 2 minutes 55 seconds:
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367162#p4367162"]хорошо......unsigned int mass[20],z,tim,bat;[/uquote]
Итого имеем. Вы портите значение z.
Можете сами проанализировать... :tea:

Код: Выделить всё

                                      z=mass[i];          // поменять
                                         mass[i]=mass[i+1]; // их
                                          mass[i+1]=z;      // местами
То есть по факту во второй строке mass=z;, а в третьей z=z;
Последний раз редактировалось КРАМ Вс фев 05, 2023 21:58:08, всего редактировалось 1 раз.
Реклама
Эиком - электронные компоненты и радиодетали
u37
Говорящий с текстолитом
Сообщения: 1524
Зарегистрирован: Пн май 01, 2017 20:01:45

Сообщение u37 »

[uquote="КРАМ",url="/forum/viewtopic.php?p=4367111#p4367111"][uquote="Alex_641",url="/forum/viewtopic.php?p=4367089#p4367089"]но проходов 19 ![/uquote]
Даладна... :))) :))) :)))

Код: Выделить всё

for (i=0;i<20;i++)   // цикл
От 0 до 19 - это сколько будет?
1 класс средней школы...[/uquote]
"От 0 до 19" будет 19
Реклама
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Еще один йуморист... :))) :))) :)))
Реклама
Мудрый кот
Сообщения: 1763
Зарегистрирован: Вт янв 05, 2016 10:14:25
Откуда: поселок Мелеуз

Сообщение Novice user »

А так?
Спойлерwhile (a>0) // сортировка массива методом пузырька кол-во элементов 20 //+++++++++++++++расчёт измерений АЦП+++++++++++++++++++++
{a=0; // флаг окончания сравнений сбросить

for (i=0;i<19;i++) // цикл
{
if (mass>mass[i+1]) // если элемент меньше следующего то
{
z=mass; // поменять
mass=mass[i+1]; // их
mass[i+1]=z; // местами
a=1; // установить флаг ( сортировка еще не закончена)
}

}
}
Последний раз редактировалось Novice user Вс фев 05, 2023 22:08:47, всего редактировалось 1 раз.
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2314
Зарегистрирован: Вт янв 26, 2021 22:33:21

Сообщение Alex_641 »

А разница то какая ? Z - просто переменная промежуточная .
Не спрашивай по ком звонит колокол, он звонит по тебе !
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="Alex_641",url="/forum/viewtopic.php?p=4367174#p4367174"]А разница то какая ?[/uquote]
Я вам причел что по факту получилось. А получилось ОТСУТСТВИЕ СОРТИРОВКИ в 20-м проходе.
Последний раз редактировалось КРАМ Вс фев 05, 2023 22:13:07, всего редактировалось 1 раз.
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2314
Зарегистрирован: Вт янв 26, 2021 22:33:21

Сообщение Alex_641 »

Главное запомните - пузырёк на 0,5 !

Добавлено after 1 minute 37 seconds:
КРАМ писал(а): получилось ОТСУТСТВИЕ СОРТИРОВКИ.
Да ! Потому что привлекался неопознанный 21-й обьект .Спасибо.

Добавлено after 2 minutes 49 seconds:
А если вообще сделаю конструкцию ! То это будет круто для электриков ))
Не спрашивай по ком звонит колокол, он звонит по тебе !
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

Вы еще не поняли, что никаких 0,5 нет и в помине. Просто дергайте ногой в начале сортировки и в конце с реальными массивами. И удивляйтесь результату...
:))) :))) :)))

Добавлено after 2 minutes 4 seconds:
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367177#p4367177"]А если вообще сделаю[/uquote]
Дай вам Б-г... А я чевойта сомневаюсь, однако... :)
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2314
Зарегистрирован: Вт янв 26, 2021 22:33:21

Сообщение Alex_641 »

Если чесно ....мне вот совсем по... Но .

Добавлено after 1 minute 16 seconds:
КРАМ писал(а):конце с реальными массивами
а дело то в конце ! Насколько он будет быстрым !

Добавлено after 1 minute 13 seconds:
Ты хочешь меня просто размазать по бетону, и сказать что пузыря на 0,5 не существует ?
Не спрашивай по ком звонит колокол, он звонит по тебе !
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="Alex_641",url="/forum/viewtopic.php?p=4367187#p4367187"]Ты хочешь меня просто размазать ?[/uquote]
Зачем? Я просто знаю результат.... Ну и резонно полагаю, что искать дурее себя не стоит. Очевидно, что ваша "идея" лежит на поверхности для столь изъезженной вдоль и поперек темы сортировки. Не катит, увы. Особенно с учетом скрипучести по проблеме лишнего элемента...
u37
Говорящий с текстолитом
Сообщения: 1524
Зарегистрирован: Пн май 01, 2017 20:01:45

Сообщение u37 »

[uquote="КРАМ",url="/forum/viewtopic.php?p=4367168#p4367168"]Еще один йуморист... :))) :))) :)))[/uquote]
Вовсе нет, возвращаю должное флудеру.
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="u37",url="/forum/viewtopic.php?p=4367198#p4367198"]возвращаю[/uquote]
Странный способ возврата - писать ахинею... :dont_know:
Может стоило просто конструктивно возразить? Или этот вариант априори не рассматривался?
Это не хвост, это антенна
Сообщения: 1495
Зарегистрирован: Ср июн 25, 2008 15:19:44

Сообщение Demiurg »

Alex_641, вот мой рабочий пример. Посмотрите его повнимательнее.
Пусть у нас 4 элемента. 3-1-10-9. Адресация в цифровой электронике начинается с 0. Он же условно "первый" элемент.
Ptr_1 на нулевой 0 "первый" элемент (3). Ptr_2 на 1 "второй" элемент (1). Начинаем двигать. Сколько сдвигов? 3. То есть size - 1. В моем примере вы увидите константу размер массива. В функции вы увидите size - 1.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7083
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

А что если не сортировать массив, а метить самый маленький из найденных элементов и исключать его из выборки, так первый помеченный будет самым маленьким, второй помеченный - вторым снизу...
для меток можно создать отдельный массив, а можно обратимо модифицировать элементы исследуемого массива:
т.к. измерение АЦП занимает 10 бит, то старшие 6 всегда == 0, любой из них можно занять под метку...
кстати такая метка автоматически увеличивает элемент настолько, что он уже точно не станет самым маленьким (таким методом мы убиваем сразу 2х зайцев :kill: )

код получится примерно таким:
1) организовываем кольцевой буфер (запись в него нового значения вытесняет самое старое), длина буфера равна 2длинам отсекаемых хвостов и 1 длине усредняемой середины.
2) в цикле находим самый маленький элемент и если i (количество итераций цикла) меньше длины хвоста то просто помечаем его:
X|=0x8000; //под метку отдали самый старший бит.
если i больше длины хвоста, то перед тем, как поставим метку, Х добавим в аккумулятор.
цикл проводим (длина хвоста+длина середины) раз.
затем пробегаем массив вторым циклом, в котором сбрасываем установленные первым циклом метки:
X&=~0x8000;
затем делим значение аккумулятора на длину середины и получаем среднемедианное значение - какраз то, что мы и ищем.
Достоинства метода:
1) не нарушается порядок элементов - не нарушается работа кольцевого буфера
2) не требуется дополнительная память для хранения и сортировки элементов.
3) высокая скорость вычисления.

Добавлено after 15 minutes 36 seconds:
Можно сделать фильтрацию с опорой на предыдущий вычисленный элемент:

Код: Выделить всё

если новое значение больше предыдущего
{если разница больше уставки гистерезиса {выодим новое значение}иначе{выводим старое+1}}
если новое значение меньше предыдущего
{если разница больше уставки гистерезиса {выодим новое значение}иначе{выводим старое-1}}
так дребезжание значений становится гораздо меньше, но оперативность реакции при этом не страдает.

Добавлено after 31 minute 5 seconds:
ещё в копилочку: для увеличения разрядности АЦП можно использовать шумы измерителя, для этого:
рецепт :))) : для получения Х дополнительных бит точности - нужно сделать оцифровку 2^(2Х) раз (для 2х бит - это будет 16 раз), все результаты суммировать, а затем сдвинуть вправо на Х позиций (т.е. разделить на 2^Х).
Получается неплохо :tea:
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4367298#p4367298"]а метить самый маленький из найденных элементов и исключать его из выборки[/uquote]
А почему только самый маленький? С самым большим что делать?
Друг Кота
Аватара пользователя
Сообщения: 7083
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

перебираем массив "снизу", отсекая поочередно самые маленькие, большие просто останутся неотсеченными, но и в сумматор не попадут...

Добавлено after 1 minute 36 seconds:
хотя, если есть желание - можно идти и "сверху", отсекая большие, просто так придется отдельно наличие метки проверять (или переменную сделать знаковой, чтоб метка автоматом число в минуса загоняла)....
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Друг Кота
Аватара пользователя
Сообщения: 26043
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Сообщение КРАМ »

[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4367315#p4367315"]большие просто останутся неотсеченными, но и....[/uquote]
Для полной медианной фильтрации вероятно пойдет, но она не годится в случае с автором темы. останется только один элемент, а это не устранит помехи имеющие линейчатый спектр типа 50 Гц с гармониками.
Кроме того, все способы прямого перебора для полной медианы имеют объем вычислений O*N^2 против O*N*logN для быстрых сортировок. Так что коэффициент O тут мало чем поможет для массивов значительной (от нескольких десятков элементов) длины.

Добавлено after 4 minutes 23 seconds:
[uquote="Martian",url="/forum/viewtopic.php?p=4367317#p4367317"]что-то сродни интерполяции?[/uquote]
Это классический оверсемплинг. Но он точность не повышает. Он повышает разрешающую способность.
Интерполяция - это другое. При интерполяции, вставляют нулевые отсчеты и производят обычную фильтрацию. Это и есть передискретизация.
Ответить

Вернуться в «AVR»