245 lines
16 KiB
Markdown
245 lines
16 KiB
Markdown
# Lab047: аппаратная передача и восстановление одного JPEG
|
||
|
||
## Состояние
|
||
|
||
Программная подготовка и единственный разрешённый аппаратный сеанс завершены.
|
||
Первоначальный независимый приём остался незавершённым из-за вычислительного
|
||
ограничения `MAX_CANDIDATES_REACHED`, до PHY/FEC/CRC он не дошёл. Это
|
||
историческое состояние сохранено и не переименовано в успешный приём.
|
||
|
||
После исправления только порядка обработки кандидатов выполнен ровно один
|
||
полный автономный повторный анализ исходной RX-записи без нового RF. Он собрал
|
||
JPEG полностью; последующая диагностическая сверка подтвердила точное
|
||
совпадение с переданным файлом. На этапе повторной обработки `RF TX = 0`,
|
||
HackRF не запускался.
|
||
|
||
## Аудит транспорта
|
||
|
||
Существующий транспорт Lab046 принимает произвольный непустой двоичный объект.
|
||
Размер 16384 байта был параметром Lab046C, а не ограничением протокола.
|
||
Число фрагментов вычисляется из фактического размера объекта, длина последнего
|
||
фрагмента восстанавливается из его собственных метаданных.
|
||
|
||
JPEG поэтому передаётся как обычная последовательность байтов. Изменения в
|
||
`protocol/`, Lab045, FEC и физическом уровне не потребовались и не выполнялись.
|
||
|
||
## Демонстрационный JPEG
|
||
|
||
Выбрана существующая настоящая фотография
|
||
`data/raw/lab011_scene.jpg`: поле, грунтовая дорога и деревья. Исходный файл не
|
||
изменялся. Подготовка полностью фиксирована:
|
||
|
||
- цветовой режим RGB;
|
||
- размер 320 x 240 пикселей;
|
||
- фильтр уменьшения LANCZOS;
|
||
- JPEG quality 35;
|
||
- цветовая субдискретизация 4:2:0;
|
||
- `optimize = false`;
|
||
- `progressive = false`.
|
||
|
||
Полученный файл `data/processed/lab047/tx_image.jpg` имеет 8724 байта,
|
||
формат JPEG, режим RGB, размер 320 x 240 и SHA-256
|
||
`e913dab9ac32795250880a4be67fbbbf89a4f96536842476ab591d1acaafc02a`.
|
||
Pillow полностью читает файл и не обнаруживает усечения.
|
||
|
||
## Программный сквозной проход
|
||
|
||
Выполнена цепочка:
|
||
|
||
`tx_image.jpg -> bytes -> Lab046 fragmentation -> Lab045 FEC/BPSK ->`
|
||
`идеальный канал -> PHY/FEC/CRC -> ObjectAssembler -> recovered_image.jpg`.
|
||
|
||
Фактический результат:
|
||
|
||
- фрагментов: 36;
|
||
- защищённых BPSK-кадров: 36;
|
||
- CRC PASS / FAIL: 36 / 0;
|
||
- действительных фрагментов: 36;
|
||
- пропущенных фрагментов: 0;
|
||
- `OBJECT COMPLETE = YES`;
|
||
- SHA-256 восстановленного файла:
|
||
`e913dab9ac32795250880a4be67fbbbf89a4f96536842476ab591d1acaafc02a`;
|
||
- `SHA MATCH = YES`;
|
||
- ошибочных байтов: 0;
|
||
- ошибочных битов: 0;
|
||
- Pillow распознаёт восстановленный файл как JPEG 320 x 240 RGB;
|
||
- `IMAGE DECODE = PASS`.
|
||
|
||
## Учёт будущего радиопотока
|
||
|
||
Каждый полный кадр Lab045 содержит 2 306 400 комплексных отсчётов. Для
|
||
фактических 8724 байт JPEG рассчитано:
|
||
|
||
- число отсчётов TX: 83 030 400;
|
||
- размер будущего `tx_stream.cs8`: 166 060 800 байт;
|
||
- расчётная длительность TX: 10,3788 с;
|
||
- полезная скорость по данным JPEG: 6724,48 бит/с;
|
||
- плановая длительность RX: 15,0 с;
|
||
- объём RX: 120 000 000 комплексных отсчётов, 240 000 000 байт;
|
||
- упреждение запуска RX: 0,75 с.
|
||
|
||
Большие `tx_stream.cs8`, `rx_stream.cs8` и сырые IQ в Git не создавались и не
|
||
добавлялись.
|
||
|
||
## Подготовленный аппаратный запуск
|
||
|
||
`experiments/lab047_jpeg_object_transport.py` содержит отдельные режимы для
|
||
формирования будущего TX-потока без RF, одного аппаратного захвата и одного
|
||
независимого полного анализа. Аппаратный режим требует одновременно три явных
|
||
ключа командной строки и обязательный новый признак разрешения внутри функции.
|
||
До попытки создаётся одноразовый файл-свидетель; автоматического повтора нет.
|
||
|
||
Параметры будущего опыта зафиксированы:
|
||
|
||
- MASTER/TX: `000000000000000097c063dc323b97d3`;
|
||
- SLAVE/RX: `000000000000000097c063dc2e5327d3`;
|
||
- центральная частота: 1 400 000 000 Гц;
|
||
- частота дискретизации: 8 МГц;
|
||
- BPSK: 20 ксимв/с, 400 отсчётов на символ;
|
||
- цифровое смещение несущей: +50 кГц;
|
||
- TX VGA: 10 дБ;
|
||
- RX LNA/VGA: 24/24 дБ;
|
||
- RF amplifier и Bias-Tee: выключены на обоих устройствах;
|
||
- общий генератор: TCXO 10 МГц -> MASTER -> CLKOUT -> SLAVE CLKIN;
|
||
- ожидаемый регистр 29 обоих устройств после проверки: `0x26`.
|
||
|
||
## Независимое обнаружение
|
||
|
||
Для каждой новой записи первый порог вычисляется заново только по фону до TX:
|
||
|
||
`threshold = Q99.9 локальных максимумов + 4 x MAD локальных максимумов`.
|
||
|
||
Интервал калибровки равен 0,0-0,5 с записи, затем порог фиксируется до полного
|
||
декодирования. Независимый контрольный фон расположен в интервале 12,0-15,0 с.
|
||
Строгий каскад остаётся прежним:
|
||
|
||
`точная синхронизация -> CFO -> фаза -> PHY header -> FEC -> CRC`.
|
||
|
||
Кадр принимается только при `CRC PASS`. Исторический
|
||
`IQ_PREAMBLE_THRESHOLD = 0.65` не изменён. Интерфейс независимого приёмника
|
||
получает только путь к RX-записи и выходной каталог. Он не получает смещения
|
||
TX, ожидаемое число кадров, индексы фрагментов передатчика, исходный JPEG,
|
||
пакеты или кодированные биты. Сравнение с TX-файлом вынесено в отдельную
|
||
функцию, которая открывается только после сохранённого полного независимого
|
||
вердикта.
|
||
|
||
## Единственный аппаратный сеанс
|
||
|
||
3 сентября 2026 года выполнен один непрерывный RF TX без повторов. Частота
|
||
равна 1400 МГц, фактическая длительность TX — 10,38030 с. RX продолжался
|
||
15,00875 с и сохранил 120000000 комплексных отсчётов, или 240000000 байт.
|
||
RX overruns 0, TX underruns 0. Проверка общего опорного генератора прошла.
|
||
Повторная передача не выполнялась: `RF TX COUNT = 1` за аппаратный сеанс и
|
||
`RF TX = 0` на этапе автономной обработки.
|
||
|
||
По фону до передачи до декодирования зафиксированы:
|
||
|
||
- Q99.9 локальных максимумов: `0.020810436457395554`;
|
||
- MAD локальных максимумов: `0.002538509201258421`;
|
||
- порог `Q99.9 + 4 * MAD`: `0.030964473262429237`.
|
||
|
||
На независимом контрольном фоне после передачи maximum равен
|
||
`0.026494961231946945`, кандидатов 0. Порог после аппаратного результата и
|
||
при повторной обработке не менялся.
|
||
|
||
Первоначальный приём остановился после 71113 локальных максимумов и заполнения
|
||
промежуточного списка из 10000 кандидатов. Сработало
|
||
`MAX_CANDIDATES_REACHED`; строгая ступень не запускалась. Поэтому сохранённый
|
||
исторический результат сформулирован точно:
|
||
`ORIGINAL HARDWARE RECEIVE = INCOMPLETE DUE TO MAX_CANDIDATES_REACHED`, а не
|
||
PHY FAIL, FEC FAIL, CRC FAIL или отказ передачи JPEG.
|
||
|
||
## Потоковая обработка кандидатов
|
||
|
||
В `lab046c_offline_recovery.py` устранено предварительное накопление всех
|
||
кандидатов. Блоки IQ и локальные максимумы идут по возрастанию смещения, а
|
||
каждый кандидат сразу передаётся строгой ступени. Защитный предел сохранён и
|
||
теперь ограничивает число фактически выполненных строгих проверок; его
|
||
значение 100000 не зависит от числа кадров JPEG.
|
||
|
||
После принятого по CRC кадра позиция перескакивает за принадлежащую ему область.
|
||
После плохого кандидата она продвигается на один отсчёт, поэтому близкий
|
||
настоящий кадр не скрывается. Точный повтор одного смещения подавляется;
|
||
произвольного радиуса подавления и глобального отношения первого пика ко
|
||
второму нет. Перекрытия блоков имеют однозначное владение и не породили
|
||
дубликатов.
|
||
|
||
Для списка кандидатов измерено около 108 байт на запись; при потоковой
|
||
обработке пиковый объём такого списка составил 49588 байт. Основной временный
|
||
объём определяет обработка блока IQ: приблизительно 1545755352 байта
|
||
(около 1,44 ГиБ).
|
||
|
||
## Автономный результат исходной RX-записи
|
||
|
||
После программного шлюза выполнен ровно один полный независимый проход всей
|
||
15-секундной записи. Передаточные смещения, период кадров, ожидаемое число
|
||
кадров, номера фрагментов, исходный JPEG, пакеты и кодированные биты не
|
||
использовались. Получено:
|
||
|
||
- всего локальных максимумов: 185828;
|
||
- кандидатов первого каскада: 32414;
|
||
- строгих проверок: 69;
|
||
- кандидатов, пропущенных как принадлежащие уже принятому локальному событию:
|
||
32345;
|
||
- точных дубликатов на перекрытиях: 0;
|
||
- PHY-заголовок PASS/FAIL: `36/33`;
|
||
- FEC attempts/PASS/FAIL: `36/36/0`;
|
||
- CRC PASS/FAIL: `36/0`;
|
||
- действительных кадров и фрагментов: `36/36`;
|
||
- отсутствующих фрагментов: 0;
|
||
- `OBJECT COMPLETE = YES`.
|
||
|
||
Все восемь блоков оценки были исчерпаны, защитные пределы не сработали. Полное
|
||
время равно 37,42391 с, из них строгая ступень заняла 32,459969 с; среднее
|
||
время одной строгой проверки — 0,470434 с. Первоначально поле `completed`
|
||
осталось ложным из-за отдельной ошибки учёта границы: последнее допустимое
|
||
начало корреляции было принято за конец обработанной области IQ. Исходный JSON
|
||
результата не изменён, полный поиск не повторяли. В отдельном исправленном JSON
|
||
после проверки исчерпания всех восьми блоков граница изменена с 119471220 на
|
||
120000000 и `completed` на `true`; порог не менялся,
|
||
`full_decoder_rerun = false`.
|
||
|
||
Только после сохранения завершённого независимого вердикта открыты опорные
|
||
данные передатчика. Совпали 36 из 36 кадров, пропущено 0, ложных CRC PASS 0.
|
||
До FEC обнаружено 19 ошибок кодированных бит, после FEC — 0 ошибок
|
||
протокольных бит. В независимый результат кадры не добавлялись.
|
||
|
||
Восстановленный `recovered_image.jpg` имеет 8724 байта. Его SHA-256 и SHA-256
|
||
переданного файла одинаковы:
|
||
`e913dab9ac32795250880a4be67fbbbf89a4f96536842476ab591d1acaafc02a`.
|
||
Ошибочных байтов 0, ошибочных битов 0. Pillow полностью декодирует JPEG как
|
||
изображение RGB 320 x 240. Итог:
|
||
`LAB047 OFFLINE RECOVERY OF HARDWARE CAPTURE = PASS`; единственный RF-сеанс
|
||
фактически передал JPEG успешно, а первоначальную обработку остановил
|
||
вычислительный предел.
|
||
|
||
## Артефакты
|
||
|
||
- `data/processed/lab047/tx_image.jpg`;
|
||
- `data/processed/lab047/recovered_image.jpg`;
|
||
- `data/processed/lab047/result.json`;
|
||
- `data/processed/lab047/result.txt`.
|
||
|
||
Большая RX-запись и результаты аппаратного сеанса оставлены вне Git в
|
||
`C:\Users\user\Documents\SDR_Rover_Lab047_raw\20260903_115747`. Исходный
|
||
`independent_reprocess_result.json` сохранён неизменным; исправление только
|
||
признака полного покрытия находится в
|
||
`independent_reprocess_result_corrected.json`, а разрешённая послерезультатная
|
||
сверка — в `post_verdict_diagnostics.json`.
|
||
|
||
## Проверки
|
||
|
||
- `python tools/quick_gate.py`: PASS, 540 проверок pytest и 10 быстрых
|
||
функциональных проверок лабораторных;
|
||
- `python -m pytest tests/ -q`: 540 passed, 0 failed;
|
||
- `git diff --check`: PASS.
|
||
|
||
Предупреждение pytest о невозможности создать служебный `.pytest_cache` не
|
||
относится к тестам и не изменило код возврата.
|
||
|
||
## Следующий этап
|
||
|
||
STOP. Разрешение на единственный аппаратный процесс Lab047 израсходовано.
|
||
Новый RF, повтор передачи, изменение порога, PHY, FEC, CRC или Lab045 без
|
||
отдельной новой постановки не выполнять. `RF TX = 0`; HackRF не запускать.
|