Refactor radar system
This commit is contained in:
@@ -6,7 +6,8 @@ from pathlib import Path
|
||||
import time
|
||||
|
||||
from PyQt6.QtWidgets import QFileDialog
|
||||
from python_app.gui.runtime.history import record_result_history, remove_last_aligned_histories
|
||||
from python_app.gui.controllers.app_window_config.state_builders import GUI_SAVE_HISTORY_LIMIT
|
||||
from python_app.gui.runtime.history import remove_last_aligned_histories
|
||||
from python_app.storage.npz.paths import radar_config_filename_prefix
|
||||
|
||||
|
||||
@@ -39,8 +40,10 @@ class AppWindowSnapshotMixin:
|
||||
return output_dir / "config_profile.json"
|
||||
|
||||
def _save_snapshot(self) -> None:
|
||||
"""Save the last-N runtime measurements as a numpy snapshot (the "Save Dataset" button)."""
|
||||
"""Save up to 1000 recent runtime measurements as a numpy snapshot."""
|
||||
self._drain_runtime_rings_for_snapshot()
|
||||
if getattr(self, "_closing", False):
|
||||
return
|
||||
|
||||
if not self._raw_history and not self._pre_history and not self._result_history:
|
||||
self._show_error("No runtime data is available for save", details=self._runtime_history_details())
|
||||
@@ -50,7 +53,8 @@ class AppWindowSnapshotMixin:
|
||||
list(self._raw_history),
|
||||
list(self._pre_history),
|
||||
list(self._result_history),
|
||||
int(self._save_count.value()),
|
||||
GUI_SAVE_HISTORY_LIMIT,
|
||||
include_unaligned=True,
|
||||
)
|
||||
|
||||
def _snapshot_destination_dir(self) -> Path:
|
||||
@@ -72,10 +76,12 @@ class AppWindowSnapshotMixin:
|
||||
preprocessed_history: list,
|
||||
result_history: list,
|
||||
last_n: int,
|
||||
*,
|
||||
include_unaligned: bool = False,
|
||||
) -> None:
|
||||
"""Save the given aligned histories as a numpy snapshot + adjacent config profile.
|
||||
"""Save the given histories as a numpy snapshot + adjacent config profile.
|
||||
|
||||
Shared by the manual "Save Dataset" button (which passes the runtime history)
|
||||
Shared by the manual "Save Last 1000" button (which passes the runtime history)
|
||||
and the on-the-fly disk recorder (which passes the freshly recorded buffers),
|
||||
so both produce byte-identical dataset layouts and identical error reporting.
|
||||
"""
|
||||
@@ -90,6 +96,7 @@ class AppWindowSnapshotMixin:
|
||||
result_history,
|
||||
last_n,
|
||||
name_prefix=self._radar_config_name_prefix(),
|
||||
include_unaligned=include_unaligned,
|
||||
)
|
||||
config_profile_path = self._snapshot_config_profile_path(snapshot_dir)
|
||||
try:
|
||||
@@ -124,13 +131,15 @@ class AppWindowSnapshotMixin:
|
||||
def _save_vna_history_json(self) -> None:
|
||||
"""Save one VNA-history JSON per available combo in runtime history."""
|
||||
self._drain_runtime_rings_for_snapshot()
|
||||
if getattr(self, "_closing", False):
|
||||
return
|
||||
|
||||
if not self._raw_history and not self._pre_history and not self._result_history:
|
||||
self._show_error("No runtime data is available for save", details=self._runtime_history_details())
|
||||
return
|
||||
|
||||
try:
|
||||
last_n = int(self._save_count.value())
|
||||
last_n = GUI_SAVE_HISTORY_LIMIT
|
||||
channel = "s21"
|
||||
output_root = Path(self._save_path_input.text().strip()).expanduser()
|
||||
output_name = self._save_name_input.text().strip()
|
||||
@@ -144,6 +153,7 @@ class AppWindowSnapshotMixin:
|
||||
channel=channel,
|
||||
primary_stage="preprocessed",
|
||||
name_prefix=self._radar_config_name_prefix(),
|
||||
include_unaligned=True,
|
||||
)
|
||||
output_stem = str(summary.get("output_stem", "")).strip()
|
||||
if not output_stem:
|
||||
@@ -210,6 +220,7 @@ class AppWindowSnapshotMixin:
|
||||
return
|
||||
|
||||
resume_acquisition = self._supervisor.is_running()
|
||||
resume_seq = getattr(self, "_stop_request_seq", 0) + 1
|
||||
dropped_raw = 0
|
||||
dropped_pre = 0
|
||||
dropped_results = 0
|
||||
@@ -220,6 +231,8 @@ class AppWindowSnapshotMixin:
|
||||
try:
|
||||
if resume_acquisition:
|
||||
self._stop_run()
|
||||
if not self._pipeline_resume_allowed(resume_seq):
|
||||
return
|
||||
|
||||
dropped_raw = self._raw_reader.drop_all() if self._raw_reader is not None else 0
|
||||
dropped_pre = self._pre_reader.drop_all() if self._pre_reader is not None else 0
|
||||
@@ -260,7 +273,7 @@ class AppWindowSnapshotMixin:
|
||||
f"results={dropped_results}"
|
||||
)
|
||||
|
||||
if resume_acquisition:
|
||||
if resume_acquisition and self._pipeline_resume_allowed(resume_seq):
|
||||
self._start_run()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self._show_exception(f"Failed to {error_action}", exc)
|
||||
@@ -280,64 +293,28 @@ class AppWindowSnapshotMixin:
|
||||
if self._raw_reader is None and self._pre_reader is None and self._result_reader is None:
|
||||
return
|
||||
try:
|
||||
start_raw_count = len(self._raw_history)
|
||||
start_pre_count = len(self._pre_history)
|
||||
start_result_count = len(self._result_history)
|
||||
readers = (self._raw_reader, self._pre_reader, self._result_reader)
|
||||
observed = [False, False, False]
|
||||
deadline = time.monotonic() + 1.2
|
||||
|
||||
while True:
|
||||
progress = False
|
||||
while time.monotonic() < deadline and not getattr(self, "_closing", False):
|
||||
limit = self._max_pop_per_snapshot_drain
|
||||
raw = self._read_all_raw(max_collections=limit) if self._raw_reader is not None else None
|
||||
preprocessed = self._read_all_preprocessed(max_collections=limit)
|
||||
result = self._read_all_results(max_collections=limit) if self._result_reader is not None else None
|
||||
latest = (raw, preprocessed, result)
|
||||
observed = [seen or collection is not None for seen, collection in zip(observed, latest)]
|
||||
|
||||
if self._raw_reader is not None:
|
||||
for _ in range(self._max_pop_per_snapshot_drain):
|
||||
collection = self._raw_reader.pop_raw_collection()
|
||||
if collection is None:
|
||||
break
|
||||
self._raw_history.append(collection)
|
||||
progress = True
|
||||
|
||||
if self._pre_reader is not None:
|
||||
for _ in range(self._max_pop_per_snapshot_drain):
|
||||
collection = self._pre_reader.pop_preprocessed_collection()
|
||||
if collection is None:
|
||||
break
|
||||
self._pre_history.append(collection)
|
||||
progress = True
|
||||
|
||||
if self._result_reader is not None:
|
||||
for _ in range(self._max_pop_per_snapshot_drain):
|
||||
collection = self._result_reader.pop_result_collection()
|
||||
if collection is None:
|
||||
break
|
||||
record_result_history(self._result_history, collection)
|
||||
progress = True
|
||||
|
||||
if progress:
|
||||
if any(collection is not None for collection in latest):
|
||||
continue
|
||||
|
||||
raw_count = len(self._raw_history)
|
||||
pre_count = len(self._pre_history)
|
||||
result_count = len(self._result_history)
|
||||
|
||||
missing_raw = self._raw_reader is not None and raw_count == start_raw_count
|
||||
missing_pre = self._pre_reader is not None and pre_count == start_pre_count
|
||||
missing_results = self._result_reader is not None and result_count == start_result_count
|
||||
got_results = result_count > start_result_count
|
||||
got_raw_or_pre = raw_count > start_raw_count or pre_count > start_pre_count
|
||||
|
||||
# Event-loop-friendly waits so the keepalive/watchdog timers and
|
||||
# queued signals keep firing instead of freezing the headless daemon.
|
||||
if got_results and (missing_raw or missing_pre) and time.monotonic() < deadline:
|
||||
self._pump_events_during_drain(0.01)
|
||||
continue
|
||||
if got_raw_or_pre and missing_results and time.monotonic() < deadline:
|
||||
self._pump_events_during_drain(0.01)
|
||||
continue
|
||||
if (
|
||||
self._result_reader is not None
|
||||
and max(raw_count, pre_count) > result_count
|
||||
and time.monotonic() < deadline
|
||||
):
|
||||
missing_stage = any(reader is not None and not seen for reader, seen in zip(readers, observed))
|
||||
awaiting_results = self._result_reader is not None and (
|
||||
max(len(self._raw_history), len(self._pre_history)) > len(self._result_history)
|
||||
)
|
||||
if (any(observed) and missing_stage) or awaiting_results:
|
||||
self._pump_events_during_drain(0.01)
|
||||
continue
|
||||
break
|
||||
|
||||
Reference in New Issue
Block a user