Files
2026-10-16 18:35:02 +03:00

301 lines
27 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.
# Калибровка и предобработка
Препроцессор (`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`.
Если изменить таблицу геометрии так, что она перестала совпадать с геометрией
выбранной поправки, выбор поправки снимается, а работающий с ней сбор
приостанавливается и продолжается уже без неё.