added gpr speed tracking
This commit is contained in:
@@ -165,6 +165,8 @@ class AppWindowConfigMixin:
|
||||
comp_power=0.2,
|
||||
start_freq_mhz=3000.0,
|
||||
stop_freq_mhz=6000.0,
|
||||
speed_m_s=0.0,
|
||||
look_angle_deg=0.0,
|
||||
background_subtract_enabled=True,
|
||||
background_mean_count=10,
|
||||
),
|
||||
@@ -217,6 +219,8 @@ class AppWindowConfigMixin:
|
||||
comp_power=float(self._gpr_comp_power.value()),
|
||||
start_freq_mhz=float(self._gpr_start_freq_mhz.value()),
|
||||
stop_freq_mhz=float(self._gpr_stop_freq_mhz.value()),
|
||||
speed_m_s=float(self._gpr_speed_m_s.value()),
|
||||
look_angle_deg=float(self._gpr_look_angle_deg.value()),
|
||||
background_subtract_enabled=bool(self._gpr_background_subtract_enabled.isChecked()),
|
||||
background_mean_count=int(self._gpr_background_mean_count.value()),
|
||||
),
|
||||
@@ -315,7 +319,7 @@ class AppWindowConfigMixin:
|
||||
details=self._capture_state_details(),
|
||||
)
|
||||
return
|
||||
if self._supervisor.is_running() or self._supervisor.is_processor_running():
|
||||
if self._supervisor.is_running():
|
||||
self._show_error(
|
||||
"Stop all pipeline processes before loading a config profile",
|
||||
details=self._process_state_details(),
|
||||
@@ -332,23 +336,26 @@ class AppWindowConfigMixin:
|
||||
return
|
||||
|
||||
try:
|
||||
self._load_config_profile(Path(selected_path))
|
||||
normalized_path = self._normalize_profile_path(Path(selected_path))
|
||||
profile = GuiProfileModel.load_from_path(normalized_path)
|
||||
processor_running = self._supervisor.is_processor_running()
|
||||
self._apply_loaded_profile(profile, normalized_path)
|
||||
profile_kind = "legacy run config" if profile.gui is None else "full GUI profile"
|
||||
message = (
|
||||
f"Config profile loaded: path={normalized_path}, "
|
||||
f"kind={profile_kind}, "
|
||||
f"combos={len(self._defaults_config.combos)}, "
|
||||
f"processing_mode={self._processing_mode.currentText()}"
|
||||
)
|
||||
if processor_running:
|
||||
message += (
|
||||
"; data_processor is still running, so live processing settings were applied immediately "
|
||||
"and stable settings are now staged in the UI for the next Start"
|
||||
)
|
||||
self._log(message)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self._show_exception("Failed to load config profile", exc)
|
||||
|
||||
def _load_config_profile(self, profile_path: Path) -> None:
|
||||
"""Load config profile from `profile_path` and atomically apply it to the UI."""
|
||||
normalized_path = self._normalize_profile_path(profile_path)
|
||||
profile = GuiProfileModel.load_from_path(normalized_path)
|
||||
self._apply_loaded_profile(profile, normalized_path)
|
||||
profile_kind = "legacy run config" if profile.gui is None else "full GUI profile"
|
||||
self._log(
|
||||
f"Config profile loaded: path={normalized_path}, "
|
||||
f"kind={profile_kind}, "
|
||||
f"combos={len(self._defaults_config.combos)}, "
|
||||
f"processing_mode={self._processing_mode.currentText()}"
|
||||
)
|
||||
|
||||
def _apply_loaded_profile(self, profile: GuiProfileModel, profile_path: Path) -> None:
|
||||
"""Apply already parsed profile to GUI state without restarting the pipeline."""
|
||||
config = profile.run_config.clone()
|
||||
@@ -395,6 +402,8 @@ class AppWindowConfigMixin:
|
||||
self._gpr_comp_power,
|
||||
self._gpr_start_freq_mhz,
|
||||
self._gpr_stop_freq_mhz,
|
||||
self._gpr_speed_m_s,
|
||||
self._gpr_look_angle_deg,
|
||||
self._gpr_background_subtract_enabled,
|
||||
self._gpr_background_mean_count,
|
||||
self._save_count,
|
||||
@@ -455,6 +464,8 @@ class AppWindowConfigMixin:
|
||||
self._gpr_comp_power.setValue(float(gui_state.processing.gpr.comp_power))
|
||||
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_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_background_subtract_enabled.setChecked(
|
||||
bool(gui_state.processing.gpr.background_subtract_enabled)
|
||||
)
|
||||
@@ -567,6 +578,8 @@ class AppWindowConfigMixin:
|
||||
gpr_comp_power=float(self._gpr_comp_power.value()),
|
||||
gpr_start_freq_mhz=float(self._gpr_start_freq_mhz.value()),
|
||||
gpr_stop_freq_mhz=float(self._gpr_stop_freq_mhz.value()),
|
||||
gpr_speed_m_s=float(self._gpr_speed_m_s.value()),
|
||||
gpr_look_angle_deg=float(self._gpr_look_angle_deg.value()),
|
||||
gpr_background_subtract_enabled=bool(self._gpr_background_subtract_enabled.isChecked()),
|
||||
gpr_background_mean_count=int(self._gpr_background_mean_count.value()),
|
||||
history_command_seq=int(self._history_command_seq),
|
||||
@@ -640,6 +653,8 @@ class AppWindowConfigMixin:
|
||||
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"speed={self._gpr_speed_m_s.value():g} m/s, "
|
||||
f"look_angle={self._gpr_look_angle_deg.value():g} deg, "
|
||||
f"background_subtract={self._gpr_background_subtract_enabled.isChecked()}, "
|
||||
f"mean_count={self._gpr_background_mean_count.value()})"
|
||||
)
|
||||
|
||||
@@ -39,10 +39,10 @@ class AppWindowPipelineMixin:
|
||||
|
||||
try:
|
||||
processor_was_running = self._supervisor.is_processor_running()
|
||||
config = self._build_config()
|
||||
if not processor_was_running:
|
||||
self._reset_runtime_history()
|
||||
|
||||
config = self._build_config()
|
||||
self._validate_processing_mode_constraints(config)
|
||||
run_signature = self._build_run_history_signature(config)
|
||||
radar_key = self._radar_key(config)
|
||||
|
||||
@@ -191,6 +191,18 @@ def build_processing_group(owner) -> QGroupBox:
|
||||
owner._gpr_stop_freq_mhz.setSingleStep(10.0)
|
||||
owner._gpr_stop_freq_mhz.setValue(float(gpr_live_defaults.stop_freq_mhz))
|
||||
|
||||
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_background_subtract_enabled = QCheckBox("Subtract mean of previous collections")
|
||||
owner._gpr_background_subtract_enabled.setChecked(bool(gpr_live_defaults.background_subtract_enabled))
|
||||
|
||||
@@ -209,6 +221,8 @@ def build_processing_group(owner) -> QGroupBox:
|
||||
gpr_form.addRow("Comp power", owner._gpr_comp_power)
|
||||
gpr_form.addRow("Start MHz", owner._gpr_start_freq_mhz)
|
||||
gpr_form.addRow("Stop MHz", owner._gpr_stop_freq_mhz)
|
||||
gpr_form.addRow("Speed m/s", owner._gpr_speed_m_s)
|
||||
gpr_form.addRow("Look angle deg", owner._gpr_look_angle_deg)
|
||||
gpr_form.addRow(owner._gpr_background_subtract_enabled)
|
||||
gpr_form.addRow("Mean count", owner._gpr_background_mean_count)
|
||||
owner._processing_mode_pages.addWidget(gpr_page)
|
||||
@@ -236,6 +250,8 @@ def build_processing_group(owner) -> QGroupBox:
|
||||
owner._gpr_comp_power.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_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_background_subtract_enabled.toggled.connect(owner._on_processing_live_settings_changed)
|
||||
owner._gpr_background_mean_count.valueChanged.connect(owner._on_processing_live_settings_changed)
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ class SweepCollection:
|
||||
collection_id: int
|
||||
monotonic_ns: int
|
||||
traces: list[TraceData] = field(default_factory=list)
|
||||
capture_start_ns: int = 0
|
||||
capture_end_ns: int = 0
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
|
||||
@@ -196,6 +196,18 @@ def gui_profile_from_dict(payload: dict[str, Any]) -> GuiProfileModel:
|
||||
gui.processing.gpr.stop_freq_mhz,
|
||||
"gui.processing.gpr",
|
||||
),
|
||||
speed_m_s=_optional_float(
|
||||
gpr_object,
|
||||
"speed_m_s",
|
||||
gui.processing.gpr.speed_m_s,
|
||||
"gui.processing.gpr",
|
||||
),
|
||||
look_angle_deg=_optional_float(
|
||||
gpr_object,
|
||||
"look_angle_deg",
|
||||
gui.processing.gpr.look_angle_deg,
|
||||
"gui.processing.gpr",
|
||||
),
|
||||
background_subtract_enabled=_optional_bool(
|
||||
gpr_object,
|
||||
"background_subtract_enabled",
|
||||
@@ -288,6 +300,8 @@ def gui_profile_to_dict(model: GuiProfileModel) -> dict[str, Any]:
|
||||
"comp_power": gui.processing.gpr.comp_power,
|
||||
"start_freq_mhz": gui.processing.gpr.start_freq_mhz,
|
||||
"stop_freq_mhz": gui.processing.gpr.stop_freq_mhz,
|
||||
"speed_m_s": gui.processing.gpr.speed_m_s,
|
||||
"look_angle_deg": gui.processing.gpr.look_angle_deg,
|
||||
"background_subtract_enabled": gui.processing.gpr.background_subtract_enabled,
|
||||
"background_mean_count": gui.processing.gpr.background_mean_count,
|
||||
},
|
||||
@@ -302,4 +316,3 @@ def gui_profile_to_dict(model: GuiProfileModel) -> dict[str, Any]:
|
||||
},
|
||||
}
|
||||
return payload
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ class GuiGprStateModel:
|
||||
comp_power: float = 0.2
|
||||
start_freq_mhz: float = 3000.0
|
||||
stop_freq_mhz: float = 6000.0
|
||||
speed_m_s: float = 0.0
|
||||
look_angle_deg: float = 0.0
|
||||
background_subtract_enabled: bool = True
|
||||
background_mean_count: int = 10
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ class ProcessingLiveConfig:
|
||||
gpr_comp_power: float = 0.2
|
||||
gpr_start_freq_mhz: float = 3000.0
|
||||
gpr_stop_freq_mhz: float = 6000.0
|
||||
gpr_speed_m_s: float = 0.0
|
||||
gpr_look_angle_deg: float = 0.0
|
||||
gpr_background_subtract_enabled: bool = True
|
||||
gpr_background_mean_count: int = 10
|
||||
history_command_seq: int = 0
|
||||
@@ -68,6 +70,8 @@ class ProcessingLiveConfig:
|
||||
"gpr_comp_power": float(self.gpr_comp_power),
|
||||
"gpr_start_freq_mhz": float(self.gpr_start_freq_mhz),
|
||||
"gpr_stop_freq_mhz": float(self.gpr_stop_freq_mhz),
|
||||
"gpr_speed_m_s": float(self.gpr_speed_m_s),
|
||||
"gpr_look_angle_deg": float(self.gpr_look_angle_deg),
|
||||
"gpr_background_subtract_enabled": bool(self.gpr_background_subtract_enabled),
|
||||
"gpr_background_mean_count": int(self.gpr_background_mean_count),
|
||||
"history_command_seq": int(self.history_command_seq),
|
||||
|
||||
@@ -48,3 +48,7 @@ class ByteCursor:
|
||||
data = self.payload[self.offset : self.offset + size]
|
||||
self.offset += size
|
||||
return data
|
||||
|
||||
def remaining_bytes(self) -> int:
|
||||
"""Return unread byte count."""
|
||||
return len(self.payload) - self.offset
|
||||
|
||||
@@ -54,7 +54,21 @@ def decode_trace_collection(payload: bytes, expected_magic: int) -> SweepCollect
|
||||
)
|
||||
)
|
||||
|
||||
return SweepCollection(collection_id=collection_id, monotonic_ns=monotonic_ns, traces=traces)
|
||||
capture_start_ns = 0
|
||||
capture_end_ns = 0
|
||||
if cursor.remaining_bytes() == 16:
|
||||
capture_start_ns = cursor.read_u64()
|
||||
capture_end_ns = cursor.read_u64()
|
||||
elif cursor.remaining_bytes() != 0:
|
||||
raise ValueError("Unexpected trailing bytes in trace collection")
|
||||
|
||||
return SweepCollection(
|
||||
collection_id=collection_id,
|
||||
monotonic_ns=monotonic_ns,
|
||||
traces=traces,
|
||||
capture_start_ns=capture_start_ns,
|
||||
capture_end_ns=capture_end_ns,
|
||||
)
|
||||
|
||||
|
||||
def decode_result_collection(payload: bytes) -> ResultCollection:
|
||||
|
||||
@@ -41,6 +41,13 @@ def serialize_trace_collection(collection: SweepCollection, magic: int) -> bytes
|
||||
_write_interleaved_complex(buffer, s11)
|
||||
_write_interleaved_complex(buffer, s21)
|
||||
|
||||
buffer.extend(
|
||||
struct.pack(
|
||||
"<QQ",
|
||||
int(collection.capture_start_ns),
|
||||
int(collection.capture_end_ns),
|
||||
)
|
||||
)
|
||||
return bytes(buffer)
|
||||
|
||||
|
||||
|
||||
@@ -117,6 +117,8 @@ def save_trace_history_binary(stage_dir: Path, history: list[SweepCollection], m
|
||||
{
|
||||
"collection_id": collection.collection_id,
|
||||
"monotonic_ns": collection.monotonic_ns,
|
||||
"capture_start_ns": int(collection.capture_start_ns),
|
||||
"capture_end_ns": int(collection.capture_end_ns),
|
||||
"trace_count": len(collection.traces),
|
||||
},
|
||||
indent=2,
|
||||
@@ -178,6 +180,8 @@ def save_trace_history_numpy(stage_dir: Path, history: list[SweepCollection]) ->
|
||||
{
|
||||
"collection_id": int(collection.collection_id),
|
||||
"monotonic_ns": int(collection.monotonic_ns),
|
||||
"capture_start_ns": int(collection.capture_start_ns),
|
||||
"capture_end_ns": int(collection.capture_end_ns),
|
||||
"trace_count": len(collection.traces),
|
||||
"traces": traces_meta,
|
||||
},
|
||||
|
||||
@@ -64,6 +64,8 @@ class NpzStore(StoreApi):
|
||||
meta = {
|
||||
"collection_id": int(collection.collection_id),
|
||||
"monotonic_ns": int(collection.monotonic_ns),
|
||||
"capture_start_ns": int(collection.capture_start_ns),
|
||||
"capture_end_ns": int(collection.capture_end_ns),
|
||||
"combos": combo_records,
|
||||
}
|
||||
meta_path.write_text(json.dumps(meta, indent=2), encoding="utf-8")
|
||||
@@ -98,6 +100,8 @@ class NpzStore(StoreApi):
|
||||
collection_id=int(meta["collection_id"]),
|
||||
monotonic_ns=int(meta["monotonic_ns"]),
|
||||
traces=traces,
|
||||
capture_start_ns=int(meta.get("capture_start_ns", 0)),
|
||||
capture_end_ns=int(meta.get("capture_end_ns", 0)),
|
||||
)
|
||||
|
||||
def list_sets(self, kind: str, radar_key: str) -> list[str]:
|
||||
|
||||
Reference in New Issue
Block a user