added legacy gpr

This commit is contained in:
Ayzen
2026-05-06 11:54:59 +03:00
parent e86f30023e
commit 1b7d9e417d
16 changed files with 2697 additions and 1335 deletions
@@ -38,12 +38,18 @@ class AppWindowLiveProcessingMixin:
bscan_gain=float(self._bscan_gain.value()),
bscan_start_freq_mhz=float(self._bscan_start_freq_mhz.value()),
bscan_stop_freq_mhz=float(self._bscan_stop_freq_mhz.value()),
gpr_algorithm=self._gpr_algorithm.currentText(),
gpr_input_positions=self._parse_csv_int_list(self._gpr_input_positions_input.text()),
gpr_output_positions=self._parse_csv_int_list(self._gpr_output_positions_input.text()),
gpr_min_depth_m=float(self._gpr_min_depth_m.value()),
gpr_max_depth_m=float(self._gpr_max_depth_m.value()),
gpr_range_comp_power=float(self._gpr_range_comp_power.value()),
gpr_angle_comp_power=float(self._gpr_angle_comp_power.value()),
gpr_comp_power=float(self._gpr_comp_power.value()),
gpr_speed_m_s=float(self._gpr_speed_m_s.value()),
gpr_look_angle_deg=float(self._gpr_look_angle_deg.value()),
gpr_snr_thresh=float(self._gpr_snr_thresh.value()),
gpr_snr_comp_max=float(self._gpr_snr_comp_max.value()),
gpr_start_freq_mhz=float(self._gpr_start_freq_mhz.value()),
gpr_stop_freq_mhz=float(self._gpr_stop_freq_mhz.value()),
gpr_background_subtract_enabled=bool(self._gpr_background_subtract_enabled.isChecked()),
@@ -176,12 +182,15 @@ class AppWindowLiveProcessingMixin:
elif mode == "gpr":
self._log(
"Processing mode selected: gpr "
f"(inputs={self._gpr_input_positions_input.text().strip() or '<all>'}, "
f"(algorithm={self._gpr_algorithm.currentText()}, "
f"inputs={self._gpr_input_positions_input.text().strip() or '<all>'}, "
f"outputs={self._gpr_output_positions_input.text().strip() or '<all>'}, "
f"depth={self._gpr_min_depth_m.value():g}..{self._gpr_max_depth_m.value():g} m, "
f"freq={self._gpr_start_freq_mhz.value():g}..{self._gpr_stop_freq_mhz.value():g} MHz, "
f"range_comp={self._gpr_range_comp_power.value():g}, "
f"angle_comp={self._gpr_angle_comp_power.value():g}, "
f"comp={self._gpr_comp_power.value():g}, "
f"snr={self._gpr_snr_thresh.value():g}, "
f"background_subtract={self._gpr_background_subtract_enabled.isChecked()}, "
f"mean_count={self._gpr_background_mean_count.value()}, "
f"remove_sidelobes={self._gpr_remove_sidelobe_objects_enabled.isChecked()}, "
@@ -70,6 +70,25 @@ class AppWindowConfigProfileIOMixin:
self._pass_through_y_min_db.setEnabled(enabled)
self._pass_through_y_max_db.setEnabled(enabled)
def _sync_gpr_algorithm_controls(self) -> None:
"""Enable only controls that affect the selected GPR algorithm."""
backprojection_enabled = self._gpr_algorithm.currentText() == "backprojection"
for widget in (
self._gpr_range_comp_power,
self._gpr_angle_comp_power,
self._gpr_remove_sidelobe_objects_enabled,
):
widget.setEnabled(backprojection_enabled)
for widget in (
self._gpr_comp_power,
self._gpr_speed_m_s,
self._gpr_look_angle_deg,
self._gpr_snr_thresh,
self._gpr_snr_comp_max,
):
widget.setEnabled(not backprojection_enabled)
def _apply_history_limit_from_config(self, config) -> None:
"""Resize in-memory history buffers to match the loaded config."""
history_limit = self._history_limit_for_config(config)
@@ -194,6 +213,7 @@ class AppWindowConfigProfileIOMixin:
self._bscan_start_freq_mhz,
self._bscan_stop_freq_mhz,
self._bscan_subtract_mean_ascan,
self._gpr_algorithm,
self._gpr_relative_permittivity,
self._gpr_tx_geometry_input,
self._gpr_rx_geometry_input,
@@ -203,6 +223,11 @@ class AppWindowConfigProfileIOMixin:
self._gpr_max_depth_m,
self._gpr_range_comp_power,
self._gpr_angle_comp_power,
self._gpr_comp_power,
self._gpr_speed_m_s,
self._gpr_look_angle_deg,
self._gpr_snr_thresh,
self._gpr_snr_comp_max,
self._gpr_start_freq_mhz,
self._gpr_stop_freq_mhz,
self._gpr_background_subtract_enabled,
@@ -265,10 +290,16 @@ class AppWindowConfigProfileIOMixin:
)
self._gpr_input_positions_input.setText(str(gui_state.processing.gpr.input_positions))
self._gpr_output_positions_input.setText(str(gui_state.processing.gpr.output_positions))
self._set_combo_current_text(self._gpr_algorithm, gui_state.processing.gpr.algorithm)
self._gpr_min_depth_m.setValue(float(gui_state.processing.gpr.min_depth_m))
self._gpr_max_depth_m.setValue(float(gui_state.processing.gpr.max_depth_m))
self._gpr_range_comp_power.setValue(float(gui_state.processing.gpr.range_comp_power))
self._gpr_angle_comp_power.setValue(float(gui_state.processing.gpr.angle_comp_power))
self._gpr_comp_power.setValue(float(gui_state.processing.gpr.comp_power))
self._gpr_speed_m_s.setValue(float(gui_state.processing.gpr.speed_m_s))
self._gpr_look_angle_deg.setValue(float(gui_state.processing.gpr.look_angle_deg))
self._gpr_snr_thresh.setValue(float(gui_state.processing.gpr.snr_thresh))
self._gpr_snr_comp_max.setValue(float(gui_state.processing.gpr.snr_comp_max))
self._gpr_start_freq_mhz.setValue(float(gui_state.processing.gpr.start_freq_mhz))
self._gpr_stop_freq_mhz.setValue(float(gui_state.processing.gpr.stop_freq_mhz))
self._gpr_background_subtract_enabled.setChecked(
@@ -299,6 +330,7 @@ class AppWindowConfigProfileIOMixin:
self._gpr_geometry_signature = None
self._gpr_selected_geometry = None
self._sync_pass_through_y_controls()
self._sync_gpr_algorithm_controls()
self._refresh_preprocess_summary_labels()
if self._preprocess_dialog is not None:
@@ -252,12 +252,18 @@ class AppWindowConfigStateBuildersMixin:
subtract_mean_ascan=bool(self._bscan_subtract_mean_ascan.isChecked()),
),
gpr=GuiGprStateModel(
algorithm=self._gpr_algorithm.currentText(),
input_positions=self._gpr_input_positions_input.text().strip(),
output_positions=self._gpr_output_positions_input.text().strip(),
min_depth_m=float(self._gpr_min_depth_m.value()),
max_depth_m=float(self._gpr_max_depth_m.value()),
range_comp_power=float(self._gpr_range_comp_power.value()),
angle_comp_power=float(self._gpr_angle_comp_power.value()),
comp_power=float(self._gpr_comp_power.value()),
speed_m_s=float(self._gpr_speed_m_s.value()),
look_angle_deg=float(self._gpr_look_angle_deg.value()),
snr_thresh=float(self._gpr_snr_thresh.value()),
snr_comp_max=float(self._gpr_snr_comp_max.value()),
start_freq_mhz=float(self._gpr_start_freq_mhz.value()),
stop_freq_mhz=float(self._gpr_stop_freq_mhz.value()),
background_subtract_enabled=bool(self._gpr_background_subtract_enabled.isChecked()),
@@ -4,6 +4,8 @@ from __future__ import annotations
import time
from PyQt6.QtCore import QSignalBlocker
from python_app.gui.runtime.constraints import validate_processing_mode_constraints
from python_app.gui.runtime.history import build_run_history_signature, record_result_history
from python_app.hardware_full.single_radar_service import create_single_radar_service
@@ -470,10 +472,21 @@ class AppWindowPipelineMixin:
)
def _drain_locator_speed_updates(self) -> None:
"""Drain queued locator speed packets; coherent BP does not use motion speed."""
"""Apply the newest queued locator speed packet to live processing settings."""
if self._locator_service is None:
return
self._locator_service.drain_speed_updates()
speed_m_s = self._locator_service.drain_speed_updates()
if speed_m_s is None:
return
previous_speed_m_s = float(self._gpr_speed_m_s.value())
with QSignalBlocker(self._gpr_speed_m_s):
self._gpr_speed_m_s.setValue(float(speed_m_s))
current_speed_m_s = float(self._gpr_speed_m_s.value())
if current_speed_m_s == previous_speed_m_s:
return
self._write_live_processing_config()
def _publish_locator_snapshot_from_collection(self, collection: ResultCollection) -> None:
"""Publish one locator snapshot from a GPR result collection."""
@@ -154,6 +154,10 @@ def build_processing_group(owner) -> QGroupBox:
gpr_defaults = owner._defaults_config.gpr
owner._gpr_algorithm = QComboBox()
owner._gpr_algorithm.addItems(["backprojection", "legacy_point", "legacy_extended"])
owner._set_combo_current_text(owner._gpr_algorithm, gpr_live_defaults.algorithm)
owner._gpr_relative_permittivity = QDoubleSpinBox()
owner._gpr_relative_permittivity.setDecimals(4)
owner._gpr_relative_permittivity.setRange(0.0001, 1000.0)
@@ -198,6 +202,36 @@ def build_processing_group(owner) -> QGroupBox:
owner._gpr_angle_comp_power.setSingleStep(0.01)
owner._gpr_angle_comp_power.setValue(float(gpr_live_defaults.angle_comp_power))
owner._gpr_comp_power = QDoubleSpinBox()
owner._gpr_comp_power.setDecimals(3)
owner._gpr_comp_power.setRange(0.0, 5.0)
owner._gpr_comp_power.setSingleStep(0.05)
owner._gpr_comp_power.setValue(float(gpr_live_defaults.comp_power))
owner._gpr_speed_m_s = QDoubleSpinBox()
owner._gpr_speed_m_s.setDecimals(3)
owner._gpr_speed_m_s.setRange(-100.0, 100.0)
owner._gpr_speed_m_s.setSingleStep(0.01)
owner._gpr_speed_m_s.setValue(float(gpr_live_defaults.speed_m_s))
owner._gpr_look_angle_deg = QDoubleSpinBox()
owner._gpr_look_angle_deg.setDecimals(2)
owner._gpr_look_angle_deg.setRange(-90.0, 90.0)
owner._gpr_look_angle_deg.setSingleStep(0.1)
owner._gpr_look_angle_deg.setValue(float(gpr_live_defaults.look_angle_deg))
owner._gpr_snr_thresh = QDoubleSpinBox()
owner._gpr_snr_thresh.setDecimals(2)
owner._gpr_snr_thresh.setRange(0.0, 1_000.0)
owner._gpr_snr_thresh.setSingleStep(0.1)
owner._gpr_snr_thresh.setValue(float(gpr_live_defaults.snr_thresh))
owner._gpr_snr_comp_max = QDoubleSpinBox()
owner._gpr_snr_comp_max.setDecimals(2)
owner._gpr_snr_comp_max.setRange(0.0, 1_000.0)
owner._gpr_snr_comp_max.setSingleStep(0.5)
owner._gpr_snr_comp_max.setValue(float(gpr_live_defaults.snr_comp_max))
owner._gpr_start_freq_mhz = QDoubleSpinBox()
owner._gpr_start_freq_mhz.setDecimals(1)
owner._gpr_start_freq_mhz.setRange(100.0, 8800.0)
@@ -220,6 +254,8 @@ def build_processing_group(owner) -> QGroupBox:
owner._gpr_remove_sidelobe_objects_enabled = QCheckBox("Remove sidelobe objects")
owner._gpr_remove_sidelobe_objects_enabled.setChecked(bool(gpr_live_defaults.remove_sidelobe_objects_enabled))
owner._sync_gpr_algorithm_controls()
owner._gpr_render_mode = QComboBox()
owner._gpr_render_mode.addItems(["heatmap", "objects_only"])
owner._set_combo_current_text(owner._gpr_render_mode, gpr_live_defaults.render_mode)
@@ -257,6 +293,7 @@ def build_processing_group(owner) -> QGroupBox:
gpr_page = _build_processing_mode_page(
owner._processing_mode_pages,
[
("Algorithm", owner._gpr_algorithm),
("Relative permittivity", owner._gpr_relative_permittivity),
("Input positions", owner._gpr_input_positions_input),
("Output positions", owner._gpr_output_positions_input),
@@ -264,12 +301,17 @@ def build_processing_group(owner) -> QGroupBox:
("Max depth m", owner._gpr_max_depth_m),
("Range comp power", owner._gpr_range_comp_power),
("Angle comp power", owner._gpr_angle_comp_power),
("Comp power", owner._gpr_comp_power),
("SNR thresh", owner._gpr_snr_thresh),
("SNR comp max", owner._gpr_snr_comp_max),
("Render mode", owner._gpr_render_mode),
("Min visible score", owner._gpr_min_visible_score),
("Tx geometry", owner._gpr_tx_geometry_input),
("Rx geometry", owner._gpr_rx_geometry_input),
("Start MHz", owner._gpr_start_freq_mhz),
("Stop MHz", owner._gpr_stop_freq_mhz),
("Speed m/s", owner._gpr_speed_m_s),
("Look angle deg", owner._gpr_look_angle_deg),
("Visible X min m", owner._gpr_visible_x_min_m),
("Visible X max m", owner._gpr_visible_x_max_m),
("Visible Z min m", owner._gpr_visible_z_min_m),
@@ -278,7 +320,7 @@ def build_processing_group(owner) -> QGroupBox:
("Mean count", owner._gpr_background_mean_count),
owner._gpr_remove_sidelobe_objects_enabled,
],
split_index=10,
split_index=12,
)
owner._processing_mode_pages.addWidget(gpr_page)
@@ -299,12 +341,19 @@ def build_processing_group(owner) -> QGroupBox:
owner._bscan_start_freq_mhz.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._bscan_stop_freq_mhz.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._bscan_subtract_mean_ascan.toggled.connect(owner._on_processing_live_settings_changed)
owner._gpr_algorithm.currentTextChanged.connect(owner._sync_gpr_algorithm_controls)
owner._gpr_algorithm.currentTextChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_input_positions_input.editingFinished.connect(owner._on_processing_live_settings_changed)
owner._gpr_output_positions_input.editingFinished.connect(owner._on_processing_live_settings_changed)
owner._gpr_min_depth_m.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_max_depth_m.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_range_comp_power.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_angle_comp_power.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_comp_power.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_speed_m_s.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_look_angle_deg.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_snr_thresh.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_snr_comp_max.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_start_freq_mhz.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_stop_freq_mhz.valueChanged.connect(owner._on_processing_live_settings_changed)
owner._gpr_background_subtract_enabled.toggled.connect(owner._on_processing_live_settings_changed)