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

167 lines
15 KiB
Markdown
Raw Permalink 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.
# CLOCK-001: независимые такты перед RF-001
17 сентября 2026 года. Статус **PARTIAL**: программный приёмник прошёл основную
сетку до ±50 ppm, но потерял длинные пакеты при ±100 ppm. Последняя точка
служит только стресс-тестом. Частоты реальных генераторов Auron HackRF Plus
не измерялись. SDR не открывался, `RF TX = 0`. Данные каждого запуска
сохранены в `data/processed/clock001/results.json`.
## Модель и вход приёмника
TX строит QPSK/FEC 2/3/RRC при номинальных 8 Мвыб/с и 500 ксимв/с. Для
приёмника с независимой частотой `Fs_RX = Fs_TX · (1 + ε)`, где
`ε = ppm · 10⁻⁶`, программа берёт комплексную TX-волну в моменты
`n / (1 + ε)` по её исходной сетке. Дробные отсчёты получаются линейной
интерполяцией. Поэтому ошибка момента **накапливается по времени**, а не
подменяется одним постоянным сдвигом. Интерполяция не описывает аналоговый
тракт АЦП, шум генераторов или аппаратное квантование.
CFO добавляется отдельно как поворот с частотой в герцах физического времени
RX; начальная фаза и AWGN задаются отдельными параметрами. Даже при нулевом
внешнем CFO цифровая несущая 125 кГц из-за изменения частоты выборки даёт
остаток `(125000 + CFO) / (1 + ε) − 125000` Гц относительно номинального
цифрового смесителя. Отчёт хранит и заданный CFO, и этот ожидаемый остаток;
один не выдаётся за другой. Частотный тест проверяет оба эффекта раздельно.
Программа `tools/clock001.py` строит по три пакета каждого размера с паузой
5 мс и seed `20260917`. Нагрузка 256 байт совпадает с RF-001; для 512 и
1012 байт та же SHA-последовательность продлена. **1012 байт** заполняют
допустимый PHY-пакет 1024 байта с 12 байтами заголовка и CRC. Во всех
39 точках ppm-сетки приёмник получает только полученный IQ и номинальный
радиорежим. TX-границы, исходные пакеты, заданный ppm/CFO и число пакетов
используются только после декодирования для оценки.
```powershell
python -B -X utf8 tools/clock001.py `
--numba-packages C:\Users\user\Desktop\projects\SDR_Rover\.lab053_cpu_runtime\packages
```
Параметр с локальным путём к Numba нужен на этом ПК; в обычном окружении с
зависимостями проекта он не требуется. Команда отказывается перезаписывать
готовый отчёт.
## Строгие результаты
В таблице каждая ячейка означает число **точных пакетов из трёх** после
PHY/FEC/CRC. CFO, фаза и AWGN в этой сетке равны нулю/отсутствуют.
| Payload | 0 | ±1 ppm | ±5 ppm | ±10 ppm | ±20 ppm | ±50 ppm | ±100 ppm, стресс |
|---|---:|---:|---:|---:|---:|---:|---:|
| 256 байт | 3/3 | 3/3 в обе стороны | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| 512 байт | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 |
| 1012 байт | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | 3/3 | **0/3** |
Основная сетка 0, ±1, ±5, ±10, ±20 и ±50 ppm: **99/99**. Наибольшая
симметричная проверенная точка со 100% точных пакетов для всех размеров:
**±50 ppm**. Для 256 и 512 байт стресс ±100 ppm тоже дал 3/3 в обе стороны.
Одиночный пакет 1012 байт при −100 и +100 ppm дал 0/1; в обоих случаях
найден один корреляционный кандидат, но CRC-пакета нет. Значит, новый поиск
преамбулы перед следующим пакетом не устраняет эту потерю внутри текущего
длинного пакета. При ±100 ppm модель накапливает по нему ±0,7572 символа.
Контроль с отдельной кубической интерполяцией повторил для одиночного
1012-байтного пакета 1/1 при ±50 и 0/1 при ±100 ppm. Вывод не зависит
только от выбора линейного интерполятора в основном опыте.
Текущий приёмник оценивает начало **каждого** пакета заново, затем выбирает
его символы с постоянным шагом 16 отсчётов. Для 1012 байт при −50 ppm
медианная ошибка в начале/расчётная ошибка в конце составили
−0,0325 / +0,3461 символа; при +50 ppm +0,0322 / −0,3464. Разность по
модели равна ±0,3786 символа. Начальную ошибку считаем по началу принятого
CRC-пакета и известной **после приёма** TX-шкале. Конечная ошибка
экстраполирована из заданного ppm при фиксированном шаге приёмника; это не
независимое измерение последнего символа. Для потерянного пакета эти оценки
равны `null`, а введённый моделью дрейф указан отдельно.
В JSON `correlation_candidates` считает кандидатов поиска. Поле
`detected_packets` равно числу CRC-valid пакетов: нынешний API не выдаёт
отдельное число пакетов, распознанных до CRC. Поля точности и потерь
считаются отдельно по TX-ведомости после приёма.
Отдельно проверены шесть сочетаний для **256 байт**, каждое с тремя пакетами:
| ppm | CFO | Фаза | Eb/N0 | Точные пакеты |
|---:|---:|---:|---:|---:|
| +5 | +20 Гц | +15° | 9 и 12 дБ | 3/3 при каждом уровне |
| +10 | +100 Гц | +90° | 9 и 12 дБ | 3/3 при каждом уровне |
| +20 | +100 Гц | −45° | 9 и 12 дБ | 3/3 при каждом уровне |
Итого **18/18**. Шум задан прежней программной AWGN-моделью VIDEO-005;
это не оценка реального RF-канала.
## Компенсация и скорость
Для основной сетки повторной оценки момента по преамбуле каждого пакета
хватило. **Непрерывное слежение в рабочий приёмник не добавлялось.** Для
расширения диапазона до ±100 ppm на пакете 1012 байт потребовалась бы
коррекция внутри пакета, например отдельное исследование детектора ошибки
момента [Gardner для BPSK/QPSK](https://doi.org/10.1109/TCOM.1986.1096561)
с интерполяцией и петлёй. [Документация GNU Radio](https://www.gnuradio.org/doc/doxygen/classgr_1_1digital_1_1symbol__sync__cc.html)
показывает такой класс синхронизатора и его параметры. Перед включением
понадобятся строгие CRC-тесты на всей сетке, проверка без истинного ppm и
новый замер скорости. Старый BPSK-детектор сюда не переносился.
На каноническом потоке VIDEO-005 из 32 длинных пакетов с добавленными
+20 ppm, +20 Гц CFO, фазой +15° и Eb/N0 9 дБ получено **32/32** при каждом
из трёх прогретых запусков. Времена приёмника: 0,272 / 0,262 / 0,262 с;
длительность IQ 0,485764 с; медианный **RADIO RECEIVER REALTIME FACTOR =
0,540**. Построение канала и ресемплирование в это время не входят. Для
сравнения, сохранённый ориентир VIDEO-005 равен 0,578 на другом входе;
разница не доказывает ускорения. Первый запуск ppm-сетки включал JIT и не
использован для оценки скорости. Порог 0,67 на этом ПК выполнен.
## Code quality audit
Рабочий `receive_iq_stream()` и его защитные проверки не менялись. Новый
пересчёт временной шкалы, сравнение с эталоном и запись JSON остаются вне
пути приёма. Отдельный `cProfile` того же 32-пакетного IQ занял 0,293 с;
его время включает накладные расходы профилировщика и не подставляется в
фактор 0,540. Основные этапы:
| Этап | Время, мс | Доля профиля | Вызовы | Основные массивы и копии |
|---|---:|---:|---:|---|
| Цифровое смещение несущей | 16,4 | 5,6% | 1 | Осциллятор и baseband |
| Согласованный RRC | 62,1 | 21,2% | 1 | Выход и внутренние FFT-буферы |
| Поиск преамбул | 47,6 | 16,2% | 1 | Две корреляции и массивы энергии |
| Восстановление момента | 9,9 | 3,4% | 32 | Индексы и символы каждого кандидата |
| Оценка CFO и фазы | 12,2 | 4,2% | 32 | Исправленные символы |
| PHY-заголовок | 0,8 | 0,3% | 32 | Короткие массивы заголовка |
| Слежение за фазой тела | 78,4 | 26,8% | 32 | Копия символов пакета и блоки решений |
| Строгий PHY/FEC/CRC | 54,8 | 18,7% | 32 | Мягкие биты и рабочие массивы декодера |
Число аллокаций NumPy не измерялось; в таблице перечислены видимые по коду
массивы. Resampling создаёт один выходной complex64 IQ и временные массивы
до миллиона отсчётов за блок; в измеренное время приёмника он не входит. Проверки
размеров и конечности IQ оставлены как защита входа; диапазон ppm и длина
пакета проверяются при создании опыта. Проверка эталона находится после
приёмника. Ruff не нашёл неиспользуемых импортов, временных compatibility
wrappers и лабораторных ветвей в новом коде нет. Канонический генератор
32-пакетного VIDEO-005 входа также строит сигнал с нарушениями канала,
который CLOCK-001 не использует; это один офлайн-вызов, не приёмный hot path.
Удалять или переписывать его здесь нет оснований. Поведение VIDEO-005
проверено его неизменённым шлюзом: 178 тестов прошли.
| Предмет | Место | Почему проверен | Решение |
|---|---|---|---|
| Дополнительный IQ от канонического генератора | `tools/clock001.py`, `run()` | Создаётся, но не участвует в CLOCK-входе | **KEEP**: однократная офлайн-цена за неизменный эталон VIDEO-005 |
| Длинная оркестрация опыта | `tools/clock001.py`, `run()` | Собирает сетку, сочетания и замер | **KEEP**: не исполняется в рабочем приёмнике; шаги явно разделены |
| Проверка конечности всего TX IQ | `tools/clock001.py`, `sample_independent_clock()` | Один проход по большому массиву | **KEEP**: защита от повреждённого входа до интерполяции |
В CLOCK-001 нет внешнего erasure FEC и видеотранспорта: это опыт с PHY-пакетами,
поэтому их время нельзя включать в фактор радиоприёмника.
## Следующий аппаратный план
План RF-001 разделён на **RF-001A** с проводной общей опорой 10 МГц как
лабораторным baseline и **RF-001B** с независимыми тактами. В B провод
CLKOUT → CLKIN отключён. Остальные параметры и TX-волна должны совпасть;
оба режима сохраняют исходный RX IQ и полные наблюдения счётчиков. В B
нужны последовательности оценок CFO и моментов пакетов, чтобы после
приёма оценить их изменение во времени и фактическую разницу частот
дискретизации. Моделируемые ppm не считаются характеристикой плат.
**Готовность A и B: да, только к подготовке контролируемого опыта.**
Фактические частоты, соединения, gain и RF-условия ещё не проверены. Для
каждого аппаратного сеанса потребуется отдельный preflight и прямое
разрешение. CLOCK-001 не открывала SDR, не меняла аппаратную конфигурацию
и не выполняла RF TX/RX. Коммита и push для этого этапа нет.