Files
SDR-Rover/docs/video/VIDEO_002.md

210 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.