Обновить

Комментарии 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, и аналоговые пороги не какие попало.


Да. В самом деле. Можно переписать в виде автомата Мура.

https://docs.google.com/spreadsheets/d/1dAsB0f5b-lm0g4HAjEvebUA9jxHLjEZ7dJht3QiOLoY/edit?gid=636705967#gid=636705967

Если бы не ваше замечание, то я бы до такого не додумался.

Я тоже попробовал ради интереса, и точно такой же 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 ) );
И тогда при масштабировании (увелививание кол-ва уровней) не понадобиться увеличивать количество триггеров и перерисовывать диаграммы состояний конечного автомата.

Это точно на си написано?

Конечные автоматы это золотой молоток системного программирования. Большинство задач решаются при помощи КА.

Это классика.

int p, d;

Дык это же и есть те самые состояния конечного автомата.

У нас про это в лекциях было.

Год 90й? ))) только там без микроконтроллера :D

Хех, так скоро до применения мажоритарных элементов дойдём ... и цифровых фильтров)))

так скоро до применения мажоритарных элементов дойдём ... и цифровых фильтров)))

У меня есть отдельный текст про цифровой фильтр
Синтез Цифрового БИХ Фильтра Низких Частот
https://habr.com/ru/articles/836830/

Ой, не фильтр это... не фильтр. При шуме выше гистерезиса - на выход будут проходить куски шума. В отличие от фильтров, которые сделают шуму положенные "минус N dB" вне зависимости от текущего значения сигнала.

В фотошопе похожая обработка тоже называется "фильтром", не вижу ничего странного. Нелинейный, не ФНЧ, конечно, но что-то связанное с квантованием.

Причём тут Фотошоп? В обработке сигналов слово "фильтр" имеет совершенно однозначную интерпретацию, и это НЕ фильтр, поскольку у него нет частотной избирательности.

Обработку двумерных и 3-мерных сигналов ведь не Святой Дух делает. И математика-то не сильно отличается от 1D.

Медианный и фазовый фильтры с вами точно не согласны.

Постройте АЧХ медианного фильтра этой схемы и поймёте.

Нет технической возможности (с)

Он во-первых нелинейный. Импульсный отклик, если вообще можно так выразиться, у медианного ровно нулевой. Хотя против крутого прямоугольного фронта фильтр бессилен - всё, как было, пропускает.

Давайте я лучше АЧХ фазового фильтра построю. Который all-pass.

Про фчх не забудьте.

Дизер подайте на вход амплитудой разряда полтора, и всё получиться

Не понял, извините. Вы каким из двух больше интересуетесь?

Я про фильтр автора, который в частотной области ничего не фильтрует. ФЧХ - это про allpass фильтры

Автор исправил название статьи. Потому что многим тут действительно резало слух слово "ФНЧ" про нелинейный фильтр. Ничего тут не поделаешь - у нелинейного фильтра в общем случае нет понятия "АЧХ" или "ФЧХ".

А про фазовые: да почти любую ФЧХ в цифре реализовать не запрещено. Нарисуйте фломастером каляку-маляку - и можете смело выдавать её в качестве ТЗ.

Исправлять надо не только названия, но и ошибочные утверждения в самой статье, например фраза " видим, что схема фильтрует вч составляющую" и соответствующая картинка принципиально неверны.

Если сигнал оцифрован и на нём шум - проще всего сделать усредняющий фильтр. Например, скользящее окно шириной в 3 или 5 точек с записью в среднюю точку среднего значения

То что вы предлагаете это Медианный фильтр https://habr.com/ru/articles/935750/

С поправкой: медианный фильтр отсекает одиночные выбросы, а непрерывные колебания, как на рисунке, не отфильтровывает. Поэтому нужно вычисление среднеарифметического значения

Поэтому нужно вычисление среднеарифметического значения

Тогда получается FIR(КИХ) фильтр скользящего среднего. Это у которого все коэффициенты одинаковые и в сумме дают 1.

Шум бывает и низкочастотным, а вовсе не в виде наивной бахромы на графике. Если б автор не поленился привести пример задачи, где гистерезисная обработка применяется, было бы понятней.

А это обычная обработка аналоговых датчиков положения, абсолютных энкодеров. Ну и в цифровой индикации тоже полезно.

Я вот MIDI- контроллером пользуюсь - там то же самое, напряжение с обычных потенциометров квантуется в 128 уровней. Фильтруют, чтобы без движения цифру не колбасило между двумя соседними значениями, и интерфейс не засорялся.

 Если б автор не поленился привести пример задачи, где гистерезисная обработка применяется, было бы понятней.

Нигде. Просто в 2019 был такой вопрос на собеседовании при устройстве на работу программистом МК.

Очень интересная концепция. Встречали такой фильтр, реализованный в железе/аналоговой схеме? Если его совместить с flash adc, то должен получиться быстрый и помехоустойчивый захват, не требующий устройства выборки/хранения.

Ещё как встречается.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации