Практика показала, что сигнал на выходе АЦП имеет свойство прыгать, и поэтому есть смысл чистить резкие скачки. Делается это обычно медианным фильтром. К сожалению, мне не удалось найти готовых быстрых библиотек с учетом особенностей эмбедов, поэтому желающим советую смотреть тут (вариант от Ekstrom). Мне не очень понравилось, что над быстрой имплементацией надо “думать”, чтобы понять как она работает. Поэтому решил пойти другим путем - разобраться с truncated mean (или как его там). Кто забыл школьные лабораторки по физике, напомню:
Считаем дисперсию измерений (среднеквадратичное отклонение от среднего арифметического).
Отбрасываем все, что вылезло за пределы допустимого и усредняем еще раз.
У меня на глаз получилось что при 8 отсчетах и отклонении 1.1*sigma выходит вполне приличный результат. По затратам - 2 полных прохода по массиву данных (в данном случае - по кольцевому буферу). На первом проходе считается среднее арифметическое и дисперсия, на втором - отбрасывается лишнее и усредняется остаток. Итого:
Оптимизированное truncated mean чуть медленнее оптимизированной медианы (меньше чем в полтора раза), но код намного понятнее.
Есть “встроенный усреднятор”, который теоретически должен скакать меньше медианы. На самом деле не факт и вопрос филосовский.
Затраты на вычисления стабильные.
Если процессор с навороченными кешами - тут только чтение, запись вообще отсутствует.
Теперь про сами измерения. Есть нюансы с точностью измерения напряжения и тока, когда они переходят через ноль. С практической точки зрения, получилось так:
Симистор открывается слегка не симметрично на положительной и отрицательной полуволне. Надо мерять не только длину полуволны, но и длину полного периода, а потом смотреть расхождение и компенсировать разницу.
В новой схеме (в отличие от макетки) применили усилитель для токового шунта, а у него выход никогда не становится 0 (есть малюсенькое смещение, хоть операционник и специализированный). В коде напряжение можно сравнивать с 0, а ток - нет. Ну тоже примерно понятно как лечить.
Там в начале автор сам пишет, что статья - практически дословный перевод той, на которую я дал ссылку.
на русском более понятно =)
{"assets_hash":"a8b26fa7f6e768b07a72c8c9aadb9422","page_data":{"users":{"39c21abc3df9550077797d18":{"_id":"39c21abc3df9550077797d18","hid":349,"name":"Vitaly","nick":"Vitaly","avatar_id":null,"css":""},"405ec5c83df9550077794e80":{"_id":"405ec5c83df9550077794e80","hid":3166,"name":"RW9UAO","nick":"RW9UAO","avatar_id":null,"css":""}},"settings":{"blogs_can_create":false,"blogs_mod_can_delete":false,"blogs_mod_can_hard_delete":false,"blogs_mod_can_add_infractions":false,"can_report_abuse":false,"can_vote":false,"can_see_ip":false,"blogs_edit_comments_max_time":30,"blogs_show_ignored":false,"blogs_reply_old_comment_threshold":30,"votes_add_max_time":168},"entry":{"_id":"5b65c4e99970730077118172","hid":23501,"title":"Регуль для бор-машинки: о фильтрации сигналов и т.п.","html":"<p><a href=\"https://github.com/speedcontrols/ac_sc_grinder\" class=\"link link-ext link-auto\" data-nd-link-type=\"autolink\" data-nd-link-orig=\"https://github.com/speedcontrols/ac_sc_grinder\" target=\"_blank\" rel=\"nofollow noopener\">github.com/speedcontrols/ac_sc_grinder</a> (точную ссылку на файл и строчки не даю, т.к. по окончании отладки будем чистить историю).</p>\n<p>Практика показала, что сигнал на выходе АЦП имеет свойство прыгать, и поэтому есть смысл чистить резкие скачки. Делается это обычно медианным фильтром. К сожалению, мне не удалось найти готовых быстрых библиотек с учетом особенностей эмбедов, поэтому желающим советую смотреть <a href=\"https://embeddedgurus.com/stack-overflow/2010/10/median-filtering/\" class=\"link link-ext\" data-nd-link-orig=\"https://embeddedgurus.com/stack-overflow/2010/10/median-filtering/\" target=\"_blank\" rel=\"nofollow noopener\">тут</a> (вариант от Ekstrom). Мне не очень понравилось, что над быстрой имплементацией надо “думать”, чтобы понять как она работает. Поэтому решил пойти другим путем - разобраться с truncated mean (или как его там). Кто забыл школьные лабораторки по физике, напомню:</p>\n<ul>\n<li>Считаем дисперсию измерений (среднеквадратичное отклонение от среднего арифметического).</li>\n<li>Отбрасываем все, что вылезло за пределы допустимого и усредняем еще раз.</li>\n</ul>\n<!--cut-->\n<p>У меня на глаз получилось что при 8 отсчетах и отклонении 1.1*sigma выходит вполне приличный результат. По затратам - 2 полных прохода по массиву данных (в данном случае - по кольцевому буферу). На первом проходе считается среднее арифметическое и дисперсия, на втором - отбрасывается лишнее и усредняется остаток. Итого:</p>\n<ul>\n<li>Оптимизированное truncated mean чуть медленнее оптимизированной медианы (меньше чем в полтора раза), но код намного понятнее.</li>\n<li>Есть “встроенный усреднятор”, который теоретически должен скакать меньше медианы. На самом деле не факт и вопрос филосовский.</li>\n<li>Затраты на вычисления стабильные.</li>\n<li>Если процессор с навороченными кешами - тут только чтение, запись вообще отсутствует.</li>\n</ul>\n<p>Теперь про сами измерения. Есть нюансы с точностью измерения напряжения и тока, когда они переходят через ноль. С практической точки зрения, получилось так:</p>\n<ul>\n<li>Симистор открывается слегка не симметрично на положительной и отрицательной полуволне. Надо мерять не только длину полуволны, но и длину полного периода, а потом смотреть расхождение и компенсировать разницу.</li>\n<li>В новой схеме (в отличие от макетки) применили усилитель для токового шунта, а у него выход никогда не становится 0 (есть малюсенькое смещение, хоть операционник и специализированный). В коде напряжение можно сравнивать с 0, а ток - нет. Ну тоже примерно понятно как лечить.</li>\n</ul>\n<p>Пока все. Победа близка <span class=\"emoji emoji-smiley\" data-nd-emoji-src=\":smiley:\">😃</span></p>\n","user":"39c21abc3df9550077797d18","ts":"2018-08-04T15:23:21.000Z","st":1,"cache":{"comment_count":3,"last_comment":"5b668ec9997073007711ca04","last_comment_hid":3,"last_ts":"2018-08-05T05:44:41.000Z","last_user":"405ec5c83df9550077794e80"},"views":723,"bookmarks":0,"votes":0},"subscription":null},"locale":"en-US","user_id":"000000000000000000000000","user_hid":0,"user_name":"","user_nick":"","user_avatar":null,"is_member":false,"settings":{"can_access_acp":false,"can_use_dialogs":false,"hide_heavy_content":false},"unread_dialogs":false,"footer":{"rules":{"to":"common.rules"},"contacts":{"to":"rco-nodeca.contacts"}},"navbar":{"tracker":{"to":"users.tracker","autoselect":false,"priority":10},"forum":{"to":"forum.index"},"blogs":{"to":"blogs.index"},"clubs":{"to":"clubs.index"},"market":{"to":"market.index.buy"}},"recaptcha":{"public_key":"6LcyTs0dAAAAADW_1wxPfl0IHuXxBG7vMSSX26Z4"},"layout":"common.layout"}