"""Потоковый 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.