Алгоритм сглаживания шумов АЦП микроконтроллера.
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
если хочешь ?
Не спрашивай по ком звонит колокол, он звонит по тебе !
- Реклама
Это не я хочу, это вы хотите узнать причину зацикливания. Лишний элемент не может быть причиной, а вот чужое значение очень даже может...
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
хорошо.
Я попробую спрятать под спойлер. Если получится. Ещё не делал этого.
Добавлено after 1 minute 30 seconds:
Я попробую спрятать под спойлер. Если получится. Ещё не делал этого.
Добавлено 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;}
}
}
Не спрашивай по ком звонит колокол, он звонит по тебе !
Зачем прятать? Всего то нужно показать объявление самого массива и то, что непосредственно за ним.
Ну либо тот же скрин с 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.
Можете сами проанализировать...
То есть по факту во второй строке mass=z;, а в третьей z=z;
Ну либо тот же скрин с 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.
Можете сами проанализировать...
Код: Выделить всё
z=mass[i]; // поменять
mass[i]=mass[i+1]; // их
mass[i+1]=z; // местами
Последний раз редактировалось КРАМ Вс фев 05, 2023 21:58:08, всего редактировалось 1 раз.
- Сообщения: 1524
- Зарегистрирован: Пн май 01, 2017 20:01:45
[uquote="КРАМ",url="/forum/viewtopic.php?p=4367111#p4367111"][uquote="Alex_641",url="/forum/viewtopic.php?p=4367089#p4367089"]но проходов 19 ![/uquote]
Даладна...
От 0 до 19 - это сколько будет?
1 класс средней школы...[/uquote]
"От 0 до 19" будет 19
Даладна...
Код: Выделить всё
for (i=0;i<20;i++) // цикл1 класс средней школы...[/uquote]
"От 0 до 19" будет 19
- Реклама
А так?
{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; // установить флаг ( сортировка еще не закончена)
}
}
}
Спойлер
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
А разница то какая ? Z - просто переменная промежуточная .
Не спрашивай по ком звонит колокол, он звонит по тебе !
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367174#p4367174"]А разница то какая ?[/uquote]
Я вам причел что по факту получилось. А получилось ОТСУТСТВИЕ СОРТИРОВКИ в 20-м проходе.
Я вам причел что по факту получилось. А получилось ОТСУТСТВИЕ СОРТИРОВКИ в 20-м проходе.
Последний раз редактировалось КРАМ Вс фев 05, 2023 22:13:07, всего редактировалось 1 раз.
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
Главное запомните - пузырёк на 0,5 !
Добавлено after 1 minute 37 seconds:
Добавлено after 2 minutes 49 seconds:
А если вообще сделаю конструкцию ! То это будет круто для электриков ))
Добавлено after 1 minute 37 seconds:
Да ! Потому что привлекался неопознанный 21-й обьект .Спасибо.КРАМ писал(а): получилось ОТСУТСТВИЕ СОРТИРОВКИ.
Добавлено after 2 minutes 49 seconds:
А если вообще сделаю конструкцию ! То это будет круто для электриков ))
Не спрашивай по ком звонит колокол, он звонит по тебе !
Вы еще не поняли, что никаких 0,5 нет и в помине. Просто дергайте ногой в начале сортировки и в конце с реальными массивами. И удивляйтесь результату...

Добавлено after 2 minutes 4 seconds:
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367177#p4367177"]А если вообще сделаю[/uquote]
Дай вам Б-г... А я чевойта сомневаюсь, однако...
Добавлено after 2 minutes 4 seconds:
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367177#p4367177"]А если вообще сделаю[/uquote]
Дай вам Б-г... А я чевойта сомневаюсь, однако...
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
Если чесно ....мне вот совсем по... Но .
Добавлено after 1 minute 16 seconds:
Добавлено after 1 minute 13 seconds:
Ты хочешь меня просто размазать по бетону, и сказать что пузыря на 0,5 не существует ?
Добавлено after 1 minute 16 seconds:
а дело то в конце ! Насколько он будет быстрым !КРАМ писал(а):конце с реальными массивами
Добавлено after 1 minute 13 seconds:
Ты хочешь меня просто размазать по бетону, и сказать что пузыря на 0,5 не существует ?
Не спрашивай по ком звонит колокол, он звонит по тебе !
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367187#p4367187"]Ты хочешь меня просто размазать ?[/uquote]
Зачем? Я просто знаю результат.... Ну и резонно полагаю, что искать дурее себя не стоит. Очевидно, что ваша "идея" лежит на поверхности для столь изъезженной вдоль и поперек темы сортировки. Не катит, увы. Особенно с учетом скрипучести по проблеме лишнего элемента...
Зачем? Я просто знаю результат.... Ну и резонно полагаю, что искать дурее себя не стоит. Очевидно, что ваша "идея" лежит на поверхности для столь изъезженной вдоль и поперек темы сортировки. Не катит, увы. Особенно с учетом скрипучести по проблеме лишнего элемента...
- Сообщения: 1524
- Зарегистрирован: Пн май 01, 2017 20:01:45
[uquote="КРАМ",url="/forum/viewtopic.php?p=4367168#p4367168"]Еще один йуморист...
[/uquote]
Вовсе нет, возвращаю должное флудеру.
Вовсе нет, возвращаю должное флудеру.
[uquote="u37",url="/forum/viewtopic.php?p=4367198#p4367198"]возвращаю[/uquote]
Странный способ возврата - писать ахинею...
Может стоило просто конструктивно возразить? Или этот вариант априори не рассматривался?
Странный способ возврата - писать ахинею...
Может стоило просто конструктивно возразить? Или этот вариант априори не рассматривался?
- Сообщения: 1495
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Alex_641, вот мой рабочий пример. Посмотрите его повнимательнее.
Пусть у нас 4 элемента. 3-1-10-9. Адресация в цифровой электронике начинается с 0. Он же условно "первый" элемент.
Ptr_1 на нулевой 0 "первый" элемент (3). Ptr_2 на 1 "второй" элемент (1). Начинаем двигать. Сколько сдвигов? 3. То есть size - 1. В моем примере вы увидите константу размер массива. В функции вы увидите size - 1.
Пусть у нас 4 элемента. 3-1-10-9. Адресация в цифровой электронике начинается с 0. Он же условно "первый" элемент.
Ptr_1 на нулевой 0 "первый" элемент (3). Ptr_2 на 1 "второй" элемент (1). Начинаем двигать. Сколько сдвигов? 3. То есть size - 1. В моем примере вы увидите константу размер массива. В функции вы увидите size - 1.
А что если не сортировать массив, а метить самый маленький из найденных элементов и исключать его из выборки, так первый помеченный будет самым маленьким, второй помеченный - вторым снизу...
для меток можно создать отдельный массив, а можно обратимо модифицировать элементы исследуемого массива:
т.к. измерение АЦП занимает 10 бит, то старшие 6 всегда == 0, любой из них можно занять под метку...
кстати такая метка автоматически увеличивает элемент настолько, что он уже точно не станет самым маленьким (таким методом мы убиваем сразу 2х зайцев
)
код получится примерно таким:
1) организовываем кольцевой буфер (запись в него нового значения вытесняет самое старое), длина буфера равна 2длинам отсекаемых хвостов и 1 длине усредняемой середины.
2) в цикле находим самый маленький элемент и если i (количество итераций цикла) меньше длины хвоста то просто помечаем его:
X|=0x8000; //под метку отдали самый старший бит.
если i больше длины хвоста, то перед тем, как поставим метку, Х добавим в аккумулятор.
цикл проводим (длина хвоста+длина середины) раз.
затем пробегаем массив вторым циклом, в котором сбрасываем установленные первым циклом метки:
X&=~0x8000;
затем делим значение аккумулятора на длину середины и получаем среднемедианное значение - какраз то, что мы и ищем.
Достоинства метода:
1) не нарушается порядок элементов - не нарушается работа кольцевого буфера
2) не требуется дополнительная память для хранения и сортировки элементов.
3) высокая скорость вычисления.
Добавлено after 15 minutes 36 seconds:
Можно сделать фильтрацию с опорой на предыдущий вычисленный элемент:так дребезжание значений становится гораздо меньше, но оперативность реакции при этом не страдает.
Добавлено after 31 minute 5 seconds:
ещё в копилочку: для увеличения разрядности АЦП можно использовать шумы измерителя, для этого:
рецепт
: для получения Х дополнительных бит точности - нужно сделать оцифровку 2^(2Х) раз (для 2х бит - это будет 16 раз), все результаты суммировать, а затем сдвинуть вправо на Х позиций (т.е. разделить на 2^Х).
Получается неплохо
для меток можно создать отдельный массив, а можно обратимо модифицировать элементы исследуемого массива:
т.к. измерение АЦП занимает 10 бит, то старшие 6 всегда == 0, любой из них можно занять под метку...
кстати такая метка автоматически увеличивает элемент настолько, что он уже точно не станет самым маленьким (таким методом мы убиваем сразу 2х зайцев
код получится примерно таким:
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:
ещё в копилочку: для увеличения разрядности АЦП можно использовать шумы измерителя, для этого:
рецепт
Получается неплохо
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4367298#p4367298"]а метить самый маленький из найденных элементов и исключать его из выборки[/uquote]
А почему только самый маленький? С самым большим что делать?
А почему только самый маленький? С самым большим что делать?
перебираем массив "снизу", отсекая поочередно самые маленькие, большие просто останутся неотсеченными, но и в сумматор не попадут...
Добавлено after 1 minute 36 seconds:
хотя, если есть желание - можно идти и "сверху", отсекая большие, просто так придется отдельно наличие метки проверять (или переменную сделать знаковой, чтоб метка автоматом число в минуса загоняла)....
Добавлено after 1 minute 36 seconds:
хотя, если есть желание - можно идти и "сверху", отсекая большие, просто так придется отдельно наличие метки проверять (или переменную сделать знаковой, чтоб метка автоматом число в минуса загоняла)....
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
[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]
Это классический оверсемплинг. Но он точность не повышает. Он повышает разрешающую способность.
Интерполяция - это другое. При интерполяции, вставляют нулевые отсчеты и производят обычную фильтрацию. Это и есть передискретизация.
Для полной медианной фильтрации вероятно пойдет, но она не годится в случае с автором темы. останется только один элемент, а это не устранит помехи имеющие линейчатый спектр типа 50 Гц с гармониками.
Кроме того, все способы прямого перебора для полной медианы имеют объем вычислений O*N^2 против O*N*logN для быстрых сортировок. Так что коэффициент O тут мало чем поможет для массивов значительной (от нескольких десятков элементов) длины.
Добавлено after 4 minutes 23 seconds:
[uquote="Martian",url="/forum/viewtopic.php?p=4367317#p4367317"]что-то сродни интерполяции?[/uquote]
Это классический оверсемплинг. Но он точность не повышает. Он повышает разрешающую способность.
Интерполяция - это другое. При интерполяции, вставляют нулевые отсчеты и производят обычную фильтрацию. Это и есть передискретизация.


