Files
templates/python/logic_analyzer/decoders/sigma_delta.py
T

40 lines
6.6 KiB
Python

"""Потоковый CIC-декодер однобитного сигма-дельта модулятора без зависимостей от GUI.""" # Ядро одинаково работает в DSView и автономных анализаторах.
class SigmaDeltaFilter: # Каскад интеграторов и гребенчатых звеньев реализует фильтры sinc первого, второго и третьего порядка.
def __init__(self, decimation=256, order=3, invert=False): # Децимация задаётся числом тактов на результат; 256 и sinc3 являются начальными настройками анализатора.
if isinstance(decimation, bool) or not isinstance(decimation, int) or not 1 <= decimation <= 65536: # Ограничение 65536 тактов удерживает максимальное усиление sinc3 в пределах 49 бит.
raise ValueError('Decimation must be an integer from 1 to 65536.') # Дробные и неположительные окна не определяют допустимую децимацию.
if isinstance(order, bool) or not isinstance(order, int) or order not in (1, 2, 3): # Число интеграторов должно совпадать с числом гребенчатых звеньев.
raise ValueError('Filter order must be 1, 2 or 3.') # Неизвестный порядок нельзя незаметно заменять sinc3.
self.decimation = decimation # Каждый результат появляется после этого числа принятых битов.
self.order = order # Порядок также определяет длительность начального установления фильтра.
self.invert = bool(invert) # Инверсия применяется к битам до фильтрации и меняет знак восстановленного сигнала.
self.gain = decimation ** order # Усиление CIC при постоянном входе равно R в степени порядка при дифференциальной задержке один.
self.mask = (1 << self.gain.bit_length()) - 1 # Модуль степени двойки строго больше усиления сохраняет точный результат при переполнениях интеграторов.
self.integrators = [0] * order # Нулевое начальное состояние не предполагает неизвестную предысторию захвата.
self.delays = [0] * order # Каждый гребенчатый каскад хранит свой предыдущий вход на пониженной частоте.
self.phase = 0 # Счётчик внутри окна исключает накопление дробной ошибки децимации.
self.blocks = 0 # Первые order минус один результатов относятся к установлению и не выдаются пользователю.
def feed(self, bit): # Принимается ровно один уровень DATA на выбранном фронте CLK.
if bit not in (0, 1): # Служебные значения неподключённых каналов sigrok не являются цифровыми уровнями.
raise ValueError('Sigma-delta data must be a logic level 0 or 1.') # Ошибка назначения входов не должна превращаться в правдоподобную амплитуду.
value = int(bit) ^ self.invert # Униполярное представление позволяет нормировать результат без знакового переполнения.
for stage in range(self.order): # Последовательно обновляем интеграторы на полной частоте модулятора.
self.integrators[stage] = (self.integrators[stage] + value) & self.mask # Модульная арифметика ограничивает память независимо от длительности записи.
value = self.integrators[stage] # Следующий интегратор получает уже обновлённый выход предыдущего.
self.phase += 1 # Считаем только фактически захваченные тактовые фронты.
if self.phase < self.decimation: # Между границами децимации выходной отсчёт ещё не готов.
return None # Неполные окна не дополняются вымышленными битами.
self.phase = 0 # Новый блок начинается со следующего реального бита.
for stage in range(self.order): # Гребенчатые звенья выполняются только на выходной частоте.
previous = value # Задержка сохраняет вход текущего звена, а не его разность.
value = (value - self.delays[stage]) & self.mask # Разности устраняют накопление интеграторов, включая их модульные переполнения.
self.delays[stage] = previous # Это состояние используется через R входных тактов.
self.blocks = min(self.order, self.blocks + 1) # Счётчик установления насыщается и не растёт вместе с записью.
if self.blocks < self.order: # Для sincN пропускаем первые N минус один выходных блоков с неизвестной предысторией.
return None # Частично установившийся фильтр не выдаёт ложное смещение постоянного сигнала.
code = 2 * value - self.gain # Биполярный код принимает диапазон от минус R**N до плюс R**N без привязки к конкретному АЦП.
return {'code': code, 'gain': self.gain, 'value': code / self.gain, 'density': value / self.gain} # Нормированная амплитуда и фильтрованная плотность единиц сохраняют точный масштаб CIC.