Complete VIDEO-001 through VIDEO-004 software video studies
This commit is contained in:
143
docs/video/SECOND_COMPUTER_SETUP.md
Normal file
143
docs/video/SECOND_COMPUTER_SETUP.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# VIDEO-001: подготовка второго компьютера
|
||||
|
||||
16 сентября 2026 года. Это ведомость и инструкция для будущей программной
|
||||
установки приёмника. Второй ноутбук не подключали, USB-плату не открывали,
|
||||
драйверы и прошивки не меняли. `RF TX = 0`.
|
||||
|
||||
## Что проверено на основном ПК
|
||||
|
||||
| Компонент | Фактическое состояние |
|
||||
|---|---|
|
||||
| ОС и Python | Windows NT 10.0.19045, 64 бита; CPython 3.13.1 x64, `C:\Users\user\AppData\Local\Programs\Python\Python313\python.exe`. |
|
||||
| Приёмник сохранённого IQ | NumPy 2.2.6, SciPy 1.18.0, Pillow 12.0.0, Numba 0.61.2, llvmlite 0.44.0. Numba/llvmlite сейчас доступны из `C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages`. Это локальная добавка к Python, не переносимая среда. |
|
||||
| Сравнение видеокодеков | OpenCV 4.12.0.88, PyAV 16.0.1, psutil 6.1.0; `libx264` открыт через PyAV. Доступны FFmpeg `libavcodec 62.11.100`, `libavformat 62.3.100`, `libavutil 60.8.100`. Отдельные команды `ffmpeg`/`ffprobe` в PATH не найдены. |
|
||||
| Базовые пакеты | matplotlib 3.11.1, pytest 9.1.1. Проверенные версии для VIDEO-001 записаны в `requirements-video.txt`; они точнее фактического `opencv-python==4.12.0` в старом `requirements.txt`. |
|
||||
| HackRF host tools | Conda-метаданные: `hackrf 2024.02.1`, `libhackrf0 2024.02.1`. Проект указывает `C:\Users\user\Tools\HackRF\Library\bin\hackrf_transfer.exe`; рядом есть `hackrf_info.exe`, `hackrf_clock.exe`, `hackrf-0.dll`. Файлы `hackrf_transfer.exe` и `hackrf-0.dll` побайтно совпадают с экземплярами в `C:\Users\user\radioconda\Library\bin`. В этом задании утилиты не запускались, фактическое устройство заново не опрашивалось. |
|
||||
| Конфигурация радио | Код Lab066: BPSK 500 ксимв/с, Fs 8 Мвыб/с, 16 выборок/символ, пауза 5 мс, общая опора 10 МГц. Это сохранённая точка предыдущего опыта, а не команда к новому запуску. |
|
||||
|
||||
## Разделение ролей
|
||||
|
||||
**Основной ПК, будущий передатчик.** Здесь остаются исходное видео, подготовка
|
||||
JPEG и сигналов (`lab047_jpeg_object_transport.py`, `lab045_hackrf_bpsk_fec.py`,
|
||||
`lab049_bpsk_symbol_rate.py`), TX HackRF и его параметры. Рабочего отправителя
|
||||
непрерывного H.264 пока нет. Программный `tools/video_compare.py` кодирует
|
||||
ролик в файл и не формирует радиопакеты.
|
||||
|
||||
**Ноутбук, будущий приёмник.** На первом этапе можно проверить импорт модулей,
|
||||
тесты и, при наличии отдельно переданного сохранённого IQ, повтор Lab053.
|
||||
`tools/video_iq_replay.py` читает файл, а не USB. Готового адаптера «USB HackRF
|
||||
на ноутбуке → непрерывные IQ-блоки → экран» нет. Процесс на основном ПК не может
|
||||
непосредственно открыть USB-плату ноутбука.
|
||||
|
||||
Для программного сравнения на ноутбуке достаточно `tools/video_compare.py`,
|
||||
`requirements-video.txt` и одного разрешённого к копированию MP4. Для проверки
|
||||
приёмника без копирования всего архива нужен следующий замкнутый набор исходных
|
||||
модулей из ветки `video-development` (статический граф локальных импортов
|
||||
`lab053_pipeline`/`ImageSink`/`lab053_streaming_receiver`; 38 файлов):
|
||||
|
||||
```text
|
||||
protocol/bit_interleaver.py
|
||||
protocol/bpsk_carrier_tracking.py
|
||||
protocol/bpsk_radio.py
|
||||
protocol/control_messages.py
|
||||
protocol/convolutional_fec.py
|
||||
protocol/image_fragments.py
|
||||
protocol/link_packet.py
|
||||
protocol/packet.py
|
||||
protocol/priority_scheduler.py
|
||||
protocol/video_age_policy.py
|
||||
protocol/video_frame_scheduler.py
|
||||
experiments/lab042_pluto_image_loopback.py
|
||||
experiments/lab043_bpsk_asymmetry_diagnostics.py
|
||||
experiments/lab043_hackrf_bpsk.py
|
||||
experiments/lab043_hackrf_hardware.py
|
||||
experiments/lab043_pluto_to_rtlsdr.py
|
||||
experiments/lab043_prbs11_hardware.py
|
||||
experiments/lab044_hackrf_bpsk_packet.py
|
||||
experiments/lab045_hackrf_bpsk_fec.py
|
||||
experiments/lab046_bpsk_object_transport.py
|
||||
experiments/lab046b_continuous_iq.py
|
||||
experiments/lab046c_hackrf_bpsk_object.py
|
||||
experiments/lab046c_offline_recovery.py
|
||||
experiments/lab047_jpeg_object_transport.py
|
||||
experiments/lab049_bpsk_symbol_rate.py
|
||||
experiments/lab049_independent_iq.py
|
||||
experiments/lab050_streaming_receiver.py
|
||||
experiments/lab050_video_stream.py
|
||||
experiments/lab051_receiver_performance.py
|
||||
experiments/lab051_receiver_profile.py
|
||||
experiments/lab051_streaming_receiver.py
|
||||
experiments/lab052_candidate_detection.py
|
||||
experiments/lab052_detector_study.py
|
||||
experiments/lab053_packet_processing.py
|
||||
experiments/lab053_pipeline.py
|
||||
experiments/lab053_receiver_profile.py
|
||||
experiments/lab053_streaming_receiver.py
|
||||
experiments/lab053_viterbi.py
|
||||
```
|
||||
|
||||
Сохранить каталоговую структуру и `tools/video_iq_replay.py`. Перечень
|
||||
проверен импортом этих 38 модулей из отдельного временного каталога с
|
||||
изолированным путём Python: `IMPORT_OK`. Он показывает зависимость нынешнего
|
||||
кода от старых лабораторных модулей;
|
||||
он не означает, что аппаратные функции будут вызваны при импорте. Это пока
|
||||
слишком широкая зависимость для удобной установки, поэтому перед живым RX
|
||||
полезно выделить минимальный приёмный пакет отдельной программной задачей.
|
||||
`data/raw` и `data/processed` целиком переносить не нужно.
|
||||
|
||||
## Порядок программного развёртывания
|
||||
|
||||
1. Выяснить ОС и разрядность ноутбука, доступную оперативную память, Python,
|
||||
модель и serial подключаемой именно к нему HackRF, тип USB-порта/контроллера
|
||||
и физический путь общей опоры 10 МГц. До этого драйвер не выбирать.
|
||||
2. В новом каталоге ноутбука разместить только перечисленный исходный код,
|
||||
`requirements-video.txt`, `tools/video_iq_replay.py` и нужные тесты. Не
|
||||
переносить всю Conda-среду, пользовательские настройки, ключи или архив IQ.
|
||||
3. Создать чистое окружение Python 3.13.1 и установить зафиксированные пакеты:
|
||||
|
||||
```powershell
|
||||
py -3.13 -m venv .venv
|
||||
.\.venv\Scripts\python.exe -m pip install -r requirements-video.txt
|
||||
.\.venv\Scripts\python.exe -c "import av; print(av.codec.Codec('libx264', 'w').name)"
|
||||
```
|
||||
|
||||
Если пакет отсутствует или установка не прошла, записать `NOT_RUN` и текст
|
||||
ошибки. Не выдавать отсутствие зависимости за `PASS`.
|
||||
4. Проверить импорт программного RX и быстрые тесты без устройства. Для
|
||||
сравнения кодеков передать только согласованный MP4. Основной опыт VIDEO-001
|
||||
использует [видео Udacity с движением камеры и автомобилей](https://github.com/udacity/CarND-Vehicle-Detection/blob/master/project_video.mp4):
|
||||
`udacity_project_video.mp4`, 25 268 015 байт, SHA-256
|
||||
`651949922042c223375d40bf8929def97dbb62c6ade651d1f5b08eea47127d5f`.
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe -c "from experiments.lab053_streaming_receiver import StreamingReceiver; from experiments.lab051_receiver_performance import ImageSink; print('IMPORT_OK')"
|
||||
.\.venv\Scripts\python.exe -B -m pytest tests\test_video_001_compare.py -q -p no:cacheprovider --basetemp video001_pytest_tmp
|
||||
```
|
||||
5. Полный повтор IQ выполнять лишь когда 386 842 624-байтный файл действительно
|
||||
нужен для оценки скорости ноутбука. Его нельзя молча включать в пакет
|
||||
переноса. Сверку эталонных JPEG держать после вердикта приёмника:
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe -B tools\video_iq_replay.py --source <путь_к_source.c64> --fixture-json <путь_к_source_fixture.json> --numba-packages .venv\Lib\site-packages --output <новый_результат.json>
|
||||
```
|
||||
|
||||
Ожидаемый размер файла 386 842 624 байта и записанный SHA-256
|
||||
`9b4f5469b21985f796a77e22981f93bcd3b7a203b573349e8bdf7ea55891bea0`
|
||||
проверяются до сравнения.
|
||||
Замер на основном ПК приведён в `VIDEO_001.md`; скорость ноутбука **NOT_RUN**.
|
||||
|
||||
## Граница аппаратного этапа
|
||||
|
||||
Драйвер и расположение `libhackrf` на ноутбуке выбираются после определения его
|
||||
ОС и оборудования; автоматической установки здесь нет. Прошивку HackRF Plus
|
||||
не менять. Первый будущий аппаратный порядок: общая опора 10 МГц включена и
|
||||
проверена на обеих платах → приёмник ноутбука готов и подтверждён → отдельное
|
||||
прямое разрешение на TX. Проверка независимых генераторов вне VIDEO-001.
|
||||
Частоту, усиления, антенны и роль устройств по старому скрипту автоматически
|
||||
не переносить. При ошибке приёма или счётчиках потерь сеанс останавливают;
|
||||
повторную передачу отдельно согласуют.
|
||||
|
||||
**NOT_RUN:** развёртывание на втором ноутбуке, проверка его USB и драйвера,
|
||||
приём вживую, непрерывный экран, передача и восстановление H.264 по радио.
|
||||
Подготовлен воспроизводимый программный пакет и перечень сведений, которых
|
||||
не хватает для конкретной установки.
|
||||
252
docs/video/VIDEO_001.md
Normal file
252
docs/video/VIDEO_001.md
Normal file
@@ -0,0 +1,252 @@
|
||||
# VIDEO-001: программный предел видеотракта
|
||||
|
||||
16 сентября 2026 года. Ветка `video-development`, исходный HEAD `af7c05f`.
|
||||
`RF TX = 0`. SDR, камеры и экран не запускались. Основной `main`, старые результаты
|
||||
и исходные IQ не менялись. Таблицы ниже относятся к этому компьютеру и одному
|
||||
ролику; они не доказывают работу живого видео через радио.
|
||||
|
||||
## Что уже работает
|
||||
|
||||
| Узел | Файл и назначение | Зависимости и измеренное состояние |
|
||||
|---|---|---|
|
||||
| Подготовка JPEG | `experiments/lab047_jpeg_object_transport.py`, `experiments/lab050_video_stream.py`: уменьшение, RGB, JPEG | Pillow; Lab047: 320×240 q35, 8724 байта. Lab050: 128×96 q25, 1740–1893 байта на искусственных сдвигах фотографии. |
|
||||
| Кодирование видео | `experiments/lab026_video_bitrate_benchmark.py` и `protocol/video_packet.py`: исследование сжатия и отдельный формат BASE/ROI | Это не подключённый к Lab045/Lab053 H.264 видеотракт. В VIDEO-001 добавлен автономный измеритель `tools/video_compare.py`, PyAV/libx264. |
|
||||
| Фрагменты объекта | `experiments/lab046_bpsk_object_transport.py`, `protocol/image_fragments.py` | 12 байт метаданных и 244 байта JPEG на пакет. Сборка требует все фрагменты; отдельного замера CPU только для фрагментации нет. |
|
||||
| Сигнал | `experiments/lab045_hackrf_bpsk_fec.py`, `experiments/lab049_bpsk_symbol_rate.py` | BPSK, свёрточный код 1/2, RRC; один пакет при 500 ксимв/с занимает 11,532 мс до паузы. Видео с H.264 в генератор не подаётся. |
|
||||
| Приём потока | `experiments/lab053_streaming_receiver.py`, `experiments/lab053_pipeline.py` | NumPy, SciPy, Numba. Lab053: программный источник 6,044416 с, 240/240 CRC-пакетов, 30/30 JPEG, 5 свежих изображений/с в стенде. Камеры и экрана там нет. |
|
||||
| Сборка и показ | `ImageSink` в `experiments/lab051_receiver_performance.py`; модель показа в `lab050_video_stream.py` | В Lab053 на 30 изображений сборка заняла 5,967 мс, JPEG decode 5,977 мс суммарно. Физический экран не реализован и не измерен. |
|
||||
|
||||
**MEASURED:** Lab047 передала по эфиру один JPEG 8724 байта за 10,3788 с на
|
||||
20 ксимв/с. Первоначальный независимый приём остановился по вычислительному
|
||||
пределу; повторный анализ той же RX-записи после сеанса восстановил 36/36
|
||||
фрагментов и точный JPEG. Lab050–052 сначала не достигали реального времени:
|
||||
например, Lab050 обработала 0,323745 с IQ за 55,157553 с при 500 ксимв/с.
|
||||
Lab053 ускорила только программный конвейер: измеренные 5 кадров/с относятся к
|
||||
заданному файлу IQ, не к аппаратному видео. Ориентир 5 кадров/с для полной
|
||||
системы остаётся непроверенным.
|
||||
|
||||
**MEASURED:** Lab066 выполнила один аппаратно валидный сеанс 500 ксимв/с с
|
||||
16 пакетами по 256 байт и 5 мс между ними. Строгие legacy и T2 получили
|
||||
10/16 точных пакетов, шесть остановились на PHY-заголовке. Lab067 связала эти
|
||||
отказы с локальным качеством принятого сигнала и не нашла основания для малой
|
||||
правки приёмника. 10/16 не считается постоянной вероятностью доставки.
|
||||
|
||||
## Радиобюджет
|
||||
|
||||
**CALCULATED по генератору Lab045/Lab066:** 256 байт нагрузки содержат 12 байт
|
||||
заголовка фрагмента и 244 байта изображения. Пакет протокола имеет ещё 8 байт
|
||||
заголовка и 4 байта CRC, всего 268 байт. Код 1/2 с шестью хвостовыми битами
|
||||
даёт `(268×8+6)×2 = 4300` кодированных бит. Преамбула PRBS7 занимает
|
||||
1280 символов, троекратный PHY-заголовок 144, вместе с кодированным телом это
|
||||
5724 BPSK-символа. Две защитные области и хвост RRC добавляют 42 интервала:
|
||||
5766 интервалов, 92 256 IQ-отсчётов и 11,532 мс на пакет при 500 ксимв/с.
|
||||
|
||||
| Условие | Полезная скорость JPEG, бит/с | Смысл |
|
||||
|---|---:|---|
|
||||
| Без потерь и пауз | 169 268 | `244×8 / 0,011532`; верхняя граница формата. |
|
||||
| Без потерь, с паузой 5 мс после пакета | 118 074 | `244×8 / 0,016532`; около 60,49 пакета/с. |
|
||||
| Один сеанс Lab066, 10 принятых пакетов, с двумя 100-мс защитными интервалами | 42 480 | `10×244×8 / 0,459512`; видеоэквивалент, потому что Lab066 передавала не JPEG. Не измерение длительной видеодоставки. |
|
||||
|
||||
При 5/10/15 кадрах/с без потерь и с паузой помещаются соответственно не более
|
||||
12/6/4 целых пакетов за период кадра: 2928/1464/976 байт изображения. Это
|
||||
только длительность эфира; опорный H.264 кадр и потери могут заполнить очередь.
|
||||
Текущий формат и сборщик понимают JPEG, поэтому H.264 требует отдельного
|
||||
видеотранспорта. Его оценка в таблицах учитывает `ceil(размер/244)` пакетов на
|
||||
кадр, но не означает готовую передачу H.264.
|
||||
|
||||
**MEASURED, сохранённый IQ Lab053:** 386 842 624 байта complex64 равны
|
||||
6,044416 с при 8 Мвыб/с. Новый `tools/video_iq_replay.py` читает их блоками,
|
||||
вызывает штатный независимый PHY/FEC/CRC-приёмник и сборщик, без графиков,
|
||||
истории по блокам и сверки с TX во время замера. Первый проход: JIT-разогрев
|
||||
0,496044 с, затем 4,099045 с обработки, или 1,475 с IQ/с обработки.
|
||||
Повторный проход: разогрев 0,000135 с, обработка 4,238388 с, или 1,426.
|
||||
Оба дали 240/240 пакетов и 30/30 точных JPEG. Первый и повторный проходы не
|
||||
образуют статистической гарантии для другого ноутбука, а профиль всё ещё
|
||||
содержит внутренние счётчики приёмника.
|
||||
|
||||
## Программное сравнение кодеков
|
||||
|
||||
**MEASURED:** один исходный файл `data/raw/video001/udacity_project_video.mp4`,
|
||||
взятый из [открытого проекта Udacity по обнаружению автомобилей](https://github.com/udacity/CarND-Vehicle-Detection/blob/master/project_video.mp4).
|
||||
Размер 25 268 015 байт, SHA-256
|
||||
`651949922042c223375d40bf8929def97dbb62c6ade651d1f5b08eea47127d5f`;
|
||||
1280×720, 25 кадров/с, 50,4 с. Это реальная съёмка с движущегося автомобиля.
|
||||
В окне 7–13 с белая машина проходит справа, в окне 33–39 с появляются и
|
||||
меняют положение чёрная и белая машины. В обоих окнах исходные выбранные кадры
|
||||
различались. При изменении разрешения пропорции сохранены чёрными полями.
|
||||
Предыдущая проба на пустой дороге сохранена отдельно в
|
||||
`data/processed/video001/camera_only/` и не входит в таблицу ниже.
|
||||
|
||||
JPEG повторяет профиль проекта: q35, 4:2:0, независимые кадры. H.264 использует
|
||||
PyAV 16.0.1 и доступный `libx264` из FFmpeg: `preset=veryfast`, `tune=zerolatency`,
|
||||
без B-кадров и lookahead, один поток кодировщика, закрытый GOP с опорным кадром раз в секунду,
|
||||
`crf=28`, VBV maxrate/buffer 160 или 320 кбит/с. Есть отдельные пробы с 40 кбит/с.
|
||||
Настройка maxrate не считается фактическим битрейтом: ниже приведены размеры
|
||||
полученных пакетов. Время кодирования и декодирования не включает чтение MP4.
|
||||
Отдельный `end_to_end_file_pipeline_latency_s` измерен прямым проходом: чтение
|
||||
очередного кадра MP4 с пропуском промежуточных, изменение размера, кодирование,
|
||||
декодирование и получение RGB. Открытие файла, эфир, очередь показа и экран в
|
||||
него не входят. Пик за 1 с рассчитан скользящим окном из `fps` кадров.
|
||||
|
||||
В таблице для каждого режима взято большее из двух окон значение среднего
|
||||
и пикового потока, а также большее среднее время обработки кадра. Единицы:
|
||||
кбит/с и мс/кадр. `FITS` сопоставляет пакетную пиковую нагрузку с 21,76
|
||||
принятого пакета/с в одном сеансе Lab066. Для всех строк это `НЕТ`; длительный
|
||||
рабочий предел радио остаётся **NOT_RUN**. По контрольным кадрам оценены
|
||||
различимость машин и полос, направление и потеря деталей. Мелких препятствий
|
||||
в этих двух участках нет; проверка с оператором ровера **NOT_RUN**.
|
||||
|
||||
| Разрешение | FPS | Кодек | Средний поток | Пик 1 с | Кодирование | Декодирование | Качество для оператора | FITS CURRENT RADIO BUDGET |
|
||||
|---|---:|---|---:|---:|---:|---:|---|---|
|
||||
| 320×240 | 5 | JPEG q35 | 245 | 280 | 0,6 | 0,5 | Ближние машины и полоса видны; дальние предметы мелки | НЕТ |
|
||||
| 320×240 | 5 | H.264 160k | 117 | 172 | 1,2 | 0,3 | Ближние машины и направление видны; мелкие детали ограничены | НЕТ |
|
||||
| 320×240 | 5 | H.264 320k | 117 | 172 | 1,2 | 0,3 | Почти тот же вид, что при 160k | НЕТ |
|
||||
| 320×240 | 10 | JPEG q35 | 491 | 563 | 0,3 | 0,4 | Ближние машины и полоса видны; дальние предметы мелки | НЕТ |
|
||||
| 320×240 | 10 | H.264 160k | 140 | 213 | 1,0 | 0,2 | Ближние машины и направление видны; мелкие детали ограничены | НЕТ |
|
||||
| 320×240 | 10 | H.264 320k | 140 | 213 | 1,0 | 0,2 | Почти тот же вид, что при 160k | НЕТ |
|
||||
| 320×240 | 15 | JPEG q35 | 738 | 850 | 0,2 | 0,3 | Ближние машины и полоса видны; дальние предметы мелки | НЕТ |
|
||||
| 320×240 | 15 | H.264 160k | 151 | 238 | 0,9 | 0,2 | Ближние машины и направление видны; мелкие детали ограничены | НЕТ |
|
||||
| 320×240 | 15 | H.264 320k | 151 | 238 | 0,9 | 0,2 | Почти тот же вид, что при 160k | НЕТ |
|
||||
| 640×360 | 5 | JPEG q35 | 580 | 726 | 0,8 | 1,7 | Машины и разметка видны; крупный поток | НЕТ |
|
||||
| 640×360 | 5 | H.264 160k | 174 | 230 | 3,2 | 0,7 | Машины видны; текстура дороги размыта при движении | НЕТ |
|
||||
| 640×360 | 5 | H.264 320k | 342 | 437 | 3,8 | 1,0 | Машины, полоса и направление различимы | НЕТ |
|
||||
| 640×360 | 10 | JPEG q35 | 1165 | 1470 | 0,6 | 0,8 | Машины и разметка видны; крупный поток | НЕТ |
|
||||
| 640×360 | 10 | H.264 160k | 178 | 250 | 2,5 | 0,5 | Машины видны; текстура дороги размыта при движении | НЕТ |
|
||||
| 640×360 | 10 | H.264 320k | 354 | 376 | 3,0 | 0,7 | Машины, полоса и направление различимы | НЕТ |
|
||||
| 640×360 | 15 | JPEG q35 | 1752 | 2226 | 0,6 | 1,3 | Машины и разметка видны; крупный поток | НЕТ |
|
||||
| 640×360 | 15 | H.264 160k | 180 | 250 | 2,3 | 0,4 | Машины видны; текстура дороги размыта при движении | НЕТ |
|
||||
| 640×360 | 15 | H.264 320k | 355 | 375 | 2,6 | 0,5 | Машины, полоса и направление различимы | НЕТ |
|
||||
| 640×480 | 5 | JPEG q35 | 699 | 841 | 1,3 | 1,4 | Машины видны; чёрные поля 60 пикселей | НЕТ |
|
||||
| 640×480 | 5 | H.264 160k | 171 | 221 | 3,7 | 0,7 | Машины видны; поля и размытие деталей | НЕТ |
|
||||
| 640×480 | 5 | H.264 320k | 347 | 412 | 4,1 | 1,0 | Машины видны; полезная область как 640×360 | НЕТ |
|
||||
| 640×480 | 10 | JPEG q35 | 1402 | 1701 | 1,0 | 1,4 | Машины видны; чёрные поля 60 пикселей | НЕТ |
|
||||
| 640×480 | 10 | H.264 160k | 178 | 252 | 2,9 | 0,5 | Машины видны; поля и размытие деталей | НЕТ |
|
||||
| 640×480 | 10 | H.264 320k | 355 | 381 | 3,3 | 0,7 | Машины видны; полезная область как 640×360 | НЕТ |
|
||||
| 854×480 | 5 | JPEG q35 | 911 | 1142 | 1,3 | 2,1 | Машины и разметка чётче; крупный поток | НЕТ |
|
||||
| 854×480 | 5 | H.264 160k | 172 | 223 | 5,2 | 0,8 | Ближние машины видны; дальние детали размыты | НЕТ |
|
||||
| 854×480 | 5 | H.264 320k | 347 | 378 | 6,3 | 1,3 | Машины, полосы и направление хорошо различимы | НЕТ |
|
||||
| 854×480 | 10 | JPEG q35 | 1828 | 2318 | 1,4 | 2,2 | Машины и разметка чётче; крупный поток | НЕТ |
|
||||
| 854×480 | 10 | H.264 160k | 179 | 265 | 4,3 | 0,6 | Ближние машины видны; дальние детали размыты | НЕТ |
|
||||
| 854×480 | 10 | H.264 320k | 357 | 456 | 5,1 | 0,8 | Машины, полосы и направление хорошо различимы | НЕТ |
|
||||
| 1280×720 | 5 | JPEG q35 | 1745 | 2247 | 2,7 | 4,9 | Машины и разметка подробны; поток велик | НЕТ |
|
||||
| 1280×720 | 5 | H.264 160k | 173 | 217 | 9,8 | 1,2 | Машины видны; разрешение не даёт ожидаемой детализации | НЕТ |
|
||||
| 1280×720 | 5 | H.264 320k | 346 | 441 | 11,5 | 1,7 | Машины и разметка видны; дальние надписи не проверены | НЕТ |
|
||||
|
||||
Полные размеры каждого кадра, включая опорные, фактическая скорость кодирования,
|
||||
оба замера задержки, RSS всего процесса, PSNR и число уникальных кадров сохранены
|
||||
в `data/processed/video001/comparison_traffic_160k.json` и
|
||||
`comparison_traffic_320k.json`. RSS в общем процессе достиг 240,9 МиБ в первом
|
||||
наборе и 241,7 МиБ во втором; это наблюдаемый пик при двух проходах на случай,
|
||||
не отдельная память кодека. В сценарии заранее загружены все выбранные кадры,
|
||||
поэтому RSS завышает память будущего поштучного видеотракта. У программных
|
||||
кандидатов максимальная задержка
|
||||
прямого файлового прохода составила 26,0 мс для HIGH QUALITY, 10,2 мс для
|
||||
NORMAL и 11,5 мс для ROBUST на этом ПК.
|
||||
Все 88 проходов этих двух наборов дали столько же уникальных декодированных
|
||||
кадров, сколько входных. Повторного кадра под новым номером не было в
|
||||
файловом декодировании; поведение экрана не проверено. Полученная частота
|
||||
кодирования выше заданной FPS на этом ПК, но это не частота доставки через радио.
|
||||
|
||||
**MEASURED, проверка малого потока:** при настройке 40 кбит/с фактический
|
||||
H.264 поток на `320×240 / 5` достигал 43,0 кбит/с в среднем и 56,0 кбит/с
|
||||
в худшую секунду; опорный кадр до 2709 байт. Ближние автомобили узнаваемы,
|
||||
но их края и дорожная текстура сильно размываются. На `640×360 / 10` получено
|
||||
44,8/67,6 кбит/с. Проверены все 11 сочетаний при 40 кбит/с, оба участка;
|
||||
во всех 44 проходах JPEG и H.264 число уникальных кадров равно входному.
|
||||
Даже наименьший пик среди всех этих проходов составил 29 пакетных мест за
|
||||
секунду, больше 21,76 принятого пакета/с в измеренном сеансе Lab066. Подробности:
|
||||
`comparison_traffic_40k.json`; пик RSS этого набора — 240,5 МиБ.
|
||||
|
||||
**MEASURED, потеря данных в файле:** в каждом H.264 проходе удаляли первый
|
||||
опорный пакет и, отдельно, первый промежуточный пакет. Точное совпадение с
|
||||
неповреждённым декодированием возвращалось на следующем опорном кадре через
|
||||
1 секунду исходного времени. Промежуточные изображения до него могут быть
|
||||
испорчены или отсутствовать. У независимого JPEG потеря одного изображения
|
||||
не мешает декодировать следующее. Это программная проба потери пакета кодека,
|
||||
а не проверка нашего радиопротокола или реального показа без зависаний.
|
||||
|
||||
## Выбор режимов и граница вывода
|
||||
|
||||
Три **кандидата для следующей программной работы**, выбранные после замеров:
|
||||
|
||||
| Назначение | Режим | Причина | Радио сейчас |
|
||||
|---|---|---|---|
|
||||
| HIGH QUALITY | 854×480, 10 кадров/с, H.264 320k | Машины и полосы различимы; 357 кбит/с средний, 456 кбит/с пик, кодирование 5,1 мс/кадр | НЕТ |
|
||||
| NORMAL | 640×360, 10 кадров/с, H.264 320k | Машины и направление различимы; 354/376 кбит/с, кодирование 3,0 мс/кадр | НЕТ |
|
||||
| ROBUST | 320×240, 5 кадров/с, H.264 160k | Ближние машины видны при меньшей нагрузке; 117/172 кбит/с, кодирование 1,2 мс/кадр | НЕТ |
|
||||
|
||||
Названия описывают исследуемые программные профили, а не пригодность для
|
||||
управления ровером. Вариант 40 кбит/с не выбран даже как ROBUST: потеря мелких
|
||||
деталей и всплеск пакетов слишком велики. Для будущего видеотранспорта нужны
|
||||
номер изображения, номер фрагмента, время создания и срок актуальности;
|
||||
ожидающая очередь не больше одного нового изображения, сброс просроченного,
|
||||
сброс зависимого H.264 потока после потери опорных данных до следующего IDR.
|
||||
Имеющиеся PHY, FEC, CRC, заголовки и модуляция не менялись.
|
||||
|
||||
Для `1280×720 / 5` H.264 320k потребовал 346 кбит/с в среднем, 441 кбит/с
|
||||
в худшую секунду и до 228 пакетных мест за секунду. Кодирование заняло в
|
||||
среднем до 11,5 мс/кадр, декодирование до 1,7 мс/кадр, прямой файловый путь
|
||||
до 32,0 мс для отдельного кадра; фактически кодировалось около 87 кадров/с.
|
||||
Текущие 5-мс паузы ограничивают эфир примерно 60,49 пакета/с без потерь.
|
||||
Крупнейший опорный кадр 12 593 байта требует 52 фрагмента и 0,860 с их
|
||||
сериализации; наибольший кадр вообще — 14 550 байт, 60 фрагментов и 0,992 с.
|
||||
Чтобы передать этот кадр в период 0,2 с, потребовалось бы не менее 300
|
||||
пакетов/с без учёта управления, ошибок и защитного запаса. JPEG q35 при
|
||||
том же режиме дал 1745/2247 кбит/с. Для 720p нужны иной радиобюджет или
|
||||
существенно меньшие кадры, а также ограничение пиков, потерь и срока
|
||||
актуальности; одной скорости кодировщика недостаточно.
|
||||
|
||||
## Очереди и наблюдаемые ограничения
|
||||
|
||||
В Lab053 очереди ограничены: 8 IQ-блоков, 4 строгих кандидата и 16 выходных
|
||||
пакетов. В программном стенде переполнений не было. У экспериментального
|
||||
`lab053_pipeline.py` растут списки истории блоков, пакетов и кадров: они нужны
|
||||
для отчёта, но не должны попадать в рабочий процесс ноутбука. Новый повтор
|
||||
IQ не собирает эту историю и не строит графики. Штатный приёмник всё же
|
||||
сохраняет внутренние счётчики и двойное IQ-кольцо; в Lab053 выделение кольца
|
||||
составило 6 797 824 байта. Это измеренная стоимость текущей реализации,
|
||||
а не основание менять PHY в VIDEO-001.
|
||||
|
||||
`ImageSink` держит один собираемый JPEG. Недостающие фрагменты старого
|
||||
изображения задерживают его завершение до появления следующего ID; в текущем
|
||||
формате нет времени создания и срока годности. Отдельной H.264 очереди ещё
|
||||
нет. В автономном сравнении создан один экземпляр libx264 на весь участок,
|
||||
не новый процесс на каждый кадр. Основные измеренные ограничения для 10/15
|
||||
кадров/с: пакетная и пиковая битовая нагрузка, потери Lab066, крупные опорные
|
||||
изображения и отсутствие транспорта с правилами свежести и восстановления.
|
||||
Одной достаточной скорости CPU-кодирования для решения этих вопросов мало.
|
||||
|
||||
**NOT_RUN:** независимые генераторы, передача H.264 или непрерывного видео по
|
||||
эфиру, живой USB-приём, камера, экран, операторская проверка препятствий,
|
||||
ноутбук и длительное подтверждение полезной скорости радиоканала. Следующая
|
||||
практическая задача: сделать программный видеотранспорт с ограничением очереди,
|
||||
дедлайном изображения и восстановлением по IDR, затем проверить его на
|
||||
сохранённом IQ без доступа к SDR.
|
||||
|
||||
**Проверки:** `video_validate_results.py` сверил 132 прохода в трёх наборах:
|
||||
матрицу режимов, SHA исходника, размеры кадров, поток, пакетные места,
|
||||
уникальность и восстановление. Целевые тесты VIDEO-001: 4 пройдены. Общие
|
||||
тесты: 1022 пройдены, один исторический тест исключён, поскольку в отдельном
|
||||
рабочем дереве нет исходного `data/raw/lab064/tx_metadata.json`. Полный
|
||||
`quick_gate.py` в этом дереве не завершён. На радио тесты не запускались.
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
Из ветки `video-development` после установки `requirements-video.txt`. Исходный
|
||||
ролик берётся по ссылке выше и сверяется с указанным SHA-256. Окна по умолчанию:
|
||||
7–13 и 33–39 с; для другого ролика доступны повторяемые параметры `--window`.
|
||||
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force data\raw\video001
|
||||
Invoke-WebRequest https://raw.githubusercontent.com/udacity/CarND-Vehicle-Detection/master/project_video.mp4 -OutFile data\raw\video001\udacity_project_video.mp4
|
||||
(Get-FileHash -Algorithm SHA256 data\raw\video001\udacity_project_video.mp4).Hash
|
||||
python -B tools/video_compare.py --source data\raw\video001\udacity_project_video.mp4 --output data\processed\video001\comparison_traffic_160k.json --h264-maxrate-bps 160000
|
||||
python -B tools/video_compare.py --source data\raw\video001\udacity_project_video.mp4 --output data\processed\video001\comparison_traffic_320k.json --h264-maxrate-bps 320000
|
||||
python -B tools/video_compare.py --source data\raw\video001\udacity_project_video.mp4 --output data\processed\video001\comparison_traffic_40k.json --h264-maxrate-bps 40000
|
||||
python -B tools/video_validate_results.py --source data\raw\video001\udacity_project_video.mp4 data\processed\video001\comparison_traffic_160k.json data\processed\video001\comparison_traffic_320k.json data\processed\video001\comparison_traffic_40k.json
|
||||
python -B tools/video_report_table.py --comparison-160k data\processed\video001\comparison_traffic_160k.json --comparison-320k data\processed\video001\comparison_traffic_320k.json --report docs\video\VIDEO_001.md
|
||||
python -B -m pytest tests\test_video_001_compare.py -q -p no:cacheprovider --basetemp data\processed\video001\pytest_temp_target
|
||||
```
|
||||
|
||||
Повтор IQ описан в `SECOND_COMPUTER_SETUP.md`; он требует сохранённый файл
|
||||
и исходную ведомость SHA только для послерезультатной сверки.
|
||||
209
docs/video/VIDEO_002.md
Normal file
209
docs/video/VIDEO_002.md
Normal file
@@ -0,0 +1,209 @@
|
||||
# VIDEO-002: транспорт H.264 и расчёт радиоканала
|
||||
|
||||
16 сентября 2026 года. Ветка `video-development`. Выполнен только программный прогон:
|
||||
`RF TX = 0`. Модуляция, FEC, PHY-заголовок, RRC и рабочий приёмник SDR не менялись.
|
||||
Коммит и отправка в удалённый репозиторий не выполнялись.
|
||||
|
||||
## Исходные данные и предел проверки
|
||||
|
||||
Тот же ролик и те же окна движения, что в [VIDEO-001](VIDEO_001.md):
|
||||
`data/raw/video001/udacity_project_video.mp4`, SHA-256
|
||||
`651949922042c223375d40bf8929def97dbb62c6ade651d1f5b08eea47127d5f`;
|
||||
белая машина на 7–13 с и чёрная на 33–39 с. Кодировщик PyAV/libx264 повторно
|
||||
создал пакеты H.264 с настройками VIDEO-001. Размер *каждого* кадра сверен с
|
||||
`comparison_traffic_160k.json` или `comparison_traffic_320k.json`.
|
||||
Исходные окна имеют по 6 с: 30 кадров ROBUST и 60 кадров NORMAL/HIGH QUALITY.
|
||||
Сырые видеоданные в Git не включены. Результат 198 прогонов находится в
|
||||
`data/processed/video002/results.json`; запуск:
|
||||
|
||||
```powershell
|
||||
python -m tools.video002_simulation
|
||||
python -m pytest tests/test_video002_transport.py tests/test_video002_codec.py -q -p no:cacheprovider
|
||||
```
|
||||
|
||||
Прогон моделирует длительность пакета и паузу, подаёт фрагменты на сборщик и
|
||||
декодирует полные кадры настоящим декодером H.264. Он **не моделирует** ошибки
|
||||
синхронизации, шум, вероятность CRC-успеха, работу независимого SDR-приёмника и
|
||||
время CPU для FEC. Контрольная программная линия `SOFTWARE_2MBPS` передаёт
|
||||
нагрузку 1024 байта за 4,096 мс без RF и нужна для отдельной проверки потерь.
|
||||
|
||||
## Формат и правило свежести
|
||||
|
||||
`protocol/video_stream_transport.py` добавляет 17-байтный заголовок *внутри*
|
||||
полезной нагрузки проверенного пакета. Он не заменяет штатные 8 байт заголовка
|
||||
`protocol.packet` и 4 байта CRC:
|
||||
|
||||
| Поле | Байты | Назначение |
|
||||
|---|---:|---|
|
||||
| Версия и тип кадра | 1 | Старшие 4 бита — версия 1; младшие — `KEYFRAME=1` или `DELTA_FRAME=2` |
|
||||
| `stream_id` | 4 | Выбор сеанса сборщика |
|
||||
| `frame_id` | 4 | Номер с последовательным сравнением и переходом через `2³²` |
|
||||
| `fragment_index`, `fragment_count` | 2 + 2 | Порядок и общее число, максимум 256 |
|
||||
| `age_ms` | 2 | Возраст кадра на расчётном конце передачи пакета |
|
||||
| `payload_length` | 2 | Проверяемая длина части H.264 |
|
||||
|
||||
При нагрузке PHY 256 байт остаётся 239 байт изображения; при 512 — 495, при
|
||||
1024 — 1007. На стороне передатчика очередь ограничена двумя кадрами и 300 мс:
|
||||
старый кадр сбрасывается даже после частичной отправки, если к округлённому
|
||||
моменту конца следующего пакета он станет просроченным. Сборщик держит максимум
|
||||
два незавершённых кадра,
|
||||
принимает части в произвольном порядке, проверяет длины и противоречивые дубликаты,
|
||||
не выдаёт неполный кадр и по истечении срока освобождает место. Потеря одного
|
||||
фрагмента не останавливает приём следующих кадров. Сборщик получает данные только
|
||||
после внешнего решения PHY/FEC/CRC; `stream_id` сам по себе не аутентифицирует
|
||||
отправителя. Номер последнего принятого к сборке кадра не позволяет старому
|
||||
пакету снова стать новым даже после вытеснения 1024 номеров из журнала закрытых
|
||||
кадров. После перезапуска нужен новый контекст сборщика/сеанса.
|
||||
|
||||
Декодер показывает кадр только один раз. После пропуска номера он ждёт полный
|
||||
опорный кадр и открывает новый контекст H.264. Это осторожное правило: некоторые
|
||||
P-кадры кодек мог бы восстановить и раньше, но подменять потерянные данные или
|
||||
показывать повреждённую картинку оператору здесь не разрешено. Показанные
|
||||
опорные кадры побайтно совпали по SHA-256 с чистым декодированием соответствующего
|
||||
окна, включая случаи восстановления после потери.
|
||||
|
||||
## Чистый прогон при возрасте не более 300 мс
|
||||
|
||||
Показаны результаты окон «белая / чёрная машина». Возраст — от захвата исходного
|
||||
кадра до завершения последнего пакета, без времени кодирования, декодирования и
|
||||
экрана. `drop` — сброс отправителем по возрасту / по переполнению. Все эти строки
|
||||
имеют **0% искусственных потерь пакетов**.
|
||||
|
||||
| Режим | Канал модели | Показано кадров | Возраст, среднее, мс | Макс. очередь | `drop` |
|
||||
|---|---|---:|---:|---:|---:|
|
||||
| ROBUST 320×240/5 | BPSK 256/5 мс | 0/30 · 0/30 | — | 2 | 6/0 · 9/0 |
|
||||
| NORMAL 640×360/10 | BPSK 256/5 мс | 0/60 · 0/60 | — | 2 | 2/58 · 2/57 |
|
||||
| HIGH QUALITY 854×480/10 | BPSK 256/5 мс | 0/60 · 0/60 | — | 2 | 2/58 · 2/58 |
|
||||
| ROBUST | QPSK 500k, 1024/0 мс, расчёт | 30/30 · 30/30 | 53,4 · 65,7 | 1 | 0/0 · 0/0 |
|
||||
| NORMAL | QPSK 500k, 1024/0 мс, расчёт | 0/60 · 20/60 | — · 115,8 | 2 | 0/6 · 0/4 |
|
||||
| HIGH QUALITY | QPSK 500k, 1024/0 мс, расчёт | 40/60 · 40/60 | 96,0 · 98,7 | 2 | 0/4 · 0/4 |
|
||||
| ROBUST | Программные 2 Мбит/с | 30/30 · 30/30 | 11,2 · 13,8 | 1 | 0/0 · 0/0 |
|
||||
| NORMAL | Программные 2 Мбит/с | 60/60 · 60/60 | 19,2 · 20,0 | 1 | 0/0 · 0/0 |
|
||||
| HIGH QUALITY | Программные 2 Мбит/с | 60/60 · 60/60 | 19,7 · 20,2 | 1 | 0/0 · 0/0 |
|
||||
|
||||
При нынешнем BPSK крупнейшие опорные кадры ROBUST занимают 397 и 479 мс
|
||||
(`ceil(размер/239) × (11,532+5)`), NORMAL — 926 и 975 мс, HIGH QUALITY — 909 и
|
||||
893 мс. Поэтому чистая модель с пределом 300 мс не декодирует их. Отказ
|
||||
NORMAL на расчётной QPSK в одном окне также показывает, что запас по среднему
|
||||
потоку нельзя считать гарантией прохождения опорных кадров.
|
||||
|
||||
## Потери пакетов и восстановление
|
||||
|
||||
Затравка генератора `20260916`; вероятность относится к *передаваемому пакету*.
|
||||
Ниже число показанных кадров на контрольной программной линии в окнах
|
||||
«белая / чёрная машина» из 30 или 60 исходных. `burst` удаляет первые 2/5/10
|
||||
пакетов потока. JSON содержит каждую из 198 комбинаций, в том числе те же
|
||||
потери на двух расчётных радиопрофилях, номера показанных кадров, потери кадров,
|
||||
время восстановления, возраст, глубину очереди и сбросы.
|
||||
|
||||
| Потеря | ROBUST | NORMAL | HIGH QUALITY |
|
||||
|---|---:|---:|---:|
|
||||
| Случайная 0% | 30/30 · 30/30 | 60/60 · 60/60 | 60/60 · 60/60 |
|
||||
| Случайная 1% | 30/30 · 30/30 | 55/60 · 51/60 | 48/60 · 47/60 |
|
||||
| Случайная 2% | 26/30 · 25/30 | 39/60 · 33/60 | 39/60 · 38/60 |
|
||||
| Случайная 5% | 21/30 · 19/30 | 6/60 · 5/60 | 18/60 · 27/60 |
|
||||
| Случайная 10% | 15/30 · 19/30 | 5/60 · 5/60 | 12/60 · 11/60 |
|
||||
| Случайная 20% | 0/30 · 0/30 | 0/60 · 0/60 | 0/60 · 0/60 |
|
||||
| `burst` 2/5/10 пакетов | 25/30 · 25/30 | 50/60 · 50/60 | 50/60 · 50/60 |
|
||||
|
||||
Отдельные сценарии с потерей первого фрагмента опорного кадра №5/10 и P-кадра
|
||||
№6/11 подтвердили восстановление на следующем полном опорном кадре №10/20.
|
||||
На программной линии после потери опорного кадра это заняло от 1025 до 1057 мс,
|
||||
после потери P-кадра — от 825 до 957 мс. Значения включают ожидание следующего
|
||||
GOP длиной 1 с и доставку его первого кадра. При случайной потере 20% ни один
|
||||
полный опорный кадр в этих коротких окнах не прошёл: время восстановления
|
||||
не определено. Скрытых повторов старого `frame_id` нет; число разных изображений
|
||||
и их SHA-256 записаны в результате.
|
||||
|
||||
## Расчёт радиопакета
|
||||
|
||||
Основа Lab045/VIDEO-001: 1280 символов преамбулы, 144 символа трёхкратного
|
||||
PHY-заголовка, 42 интервала защитных областей и RRC; `protocol.packet` добавляет
|
||||
12 байт (заголовок и CRC), свёрточный FEC 1/2 кодирует также 6 хвостовых бит.
|
||||
Для нагрузки PHY `P` байт тело содержит `2 × ((P+12) × 8 + 6)` кодовых бит.
|
||||
BPSK передаёт один бит на символ. Расчётная QPSK оставляет преамбулу и
|
||||
PHY-заголовок двоичными и передаёт тело по два бита на символ; такой смешанный
|
||||
пакет **не реализован и не проверен**. Все строки считают полный пакет даже для
|
||||
последнего неполного фрагмента, поэтому оценка задержки консервативна.
|
||||
Накладная доля — `1 − полезные биты изображения / (сырая скорость × период
|
||||
пакета с паузой)`; она включает паузу, служебные поля и FEC.
|
||||
|
||||
| Модуляция, ксимв/с | Сырая скорость, кбит/с | Символ, мкс | Оценка ширины при RRC 0,35, кГц |
|
||||
|---|---:|---:|---:|
|
||||
| BPSK 500 | 500 | 2 | 675 |
|
||||
| QPSK 250 | 500 | 4 | 337,5 |
|
||||
| QPSK 500 | 1000 | 2 | 675 |
|
||||
|
||||
В каждой ячейке ниже: **эфирное время пакета, мс / полезная скорость видео,
|
||||
кбит/с / накладная доля, %**. Пауза в заголовке столбца дана в миллисекундах.
|
||||
|
||||
| Модуляция | PHY, байт | 5 мс | 2 мс | 1 мс | 0 мс |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| BPSK 500 | 256 | 11,532 / 115,7 / 76,9 | 11,532 / 141,3 / 71,7 | 11,532 / 152,6 / 69,5 | 11,532 / 165,8 / 66,8 |
|
||||
| BPSK 500 | 512 | 19,724 / 160,2 / 68,0 | 19,724 / 182,3 / 63,5 | 19,724 / 191,1 / 61,8 | 19,724 / 200,8 / 59,8 |
|
||||
| BPSK 500 | 1024 | 36,108 / 196,0 / 60,8 | 36,108 / 211,4 / 57,7 | 36,108 / 217,1 / 56,6 | 36,108 / 223,1 / 55,4 |
|
||||
| QPSK 250 | 256 | 14,464 / 98,2 / 80,4 | 14,464 / 116,1 / 76,8 | 14,464 / 123,6 / 75,3 | 14,464 / 132,2 / 73,6 |
|
||||
| QPSK 250 | 512 | 22,656 / 143,2 / 71,4 | 22,656 / 160,6 / 67,9 | 22,656 / 167,4 / 66,5 | 22,656 / 174,8 / 65,0 |
|
||||
| QPSK 250 | 1024 | 39,040 / 182,9 / 63,4 | 39,040 / 196,3 / 60,7 | 39,040 / 201,2 / 59,8 | 39,040 / 206,4 / 58,7 |
|
||||
| QPSK 500 | 256 | 7,232 / 156,3 / 84,4 | 7,232 / 207,1 / 79,3 | 7,232 / 232,3 / 76,8 | 7,232 / 264,4 / 73,6 |
|
||||
| QPSK 500 | 512 | 11,328 / 242,5 / 75,7 | 11,328 / 297,1 / 70,3 | 11,328 / 321,2 / 67,9 | 11,328 / 349,6 / 65,0 |
|
||||
| QPSK 500 | 1024 | 19,520 / 328,5 / 67,1 | 19,520 / 374,3 / 62,6 | 19,520 / 392,6 / 60,7 | 19,520 / 412,7 / 58,7 |
|
||||
|
||||
Текущая конфигурация — первая ячейка: 115,7 кбит/с видео **при 100% доставке**.
|
||||
В VIDEO-001 фигурировали 118,1 кбит/с JPEG, поскольку его фрагментный
|
||||
заголовок занимает 12, а новый H.264 — 17 байт. Один сеанс Lab066 доставил
|
||||
10/16 пакетов; это наблюдение не является постоянной вероятностью доставки и
|
||||
не подставлено в расчёт. Предельный размер *всего* пакета PHY сейчас 1024 байта:
|
||||
нагрузка 1024 плюс 12 байт `protocol.packet` его превышает. Lab045 в действующем
|
||||
плане формирует нагрузку ровно 256 байт; строки 512/1024 потребуют разработки и
|
||||
проверки даже при арифметическом соблюдении размера. Уменьшение паузы также
|
||||
не проверялось через радио.
|
||||
|
||||
## Запас относительно реальных пиков VIDEO-001
|
||||
|
||||
Максимум односекундного видеопотока среди двух окон приведён в таблице.
|
||||
Здесь «запас 20%» определён как
|
||||
`полезная скорость ≥ пик × 1,2`, «запас 50%» — как `≥ пик × 1,5`.
|
||||
|
||||
| Режим | Пик, кбит/с | Нужно при 20%, кбит/с | Нужно при 50%, кбит/с | Вывод для предела 500 кбит/с |
|
||||
|---|---:|---:|---:|---|
|
||||
| ROBUST 320×240/5 | 171,7 | 206,0 | 257,5 | Оба запаса возможны только в ещё не проверенных вариантах |
|
||||
| NORMAL 640×360/10 | 375,8 | 451,0 | 563,7 | 20% да, 50% нет |
|
||||
| 640×480/10 | 380,9 | 457,1 | 571,4 | 20% да, 50% нет |
|
||||
| HIGH QUALITY 854×480/10 | 455,6 | 546,7 | 683,3 | Даже 20% нет |
|
||||
| 1280×720/5 | 440,6 | 528,8 | 661,0 | Даже 20% нет |
|
||||
|
||||
Из рассчитанных пакетов 20% запаса для ROBUST дают, например, BPSK
|
||||
500/1024/0 (223,1 кбит/с) или QPSK 500/256/0 (264,4 кбит/с); 50% — только
|
||||
некоторые QPSK 500. Все эти варианты требуют разработки и проверки. Максимум
|
||||
всей таблицы, QPSK 500/1024/0, равен 412,7 кбит/с и не покрывает 20% запас
|
||||
для NORMAL, 640×480, HIGH QUALITY или 1280×720. Сам инженерный диапазон
|
||||
400–500 кбит/с покрывает 20% лишь для NORMAL и 640×480 в своей верхней части.
|
||||
Расчёт не разрешает называть ни один из режимов прошедшим по текущему радиоканалу.
|
||||
|
||||
## Итог VIDEO-002
|
||||
|
||||
| Требуемое поле | Результат |
|
||||
|---|---|
|
||||
| `VIDEO TRANSPORT` | **PARTIAL**: формат, очередь, сборка и H.264 работают в программной модели; на текущем радиобюджете чистый 300-мс прогон не показывает кадров |
|
||||
| `BOUNDED QUEUE` | **YES**, максимум 2 кадра |
|
||||
| `STALE FRAME DROP` | **YES**, срок 300 мс, метрики в JSON |
|
||||
| `KEYFRAME RECOVERY` | На контрольной линии после потери IDR кадр №10/20, 1025–1057 мс; SHA-256 совпал с чистым декодированием |
|
||||
| `LOSS TESTS` | 0/1/2/5/10/20% и серии 2/5/10 пакетов, фиксированная затравка, два окна, три видеорежима, три канала модели |
|
||||
| `CURRENT PHY USEFUL RATE` | 115,7 кбит/с H.264 при 256 байтах, 5 мс, без потерь; измеренной устойчивой скорости H.264 нет |
|
||||
| `BEST BPSK PACKETIZATION CANDIDATE` | 1024 байта / 0 мс: расчёт 223,1 кбит/с, но полный пакет 1036 байт превышает действующий предел; среди допустимых по размеру 512/0 даёт 200,8 кбит/с |
|
||||
| `QPSK 250K CALCULATED RATE` | Максимум 206,4 кбит/с при 1024/0; пакет сверх действующего предела |
|
||||
| `QPSK 500K CALCULATED RATE` | Максимум 412,7 кбит/с при 1024/0; пакет сверх предела, пик NORMAL без 20% запаса |
|
||||
| `TARGET VIDEO RADIO BUDGET` | 400–500 кбит/с как инженерная цель, не достигнутый результат; для HIGH QUALITY с 20% требуется ≥546,7 кбит/с, для 1280×720/5 — ≥528,8 кбит/с |
|
||||
| `NEXT RF DEVELOPMENT CANDIDATE` | BPSK 500 ксимв/с, нагрузка 512 байт, пауза 0 мс: один конкретный следующий предмет отдельной разработки и *последующей* проверки независимого приёма. Теоретический предел 200,8 кбит/с, робастный пик с 20% запасом не покрыт. VIDEO-002 не разрешает RF TX |
|
||||
| `RF TX` | **0** |
|
||||
| `COMMIT` / `PUSH` | **NOT PERFORMED** / **NOT PERFORMED** |
|
||||
|
||||
Проверка после исправлений: 11 целевых тестов VIDEO-002 и 4 теста VIDEO-001
|
||||
прошли. Независимый проверяющий повторил все 198 симуляций и все 36 расчётных
|
||||
строк; результат совпал с сохранённым JSON. Общий `tools/quick_gate.py` в этом
|
||||
рабочем дереве не прошёл: у исторических аппаратных лабораторий нет
|
||||
`data/raw/lab064/tx_metadata.json` и других исходных файлов, а системный
|
||||
временный каталог pytest недоступен для части тестов. Целевые тесты запускались
|
||||
с `-p no:cacheprovider`; для тестов VIDEO-001 временный каталог pytest был
|
||||
явно направлен в это рабочее дерево. Никакая из этих проверок не запускала RF.
|
||||
294
docs/video/VIDEO_003.md
Normal file
294
docs/video/VIDEO_003.md
Normal file
@@ -0,0 +1,294 @@
|
||||
# VIDEO-003: видеокодек и радиоформат, программная проверка
|
||||
|
||||
16 сентября 2026 года. Worktree `SDR_Rover_Video`, ветка `video-development`,
|
||||
исходный HEAD `af7c05f`. Передача через эфир и обращения к SDR не выполнялись.
|
||||
Число 600 кбит/с здесь служит инженерной целью, а не условием зачёта работы.
|
||||
|
||||
## Что проверено
|
||||
|
||||
Результаты разделены по происхождению:
|
||||
|
||||
| Уровень | Смысл в этом отчёте |
|
||||
|---|---|
|
||||
| `CALCULATED MAXIMUM` | Арифметика формата PHY, кода, преамбулы, защитных интервалов и паузы при нулевых потерях. |
|
||||
| `IMPLEMENTED` | Действующий генератор Lab045 формирует пакет с нагрузкой `protocol.packet` ровно 256 байт, BPSK 500 ксимв/с, FEC 1/2. VIDEO-003 его не меняет. |
|
||||
| `OFFLINE VERIFIED` | Новый отдельный приёмник декодировал программный сигнал: поиск известной преамбулы, оценка фазы/частоты, PHY-заголовок, FEC и CRC. Это не проверка производственного передатчика или приёмника. |
|
||||
|
||||
Исходник H.264 тот же, что в VIDEO-001/002:
|
||||
`data/raw/video001/udacity_project_video.mp4`, SHA-256
|
||||
`651949922042c223375d40bf8929def97dbb62c6ade651d1f5b08eea47127d5f`.
|
||||
Сравнивались два шестисекундных окна. Размеры кадров режима `CURRENT`
|
||||
побайтно совпали с сохранёнными результатами VIDEO-001 во всех шести
|
||||
проверенных сочетаниях окна и разрешения.
|
||||
|
||||
## Предел PHY и полезная нагрузка
|
||||
|
||||
Длина полного пакета в PHY Lab045 ограничена 1024 байтами. Внутри него
|
||||
`protocol.packet` занимает 8 байт заголовка и 4 байта CRC-32. Максимальная
|
||||
нагрузка этого пакета равна `1024 − 8 − 4 = 1012` байтам. Формат VIDEO-002
|
||||
содержит 17-байтный видеозаголовок, поэтому максимум данных видео в одном
|
||||
фрагменте равен **995 байтам**. Это граница формата; генератор Lab045 пока
|
||||
принимает только 256 байт нагрузки, что оставило бы 239 байт видео в формате
|
||||
VIDEO-002. Производственный TX/RX с фрагментом 995 байт не проверялся.
|
||||
|
||||
Видеозаголовок VIDEO-002 состоит из флагов версии/типа кадра (1 байт),
|
||||
`stream_id` (4), `frame_id` (4), индекса (2), числа фрагментов (2), возраста
|
||||
кадра (2) и длины данных (2). Поток и номер кадра нужны для разделения потоков
|
||||
и отказа от старых кадров; индекс и число фрагментов нужны при перестановке
|
||||
и потере; тип кадра нужен декодеру; возраст нужен каждому фрагменту для
|
||||
ограничения срока доставки. Длина уже выводится из CRC-проверенного внешнего
|
||||
пакета. Отдельная пробная версия укладывает индекс и `count−1` в байт каждый
|
||||
и убирает повтор длины, сохраняя 32-битные `stream_id` и `frame_id`: 13 байт,
|
||||
экономия 4 байта, или 23,5% заголовка. Она даёт 999 байт видео на пакет и
|
||||
увеличивает верхнюю скорость лишь с 574,149 до 576,457 кбит/с. Это не основной
|
||||
способ увеличить пропускную способность; формат VIDEO-002 остался исходным.
|
||||
|
||||
## Радиобюджет
|
||||
|
||||
Расчёт использует 1280 BPSK-символов преамбулы, 144 символа защищённого
|
||||
PHY-заголовка и 42 символьных интервала защитных областей/RRC. В тело FEC
|
||||
входят все биты полного пакета и шесть хвостовых битов свёрточного кода.
|
||||
Прокалывание применяется к существующему коду R=1/2; фактическое число
|
||||
передаваемых битов посчитано по маске, включая неполный последний период.
|
||||
В QPSK тело несёт два кодовых бита на символ, преамбула и PHY-заголовок
|
||||
остаются BPSK. Оценка занятой полосы `Rs × (1 + 0,35)` учитывает скругление
|
||||
RRC и не является измеренной полосой излучения.
|
||||
|
||||
Для размеров нагрузки PHY 256, 512, 768 и 1012 байт и пауз 5 / 2 / 1 / 0,5 /
|
||||
0 мс сохранено 140 строк в `data/processed/video003/design_space.json`.
|
||||
В таблице ниже приведён максимум каждой группы: 1012 байт нагрузки, 0 мс,
|
||||
нулевые потери.
|
||||
|
||||
| Модуляция, ксимв/с | FEC | Сырая скорость, кбит/с | Эфирное время пакета, мс | Видео, кбит/с | Расчётная полоса, кГц |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| BPSK 500 | 1/2 | 500 | 35,724 | 222,819 | 675 |
|
||||
| QPSK 250 | 1/2 | 500 | 38,656 | 205,919 | 337,5 |
|
||||
| QPSK 250 | 2/3 | 500 | 30,460 | 261,326 | 337,5 |
|
||||
| QPSK 250 | 3/4 | 500 | 27,728 | 287,074 | 337,5 |
|
||||
| QPSK 500 | 1/2 | 1000 | 19,328 | 411,838 | 675 |
|
||||
| QPSK 500 | 2/3 | 1000 | 15,230 | 522,653 | 675 |
|
||||
| QPSK 500 | 3/4 | 1000 | 13,864 | **574,149** | 675 |
|
||||
|
||||
Символ длится 4 мкс при 250 ксимв/с и 2 мкс при 500 ксимв/с. При частоте
|
||||
дискретизации 8 Мвыб/с это 32 и 16 выборок на символ. Для кандидата
|
||||
QPSK 500, FEC 2/3, нагрузка 1012 байт изменение паузы даёт:
|
||||
|
||||
| Пауза, мс | Эфирное время, мс | Доля времени передачи | Видео, кбит/с | Накладная доля |
|
||||
|---:|---:|---:|---:|---:|
|
||||
| 5 | 15,230 | 75,28% | 393,475 | 60,65% |
|
||||
| 2 | 15,230 | 88,39% | 461,985 | 53,80% |
|
||||
| 1 | 15,230 | 93,84% | 490,450 | 50,96% |
|
||||
| 0,5 | 15,230 | 96,82% | 506,039 | 49,40% |
|
||||
| 0 | 15,230 | 100% | 522,653 | 47,73% |
|
||||
|
||||
Здесь накладная доля равна `1 − видео-биты / (сырая скорость × период пакета)`;
|
||||
она включает FEC, преамбулу, заголовки и паузу. Нулевой интервал проверен
|
||||
только программно. Передача пакетов без паузы через SDR не разрешена этим
|
||||
опытом.
|
||||
|
||||
Даже при нулевой паузе, полном пакете и FEC 3/4 максимум **574,149 кбит/с**.
|
||||
Без видеозаголовка получилось бы 583,958 кбит/с. Для перехода за 600 кбит/с
|
||||
при сохранении остальных параметров нужна символьная скорость не ниже
|
||||
**522 513 символов/с**. При неизменных 8 Мвыб/с ближайшее большее целое
|
||||
отношение выборок к символу — 15, то есть 533 333 символа/с; арифметическая
|
||||
скорость тогда составила бы 612,425 кбит/с. Это минимальное изменение одного
|
||||
параметра в расчёте, а не готовая настройка RF: потребуются новый тактовый
|
||||
режим PHY, проверка полосы, синхронизации и скорости обработки. Другие
|
||||
одиночные расчётные варианты: полный пакет не меньше 1248 байт при 500
|
||||
ксимв/с и FEC 3/4 либо сокращение фиксированной части кадра минимум на 299
|
||||
символов. Оба требуют изменения PHY и отдельной проверки.
|
||||
|
||||
## QPSK и FEC: автономный приём
|
||||
|
||||
Отображение Gray зафиксировано как `00=(-1−j)/√2`, `01=(-1+j)/√2`,
|
||||
`11=(1+j)/√2`, `10=(1−j)/√2`; энергия каждого QPSK-символа равна единице.
|
||||
Приёмник ищет PRBS7-преамбулу, оценивает частотный сдвиг и начальную фазу
|
||||
только по известным символам, проверяет повторённый PHY-заголовок, затем
|
||||
декодирует тело и CRC. Второе уточнение фазы использует уже проверенный
|
||||
PHY-заголовок. Исходные биты полезной нагрузки передаются только измерителю
|
||||
ошибок после завершения приёма. Проверены поворот на 90°, случайная фаза,
|
||||
сдвиг 73 Гц, шум и поиск после 11 начальных шумовых символов. Отдельный
|
||||
контроль RRC при 250 и 500 ксимв/с прошёл с 32/16 выборками на символ при
|
||||
идеальной тактовой синхронизации; он не доказывает захват тактов из IQ.
|
||||
|
||||
Прокалывание штатного кода K=7: для 2/3 повторяется маска `1110`, для 3/4 —
|
||||
`111001`, для 1/2 сохраняются все биты. Удалённые биты возвращаются в
|
||||
декодер Витерби как нулевые мягкие метрики. Эталонные векторы, длины кода,
|
||||
включая хвост, декодирование без ошибок и отказ при неверной длине проверены
|
||||
тестами. Код R=1/2 не заменён.
|
||||
|
||||
AWGN-контроль содержит 32 реализации на каждую точку 0/3/6/9 dB `Eb/N0`,
|
||||
семь сочетаний модуляции/скорости/FEC, всего 896 прогонов, затравка
|
||||
`20260916`. `Es=1`, `Eb=Es × число символов тела / число информационных битов`;
|
||||
учтён и добавочный бит при нечётной длине QPSK-тела. Фиксированные расходы кадра учтены отдельно в
|
||||
радиобюджете. Это сравнение при одинаковом `Eb/N0`, а не при одинаковой
|
||||
мощности или `Es/N0`. BER до FEC считается только для достигнутых тел пакета,
|
||||
BER после FEC — для выданных декодером пакетов; оба знаменателя записаны в
|
||||
JSON. Успех полного пакета и прохождение CRC учитываются отдельно.
|
||||
|
||||
| QPSK 500 ксимв/с | CRC при 3 dB | CRC при 6 dB | CRC при 9 dB |
|
||||
|---|---:|---:|---:|
|
||||
| FEC 1/2 | 26/32 | 32/32 | 32/32 |
|
||||
| FEC 2/3 | 13/32 | 32/32 | 32/32 |
|
||||
| FEC 3/4 | 3/32 | 32/32 | 32/32 |
|
||||
|
||||
Нулевая частота ошибок в 32 реализациях не доказывает малую вероятность
|
||||
потери на длинном потоке. Ставка 3/4 повышает расчётную скорость, но на
|
||||
3 dB в этом опыте уступила 2/3 по прохождению CRC.
|
||||
|
||||
Дополнительно переданы **32 последовательных максимальных пакета** без
|
||||
межпакетной паузы через программный канал с 42 переходными символами на
|
||||
пакет. При `Eb/N0=9 dB` и сдвиге 73 Гц QPSK 500 с FEC 2/3 и 3/4 получили
|
||||
по 32/32 CRC и по 32/32 правильно разобранных видеозаголовка. Приёмник
|
||||
выводил длину очередного пакета из принятого PHY-заголовка и не получал
|
||||
границы или payload от генератора. Полезные скорости коротких потоков:
|
||||
**522,653** и **574,149 кбит/с** за 0,487 и 0,444 с сигнального времени.
|
||||
Время программной обработки оказалось в **5,57** и **6,20** раза больше
|
||||
длительности сигнала. Поэтому проверен короткий автономный поток, а
|
||||
обработка в реальном времени и длительная устойчивая доставка — **NOT_RUN**.
|
||||
|
||||
Исходной IQ-записи Lab066 в данном worktree нет. Частотная неравномерность
|
||||
по её сводным JSON не воспроизводится однозначно; отдельная модель по Lab066
|
||||
не строилась. AWGN не объявляется эквивалентом OTA-канала.
|
||||
|
||||
## H.264 через PyAV
|
||||
|
||||
Использован **PyAV 16.0.1** с библиотеками FFmpeg: `libavcodec 62.11.100`,
|
||||
`libavformat 62.3.100`, `libavutil 60.8.100`. FFmpeg CLI не вызывался.
|
||||
Для каждого из 60 прогонов рядом с размерами кадров сохранены имя кодека,
|
||||
разрешение, частота кадров, формат пикселей, целевой и предельный потоки,
|
||||
размер VBV, GOP, число B-кадров, `preset`, `tune`, фактический профиль,
|
||||
`intra-refresh`, `time_base` и точные `x264-params`. Профиль всех проверенных
|
||||
потоков декодер определил как `High`; B-кадров нет. `CURRENT` повторил
|
||||
VIDEO-001 с GOP 1 с и VBV 1 с. `CURRENT_VBV`, `SHORT_GOP` и `INTRA_REFRESH`
|
||||
проверены при 300/400/500 кбит/с и VBV 0,2 с. Короткий GOP равен 5 кадрам
|
||||
при 10 кадрах/с и 3 кадрам при 5 кадрах/с. Запрошенный intra refresh
|
||||
уменьшил отдельные пики, но в испытании с потерей кадра восстанавливал
|
||||
точное изображение позже короткого GOP.
|
||||
|
||||
В таблице приведено худшее из двух окон для потока и размера кадра, худшее
|
||||
время восстановления после удаления одного кадра и меньшее среднее PSNR
|
||||
из двух окон. Пик за 100 мс отражает один крупный кадр, его нельзя
|
||||
подменять средним потоком.
|
||||
|
||||
| Режим | H.264 | Средний, кбит/с | Пик 100 мс | Пик 1 с | Макс. кадр, байт | P95 кадра, байт | Восстановление, мс | PSNR, dB |
|
||||
|---|---|---:|---:|---:|---:|---:|---:|---:|
|
||||
| NORMAL | CURRENT | 354,0 | 1116,1 | 375,8 | 13951 | 12784 | 900 | 33,8 |
|
||||
| NORMAL | SHORT_GOP 400k | 361,4 | 740,2 | 408,8 | 9252 | 9114 | 400 | 33,3 |
|
||||
| HIGH QUALITY | CURRENT | 357,2 | 1034,6 | 455,6 | 12933 | 7892 | 900 | 33,2 |
|
||||
| HIGH QUALITY | SHORT_GOP 400k | 391,8 | 751,7 | 427,1 | 9396 | 9080 | 400 | 33,1 |
|
||||
| 720p/5 | CURRENT | 345,5 | 1164,0 | 440,6 | 14550 | 11653 | 800 | 33,0 |
|
||||
| 720p/5 | SHORT_GOP 400k | 340,2 | 736,6 | 345,5 | 9208 | 9122 | 600 | 32,1 |
|
||||
|
||||
Порог 300 кбит/с снижал размер пиков сильнее, но ухудшал PSNR. Порог 500
|
||||
кбит/с повышал пиковый поток и требовал большего радиобюджета. Вариант
|
||||
`SHORT_GOP 400k` выбран для совместного расчёта по размеру кадров и сроку
|
||||
восстановления, без утверждения о проверенном операторском качестве.
|
||||
Контрольных сцен с мелкими препятствиями и оценки оператором не было.
|
||||
|
||||
## Сопоставление видео и радио
|
||||
|
||||
Измерения VIDEO-001/002 и требуемые запасы:
|
||||
|
||||
| Видео | Средний, кбит/с | Пик 1 с, кбит/с | Нужно +20%, кбит/с | Нужно +50%, кбит/с |
|
||||
|---|---:|---:|---:|---:|
|
||||
| ROBUST 320×240/5 | 117,2 | 171,7 | 206,0 | 257,5 |
|
||||
| NORMAL 640×360/10 | 354,0 | 375,8 | 451,0 | 563,7 |
|
||||
| HIGH QUALITY 854×480/10 | 357,2 | 455,6 | 546,7 | 683,3 |
|
||||
| 720p/5 | 345,5 | 440,6 | 528,8 | 661,0 |
|
||||
|
||||
Для расчётного QPSK 500, FEC 2/3, пакет 1024 байта, пауза 0 мс исходные
|
||||
пики дают запас `522,653/peak`: NORMAL 1,391, HIGH QUALITY 1,147,
|
||||
720p/5 1,186. После `SHORT_GOP 400k` пики 408,8 / 427,1 / 345,5 кбит/с
|
||||
дают запас **1,278 / 1,224 / 1,512**. По одному лишь расчётному фильтру
|
||||
все три превышают 1,2; при исходном кодировании HIGH QUALITY и 720p/5
|
||||
порог 1,2 не проходили. Эти числа не учитывают ошибки PHY, занятость
|
||||
процессора и серийные потери пакетов.
|
||||
|
||||
Модель VIDEO-002 повторена на настоящих H.264 пакетах с рассчитанным
|
||||
временем передачи каждого полного пакета. Очередь ограничена двумя кадрами,
|
||||
срок — 300 мс, потери 0/1/2/5/10% независимы по передаваемому пакету,
|
||||
фиксированная затравка `20260916`. Отдельно сохранены серии из 2/5/10
|
||||
потерянных пакетов; их нельзя трактовать как независимую вероятность.
|
||||
Ниже для `SHORT_GOP 400k + QPSK 500 / FEC 2/3 / 1012 байт / 0 мс`
|
||||
показано число отображённых кадров в окнах «белая / чёрная машина»:
|
||||
|
||||
| Потеря пакетов | NORMAL, из 60 | HIGH QUALITY, из 60 | 720p/5, из 30 |
|
||||
|---:|---:|---:|---:|
|
||||
| 0% | 60 / 60 | 60 / 60 | 30 / 30 |
|
||||
| 1% | 54 / 55 | 56 / 55 | 27 / 25 |
|
||||
| 2% | 45 / 42 | 47 / 46 | 23 / 20 |
|
||||
| 5% | 27 / 22 | 28 / 25 | 11 / 12 |
|
||||
| 10% | 16 / 16 | 16 / 13 | 5 / 5 |
|
||||
|
||||
Без потерь максимальные и P95 возрасты показанных кадров в этих прогонах
|
||||
не превысили 152,3 мс; сбросов по устареванию не было. При потере пакетов
|
||||
возраст остаётся ограниченным, но неполные кадры не показываются. При 5%
|
||||
потерь до оператора доходит меньше половины кадров NORMAL и HIGH QUALITY
|
||||
в одном или обоих окнах. Время восстановления после первой потерянной
|
||||
части записано отдельно для каждого прогона в JSON; например, при 1%
|
||||
потерь диапазон для этих трёх режимов составил 252–752 мс. Это конкретные
|
||||
короткие реализации, а не оценка вероятности для длительного канала.
|
||||
|
||||
## Статус и ограничения
|
||||
|
||||
| Поле | Результат |
|
||||
|---|---|
|
||||
| `VIDEO-003 STATUS` | **PARTIAL**: программный PHY и видео проверены по отдельности и в модели доставки; производственный TX/RX, real-time и OTA не проверены. |
|
||||
| `MAX PHY PACKET SIZE` | 1024 байта полного пакета. |
|
||||
| `CURRENT IMPLEMENTED PAYLOAD LIMIT` | Ровно 256 байт нагрузки `protocol.packet` у генератора Lab045; видео в производственный TX/RX не встроено. |
|
||||
| `MAX CALCULATED VIDEO PAYLOAD` | 995 байт при текущем 17-байтном заголовке. |
|
||||
| `BEST H264 PROFILE` | `SHORT_GOP 400k`, GOP 0,5 с при 10 кадрах/с, VBV 0,2 с; операторское качество не проверялось. |
|
||||
| `BEST BPSK CONFIGURATION` | 500 ксимв/с, FEC 1/2, PHY payload 1012 байт, 0 мс: 222,819 кбит/с **только расчёт**; действующий размер 256 байт и пауза 5 мс дают 115,654 кбит/с при нулевых потерях. |
|
||||
| `BEST QPSK 250K CONFIGURATION` | FEC 3/4, payload 1012 байт, 0 мс: 287,074 кбит/с **только расчёт**. |
|
||||
| `BEST QPSK 500K CONFIGURATION` | По скорости FEC 3/4, payload 1012 байт, 0 мс: 574,149 кбит/с; по балансу с ошибками и `SHORT_GOP 400k` кандидат FEC 2/3: 522,653 кбит/с. Оба только программные. |
|
||||
| `BEST FEC RATE` | **2/3 как следующий диагностический кандидат**; при 3 dB получил 13/32 CRC против 3/32 у 3/4, а расчётный поток после смены GOP даёт запас более 1,2 для трёх видеорежимов. |
|
||||
| `BEST CALCULATED USEFUL RATE` | 574,149 кбит/с при нулевых потерях. |
|
||||
| `BEST OFFLINE-VERIFIED USEFUL RATE` | 574,149 кбит/с на коротком 32-пакетном синтетическом потоке при 9 dB, 32/32 CRC; CPU/signal = 6,20, поэтому это **не real-time goodput**. |
|
||||
| `600 KBIT/S TARGET WITH CURRENT PHY` | `NOT_REACHABLE` в проверенной матрице при пакете до 1024 байт, скоростях до 500 ксимв/с и FEC до 3/4. |
|
||||
| `MINIMUM ARCHITECTURAL CHANGE REQUIRED` | Для арифметического превышения 600 кбит/с при FEC 3/4 поднять скорость минимум до 522 513 символов/с; при Fs=8 Мвыб/с и целых выборках на символ следующий вариант 533 333 символа/с (15 выборок/символ). Требуются новые PHY/RX и тесты. |
|
||||
| `NORMAL VIDEO FITS WITH 20% HEADROOM` | `YES` только в расчёте для `SHORT_GOP 400k + QPSK 500/FEC 2/3/1012/0`: запас 1,278. |
|
||||
| `HIGH QUALITY VIDEO FITS WITH 20% HEADROOM` | `YES` только в том же расчёте: 1,224; исходный режим VIDEO-001 давал 1,147. |
|
||||
| `720P5 FITS WITH 20% HEADROOM` | `YES` только в том же расчёте: 1,512; исходный режим давал 1,186. |
|
||||
| `BEST NEXT RF CANDIDATE` | Предмет **отдельной разработки и будущего разрешённого опыта**: QPSK 500 ксимв/с, FEC 2/3, полный пакет 1024 байта, пауза 0 мс, `SHORT_GOP 400k`. Сейчас real-time декодирование и устойчивость к потерям не подтверждены. |
|
||||
| `WHY` | 2/3 заметно лучше 3/4 в AWGN-контроле 3 dB; расчёт 522,653 кбит/с покрывает пики нового H.264 с запасом ≥1,2. В модели при 0% потерь показаны все кадры; при 5% большая доля кадров теряется. |
|
||||
| `ENCODER API` | PyAV 16.0.1; версии библиотек и точные параметры каждого прогона — в `codec_results.json`. |
|
||||
| `FFMPEG CLI USED` | `NO`. |
|
||||
| `VIDEO-SPECIFIC GATE` | `PASS`: 123 целевых теста, сверка результатов, импортов и отсутствия аппаратных импортов в проверяемых модулях. |
|
||||
| `RF TX` | `0`. |
|
||||
| `COMMIT` / `PUSH` | `NOT PERFORMED` / `NOT PERFORMED`. |
|
||||
|
||||
## Файлы и повторение
|
||||
|
||||
- `protocol/punctured_fec.py`, `protocol/video003_modem.py`: автономный кодер и приёмник; производственный BPSK и SDR receiver не изменены.
|
||||
- `protocol/video003_compact_header.py`: отдельная проба 13-байтного заголовка, версия VIDEO-002 остаётся исходной.
|
||||
- `tools/video003_design.py`: `design_space.json` и точный расчёт.
|
||||
- `tools/video003_synthetic.py`: `synthetic_phy.json`, 896 реализаций AWGN.
|
||||
- `tools/video003_stream.py`: `continuous_stream.json`, короткий непрерывный поток.
|
||||
- `tools/video003_codec.py`: `codec_results.json`, 60 прогонов PyAV.
|
||||
- `tools/video003_transport.py`: `transport_results.json`, 784 прогона доставки.
|
||||
- `tools/video_gate.py`: целевой шлюз проверки без исторических RF-данных.
|
||||
|
||||
Запуск из корня worktree после установки `requirements-video.txt`:
|
||||
|
||||
```powershell
|
||||
python -B -X utf8 -m tools.video003_design
|
||||
python -B -X utf8 -m tools.video003_synthetic
|
||||
python -B -X utf8 -m tools.video003_stream
|
||||
python -B -X utf8 -m tools.video003_codec
|
||||
python -B -X utf8 -m tools.video003_transport
|
||||
python -B -X utf8 -m tools.video_gate
|
||||
```
|
||||
|
||||
Последние две программы читают результаты предыдущих. `video_gate` проверяет
|
||||
только файлы VIDEO-001/002/003 и используемые модули `protocol`, запускает
|
||||
тесты без аппаратных entry point. Статический запрет аппаратных импортов в
|
||||
этих модулях и отсутствие аппаратного запуска в перечисленных командах
|
||||
не служат доказательством качества радиоканала. Следующий опыт с RF требует
|
||||
отдельного прямого разрешения и новой подготовки PHY.
|
||||
|
||||
При независимой проверке общий `python tools/quick_gate.py` завершился с
|
||||
ошибкой: 1059 тестов прошли, один тест Lab065 и его функциональная проверка
|
||||
не нашли исторический `data/raw/lab064/tx_metadata.json` в VIDEO worktree.
|
||||
Этот файл не создавался для VIDEO-003. Целевой `video_gate` прошёл отдельно:
|
||||
123 теста и сверка сохранённых результатов.
|
||||
310
docs/video/VIDEO_004.md
Normal file
310
docs/video/VIDEO_004.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# VIDEO-004: скорость программного приёмника и защита видео от потери пакетов
|
||||
|
||||
16 сентября 2026 года. Worktree `SDR_Rover_Video`, ветка `video-development`,
|
||||
исходный HEAD `af7c05f`. Все опыты программные: `RF TX = 0`, SDR не открывался.
|
||||
Файлы VIDEO-001/002/003 и производственный BPSK не заменялись. Коммит и push
|
||||
не выполнялись.
|
||||
|
||||
## Вывод и граница опыта
|
||||
|
||||
`VIDEO-004 STATUS = PARTIAL`. Прогретый доступный программный путь выполнил
|
||||
порог скорости: фактор реального времени **0,130** на исходном 32-пакетном
|
||||
сигнале и **0,131** на 40-пакетном пути с внешним FEC. Порог `≤0,67` и
|
||||
предпочтительный `≤0,50` пройдены на этом ПК. Восстановлены четыре стёртых
|
||||
пакета и четыре видеокадра побайтно. Существующий H.264 SHORT_GOP проверен
|
||||
отдельной моделью доставки.
|
||||
|
||||
Это **AVAILABLE SOFTWARE PATH REALTIME FACTOR**, а не скорость полного SDR RX.
|
||||
В потоковом замере сигнал уже дан с известными символьными отсчётами.
|
||||
`TIMING RECOVERY = NOT_IMPLEMENTED_IN_THIS_BENCHMARK` и
|
||||
`CARRIER TRACKING FROM RAW IQ = NOT_IMPLEMENTED_IN_THIS_BENCHMARK`.
|
||||
RRC-проверка с известными тактами существует отдельно. Её время не включено
|
||||
в число 0,130. Модель не оценивает операторское качество и не доказывает
|
||||
устойчивость через эфир.
|
||||
|
||||
При пяти затравках и двух шестисекундных окнах NORMAL 640×360/10 лучший
|
||||
проверенный для 1–5% потерь вариант `QPSK 500 / inner FEC 2/3 / outer 8+1`
|
||||
с дополнительным проверочным пакетом для блока опорного кадра показал
|
||||
**591/600 кадров при 1%** и **498/600 при 5%**. Потеря 102 кадров из 600
|
||||
при 5% вместе с малым запасом пропускной способности не позволяет объявить
|
||||
этот режим надёжно поддерживаемым. `NORMAL SUPPORTED IN SOFTWARE MODEL = NO`
|
||||
для всего диапазона 1–5% с принятым в VIDEO-003 запасом 20% к пику.
|
||||
Это не отрицание отдельных
|
||||
успешных прогонов.
|
||||
|
||||
## Скорость: одинаковый вход до и после
|
||||
|
||||
Канонический вход содержит 32 полных PHY-пакета QPSK 500 ксимв/с, inner FEC
|
||||
2/3, 9 dB `Eb/N0`, сдвиг несущей 73 Гц и 42 переходных символа на пакет.
|
||||
Затравка `20260916`; файл `data/processed/video004/canonical_symbols.npy`
|
||||
проверяется по SHA-256 из `canonical_manifest.json`. Приёмник узнаёт размер
|
||||
пакета из принятого PHY-заголовка. Эталонные SHA передаются только проверке
|
||||
после CRC. Длительность 32-пакетного сигнала: **0,48736 с**.
|
||||
|
||||
`cProfile` использован для поиска затрат. Числа скорости ниже получены
|
||||
отдельно через `time.perf_counter()` без профилировщика. Для каждого прохода
|
||||
записаны повторные измерения; указан средний по порядку из повторов.
|
||||
|
||||
| Замер | Исходный декодер | Прогретый Numba | Ускорение |
|
||||
|---|---:|---:|---:|
|
||||
| 32 пакета, приём и видеозаголовок | 2,690 с; фактор **5,520** | 0,0635 с; фактор **0,130** | **42,36×** |
|
||||
| Только Витерби, те же 32 мягких слова | 2,125 с; фактор **4,360** | 0,0270 с; фактор **0,055** | **78,68×** |
|
||||
| 256 пакетов, длинный контроль | фактор **4,518** | фактор **0,133** | 34,1× |
|
||||
| 40 пакетов, CRC → внешний FEC → сборка видеокадра | фактор **4,446** | фактор **0,131** | **33,90×** |
|
||||
|
||||
Первый полный проход с компиляцией Numba занял **0,929 с**; это отдельная
|
||||
стоимость запуска, не включённая в прогретый фактор. Numba 0.61.2 и
|
||||
llvmlite 0.44.0 взяты из уже существующего локального набора проекта.
|
||||
Компиляция работает с `fastmath=False`, а отсутствие Numba даёт явную ошибку
|
||||
выбранного JIT-режима. После отказа CRC другой декодер не запускается.
|
||||
Эталонные битовые выходы, решения QPSK, CRC, пакеты и SHA видеоданных до и
|
||||
после совпали. Длинный поток также совпал на всех 256 пакетах.
|
||||
|
||||
Предварительный `cProfile` исходного 32-пакетного пути относил 2,743 из
|
||||
3,196 с профилируемого времени к Витерби; внутри было 262 336 вызовов
|
||||
`argmin`. После JIT основными расходами стали поиск преамбулы и оценка
|
||||
несущей. Для нового 40-пакетного пути профиль приведён отдельно:
|
||||
|
||||
| Этап | Время `cProfile`, мс | Доля 91,4 мс | Вызовы | Основной массив или копия |
|
||||
|---|---:|---:|---:|---|
|
||||
| Витерби вместе с вызовом декодера | 34,8 | 38,1% | 40 | `choices`: 524 672 байта на полный пакет внутри Numba |
|
||||
| Поиск преамбулы | 27,1 | 29,7% | 40 | короткие срезы по 1280 символам |
|
||||
| Коррекция фазы/частоты | 11,3 | 12,4% | 120 | копия только текущего заголовка или тела |
|
||||
| Оценка фазы/частоты | 9,3 | 10,2% | 80 | временные массивы пилота и заголовка |
|
||||
| Снятие прокалывания | 1,59 | 1,7% | 40 | 16 396 `float64`, около 131 Кбайт на пакет |
|
||||
| Решения QPSK | 0,56 | 0,6% | 40 | около 98 Кбайт мягких значений |
|
||||
| Разбор `protocol.packet` и CRC | 0,33 | 0,4% | 40 | до 1024 байт пакета |
|
||||
| Сборщик внешнего FEC | 1,61 | 1,8% | 36 | буфер максимум 8 блоков; четыре матричных восстановления |
|
||||
| Выдача фрагмента видеосборщику | 0,36 | 0,4% | 32 | повторная упаковка в байты не выполняется |
|
||||
| RRC | отдельно | вне пути | один контроль | 11,09 мс на один пакет при известных тактах |
|
||||
| Восстановление тактов и слежение из IQ | `NOT_IMPLEMENTED` | вне пути | 0 | не измерялись |
|
||||
|
||||
Строки со вложенными вызовами нельзя складывать: например, снятие
|
||||
прокалывания входит во время декодера. Одиночный RRC-контроль с 16 выборками
|
||||
на символ прошёл CRC, но его 11,09 мс нельзя прибавлять к потоку как
|
||||
доказательство готового IQ-приёмника. `tracemalloc` показал пик Python-памяти
|
||||
13,69 Мбайт до правок и 1,07 Мбайт после на 32 пакетах. Он не учитывает всю
|
||||
нативную память NumPy и Numba.
|
||||
|
||||
## Защита от стирания пакета
|
||||
|
||||
Внешний систематический код использует уже существующую в проекте
|
||||
арифметику GF(256) из `protocol/packet_erasure_fec.py`. Упаковка Lab028 не
|
||||
используется. Новый символ содержит 16 байт метаданных блока, 2 байта длины,
|
||||
4 байта времени создания кадра и проверенный 13-байтный видеозаголовок.
|
||||
Максимум данных видео: **977 байт** в полном payload PHY 1012 байт.
|
||||
Все внешние символы имеют одинаковую длину для точного восстановления
|
||||
последнего короткого фрагмента. Внешний код восстанавливает стирания после
|
||||
строгого CRC; он не исправляет неизвестные ошибочные биты внутри пакета.
|
||||
|
||||
Систематический фрагмент сразу передаётся сборщику. При потерях декодирование
|
||||
блока начинается после получения любых `K` различных символов. Полученный
|
||||
после 300 мс фрагмент отвергается по времени создания кадра. Буфер
|
||||
ограничен восемью блоками; дубли и противоречивые метаданные проверяются.
|
||||
Тесты подтвердили одну потерю, потери до `R`, отказ при числе потерь больше
|
||||
`R`, точное восстановление байтов и короткого последнего фрагмента.
|
||||
|
||||
Для полных пакетов расчётный бюджет без пауз:
|
||||
|
||||
| K+R | Доля проверочных пакетов | 2/3: чистое видео, кбит/с | 3/4: чистое видео, кбит/с | Время полного блока 2/3, мс |
|
||||
|---|---:|---:|---:|---:|
|
||||
| 8+1 | 11,11% | 456,176 | 501,122 | 137,07 |
|
||||
| 8+2 | 20,00% | 410,558 | 451,010 | 152,30 |
|
||||
| 12+2 | 14,29% | 439,884 | 483,225 | 213,22 |
|
||||
| 12+3 | 20,00% | 410,558 | 451,010 | 228,45 |
|
||||
| 16+2 | 11,11% | 456,176 | 501,122 | 274,14 |
|
||||
| 16+4 | 20,00% | 410,558 | 451,010 | 304,60 |
|
||||
|
||||
Это предел для полного блока с заполненными пакетами. Последний частичный
|
||||
блок и защита опорного кадра меняют фактическую долю чётности. Например,
|
||||
для NORMAL 8+1 с усилением опорных блоков расчёт по числу реально созданных
|
||||
символов в двух окнах даёт **424,922 / 425,142 кбит/с**. Пик SHORT_GOP 400k
|
||||
за одну секунду, худший из двух окон: **408,8 кбит/с**. Запас в этой паре
|
||||
всего около 1,04, без учёта ошибок внутреннего PHY. Блок 16+4 из 20 полных
|
||||
пакетов занимает 304,6 мс, уже больше срока кадра без ожидания накопления
|
||||
данных. Для каждого прогона модель учитывает готовность исходных фрагментов,
|
||||
момент появления чётности и истечение срока.
|
||||
|
||||
## Потери, перемежение и опорные кадры
|
||||
|
||||
В модели использованы настоящие H.264 пакеты, короткий GOP, ограниченный
|
||||
сборщик VIDEO-002 и декодер PyAV. Случайные потери применяются независимо
|
||||
к передаваемым радиопакетам; 1440 основных прогонов покрывают ROBUST,
|
||||
NORMAL и HIGH QUALITY, два окна, обе скорости внутреннего FEC, шесть схем,
|
||||
равномерную и усиленную защиту, уровни 0/1/2/5/10/20% и серии 2/5/10.
|
||||
Для выбора NORMAL дополнительно выполнены 180 прогонов на пяти фиксированных
|
||||
затравках `20260916…20260920`. Числа ниже относятся к 10 окнам по 60 кадров.
|
||||
|
||||
| Внешняя защита, inner 2/3 | 1%: показано / 600 | 5%: показано / 600 | 10%: показано / 600 | 5%: кадр/с | 5%: доля потерь кадров |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| 8+1 одинаковая | 594 | 452 | 264 | 7,53 | 24,7% |
|
||||
| 8+1, опорный блок +1 parity | 591 | **498** | 330 | **8,30** | **17,0%** |
|
||||
| 8+2 одинаковая | 580 | 484 | **363** | 8,07 | 19,3% |
|
||||
|
||||
При 1% лучшая доля в этой выборке у одинаковой 8+1; при 5% у усиленной
|
||||
8+1; при 10% у одинаковой 8+2. Эти короткие реализации не дают оценки
|
||||
длительного канала. В варианте 8+1 с усилением среднее время от первого
|
||||
непоказанного кадра до следующего показанного опорного кадра при 5%
|
||||
составило **535 мс** против **665 мс** у одинаковой 8+1. Это показатель
|
||||
данной модели и затравок, а не обещание восстановления при любой серии.
|
||||
|
||||
В отдельном контроле две потери источников **одного блока опорного кадра**
|
||||
дали 55/60 показанных кадров в каждом окне при 8+1 без усиления; следующий
|
||||
опорный кадр появился через 652/668 мс. При усилении блока до двух parity
|
||||
получено 60/60, два фрагмента восстановлены до срока и провала изображения
|
||||
не было. Одну потерю восстанавливали оба варианта.
|
||||
|
||||
Проверка перемежения глубины 2 отклонена. Даже при 0% потерь она показала
|
||||
лишь 24/120 кадров для 8+1, 21/120 для 8+2 и 3/120 для 12+2 в NORMAL:
|
||||
ожидание фрагментов следующего блока нарушило срок 300 мс. Без перемежения
|
||||
при 0% эти схемы показали 120/120. Серии 2/5/10 сохранены отдельно в JSON;
|
||||
уменьшение влияния серии не окупило задержку в этом способе чередования.
|
||||
|
||||
При одинаковых заданных стираниях пакетов inner FEC 2/3 и 3/4 дали одинаковые
|
||||
числа показанных кадров для трёх сравниваемых схем NORMAL на пяти затравках;
|
||||
3/4 даёт больше расчётной ёмкости. Эта модель не создаёт битовых ошибок.
|
||||
Контроль VIDEO-003 при 3 dB `Eb/N0` на пакетах меньшей длины дал 13/32 CRC
|
||||
для 2/3 против 3/32 для 3/4. Его нельзя переносить как точную вероятность
|
||||
для максимальных пакетов, но оснований заменить первый диагностический
|
||||
кандидат на 3/4 пока нет.
|
||||
|
||||
## CODE QUALITY AUDIT
|
||||
|
||||
Исходная инвентаризация восьми модулей: 1967 строк, 70 функций. Сейчас те же
|
||||
восемь модулей содержат 2008 строк и 72 функции; новые модули Витерби и
|
||||
внешнего FEC содержат ещё 309 строк и 11 функций. Размер кода здесь не
|
||||
критерий качества. Рабочая цепочка: символы → преамбула/PHY → QPSK → снятие
|
||||
прокалывания → Витерби → CRC → внешний FEC → свежий видеофрагмент.
|
||||
|
||||
| ITEM | BEFORE | ACTION | AFTER | EFFECT |
|
||||
|---|---|---|---|---|
|
||||
| Витерби | Python-цикл, 262 336 `argmin` за 32 пакета | JIT со скалярным выбором ветви и `fastmath=False` | те же биты | 78,68× для Витерби |
|
||||
| Коррекция несущей | два прохода по всему оставшемуся потоку на пакет | ограничена заголовком и текущим телом | те же пакеты/CRC | фактор пути 5,520 → 0,130 вместе с JIT |
|
||||
| Проверка конечности | сканирование всего суффикса на каждом пакете | проверяется кандидат и его тело | повреждение текущего пакета отвергается | 256 пакетов: фактор 0,288 → 0,133 |
|
||||
| Маска FEC и преамбула | повторные массивы и PRBS7 | точный арифметический счёт, ограниченный кеш неизменяемых масок | те же кодовые длины и биты | меньше выделений |
|
||||
| Сборщик блоков | состояние росло с числом блоков | ограничен восемью блоками, поздние повторы игнорируются | строгие кадры и счётчики без изменений | ограничена память |
|
||||
| Подача v2-фрагмента | требовала бы повторной упаковки под v1 | отдельный проверяемый вход `offer_fragment` | v1 сохранён | меньше копий в горячем пути |
|
||||
|
||||
Классификация существенных проверок: **A, production safety**: длины PHY и
|
||||
FEC, конечность текущих символов, метаданные блока, возраст, границы буфера,
|
||||
CRC и отказ от старого кадра оставлены. **B, development assertion**:
|
||||
сравнение SHA, точных битов и ожидаемого числа кадров живёт в тестах и
|
||||
инструментах опыта. **C, offline diagnostic**: `cProfile`, `tracemalloc`,
|
||||
JSON и исходные H.264 сравнения находятся в `tools/`, вне приёмника.
|
||||
**D, duplicated check**: повторный проход по всему суффиксу убран;
|
||||
проверка полей на публичном входе `offer_fragment` оставлена, хотя текущий
|
||||
вызывающий код уже разобрал заголовок. **E, hot-loop check**: проверка
|
||||
конечности вынесена из полного потока в границу текущего пакета, а
|
||||
Numba-цикл Витерби не строит NumPy-массивы на каждом шаге.
|
||||
|
||||
| Существенная runtime-проверка | Место | Категория | Решение |
|
||||
|---|---|---|---|
|
||||
| PHY-длина, версия и CRC пакета | `video003_modem`, `packet` | A | Оставить до выдачи данных внешнему FEC |
|
||||
| Длина и конечность мягких значений | `punctured_fec` | A/E | Оставить один раз перед решёткой |
|
||||
| Диапазоны K/R, индекс, поток и длина символа | `video004_erasure` | A | Оставить перед накоплением блока |
|
||||
| Время создания и возраст фрагмента | `video004_erasure`, `video_stream_transport` | A | Оставить; после 300 мс не выдавать |
|
||||
| Предел буфера и повтор старого кадра | оба сборщика | A | Оставить с ограничением 8 блоков и 2 кадров |
|
||||
| SHA эталона, точные биты и ожидаемые счётчики | `tests/`, `tools/video004_*` | B/C | Держать вне приёмника |
|
||||
| Повторная проверка полей на публичном входе | `FrameReassembler.offer_fragment` | D → A | Оставить как защиту от другого вызывающего кода |
|
||||
| Сканирование всего хвоста потока | прежний `receive_frame` | E | Заменить проверкой текущего кандидата и тела |
|
||||
|
||||
| ITEM | LOCATION | WHY SUSPICIOUS | ACTION |
|
||||
|---|---|---|---|
|
||||
| Сборка `np.concatenate` и SHA эталона | `tools/video004_benchmark.py` | массивы и знание исходного пакета | **KEEP** только в генераторе и проверке после CRC |
|
||||
| RRC roundtrip | `protocol/video003_modem.py` | не является поточным IQ-приёмом | **KEEP** как отдельный контроль; вне горячего пути |
|
||||
| Упаковка Lab028 | `protocol/packet_erasure_fec.py` | лишний заголовок и иной формат пакета | **KEEP** для старых лаб; новый видеоформат её не вызывает |
|
||||
| `_linear_combine` | `protocol/packet_erasure_fec.py` | внутренний API другого модуля | **KEEP** проверенную арифметику; публичный общий API отложить |
|
||||
| Преобразования в решётке | прежний `convolutional_fec.py` | массивы на каждом шаге | **REWRITE** в отдельном JIT-варианте; старый код сохранён как эталон |
|
||||
| Большая функция `simulate` | `tools/video004_transport.py` | смешивает график передачи, потери и H.264 | **KEEP** как автономную модель с фиксированными входами; не импортируется рабочим приёмником |
|
||||
|
||||
Генерация сигнала, `np.concatenate`, SHA и сравнение с эталоном остались в
|
||||
`tools/` как диагностика. В критическом пути нет
|
||||
графиков, исторических Lab-проверок, verifier, подробного JSON и сравнения с
|
||||
исходными пакетами. Нужные проверки повреждённых данных не удалялись.
|
||||
|
||||
После правок повторены модемные векторы, FEC/CRC, тесты стираний,
|
||||
1440 моделей потерь, 48 случаев перемежения, 180 случаев пяти затравок и
|
||||
оба замера производительности. Сравнение копии 1440 результатов до и после
|
||||
аудита: показанные кадры, возраст и восстановления совпали; изменилось
|
||||
лишь исправленное диагностическое поле числа неполных блоков в 480 строках.
|
||||
`BEHAVIOR EQUIVALENT = YES` для строгого приёма и показа кадров.
|
||||
|
||||
`RUFF = NOT_RUN — TOOL NOT INSTALLED`.
|
||||
`coverage`, `mypy`, `pyright`, `vulture`, `radon` также `NOT_RUN — TOOL NOT INSTALLED`.
|
||||
Постоянные новые зависимости не устанавливались. Правило полного обзора после
|
||||
крупного этапа сохраняется для CONTROL-001/002; мелким правкам достаточно
|
||||
`pytest`, доступного `ruff` и `git diff --check`.
|
||||
|
||||
## Машинные результаты и повторение
|
||||
|
||||
Все файлы находятся в `data/processed/video004/`: канонический 32-пакетный
|
||||
сигнал и его manifest, `benchmark_before.json`, `benchmark_after.json`,
|
||||
`viterbi_benchmark.json`, 256-пакетный сигнал и `benchmark_256.json`,
|
||||
40-пакетный `pipeline_benchmark.json`, `transport_results.json`,
|
||||
`interleaving_results.json`, `normal_seed_sweep.json` и
|
||||
`keyframe_recovery.json`. Эталонные пакеты не передаются декодеру.
|
||||
|
||||
Из корня VIDEO worktree, с доступной Numba 0.61.2:
|
||||
|
||||
```powershell
|
||||
python -B -X utf8 -m tools.video004_benchmark --phase after --numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
|
||||
python -B -X utf8 -m tools.video004_viterbi_benchmark --numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
|
||||
python -B -X utf8 -m tools.video004_longrun --numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
|
||||
python -B -X utf8 -m tools.video004_pipeline_benchmark --numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
|
||||
python -B -X utf8 -m tools.video004_transport
|
||||
python -B -X utf8 -m tools.video004_interleaving
|
||||
python -B -X utf8 -m tools.video004_seed_sweep
|
||||
python -B -X utf8 -m tools.video004_keyframe
|
||||
python -B -X utf8 -m tools.video_gate --numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
|
||||
```
|
||||
|
||||
Старый `benchmark_before.json` повторно не создаётся после правок: он
|
||||
фиксирует исходный код VIDEO-003 на том же сигнале. На другой машине нужно
|
||||
установить зависимости из `requirements-video.txt`; абсолютный путь локальных
|
||||
пакетов Numba в командах относится только к этому ПК. Замер скорости следует
|
||||
повторять на целевом Raspberry/Jetson отдельно.
|
||||
|
||||
## Обязательные поля результата
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---|
|
||||
| `VIDEO-004 STATUS` | `PARTIAL` |
|
||||
| `QPSK 500K FEC 2/3 INITIAL REALTIME FACTOR` | **5,520**, 32 пакета, доступный путь VIDEO-003 |
|
||||
| `OPTIMIZED REALTIME FACTOR` | **0,130**, тот же 32-пакетный сигнал, прогретый путь |
|
||||
| `REALTIME TARGET >=1.5X` | `PASS` для доступного пути; также пройден предпочтительный фактор ≤0,50 |
|
||||
| `MAIN BOTTLENECK BEFORE OPTIMIZATION` | Витерби, 2,743/3,196 с по `cProfile` |
|
||||
| `MAIN OPTIMIZATIONS` | JIT без `fastmath`; обработка только текущего пакета; ограниченная проверка конечности; кеш преамбулы и маски |
|
||||
| `JIT FIRST RUN TIME` | 0,929 с для первого полного 32-пакетного прохода |
|
||||
| `WARM RUN TIME` | медиана 0,0635 с на 32 пакета |
|
||||
| `STEADY-STATE REALTIME FACTOR` | **0,130** |
|
||||
| `VITERBI REALTIME FACTOR BEFORE / AFTER` | **4,360 / 0,055** |
|
||||
| `AVAILABLE PIPELINE REALTIME FACTOR BEFORE / AFTER` | **4,446 / 0,131** на 40 пакетах с четырьмя стираниями |
|
||||
| `VITERBI SPEEDUP` | **78,68×** |
|
||||
| `FULL AVAILABLE PIPELINE SPEEDUP` | **33,90×** |
|
||||
| `TRANSPORT ERASURE CODE` | Систематический GF(256), отдельная видеооболочка |
|
||||
| `BEST DATA/PARITY CONFIGURATION` | 8+1 с дополнительным parity для опорного блока в диапазоне 1–5% данной модели; 8+2 одинаковая лучше при 10% |
|
||||
| `PACKET LOSS 1%: DISPLAYED FPS / FRAME LOSS` | 8+1 с усилением: **9,85 кадр/с; 1,5%**, 591/600 |
|
||||
| `PACKET LOSS 5%: DISPLAYED FPS / FRAME LOSS` | **8,30 кадр/с; 17,0%**, 498/600 |
|
||||
| `PACKET LOSS 10%: DISPLAYED FPS / FRAME LOSS` | 8+1 с усилением: **5,50 кадр/с; 45,0%**; 8+2 одинаковая: 6,05 кадр/с; 39,5% |
|
||||
| `BURST LOSS RESULT` | Глубина перемежения 2 непригодна при сроке 300 мс: даже при 0% потерь лишь 24/120 кадров для 8+1 |
|
||||
| `KEYFRAME RECOVERY` | Две потери в одном блоке: 55/60 без усиления, 60/60 с усилением, в обоих окнах |
|
||||
| `NET VIDEO RATE AFTER OUTER FEC` | 8+1 с усилением NORMAL: **424,922 / 425,142 кбит/с**; равномерная 8+2: около 409,4 / 409,8 кбит/с с учётом частичного блока |
|
||||
| `NORMAL 640x360/10 SUPPORTED IN SOFTWARE MODEL` | `NO` для устойчивой работы на всём интервале 1–5% с инженерным запасом |
|
||||
| `INNER FEC 2/3 VS 3/4 RESULT` | При заданных стираниях кадры одинаковы в сравниваемых схемах; более слабый внутренний код 3/4 не подтвердил общего выигрыша с учётом AWGN-контроля VIDEO-003 |
|
||||
| `BEST NEXT RF CANDIDATE` | Отложен; диагностический программный кандидат: QPSK 500 ксимв/с, inner 2/3, outer 8+1 с усилением опорного блока, SHORT_GOP 400k |
|
||||
| `WHY` | Порог CPU выполнен, но при 5% потерь не показаны 102/600 кадров, запас скорости около 1,04 и нет проверки полного IQ/RF-приёмника |
|
||||
| `TESTS BEFORE / AFTER` | VIDEO-003: 123; до заключительного обзора VIDEO-004: 143; после: **145 passed** |
|
||||
| `BEHAVIOR EQUIVALENT` | `YES` для битов, CRC, пакетов и кадров на фиксированных входах |
|
||||
| `HOT PATH REMAINING BOTTLENECK` | По `cProfile`: Витерби 34,8 мс, поиск преамбулы 27,1 мс на 40 пакетов; отсутствуют timing recovery и IQ carrier tracking |
|
||||
| `VIDEO-SPECIFIC GATE` | **PASS: 145 тестов**, сверка артефактов и повторный замер |
|
||||
| `RF TX` | `0` |
|
||||
| `SDR HARDWARE` | `NOT ACCESSED` |
|
||||
| `COMMIT / PUSH` | `NOT PERFORMED / NOT PERFORMED` |
|
||||
|
||||
Отдельный общий `python tools/quick_gate.py` дал 1070 passed, 2 skipped и
|
||||
1 failed: в этом worktree отсутствует исторический
|
||||
`data/raw/lab064/tx_metadata.json`, нужный проверке Lab065. Целевой VIDEO-шлюз
|
||||
прошёл: 145 passed. Это разные наборы проверок.
|
||||
|
||||
Следующий RF-опыт требует отдельного прямого разрешения. VIDEO-005 в этой
|
||||
работе не начинается.
|
||||
Reference in New Issue
Block a user