FPGA мастера: порт излучает не в одной стадии, а в блоке подряд идущих —
младшие SUBSTAGE_BITS бит счётчика стадий стали положением выходного ключа,
старшие выбирают порт. Вынесено в функцию port_excites в Sweep.vhd, новое поле
приезжает из свободных битов 8:6 регистра SweepSetup через SPIConfig и top.vhd.
Совместимость со стоком строгая: при SUBSTAGE_BITS=0 сдвиг нулевой, а
добавленная проверка "порт-стадия выше последней" ничего не меняет, потому что
счётчик стадий и так пробегает только 0..STAGES. Ручной режим и анализатор
спектра, где STAGES=0, ведут себя ровно как раньше.
MCU: у SetupSweep добавлен параметр substage_bits со значением по умолчанию 0,
поэтому вызовы из Manual.cpp и SpectrumAnalyzer.cpp не тронуты. VNA.cpp берёт
ширину под-стадии из port3Stage — порта 3 у этого железа нет, поле свободно, и
формат пакета не меняется.
Проверено: GHDL анализирует все три VHDL-файла чисто; новый самопроверяющийся
Test_Sweep.vhd прогоняет четыре сценария (сток, два положения, приёмник без
излучения, четыре положения) и проверен мутацией — с возвращённым стоковым
сравнением сценарии с под-стадиями падают. Обе сборки MCU собираются без ошибок.
Битовые позиции сверены сквозь всю цепочку: хост шлёт port3Stage=1 в слове
0x243, MCU пишет регистр 0x7041, FPGA читает SUBSTAGE_BITS=1.
Слейвы перепрошивать не нужно: им шлётся порт-стадия 7, которая со счётчиком
0..3 не совпадает и в стоковом сравнении.
Исходники теперь опережают лежащие рядом бинарники — предупреждение добавлено в
начало reproduce/README.md, хеш README в SHA256SUMS обновлён. Порядок ввода в
строй расписан в per_point_switching.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Прошивка STM32 (WeAct G431CB, тот же тулчейн, что у пульта тележки), которая
стоит в разрыве триггерной петли между мастером и первым слейвом и переключает
выходной ключ внутри частотной точки.
Положение ключа — младший бит номера стадии, а период 2 нацело делит 4 стадии,
поэтому чередование не рвётся на границе точки и контроллеру достаточно
инвертировать ногу на каждый цикл триггера. Переключение по СПАДУ: спад означает
«оцифровка закончилась», дальше идёт окно успокоения следующей стадии (~62 мкс
при dwell_us=2), которого ключу хватает с запасом, и кольцо удерживать не надо.
Один потерянный фронт инвертировал бы чётность навсегда и молча поменял антенны
местами, поэтому контроллер распознаёт границу точки по длине паузы (между
точками к успокоению добавляется перезагрузка регистров PLL) и принудительно
ставит положение A — чётность чинится на каждой точке, а не раз на развёртку.
Порог берётся как минимум паузы по скользящему окну с запасом, то есть
подстраивается сам; отдельный провод-маркер начала развёртки не нужен.
Задержку зеркалирования проверил по Sweep.vhd: мастер стартует оцифровку по
своему TRIGGER_IN с конца кольца, то есть тоже после контроллера. Задержка
общая для всех приборов и сокращается в отношении «приёмник/опорник» — фазовой
ошибки не вносит, только чуть удлиняет развёртку.
Собирается: RAM 13.9%, Flash 20.0%.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Матрица 4x4 за одну развёртку: каждый порт мастера измеряется на каждой частоте
дважды, с двумя положениями выходного ключа. Ключ дёргает контроллер в
триггерной петле, поэтому расбери переключателями больше не управляет —
SwitchedMatrixRadarService уходит из тракта, все 16 комбинаций снимаются в
пределах одной точки вместо разброса между тремя развёртками.
Выходы нумеруются позиция-мажорно, стадии порт-мажорно (старшие биты счётчика
стадий выбирают порт, младший — положение ключа). Из этого следует, что
положение ключа = младший бит номера стадии, а период 2 нацело делит 4 стадии —
поэтому контроллеру достаточно инвертировать ногу на каждый цикл триггера, без
абсолютного счётчика. Выходы 0 и 1 при этом сохраняют прежний смысл.
Приёмники слейвов пронумерованы от числа выходов + 1, а не от фиксированного 3:
иначе при 4 выходах прямой член «приёмник 3 <- выход 3» назывался бы так же, как
отражение выхода 3. При двух выходах даёт прежние порты 3..6.
Слейвам порт-стадии выставляются в 7: стоковый приём «одна за последней стадией»
перестаёт работать, когда порт выбирается старшими битами.
Всё за флагом multi_device.stimulus_switch_positions (1 = прежнее поведение,
байт в байт). Спецификация правок FPGA/STM в device_firmware/per_point_switching.md.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>