added docs

This commit is contained in:
Ayzen
2026-10-16 18:35:02 +03:00
parent b88d704126
commit ad2b3e555a
19 changed files with 3719 additions and 663 deletions
+300
View File
@@ -0,0 +1,300 @@
# Калибровка и предобработка
Препроцессор (`data_preprocessor`) по очереди применяет к каждой коллекции четыре
шага и только потом отдаёт её на обработку. Зачем нужен каждый шаг, объяснено в
главе [Как работает радар](principles.md).
## Цепочка предобработки
Для каждой пары и каждой частотной точки:
| Шаг | Формула | Набор |
| --- | --- | --- |
| 1. Калибровка | S21 ← S21 / S21_through | набор калибровки (through) |
| 2. Вычитание референса | S21 ← S21 − S21_ref / S21_through | набор референса |
| 3. Режекторный фильтр | S21 ← S21 · m(f) | настройки `preprocess.notch` в профиле |
| 4. Калибровка по объекту | S21 ← S21 · F | набор калибровки по объекту, если выбран |
Референс делится на through один раз при загрузке, поэтому вычитается уже
откалиброванный фон. Точки, где |S21_through|² не больше 10⁻¹², на шаге 1 остаются как
есть, без деления. Окно съёма и номер коллекции не меняются.
У каждого набора должна быть каждая пара сбора, а сетка частот — совпадать с
развёрткой: то же число точек, а каждая частота отличается от своей не больше чем на
10⁻⁵ её значения, но допуск не меньше 1 мГц (на 6 ГГц — 60 кГц). Наборы проверяются при запуске
препроцессора, и неподходящий набор его останавливает. Если это случилось, пока
программа ждёт готовности процессов, **Start** отказывает с сообщением
``Failed to start pipeline: RuntimeError: Process `data_preprocessor` exited with code 1.``
и текстом ошибки. Если позже, в журнале окна появляется отчёт о завершении
процесса, а программа перезапускает конвейер с нарастающей паузой.
Коллекцию, которая не прошла проверку уже во время
работы, препроцессор отбрасывает и пишет об этом в свой журнал
`python_app/runtime/logs/data_preprocessor.err.log`. В окне программы это видно
только по тому, что изображение перестаёт обновляться.
## Наборы
| Набор | Каталог | Обязателен |
| --- | --- | --- |
| S21 Calibration — калибровка (through) | `python_app/data/s21_calibration/` | да |
| S21 Reference — референс | `python_app/data/s21_reference/` | да |
| Object Calibration — калибровка по объекту | `python_app/data/s21_object_calibration/` | нет |
Набор — архив NPZ с массивами частот и S21 по парам и JSON-файл рядом с описанием
(формат — в главе [Данные на диске](data.md)). Наборы лежат в подкаталогах с именем
`radar_key` — ключа конфигурации радара:
- у LibreVNA ключ складывается из модели, серийных номеров, начала и конца
развёртки, числа точек, полосы ПЧ и мощности, а у многоприборной схемы ещё из
положений ключей;
- у радиофотонного радара ключ — хеш выходной полосы, фазовой калибровки, параметров
источника, положений ключей и настроек лазера; лазер входит в ключ, если плата
лазеров включена в профиле или источник — плата RFG.
Программа показывает только наборы текущего ключа. Если изменить любую из этих
величин (например, число точек), старые наборы пропадают из списков, а выбор
сбрасывается с записью `Preprocess selection reset: <старый ключ> -> <новый ключ>; cleared {...}`
в журнале. Так программа не даёт применить калибровку, снятую при других
настройках. Если вернуть прежние настройки, наборы снова появятся в списках, но
выбрать их придётся заново.
Наборы применяются при запуске сбора: программа пересобирает из выбранных наборов
файлы `python_app/runtime/*_bundle.bin` и заново запускает препроцессор. Запуск — это
**Start**, а также продолжение сбора после приостановки: после съёма набора,
временного референса или нейтральных наборов сбор, если он шёл, продолжается уже с
новыми наборами. Смена выбора в списке во время сбора применится при следующем
запуске.
Перед запуском программа проверяет наборы и, если что-то не так, отказывается
запускаться, ничего не остановив. Окно ошибки показывает
`Failed to start pipeline: <тип ошибки>: <текст>`, где текст — один из этих:
| Условие | Сообщение |
| --- | --- |
| не выбраны калибровка или референс | `Select all required preprocess sets in Preprocessing Panel before Start: S21 Calibration, S21 Reference` |
| файла набора нет для текущего ключа | `Missing set files for <вид>/<radar_key>/<имя>` |
| в наборе нет какой-то пары сбора | `Selected <набор> set does not cover requested run combos` |
| архив повреждён или содержит не числа | `Corrupted preprocess set <вид>/<ключ>/<имя>: …` |
| калибровка по объекту не подходит | см. раздел «Калибровка по объекту» |
## Окно Preprocessing Setup
Открывается кнопкой **Preprocessing…**. Окно не модальное: пока оно открыто, главным
окном можно пользоваться.
Группа **Preprocess Sets**:
| Элемент | Что делает |
| --- | --- |
| **Set name** | имя нового набора; по умолчанию `set_001`. Для этого вида набора и этого ключа радара имя должно быть новым |
| **Create Neutral S21 Sets** | создаёт нейтральные наборы (см. ниже). Кнопка есть только у радиофотонного радара, у многоприборной схемы и у одиночного LibreVNA в режиме `mock` |
| **Refresh Sets** | перечитывает списки наборов с диска и каталог вариантов радара |
| **Sweeps per combo (median)** | сколько развёрток снимать на каждую пару, от 1 до 99, по умолчанию 5. В набор идёт медиана по каждой частоте, отдельно по вещественной и мнимой части: при трёх развёртках и больше одиночный сбой развёртки в набор не попадает. Это же число развёрток берут временный референс и калибровка по объекту |
| **Radar Config Variants** → **Directory**, **Browse…** | каталог с профилями JSON для съёма наборов сразу под несколько настроек развёртки (см. ниже). Под полем — итог просмотра: `Directory: <каталог> \| json=…, valid=…, skipped=…, duplicates=…` (файлов JSON, подходящих вариантов, пропущенных, повторов) или `No radar config directory selected.` |
| **Capture current combo for all found radar configs** | включает съём по всем вариантам из каталога |
| **S21 calibration**, **S21 reference** | выбор набора калибровки и референса для следующего **Start** |
| **Object calibration** | выбор калибровки по объекту; **Off** — не применять |
| **Create…** | открывает окно калибровки по объекту |
Группа **Capture All Antenna Pairs**:
| Элемент | Что делает |
| --- | --- |
| **Active type**, **Progress**, **Current combo** | вид снимаемого набора, сколько пар снято из скольких, какая пара следующая; без съёма — `<none>`, `0 / 0`, после последней пары — `<complete>` |
| **Start S21 Calibration**, **Start S21 Reference** | начинают съём набора |
| **Capture Current Combo** | снимает следующую пару |
| **Capture All Remaining** | снимает подряд все оставшиеся пары |
| **Undo Last Capture** | отменяет последний съём, чтобы переснять пару |
| **Save Captured Set** | сохраняет набор и выбирает его; доступна, когда сняты все пары |
| **Abort Sequence** | прерывает съём и отбрасывает снятое |
Ниже — журнал съёма (`S21 Calibration: 1/8 | input=0 output=0` на каждую пару),
строка состояния (сначала `Ready`) и графики модуля и фазы последней снятой развёртки
(до первого съёма — `Preview will appear after the first successful capture.`).
Последняя развёртка рисуется и в главном окне.
## Съём калибровки и референса
1. Выберите профиль и настройки радара. Наборы привязаны к ключу радара, поэтому
снимайте их при тех настройках развёртки, с которыми будете работать.
2. Подготовьте установку. Для калибровки — эталонный тракт для текущей пары; для
референса — пустую сцену: всё, что должно остаться в фоне, на месте, целей нет.
3. Нажмите **Preprocessing…**, задайте **Set name** и
**Sweeps per combo (median)**.
4. Нажмите **Start S21 Calibration** или **Start S21 Reference**. Сбор
приостанавливается, и на время съёма прибором управляет окно предобработки.
5. Снимайте пары кнопкой **Capture Current Combo** или все сразу кнопкой
**Capture All Remaining**. Проверяйте каждую развёртку по графикам; неудачную
переснимите через **Undo Last Capture**. При ошибке съёма уже снятые пары
сохраняются, и съём можно повторить.
6. Когда сняты все пары, нажмите **Save Captured Set**. Набор сохраняется и
выбирается, приостановленный сбор продолжается.
Съём всегда идёт по полной матрице положений ключей, а не только по парам сбора.
- Одиночный LibreVNA: для каждой пары программа выставляет ключи, ждёт время
установления (`run.settling_ms`, в окне — **Settling (ms)**) и снимает нужное
число развёрток этой пары.
- Многоприборная схема при калибровке: прибор снимает всю матрицу, а в набор идёт
только текущая пара, по одной за нажатие. **Capture All Remaining** здесь
недоступна.
- Многоприборная схема при съёме референса: одно нажатие снимает всю матрицу нужное
число раз, и набор сразу готов.
### Варианты радара
Иногда наборы нужны сразу под несколько развёрток — например, под разные полосы
частот. Для этого в **Directory** указывают каталог с профилями JSON. Профиль
считается вариантом, если в его `radar.sweep` есть хотя бы одно из полей
`start_hz`, `stop_hz`, `points`, `if_bandwidth_hz`, `stimulus_power_dbm`; эти поля
накладываются на текущий профиль, повторы одного ключа пропускаются. С включённой
**Capture current combo for all found radar configs** каждое нажатие снимает пару во
всех вариантах подряд, с перенастройкой прибора. **Save Captured Set** сохраняет
по набору на каждый вариант под одним именем, а картинки развёрток — в
`python_app/data/preview_png/<вид>/<имя>/<radar_key>/i<вход>_o<выход>.png`.
## Временный референс
Кнопка **Capture Temporary Reference** в секции **Data Actions** снимает референс
одним нажатием, не открывая окно предобработки. То же действие есть в
веб-интерфейсе и на GPIO-кнопке.
Программа приостанавливает сбор, снимает полную матрицу с текущими настройками
(медиана **Sweeps per combo (median)** развёрток) и сохраняет её как набор
`tmp_reference`, заменяя прежний. Затем она выбирает этот набор, очищает историю
обработки, рисует последнюю развёртку с подписью `Tmp S21 Reference last trace` и
продолжает сбор. Процессор и локатор при этом не перезапускаются, клиенты локатора
не отключаются.
Временный референс нужен, когда сцена или положение радара изменились: после
перестановки, на новом месте, после заметного изменения обстановки.
## Нейтральные наборы
**Create Neutral S21 Sets** сохраняет под именем из **Set name** два набора:
калибровку, равную 1, и референс, равный 0, для всех пар на текущей сетке частот.
С ними данные проходят предобработку без изменений. Они нужны, чтобы запустить
конвейер, пока настоящей калибровки нет: с симулятором, при первой проверке прибора.
Если набор с таким именем уже есть, программа откажется. После создания наборы
выбираются, история очищается, а процессор перезапускается: сразу, если сбор шёл,
иначе при следующем **Start**.
## Режекторный фильтр
Фильтр настраивается только в профиле, в разделе `preprocess.notch`; в окне
программы его нет.
| Ключ | По умолчанию | Что делает |
| --- | --- | --- |
| `enabled` | `false` | включает фильтр |
| `bands_hz` | `[]` | полосы подавления: список пар `[нижняя, верхняя]` в герцах, верхняя не меньше нижней |
| `taper_width_hz` | `40e6` | ширина плавного края w, Гц, не меньше 0 |
| `taper_type` | `"cosine"` | форма края: `"cosine"` — косинусный спад, `"hard"` — без спада |
Внутри полосы [L, H] множитель m(f) равен нулю. При `"cosine"` по краям полосы он
плавно спадает от 1 до 0 по закону 0,5·(1 + cos(…)) на участках [L − w, L] и
[H, H + w]. При `"hard"` (или w = 0) зануляется вся полоса [L − w, H + w]. Края
соседних полос перемножаются.
Во всех профилях-примерах `enabled: true` и `bands_hz: []`, то есть фильтр ничего не
подавляет. Изменение фильтра применяется при следующем **Start** и сбрасывает
историю.
## Калибровка по объекту
Калибровка по объекту находит для каждой пары комплексную поправку по частоте так,
чтобы отклик известного отражателя у всех пар совпадал по фазе. Эталон — ноутбук
`MIMO_calibration.ipynb`, он хранится вне репозитория. Поправку можно строить по
нескольким положениям отражателя: они уточняют друг друга.
Что нужно заранее:
- кольцо `rings.preprocessed_tap` в профиле: калибровка снимает данные из него;
- таблицы геометрии антенн: в калибровку входят только пары, у которых есть
геометрия обеих антенн, остальные получают поправку 1;
- выбранный набор калибровки (through): поправка запоминает его имя и содержимое и
годится только вместе с ним;
- металлический шар известного радиуса (или другой точечный отражатель) и способ
измерить положение его центра.
Окно **MIMO Object Calibration** открывается кнопкой **Create…** в окне
предобработки. Вверху — подсказка о порядке работы
(`Capture data, then enter the measured reflector centre: …`), внизу — строка
состояния (сначала `Ready to capture`), а на месте карт фаз до расчёта —
`Pair phases at the target will appear after calculation.`
| Элемент | Что делает |
| --- | --- |
| **Set name** | имя набора поправки |
| таблица **Target**, **Sweeps**, **X (m)**, **Y (m)**, **Z (m)** | снятые положения отражателя: сколько коллекций снято и измеренный центр |
| **Capture Data** | снимает данные для нового положения отражателя |
| **Remove Selected Target** | удаляет выбранное положение |
| **Sphere radius (m, 0 = point)** | радиус шара, по умолчанию 0,16 м; 0 — точечный отражатель |
| **Antenna origin height above ground (m)** | высота начала осей антенн над землёй, по умолчанию 0,92 м |
| **Radar downward tilt (°)** | наклон радара вниз, по умолчанию 10° |
| **Calculation Settings** | раскрывает остальные параметры расчёта (таблица ниже) |
| **Calculate and Save** | считает поправку в фоне и сохраняет набор |
| **Cancel Operation** | прерывает съём или расчёт |
| **Close** | закрывает окно |
Параметры в **Calculation Settings**:
| Параметр | По умолчанию | Что делает |
| --- | --- | --- |
| **Estimation band start (MHz)**, **Estimation band stop (MHz)** | 2000 и 6000 | полоса, по которой оценивается поправка; в ней должно быть не меньше 4 точек |
| **Echo path gate half-width (m)** | 0,15 | полуширина окна вокруг ожидаемого пути до отражателя, в котором ищется его эхо |
| **Gate taper width (m)** | 0,03 | ширина плавного края этого окна |
| **Coarse path search (±m, 0 = off)** | 0,6 | предварительный поиск: на сколько можно сдвинуть отражатель по дальности до самого сильного эха |
| **Coordinate refinement (±m)** | 0,1 | в каких пределах уточнять координаты отражателя |
| **Refine coordinates** X, Y, Z | все три | по каким осям уточнять координаты |
| **Antenna phase model** | `linear` | модель фазы антенны по частоте: `const` — постоянная, `linear` — линейная (задержка), `poly3` — многочлен третьей степени, `raw` — без сглаживания |
| **Equalize amplitudes** | выключен | выравнивать и амплитуды, а не только фазы |
Порядок:
1. Поставьте отражатель в сцену и измерьте положение его центра в осях сцены: X —
вдоль ряда антенн, Y — высота над землёй, Z — вдоль земли от радара.
2. Нажмите **Capture Data**. Программа приостанавливает текущий сбор и запускает
конвейер с этим же профилем, но без калибровки по объекту и по всем парам из
таблиц геометрии (многоприборная схема — по полной матрице). Она собирает
столько новых коллекций, сколько задано в
**Sweeps per combo (median)**, и возвращает прежний режим работы. Предел ожидания —
300 с.
3. Введите X, Y, Z в строке нового положения.
4. Повторите для других положений, если нужно. Все положения должны быть сняты при
одних и тех же настройках радара, геометрии и предобработке.
5. Нажмите **Calculate and Save**. Расчёт идёт в фоне. После него окно показывает
карты фаз пар в точке отражателя до и после поправки (**Before**, **After**):
строки — передающие антенны, столбцы — приёмные, фаза — относительно суммы по
всем парам, по шкале ±180°, с разбросом в градусах.
**Capture Data** отказывает, если идёт однократный съём или запись на диск
(`Finish the single capture or disk recording before taking calibration data`), если
нет таблиц геометрии (`Configure Tx/Rx antenna positions before taking calibration data`)
или кольца копии
(`Object calibration requires rings.preprocessed_tap; enable it in the run profile`).
6. Если набор подходит к текущим настройкам, он выбирается и применяется при
следующем **Start** (`Applies on the next Start.`). Иначе он сохраняется
невыбранным с объяснением `Not selected for the current configuration: <причина>`.
Коллекции одного положения усредняются. По каждой частоте поправка раскладывается на
множители передающих и приёмных антенн; фазы сглаживаются выбранной моделью и
продолжаются на всю сетку частот. Поправка пары — сопряжённая фаза произведения
множителей, а с **Equalize amplitudes** — обратное произведение.
Перед каждым **Start** программа проверяет, что поправка снята при тех же настройках
радара, той же геометрии и с тем же набором калибровки (по имени и содержимому), что
она и калибровка покрывают все пары сбора, не содержит нулей и имеет ту же сетку
частот. Сообщения при отказе:
- `Object calibration has no capture provenance; capture it again`;
- `Object calibration radar configuration differs from the captured state` (а также
`antenna geometry`, `through calibration name`, `through calibration content`);
- `Object calibration and through must cover input=i, output=o`;
- `Object calibration corrections must be nonzero`;
- `Object calibration frequency grid differs for input=i, output=o`.
Если изменить таблицу геометрии так, что она перестала совпадать с геометрией
выбранной поправки, выбор поправки снимается, а работающий с ней сбор
приостанавливается и продолжается уже без неё.