CLOCK-001: validate independent-clock QPSK receiver
This commit is contained in:
185
docs/rf/RF_001_PLAN.md
Normal file
185
docs/rf/RF_001_PLAN.md
Normal file
@@ -0,0 +1,185 @@
|
||||
# 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 и одного контролируемого
|
||||
сеанса; автоматического перехода к эфиру нет.
|
||||
Reference in New Issue
Block a user