From 3d14c753650b8f57b4c4c1d54da1165fc5d42ea8 Mon Sep 17 00:00:00 2001 From: LittleSam129 <1qwe432@gmail.com> Date: Mon, 10 Aug 2026 11:39:39 +0300 Subject: [PATCH] Lab042: add hardware loopback specification Specification for the first transmission through real hardware. The project has no TX call anywhere across Lab001-Lab041, so the whole chain exists but has never been connected to a transmitter. Scope is deliberately minimal: get a JPEG through a cable loopback on a single PlutoSDR and see the picture. Single device means TX and RX share a reference clock, which removes the carrier offset and clock drift that the receiver chain handles weakest. - reuse Lab018 signal parameters unchanged, so hardware is the only new variable - reuse image_fragments, packet, build_radio_frame, find_radio_frame - list the first-time traps: cyclic TX buffer, sample scaling, RX started after TX, undersized RX buffer, automatic gain, receiver saturation - define acceptance criteria and required measurements - state explicitly what is out of scope: retransmission, erasure coding, higher rate, two devices, over-the-air Co-Authored-By: Claude Opus 5 --- docs/lab042_hardware_loopback_spec.md | 210 ++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 docs/lab042_hardware_loopback_spec.md diff --git a/docs/lab042_hardware_loopback_spec.md b/docs/lab042_hardware_loopback_spec.md new file mode 100644 index 0000000..d6cbdf9 --- /dev/null +++ b/docs/lab042_hardware_loopback_spec.md @@ -0,0 +1,210 @@ +# Lab042 — техническое задание + +## Передача JPEG через настоящий радиотракт: кабельная петля на одном PlutoSDR + +Документ предназначен для исполнителя, не участвовавшего в предыдущих лабораторных. Всё, что нужно для работы, изложено здесь. + +--- + +## 1. Зачем эта лабораторная + +За Lab001–Lab041 собран весь тракт передачи изображения, кроме одного звена: **передатчик ни разу не включался**. Во всём проекте нет ни одного вызова передачи через SDR. + +Цель Lab042 — соединить уже готовые части и получить **изображение, прошедшее через настоящий радиотракт**. Не улучшить, не оптимизировать, не измерить дальность. Получить картинку на выходе. + +Всё, что не требуется для этой цели, в Lab042 не делается. + +--- + +## 2. Что уже готово и должно быть переиспользовано + +Ничего из перечисленного писать заново не нужно. + +| Звено | Где взять | +|---|---| +| Разбиение JPEG на фрагменты и сборка обратно | `protocol/image_fragments.py`, примеры в `tests/lab007_image_fragmentation.py` | +| Пакет с CRC32, кодирование и разбор | `protocol/packet.py` | +| Подбор размера и качества JPEG | `tests/lab010_image_optimization.py`, готовые профили в `data/processed/lab010` | +| Формирование радиокадра с преамбулой и маркером | `build_radio_frame` в `tests/lab018_bpsk_radio_frame.py` | +| Фильтр приподнятого косинуса | `root_raised_cosine_taps` там же | +| Модуляция BPSK | `bpsk_modulate` там же | +| Поиск кадра в потоке отсчётов | `find_radio_frame` в `tests/lab019_bpsk_receiver.py` | +| Оценка и коррекция ухода частоты | `estimate_carrier_parameters`, `correct_phase_and_frequency` там же | +| Демодуляция и разбор кадра | `bpsk_demodulate`, `decode_radio_frame` там же | +| Работа с Pluto на приём | `tests/lab024a_pluto_rx_capture.py` | + +**Единственное, чего нет в проекте — передача.** Это и есть основной объём работы. + +--- + +## 3. Почему петля на одном устройстве, а не два устройства + +Передатчик и приёмник одного PlutoSDR работают от общего опорного генератора. Поэтому между ними практически нет ухода несущей частоты и не расходятся часы. + +Это снимает ровно те две проблемы, которые в проекте проработаны слабее всего, и позволяет получить картинку сразу. Разведение на два устройства — отдельная лабораторная Lab043, там появится настоящий уход частоты, и вот там понадобятся наработки Lab021–Lab023. + +**Не пытайтесь сделать Lab042 и Lab043 одной работой.** Разница между ними — вся сложность синхронизации. + +--- + +## 4. Требования безопасности + +Обязательны к исполнению. Это правило 8 проекта, оно не формальное. + +1. Выход передатчика соединяется с входом приёмника **только кабелем через аттенюатор**. Рекомендуемое ослабление 30 дБ. +2. **Антенну на передатчик не подключать.** Выход в эфир в этой лабораторной не выполняется ни при каких условиях. +3. Передатчик не включать при отключённом кабеле: выход без нагрузки вреден для оконечного каскада. +4. Усиление передатчика начинать с минимального и поднимать только при необходимости. + +--- + +## 5. Параметры тракта + +Все значения взяты из Lab018 и менять их в этой лабораторной **запрещено**. Причина: переход на железо сам по себе вносит достаточно неизвестных. Менять одновременно и параметры сигнала — значит потерять возможность понять причину отказа. + +| Параметр | Значение | Источник | +|---|---|---| +| Символьная скорость | 20 000 симв/с | `SYMBOL_RATE`, Lab018 | +| Отсчётов на символ | 32 | `SAMPLES_PER_SYMBOL`, Lab018 | +| Частота дискретизации | 640 000 Гц | произведение двух предыдущих | +| Скругление фильтра | 0,35 | `RRC_ROLLOFF`, Lab018 | +| Длина фильтра | 10 символов | `RRC_SPAN_SYMBOLS`, Lab018 | +| Преамбула | 64 бита | `PREAMBLE_BIT_COUNT`, Lab018 | +| Слово синхронизации | 0xD391 | `RADIO_SYNC_WORD`, Lab018 | +| Защитный интервал | 16 символов | `GUARD_SYMBOL_COUNT`, Lab018 | +| Амплитуда передачи | 0,70 | `TX_AMPLITUDE`, Lab018 | + +Полезная скорость получается около 20 кбит/с. Для картинки в несколько килобайт это единицы секунд. Этого достаточно: цель — картинка, а не скорость. + +### Параметры PlutoSDR + +| Параметр | Значение | Примечание | +|---|---|---| +| Адрес устройства | `ip:192.168.2.1` | как в Lab024a | +| Несущая передачи и приёма | 435 МГц | обе одинаковые | +| Частота дискретизации | 640 000 | совпадает с трактом | +| Полоса радиочастотного тракта | 200 000 Гц | минимум Pluto, сигнал занимает около 27 кГц | +| Усиление передатчика | начать с −40 дБ | допустимый диапазон от −89 до 0 | +| Режим усиления приёмника | `manual` | автоматика мешает измерениям | +| Усиление приёмника | начать с 20 дБ | подобрать по амплитуде | +| Циклический буфер передачи | **выключен** | см. раздел 7 | + +Про несущую: 435 МГц выбрана потому, что нижняя граница PlutoSDR составляет около 325 МГц, а целевой диапазон проекта ниже 350 МГц находится у самого края. Поскольку передача идёт по кабелю и в эфир не выходит, выбор частоты здесь ни на что не влияет. Вопрос рабочего диапазона решается отдельно перед Lab044. + +--- + +## 6. Порядок работы + +**Передающая сторона** + +1. Взять исходное изображение из `data/raw`, привести к профилю из Lab010 так, чтобы JPEG получился не крупнее 5 КБ. +2. Разбить на фрагменты через `protocol/image_fragments.py`. +3. Каждый фрагмент упаковать в пакет с CRC32 через `protocol/packet.py`. +4. Каждый пакет обернуть в радиокадр через `build_radio_frame`. +5. Промодулировать BPSK и отфильтровать. +6. Привести к целым числам и передать. + +**Приёмная сторона** + +1. Запустить приём **до** начала передачи. +2. Найти кадры через `find_radio_frame`. +3. Скорректировать фазу и частоту. +4. Демодулировать, разобрать кадр, проверить CRC32. +5. Собрать изображение из уцелевших фрагментов и сохранить на диск. + +Приём и передача идут в одном процессе. Приём запускается первым — иначе начало первого кадра теряется безвозвратно. + +--- + +## 7. Ловушки, на которых спотыкаются в первый раз + +Перечислено то, что почти наверняка будет сделано неправильно без предупреждения. + +1. **Циклический буфер передачи.** У PlutoSDR буфер передачи по умолчанию повторяется бесконечно. Кажется, что передан один кадр, а передаётся бесконечный поток. Признак: приёмник видит тысячи копий одного кадра, а передача не заканчивается. Буфер надо явно выключить и явно освобождать после передачи. + +2. **Масштаб отсчётов.** PlutoSDR принимает целые числа, а не дробные значения от минус единицы до единицы. Готовый сигнал надо умножить на масштабный множитель, обычно 2 в степени 14. Признак ошибки: передаётся почти тишина, приёмник ничего не находит. + +3. **Приём запущен после передачи.** Начало кадра теряется, преамбула не находится. Признак: `find_radio_frame` не срабатывает при заведомо исправном сигнале. + +4. **Размер приёмного буфера меньше кадра.** Кадр не помещается целиком, поиск преамбулы срывается. Буфер должен вмещать кадр с запасом минимум вдвое. + +5. **Автоматическая регулировка усиления приёмника.** Меняет амплитуду в процессе и портит оценку. Режим должен быть ручным. + +6. **Насыщение приёмника.** При слишком слабом ослаблении сигнал упирается в потолок и созвездие разваливается, хотя уровень кажется отличным. Признак: демодуляция не работает при очень сильном сигнале. Лечится увеличением ослабления, а не усилением. + +7. **Переходный процесс в начале передачи.** Первые несколько десятков отсчётов недостоверны. Поэтому в тракте есть защитный интервал в 16 символов — его нельзя убирать. + +--- + +## 8. Что считается выполненной работой + +Лабораторная принимается, если выполнено всё перечисленное. + +**Обязательный результат** + +1. Файл принятого изображения на диске, открывающийся просмотрщиком. +2. Принятое изображение совпадает с переданным при отсутствии потерь — сравнение по контрольной сумме всего файла. +3. Работа воспроизводится: два запуска подряд дают одинаковый успешный результат. + +**Обязательные измерения** + +| Величина | Как получить | +|---|---| +| Размер переданного JPEG, байт | из файла | +| Число фрагментов и пакетов | из разбиения | +| Число принятых кадров | счётчик приёмника | +| Число кадров, не прошедших CRC32 | счётчик приёмника | +| Доля успешно принятых фрагментов | отношение | +| Полное время передачи, секунды | измерение | +| Фактическая полезная скорость, кбит/с | расчёт из двух предыдущих | +| Усиление передатчика и приёмника | из настроек устройства | +| Ослабление аттенюатора, дБ | из состава схемы | + +**Обязательные файлы в `data/processed/lab042`** + +- принятое изображение; +- CSV с измерениями из таблицы выше; +- текстовый отчёт; +- график созвездия принятого сигнала; +- график спектра принятого сигнала. + +**Требования к коду** + +- Ничего из `protocol/` не переписывать. Только использовать. +- Параметры тракта из раздела 5 не менять. +- Все константы вынести в начало файла с указанием источника, как это сделано в Lab041. +- Никаких вписанных руками результатов: каждое число в отчёте должно вычисляться из измерений текущего запуска. Это отдельно проверяется при приёмке. +- Файл лабораторной: `tests/lab042_pluto_image_loopback.py`, запуск через `python -m tests.lab042_pluto_image_loopback` из корня проекта. + +--- + +## 9. Что в этой лабораторной делать не надо + +Перечислено, чтобы не расширять объём. + +- Не реализовывать повторную передачу потерянных фрагментов. Потери фиксируются, но не восстанавливаются. +- Не подключать исправление стираний из `protocol/packet_erasure_fec.py`. +- Не поднимать скорость и не менять модуляцию. +- Не выходить в эфир и не подключать антенну. +- Не работать с двумя устройствами. +- Не трогать логику сеансов, аварийной остановки и приоритетов — она к передаче картинки отношения не имеет. + +Всё это относится к последующим лабораторным. + +--- + +## 10. Порядок приёмки + +1. Исполнитель выполняет работу и сообщает о готовности. +2. Проверяется `python tools/quick_gate.py` — должен проходить. +3. Проводится аудит: соответствие разделу 8, отсутствие вписанных результатов, происхождение каждого числа в отчёте. +4. При наличии замечаний они оформляются списком с указанием файла и строки. +5. После приёмки в `PROJECT_LOG.md` добавляется новая запись по принятому в проекте образцу. + +--- + +## 11. Что дальше + +- **Lab043** — разведение на два устройства: передаёт PlutoSDR, принимает RTL-SDR. Появляется настоящий уход несущей частоты и расхождение часов. Здесь понадобятся Lab021–Lab023. +- **Lab044** — выбор рабочего диапазона и первый выход в эфир на малой мощности. +- Повышение скорости, исправление стираний и передача последовательности кадров — после того, как картинка устойчиво проходит.