Files
SDR-Rover/docs/lab042_hardware_loopback_spec.md
LittleSam129 3d14c75365 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 <noreply@anthropic.com>
2026-08-10 11:39:39 +03:00

211 lines
17 KiB
Markdown
Raw 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.
# Lab042 — техническое задание
## Передача JPEG через настоящий радиотракт: кабельная петля на одном PlutoSDR
Документ предназначен для исполнителя, не участвовавшего в предыдущих лабораторных. Всё, что нужно для работы, изложено здесь.
---
## 1. Зачем эта лабораторная
За Lab001Lab041 собран весь тракт передачи изображения, кроме одного звена: **передатчик ни разу не включался**. Во всём проекте нет ни одного вызова передачи через 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, там появится настоящий уход частоты, и вот там понадобятся наработки Lab021Lab023.
**Не пытайтесь сделать 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. Появляется настоящий уход несущей частоты и расхождение часов. Здесь понадобятся Lab021Lab023.
- **Lab044** — выбор рабочего диапазона и первый выход в эфир на малой мощности.
- Повышение скорости, исправление стираний и передача последовательности кадров — после того, как картинка устойчиво проходит.