added s11 collections
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from python_app.gui.runtime.history import remove_last_aligned_histories
|
||||
from python_app.hardware_full.librevna_service import LibreVnaService
|
||||
from python_app.models.run_config_model import ComboModel, GprRxGeometryModel, GprTxGeometryModel, RunConfigModel
|
||||
from python_app.models.run_config_validation import validate_gpr_model
|
||||
@@ -200,6 +199,8 @@ class AppWindowConfigMixin:
|
||||
self._clear_gpr_plot()
|
||||
elif self._result_history:
|
||||
self._draw_results(self._result_history[-1])
|
||||
else:
|
||||
self._clear_trace_plots()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self._show_error(f"Failed to update live processing settings: {exc}")
|
||||
|
||||
@@ -218,72 +219,16 @@ class AppWindowConfigMixin:
|
||||
self._processing_mode_pages.updateGeometry()
|
||||
self._on_processing_live_settings_changed()
|
||||
|
||||
def _on_bscan_clear_history_clicked(self) -> None:
|
||||
"""Permanently clear all runtime histories, ring backlogs, and B-scan cache."""
|
||||
self._apply_history_mode_deletion(mode_label="B-scan", remove_last_only=False)
|
||||
|
||||
def _on_bscan_remove_last_sweep_clicked(self) -> None:
|
||||
"""Permanently delete the latest sweep from runtime histories and rings."""
|
||||
self._apply_history_mode_deletion(mode_label="B-scan", remove_last_only=True)
|
||||
|
||||
def _on_gpr_clear_history_clicked(self) -> None:
|
||||
"""Permanently clear all runtime histories, ring backlogs, and GPR cache."""
|
||||
self._apply_history_mode_deletion(mode_label="GPR", remove_last_only=False)
|
||||
|
||||
def _on_gpr_remove_last_measurement_clicked(self) -> None:
|
||||
"""Permanently delete the latest measurement from runtime histories and rings."""
|
||||
self._apply_history_mode_deletion(mode_label="GPR", remove_last_only=True)
|
||||
|
||||
def _clear_history_mode_caches(self) -> None:
|
||||
"""Drop mode-specific cached render state."""
|
||||
"""Drop cached render state for pass-through, B-scan, and GPR views."""
|
||||
self._bscan_history_floor_collection_id = 0
|
||||
self._clear_bscan_plot_history()
|
||||
if hasattr(self, "_bscan_plot"):
|
||||
self._bscan_plot.clear()
|
||||
self._clear_trace_plots()
|
||||
if hasattr(self, "_gpr_plot"):
|
||||
self._clear_gpr_plot()
|
||||
|
||||
def _apply_history_mode_deletion(self, *, mode_label: str, remove_last_only: bool) -> None:
|
||||
"""Apply destructive history deletion via C++ processor history commands."""
|
||||
resume_acquisition = self._supervisor.is_running()
|
||||
history_command = "remove_last" if remove_last_only else "clear_all"
|
||||
action = "last measurement removed" if remove_last_only else "history fully cleared"
|
||||
dropped_results = 0
|
||||
|
||||
try:
|
||||
if resume_acquisition:
|
||||
self._stop_run()
|
||||
|
||||
if self._result_reader is not None:
|
||||
dropped_results = self._result_reader.drop_all()
|
||||
|
||||
if remove_last_only:
|
||||
retained_raw, retained_pre, retained_result = remove_last_aligned_histories(
|
||||
list(self._raw_history),
|
||||
list(self._pre_history),
|
||||
list(self._result_history),
|
||||
)
|
||||
else:
|
||||
retained_raw = []
|
||||
retained_pre = []
|
||||
retained_result = []
|
||||
self._replace_runtime_history(
|
||||
retained_raw=retained_raw,
|
||||
retained_pre=retained_pre,
|
||||
retained_result=retained_result,
|
||||
)
|
||||
self._clear_history_mode_caches()
|
||||
|
||||
self._write_live_processing_config(history_command=history_command, bump_history_seq=True)
|
||||
|
||||
if self._supervisor.is_processor_running():
|
||||
self._drain_results_until_quiet(timeout_s=0.35, poll_s=0.01)
|
||||
|
||||
self._update_history_indicator()
|
||||
self._redraw_after_history_deletion()
|
||||
if resume_acquisition:
|
||||
self._start_run()
|
||||
self._log(f"{mode_label} {action}; dropped pending results={dropped_results}")
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self._show_error(f"Failed to delete {mode_label} history: {exc}")
|
||||
|
||||
def _redraw_after_history_deletion(self) -> None:
|
||||
"""Refresh plot immediately after destructive history deletion."""
|
||||
if self._processing_mode.currentText() == "bscan":
|
||||
|
||||
@@ -536,7 +536,7 @@ class AppWindowPlotMixin:
|
||||
plot.setLabel("left", "Depth", units="m")
|
||||
|
||||
view_box = plot.getViewBox()
|
||||
view_box.invertY(True)
|
||||
view_box.invertY(False)
|
||||
view_box.enableAutoRange(x=False, y=False)
|
||||
|
||||
if self._gpr_lookup_table is None:
|
||||
@@ -673,6 +673,7 @@ class AppWindowPlotMixin:
|
||||
plot.setUpdatesEnabled(False)
|
||||
try:
|
||||
self._ensure_gpr_plot_items()
|
||||
plot.getViewBox().invertY(False)
|
||||
self._clear_gpr_point_labels()
|
||||
self._clear_gpr_region_labels()
|
||||
self._clear_gpr_region_masks()
|
||||
@@ -684,7 +685,7 @@ class AppWindowPlotMixin:
|
||||
self._gpr_image_item.show()
|
||||
|
||||
plot.setXRange(x_min, x_max, padding=0.02)
|
||||
plot.setYRange(y_min, y_max, padding=0.02)
|
||||
plot.setYRange(min(0.0, y_min), y_max, padding=0.02)
|
||||
|
||||
x_tx, x_rx = self._selected_gpr_geometry()
|
||||
if x_tx.size > 0:
|
||||
|
||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
import time
|
||||
|
||||
from PyQt6.QtWidgets import QFileDialog
|
||||
from python_app.gui.runtime.history import record_result_history
|
||||
from python_app.gui.runtime.history import record_result_history, remove_last_aligned_histories
|
||||
|
||||
|
||||
class AppWindowSnapshotMixin:
|
||||
@@ -90,16 +90,27 @@ class AppWindowSnapshotMixin:
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self._show_error(f"Failed to save VNA history JSON: {exc}")
|
||||
|
||||
def _remove_last_runtime_history(self) -> None:
|
||||
"""Remove the newest runtime measurement from all stages and processor replay state."""
|
||||
self._apply_runtime_history_deletion(remove_last_only=True)
|
||||
|
||||
def _clear_all_runtime_history(self) -> None:
|
||||
"""Clear all runtime histories, ring backlogs, and processor replay state."""
|
||||
self._apply_runtime_history_deletion(remove_last_only=False)
|
||||
|
||||
def _apply_runtime_history_deletion(self, *, remove_last_only: bool) -> None:
|
||||
"""Apply destructive runtime-history deletion across readers, caches, and processor replay state."""
|
||||
if self._capture_session is not None:
|
||||
self._show_error("Cannot clear runtime history during active capture sequence")
|
||||
self._show_error("Cannot modify runtime history during active capture sequence")
|
||||
return
|
||||
|
||||
resume_acquisition = self._supervisor.is_running()
|
||||
dropped_raw = 0
|
||||
dropped_pre = 0
|
||||
dropped_results = 0
|
||||
history_command = "remove_last" if remove_last_only else "clear_all"
|
||||
action_label = "last runtime measurement removed" if remove_last_only else "runtime history fully cleared"
|
||||
error_action = "remove last runtime measurement" if remove_last_only else "clear runtime history"
|
||||
|
||||
try:
|
||||
if resume_acquisition:
|
||||
@@ -109,23 +120,36 @@ class AppWindowSnapshotMixin:
|
||||
dropped_pre = self._pre_reader.drop_all() if self._pre_reader is not None else 0
|
||||
dropped_results = self._result_reader.drop_all() if self._result_reader is not None else 0
|
||||
|
||||
self._replace_runtime_history(retained_raw=[], retained_pre=[], retained_result=[])
|
||||
if remove_last_only:
|
||||
retained_raw, retained_pre, retained_result = remove_last_aligned_histories(
|
||||
list(self._raw_history),
|
||||
list(self._pre_history),
|
||||
list(self._result_history),
|
||||
)
|
||||
else:
|
||||
retained_raw = []
|
||||
retained_pre = []
|
||||
retained_result = []
|
||||
|
||||
self._replace_runtime_history(
|
||||
retained_raw=retained_raw,
|
||||
retained_pre=retained_pre,
|
||||
retained_result=retained_result,
|
||||
)
|
||||
self._bscan_history_floor_collection_id = 0
|
||||
self._clear_history_mode_caches()
|
||||
|
||||
# Clear processor-side replay cache so newly rendered B-scan starts clean.
|
||||
self._write_live_processing_config(history_command="clear_all", bump_history_seq=True)
|
||||
self._write_live_processing_config(history_command=history_command, bump_history_seq=True)
|
||||
|
||||
if self._supervisor.is_processor_running():
|
||||
self._drain_results_until_quiet(timeout_s=0.25, poll_s=0.01)
|
||||
self._drain_results_until_quiet(timeout_s=0.35, poll_s=0.01)
|
||||
if self._result_reader is not None:
|
||||
dropped_results += self._result_reader.drop_all()
|
||||
self._result_history.clear()
|
||||
|
||||
self._update_history_indicator()
|
||||
self._redraw_after_history_deletion()
|
||||
self._log(
|
||||
"Runtime history fully cleared: "
|
||||
f"{action_label}: "
|
||||
f"dropped raw={dropped_raw}, "
|
||||
f"preprocessed={dropped_pre}, "
|
||||
f"results={dropped_results}"
|
||||
@@ -134,7 +158,7 @@ class AppWindowSnapshotMixin:
|
||||
if resume_acquisition:
|
||||
self._start_run()
|
||||
except Exception as exc: # noqa: BLE001
|
||||
self._show_error(f"Failed to clear runtime history: {exc}")
|
||||
self._show_error(f"Failed to {error_action}: {exc}")
|
||||
|
||||
def _browse_save_path(self) -> None:
|
||||
"""Open directory picker for snapshot output path."""
|
||||
|
||||
@@ -18,6 +18,8 @@ def build_data_actions_group(owner) -> QGroupBox:
|
||||
save_button.clicked.connect(owner._save_snapshot)
|
||||
save_vna_json_button = QPushButton("Save VNA History JSON")
|
||||
save_vna_json_button.clicked.connect(owner._save_vna_history_json)
|
||||
remove_last_button = QPushButton("Remove Last Runtime Measurement")
|
||||
remove_last_button.clicked.connect(owner._remove_last_runtime_history)
|
||||
clear_history_button = QPushButton("Clear ALL Runtime History")
|
||||
clear_history_button.clicked.connect(owner._clear_all_runtime_history)
|
||||
owner._save_count = QSpinBox()
|
||||
@@ -35,6 +37,7 @@ def build_data_actions_group(owner) -> QGroupBox:
|
||||
|
||||
save_row.addWidget(save_button)
|
||||
save_row.addWidget(save_vna_json_button)
|
||||
save_row.addWidget(remove_last_button)
|
||||
save_row.addWidget(clear_history_button)
|
||||
save_row.addWidget(QLabel("Last N"))
|
||||
save_row.addWidget(owner._save_count)
|
||||
|
||||
@@ -8,9 +8,7 @@ from PyQt6.QtWidgets import (
|
||||
QDoubleSpinBox,
|
||||
QFormLayout,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
QLineEdit,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QSpinBox,
|
||||
QStackedWidget,
|
||||
@@ -138,24 +136,12 @@ def build_processing_group(owner) -> QGroupBox:
|
||||
owner._bscan_stop_freq_mhz.setSingleStep(10.0)
|
||||
owner._bscan_stop_freq_mhz.setValue(8800.0)
|
||||
|
||||
owner._bscan_clear_history_button = QPushButton("Clear B-scan History")
|
||||
owner._bscan_clear_history_button.clicked.connect(owner._on_bscan_clear_history_clicked)
|
||||
owner._bscan_remove_last_button = QPushButton("Remove Last Sweep")
|
||||
owner._bscan_remove_last_button.clicked.connect(owner._on_bscan_remove_last_sweep_clicked)
|
||||
bscan_actions = QWidget(owner._processing_mode_pages)
|
||||
bscan_actions_layout = QHBoxLayout(bscan_actions)
|
||||
bscan_actions_layout.setContentsMargins(0, 0, 0, 0)
|
||||
bscan_actions_layout.setSpacing(8)
|
||||
bscan_actions_layout.addWidget(owner._bscan_remove_last_button)
|
||||
bscan_actions_layout.addWidget(owner._bscan_clear_history_button)
|
||||
|
||||
bscan_form.addRow("Axis", owner._bscan_axis)
|
||||
bscan_form.addRow("Cut m", owner._bscan_cut_m)
|
||||
bscan_form.addRow("Max depth m", owner._bscan_max_depth_m)
|
||||
bscan_form.addRow("Gain", owner._bscan_gain)
|
||||
bscan_form.addRow("Start MHz", owner._bscan_start_freq_mhz)
|
||||
bscan_form.addRow("Stop MHz", owner._bscan_stop_freq_mhz)
|
||||
bscan_form.addRow(bscan_actions)
|
||||
owner._processing_mode_pages.addWidget(bscan_page)
|
||||
|
||||
gpr_page = QWidget(owner._processing_mode_pages)
|
||||
@@ -206,17 +192,6 @@ def build_processing_group(owner) -> QGroupBox:
|
||||
owner._gpr_background_mean_count.setRange(0, 10_000)
|
||||
owner._gpr_background_mean_count.setValue(10)
|
||||
|
||||
owner._gpr_clear_history_button = QPushButton("Clear GPR History")
|
||||
owner._gpr_clear_history_button.clicked.connect(owner._on_gpr_clear_history_clicked)
|
||||
owner._gpr_remove_last_button = QPushButton("Remove Last Measurement")
|
||||
owner._gpr_remove_last_button.clicked.connect(owner._on_gpr_remove_last_measurement_clicked)
|
||||
gpr_actions = QWidget(owner._processing_mode_pages)
|
||||
gpr_actions_layout = QHBoxLayout(gpr_actions)
|
||||
gpr_actions_layout.setContentsMargins(0, 0, 0, 0)
|
||||
gpr_actions_layout.setSpacing(8)
|
||||
gpr_actions_layout.addWidget(owner._gpr_remove_last_button)
|
||||
gpr_actions_layout.addWidget(owner._gpr_clear_history_button)
|
||||
|
||||
gpr_form.addRow("Input positions", owner._gpr_input_positions_input)
|
||||
gpr_form.addRow("Output positions", owner._gpr_output_positions_input)
|
||||
gpr_form.addRow("Min depth m", owner._gpr_min_depth_m)
|
||||
@@ -226,7 +201,6 @@ def build_processing_group(owner) -> QGroupBox:
|
||||
gpr_form.addRow("Stop MHz", owner._gpr_stop_freq_mhz)
|
||||
gpr_form.addRow(owner._gpr_background_subtract_enabled)
|
||||
gpr_form.addRow("Mean count", owner._gpr_background_mean_count)
|
||||
gpr_form.addRow(gpr_actions)
|
||||
owner._processing_mode_pages.addWidget(gpr_page)
|
||||
|
||||
owner._processing_mode.currentTextChanged.connect(owner._on_processing_mode_changed)
|
||||
|
||||
Reference in New Issue
Block a user