from dataclasses import dataclass, fields # Неизменяемая таблица наследует прежнюю модель, сохраняя сравнение обеих координат перед пуском. from .waveform import Waveform # Общие частота, точки X, Vref и период принадлежат прежней модели генератора. from .signal_reconstruction import dac12 # Напряжения Y квантует то же C-ядро, что используется одиночным выходом X. @dataclass(frozen=True) # Изменение любого кода Y создаёт другое задание и требует повторной загрузки перед start. class XYWaveform(Waveform): # Дополняет один общий период второй синхронной координатой без дублирования настройки таймера. codes_y: tuple # Ровно один 12-битный код Y соответствует каждому коду X с тем же индексом и временем. def with_y(wave, volts): # Добавляет вертикальное отклонение к уже построенной и проверенной временной сетке X. values=tuple(volts) # Однократно фиксирует последовательность, включая генераторы Python. if len(values)!=len(wave.codes): # Оба DMA-канала должны содержать строго одинаковое число пар, без дополнения и обрезки. raise ValueError("X и Y должны иметь одинаковое число отсчётов") # Ошибка выявляется до открытия порта и изменения состояния устройства. codes=dac12(values,wave.vref) # Общая проверка отвергает NaN, бесконечность и выход Y за диапазон 0…Vref. return XYWaveform(**{field.name:getattr(wave,field.name) for field in fields(Waveform)},codes_y=codes) # Сохраняет точные коды X и добавляет Y без интерполяции и изменения частоты.