Во-первых, среднее у вас вычисляется не из `N_MAX` значений, как написано в комментарии, а из `2^N_MAX` значений. Во-вторых, вышеприведенная функция возвращает новое среднее только на каждой `2^N_MAX` итерации. На остальных итерациях возвращается последнее вычисленное среднее. Это так и задумано?
1. Да, я забыл обновить комментарий после обновления кода. 2. Да, так и задумано, я ведь не получу новое среднее значение раньше, чем через 2^N_MAX операций. Наверно, можно было добавить флаг "обновлено/не обновлено" и записывать значение в OC1A, только если оно обновилось, но мне показалось это лишним в этом случае. В векторах прерываний тут ничего важного не происходит (может, индикатор потом прикручу), остановка прерываний раз в цикл не критична.
Не знал о существовании спец. библиотеки атомарных операций для AVR-GCC. Но какая разница - в датащите универсальный сишный вариант под любую среду разработки, насколько я понимаю. А атомарность операций нужна здесь "чтоб была" - в процессе борьбы ловли багов Протеуса добавил для надежности, Atmel ведь рекомендует.
_________________ We do what we must because we can (c) GLaDOS
Но какая разница - в датащите универсальный сишный вариант под любую среду разработки, насколько я понимаю.
разница очень большая: если вы делаете атомарное ЧТЕНИЕ, то вам придется совершать без этого библиотечного макроса достаточно много "лишних" телодвижений - я привел код функции, возвращающей атомарно считанное значение регистра, попробуйте написать аналог без этого макроса
baron_P писал(а):
я ведь не получу новое среднее значение раньше, чем через 2^N_MAX операций
да легко! только это будет не среднее за N_MAX семплов, а среднее за N_MAX предыдущих семплов. метод называется "скользящее среднее" и является простейшим вариантом какого-то там КИХ/БИХ (я нихрена в этом не понимаю) фильтра. алгоритм вам ранее был описан словесно
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
разница очень большая: если вы делаете атомарное ЧТЕНИЕ, то вам придется совершать без этого библиотечного макроса достаточно много "лишних" телодвижений - я привел код функции, возвращающей атомарно считанное значение регистра, попробуйте написать аналог без этого макроса да легко! только это будет не среднее за N_MAX семплов, а среднее за N_MAX предыдущих семплов. метод называется "скользящее среднее" и является простейшим вариантом какого-то там КИХ/БИХ (я нихрена в этом не понимаю) фильтра. алгоритм вам ранее был описан словесно
А чем плох этот пример чтения?
Код:
unsigned int TIM16_ReadTCNT1( void ) { unsigned char sreg; unsigned int i; /* Save Global Interrupt Flag */ sreg = SREG; /* Disable interrupts */ _CLI(); /* Read TCNT1 into i */ i = TCNT1; /* Restore Global Interrupt Flag */ SREG = sreg; return i; }
Я слышал про этот метод, но мне он не нужен в данном случае - частота входного сигнала очень низкая.
_________________ We do what we must because we can (c) GLaDOS
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
хотя бы тем, что он в 3 раза объемнее по строкам соответственно, в 3 раза выше вероятность где-то ошибиться.
baron_P писал(а):
мне он не нужен в данном случае - частота входного сигнала очень низкая
фильтр нужен практически всегда, и с частотой это не связано. первое, для чего он нужен - это сгладить "естественный" шум АЦП в младшем разряде. но, разумеется, хозяин - барин
_________________ если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе при взгляде на многих сверху ничего не меняется...
хотя бы тем, что он в 3 раза объемнее по строкам соответственно, в 3 раза выше вероятность где-то ошибиться.
baron_P писал(а):
мне он не нужен в данном случае - частота входного сигнала очень низкая
фильтр нужен практически всегда, и с частотой это не связано. первое, для чего он нужен - это сгладить "естественный" шум АЦП в младшем разряде. но, разумеется, хозяин - барин
Это копипаста из датащита - в нажатии двух кнопок ошибиться трудно Я не использую АЦП - это обработка цифровых сигналов очень низкой частоты. Усреднение - чтобы минимизировать влияние внезапных импульсных помех, если оные проберутся в сигнал.
_________________ We do what we must because we can (c) GLaDOS
Я не использую АЦП - это обработка цифровых сигналов очень низкой частоты. Усреднение - чтобы минимизировать влияние внезапных импульсных помех, если оные проберутся в сигнал.
Я не использую АЦП - это обработка цифровых сигналов очень низкой частоты. Усреднение - чтобы минимизировать влияние внезапных импульсных помех, если оные проберутся в сигнал.
может лучше контрольные суммы использовать?
Не соображу, как это можно сделать здесь. Железка с 12-ю открытыми коллекторами соединена со входами контроллера. Иногда, значения на входах меняются по желанию этой железки. Куда тут контрольную сумму можно воткнуть?
_________________ We do what we must because we can (c) GLaDOS
т.е. за входной сигнал ты не в ответе? Ну, а о нем хоть что-то известно?
Не в ответе. О том, какие значения будут выставлены в конкретный момент - нет, не известно. Есть еще тринадцатый бит, который говорит о том, что сигнал с 12 остальных можно читать. Я собираю значения со входов только когда активен этот бит. Код (лишнее выкинулЮ нужное добавил): Спойлер
Код:
/* МК ATMEGA8 Частота МК = 8 МГц Fuse High Byte BODLEVEL = 0 - нижний порог напряжения питания 4 В BODEN = 0 - слежение за напряжением питания вкл. SUT1 = 0 \ время включения 6СК + 64 ms SUT0 = 0 / CKSEL3 = 0 \ CKSEL2 = 1 - встроенный источник тактовых импульсов CKSEL1 = 0 - с частотой 8 МГц CKSEL0 = 0 / Fuse Low Byte RSTDISBL = 1 - переназначение вывода ~RESET выкл. WDTON = 1 - постоянная работа сторожевого таймера выкл. SPIEN = 0 - внутрисхемное программирование вкл. CKOPT = 1 - опции работы с внешним кварцевым резонатором выкл. EESAVE = 1 - защита EEPROM от стирания выкл. BOOTSZ1 = 0 \ размер загрузочного сектора BOOTSZ0 = 0 / 1024 слова, начальный адрес $0C00 BOOTRST = 1 - перенос стартового сектора в область загрузчика выкл. */
//Подключенные файлы #include <avr/io.h> // Стандартные функции ввода/вывода для МК #include <avr/wdt.h> // Стандартные функции работы cо сторожевым таймером
//Подстановки #define PWM_MAX 4095 // Максимальное значение скважности для 12-битиного ШИМ (PWM_MAX = 2^12 - 1) #define N_MAX 3 // Максимальное количесво значений для получения средне арифметичесого (2^N_MAX = 8) #define U_INT_MAX 65535 // Максимальное значение типа unsigned int
//Прототипы функций //Процедура инициализации входов/выходов void init_IO(void); //Процедура инициализации ТС1 void init_TC1(void); //Процедура получения среднего значения из 2^N_MAX полученных и выдачи его в ШИМ void data_conv_PWM(unsigned int); //Функция чтения 12-битного значения задания со входов unsigned int data_read(void);
/********** Главная фунция **********/ void main(void) {
//Инициализация локальных переменных //Значение числа с 12-битного входа unsigned int data_input = 0;
//Включение сторожевого таймера с периодом 1с wdt_enable(WDTO_1S);
//Рабочий цикл while(1) { //Если на входе присутствует сигнал чтения if (PINB & (1 << PB0)) { //Чтение 12-битного значения задания со входов data_input = data_read();
//Получение среднего арифметического из 2^N_MAX значений и выдача его в ШИМ data_conv_PWM(data_input); }
//Процедура инициализации ТС1 (формирование выходного аналогового напряжения) void init_TC1(void) { //Вывод PB1 (OC1A) - выход ШИМ DDRB |= (1 << PB1); //Сброс в ноль выхода OC1A при совпадении, режим FastPWM (ICR1) TCCR1A |= (1 << COM1A1) | (1 << WGM11); //Предделитель 1 TCCR1B |= (1 << WGM13) | (1 << WGM12) | (1 << CS10); //Маскимальное значение скважности ICR1 = PWM_MAX; //Начальное (нулевое) значение скважности ШИМ OCR1A= 0; }
//Процедура получения среднего значения из 2^N_MAX полученных и выдачи его в ШИМ void data_conv_PWM(unsigned int data_in) { //Суммарное значение 2^N_MAX полученных static unsigned int data_sum; //Счетчик количества просуммированых значений static unsigned char data_n;
//Если количество просуммированных значений меньше заданного if (data_n < (1 << N_MAX)) { //Добавляем полученное значение к сумме предыдущих (предельное значени data_in = PWM_MAX*2^N_MAX = 32670) data_sum += data_in; //Инкрементируем счетчик полученных значений data_n++; } else { //Иначе, обновляем предыдущее средне-арифметическое значение data_sum = (data_sum >> N_MAX);
//Выдача заданния скважности ШИМ в регистр сравнения OCR1A= data_sum;
//Функция чтения 12-битного значения задания со входов unsigned int data_read(void) { //Значения с входов соотв. портов unsigned char data_in_D = 0, data_in_B = 0; //Значение числа с 12-битного входа unsigned int data_in = 0;
//Чтение значений со входов //Порт D без изменений data_in_D = PIND; //Порт B с очисткой неиспользуемых младших битов data_in_B = PINB & ((1 << PB7) | (1 << PB6) | (1 << PB5) | (1 << PB4));
//Преобразование полученных значений в 12-битное число (0b00 4бита PortB 8 битов PortD) data_in = (data_in_B << 4) | data_in_D;
//Возвращение полученного 12-битного числа return data_in; }
_________________ We do what we must because we can (c) GLaDOS
Не в ответе. О том, какие значения будут выставлены в конкретный момент - нет, не известно.
а частота тоже неизвестна?
Частота тоже неизвестна. Известно, что имеют место быть импульсные помехи около 10 кГц частотой. На входах будет подаваться 24 В через делитель 20 кОм - 3,9 кОм. Параллельно 3,9 кОм будут конденсаторы 0,01 мкФ, чтобы срезать все, что выше 1 кГц.
_________________ We do what we must because we can (c) GLaDOS
baron_P, от импульсных помех избавляются медианный фильтром, а не усреднением. То бишь, формируем скользящее окно из N показаний. N - нечётное. Окно лучше формировать списком. В списке держим N последних показаний в отсортированном порядке. Среднее показание - наша медиана. При поступлении нового показания удаляем из списка самое старое показание и вставляем в список, сохраняя сортировку по значениям показаний, новое показание. Средний элемент списка снова наша медиана.
baron_P, от импульсных помех избавляются медианный фильтром, а не усреднением. То бишь, формируем скользящее окно из N показаний. N - нечётное. Окно лучше формировать списком. В списке держим N последних показаний в отсортированном порядке. Среднее показание - наша медиана. При поступлении нового показания удаляем из списка самое старое показание и вставляем в список, сохраняя сортировку по значениям показаний, новое показание. Средний элемент списка снова наша медиана.
короче, надо знать, что представляют собой эти самые показания и можно ли их вообще фильтровать
ozonn, так ТС же явно сказал, что "имеют место быть импульсные помехи". Если только импульсные помехи - то медианного фильтра достаточно. Если не столько ипульсные, сколько шум при известном спектре полезного сигнала - то уравнение Винера. В общем случае - собираем мегабайты статистики, берем R в зубы, находим функцию распределения и от нее уже пляшем.
ozonn, так ТС же явно сказал, что "имеют место быть импульсные помехи". Если только импульсные помехи - то медианного фильтра достаточно. Если не столько ипульсные, сколько шум при известном спектре полезного сигнала - то уравнение Винера. В общем случае - собираем мегабайты статистики, берем R в зубы, находим функцию распределения и от нее уже пляшем.
а теперь представь, что полезная информация - это буквы. И ты бльшую часть из них фильтруешь. Короче, надо знать, какую инфу нисут в себе принимаемые числа
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 33
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения