Lab045: demonstrate real RF BPSK error correction

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
LittleSam129
2026-09-01 10:49:00 +03:00
parent 72f933a32b
commit 62a376c811
6 changed files with 2354 additions and 0 deletions

View File

@@ -0,0 +1,217 @@
# Lab045: текущее состояние
## Статус
**РЕАЛИЗАЦИЯ ГОТОВА. ПРОГРАММНО ПРОВЕРЕНО. АППАРАТНАЯ ПРОВЕРКА ПРОЙДЕНА
(RESULT A). РЕАЛЬНАЯ FEC-КОРРЕКЦИЯ В ЭФИРЕ ДОКАЗАНА.**
Работа выполнена от фактического HEAD
`72f933a32b0dfaef3a4af5bd2cb4a2c` (`Lab044: validate arbitrary BPSK
packet reception`). 1 сентября 2026 года выполнен **ровно один** аппаратный
RF-прогон Lab045: RF TX count = 1, без повторов.
## Аппаратный результат (1 сентября 2026 года) — RESULT A
Каталог артефактов:
`C:\Users\user\Documents\SDR_Rover_Lab045_raw\20260901_103434_bpsk_fec\`
- **RF TX count = 1** (ровно одна передача, `TransmitGuard`, без повторов).
- **Инвентарь плат** подтверждён по серийникам: MASTER/TX `…323b97d3`,
SLAVE/RX `…2e5327d3`.
- **Общий опорный генератор PASS**: MASTER reg29 = 0x26 (38), SLAVE reg29 =
0x26 (38), SLAVE CLKIN = DETECTED (за 2 опроса, 141,8 мс).
- **Независимая синхронизация по преамбуле PASS**: peak/median +34,3 дБ,
peak/second +12,7 дБ, payload не использовался.
- **Защищённый PHY header PASS** (packet length = 268 восстановлена
мажоритарно, checksum сошёлся).
- **Канал был реально шумным**: SNR всего **2,63 дБ**, ошибок преамбулы
**39/1280** (BER 3,05 %), сырых ошибок кодированного потока
**155/4300** (BER **3,60 %**).
- **Свёрточный декодер Витерби исправил все ошибки**: post-FEC ошибок
пакета — **0/2144**, ошибок payload — **0/2048**, байтовых ошибок — 0.
- **CRC = PASS**, protocol header PASS (SYNC 0xAA55, версия 1, тип 2
(телеметрия), sequence 44, payload_length 256).
- **Payload восстановлен побитово точно**: SHA-256 `rx_payload.bin`
совпал с `tx_payload.bin` (`cb9d06fe…`); `rx_packet.bin` совпал с
`tx_packet.bin` (`ed5a5713…`).
### Главный научный итог
**REAL RF FEC CORRECTION DEMONSTRATED = YES.** До декодера в реальном
принятом сигнале присутствовали 155 ошибок кодированных бит (3,60 %),
после мягкого декодера Витерби осталось 0 ошибок, CRC пройден, произвольный
256-байтный payload восстановлен без единой ошибки. Это прямое
доказательство работы помехоустойчивого кода на реальном радиоканале — при
таком SNR незащищённый пакет Lab044 не имел бы шансов пройти CRC.
### Радиометрика прогона
CFO 0,128 Гц (общий опорник), phase −133,9°, separation 2,707,
timing offset −2 отсчёта. ADC: peak_complex 5,83 code, peak_component 5,0,
p99.9 ≈ 4,12 code (headroom 122). Clipping 0, near-int8 0. RX overruns 0,
TX underruns 0. BEFORE/DURING/AFTER: RMS после DC 0,832 / 0,874 / 0,846 —
на интервале кадра (0,288 с) сигнал слегка выше фона, хвост p99.9 during
4,21 против 4,12, перегрузки АЦП нет.
### Cleanup
MASTER CLKOUT OFF (SLAVE CLKIN «no clock signal detected»), SLAVE CLKOUT
OFF, зависших `hackrf_transfer.exe` нет. SHA-256 всех реально созданных
бинарных артефактов вычислены дважды и совпали.
Пост-RF программный шлюз повторно пройден: quick_gate PASS,
`pytest` 417 passed, `git diff --check` чист. Второй TX не выполнялся.
## Назначение
Lab045 добавляет исправление неизвестных битовых ошибок внутри принятого
радиопакета. Существующий `protocol/packet_erasure_fec.py` не менялся: его
GF(256) 12+3 предназначен для восстановления известных потерянных shards на
более высоком уровне, а не для исправления неизвестных позиций ошибочных битов.
Программно доказан тракт:
`256 произвольных байт -> существующий protocol packet и CRC32 -> MSB-first
bits -> convolutional R=1/2, K=7 -> interleaver -> noisy soft BPSK ->
deinterleaver -> soft Viterbi -> существующий parser/CRC -> исходный payload`.
## Свёрточный код
- `K = 7`, память `m = 6`, 64 состояния.
- Скорость `R = 1/2`.
- Порождающие многочлены в порядке выходных битов: `G0 = 171 octal`,
`G1 = 133 octal`.
- Полный регистр: `(input_bit << 6) | state`; в `state` находятся шесть
предыдущих входных битов, самый свежий занимает бит 5.
- Начальное состояние 0.
- К информационным битам добавляются шесть нулевых tail bits.
- Финальное состояние решётки 0; traceback начинается только из состояния 0;
tail bits удаляются из результата.
- BPSK-соглашение совпадает с `protocol.bpsk_radio`: `0 -> -1`, `1 -> +1`.
- Soft Viterbi получает вещественные значения до hard slicing. Branch metric:
сумма квадратов евклидовых расстояний до ожидаемой пары `{-1,+1}`.
Encoder проверен не только round trip с decoder: есть фиксированные короткие
эталонные векторы и второй независимо записанный reference encoder.
## Перемежитель
Детерминированный блочный interleaver записывает индексы строками и читает по
столбцам. Для Lab045 используется 64 столбца. Неполная последняя строка не
дополняется: отсутствующие ячейки пропускаются, поэтому длина не меняется.
Одна и та же permutation применяется к TX bits и обратно к RX soft values.
Перед применением проверяется, что каждый индекс встречается ровно один раз.
## Защищённый PHY header
Незащищённый header имеет 6 байт, 48 бит:
- magic `0xD391`, 16 бит;
- версия режима Lab045 `1`, 8 бит;
- длина существующего protocol packet в байтах, 16 бит;
- младшие 8 бит CRC32 предыдущих пяти байт, 8 бит.
Каждый отдельный header bit передаётся буквально как `b,b,b`; формат не
является конкатенацией `header|header|header`. После soft majority выполняется
fail-closed проверка magic, версии, checksum и диапазона длины `12..1024`
(12 байт равны минимальным header + CRC существующего protocol packet).
По принятой длине вычисляется точное число coded symbols. Если их физически не
хватает, Viterbi и protocol parser не запускаются. Лишние trailing soft values
детерминированно игнорируются.
## Независимый порядок приёма
Аппаратный адаптер подготовлен, но не запускался. Он принимает только IQ и
переиспользует из Lab044 независимый PRBS7 detector, timing, CFO и
phase/polarity recovery. На выходе берётся `normalized.real` до строки hard
slicing Lab044. Далее порядок фиксирован:
`PHY sync -> protected PHY header -> deinterleave soft -> soft Viterbi ->
reconstructed protocol packet -> existing parse_packet -> existing CRC`.
RX analyzer не принимает TX packet или payload. Сравнение pre-FEC, post-FEC и
payload с TX вынесено в отдельную диагностическую функцию, вызываемую только
после независимого CRC verdict.
## Точный размер кадра
| Величина | Значение |
|---|---:|
| Protocol packet | 268 bytes |
| Information bits | 2144 |
| Tail bits | 6 |
| Входных битов encoder с tail | 2150 |
| Coded bits | 4300 |
| Interleaver elements | 4300 |
| Незащищённый PHY header | 48 bits |
| Защищённый PHY header | 144 bits |
| PRBS7 preamble | 1280 bits |
| Всего BPSK-символов кадра | 5724 |
| Samples per symbol | 400 |
Учёт кадра и формы сигнала — это две разные величины, и их нужно различать:
| Величина | Символы | Отсчёты | Длительность при 8 MS/s |
|---|---|---|---|
| **Только информационные BPSK-символы кадра** | 5724 | 2 289 600 | 286,2 мс |
| **Фактически сгенерированная форма сигнала** | 5766 | 2 306 400 | 288,3 мс |
| Разница | 42 | 16 800 | 2,1 мс |
Откуда берётся разница в 42 символа (16 800 отсчётов) — подтверждено прямо по
формирователю `shape_frame_like_lab042` (свёртка `guard + upsampled + guard`
с ФРК-фильтром в режиме `full`, длина = `(N + 2·guard + span)·sps`):
- **32 символа** — защитные интервалы Lab042 (`LAB042_GUARD_SYMBOL_COUNT = 16`
с каждой стороны, до и после кадра);
- **10 символов** — длина корневого приподнятого косинуса (ФРК)
`LAB042_RRC_SPAN_SYMBOLS = 10` (переходный хвост фильтра от режима `full`).
Это не guard/RRC «на веру» и не дефект сигнала: это ровно тот же механизм
формирования, что и в проверенном Lab044, где 3456 символов кадра дают
1 399 200 отсчётов = (3456 + 42)·400. Форму сигнала менять не нужно.
Для сравнения Lab044: кадр 3456 символов, форма 1 399 200 отсчётов, 174,9 мс.
Lab045 добавляет к кадру 2268 символов. Старая оценка около 280 мс для Lab044
не используется.
## Фактические программные результаты
- Новый набор `tests/test_lab045_hackrf_bpsk_fec.py`: 41 passed.
- Идеальный soft BPSK: CRC PASS, payload совпал побайтово.
- Детерминированный канал с `bit_error_probability=0.006`, seed 7: до FEC
28 ошибок из 4300 coded bits (`BER = 0.0065116`), после FEC 0 ошибок в
protocol packet, CRC PASS, payload точный.
- Пачка из 14 соседних channel symbols: после interleaver/FEC CRC PASS,
payload точный.
- Детерминированный Gaussian noise с `sigma=0.45`, seed 45: CRC PASS.
- На отдельном честном AWGN-примере из 128 information bits hard slicing дал
15 channel-bit errors и после hard Viterbi осталось 5 information-bit
errors; soft Viterbi по тем же значениям дал 0 information-bit errors.
Это доказывает использование амплитудной информации, но не является
измерением выигрыша в dB реального канала.
- Синтетическая cs8 IQ-форма прошла тот же detector/timing/CFO/phase adapter,
что Lab044: PHY sync PASS, CRC PASS, payload точный.
- Majority, checksum, bad magic, bad version, impossible length, truncated
header/body, extra trailing data, CRC corruption и отсутствие TX-data
leakage покрыты отдельными тестами.
## Software gate
- `python tools/quick_gate.py`: PASS; 414 тестов ядра, 5 функциональных
проверок лаб, 13 штатно пропущенных проверок.
- `python -m pytest tests/ -q`: 414 passed, 0 failed, 0 skipped.
- `git diff --check`: PASS.
- Pytest сообщил только предупреждение о невозможности создать `.pytest_cache`
из-за прав каталога; на выполнение и итог тестов это не повлияло.
## Ограничения и следующий шаг
`run_hardware_experiment()` намеренно завершается `NotImplementedError`, а CLI
с `--hardware` возвращает ненулевой код и печатает `RF TX = 0`. Аппаратный
Lab045, повтор Lab044, gain tuning, QPSK, JPEG и video в этой сессии не
выполнялись.
Следующий этап возможен только по отдельному разрешению: дополнить аппаратную
обвязку Lab045 доказанными common-clock preflight, one-TX guard, artifact и
cleanup механизмами Lab044, повторно пройти software gate и выполнить один
ограниченный аппаратный прогон.