
Комментарии 36
Какой же это фильтр "Нижних Частот" - это квантование. Вы АЧХ постройте и сразу будет всё ясно.
Как-то всё сложно у вас получилось. Триггер, конечно, обладает памятью, но состояний схемы ведь всего два: в любой момент времени точка на фазовой диаграмме движется либо по красной ветке гистерезиса, либо по синей. Не важно, сколько там порогов.
Надо чтобы проходил вот такой модульный тест
bool test_hist_filter_proc2(void){
bool res = true;
ASSERT_EQ(0, hist_filter_proc_sample(TEST_HIST_FILTER, 1.0f));
ASSERT_EQ(1, hist_filter_proc_sample(TEST_HIST_FILTER, 20.0f));
ASSERT_EQ(1, hist_filter_proc_sample(TEST_HIST_FILTER, 12.0f));
ASSERT_EQ(3, hist_filter_proc_sample(TEST_HIST_FILTER, 87.0f));
return res;
}
А для этого два триггера должны быть в разных состояниях (TG0=1 TG3=0).
Вариантов выходных состояний, да, побольше, целых 5. Я про количество внутренних состояний, которые нужно помнить. Их явно не 16.
И у вас сделана наивная реализация, имитирующая реальное железо. В железе, да, так удобнее, наверное, потому что оно работает параллельно. Но софт в мк так не умеет, и эффективнее сделать один конечный автомат, а не 4 независимых. И сравнение с порогами сделать оптимальнее. Тем более, что взялись за LUT, и аналоговые пороги не какие попало.
Иначе вот это:
Можно и дальше наращивать квантование добавляя количество отдельных триггеров Шмитта.
приведёт к ужасно медленному коду.
если ему завести ОС и двигать порог у получившегося компаратора, то кажется получится дельта-сигма.... надо собрать как-нибудь на рассыпухе, а то никогда не понимал как оно работает...
Почти с языка сняли) Буквально недавно искал, к чему лишний ОУ в схеме приложить. Попытался индикацию заряда на мигающем светодиоде сделать.
Типа того

Что это за программа в которой Вы схему смоделировали?
Qucs-Spice при поддержке нашего товарища @vv_kuznetsov
Вариантов выходных состояний 5. количество внутренних состояний, которые нужно помнить. Их явно не 16.
И у вас сделана наивная реализация, имитирующая реальное железо. В железе, да, так удобнее, наверное, потому что оно работает параллельно. Но софт в мк так не умеет, и эффективнее сделать один конечный автомат, а не 4 независимых. И сравнение с порогами сделать оптимальнее. Тем более, что взялись за LUT, и аналоговые пороги не какие попало.
Да. В самом деле. Можно переписать в виде автомата Мура.

Если бы не ваше замечание, то я бы до такого не додумался.
Я тоже попробовал ради интереса, и точно такой же LUT получил. Большой, да, но зато регулярный. Значит при большом числе порогов его проще описать формулой, например
state = input / 2 + (input & (state > (input / 2)))
Если и пороги тоже регулярны, то остаётся найти формулу для перевода аналогового сигнала в input.
Вот даже граф нарисовал

Код построения графа на Graphviz
digraph G {
rankdir=TB;
OUT0 [fillcolor = darkorchid1] [shape = box][style="filled"]
OUT1 [fillcolor = mediumslateblue] [shape = box][style="filled"]
OUT2 [fillcolor = green] [shape = box][style="filled"]
OUT3 [fillcolor = blue] [shape = box][style="filled"]
OUT4 [fillcolor = red] [shape = box][style="filled"]
OUT0 -> OUT0 [label="GAP0"][color="darkorchid1"] [fontcolor = darkorchid1]
OUT0 -> OUT0 [label="HIST0"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT1 [label="GAP1"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT1 [label="HIST1"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT2 [label="GAP2"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT2 [label="HIST2"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT3 [label="GAP3"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT3 [label="HIST3"][color="darkorchid1"][fontcolor = darkorchid1]
OUT0 -> OUT4[label="GAP4"][color="darkorchid1"][fontcolor = darkorchid1]
OUT1-> OUT0 [label="GAP0"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT1 [label="HIST0"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT1 [label="GAP1"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT1 [label="HIST1"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT2 [label="GAP2"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT2 [label="HIST2"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT3 [label="GAP3"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT3 [label="HIST3"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT1->OUT4 [label="GAP4"][color="mediumslateblue"][fontcolor = mediumslateblue]
OUT2 -> OUT0 [label="GAP0"][color="green"][fontcolor = green]
OUT2 ->OUT1 [label="HIST0"][color="green"][fontcolor = green]
OUT2 ->OUT1 [label="GAP1"][color="green"][fontcolor = green]
OUT2 ->OUT2 [label="HIST1"][color="green"][fontcolor = green]
OUT2 ->OUT2 [label="GAP2"][color="green"][fontcolor = green]
OUT2 ->OUT2 [label="HIST2"][color="green"][fontcolor = green]
OUT2 ->OUT3 [label="GAP3"][color="green"][fontcolor = green]
OUT2 ->OUT3 [label="HIST3"][color="green"][fontcolor = green]
OUT2 ->OUT4 [label="GAP4"][color="green"][fontcolor = green]
OUT3-> OUT0 [label="GAP0"][color="blue"][fontcolor = blue]
OUT3->OUT1 [label="HIST0"][color="blue"][fontcolor = blue]
OUT3->OUT1 [label="GAP1"][color="blue"][fontcolor = blue]
OUT3->OUT2 [label="HIST1"][color="blue"][fontcolor = blue]
OUT3->OUT2 [label="GAP2"][color="blue"][fontcolor = blue]
OUT3->OUT3 [label="HIST2"][color="blue"][fontcolor = blue]
OUT3->OUT3 [label="GAP3"][color="blue"][fontcolor = blue]
OUT3->OUT3 [label="HIST3"][color="blue"][fontcolor = blue]
OUT3->OUT4 [label="GAP4"][color="blue"][fontcolor = blue]
OUT4-> OUT0 [label="GAP0"][color="red"][fontcolor = red]
OUT4->OUT1 [label="HIST0"][color="red"][fontcolor = red]
OUT4->OUT1 [label="GAP1"][color="red"][fontcolor = red]
OUT4->OUT2 [label="HIST1"][color="red"][fontcolor = red]
OUT4->OUT2 [label="GAP2"][color="red"][fontcolor = red]
OUT4->OUT3 [label="HIST2"][color="red"][fontcolor = red]
OUT4->OUT3 [label="GAP3"][color="red"][fontcolor = red]
OUT4->OUT4 [label="HIST3"][color="red"][fontcolor = red]
OUT4->OUT4 [label="GAP4"][color="red"][fontcolor = red]
}
А зачем вам вообще понадобились автоматы?
Почему не сделать пример но так:
typedef float flt;
struct Filter {
flt e; int p, d;
flt next(flt y) {
int r, t[2]={ (int)floor(y+e), (int)floor(y-e) };
r=t[d]; if (r>p) d=1; else
if (r<p) d=0; else { p=r; return p; }
p=t[d]; return p;
}
Filter() { p=0; d=1; e=0.25001; }
};
d - направление (0,1), e-порог гистерезиса (±e), p - предыдущее значение
rk = filter.next( clip(yk, y_min, y_max ) );
И тогда при масштабировании (увелививание кол-ва уровней) не понадобиться увеличивать количество триггеров и перерисовывать диаграммы состояний конечного автомата.
У нас про это в лекциях было.
Год 90й? ))) только там без микроконтроллера :D
Хех, так скоро до применения мажоритарных элементов дойдём ... и цифровых фильтров)))
так скоро до применения мажоритарных элементов дойдём ... и цифровых фильтров)))
У меня есть отдельный текст про цифровой фильтр
Синтез Цифрового БИХ Фильтра Низких Частот
https://habr.com/ru/articles/836830/
Ой, не фильтр это... не фильтр. При шуме выше гистерезиса - на выход будут проходить куски шума. В отличие от фильтров, которые сделают шуму положенные "минус N dB" вне зависимости от текущего значения сигнала.
В фотошопе похожая обработка тоже называется "фильтром", не вижу ничего странного. Нелинейный, не ФНЧ, конечно, но что-то связанное с квантованием.
Причём тут Фотошоп? В обработке сигналов слово "фильтр" имеет совершенно однозначную интерпретацию, и это НЕ фильтр, поскольку у него нет частотной избирательности.
Обработку двумерных и 3-мерных сигналов ведь не Святой Дух делает. И математика-то не сильно отличается от 1D.
Медианный и фазовый фильтры с вами точно не согласны.
Постройте АЧХ медианного фильтра этой схемы и поймёте.
Нет технической возможности (с)
Он во-первых нелинейный. Импульсный отклик, если вообще можно так выразиться, у медианного ровно нулевой. Хотя против крутого прямоугольного фронта фильтр бессилен - всё, как было, пропускает.
Давайте я лучше АЧХ фазового фильтра построю. Который all-pass.
Про фчх не забудьте.
Дизер подайте на вход амплитудой разряда полтора, и всё получиться
Не понял, извините. Вы каким из двух больше интересуетесь?
Я про фильтр автора, который в частотной области ничего не фильтрует. ФЧХ - это про allpass фильтры
Автор исправил название статьи. Потому что многим тут действительно резало слух слово "ФНЧ" про нелинейный фильтр. Ничего тут не поделаешь - у нелинейного фильтра в общем случае нет понятия "АЧХ" или "ФЧХ".
А про фазовые: да почти любую ФЧХ в цифре реализовать не запрещено. Нарисуйте фломастером каляку-маляку - и можете смело выдавать её в качестве ТЗ.
Если сигнал оцифрован и на нём шум - проще всего сделать усредняющий фильтр. Например, скользящее окно шириной в 3 или 5 точек с записью в среднюю точку среднего значения
То что вы предлагаете это Медианный фильтр https://habr.com/ru/articles/935750/
С поправкой: медианный фильтр отсекает одиночные выбросы, а непрерывные колебания, как на рисунке, не отфильтровывает. Поэтому нужно вычисление среднеарифметического значения
Шум бывает и низкочастотным, а вовсе не в виде наивной бахромы на графике. Если б автор не поленился привести пример задачи, где гистерезисная обработка применяется, было бы понятней.
А это обычная обработка аналоговых датчиков положения, абсолютных энкодеров. Ну и в цифровой индикации тоже полезно.
Я вот MIDI- контроллером пользуюсь - там то же самое, напряжение с обычных потенциометров квантуется в 128 уровней. Фильтруют, чтобы без движения цифру не колбасило между двумя соседними значениями, и интерфейс не засорялся.
Очень интересная концепция. Встречали такой фильтр, реализованный в железе/аналоговой схеме? Если его совместить с flash adc, то должен получиться быстрый и помехоустойчивый захват, не требующий устройства выборки/хранения.
Ещё как встречается.
Квантование на Триггерах Шмитта