Port the SAR3D background gate, CLEAN and object boxes from Multi_depthnorm_clean

- BG_GATE_ENABLE: frame peak over its median background (sar3d_background); the
  GUI scales the frame with bg_gate_gain and its cloud threshold.
- SAR_CLEAN_ENABLE: CLEAN of a one-frame aperture on a 4x10x4 cm search grid over
  the whole scene; objects in their own scale (sar3d_objects).
- SAR_MARK_ENABLE: boxes by class around object groups (sar3d_marks), with the
  legend under the views.
- SAR_VOXEL_M as three steps X/Y/Z with the notebook defaults 0.025/0.02/0.02.
- GPU backend: image/download/load/project API, per-plane block reduction for the
  maximum, depth gate without FMA; sar3d host code built with -ffp-contract=off.
- References regenerated from notebook cells 1 and 5, with new CLEAN scenes and a
  synthetic box-rule case; docs updated.
This commit is contained in:
Ayzen
2026-10-16 12:08:57 +03:00
parent 9a9b8ce5c7
commit b88d704126
26 changed files with 1895 additions and 407 deletions
@@ -214,7 +214,7 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
)
processing_mode_pages.addWidget(gpr_page)
# 3D SAR page. The labels are the names of the reference notebook
# Multi_antenna_demonstrate_depthnorm.ipynb; the shared gpr_* fields get their own
# Multi_depthnorm_clean.ipynb; the shared gpr_* fields get their own
# widgets here, like on the GPR page.
sar3d_input_positions_input = view.add("_sar3d_input_positions_input", QLineEdit())
sar3d_input_positions_input.setPlaceholderText("0,1,2")
@@ -226,11 +226,12 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
sar3d_min_depth_m.setToolTip("Radar depth gate start (m); the scene grid along Z follows the gate.")
sar3d_max_depth_m = view.add("_sar3d_max_depth_m", double_spin(0.1, 50.0, 2, 0.1))
sar3d_max_depth_m.setToolTip("Radar depth gate end (m); the scene grid along Z follows the gate.")
sar3d_voxel_m = view.add("_sar3d_voxel_m", double_spin(0.01, 0.1, 3, 0.005))
sar3d_voxel_m.setToolTip(
"Edge of the cubic voxel (m), the same along X, Y and Z. Smaller is finer and slower: "
"halving it makes 8 times more voxels."
)
sar3d_voxel_x_m = view.add("_sar3d_voxel_x_m", double_spin(0.01, 0.1, 3, 0.005))
sar3d_voxel_y_m = view.add("_sar3d_voxel_y_m", double_spin(0.01, 0.1, 3, 0.005))
sar3d_voxel_z_m = view.add("_sar3d_voxel_z_m", double_spin(0.01, 0.1, 3, 0.005))
for axis, step in zip("XYZ", (sar3d_voxel_x_m, sar3d_voxel_y_m, sar3d_voxel_z_m)):
step.setToolTip(f"Voxel step along {axis} (m). Smaller is finer and slower: halving all three "
"steps makes 8 times more voxels.")
sar3d_look_angle_deg = view.add("_sar3d_look_angle_deg", double_spin(-90.0, 90.0, 2, 0.5))
sar3d_look_angle_deg.setToolTip(
"Downward tilt of the radar (deg): motion correction along range and the ground scene axes."
@@ -253,6 +254,17 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
sar3d_pair_depth_equalize = view.add("_sar3d_pair_depth_equalize", QCheckBox("PAIR_DEPTH_EQUALIZE"))
sar3d_background_subtract_enabled = view.add("_sar3d_background_subtract_enabled", QCheckBox("Subtract mean of previous collections"))
sar3d_background_mean_count = view.add("_sar3d_background_mean_count", integer_spin(0, 10000))
sar3d_bg_gate_enabled = view.add("_sar3d_bg_gate_enabled", QCheckBox("BG_GATE_ENABLE"))
sar3d_bg_gate_enabled.setToolTip(
"Show the frame relative to its background, the median of the volume: below 6 backgrounds the "
"frame is empty, at 6 its maximum appears at SAR_CLOUD_THRESHOLD, from 8.5 the scale is full."
)
sar3d_clean_enabled = view.add("_sar3d_clean_enabled", QCheckBox("SAR_CLEAN_ENABLE"))
sar3d_clean_enabled.setToolTip(
"CLEAN: subtract the strongest responses one by one, so weak objects show beside strong ones; "
"each object is drawn in its own 0-1 scale. Runs on a one-frame aperture: always with "
"SAR_FRAME_RADIUS = 0, otherwise while no previous frame is available, as after Start."
)
sar3d_x_size_m = view.add("_sar3d_x_size_m", double_spin(0.0, 100.0, 2, 0.1))
sar3d_y_min_m = view.add("_sar3d_y_min_m", double_spin(-50.0, 50.0, 2, 0.1))
sar3d_y_max_m = view.add("_sar3d_y_max_m", double_spin(-50.0, 50.0, 2, 0.1))
@@ -261,6 +273,11 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
sar3d_zoom_percent = view.add("_sar3d_zoom_percent", QSlider(Qt.Orientation.Horizontal))
sar3d_zoom_percent.setRange(100, 1000)
sar3d_zoom_percent.setToolTip("100% shows the full scene; higher values zoom towards its brightest object.")
sar3d_mark_enabled = view.add("_sar3d_mark_enabled", QCheckBox("SAR_MARK_ENABLE"))
sar3d_mark_enabled.setToolTip(
"Box the CLEAN objects by height: red very low (like a mine), orange on the ground, blue above it, "
"dashed grey at the scene boundary (not yet decidable). Off: numbered objects instead."
)
sar3d_page = _build_processing_mode_page(
processing_mode_pages,
@@ -271,7 +288,9 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
("F_STOP MHz", sar3d_stop_freq_mhz),
("MIN_DEPTH", sar3d_min_depth_m),
("MAX_DEPTH", sar3d_max_depth_m),
("SAR_VOXEL_M", sar3d_voxel_m),
("SAR_VOXEL_M X", sar3d_voxel_x_m),
("SAR_VOXEL_M Y", sar3d_voxel_y_m),
("SAR_VOXEL_M Z", sar3d_voxel_z_m),
("LOOK_ANGLE_DEG", sar3d_look_angle_deg),
sar3d_ignore_socket_speed_enabled,
("SPEED_M_S", sar3d_speed_m_s),
@@ -283,14 +302,16 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
sar3d_pair_depth_equalize,
sar3d_background_subtract_enabled,
("Mean count", sar3d_background_mean_count),
sar3d_bg_gate_enabled,
sar3d_clean_enabled,
("SAR_X_SIZE_M (0 = auto)", sar3d_x_size_m),
("SAR_Y_RANGE_M min", sar3d_y_min_m),
("SAR_Y_RANGE_M max", sar3d_y_max_m),
("SAR_Z_SIZE_M (0 = auto)", sar3d_z_size_m),
("SAR_CLOUD_THRESHOLD", sar3d_cloud_threshold),
("Zoom (%)", sar3d_zoom_percent),
sar3d_mark_enabled,
],
split_index=8,
)
processing_mode_pages.addWidget(sar3d_page)
@@ -320,7 +341,7 @@ def build_processing_group(config: RunConfigModel, gui: GuiStateModel) -> Proces
trace_controls=(show_magnitude_checkbox, show_phase_checkbox, unwrap_phase_checkbox,
pass_through_combo_filter_input, pass_through_fixed_y_enabled,
pass_through_y_min_db, pass_through_y_max_db),
visual_controls=(gpr_render_mode, sar3d_cloud_threshold, sar3d_zoom_percent),
visual_controls=(gpr_render_mode, sar3d_cloud_threshold, sar3d_zoom_percent, sar3d_mark_enabled),
locator_controls=(gpr_max_detected_objects_to_draw, gpr_draw_top_m_objects,
gpr_visible_x_min_m, gpr_visible_x_max_m,
gpr_visible_z_min_m, gpr_visible_z_max_m),