Алгоритм сглаживания шумов АЦП микроконтроллера.
[uquote="Martian",url="/forum/viewtopic.php?p=4367322#p4367322"]разрешающей способности...[/uquote]Точность важна для измерителя, а разрешающая способность для обнаружителя. Правда в обнаружителе нужно учитывать неизбежную интермодуляцию связанную с исходной точностью, читайте линейностью.
- Реклама
останется несколько максимальных элементов, т.к. поиск остановится раньше (как только найдётся последний, интересующий нас элемент).
количество итераций поиска I = L-N
где L- длина массива
N- количество элементов, которые искать не надо (один из "хвостов" массива). N=(L-M)/2
M- количество элементов входящих в усреднительный фильтр
отсюда I= L-(L-M)/2 = (L+M)/2
количество сравнений: X=L*I=L*(L+M)/2 = (L^2+LM)/2;
......
пожалуй действительно увеличения скорости нет (модификация значения ведь тоже время занимает)... но памяти требуется в 2 раза меньше... т.к. нет сортируемой копии массива.
и, я думаю (пока этот вопрос не проанализировал), что флеш сэкономится, т.к. и сортировка и вычисление проходят внутри одного цикла.
но с тем, что останется только один максимальный элемент, я не согласен - сортировку можно остановить сразу после того, как будет найден последний интересующий элемент.
количество итераций поиска I = L-N
где L- длина массива
N- количество элементов, которые искать не надо (один из "хвостов" массива). N=(L-M)/2
M- количество элементов входящих в усреднительный фильтр
отсюда I= L-(L-M)/2 = (L+M)/2
количество сравнений: X=L*I=L*(L+M)/2 = (L^2+LM)/2;
......
пожалуй действительно увеличения скорости нет (модификация значения ведь тоже время занимает)... но памяти требуется в 2 раза меньше... т.к. нет сортируемой копии массива.
и, я думаю (пока этот вопрос не проанализировал), что флеш сэкономится, т.к. и сортировка и вычисление проходят внутри одного цикла.
но с тем, что останется только один максимальный элемент, я не согласен - сортировку можно остановить сразу после того, как будет найден последний интересующий элемент.
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4367331#p4367331"]количество итераций поиска I = L-N
где L- длина массива
N- количество элементов, которые искать не надо (один из "хвостов" массива).[/uquote]
Увы, нет. Элементы которые "искать не надо", на самом деле тоже ищутся по своей метке или указателю.
где L- длина массива
N- количество элементов, которые искать не надо (один из "хвостов" массива).[/uquote]
Увы, нет. Элементы которые "искать не надо", на самом деле тоже ищутся по своей метке или указателю.
Тут не понял... ну, есть они в массиве, а мне то что с того...? придёт их черёд - затрутся свежим значением...
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=4367347#p4367347"]Тут не понял... ну, есть они в массиве[/uquote]
Циклы поиска всегда ПОЛНЫЕ. Не важно - стоит какая то метка на минимальных или нет. Потому что поиск минимальных ничем не отличается от пропуска отмеченных. То есть циклов будет по прежнему O*N^2. Только О будет равно 0,5.
Циклы поиска всегда ПОЛНЫЕ. Не важно - стоит какая то метка на минимальных или нет. Потому что поиск минимальных ничем не отличается от пропуска отмеченных. То есть циклов будет по прежнему O*N^2. Только О будет равно 0,5.
- Реклама
нет, это внутри итерации цикла перебирается весь массив (и меченые и нет) а количество таких итераций меньше количества элементов массива, оно равно количеству найденных минимальных элементов (равно сумме пропускаемых и суммируемых минимальных элементов)
Добавлено after 1 minute 8 seconds:
про квадратичную скорость роста количества расчетов от размера массива я не спорю.
Добавлено after 1 minute 8 seconds:
про квадратичную скорость роста количества расчетов от размера массива я не спорю.
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
Алгоритм сортировки работает идеально и быстро. И всё остальное в проге. Проблема была в том, что я заштриховал строку в которой были настройки АЦП. И при обращении к нему МК уходил в зависон. Так же почему то не заработал ареф ( ацп всегда показывал 1023) , переназначил источник опорного на внутреннее 2,5 вольта и всё заработало. Но ...
Добавлено after 6 minutes 5 seconds:
Показания ИНОГДА прыгают в пределах единицы младшего разряда, и если число ровное например 100 , то прыгают соответственно все 3 его разряда.
Добавлено after 6 minutes 5 seconds:
Показания ИНОГДА прыгают в пределах единицы младшего разряда, и если число ровное например 100 , то прыгают соответственно все 3 его разряда.
Не спрашивай по ком звонит колокол, он звонит по тебе !
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367545#p4367545"]Показания ИНОГДА прыгают в пределах единицы младшего разряда, и если число ровное например 100 , то прыгают соответственно все 3 его разряда.[/uquote]
А вот тут нужен гистерезис на полразряда.
А вот тут нужен гистерезис на полразряда.
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
Ну ... жду алгоритм реализации.
Не спрашивай по ком звонит колокол, он звонит по тебе !
Алгоритм очень простой. Переключение на следующее значение в одну сторону происходит на полразряда позже, чем в другую. Для этого нужно сделать экспоненциальный фильтр сглаживания с коэффициентом 0,5. Это даст на выходе один лишний разряд после точки. Он позволит получить разрешение в 0,5 единицы измерений. Когда текущее измерение больше предыдущего на 0,5 - прибавляем единицу, если меньше на такую же величину - вычитаем единицу. Если внутри этих значений - не изменяем.
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
А где взять "пол разряда" то ? был бы 11 бит в ацп, а его нет.
Не спрашивай по ком звонит колокол, он звонит по тебе !
[uquote="Alex_641",url="/forum/viewtopic.php?p=4367568#p4367568"]А где[/uquote]
Я же вам сказал - экспоненциальный фильтр сглаживания S[t+1]=((1-β)*S[t])+A[t+1] c коэффициентом β=0,5.
S[t+1]=(0,5*S[t])+A[t+1], где:
S[t+1] - текущее значение фильтра в формате 15.1
S[t] - предыдущее значение фильтра в формате 15.1
A[t+1] - текущее измерение uint16_t (10 значащих разрядов)
Таким образом, разрядность фильтра больше на 1 разрядности измерений. Лишний младший разряд - это дробная часть числа. 1 в нем означает 0,5 в десятичном формате. Например десятичное число 10,5 в двоичном виде (uint16_t) будет 000000000001010.1
Если выбрать коэффициент 0,25 - формула примет вид S[t+1]=(0,75*S[t])+A[t+1], то получите два дробных разряда в формате 14.2. Число 5,25 будет выглядеть как 00000000000101.01.
Это и есть фикспойнты.
Умножение на 0,5 - это арифметический сдвиг на один разряд вправо.
Умножение на 0,25 - это арифметический сдвиг на два разряда вправо.
Умножение на 0,75 - это сумма двух предыдущих значений.
ЗЫ. И учтите, как и любой рекурсивный фильтр, этот в целых числах НЕ РАБОТАЕТ. В целых числах фильтр не будет реагировать на входные значения разрядностью меньше дробной. Поэтому фикспойнты или флоаты обязательны.
Я же вам сказал - экспоненциальный фильтр сглаживания S[t+1]=((1-β)*S[t])+A[t+1] c коэффициентом β=0,5.
S[t+1]=(0,5*S[t])+A[t+1], где:
S[t+1] - текущее значение фильтра в формате 15.1
S[t] - предыдущее значение фильтра в формате 15.1
A[t+1] - текущее измерение uint16_t (10 значащих разрядов)
Таким образом, разрядность фильтра больше на 1 разрядности измерений. Лишний младший разряд - это дробная часть числа. 1 в нем означает 0,5 в десятичном формате. Например десятичное число 10,5 в двоичном виде (uint16_t) будет 000000000001010.1
Если выбрать коэффициент 0,25 - формула примет вид S[t+1]=(0,75*S[t])+A[t+1], то получите два дробных разряда в формате 14.2. Число 5,25 будет выглядеть как 00000000000101.01.
Это и есть фикспойнты.
Умножение на 0,5 - это арифметический сдвиг на один разряд вправо.
Умножение на 0,25 - это арифметический сдвиг на два разряда вправо.
Умножение на 0,75 - это сумма двух предыдущих значений.
ЗЫ. И учтите, как и любой рекурсивный фильтр, этот в целых числах НЕ РАБОТАЕТ. В целых числах фильтр не будет реагировать на входные значения разрядностью меньше дробной. Поэтому фикспойнты или флоаты обязательны.
а разве A[t+1] не нужно сдвигать влево на 1 разряд (или 2 разряда)?КРАМ писал(а):A[t+1] - текущее измерение uint16_t (10 значащих разрядов)
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
[uquote="Starichok51",url="/forum/viewtopic.php?p=4367799#p4367799"]а разве A[t+1] не нужно ?[/uquote]
Категорически нет. Это приведет выражение к целочисленной форме и входящие значения меньше 2 или 4 будут игнорироваться. Мы получим мертвую зону входных сигналов. Ну и не получим дробную часть у фильтра.
Просто нужно понимать, что входящие значения с АЦП уже приведены к формату фильтра. Их сдвигать не требуется.
Категорически нет. Это приведет выражение к целочисленной форме и входящие значения меньше 2 или 4 будут игнорироваться. Мы получим мертвую зону входных сигналов. Ну и не получим дробную часть у фильтра.
Просто нужно понимать, что входящие значения с АЦП уже приведены к формату фильтра. Их сдвигать не требуется.
если использовать тип флот, то сдвигать, конешно, не нужно.
а если использовать фиксированную точку, то как получится младший разряд в формате 15.1 без сдвига?
я так понимаю, что при фиксированной точке произведение 0,5*S[t] будет целым числом, и с этой "половинкой" в младшем разряде результат измерения нужно сдвинуть (удвоить).
или ты фиксированную точку понимаешь не так, как я?
а если использовать фиксированную точку, то как получится младший разряд в формате 15.1 без сдвига?
я так понимаю, что при фиксированной точке произведение 0,5*S[t] будет целым числом, и с этой "половинкой" в младшем разряде результат измерения нужно сдвинуть (удвоить).
или ты фиксированную точку понимаешь не так, как я?
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
[uquote="Starichok51",url="/forum/viewtopic.php?p=4367918#p4367918"]если использовать тип флот, то сдвигать, конешно, не нужно.[/uquote]
Тип float позволяет использовать каноническую форму такого фильтра вида:
S[t+1]=(α*S[t])+(β*A[t+1]), где α+β=1.
Но есть один нюанс. При α+β>1 фильтр перестает быть устойчивым. А использование float не гарантирует, что это условие не возникнет из-за нелинейного разрешения float.
Поэтому с float придется вручную вычислить α=1-β, затем проверить, что сумма α+β МЕНЬШЕ единицы (равна она не может быть по определению) и при вычислениях использовать первичную каноническую форму с двумя коэффициентами.
[uquote="Starichok51",url="/forum/viewtopic.php?p=4367918#p4367918"]я так понимаю, что при фиксированной точке произведение 0,5*S[t] будет целым числом[/uquote]
Нет, не будет. Все числа в приведенной мной в предыдущих сообщениях формуле ДРОБНЫЕ и имеют ОДИНАКОВЫЙ ФОРМАТ. Просто при таком формате данные с АЦП УЖЕ ПРЕДСТАВЛЕНЫ КАК ДРОБНЫЕ формата 15.1
То есть умножение на 0,5 не делает число целым, оно просто делит его пополам, СОХРАНЯЯ РАЗРЯДНОСТИ ЦЕЛОЙ И ДРОБНОЙ ЧАСТИ.
И не следует путать вычисления самого фильтра с приведением РЕЗУЛЬТАТА фильтрации к целому (отсечение дробной части) для целей вывода. Формально это выглядит тоже как деление на 2, но суть становится совершенно другой. И, кстати, по правилам математического округления такое приведение должно быть выполнено с предварительным увеличением результата фильтрации на 0,5 для положительных чисел и вычитанием 0,5 для отрицательных.
Тип float позволяет использовать каноническую форму такого фильтра вида:
S[t+1]=(α*S[t])+(β*A[t+1]), где α+β=1.
Но есть один нюанс. При α+β>1 фильтр перестает быть устойчивым. А использование float не гарантирует, что это условие не возникнет из-за нелинейного разрешения float.
Поэтому с float придется вручную вычислить α=1-β, затем проверить, что сумма α+β МЕНЬШЕ единицы (равна она не может быть по определению) и при вычислениях использовать первичную каноническую форму с двумя коэффициентами.
[uquote="Starichok51",url="/forum/viewtopic.php?p=4367918#p4367918"]я так понимаю, что при фиксированной точке произведение 0,5*S[t] будет целым числом[/uquote]
Нет, не будет. Все числа в приведенной мной в предыдущих сообщениях формуле ДРОБНЫЕ и имеют ОДИНАКОВЫЙ ФОРМАТ. Просто при таком формате данные с АЦП УЖЕ ПРЕДСТАВЛЕНЫ КАК ДРОБНЫЕ формата 15.1
То есть умножение на 0,5 не делает число целым, оно просто делит его пополам, СОХРАНЯЯ РАЗРЯДНОСТИ ЦЕЛОЙ И ДРОБНОЙ ЧАСТИ.
И не следует путать вычисления самого фильтра с приведением РЕЗУЛЬТАТА фильтрации к целому (отсечение дробной части) для целей вывода. Формально это выглядит тоже как деление на 2, но суть становится совершенно другой. И, кстати, по правилам математического округления такое приведение должно быть выполнено с предварительным увеличением результата фильтрации на 0,5 для положительных чисел и вычитанием 0,5 для отрицательных.
понятно.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
- Сообщения: 2314
- Зарегистрирован: Вт янв 26, 2021 22:33:21
Я так понял , не надо искать среднее арефметическое. Надо найти количество показаний отличающихся на единицу в предыдущем цикле, и в данном . И если есть разница на единицу АЦП , то просто выводить старую информацию. Это проще чем ...всё что написано выше "умными людьми" , которые так и не смогли привести пример )))
Не спрашивай по ком звонит колокол, он звонит по тебе !
- Сообщения: 1495
- Зарегистрирован: Ср июн 25, 2008 15:19:44
Alex_ka перелогинься.
[uquote="Alex_641",url="/forum/viewtopic.php?p=4369415#p4369415"]Это проще чем ...всё что написано выше "умными людьми" , которые так и не смогли привести пример )))[/uquote]
Вы не в состоянии написать простейший код по несложной формуле?
Так много разговоров было о медиане и так все проблематично с самым простым фильтром сглаживания...
Кстати, чтобы исключить нечитаемое дрожание показаний можно не гистерезисом озаботиться, а простым увеличением интервала вывода показаний.
Самым лучшим вариантом будет тот же экспоненциальный фильтр, только с коэффициентом 0,125 или 0,0625. Будет комфортное "резиновое" отображение - плавное (например за 0,5...1 сек) нарастание/падение показаний и практически незаметное глазу переключение на границе значений.
Гистерезис на единице младшего разряда даст потерю минимум одного младшего разряда.
Фильтр для коэффициента 0,0625:
Где:
Расчет делается на каждое преобразование АЦП.
Вы не в состоянии написать простейший код по несложной формуле?
Так много разговоров было о медиане и так все проблематично с самым простым фильтром сглаживания...
Кстати, чтобы исключить нечитаемое дрожание показаний можно не гистерезисом озаботиться, а простым увеличением интервала вывода показаний.
Самым лучшим вариантом будет тот же экспоненциальный фильтр, только с коэффициентом 0,125 или 0,0625. Будет комфортное "резиновое" отображение - плавное (например за 0,5...1 сек) нарастание/падение показаний и практически незаметное глазу переключение на границе значений.
Гистерезис на единице младшего разряда даст потерю минимум одного младшего разряда.
Фильтр для коэффициента 0,0625:
Код: Выделить всё
S_IIR=S_IIR-(S_IIR>>4)+resultADC; // S[t+1]=((1-β)*S[t])+A[t+1], где β=0,0625=1/16
outputResult=(S_IIR+8)>>4; // округление и приведение к целому
Код: Выделить всё
uint16_t S_IIR; //тело фильтра (максимум 14 значащих разрядов)
uint16_t resultADC; // результат преобразования АЦП (10 разрядов)
uint16_t outputResult; // выводимый результат фильтрации (10 разрядов)


