Перейти к содержанию

Lab 11.42 — Последние проценты: ложный захват frame-sync

Цель

После починки DC-блокера (Lab 11.41) двухплатный канал под Gardner чист на ~92%. Понять, что за оставшиеся ~6–8% кадров, и закрыть их — либо доказать, что без RTL-изменения закрыть нельзя.

Отказы бимодальны

Первый шаг — не крутить ручки, а посмотреть, что вообще представляют собой грязные кадры. Разбивка залоченных кадров по числу ошибок payload:

  • ~92% декодируются идеально;
  • ~2–3% несут один неверный бит — обычный шум канала, разбросан по случайным индексам;
  • ~2–3% несут ~117 из 256 бит неверно — 46%.

46% — это не маргинальный SNR. Кадр у порога шума теряет горстку бит, а не половину. Половина бит — это дискретное событие: весь бёрст декодирован в неверном повороте созвездия. Две популяции ошибок требуют разных объяснений; усреднение их в один «BER» прячет ту, что важна.

Где сидят грубые ошибки

Поворот на 90° и проскок несущей в середине оба дают ~50% BER, поэтому число ошибок их не различит. А позиция — различит, и телеметрия gp_ctrl[15] её сообщает: какой квартиль отказывает первым и индекс первой ошибки. По грубым кадрам:

  • квартиль 0 чист лишь в ~1 из 17 грубых кадров;
  • первая ошибка в битах 0–31 в ~16 из 17.

Порча начинается с бита 0 и охватывает весь кадр. Это исключает проскок в середине (он оставил бы ранний чистый участок) и фиксирует механизм как разворот всего бёрста с самого первого символа.

Каждый рантайм-рычаг — отвергнут

Приёмник уже разрешает 90-градусную неоднозначность QPSK четырёхветочным frame-sync, значит неверный поворот означает, что это разрешение промахнулось. До RTL каждая рантайм-гипотеза проверена и убита данными:

Гипотеза Рычаг Результат
межплатный CFO путает захват coarse CFO gp_ctrl[13] хуже — gross 5% → 16%, lock 100% → 84%
реакквизиция с нуля каждый бёрст costas_hold_phase gp_ctrl[11] без эффекта (3.0% → 3.3%)
плохая фаза выборки свип start_offset 0–7 плоско; прежняя «корреляция» была шумом
не хватает SNR TX −38…−22 dBm U-образно, минимум ~3% на −30 (ниже шум, выше компрессия)
рабочая точка RX RX gain 30–70 U-образно, минимум ~3% на gain 30–50

Обе оси мощности U-образны с полом на оптимуме, и ни один гейт его не убирает. Пол — не условие канала и не тюнинг; он структурный.

Причина — арифметическая

Арбитраж frame-sync (qpsk_ber_counter) — first-past-the-post по скользящей 24-битной корреляции: первая ветка, нашедшая окно с промахом преамбулы ≤ LOCK_ERR_TOL, забирает бёрст, и у ветки A приоритет. Комментарий модуля предполагал, что неверный квадрант «промахивается на ~12 из 24 бит преамбулы, далеко за LOCK_ERR_TOL, поэтому захватывает ровно одна ветка». Это верно в истинной позиции кадра. И игнорирует скользящий поиск по остальной части бёрста.

Неверный квадрант совпадает по каждому биту преамбулы с вероятностью ~½, поэтому на любой из ~140 скользящих позиций шанс окна с ≤ LOCK_ERR_TOL промахами равен C(24, ≤tol) / 2²⁴. По бёрсту:

python lab_11_42_ber_floor_lock_tolerance.py --predict
   LOCK_ERR_TOL=3: per-position 1.4e-4 -> per-burst 1.9e-2
   LOCK_ERR_TOL=2: per-position 1.8e-5 -> per-burst 2.5e-3
   LOCK_ERR_TOL=1: per-position 1.5e-6 -> per-burst 2.1e-4
   LOCK_ERR_TOL=0: per-position 6.0e-8 -> per-burst 8.3e-6

При отгруженном LOCK_ERR_TOL=3 это ~2% на бёрстложный захват, и он совпадает с измеренным полом. Грубые отказы — это ветка A, скользящая по шумной части бёрста и лочащаяся на случайном окне раньше, чем приходит истинный кадр.

Правка, и почему она не стоит lock rate

Ужесточить LOCK_ERR_TOL до 1: случайное окно падает ~100× до ~0.02% на бёрст. Очевидное опасение — другая сторона компромисса: истинная преамбула с парой шумовых ошибок теперь не залочится и бёрст потеряется. Здесь это безопасно по двум причинам:

  • истинная преамбула совпадает почти идеально (у чистых кадров ноль ошибок преамбулы), поэтому лочится с запасом при tol=1;
  • проверено симуляцией на реальных self-OTA захватах — и tb_qpsk_rx_costas, и, что важно, tb_qpsk_costas_stress (который добавляет 3000 отсчётов шума перед кадром — ровно сценарий ложного захвата) декодируют при BER 0/280 с LOCK_ERR_TOL=1. Ужесточённый захват отвергает шум и всё равно берёт истинный кадр.

Полный пакет блока 5: 35/35. Правка — один параметр в инстанциации моста, но за ней арифметика выше и стресс-бенч, а не догадка.

Проверка на железе

Пересобрано при LOCK_ERR_TOL=1, передеплоено холодной загрузкой и прогнано через A TX1 → 30 дБ → B RX1 (1200 бёрстов за два прогона):

tol=3 (baseline) tol=1 (эта сборка)
чистых кадров ~92% 98.9% (1182/1195)
грубых (разворот всего бёрста) ~3% 0.75% (9/1195)
однобитный шум ~2% ~0.3%
lock rate ~100% 99.6% (5 потеряно из 1200)

Пол упал в ~3–4×, чистота выросла с ~92% до ~99%. Пять потерянных кадров — намеренный размен: бёрст, у которого истинная преамбула несла ≥2 шумовых ошибки, теперь отвергается, а не декодируется криво, и потерянный кадр даёт ноль ошибок там, где грубый давал ~117.

Но арифметика обещала ~100×, а железо дало ~4× — значит модель была неполной, и честнее сказать почему, а не округлить. Компонента скользящего ложного захвата (~2%) упала как предсказано (до ~0.02%); осталась другая причина неверного поворота, которую LOCK_ERR_TOL не трогает. Проверены две:

  • самоподобие преамбулы под поворотом — отвергнуто офлайн: 24-битная преамбула промахивается по своим 90° и 270° поворотам ровно на 12/24, по 180° на 24/24, то есть не легче случайного;
  • бёрсты с маргинальной несущей — остаточная частота гуляла 0.3%→1.0% между прогонами, отслеживая медленный дрейф межплатного CFO, что указывает на бёрсты, где Costas садится у 45°-границы: преамбула лочится на верном повороте, но payload разворачивается. Это подлинное событие захвата, не ложный лок, и ужесточение корреляции на него не влияет.

Так что честный итог — устойчивое, понятое сокращение в ~4× до пола ~1%, а не 100× из одномеханизменной модели. Пробить ниже ~1% потребует другого инструмента — дифференциального кодирования или проверки согласованности payload, а не очередного шага lock-толеранса. Результат: docs/assets/lab1142_ber_floor_live.json.

О чём эта лаба на самом деле

Баг DC-блокера — один блок доверял измерению, снятому не в том месте. Этот — один комментарий доверял допущению в одной точке («неверная ветка не может залочиться»), которое держалось в истинной позиции кадра и рушилось везде ещё, куда смотрел коррелятор. Оба закрыты одинаково: перестать усреднять, разделить популяцию отказов и идти за той, что несёт сигнал. Здесь арифметика скользящего коррелятора предсказала точный пол ещё до того, как повернули хоть одну ручку.