projector version
This commit is contained in:
@@ -14,6 +14,7 @@ from python_app.models.gui_profile_schema import (
|
||||
GuiPreprocessDialogStateModel,
|
||||
GuiProcessingStateModel,
|
||||
GuiProfileModel,
|
||||
GuiSar3dStateModel,
|
||||
GuiStateModel,
|
||||
GuiSwitchStateModel,
|
||||
)
|
||||
@@ -106,6 +107,7 @@ def gui_profile_from_dict(payload: dict[str, Any]) -> GuiProfileModel:
|
||||
bscan_object = _as_dict(processing_object.get("bscan"), "gui.processing.bscan")
|
||||
gpr_object = _as_dict(processing_object.get("gpr"), "gui.processing.gpr")
|
||||
legacy_gpr_object = _as_dict(processing_object.get("legacy_gpr"), "gui.processing.legacy_gpr")
|
||||
sar3d_object = _as_dict(processing_object.get("sar3d"), "gui.processing.sar3d")
|
||||
root_gpr_object = payload.get("gpr")
|
||||
|
||||
selected_mode = _optional_string(
|
||||
@@ -452,9 +454,136 @@ def gui_profile_from_dict(payload: dict[str, Any]) -> GuiProfileModel:
|
||||
visible_z_min_m=legacy_float("visible_z_min_m", gui.processing.legacy_gpr.visible_z_min_m),
|
||||
visible_z_max_m=legacy_float("visible_z_max_m", gui.processing.legacy_gpr.visible_z_max_m),
|
||||
),
|
||||
sar3d=GuiSar3dStateModel(
|
||||
input_positions=_optional_string(
|
||||
sar3d_object,
|
||||
"input_positions",
|
||||
gui.processing.sar3d.input_positions,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
output_positions=_optional_string(
|
||||
sar3d_object,
|
||||
"output_positions",
|
||||
gui.processing.sar3d.output_positions,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
min_depth_m=_optional_float(
|
||||
sar3d_object,
|
||||
"min_depth_m",
|
||||
gui.processing.sar3d.min_depth_m,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
max_depth_m=_optional_float(
|
||||
sar3d_object,
|
||||
"max_depth_m",
|
||||
gui.processing.sar3d.max_depth_m,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
start_freq_mhz=_optional_float(
|
||||
sar3d_object,
|
||||
"start_freq_mhz",
|
||||
gui.processing.sar3d.start_freq_mhz,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
stop_freq_mhz=_optional_float(
|
||||
sar3d_object,
|
||||
"stop_freq_mhz",
|
||||
gui.processing.sar3d.stop_freq_mhz,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
speed_m_s=_optional_float(
|
||||
sar3d_object,
|
||||
"speed_m_s",
|
||||
gui.processing.sar3d.speed_m_s,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
ignore_socket_speed_enabled=_optional_bool(
|
||||
sar3d_object,
|
||||
"ignore_socket_speed_enabled",
|
||||
gui.processing.sar3d.ignore_socket_speed_enabled,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
look_angle_deg=_optional_float(
|
||||
sar3d_object,
|
||||
"look_angle_deg",
|
||||
gui.processing.sar3d.look_angle_deg,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
direction_sign=_optional_float(
|
||||
sar3d_object,
|
||||
"direction_sign",
|
||||
gui.processing.sar3d.direction_sign,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
apply_freq_phase_correction=_optional_bool(
|
||||
sar3d_object,
|
||||
"apply_freq_phase_correction",
|
||||
gui.processing.sar3d.apply_freq_phase_correction,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
frame_radius=_optional_int(
|
||||
sar3d_object,
|
||||
"frame_radius",
|
||||
gui.processing.sar3d.frame_radius,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
edge_frame_weight=_optional_float(
|
||||
sar3d_object,
|
||||
"edge_frame_weight",
|
||||
gui.processing.sar3d.edge_frame_weight,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
pitch_deg=_optional_float(
|
||||
sar3d_object,
|
||||
"pitch_deg",
|
||||
gui.processing.sar3d.pitch_deg,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
center_depth_m=_optional_float(
|
||||
sar3d_object,
|
||||
"center_depth_m",
|
||||
gui.processing.sar3d.center_depth_m,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
half_width_x_m=_optional_float(
|
||||
sar3d_object,
|
||||
"half_width_x_m",
|
||||
gui.processing.sar3d.half_width_x_m,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
half_width_y_m=_optional_float(
|
||||
sar3d_object,
|
||||
"half_width_y_m",
|
||||
gui.processing.sar3d.half_width_y_m,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
half_width_z_m=_optional_float(
|
||||
sar3d_object,
|
||||
"half_width_z_m",
|
||||
gui.processing.sar3d.half_width_z_m,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
grid_nx=_optional_int(sar3d_object, "grid_nx", gui.processing.sar3d.grid_nx, "gui.processing.sar3d"),
|
||||
grid_ny=_optional_int(sar3d_object, "grid_ny", gui.processing.sar3d.grid_ny, "gui.processing.sar3d"),
|
||||
grid_nz=_optional_int(sar3d_object, "grid_nz", gui.processing.sar3d.grid_nz, "gui.processing.sar3d"),
|
||||
use_compensation=_optional_bool(
|
||||
sar3d_object,
|
||||
"use_compensation",
|
||||
gui.processing.sar3d.use_compensation,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
normalize_pairs=_optional_bool(
|
||||
sar3d_object,
|
||||
"normalize_pairs",
|
||||
gui.processing.sar3d.normalize_pairs,
|
||||
"gui.processing.sar3d",
|
||||
),
|
||||
),
|
||||
)
|
||||
if gui.processing.selected_mode not in {"pass_through", "bscan", "gpr", "legacy_gpr"}:
|
||||
raise ValueError("gui.processing.selected_mode must be one of: pass_through, bscan, gpr, legacy_gpr")
|
||||
if gui.processing.selected_mode not in {"pass_through", "bscan", "gpr", "legacy_gpr", "sar3d"}:
|
||||
raise ValueError(
|
||||
"gui.processing.selected_mode must be one of: pass_through, bscan, gpr, legacy_gpr, sar3d"
|
||||
)
|
||||
if gui.processing.bscan.axis not in {"abs", "real", "phase"}:
|
||||
raise ValueError("gui.processing.bscan.axis must be one of: abs, real, phase")
|
||||
if gui.processing.gpr.render_mode not in {"heatmap", "objects_only"}:
|
||||
@@ -489,6 +618,12 @@ def gui_profile_from_dict(payload: dict[str, Any]) -> GuiProfileModel:
|
||||
raise ValueError("gui.processing.legacy_gpr.snr_comp_max must be >= 0")
|
||||
if gui.processing.legacy_gpr.min_visible_pair_count < 1:
|
||||
raise ValueError("gui.processing.legacy_gpr.min_visible_pair_count must be >= 1")
|
||||
if gui.processing.sar3d.frame_radius < 0:
|
||||
raise ValueError("gui.processing.sar3d.frame_radius must be >= 0")
|
||||
if not 0.0 <= gui.processing.sar3d.edge_frame_weight <= 1.0:
|
||||
raise ValueError("gui.processing.sar3d.edge_frame_weight must be within [0, 1]")
|
||||
if min(gui.processing.sar3d.grid_nx, gui.processing.sar3d.grid_ny, gui.processing.sar3d.grid_nz) < 2:
|
||||
raise ValueError("gui.processing.sar3d.grid_nx/ny/nz must each be >= 2")
|
||||
|
||||
data_actions_object = _as_dict(gui_object.get("data_actions"), "gui.data_actions")
|
||||
gui.data_actions = GuiDataActionsStateModel(
|
||||
@@ -640,6 +775,31 @@ def gui_profile_to_dict(model: GuiProfileModel) -> dict[str, Any]:
|
||||
"visible_z_min_m": gui.processing.legacy_gpr.visible_z_min_m,
|
||||
"visible_z_max_m": gui.processing.legacy_gpr.visible_z_max_m,
|
||||
},
|
||||
"sar3d": {
|
||||
"input_positions": gui.processing.sar3d.input_positions,
|
||||
"output_positions": gui.processing.sar3d.output_positions,
|
||||
"min_depth_m": gui.processing.sar3d.min_depth_m,
|
||||
"max_depth_m": gui.processing.sar3d.max_depth_m,
|
||||
"start_freq_mhz": gui.processing.sar3d.start_freq_mhz,
|
||||
"stop_freq_mhz": gui.processing.sar3d.stop_freq_mhz,
|
||||
"speed_m_s": gui.processing.sar3d.speed_m_s,
|
||||
"ignore_socket_speed_enabled": gui.processing.sar3d.ignore_socket_speed_enabled,
|
||||
"look_angle_deg": gui.processing.sar3d.look_angle_deg,
|
||||
"direction_sign": gui.processing.sar3d.direction_sign,
|
||||
"apply_freq_phase_correction": gui.processing.sar3d.apply_freq_phase_correction,
|
||||
"frame_radius": gui.processing.sar3d.frame_radius,
|
||||
"edge_frame_weight": gui.processing.sar3d.edge_frame_weight,
|
||||
"pitch_deg": gui.processing.sar3d.pitch_deg,
|
||||
"center_depth_m": gui.processing.sar3d.center_depth_m,
|
||||
"half_width_x_m": gui.processing.sar3d.half_width_x_m,
|
||||
"half_width_y_m": gui.processing.sar3d.half_width_y_m,
|
||||
"half_width_z_m": gui.processing.sar3d.half_width_z_m,
|
||||
"grid_nx": gui.processing.sar3d.grid_nx,
|
||||
"grid_ny": gui.processing.sar3d.grid_ny,
|
||||
"grid_nz": gui.processing.sar3d.grid_nz,
|
||||
"use_compensation": gui.processing.sar3d.use_compensation,
|
||||
"normalize_pairs": gui.processing.sar3d.normalize_pairs,
|
||||
},
|
||||
},
|
||||
"data_actions": {
|
||||
"save_count": gui.data_actions.save_count,
|
||||
|
||||
@@ -10,6 +10,7 @@ from python_app.models.gui_profile_schema import (
|
||||
GuiPreprocessDialogStateModel,
|
||||
GuiProcessingStateModel,
|
||||
GuiProfileModel,
|
||||
GuiSar3dStateModel,
|
||||
GuiStateModel,
|
||||
GuiSwitchStateModel,
|
||||
)
|
||||
@@ -23,6 +24,7 @@ __all__ = [
|
||||
"GuiPreprocessDialogStateModel",
|
||||
"GuiProcessingStateModel",
|
||||
"GuiProfileModel",
|
||||
"GuiSar3dStateModel",
|
||||
"GuiStateModel",
|
||||
"GuiSwitchStateModel",
|
||||
"gui_profile_from_dict",
|
||||
|
||||
@@ -123,6 +123,40 @@ class GuiLegacyGprStateModel:
|
||||
visible_z_max_m: float = 14.0
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class GuiSar3dStateModel:
|
||||
"""UI-only defaults for the 3D SAR (sar3d) live settings.
|
||||
|
||||
The band, depth gate, antenna selection and motion knobs mirror the shared
|
||||
gpr_* live-config fields; the sar3d_* knobs mirror the VNA_AlGo gpr_core
|
||||
defaults used by the C++ sar3d processor.
|
||||
"""
|
||||
|
||||
input_positions: str = ""
|
||||
output_positions: str = ""
|
||||
min_depth_m: float = 2.0
|
||||
max_depth_m: float = 14.0
|
||||
start_freq_mhz: float = 3000.0
|
||||
stop_freq_mhz: float = 6000.0
|
||||
speed_m_s: float = 0.0
|
||||
ignore_socket_speed_enabled: bool = False
|
||||
look_angle_deg: float = 0.0
|
||||
direction_sign: float = 1.0
|
||||
apply_freq_phase_correction: bool = True
|
||||
frame_radius: int = 6
|
||||
edge_frame_weight: float = 0.75
|
||||
pitch_deg: float = 6.0
|
||||
center_depth_m: float = 5.6
|
||||
half_width_x_m: float = 1.8
|
||||
half_width_y_m: float = 1.0
|
||||
half_width_z_m: float = 1.8
|
||||
grid_nx: int = 150
|
||||
grid_ny: int = 120
|
||||
grid_nz: int = 160
|
||||
use_compensation: bool = True
|
||||
normalize_pairs: bool = True
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class GuiProcessingStateModel:
|
||||
"""UI-only processing-section defaults."""
|
||||
@@ -132,6 +166,7 @@ class GuiProcessingStateModel:
|
||||
bscan: GuiBscanStateModel = field(default_factory=GuiBscanStateModel)
|
||||
gpr: GuiGprStateModel = field(default_factory=GuiGprStateModel)
|
||||
legacy_gpr: GuiLegacyGprStateModel = field(default_factory=GuiLegacyGprStateModel)
|
||||
sar3d: GuiSar3dStateModel = field(default_factory=GuiSar3dStateModel)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
|
||||
@@ -175,6 +175,7 @@ def run_config_from_dict(payload: dict[str, Any]) -> RunConfigModel:
|
||||
"run.locator_server",
|
||||
)
|
||||
multi_device_payload = _as_dict(radar_payload.get("multi_device"), "radar.multi_device")
|
||||
replay_payload = _as_dict(radar_payload.get("replay"), "radar.replay")
|
||||
kamil_adc_payload = _as_dict(radar_payload.get("kamil_adc"), "radar.kamil_adc")
|
||||
laser_control_payload = _as_dict(radar_payload.get("laser_control"), "radar.laser_control")
|
||||
|
||||
@@ -235,6 +236,13 @@ def run_config_from_dict(payload: dict[str, Any]) -> RunConfigModel:
|
||||
"stimulus_switch_positions",
|
||||
model.radar.multi_device.stimulus_switch_positions,
|
||||
)
|
||||
model.radar.replay.dataset_dir = _read_str(
|
||||
replay_payload, "dataset_dir", model.radar.replay.dataset_dir
|
||||
)
|
||||
model.radar.replay.loop = _read_bool(replay_payload, "loop", model.radar.replay.loop)
|
||||
model.radar.replay.rate_scale = _read_float(
|
||||
replay_payload, "rate_scale", model.radar.replay.rate_scale
|
||||
)
|
||||
model.radar.kamil_adc.project_dir = _read_str(
|
||||
kamil_adc_payload, "project_dir", model.radar.kamil_adc.project_dir
|
||||
)
|
||||
@@ -519,6 +527,11 @@ def run_config_to_dict(model: RunConfigModel) -> dict[str, Any]:
|
||||
"input_switch_positions": model.radar.multi_device.input_switch_positions,
|
||||
"stimulus_switch_positions": model.radar.multi_device.stimulus_switch_positions
|
||||
},
|
||||
"replay": {
|
||||
"dataset_dir": model.radar.replay.dataset_dir,
|
||||
"loop": model.radar.replay.loop,
|
||||
"rate_scale": model.radar.replay.rate_scale,
|
||||
},
|
||||
"kamil_adc": {
|
||||
"project_dir": model.radar.kamil_adc.project_dir,
|
||||
"executable_path": model.radar.kamil_adc.executable_path,
|
||||
|
||||
@@ -52,6 +52,25 @@ class RadarMultiDeviceModel:
|
||||
stimulus_switch_positions: int = 1
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class RadarReplayModel:
|
||||
"""Recorded-dataset replay settings (no hardware).
|
||||
|
||||
When ``dataset_dir`` is non-empty the supervisor launches
|
||||
``python_app.scripts.replay_raw_producer`` instead of the model's normal
|
||||
acquisition producer. The dataset is a directory of snapshot folders named
|
||||
``NNNN_idK_ns<timestamp>``, each holding ``i{input}_o{output}_s21.npy`` /
|
||||
``_freq.npy`` files (the VNA_AlGo preprocessed-capture layout).
|
||||
"""
|
||||
|
||||
dataset_dir: str = ""
|
||||
# Restart from the first snapshot when the dataset ends; the replay
|
||||
# timeline keeps advancing monotonically across the seam.
|
||||
loop: bool = True
|
||||
# Playback speed multiplier: 1.0 replays at the recorded frame cadence.
|
||||
rate_scale: float = 1.0
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class KamilAdcPhaseCalibrationModel:
|
||||
"""Affine law mapping the reference signal's unwrapped phase to frequency.
|
||||
@@ -159,6 +178,7 @@ class RadarModel:
|
||||
visa_library: str = ""
|
||||
sweep: RadarSweepModel = field(default_factory=RadarSweepModel)
|
||||
multi_device: RadarMultiDeviceModel = field(default_factory=RadarMultiDeviceModel)
|
||||
replay: RadarReplayModel = field(default_factory=RadarReplayModel)
|
||||
kamil_adc: KamilAdcModel = field(default_factory=KamilAdcModel)
|
||||
laser_control: LaserControlModel = field(default_factory=LaserControlModel)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user