Files
radar_system/docs/configuration.md
T
2026-10-16 18:35:02 +03:00

429 lines
42 KiB
Markdown
Raw 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.
# Файл конфигурации
Все настройки программы хранятся в профиле — файле JSON. В профиле две части:
конфигурация сбора и обработки (разделы `radar`, `switches`, `control_button`,
`logging`, `run`, `preprocess`, `gpr`, `rings`) и состояние окна (раздел `gui`).
Незнакомые термины (полоса ПЧ, дБм, пара, коллекция) — в [словаре](glossary.md).
| Где | Что |
| --- | --- |
| `run_config.json` в корне | профиль для разработки: симулятор многоприборной схемы, `driver_mode: "mock"`, уровень журнала `debug` |
| `run_config_examples/` | готовые профили под каждое железо (таблица ниже) |
| `run_configs/` | профили, которые можно загрузить из веб-интерфейса |
| `python_app/runtime/run_config.json` | рабочая копия, которую программа пишет при каждом **Start**; по ней работают процессы конвейера |
> **Внимание.** Корневой `run_config.json` — профиль симулятора: с ним программа не
> обращается к железу. На машине с радаром работайте с профилем из
> `run_config_examples/`, скопированным и настроенным под установку.
## Как профиль загружается и сохраняется
При запуске программа берёт профиль по порядку:
1. путь из переменной окружения `RADAR_SYSTEM_PROFILE` (её задаёт
`./start.sh --profile ПУТЬ`);
2. последний использованный профиль из `python_app/runtime/gui_session_state.json`;
3. корневой `run_config.json`.
Относительный путь отсчитывается от каталога проекта. Если выбранный профиль не
читается, программа пишет
`Failed to load the last selected config profile; falling back to root run_config.json.`
и загружает корневой; если не читается файл сеанса —
`Failed to read GUI session-state; using root run_config.json.` Если не читается и
корневой профиль, программа не запускается. Профиль без раздела `gui` загружается со
значениями окна по умолчанию; при запуске (кроме корневого профиля) об этом пишется
`Loaded legacy run config without GUI defaults: <путь>`, при **Load Config…** —
`kind=legacy run config`
в строке `Config profile loaded: …`.
**Load Config…** загружает другой профиль; это возможно только при остановленном
сборе (`Stop all pipeline processes before loading a config profile`) и не во время
съёма наборов.
**Save Config…** записывает текущие значения всех полей окна, выбранные наборы и
геометрию антенн. Загруженный или сохранённый профиль становится стартовым для
следующего запуска.
> **Внимание.** Изменения в окне и в веб-интерфейсе, в том числе выбор наборов и
> временный референс, в профиль сами не записываются. После перезапуска программы они
> пропадут, если не нажать **Save Config…**.
Правила чтения:
- нет раздела или ключа — берётся значение по умолчанию. Умолчания схемы — минимальные
заглушки (`points: 1`, `if_bandwidth_hz: 1.0`, пустые имена колец), а не рабочие
настройки: начинайте с профиля-примера;
- типы строгие: целое число нельзя записать как `5.0`, логическое — как `1`; ошибка
называет ключ (`points must be a JSON integer`);
- неизвестные ключи пропускаются и при сохранении исчезают;
- раздел `gui` с неизвестным номером версии отвергается (`Unsupported gui.version: N`).
## Когда изменение вступает в силу
| Обозначение | Когда |
| --- | --- |
| сразу | сразу, в том числе во время сбора |
| Apply Radar | при нажатии **Apply Radar** (без экрана — автоматически при запуске) |
| Start | при следующем **Start** или **Single Capture**: программа заново пишет рабочую копию профиля и перезапускает процессы сбора и предобработки |
| Start, процессор | как Start, но перезапускается и процессор, а с ним TCP-локатор: его клиенты отключаются, история обработки очищается |
| профиль | ключа нет в окне: правьте файл и загрузите его через **Load Config…** при остановленном сборе |
Процессор перезапускается, если изменились: ключ радара (`radar_key`), опорная частота
многоприборной схемы, `driver_mode` радара и ключей, число положений ключей, список
пар, любой ключ раздела `rings`, любой ключ `run.locator_server`, путь к live-файлу
или `run.idle_sleep_ms`. Смена наборов предобработки процессор не перезапускает
(исключение — нейтральные наборы).
## Ключ радара
`radar_key` — строка, по которой программа находит наборы калибровки и референса:
они лежат в каталогах `python_app/data/<вид набора>/<radar_key>/`. Смена любой
величины, из которой строится ключ, скрывает наборы, снятые при старых значениях.
| Радар | Из чего строится | Пример (из профилей-примеров) |
| --- | --- | --- |
| `librevna` | модель, серийный номер (`no_serial`, если пуст), начало и конец развёртки, число точек, полоса ПЧ, мощность | `librevna_no_serial_st1000000_sp6000000000_p201_if50000_pw-10` |
| `librevna_multi` | то же для мастера и обоих ведомых, плюс положения ключей `_out`, `_in`, `_stim` | `librevna_multi_209E307A5532_20A1307D5532_2072306C5532_st500000000_sp6000000000_p1031_if50000_pw-3_out1_in1_stim2` |
| `rph_radar` | первые 16 знаков хеша SHA-256 от выходной полосы, фазовой калибровки, параметров коллектора (`args`) или источника `rfg_udp`, числа положений ключей и настроек лазера (если плата лазеров включена или источник — RFG) | `rph_radar_2afdaa32e154b122` |
`dwell_us`, путь к программам и тайм-ауты в ключ не входят.
## Профили-примеры
| Файл | Радар | Что в нём |
| --- | --- | --- |
| `run_config.json` (корневой) | `librevna_multi`, `mock` | симулятор схемы с переключением стимула: 16 пар, 1 МГц–6 ГГц, 201 точка, вертикальная база антенн 0,445 м, журнал `debug` |
| `run_config_librevna.example.json` | `librevna`, `native` | одиночный LibreVNA, выходной ключ на 2 положения (линии 17, 27), входной на 4 (линии 22, 23), 8 пар, 1 МГц–6 ГГц, 201 точка |
| `run_config_librevna_multi.example.json` | `librevna_multi`, `native` | приборы `209E307A5532` (мастер), `20A1307D5532`, `2072306C5532`; 8 пар, 1 МГц–6 ГГц, 201 точка |
| `run_config_librevna_multi.example2.json` | `librevna_multi`, `native` | то же для второго комплекта: `206830985532`, `206930965532`, `206930A15532` |
| `run_config_librevna_multi_per_point.example.json` | `librevna_multi`, `native` | переключение стимула, комплект `209E307A5532`; 16 пар, 0,5–6 ГГц, 1031 точка, −3 дБм, `dwell_us: 2`, измеренная геометрия антенн; режим `sar3d` |
| `run_config_librevna_multi_per_point_lowband.example.json` | `librevna_multi`, `native` | переключение стимула, комплект `206830985532`; 30–200 МГц, 201 точка — проверка ключей на низких частотах; у антенн y = z = 0, Tx2 и Tx3 совпадают с Tx0 и Tx1 |
| `run_config_rph_radar.example.json` | `rph_radar`, `e502` | АЦП E-502, плата лазеров на `/dev/ttyUSB0` в режиме `variation`, ключи на 2 и 4 положения, 8 пар |
| `run_config_rph_radar_rfg.example.json` | `rph_radar`, `rfg_udp` | плата RFG на `192.168.2.1:5000`, плата лазеров на `/dev/serial/by-id/usb-Silicon_Labs_CP2102_…`, одна пара, измеренные фазовые якоря |
| `run_config_simulator.example.json` | `librevna`, `mock` | симулятор одиночного LibreVNA: 8 пар, 1 МГц–6 ГГц, 201 точка; режим `gpr` |
`run_configs/run_config.json` — профиль симулятора одиночного LibreVNA для
веб-интерфейса, близкий к `run_config_simulator.example.json`.
## radar
| Ключ | Тип, по умолчанию | Что делает | Когда |
| --- | --- | --- | --- |
| `radar.model` | строка, `"librevna"` | тип радара: `"librevna"`, `"librevna_multi"` или `"rph_radar"`. Старое имя `"kamil_adc"` отвергается с подсказкой перейти на `rph_radar` | профиль; Start, процессор |
| `radar.serial` | строка, `""` | серийный номер прибора; у многоприборной схемы — мастера (обязателен). Пустой у одиночного — первый найденный прибор | профиль; Start, процессор |
| `radar.driver_mode` | строка, `"mock"` | `"native"` — настоящее железо, `"mock"` — симулятор. Радиофотонному радару нужен `"native"` | профиль; Start, процессор |
### radar.sweep
Развёртка LibreVNA. Радиофотонный радар эти ключи не использует (у него
`radar.rph_radar.band`), а `points` у него в профиль не записывается. Поля редактируются в секции
**Radar**; с подключённым прибором они подрезаются под его пределы.
| Ключ | Тип, по умолчанию | Поле | Что делает | Ключ радара |
| --- | --- | --- | --- | --- |
| `start_hz` | число, `1000000.0` | **Start (Hz)** | начало развёртки, Гц, не меньше 0 | да |
| `stop_hz` | число, `6000000000.0` | **Stop (Hz)** | конец развёртки, Гц, больше начала | да |
| `points` | целое, `1` | **Points** | число частотных точек | да |
| `if_bandwidth_hz` | число, `1.0` | **IF bandwidth (Hz)** | полоса ПЧ, Гц, больше 0 | да |
| `stimulus_power_dbm` | число, `-30.0` | **Stimulus power (dBm)** | мощность излучения, дБм | да |
| `dwell_us` | целое, `0` | — | дополнительная задержка на каждой стадии прибора, мкс; при отправке значение молча ограничивается диапазоном 0–65535, а прибор — 10 239 мкс. В режиме переключения стимула в это время контроллер переключает ключ; в примерах `2` | нет |
Изменения применяются при **Start**; у одиночного LibreVNA — ещё и при
**Apply Radar**.
### radar.multi_device
Только для `librevna_multi`; другие радары эти ключи игнорируют. В окне не
редактируются.
| Ключ | Тип, по умолчанию | Что делает |
| --- | --- | --- |
| `slave_serials` | список строк, `[]` | серийные номера двух ведомых, ровно два. Первый даёт входы 0 и 1, второй — 2 и 3; порядок важен. Можно записать строкой через запятую; старое имя `slave_serial_numbers` тоже читается |
| `force_external_reference` | логическое, `false` | внешняя опорная частота 10 МГц на всех трёх приборах. Включайте, только если опора подана на все приборы (глава [Оборудование](hardware.md)) |
| `recovery_attempts` | целое, `3` | сколько раз переподключать приборы после сбоя, прежде чем передать ошибку процессу сбора |
| `output_switch_positions` | целое, `1` | положения настоящего ВЧ-ключа на выходах мастера, которым управляет компьютер (линии из `switches.port1`). 1 — ключа нет. Ни один пример его не использует |
| `input_switch_positions` | целое, `1` | то же для входов ведомых (линии из `switches.port2`) |
| `stimulus_switch_positions` | целое, `1` | положения ключа переключения стимула внутри частотной точки; `2` — режим переключения стимула. Прошивка мастера поддерживает 1, 2 и 4, контроллер STM32 — 2 |
Все ключи, кроме `recovery_attempts`, входят в ключ радара или в условие перезапуска
процессора.
### radar.rph_radar
Только для `rph_radar`. Поля без пометки «—» редактируются в секции **Radar**.
| Ключ | Тип, по умолчанию | Поле | Что делает |
| --- | --- | --- | --- |
| `source` | строка, `"e502"` | — | источник: `"e502"` — АЦП L-Card через `rph_radar_collector`, `"rfg_udp"` — плата RFG по UDP |
| `udp_bind` | строка, `"0.0.0.0:5000"` | — | только RFG: адрес `IPv4:порт`, на котором принимаются пакеты |
| `project_dir` | строка, `""` | **Project dir** | рабочий каталог коллектора; пусто — каталог проекта |
| `executable_path` | строка, `""` | **Executable path** | путь к коллектору, обычно `build/bin/rph_radar_collector` |
| `tty_path` | строка, `""` | **TTY path** | путь псевдотерминала, через который коллектор передаёт развёртки; старый файл по этому пути удаляется перед запуском |
| `args` | список строк, `[]` | **Arguments** (по строке на параметр) | параметры коллектора (глава [Оборудование](hardware.md)); `tty:` здесь задавать нельзя |
| `env` | объект строк, `{}` | **Environment JSON** | переменные окружения коллектора; `~` и `$ПЕРЕМЕННАЯ` раскрываются. Если `env` не задаёт `LD_LIBRARY_PATH`, в начало унаследованного `LD_LIBRARY_PATH` добавляется `~/.local/lib` |
| `startup_timeout_s` | число, `5.0` | **Startup timeout (s)** | сколько ждать появления псевдотерминала после запуска коллектора |
| `sweep_timeout_s` | число, `5.0` | **Read timeout (s)** | сколько ждать пригодной развёртки, покрывающей полосу, прежде чем переподключиться |
| `stop_timeout_s` | число, `2.0` | **Stop timeout (s)** | ожидание остановки коллектора; на деле не больше 0,5 с, затем он завершается принудительно |
| `phase_calibration.phase0_rad`, `freq0_hz` | `0.0`, `2046000000.0` | — | первая опорная точка «фаза опорного сигнала — частота» |
| `phase_calibration.phase1_rad`, `freq1_hz` | `300.0`, `5612000000.0` | — | вторая опорная точка; фазы и частоты точек должны различаться |
| `band.start_hz`, `band.stop_hz` | `2100000000.0`, `5500000000.0` | — | выходная полоса: развёртка пересчитывается на её сетку; развёртка, не покрывающая полосу, отбрасывается |
| `band.points` | `2048` | — | число точек выходной сетки, не меньше 2 |
Для `source: "e502"` поля `executable_path` и `tty_path` обязательны, а `project_dir`, если
задан, должен быть каталогом. Все три тайм-аута должны быть конечными положительными
числами (`radar.rph_radar.<ключ> must be finite and positive`).
Фазы `phase0_rad` и `phase1_rad` записывает программа фазовой калибровки
(`rph_radar_calibrate --apply`). Полоса и якоря входят в ключ радара, поэтому после
новой фазовой калибровки старые наборы не видны.
### radar.laser_control
Плата лазеров радиофотонного радара. Поля — в секции **Radar**, применяются кнопкой
**Apply Radar**.
| Ключ | По умолчанию | Что делает |
| --- | --- | --- |
| `enabled` | `false` | программировать плату при **Apply Radar** |
| `port` | `""` | последовательный порт платы, 115 200 бод |
| `mode` | `"manual"` | `"manual"` — постоянные токи и температуры, `"variation"` — развёртка тока LD1 (плате RFG нужен этот режим) |
| `pi_coeff1_p`, `pi_coeff1_i` | `1280`, `25` | коэффициенты ПИ-регулятора первого канала |
| `pi_coeff2_p`, `pi_coeff2_i` | `1280`, `179` | коэффициенты ПИ-регулятора второго канала |
| `manual.temp1`, `manual.temp2` | `24.0`, `24.9` | температуры лазеров, °C, 15–40 |
| `manual.current1`, `manual.current2` | `97.3`, `102.0` | токи лазеров, мА, 15–110 |
| `variation.variation_type` | `"CHANGE_CURRENT_LD1"` | что меняется; другого варианта нет |
| `variation.static_temp1`, `static_temp2` | `24.0`, `24.9` | температуры во время развёртки |
| `variation.static_current1`, `static_current2` | `97.3`, `102.0` | постоянные токи во время развёртки |
| `variation.min_value`, `max_value` | `97.3`, `107.0` | пределы развёртки тока LD1, мА, начало меньше конца |
| `variation.step` | `0.05` | шаг тока, мА, 0,002–0,5 |
| `variation.time_step` | `50` | длительность ступени, мкс, 20–100 |
| `variation.delay_time` | `10` | пауза между развёртками, мс, 3–10 |
## switches
Два ВЧ-ключа: `port1` — выходной (передающие антенны), `port2` — входной (приёмные).
Таблица положений — в главе [Оборудование](hardware.md).
| Ключ | Тип, по умолчанию | Что делает |
| --- | --- | --- |
| `name` | строка, `""` | имя ключа в сообщениях и в GPIO (`radar_<имя>`) |
| `driver_mode` | `"mock"` | `"native"` — управлять линиями GPIO, `"mock"` — только помнить положение |
| `radar_port` | целое, `0` | порт прибора, к которому подключён ключ: 1 или 2. Задайте его явно: `0` не проходит проверку при **Start** (`switches.<имя>.radar_port must be 1 or 2`) |
| `positions` | `1` | число положений, у настоящего ключа 1–4. Задаёт число выходов или входов матрицы |
| `default_position` | `0` | положение после открытия ключа, меньше `positions` |
| `gpio_chip` | `""` | GPIO-чип, например `/dev/gpiochip0`; для `native` обязателен |
| `pin_a`, `pin_b` | `-1` | номера линий A и B на чипе; для `native` — разные и неотрицательные |
Поле `driver` допускается только со значением `"h7992"`, `invert_logic` — только
`false`; оба при сохранении убираются. Другие значения отвергаются ещё до обращения к
GPIO. У многоприборной схемы программа сама переписывает в этих разделах `driver_mode`
(`"mock"`), `radar_port`, `positions` (положения настоящего ключа × выходы или входы
приборов) и `default_position` (`0`): значения из файла не используются. Читаются
только `name`, `gpio_chip`, `pin_a` и `pin_b` — для настоящих ключей на выходах мастера
или входах ведомых, если `multi_device.output_switch_positions` или
`input_switch_positions` больше 1; их режим берётся из `radar.driver_mode`. Изменения
применяются при **Start**;
число положений и режим перезапускают процессор.
## control_button
GPIO-кнопка, которая снимает временный референс. Настройки читаются один раз при
запуске программы.
| Ключ | По умолчанию | Что делает |
| --- | --- | --- |
| `enabled` | `false` | включить кнопку |
| `gpio_chip` | `"/dev/gpiochip0"` | GPIO-чип |
| `pin` | `-1` | номер линии на чипе (не номер контакта разъёма); отрицательный — кнопка не включается |
| `active_low` | `true` | `true` — нажатие опускает линию в 0 (кнопка на землю), `false` — поднимает в 1 |
| `bias` | `""` | подтяжка: `"pull_up"`, `"pull_down"`, `"disabled"`; пусто — к питанию при `active_low`, к земле иначе |
| `debounce_ms` | `50` | подавление дребезга средствами ядра, мс; 0 — без подавления |
| `action` | `"capture_tmp_reference"` | действие по нажатию; другого нет |
## logging
| Ключ | По умолчанию | Что делает |
| --- | --- | --- |
| `level` | `"info"` | наименьший уровень записей журнала: `debug`, `info`, `warning` или `error`. Меняется списком **Level** над журналом окна; записывается при **Save Config…** |
На уровне `debug` в журнал попадают трассы тайминга переключений; корневой профиль
работает с ним.
## run
| Ключ | Тип, по умолчанию | Что делает | Когда |
| --- | --- | --- | --- |
| `settling_ms` | целое, `0` | пауза после переключения ВЧ-ключей перед развёрткой, мс. Поле **Settling (ms)** | Start |
| `idle_sleep_ms` | целое, `2` | сколько процессы предобработки и обработки спят, когда нет входных данных, мс | Start, процессор |
| `continuous` | логическое, `false` | непрерывный сбор или одна коллекция. Программа сама ставит `true` при **Start** и `false` при **Single Capture**; значение из профиля важно только для `./start.sh --producer-only` | — |
| `processing_live_config_path` | строка, `""` | путь к live-файлу. Программа всегда подставляет `python_app/runtime/processing_live.json` своего каталога | — |
| `combos` | список `{"input", "output"}`, `[]` | пары сбора в порядке обхода (ниже) | Start, процессор |
| `locator_server` | объект | TCP-локатор (ниже) | Start, процессор |
### run.combos
Список пар `{"input": вход, "output": выход}`; пустой список — полная матрица:
выходы по порядку, внутри каждого — все входы. Пар не больше 4096, повторы и номера
вне матрицы отвергаются.
- Одиночный LibreVNA и радиофотонный радар: при **Start** список берётся из окна —
**Run combos** (`вход:выход` через запятую, пусто — полная матрица) или
**Single combo**. В режимах pass-through и B-scan, если оба ключа `mock` или у обоих
не больше одного положения, программа снимает только пару `0:0`.
- Многоприборная схема: список всегда равен полной матрице; в окне он показан, но не
редактируется.
### run.locator_server
TCP-сервер, который отдаёт объекты GPR внешним программам и принимает от них
скорость (протокол — в главе [Веб-интерфейс, кнопка и локатор](web.md)). В окне не
редактируется. Старое имя раздела `run.locator` тоже читается.
| Ключ | По умолчанию | Что делает |
| --- | --- | --- |
| `host` | `"0.0.0.0"` | адрес, на котором сервер ждёт клиентов; `0.0.0.0` — все интерфейсы |
| `port` | `8888` | TCP-порт, 1–65535 |
| `device_id` | `3` | номер устройства в заголовке каждого пакета |
| `protocol_version` | `1` | поле `ver` в пакетах |
| `max_payload_bytes` | `65536` | наибольший размер входящего пакета; клиент с большим пакетом отключается |
| `client_queue_size` | `32` | очередь пакетов на клиента; при переполнении выбрасываются старые |
| `logger_name` | `"locator_runtime"` | не используется |
Ключ `enabled` в этом разделе программа не сохраняет: локатор включён всегда.
## preprocess
| Ключ | Что делает |
| --- | --- |
| `s21.calibration.set_name` | имя выбранного набора калибровки (through) |
| `s21.reference.set_name` | имя выбранного набора референса |
| `s21.object_calibration.set_name` | имя выбранной калибровки по объекту; пусто — не применять |
| `s21.*.bundle_path` | путь к файлу набора для препроцессора; программа заполняет его сама при **Start**, в профиле — пусто |
| `notch.enabled` | включить режекторный фильтр, по умолчанию `false` |
| `notch.bands_hz` | полосы подавления `[нижняя, верхняя]`, Гц, по умолчанию `[]` |
| `notch.taper_width_hz` | ширина плавного края, Гц, не меньше 0, по умолчанию `40000000.0` |
| `notch.taper_type` | форма края: `"cosine"` (по умолчанию) или `"hard"`; как работает фильтр — в главе [Калибровка и предобработка](preprocessing.md) |
Наборы выбираются в окне **Preprocessing Setup** и записываются в профиль при
**Save Config…**. Изменения применяются при **Start**.
## gpr
Геометрия антенн для GPR и 3D SAR и для симулятора. Редактируется таблицами
**Tx geometry** и **Rx geometry** на страницах GPR и 3D SAR; правка таблицы сразу
уходит процессору.
| Ключ | Запись | Что делает |
| --- | --- | --- |
| `tx_geometry` | `{"output_pos", "x_m", "y_m", "z_m"}` | положения передающих антенн: номер выхода и координаты в осях радара, м |
| `rx_geometry` | `{"input_pos", "x_m", "y_m", "z_m"}` | положения приёмных антенн: номер входа и координаты, м |
Записей может быть меньше, чем выходов или входов: антенны без записи в GPR и 3D SAR
не участвуют. Номер должен быть меньше числа выходов (входов), без повторов, иначе
`gpr.tx_geometry output_pos is out of range [0, N)`. При сужении матрицы лишние
записи нужно удалить. Отсутствующие `y_m` и `z_m` считаются нулями. Оси — в главе
[Как работает радар](principles.md).
## rings
Пять колец разделяемой памяти, через которые процессы передают данные
(глава [Устройство программы](architecture.md)):
| Кольцо | Кто пишет | Кто читает |
| --- | --- | --- |
| `raw` | процесс сбора | препроцессор |
| `raw_tap` | процесс сбора, копия | окно программы |
| `preprocessed` | препроцессор | процессор |
| `preprocessed_tap` | препроцессор, копия | окно программы |
| `results` | процессор | окно программы |
| Ключ | По умолчанию | Что делает |
| --- | --- | --- |
| `name` | `""` | имя сегмента разделяемой памяти, например `/radar_raw`. Пустое имя у `raw_tap` или `preprocessed_tap` отключает копию и соответствующую историю окна |
| `capacity` | `1` | сколько кадров помещается в кольцо; при переполнении затирается самый старый |
| `slot_size_bytes` | `4096` | наибольший размер кадра, байт, кратный 8 |
Слоты `raw`, `preprocessed` и включённых копий должны вмещать коллекцию:
44 + пары × (28 + 12 × точки) байт. Например, 16 пар по 1031 точке требуют 198 444
байт. Программа проверяет это до запуска
(`rings.raw.slot_size_bytes must be at least N for this sweep`). Слот `results` должен
вмещать результат; изображения 3D SAR при настройках по умолчанию занимают около
1 МБ. Во всех примерах слоты по 2 МиБ (`2097152`) и ёмкость 50.
Ёмкость влияет и на историю: процессор хранит до 50 коллекций, но не больше
ёмкости `preprocessed` и `results`, а B-scan во время сбора показывает столько же. В
GPR и 3D SAR процессор при этом хранит не меньше, чем нужно обработке: 1 +
**Mean count** (если включено вычитание среднего) + **SAR_FRAME_RADIUS** (в 3D SAR),
независимо от ёмкости колец.
Калибровке по объекту нужно кольцо `preprocessed_tap`.
## gui
Состояние окна: значения всех полей, которые программа запоминает. Раздел
записывается целиком при **Save Config…**. Если его нет, программа берёт значения по
умолчанию, а часть вычисляет из профиля: номера антенн — из геометрии и списка пар,
окно видимости GPR — из положения антенн, каталог сохранения —
`python_app/data/snapshots`.
| Ключ | Поле в окне | Смысл |
| --- | --- | --- |
| `version` | — | версия раздела, всегда `1` |
| `switches.combo_mode` | кнопки **Select** у **Run combos** и **Single combo** | откуда брать пары сбора: `"text"` или `"single"` |
| `switches.combos_text` | **Run combos** | список пар `вход:выход` |
| `switches.single_input`, `single_output` | **Input**, **Output** в строке **Single combo** | одна пара |
| `processing.selected_mode` | **Mode** | режим обработки: `pass_through`, `bscan`, `gpr`, `sar3d` |
| `processing.pass_through.*` | страница pass-through | `show_magnitude`, `show_phase`, `unwrap_phase`, `combo_filter`, `fixed_y_enabled`, `y_min_db`, `y_max_db` |
| `processing.bscan.*` | страница B-scan | `axis`, `cut_m`, `max_depth_m`, `gain`, `start_freq_mhz`, `stop_freq_mhz`, `subtract_mean_ascan`, `history_window_scans` |
| `processing.gpr.*` | страница GPR | `input_positions`, `output_positions`, `min_depth_m`, `max_depth_m`, `range_comp_power`, `object_min_frac`, `score_mode`, `motion_mode`, `look_angle_deg`, `direction_sign`, `speed_m_s`, `ignore_socket_speed_enabled`, `max_detected_objects_to_draw`, `draw_top_m_objects`, `object_approach_min_frames`, `start_freq_mhz`, `stop_freq_mhz`, `background_subtract_enabled`, `background_mean_count`, `remove_sidelobe_objects_enabled`, `bp_ground_depth_m`, `pair_depth_equalize`, `render_mode`, `visible_x_min_m`, `visible_x_max_m`, `visible_z_min_m`, `visible_z_max_m` |
| `processing.sar3d.*` | страница 3D SAR | `input_positions`, `output_positions`, `min_depth_m`, `max_depth_m`, `start_freq_mhz`, `stop_freq_mhz`, `speed_m_s`, `ignore_socket_speed_enabled`, `look_angle_deg`, `frame_radius`, `voxel_x_m`, `voxel_y_m`, `voxel_z_m`, `bp_ground_depth_m`, `comp_range_power`, `use_compensation`, `normalize_each_frame`, `pair_depth_equalize`, `background_subtract_enabled`, `background_mean_count`, `bg_gate_enabled`, `clean_enabled`, `x_size_m`, `y_min_m`, `y_max_m`, `z_size_m`, `cloud_threshold`, `zoom_percent`, `mark_enabled` |
| `data_actions.save_path` | **Path** | каталог для сохранения данных; относительный путь — от рабочего каталога процесса |
| `data_actions.save_name` | **Name** | имя сохраняемого набора данных, по умолчанию `snapshot_manual` |
| `data_actions.record_count` | **Sweeps to record** | сколько коллекций записать на диск, по умолчанию 100 |
| `preprocess_dialog.set_name` | **Set name** | имя нового набора, по умолчанию `set_001` |
| `preprocess_dialog.radar_config_dir` | **Directory** | каталог вариантов радара |
| `preprocess_dialog.use_all_radar_configs` | **Capture current combo for all found radar configs** | съём по всем вариантам |
| `preprocess_dialog.median_sweep_count` | **Sweeps per combo (median)** | развёрток на пару, по умолчанию 5 |
Ключи страниц обработки названы по полям окна; что делает каждое поле, сколько оно по
умолчанию и в каких пределах — в главе [Режимы обработки](processing.md). Типы,
варианты выбора, объявленные в схеме границы и версия проверяются при чтении, и
нарушение отвергает весь профиль: `gui.processing.gpr.score_mode must be one of: peak, combined`,
`gui.processing.sar3d.zoom_percent must be <= 1000`. Значение в пределах схемы, но вне
пределов поля окна поле молча подрезает к своей границе (например, `frame_radius: 1000`
станет 24), и подрезанное значение запишется при следующем **Save Config…**.
`preprocess_dialog.median_sweep_count` меньше 1 поднимается до 1.
## processing_live.json
Живые настройки процессора. Файл `python_app/runtime/processing_live.json` пишет
программа при каждом изменении настройки обработки, смене режима, правке геометрии,
очистке истории и удалении последнего измерения; читает его только процессор. Править
его вручную не нужно: программа перезаписывает его целиком.
В файле 53 ключа. Ключи настроек обработки соответствуют полям окна:
| Ключ | Поле |
| --- | --- |
| `processor_mode` | **Mode** |
| `bscan_axis`, `bscan_cut_m`, `bscan_max_depth_m`, `bscan_gain`, `bscan_start_freq_mhz`, `bscan_stop_freq_mhz` | поля B-scan |
| `gpr_input_positions`, `gpr_output_positions`, `gpr_min_depth_m`, `gpr_max_depth_m`, `gpr_start_freq_mhz`, `gpr_stop_freq_mhz`, `gpr_speed_m_s`, `gpr_look_angle_deg`, `ignore_socket_speed`, `gpr_background_subtract_enabled`, `gpr_background_mean_count`, `pair_depth_equalize` | общие поля GPR и 3D SAR — со страницы выбранного режима |
| `gpr_range_comp_power`, `gpr_object_min_frac`, `gpr_score_mode`, `gpr_motion_mode`, `gpr_direction_sign`, `gpr_max_detected_objects_to_draw`, `gpr_draw_top_m_objects`, `gpr_object_approach_min_frames`, `gpr_remove_sidelobe_objects_enabled`, `gpr_bp_ground_depth_m`, `gpr_visible_x_min_m`, `gpr_visible_x_max_m`, `gpr_visible_z_min_m`, `gpr_visible_z_max_m` | поля GPR |
| `sar3d_frame_radius`, `sar3d_voxel_x_m`, `sar3d_voxel_y_m`, `sar3d_voxel_z_m`, `sar3d_bp_ground_depth_m`, `sar3d_comp_range_power`, `sar3d_use_compensation`, `sar3d_normalize_each_frame`, `sar3d_x_size_m`, `sar3d_y_min_m`, `sar3d_y_max_m`, `sar3d_z_size_m`, `sar3d_bg_gate_enabled`, `sar3d_clean_enabled` | поля 3D SAR |
| `tx_geometry`, `rx_geometry` | таблицы геометрии; заменяют `gpr` профиля в процессоре |
Служебные ключи:
| Ключ | Что делает |
| --- | --- |
| `settings_revision` | номер ревизии настроек (время записи по монотонным часам, нс). Процессор возвращает его в каждом результате, и окно рисует GPR и 3D SAR только текущей ревизии |
| `reprocess_current_result` | пересчитывать ли сохранённые коллекции при новой ревизии; `false` — пока окно само пересчитывает остановленный B-scan |
| `history_clear_before_ns` | граница **Clear Runtime History**: коллекции, начатые не позже этого момента, удаляются из истории процессора |
| `history_removed` | пары `{"collection_id", "capture_start_ns"}`, удалённые **Remove Last Measurement**; список очищается при **Clear Runtime History** |
Процессор отвергает файл целиком, если в нём ошибка JSON, число не того типа или вне
float32, неизвестное значение `processor_mode`, `gpr_score_mode` или
`gpr_motion_mode`, геометрия с номером вне матрицы или с повтором, отрицательные
`sar3d_x_size_m` или `sar3d_z_size_m`, `sar3d_y_max_m` не больше `sar3d_y_min_m`.
Тогда он работает с последними принятыми настройками и пишет
`data_processor warning: failed to refresh live processing config: …` в
`python_app/runtime/logs/data_processor.err.log`. Неизвестные ключи пропускаются.