43 KiB
Lab046: текущее состояние
Статус
LAB046 SOFTWARE OBJECT TRANSPORT = COMPLETE.
CONTINUOUS STREAM VALIDATION = PASS (NORMALIZED SOFT-SYMBOL LEVEL).
ПРОГРАММНАЯ ПРОВЕРКА НЕПРЕРЫВНОГО СЫРОГО IQ-ПОТОКА = PASS.
LAB046C HARDWARE RESULT = A (FULL 1400 MHZ RF OBJECT TRANSPORT).
FULL RF OBJECT TRANSPORT = PASS.
RF TX PROCESS COUNT FOR THIS RESULT = 1.
VALID FRAMES = 68/68. CRC PASS = 68. CRC FAIL = 0.
PRE-FEC CODED BIT ERRORS = 787. POST-FEC PROTOCOL BIT ERRORS = 0.
OBJECT COMPLETE = YES. OBJECT SIZE = 16384 BYTES.
SHA MATCH = YES. OBJECT BYTE ERRORS = 0. OBJECT BIT ERRORS = 0.
HISTORICAL FIRST LAB046C AT 1080 MHZ = RESULT C.
THE HISTORICAL 1080 MHZ RESULT WAS NOT RECLASSIFIED.
INDEPENDENT 1400 MHZ THRESHOLD = 0.033527640625834465.
CURRENT SOFTWARE GATE = PASS: quick_gate 512, pytest 512 passed, git diff --check clean.
Lab046A/B остаются только программными лабами. В истории Lab046C отдельно сохранены первый полный аппаратный результат C на 1080 МГц и новый полный аппаратный результат A на 1400 МГц. В новом опыте выполнен ровно один заранее разрешённый непрерывный процесс передачи без повтора. Ни JPEG, ни видео, ни QPSK не запускались.
Lab046C: полный аппаратный результат 1400 МГц, RESULT A
2 сентября 2026 года через два HackRF передан новый криптографически случайный объект размером 16384 байта. Он был разбит существующей архитектурой Lab046 на 68 фрагментов и передан 68 последовательными защищёнными BPSK-кадрами одним непрерывным процессом. Частота равна 1400 МГц, частота дискретизации 8 МГц, символьная скорость 20 ксимв/с, цифровое смещение несущей +50 кГц. Усиления не менялись: TX VGA 10 дБ, RX LNA/VGA 24/24 дБ, RF amplifier и Bias-Tee выключены.
Общий опорный генератор прошёл аварийно-безопасную проверку: MASTER reg29
0x26, SLAVE CLKIN DETECTED, SLAVE reg29 0x26. Приём начался на
0.7525116 с раньше передачи и закончился на 3.6341200 с позже неё. Файл
передачи содержит 156 835 200 комплексных отсчётов, 313 670 400 байт и
19,6044 с сигнала; процесс передачи занял 19,6408497 с. Приём содержит
192 000 000 комплексных отсчётов, 384 000 000 байт и 24,0 с сигнала; процесс
приёма занял 24,0274813 с. Переполнения приёмника, опустошения передатчика,
ограничение АЦП и приближение к пределу отсутствуют.
До полного декодирования по фону до передачи зафиксировано правило первого
каскада Q99.9 локальных максимумов + 4 * MAD: Q99.9
0.023181289434432983, MAD 0.0025865877978503704, порог
0.033527640625834465. После начала декодирования порог не менялся. На
независимом фоне после передачи максимум равен 0.030997175723314285,
кандидатов выше порога нет. Исторический строгий порог
IQ_PREAMBLE_THRESHOLD = 0.65, Lab045, PHY и FEC не менялись.
Независимый приёмник обработал весь 24-секундный файл. Он не использовал
смещения и период кадров передатчика, ожидаемое число 68, пакеты, кодированные
биты или исходный объект. Первый каскад получил 295469 локальных максимумов и
35009 кандидатов. Строгий каскад обработал 95 неперекрывающихся гипотез:
PHY-заголовок PASS/FAIL 68/27, FEC attempts/PASS/FAIL 68/68/0, CRC
PASS/FAIL 68/0, действительных кадров 68. Поиск завершился по концу записи
и списка кандидатов, а не по достижении известного количества кадров.
ObjectAssembler принял 68 уникальных фрагментов. Дубликатов, конфликтующих
дубликатов и пропусков нет. Независимый вердикт: OBJECT COMPLETE = YES.
Восстановленный объект размером 16384 байта был записан до открытия опорных
данных передатчика. Только после этого выполнено сравнение: все 68 кадров
совпали с 68 переданными, пропущенных кадров и ложных CRC PASS нет. Ошибки до
FEC составили 787 кодированных бит, после FEC 0 протокольных бит. Ошибки
объекта равны 0 байт и 0 бит. SHA-256 исходного и восстановленного объектов:
b5a27caaa3f03dfc468e71a857a06f18cf0259ca6ea21d3c42ccfde7168d1dfe.
Для 68 принятых кадров SNR min/median/max равен
8.302870/8.909278/9.837726 дБ, ошибки преамбулы 0/3/9 из 1280, CFO
-0.214661/0.016493/0.281551 Гц. Медианный SNR по третям сеанса плавно
снижался 9.29 -> 8.86 -> 8.57 дБ, но все кадры прошли FEC и CRC. Ошибки
начала кадра находились в пределах от -4 до +3 отсчётов.
Фактические внешние артефакты сохранены в
C:\Users\user\Documents\SDR_Rover_Lab046_raw\20260902_151819_1400MHz_full.
Большие tx_stream.cs8, rx_stream.cs8, tx_object.bin и
recovered_object.bin в Git не добавляются. После результата оба CLKOUT
выключены, процессов hackrf_transfer нет. Независимая проверка сохранённых
JSON, размеров, SHA-256, временного покрытия и счётчиков расхождений не нашла.
Lab046C: подготовка аппаратного непрерывного объекта
Добавлен experiments/lab046c_hackrf_bpsk_object.py, который не меняет
протокол и только связывает готовые Lab043--Lab046B. Подготовительный режим
создаёт новый криптографически случайный объект 16384 байта вне Git, разбивает
его существующим Lab046 API на 68 фрагментов и последовательно записывает
68 полных Lab045 waveform в один tx_stream.cs8. Полные 313 670 400 байт не
удерживаются в ОЗУ одновременно; SHA-256 объекта и потока сохраняются в
tx_metadata.json.
24-секундный RX был запланирован как 192 000 000 complex cs8 samples,
384 000 000 байт. Такой capture даёт 0,75 с до передачи и около 3,65 с после
потока длительностью 19,6044 с. Приёмный API получает только путь к сырому
cs8 и PHY safety limits. Он читает файл через memmap окнами complex64, ищет
локальные PRBS7-кандидаты без обязательного global peak/second gate, получает
длину кадра из принятого PHY header и передаёт прошедшие CRC payload в
ObjectAssembler. TX start, границы 68 waveform, ожидаемое число фрагментов,
пакеты, coded bits и исходный объект приёмнику не передаются.
Аппаратный runner фиксирует доказанные serial и PHY-параметры, запускает RX
раньше TX, содержит один TransmitGuard.register_transmit() и cleanup в
finally. --preflight-only не регистрирует передачу и выполняет только
inventory/common-clock gate с последующим CLKOUT OFF. RF-режим требует два
отдельных CLI-ключа. После отдельной точной авторизации он был выполнен один
раз; повторный запуск не выполнялся и не разрешён.
Фактическая подготовка 1 сентября 2026 года создала внешний каталог
C:\Users\user\Documents\SDR_Rover_Lab046_raw\20260901_145339_bpsk_object:
tx_object.bin: 16384 байта, SHA-256f7568a5d1a6dc5dd907fa1e971a171578315de740bd6788136f447e409fc6bf8;tx_stream.cs8: 313670400 байт, 156835200 complex samples, 19,6044 с, SHA-2568941eb231f1f2f99cde51f3cc5426472dbedf1a61675543e7774faec4b935f5e;tx_metadata.json:LAB046C_PREPARATION_ONLY,rf_tx_count = 0.
Software gate подготовки: quick gate PASS с 482 тестами и 8 функциональными
лабами; полный pytest = 482 passed. Безопасный common-clock preflight также PASS:
MASTER reg29 0x26, SLAVE CLKIN DETECTED после 141,51 мс, SLAVE reg29
0x26; после проверки оба CLKOUT выключены, процессов hackrf_transfer нет,
RF TX = 0 на этапе подготовки.
Lab046C: первый аппаратный результат 1080 МГц, исторический RESULT C
Выполнен ровно один непрерывный RF TX всего tx_stream.cs8; автоматического
или ручного повтора не было. MASTER/TX
000000000000000097c063dc323b97d3, SLAVE/RX
000000000000000097c063dc2e5327d3, RF 1080 МГц, Fs 8 MS/s, BPSK 20 ксимв/с,
TX VGA 10 дБ, RX LNA/VGA 24/24 дБ, RF amp и bias OFF. Common clock прошёл
fail-closed gate: MASTER reg29 0x26, SLAVE CLKIN DETECTED, SLAVE reg29
0x26. Передача длилась 19,60632 с и полностью находилась внутри RX capture
длительностью 24,00386 с. USB-журналы чистые: TX underruns 0, RX overruns 0.
Независимый приёмник без TX oracle вернул официальный RESULT C:
PREAMBLE CANDIDATES = 0;VALID FRAMES = 0;PHY HEADER PASS = 0;CRC PASS = 0;OBJECT COMPLETE = NO;- восстановленный объект не создавался.
Рабочий порог PRBS7 оставался 0.65; максимальная независимая корреляция
равна 0.126562. Фоновая медиана мощности -34.467535 dBFS, кратковременный
максимум -34.307678 dBFS; максимальный средний подъём на интервале 19,6 с
всего 0.012049 dB. Обычный power/PSD-анализ не показывает заметной передачи.
После завершения и фиксации независимого RESULT C выполнена разрешённая
read-only диагностика с TX reference. Она обнаружила следы всех 68 waveform с
точным периодом 2 306 400 samples. Нормированная корреляция в выровненных
позициях: min 0.065784, median 0.089991, max 0.122379; контроль со
смещением: median 0.004275, max 0.010075. Медианное преимущество 26,46 дБ,
все 68 aligned значений выше максимума контроля.
Эта post-run диагностика использует знание TX только после официального
решения и не превращает опыт в PASS: OBJECT TRANSPORT PASS и
LAB046C COMPLETE SUCCESS не заявляются. TX-файл, его спектр около +50 кГц,
первый/средний/последний self-decode и runner проверены; дефекта формирования
или управления, объясняющего результат, не найдено. Сохранённый официальный
исход остаётся LAB046C HARDWARE RESULT = C, RF TX COUNT = 1,
OBJECT COMPLETE = NO.
Lab046C: автономная слабосигнальная обработка исходного RX capture
После аппаратного RESULT C реализован отдельный offline-модуль
experiments/lab046c_offline_recovery.py. Lab045 и строгий многокадровый
порог Lab046B IQ_PREAMBLE_THRESHOLD = 0.65 не изменялись. Новый режим не
содержит HackRF-команд и читает только ранее сохранённый rx_stream.cs8 через
np.memmap.
Первый каскад был зафиксирован до полного прогона по калибровочному фону
0.0--0.5 s: порог равен 99,9-му процентилю локальных PRBS7-максимумов.
Получено threshold = 0.025011632591485977, correlation median
0.00838765874505043, MAD 0.003039387986063957, 5193 локальных максимума,
6 кандидатов, 12.0 candidates/s. После фиксации правило проверено на
отдельном контрольном фоне 21.0--24.0 s и больше не менялось: 35501 локальный
максимум, 301 кандидат, 100.333333 candidates/s. Временные границы TX
использовались только для выбора участков, где передачи заведомо не было, и не
передавались поиску кадров.
Выполнен ровно один независимый полный offline-прогон 192 000 000 samples без
tx_stream.cs8, tx_object.bin, TX offsets, ожидаемого числа 68, fragment
order, packets или coded bits. Первый каскад насчитал 291446 локальных
максимумов и 3025 кандидатов выше порога. Все 3025 прошли refinement, timing и
оценку carrier/CFO/phase, но все 3025 были отвергнуты как
PHY_HEADER_MAGIC_MISMATCH. PHY HEADER PASS = 0, FEC ATTEMPTS = 0,
CRC PASS = 0, VALID FRAMES = 0, VALID FRAGMENTS = 0,
OBJECT COMPLETE = NO. recovered_object.bin не создавался.
Только после завершённого independent verdict была открыта TX reference.
Диагностика показала, что каждый из 68 настоящих стартов имел first-stage
кандидат в пределах +-40 samples; корреляция на этих кандидатах
min/median/max 0.059379209/0.088661019/0.126557365, то есть все они были выше
зафиксированного порога. FALSE CRC PASS = 0, но совпавших independently valid
frames также 0, пропущены все 68 TX frames. На известных только post-verdict
позициях локальная физическая экстракция прошла для 68/68, однако ошибки
min/median/max составили 341/430/554 из 1280 бит преамбулы и 30/54/81 из
144 бит PHY header. Оценочный SNR min/median/max
-19.282130/-12.829480/-9.195846 dB; все заголовки дали MAGIC_MISMATCH.
Следовательно, новый first-stage detector обнаружил слабые следы, но качество
демодуляции оказалось недостаточным даже для защищённого PHY header.
Производительность: calibration 0.269617 s, control 1.031204 s, coarse
search 7.721316 s, strict candidate processing 836.340048 s, в среднем
0.276476 s/candidate, полный прогон 845.427589 s. Capture длительностью
24 s обработан за 35.226150 его длительности. RX остаётся memmap; самый
большой coarse complex64 block содержит 16 000 000 samples (128 000 000
байт), консервативная оценка временных массивов SciPy 1 545 705 764 байта.
Максимальное strict local window: 594400 samples, 4 755 200 байт. Полный
192M-sample complex64 массив не создавался.
Артефакты результата находятся в
data/processed/lab046c_offline_recovery/: independent_result.json,
post_verdict_diagnostics.json, tx_reference_stage_diagnostics.json.
Правильная итоговая формулировка: ORIGINAL LAB046C HARDWARE RESULT = C;
OFFLINE REPROCESSING OF ORIGINAL RX CAPTURE = FAIL; OBJECT RECOVERED = NO;
ORIGINAL HARDWARE RESULT CHANGED = NO. Второй независимый прогон с новым
порогом не выполнялся.
Финальный software gate после результата: python tools/quick_gate.py PASS,
506 проверок и 9 функциональных лабораторий; python -m pytest tests/ -q =
506 passed. Единственное предупреждение связано с недоступным .pytest_cache
и не является отказом. git diff --check чист, кроме информационных LF/CRLF
notices.
Назначение
Lab046 переходит от одиночной 256-байтной полезной нагрузки к передаче произвольного бинарного объекта последовательностью независимо защищённых радиокадров. Два уровня строго разделены и не смешиваются:
- Уровень 1 (внутри одного кадра) — Lab045. Свёрточный код R=1/2 K=7, перемежитель, мягкий декодер Витерби, CRC пакета. Исправляет неизвестные битовые ошибки внутри принятого кадра.
- Уровень 2 (большой объект) — существующий
protocol/image_fragments. Фрагментация, нумерация фрагментов, идентификатор объекта, сборка. Собирает объект из нескольких независимо принятых кадров.
Новый код в experiments/lab046_bpsk_object_transport.py минимален: он
связывает два готовых уровня и добавляет fail-closed сборщик объекта.
Отдельный модуль формата фрагмента НЕ создавался: переиспользован 12-байтовый
заголовок image_fragments (>IHHI: object_id u32, fragment_index u16,
fragment_count u16, original_size u32).
Аудит: что переиспользовано, чего не хватало, минимальный новый слой
- Переиспользовано.
protocol/image_fragmentsуже даёт нужную семантику фрагмента: идентификатор объекта, индекс, число фрагментов, общий размер, а также fail-closedreassemble_image(несовпадение id/count/size, конфликтующие дубликаты, недостающие фрагменты, финальная проверка длины). Слой Lab045 даёт кадр целиком:build_transmission_plan,analyze_post_preamble_soft,simulate_soft_channel, диагностику pre/post-FEC. - Чего не хватало. Не было (а) упаковки фрагмента в 256-байтную нагрузку
Lab045 с обрезкой добивки на приёме по длине из заголовка и (б) сборщика,
который принимает по одному независимо декодированному кадру и никогда не
бросает на плохом входе, возвращая
object_complete = Falseвместо фиктивного объекта. - Минимальный новый слой.
recover_fragment_from_payload(fail-closed декод + обрезка добивки) и классObjectAssembler(offer/missing/complete/ recovered). Erasure-код 12+3 GF(256) (protocol/packet_erasure_fec) НЕ использован и НЕ изменён — он остаётся будущим расширением для потери целых фрагментов, а не для битовых ошибок (это работа свёрточного кода).
После этого Lab046A закрыла оставшийся пробел: до неё Lab046 передавала каждый
кадр отдельным вызовом и выбирала его из TX-плана по известному индексу. Функции
поиска нескольких кадров в одном потоке не было. Теперь
scan_continuous_soft_stream получает только один массив soft-символов,
самостоятельно ищет PRBS7 после монотонного cursor, проверяет защищённый PHY
header, вычисляет длину coded body из принятого packet length, выполняет готовые
FEC/CRC Lab045 и передаёт принятый fragment в ObjectAssembler.
TX offsets, список длин кадров, ожидаемое число 68, порядок/индексы TX,
исходный объект, TX packets и coded bits scanner-у не передаются. TX-side
frame_starts остаётся только в генераторе потока и используется тестом для
сравнения уже после независимого receive.
Граница доказательства Lab046A
Lab046A работает на уровне одного непрерывного нормализованного soft BPSK
stream (float32). Это разрешённый интерфейс после уже проверенного в Lab045
sample-level front-end: PRBS7 detection, matched filtering, timing, CFO и
phase/polarity recovery. Внутри нового длинного теста эти sample-level операции
заново не моделируются для каждого кадра. Поэтому результат доказывает
самостоятельный поиск границ, header-driven длину, FEC/CRC и сборку объекта в
непрерывном soft stream, но не является аппаратной или непрерывной IQ-проверкой.
Каждый фрагмент содержит полный активный Lab045 PHY frame: 1280 бит PRBS7, 144 бита защищённого header и 4300 coded bits. Точная полная sample-level форма с guard и хвостом ФРК учитывается как 2 306 400 отсчётов на кадр, однако все 156 835 200 IQ-отсчётов одновременно в памяти не создаются. Это намеренное ограничение памяти, а не использование известных границ приёмником.
Scanner fail-closed:
- cursor всегда растёт, после принятого кадра переносится за вычисленный конец;
- все PRBS7 candidates выше порога рассматриваются в порядке stream; после принятого кадра cursor переносится за вычисленный конец и не даёт декодировать этот кадр повторно;
- плохой header, усечённое body, ошибка FEC/CRC отвергают candidate, но поиск следующего продолжается;
MAX_FRAMESиMAX_SEARCH_ITERATIONSдают явную причину остановки, а не частичный объект, объявленный полным;- scan продолжается до конца capture и не останавливается на числе 68.
Сценарии continuous stream
| Сценарий | Получено |
|---|---|
| Идеальный, кадры подряд | candidates 68, valid headers 68, FEC PASS 68, CRC PASS 68/68, fragments 68, complete=True, SHA совпал, 0 байт-ошибок |
| Фон до/между/после | 37/37/43 soft-символа, valid frames 68, complete=True, SHA совпал |
| Непрерывный AWGN, sigma=0.40, seed=46001 | frames 68, pre-FEC 1791, post-FEC 0, CRC 68/0, complete=True, SHA совпал |
| Valid-looking preamble + bad protected header | candidates 71, rejected 3, последующие valid frames 68, complete=True, SHA совпал |
Фон между кадрами добавлен только после кадров 7, 23 и 51: 11, 19 и 7 soft-символов, всего 37. В baseline дополнительного inter-frame gap нет. Отдельный тест с валидным header для 12-байтного packet и повреждённым body проверяет, что scanner берёт длину именно из принятого header, отвергает этот candidate и затем находит настоящий кадр.
Verifier нашёл опасный вариант прежнего глобального non-maximum suppression: более сильный ложный PRBS7 peak мог удалить более поздний настоящий старт кадра. Поэтому suppression убран из списка кандидатов, а добавленный регрессионный тест проверяет, что ложный peak не скрывает настоящий кадр.
Lab046B: непрерывный сырой IQ-поток
Lab046B закрывает только программный sample-level пробел Lab046A. Новый
experiments/lab046b_continuous_iq.py формирует пять полных Lab045 waveform с
PRBS7, защищённым PHY header, interleaved convolutional body, BPSK, RRC и
guards, размещает их в одном complex64 массиве и передаёт scanner-у только
этот массив. TX start offsets, длины TX waveform, номера кадров, payload,
packet и coded bits в scan_continuous_iq не передаются.
Переиспользованы существующие функции Lab043-Lab045: BPSK/RRC waveform,
PRBS7 reference, normalized sliding correlation, локальное уточнение sample
start, matched filter, preamble-only timing, non-data-aided CFO и комплексный
gain, normalized.real, защищённый PHY header, deinterleave, soft Viterbi и
protocol CRC. Новый слой только перечисляет локальные IQ-кандидаты, вызывает
этот тракт на окне кандидата и монотонно продолжает поиск.
Глобальное требование «главный пик значительно выше второго» не используется.
В идеальном пятикадровом опыте peak/second для настоящих кадров лежит около
0 dB, поскольку вторым пиком является другой настоящий кадр; тем не менее все
пять кадров приняты. Все локальные максимумы выше порога сохраняются, а после
CRC PASS cursor переносится за вычисленный по принятому header конец кадра.
После плохого кандидата cursor также строго растёт, но следующий кандидат не
скрывается. Выход ограничен MAX_FRAMES и MAX_SEARCH_ITERATIONS.
Фактические сценарии Lab046B
| Сценарий | Получено |
|---|---|
| Идеальный continuous IQ | PRBS7 candidates 32, processed 5, accepted 5, rejected 0, PHY/FEC/CRC 5/5/5, CRC FAIL 0, sample offset error 0 для всех |
| CFO + phase + amplitude | внесено 0.2 Hz / 0.7 rad / 0.65; медианная оценка 0.200003768 Hz / 0.699634288 rad; CRC 5/0 |
| Комплексный AWGN | sigma=0.17, seed=46002; accepted 5, pre-FEC 0, post-FEC 0, CRC 5/0 |
| PRBS7 + неверный PHY header перед настоящим кадром | candidates 11, processed 8, rejected 7, следующий настоящий кадр найден, CRC 1/0 |
Начало первого waveform: sample 137, то есть не sample 0 и не граница сетки 400 samples/symbol. Дополнительные gaps: 211/353/587/809 samples. Найденные фазы символьной выборки: 137/348/301/88/97 samples modulo 400. Точные TX offsets используются только постфактум после CRC PASS; ошибки обнаруженного start во всех пяти случаях равны нулю.
Шумовая точка зафиксирована честно. Первый разумный однокадровый запуск при sigma=0.12 дал CRC PASS, но 0 pre-FEC ошибок. Выполнена одна разрешённая обоснованная корректировка до sigma=0.17; она также дала 0 pre-FEC ошибок и CRC PASS. Дальнейший подбор не выполнялся. Поэтому этот сценарий доказывает устойчивый многокадровый IQ receive с комплексным детерминированным шумом, но не является новым доказательством реального исправления ошибок FEC; такое доказательство уже относится к аппаратной Lab045.
Основной массив содержит 11 534 330 complex64 отсчётов и занимает
92 274 640 байт (88.0 MiB). Пять waveform занимают 11 532 000 samples, остальное
— leading/gaps/trailing. Полные CFO/phase-corrected копии не создаются:
первичный поиск работает с decimated stream, а matched filtering и soft
extraction выполняются на локальном окне одного кандидата. Это размер именно
основного IQ-массива, а не peak RSS процесса: RRC/FFT, локальный matched stream
и временные массивы SciPy требуют дополнительную рабочую память.
Память continuous stream
Основной 68-кадровый soft stream содержит 389 232 значения float32 и занимает
1 556 928 байт (1,485 MiB). Массив correlation scores занимает 1 551 812 байт,
накопленная энергия float64 — 3 113 864 байта. FFT и denominator создают
временное рабочее пространство, размер которого зависит от SciPy, но стратегия
остается в пределах десятков MiB, а не нескольких GiB. Для сравнения, один
материализованный continuous complex64 IQ stream из 156 835 200 отсчётов
занял бы около 1,17 GiB ещё до временных копий.
Детерминированный объект
- Размер 16384 байта (16 KiB). Это не JPEG, а воспроизводимый
псевдослучайный поток
numpy.random.default_rng(seed).integers(0,256,...). - Выбор размера. 16 KiB — компромисс: достаточно велик, чтобы кадров было много (68) и учёт фрагментации/сборки был содержательным, но достаточно мал, чтобы программный прогон 68 кадров с мягким Витерби считался секунды. Ровный размер (не кратный 244) специально оставляет короткий последний фрагмент.
- Seed объекта по умолчанию
46, идентификатор объекта0x4C303436(«L046»). - SHA-256 объекта по умолчанию:
748013b5f670c82bd52650be5454555355dbd8528538753df4558f1c3408d515. - Объект не сохраняется в Git (крупный генерируемый артефакт); при необходимости он детерминированно восстанавливается по seed.
Раскладка нагрузки пакета
Полезная нагрузка Lab045 остаётся 256 байт (доказанная рабочая точка):
[12 байт метаданных фрагмента][244 байта данных фрагмента]
FRAGMENT_DATA_SIZE = 256 − 12 = 244. Последний фрагмент короче; его нагрузка
добивается нулями до 256 байт перед Lab045 и обрезается на приёме по длине,
вычисленной только из полей заголовка (expected_fragment_data_length).
Для 16384 байт последний, 68-й фрагмент несёт 36 байт данных (16384 − 67·244).
Fail-closed сборка (без оракула)
Приёмник независим: переданный объект и TX-биты не используются ни для приёма пакета, ни для FEC, ни для восстановления метаданных, ни для решения о завершении объекта. Сравнение с оригиналом делается только в диагностике, после независимого CRC-решения и независимой сборки.
ObjectAssembler.offer(fragment) возвращает accepted/duplicate/conflicting/ rejected и никогда не бросает. Отвергаются: чужой object_id, несогласованные
count/original_size, невозможный индекс, конфликтующий дубликат (тот же индекс,
другие данные), malformed/усечённые метаданные. Идентичный дубликат
игнорируется. Пока не собраны все индексы, object_complete() = False, а
recovered_object() = None — фиктивный объект не создаётся. Поле original_size
проверяется на обе границы ((count−1)·244 < original_size ≤ count·244), чтобы
абсурдное значение не управляло размером аллокаций.
Программные сценарии (seed фиксирован)
| Сценарий | Условие | Ожидалось | Получено |
|---|---|---|---|
| A. Идеальный канал | шума нет | объект точен | complete=True, sha совпал, 0 байт-ошибок, CRC 68/0 |
| B. Распределённые битовые ошибки | гауссов шум sigma=0.40 | pre-FEC>0, post-FEC=0, все CRC PASS, объект точен | pre-FEC 1805, post-FEC 0, CRC 68/0, complete=True, sha совпал |
| C. Приём не по порядку | обратный порядок кадров | объект точен | complete=True, sha совпал |
| D. Дубликаты фрагментов | повтор кадров 0,2,2 | объект точен, дубликаты учтены | duplicates≥1, complete=True, sha совпал |
| E. Один потерянный фрагмент | кадр 1 не дошёл | OBJECT COMPLETE = NO | complete=False, 1 в missing, recovered SHA = None |
| F. Повреждённый пакет | инверсия coded-потока кадра 0 | CRC FAIL, объекта нет | crc_fail≥1, complete=False, recovered SHA = None |
Сценарий B — честная точка: уровень sigma выбран так, чтобы мягкий Витерби исправлял все 68 кадров (при sigma=0.45+ отдельный кадр не декодируется, и без erasure-FEC объект оказывается неполным — это по сути сценарий E, а не подгон). Числа не подкручивались ради прохождения: до FEC присутствуют 1805 реальных ошибок кодированных бит, после мягкого Витерби — ноль, объект побитово точен.
Метрики (объект 16384 байта, идеальный канал)
| Величина | Значение |
|---|---|
| Размер объекта | 16384 байта |
| SHA-256 объекта | 748013b5…3408d515 |
| Размер метаданных фрагмента | 12 байт/пакет |
| Размер данных фрагмента | 244 байта (последний 36) |
| Число фрагментов | 68 |
| Размер протокольного пакета | 268 байт (256 нагрузка + 8 header + 4 CRC) |
| Число BPSK-кадров | 68 |
| Всего информационных BPSK-символов | 389 232 (5724 × 68) |
| Всего отсчётов формы сигнала | 156 835 200 (2 306 400 × 68) |
| Baseline: дополнительный inter-frame gap | 0 отсчётов |
| Baseline: полная длительность | 19,604400 с |
| Baseline: полезный goodput | 835,7 байт/с = 6,685846 кбит/с |
| Фоновый тест: leading/inter-frame/trailing | 14 800 / 14 800 / 17 200 отсчётов |
| Фоновый тест: полная длина и длительность | 156 882 000 отсчётов, 19,610250 с |
| Фоновый тест: фактический goodput | 6,683852 кбит/с |
| Полезных бит на символ | ≈ 0,337 |
Учёт кадра совпадает с Lab045: 2144 информационных бита, 6 tail-бит, 4300
кодированных бит (R=1/2), перемежитель 4300, PHY header 48→144 бит (×3),
преамбула PRBS7 1280 бит, итого 5724 информационных символа кадра. Форма
сигнала добавляет 42 символо-времени (32 нулевых guard + 10 хвост ФРК,
shape_frame_like_lab042, режим full): 5766 символо-времён = 2 306 400
отсчётов = 288,3 мс на кадр при 8 MS/s.
Разбор накладных расходов
- Фрагментация (уровень 2): 12 байт метаданных на пакет × 68 = 816 байт.
- Протокольный header+CRC (уровень 1): 12 байт на пакет × 68 = 816 байт.
- Свёрточный код R=1/2: удваивает число кодированных бит (2144→4300 с tail).
- PHY преамбула и защищённый header: 1280 + 144 = 1424 бита на кадр.
- Guard/фильтр: 42 символо-времени на кадр (32 guard + 10 хвост ФРК).
- Добивка последнего фрагмента: 208 нулевых байт (только 68-й кадр).
Goodput 6,69 кбит/с — это честная baseline при 20 ксимв/с с полной преамбулой и guard на каждый кадр; в реальной серии кадров преамбула на кадр доминирует в накладных расходах, и это направление для будущей оптимизации, а не дефект.
Фактические программные результаты
- Новый набор
tests/test_lab046_bpsk_object_transport.py: все проверки проходят (фрагмент туда-обратно, короткий последний фрагмент, чужой object_id, невозможный индекс, несогласованный счётчик, усечённые и абсурдные метаданные без крупной аллокации, полный тракт PHY для сценариев A–F, отсутствие оракула, последовательный continuous scan, rejected candidate, MAX_FRAMES/MAX_SEARCH_ITERATIONS, регрессия против удаления настоящего кадра ложным PRBS7 peak, детерминизм и SHA объекта). - Полный тракт
объект → фрагменты → кадр Lab045 → канал → приём → сборкапроверен для всех шести сценариев значениями выше.
Software gate Lab046B на момент его фиксации
python tools/quick_gate.py: PASS; 468 тестов ядра, 7 функциональных проверок лабораторий выполнено, 13 штатно пропущено.python -m pytest tests/ -q: 468 passed, 0 failed, 0 errors, 0 skipped. Единственное предупреждение связано с отсутствием прав на создание.pytest_cache; на выполнение и результат тестов оно не повлияло.git diff --check: чист.
Актуальный общий gate после добавления Lab046C указан в начале документа.
Ограничения и следующий шаг
Для Lab046A/B RF TX = 0. Первый полный аппаратный Lab046C на 1080 МГц сохранён как исторический RESULT C. Новый полный аппаратный Lab046C на 1400 МГц завершён как RESULT A: 68/68 кадров, объект 16384 байта восстановлен без ошибок. Erasure-код 12+3 GF(256) не задействован, Lab045, PHY и FEC не менялись. Следующий этап определяется отдельной постановкой. Новый RF-сеанс, JPEG, видео, QPSK и переход к другой FEC автоматически не разрешены.