optimized bscan

This commit is contained in:
Ayzen
2025-10-06 21:30:01 +03:00
parent 6c363433d6
commit ad1a39ac6b

View File

@ -165,19 +165,6 @@ class BScanProcessor(BaseProcessor):
Or: {"error": "..."} on failure. Or: {"error": "..."} on failure.
""" """
try: try:
# Skip B-scan processing for S21 mode - only works with S11
# if vna_config and vna_config.get("mode") == "s21":
# return {"error": "B-scan only available in S11 mode"}
# Choose calibrated data when provided
data_to_process = calibrated_data or sweep_data
complex_data = self._get_complex_s11(data_to_process)
if complex_data is None or complex_data.size == 0:
logger.warning("No valid complex data for B-scan processing")
return {"error": "No valid complex data"}
# Optional reference subtraction (latest stored reference in sweep history)
reference_data: SweepData | None = None reference_data: SweepData | None = None
if self._config["open_air"] and self._sweep_history: if self._config["open_air"] and self._sweep_history:
latest_history = self._sweep_history[-1] latest_history = self._sweep_history[-1]
@ -223,18 +210,8 @@ class BScanProcessor(BaseProcessor):
all_timestamps = [record["timestamp"] for record in self._plot_history] all_timestamps = [record["timestamp"] for record in self._plot_history]
return { return {
"time_domain_data": analysis["time_data"].tolist(), # Latest sweep **payload,
"distance_data": analysis["distance"].tolist(), # Latest sweep **history_payload,
"frequency_range": analysis["freq_range"],
"reference_used": bool(self._config["open_air"] and reference_data is not None),
"axis_type": self._config["axis"],
"points_processed": int(complex_data.size),
"plot_history_count": len(self._plot_history),
# Full history data
"all_time_domain_data": all_time_domain,
"all_distance_data": all_distance,
"all_sweep_numbers": all_sweep_numbers,
"all_timestamps": all_timestamps,
} }
except Exception as exc: # noqa: BLE001 except Exception as exc: # noqa: BLE001
@ -396,47 +373,143 @@ class BScanProcessor(BaseProcessor):
# Clear existing plot history to rebuild from scratch # Clear existing plot history to rebuild from scratch
self._plot_history.clear() self._plot_history.clear()
# Process all sweeps in history with current config last_payload: dict[str, Any] | None = None
last_processed = None last_vna_config: dict[str, Any] = {}
last_vna_config = {}
for entry in self._sweep_history:
sweep_data = entry["sweep_data"]
calibrated_data = entry["calibrated_data"]
vna_config = entry["vna_config"]
# Use process_sweep to handle the processing logic for entry in history_entries:
processed = self.process_sweep(sweep_data, calibrated_data, vna_config) payload, plot_record = self._process_single_sweep(
entry["sweep_data"],
# Skip if processing failed entry["calibrated_data"],
if "error" not in processed: entry["vna_config"],
last_processed = processed entry.get("reference_data"),
last_vna_config = vna_config
# Trim plot history if needed
if len(self._plot_history) > self._max_history:
self._plot_history = self._plot_history[-self._max_history:]
logger.info("Recalculated B-scan with all history",
plot_records=len(self._plot_history),
sweep_records=len(self._sweep_history))
# Build result from last successful processing
if last_processed is None:
return None
# Generate plotly config and wrap into ProcessedResult
plotly_conf = self.generate_plotly_config(last_processed, last_vna_config)
ui_params = self.get_ui_parameters()
return ProcessedResult(
processor_id=self.processor_id,
timestamp=datetime.now().timestamp(),
data=last_processed,
plotly_config=plotly_conf,
ui_parameters=ui_params,
metadata=self._get_metadata(),
) )
if "error" in payload:
continue
self._append_plot_record(plot_record)
last_payload = payload
last_vna_config = entry.get("vna_config", {})
if last_payload is None:
return None
history_payload = self._build_full_history_payload()
combined_data = {
**last_payload,
**history_payload,
}
logger.info(
"Recalculated B-scan with all history",
plot_records=history_payload["plot_history_count"],
sweep_records=len(history_entries),
)
plotly_conf = self.generate_plotly_config(combined_data, last_vna_config)
ui_params = self.get_ui_parameters()
return ProcessedResult(
processor_id=self.processor_id,
timestamp=datetime.now().timestamp(),
data=combined_data,
plotly_config=plotly_conf,
ui_parameters=ui_params,
metadata=self._get_metadata(),
)
# -------------------------------------------------------------------------
# History helpers
# -------------------------------------------------------------------------
def _process_single_sweep(
self,
sweep_data: SweepData,
calibrated_data: SweepData | None,
vna_config: dict[str, Any],
reference_data: SweepData | None,
) -> tuple[dict[str, Any], dict[str, Any]]:
"""Process a single sweep and produce payload + plot record."""
# Skip B-scan processing for S21 mode - only works with S11
# if vna_config and vna_config.get("mode") == "s21":
# return {"error": "B-scan only available in S11 mode"}, {}
data_to_process = calibrated_data or sweep_data
complex_data = self._get_complex_s11(data_to_process)
if complex_data is None or complex_data.size == 0:
logger.warning("No valid complex data for B-scan processing")
return {"error": "No valid complex data"}, {}
if self._config["open_air"] and reference_data is None:
logger.warning("Open air subtraction cannot be done: reference_data is None")
self._config["open_air"] = False
if self._config["open_air"] and reference_data is not None:
reference_complex = self._get_complex_s11(reference_data)
if reference_complex is not None and reference_complex.size:
complex_data = self._subtract_reference(complex_data, reference_complex)
logger.debug("Applied open-air reference subtraction")
self._update_frequency_ranges(vna_config)
analysis = self._perform_data_analysis(complex_data, vna_config)
if analysis is None:
logger.warning("Data analysis failed")
return {"error": "Data analysis failed"}, {}
time_data = analysis["time_data"].tolist()
distance_data = analysis["distance"].tolist()
freq_range = analysis["freq_range"]
plot_record = {
"time_domain_data": time_data,
"distance_data": distance_data,
"sweep_number": sweep_data.sweep_number,
"timestamp": sweep_data.timestamp,
"frequency_range": freq_range,
}
payload = {
"time_domain_data": time_data,
"distance_data": distance_data,
"frequency_range": freq_range,
"reference_used": bool(self._config["open_air"] and reference_data is not None),
"axis_type": self._config["axis"],
"points_processed": int(complex_data.size),
}
return payload, plot_record
def _append_plot_record(self, plot_record: dict[str, Any]) -> None:
"""Store a plot record in history with trimming."""
if not plot_record:
return
with self._lock:
self._plot_history.append(plot_record)
if len(self._plot_history) > self._max_history:
self._plot_history = self._plot_history[-self._max_history :]
def _build_full_history_payload(self) -> dict[str, Any]:
"""Assemble cached history into JSON-friendly lists."""
with self._lock:
all_time_domain = [record["time_domain_data"] for record in self._plot_history]
all_distance = [record["distance_data"] for record in self._plot_history]
all_sweep_numbers = [record["sweep_number"] for record in self._plot_history]
all_timestamps = [record["timestamp"] for record in self._plot_history]
count = len(self._plot_history)
return {
"all_time_domain_data": all_time_domain,
"all_distance_data": all_distance,
"all_sweep_numbers": all_sweep_numbers,
"all_timestamps": all_timestamps,
"plot_history_count": count,
}
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# Low-level helpers # Low-level helpers
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------