This commit is contained in:
awe
2026-03-25 18:54:59 +03:00
parent fa4870c56c
commit 64e66933e4
14 changed files with 350 additions and 42 deletions

View File

@ -155,6 +155,41 @@ def apply_working_range_to_aux_curves(
)
def apply_working_range_to_signal(
freqs: Optional[np.ndarray],
sweep: Optional[np.ndarray],
signal_values: Optional[np.ndarray],
range_min_ghz: float,
range_max_ghz: float,
) -> Optional[np.ndarray]:
"""Crop an arbitrary signal with the same mask used for the raw sweep."""
if freqs is None or sweep is None or signal_values is None:
return None
freq_arr = np.asarray(freqs, dtype=np.float64).reshape(-1)
sweep_arr = np.asarray(sweep, dtype=np.float32).reshape(-1)
signal_arr = np.asarray(signal_values).reshape(-1)
width = min(freq_arr.size, sweep_arr.size, signal_arr.size)
if width <= 0:
return None
freq_arr = freq_arr[:width]
sweep_arr = sweep_arr[:width]
signal_arr = signal_arr[:width]
valid = (
np.isfinite(freq_arr)
& np.isfinite(sweep_arr)
& (freq_arr >= float(range_min_ghz))
& (freq_arr <= float(range_max_ghz))
)
if not np.any(valid):
return None
if np.iscomplexobj(signal_arr):
return np.asarray(signal_arr[valid], dtype=np.complex64)
return np.asarray(signal_arr[valid], dtype=np.float32)
def resolve_visible_aux_curves(aux_curves: SweepAuxCurves, enabled: bool) -> SweepAuxCurves:
"""Return auxiliary curves only when their display is enabled."""
if (not enabled) or aux_curves is None:
@ -198,6 +233,7 @@ def run_pyqtgraph(args) -> None:
"""Start the PyQtGraph GUI."""
peak_calibrate_mode = bool(getattr(args, "calibrate", False))
peak_search_enabled = bool(getattr(args, "peak_search", False))
complex_sweep_mode = bool(getattr(args, "parser_complex_ascii", False))
try:
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtWidgets # type: ignore
@ -218,6 +254,7 @@ def run_pyqtgraph(args) -> None:
logscale=bool(args.logscale),
parser_16_bit_x2=bool(args.parser_16_bit_x2),
parser_test=bool(args.parser_test),
parser_complex_ascii=complex_sweep_mode,
)
reader.start()
@ -413,6 +450,12 @@ def run_pyqtgraph(args) -> None:
background_buttons_row.addWidget(background_load_btn)
background_group_layout.addLayout(background_buttons_row)
parsed_data_cb = QtWidgets.QCheckBox("данные после парсинга")
if complex_sweep_mode:
try:
parsed_data_cb.setText("Re/Im после парсинга")
p_line.setTitle("Модуль комплексного сигнала")
except Exception:
pass
try:
settings_layout.addWidget(QtWidgets.QLabel("Настройки"))
except Exception:
@ -576,6 +619,8 @@ def run_pyqtgraph(args) -> None:
if runtime.full_current_freqs is None or runtime.full_current_sweep_raw is None:
runtime.current_freqs = None
runtime.current_sweep_raw = None
runtime.current_fft_source = None
runtime.current_fft_input = None
runtime.current_aux_curves = None
runtime.current_sweep_norm = None
runtime.current_fft_mag = None
@ -591,6 +636,13 @@ def run_pyqtgraph(args) -> None:
)
runtime.current_freqs = current_freqs
runtime.current_sweep_raw = current_sweep
runtime.current_fft_source = apply_working_range_to_signal(
runtime.full_current_freqs,
runtime.full_current_sweep_raw,
runtime.full_current_fft_source,
runtime.range_min_ghz,
runtime.range_max_ghz,
)
runtime.current_aux_curves = apply_working_range_to_aux_curves(
runtime.full_current_freqs,
runtime.full_current_sweep_raw,
@ -604,6 +656,8 @@ def run_pyqtgraph(args) -> None:
reset_ring_buffers()
runtime.current_freqs = None
runtime.current_sweep_raw = None
runtime.current_fft_source = None
runtime.current_fft_input = None
runtime.current_aux_curves = None
runtime.current_sweep_norm = None
runtime.current_fft_mag = None
@ -615,6 +669,10 @@ def run_pyqtgraph(args) -> None:
recompute_current_processed_sweep(push_to_ring=push_to_ring)
def recompute_current_processed_sweep(push_to_ring: bool = False) -> None:
fft_source = runtime.current_fft_source
if fft_source is None and runtime.current_sweep_raw is not None:
fft_source = np.asarray(runtime.current_sweep_raw, dtype=np.float32)
if (
runtime.current_sweep_raw is not None
and runtime.current_sweep_raw.size > 0
@ -625,6 +683,16 @@ def run_pyqtgraph(args) -> None:
else:
runtime.current_sweep_norm = None
if fft_source is None or np.asarray(fft_source).size == 0:
runtime.current_fft_input = None
elif calib_enabled and runtime.calib_envelope is not None:
runtime.current_fft_input = normalize_by_envelope(fft_source, runtime.calib_envelope)
else:
runtime.current_fft_input = np.asarray(
fft_source,
dtype=np.complex64 if np.iscomplexobj(fft_source) else np.float32,
).copy()
runtime.current_fft_mag = None
runtime.current_fft_db = None
if (
@ -635,8 +703,9 @@ def run_pyqtgraph(args) -> None:
return
sweep_for_processing = runtime.current_sweep_norm if runtime.current_sweep_norm is not None else runtime.current_sweep_raw
fft_input_for_processing = runtime.current_fft_input if runtime.current_fft_input is not None else sweep_for_processing
ensure_buffer(runtime.current_sweep_raw.size)
runtime.ring.push(sweep_for_processing, runtime.current_freqs)
runtime.ring.push(sweep_for_processing, runtime.current_freqs, fft_input=fft_input_for_processing)
runtime.current_distances = runtime.ring.distance_axis
runtime.current_fft_mag = runtime.ring.get_last_fft_linear()
runtime.current_fft_db = runtime.ring.last_fft_db
@ -860,7 +929,7 @@ def run_pyqtgraph(args) -> None:
runtime.mark_dirty()
try:
fft_mode_combo.setCurrentIndex(1)
fft_mode_combo.setCurrentIndex(2 if complex_sweep_mode else 1)
except Exception:
pass
restore_range_controls()
@ -1060,27 +1129,46 @@ def run_pyqtgraph(args) -> None:
break
drained += 1
base_freqs = np.linspace(SWEEP_FREQ_MIN_GHZ, SWEEP_FREQ_MAX_GHZ, sweep.size, dtype=np.float64)
calibrated = calibrate_freqs(
{
"F": base_freqs,
"I": sweep,
}
)
runtime.full_current_freqs = np.asarray(calibrated["F"], dtype=np.float64)
runtime.full_current_sweep_raw = np.asarray(calibrated["I"], dtype=np.float32)
if aux_curves is None:
runtime.full_current_aux_curves = None
else:
runtime.full_current_aux_curves = None
runtime.full_current_fft_source = None
if complex_sweep_mode and aux_curves is not None:
try:
aux_1, aux_2 = aux_curves
calibrated_aux_1 = calibrate_freqs({"F": base_freqs, "I": aux_1})["I"]
calibrated_aux_1_payload = calibrate_freqs({"F": base_freqs, "I": aux_1})
calibrated_aux_2 = calibrate_freqs({"F": base_freqs, "I": aux_2})["I"]
runtime.full_current_aux_curves = (
np.asarray(calibrated_aux_1, dtype=np.float32),
np.asarray(calibrated_aux_2, dtype=np.float32),
runtime.full_current_freqs = np.asarray(calibrated_aux_1_payload["F"], dtype=np.float64)
calibrated_aux_1 = np.asarray(calibrated_aux_1_payload["I"], dtype=np.float32)
calibrated_aux_2 = np.asarray(calibrated_aux_2, dtype=np.float32)
runtime.full_current_aux_curves = (calibrated_aux_1, calibrated_aux_2)
runtime.full_current_fft_source = (
calibrated_aux_1.astype(np.complex64) + (1j * calibrated_aux_2.astype(np.complex64))
)
runtime.full_current_sweep_raw = np.abs(runtime.full_current_fft_source).astype(np.float32)
except Exception:
runtime.full_current_aux_curves = None
runtime.full_current_fft_source = None
if runtime.full_current_fft_source is None:
calibrated = calibrate_freqs(
{
"F": base_freqs,
"I": sweep,
}
)
runtime.full_current_freqs = np.asarray(calibrated["F"], dtype=np.float64)
runtime.full_current_sweep_raw = np.asarray(calibrated["I"], dtype=np.float32)
runtime.full_current_fft_source = np.asarray(runtime.full_current_sweep_raw, dtype=np.float32).copy()
if aux_curves is not None:
try:
aux_1, aux_2 = aux_curves
calibrated_aux_1 = calibrate_freqs({"F": base_freqs, "I": aux_1})["I"]
calibrated_aux_2 = calibrate_freqs({"F": base_freqs, "I": aux_2})["I"]
runtime.full_current_aux_curves = (
np.asarray(calibrated_aux_1, dtype=np.float32),
np.asarray(calibrated_aux_2, dtype=np.float32),
)
except Exception:
runtime.full_current_aux_curves = None
runtime.current_info = info
refresh_current_window(push_to_ring=True)
if drained > 0:
@ -1165,7 +1253,9 @@ def run_pyqtgraph(args) -> None:
if finite_x.size > 0:
p_line.setXRange(float(np.min(finite_x)), float(np.max(finite_x)), padding=0)
sweep_for_fft = runtime.current_sweep_norm if runtime.current_sweep_norm is not None else runtime.current_sweep_raw
sweep_for_fft = runtime.current_fft_input
if sweep_for_fft is None:
sweep_for_fft = runtime.current_sweep_norm if runtime.current_sweep_norm is not None else runtime.current_sweep_raw
distance_axis = runtime.current_distances if runtime.current_distances is not None else runtime.ring.distance_axis
if sweep_for_fft is not None and sweep_for_fft.size > 0 and distance_axis is not None:
if runtime.current_fft_mag is None or runtime.current_fft_mag.size != distance_axis.size or runtime.plot_dirty: