Files
SDR-Rover/docs/rf/RF_001_PLAN.md
2026-09-17 15:05:44 +03:00

186 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# RF-001 — подготовка первого QPSK-пакетного опыта
**Статус: PREPARED / NOT_RUN.** Это программная подготовка после коммита
VIDEO-005 `6df5f8a`. SDR не открывался; приёма и передачи через него не было.
`RF TX = 0`. Первый аппаратный сеанс требует отдельной постановки и прямого
разрешения.
## Цель и граница
Будущий опыт проверит известные PHY-пакеты через два Auron HackRF Plus.
Утверждён один начальный режим: QPSK, **500 000 символов/с**, внутренний FEC
**2/3**, прикладная нагрузка **256 байт**, пауза **5 мс**, **100 пакетов** с
номерами 0–99 и seed `20260917`. H.264, камера, видеотранспорт, внешний
erasure FEC и адаптивное переключение не участвуют. До первого аппаратного
результата нагрузку не увеличивать, а паузу не уменьшать.
```text
TX: payload(seed, sequence) → build_frame(QPSK, 2/3) → shape_packet(RRC)
→ IQ-файл → [будущий аппаратный IQSink]
RX: [будущий аппаратный IQSource] → исходный raw IQ-файл
→ receive_iq_stream() VIDEO-005 → CRC-valid пакеты
→ отдельное сравнение с TX-ведомостью и отчёт
```
PHY-приёмник не получает TX-границы, payload, истинную фазу, CFO, момент
выборки или ожидаемое число пакетов. SHA и ошибки сравниваются после строгого
декодирования. `receive_iq_stream()` для RF-001 не менялся. Исторический
`build_frame()` ставит в пакет тип 3; здесь содержимое — тестовые байты,
видеосборщик не вызывается.
## Файловые инструменты
`tools/qpsk_rf_tx.py` создаёт весь IQ без аппаратных импортов в новом
каталоге `data/raw/rf001/offline_qpsk_100_packets/`. Существующие файлы он
не перезаписывает. Нагрузка каждого номера получается из SHA-256 по seed,
номеру и счётчику блока, без зависимости от версии генератора NumPy.
```powershell
python -B -X utf8 tools/qpsk_rf_tx.py
```
`tx_waveform.c64le` — сырые little-endian complex64, 8 байт на комплексный
отсчёт, без заголовка. `tx_metadata.json` содержит `test_id`, UTC-время,
режим, номинальный цифровой сдвиг несущей 125 кГц, seed, номера и SHA-256
payload/пакетов, паузу, dtype, число/длительность отсчётов, SHA IQ и
TX-границы. Последние остаются только в ведомости. Форма каждого пакета
включает по 64 защитных отсчёта на концах; между массивами вставлены
39 872 нулевых отсчёта. Итого пауза вместе с защитными участками — ровно
**40 000 отсчётов = 5 мс**. Это цифровая форма без аппаратной калибровки
амплитуды и преобразования к формату TX устройства.
`tools/qpsk_rf_rx.py` читает `c64le` и вызывает существующий приёмник
VIDEO-005. Необязательная TX-ведомость читается **после** вызова приёмника.
Для будущего сохранённого аппаратного файла предусмотрен вход
`--iq-format cs8`: чередующиеся знаковые байты I/Q преобразуются в
complex64 для анализа, исходный файл не меняется; отдельно считаются
коды насыщения −128/127. Это файловый конвертер, не аппаратный адаптер.
```powershell
python -B -X utf8 tools/qpsk_rf_rx.py `
--iq-file data/raw/rf001/offline_qpsk_100_packets/tx_waveform.c64le `
--truth-metadata data/raw/rf001/offline_qpsk_100_packets/tx_metadata.json `
--report data/processed/rf001/offline_roundtrip.json `
--numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
```
Путь `--numba-packages` относится к текущему ПК; на втором ноутбуке Numba
берётся из его окружения. Без TX-ведомости инструмент сообщает кандидатов
преамбулы и CRC-пакеты, номера, повторы и оценки CFO/фазы/такта, но не
объявляет точность или потери относительно неизвестного ожидаемого списка.
## Программный круг на 100 пакетах
| Показатель | Результат |
|---|---:|
| IQ | 8 833 828 отсчётов; 1,1042285 с; 70 670 624 байта |
| SHA-256 IQ | `7cd81395efaa88b623b7e4e5a02e3a80b52185007397ea56ceaacc13353974b2` |
| Кандидаты корреляционного поиска / отвергнутые | 557 / 457 |
| CRC-valid / точные пакеты | 100 / 100 |
| Пропущенные / дубли | 0 / 0 |
| Raw BER по всем 100 принятым пакетам | 0 / 322 500 кодированных битов |
| Ошибки после FEC | 0 в сопоставленных пакетах |
**557 — кандидаты корреляции, а не 557 принятых преамбул.** Только 100
прошли PHY/FEC/CRC. Raw BER получен отдельным повтором штатных PHY-функций
после первого приёма. При потере пакетов полный raw BER неизвестен: API
VIDEO-005 не отдаёт мягкие решения отвергнутых кандидатов. Тогда отчёт
покажет BER на CRC-valid пакетах отдельно, а `raw_ber` оставит `null`.
Условный BER нельзя выдавать за BER всего канала.
Полный машинный отчёт сохранён в `data/processed/rf001/offline_roundtrip.json`;
исходный IQ и TX-ведомость лежат в игнорируемом Git `data/raw/rf001/`.
## Будущий захват и аппаратная граница
Следующий этап сначала сохраняет **исходные** байты аппаратного RX, затем
анализирует их офлайн. Небольшая граница `IQSource` создаёт raw IQ-файл и
`capture_metadata.json`; файловый анализатор читает сохранённый файл.
`IQSink` сможет принять заранее проверенный TX-файл только после отдельного
допуска. PHY-модули не знают о HackRF API; собственный libusb-слой не нужен.
Предлагаемый файловый контракт capture: `capture.cs8` без заголовка, пары
знаковых байтов `I0,Q0,I1,Q1,…`; исходный файл не нормализовать и не
перезаписывать. `capture_metadata.json` создаётся рядом. Неизвестные поля
остаются `null` или `NOT_RUN`, а не заполняются нулями:
```json
{
"schema_version": 1,
"status": "NOT_RUN",
"raw_iq_file": "capture.cs8",
"iq_format": "cs8_interleaved_signed_iq",
"sample_rate_hz": 8000000,
"sample_count": null,
"raw_iq_sha256": null,
"capture_started_utc": null,
"center_frequency_hz": null,
"nominal_digital_carrier_offset_hz": 125000,
"clock_mode": "NOT_RUN",
"clock_link": "NOT_RUN",
"estimated_sample_clock_offset_ppm": null,
"cfo_series_hz": null,
"timing_drift_series_symbols": null,
"receiver_serial": null,
"gain_settings": null,
"common_clock": "NOT_RUN",
"tx_underrun_observations": [],
"rx_overrun_observations": [],
"rx_clipping_rail_codes": null,
"counter_observation_complete": false,
"capture_validity": "NOT_RUN",
"command_log": []
}
```
В metadata захвата потребуются время, путь/формат/SHA raw IQ, частота
дискретизации, центр RF, номинальный цифровой сдвиг, число отсчётов,
серийные номера, gain, состояние общей опоры, журнал команд и **все**
наблюдения underrun/overrun/clipping по ходу сеанса. Неполный или нечистый
счётчик делает результат непригодным для PASS; конечный ноль не отменяет
промежуточную потерю. Сейчас аппаратного источника/стока и фактического
capture metadata нет — это будущая отдельно разрешённая работа.
Дрейф частоты дискретизации не моделировался в VIDEO-005 и остаётся отдельным
риском для реального захвата.
RF-001 делится на два будущих режима с отдельным разрешением на каждый выход
в эфир. **RF-001A** использует проводную общую опору 10 МГц только как
лабораторный baseline: TCXO → MASTER → MASTER CLKOUT → SLAVE CLKIN. Предыдущие
лабораторные проверки фиксировали MASTER и SLAVE `reg29 = 0x26`, `SLAVE CLKIN =
DETECTED`. Это **исторические данные**, а не свежая проверка подключения.
**RF-001B** использует независимые такты: провод CLKOUT → CLKIN снят. Именно
этот вариант соответствует архитектуре ровера и НСУ без проводной опоры.
Для сравнения A/B одинаковыми остаются RF-частота, 500 ксимв/с, FEC 2/3,
payload 256 байт, пауза 5 мс, 100 пакетов, TX-уровень, RX-усиления,
геометрия, антенны и TX-волна. Оба сеанса сначала сохраняют исходный RX IQ и
полный журнал счётчиков. В RF-001B по принятой преамбуле каждого пакета и
известным TX-номерам нужно оценить CFO по времени и наклон ошибки момента
выборки, затем разницу частот дискретизации. Эти оценки делаются **после**
строгого PHY/FEC/CRC; потери и пропуски не подменяются известными границами
передатчика. Программная сетка CLOCK-001 проверила до ±50 ppm, но фактический
ppm плат ещё не измерен. Частота RF, gain, кабели, антенны и уровень сигнала
для нового опыта не утверждены здесь; они войдут в отдельный аппаратный
preflight.
## Форма отчёта и следующий критерий
Будущий отчёт содержит `RF-001 STATUS`, режим, число кандидатов преамбулы,
CRC-valid и точных пакетов, долю точных, raw BER с областью расчёта,
ошибки после FEC, дубли/пропуски, медиану CFO и P95 |CFO|, оценки фазы/такта,
TX underruns, RX overruns, RX clipping, общую опору
`DETECTED / NOT_DETECTED`, SHA capture и причины отказа. Сейчас аппаратные
поля — `NOT_RUN`, а не нули.
Для будущего короткого OTA smoke test, если захват и счётчики чисты:
не менее 99 точных из 100 — GOOD; 95–98 — DIAGNOSTIC/PARTIAL; менее 95 —
не переходить к видео. Это предварительная классификация, не
эксплуатационная норма. Программные 100/100 не доказывают RF PASS.
Только после отдельного аппаратного PASS: сравнение пауз 5 → 2 → 1 → 0,5
→ 0 мс при 256 байтах. После выбора паузы — отдельно 256 → 512 →
максимально допустимый рабочий payload. Здесь матрица не выполняется.
**RF-001 HARDWARE STATUS = NOT_RUN. SDR HARDWARE = NOT_ACCESSED. RF TX = 0.**
Следующий шаг — отдельное согласование preflight и одного контролируемого
сеанса; автоматического перехода к эфиру нет.