# Файл конфигурации Все настройки программы хранятся в профиле — файле 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/<вид набора>//`. Смена любой величины, из которой строится ключ, скрывает наборы, снятые при старых значениях. | Радар | Из чего строится | Пример (из профилей-примеров) | | --- | --- | --- | | `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`. Неизвестные ключи пропускаются.