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

30 KiB
Raw Permalink Blame History

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:

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 в этой работе не начинается.