phase graph

This commit is contained in:
awe
2026-04-10 22:34:36 +03:00
parent d0d2f5a59e
commit 992ba88480
2 changed files with 59 additions and 0 deletions

View File

@ -465,6 +465,23 @@ def resolve_visible_aux_curves(aux_curves: SweepAuxCurves, enabled: bool) -> Swe
return aux_1_arr, aux_2_arr return aux_1_arr, aux_2_arr
def compute_aux_phase_curve(aux_curves: SweepAuxCurves) -> Optional[np.ndarray]:
"""Compute phase-like curve atan2(aux_2, aux_1) for raw CH2/CH1 display."""
if aux_curves is None:
return None
try:
aux_1, aux_2 = aux_curves
except Exception:
return None
aux_1_arr = np.asarray(aux_1, dtype=np.float32).reshape(-1)
aux_2_arr = np.asarray(aux_2, dtype=np.float32).reshape(-1)
width = min(aux_1_arr.size, aux_2_arr.size)
if width <= 0:
return None
phase = np.arctan2(aux_2_arr[:width], aux_1_arr[:width]).astype(np.float32, copy=False)
return phase
def decimate_curve_for_display( def decimate_curve_for_display(
xs: Optional[np.ndarray], xs: Optional[np.ndarray],
ys: Optional[np.ndarray], ys: Optional[np.ndarray],
@ -717,6 +734,21 @@ def run_pyqtgraph(args) -> None:
except Exception: except Exception:
pass pass
p_line_phase = win.addPlot(row=2, col=0, title="Raw phase: atan(CH2/CH1)")
p_line_phase.showGrid(x=True, y=True, alpha=0.3)
curve_phase = p_line_phase.plot(pen=pg.mkPen((230, 180, 40), width=1))
p_line_phase.setLabel("bottom", "ГГц")
p_line_phase.setLabel("left", "рад")
try:
p_line_phase.setXLink(p_line)
except Exception:
pass
if not complex_sweep_mode:
try:
p_line_phase.hide()
except Exception:
pass
p_img = win.addPlot(row=0, col=1, title="Сырые данные водопад") p_img = win.addPlot(row=0, col=1, title="Сырые данные водопад")
p_img.invertY(False) p_img.invertY(False)
p_img.showGrid(x=False, y=False) p_img.showGrid(x=False, y=False)
@ -1820,6 +1852,7 @@ def run_pyqtgraph(args) -> None:
) )
displayed_calib = None displayed_calib = None
displayed_aux = resolve_visible_aux_curves(runtime.current_aux_curves, parsed_data_enabled) displayed_aux = resolve_visible_aux_curves(runtime.current_aux_curves, parsed_data_enabled)
displayed_phase = compute_aux_phase_curve(displayed_aux)
if runtime.current_sweep_raw is not None: if runtime.current_sweep_raw is not None:
raw_x, raw_y = decimate_curve_for_display(xs, runtime.current_sweep_raw) raw_x, raw_y = decimate_curve_for_display(xs, runtime.current_sweep_raw)
@ -1841,6 +1874,14 @@ def run_pyqtgraph(args) -> None:
curve_aux_1.setData([], []) curve_aux_1.setData([], [])
curve_aux_2.setData([], []) curve_aux_2.setData([], [])
if displayed_phase is not None:
phase_width = min(xs.size, displayed_phase.size)
phase_x, phase_y = decimate_curve_for_display(xs[:phase_width], displayed_phase[:phase_width])
phase_x, phase_y = sanitize_curve_data_for_display(phase_x, phase_y)
curve_phase.setData(phase_x, phase_y, autoDownsample=False)
else:
curve_phase.setData([], [])
if runtime.calib_envelope is not None: if runtime.calib_envelope is not None:
if runtime.current_sweep_raw is not None: if runtime.current_sweep_raw is not None:
displayed_calib = resample_envelope(runtime.calib_envelope, runtime.current_sweep_raw.size) displayed_calib = resample_envelope(runtime.calib_envelope, runtime.current_sweep_raw.size)
@ -1887,10 +1928,14 @@ def run_pyqtgraph(args) -> None:
) )
if aux_limits is not None: if aux_limits is not None:
p_line_aux_vb.setYRange(aux_limits[0], aux_limits[1], padding=0) p_line_aux_vb.setYRange(aux_limits[0], aux_limits[1], padding=0)
phase_limits = compute_auto_ylim(displayed_phase)
if phase_limits is not None:
p_line_phase.setYRange(phase_limits[0], phase_limits[1], padding=0)
line_x_bounds = resolve_axis_bounds(xs) line_x_bounds = resolve_axis_bounds(xs)
if line_x_bounds is not None: if line_x_bounds is not None:
p_line.setXRange(line_x_bounds[0], line_x_bounds[1], padding=0) p_line.setXRange(line_x_bounds[0], line_x_bounds[1], padding=0)
p_line_phase.setXRange(line_x_bounds[0], line_x_bounds[1], padding=0)
sweep_for_fft = runtime.current_fft_input sweep_for_fft = runtime.current_fft_input
if sweep_for_fft is None: if sweep_for_fft is None:

View File

@ -13,6 +13,7 @@ from rfg_adc_plotter.gui.pyqtgraph_backend import (
build_main_window_layout, build_main_window_layout,
coalesce_packets_for_ui, coalesce_packets_for_ui,
compute_background_subtracted_bscan_levels, compute_background_subtracted_bscan_levels,
compute_aux_phase_curve,
decimate_curve_for_display, decimate_curve_for_display,
resolve_axis_bounds, resolve_axis_bounds,
resolve_heavy_refresh_stride, resolve_heavy_refresh_stride,
@ -217,6 +218,19 @@ class ProcessingTests(unittest.TestCase):
self.assertTrue(np.allclose(visible[0], aux[0])) self.assertTrue(np.allclose(visible[0], aux[0]))
self.assertTrue(np.allclose(visible[1], aux[1])) self.assertTrue(np.allclose(visible[1], aux[1]))
def test_compute_aux_phase_curve_returns_atan2_of_aux_channels(self):
aux = (
np.asarray([1.0, 1.0, -1.0, 0.0], dtype=np.float32),
np.asarray([0.0, 1.0, 1.0, 1.0], dtype=np.float32),
)
phase = compute_aux_phase_curve(aux)
self.assertIsNotNone(phase)
expected = np.asarray([0.0, np.pi / 4.0, 3.0 * np.pi / 4.0, np.pi / 2.0], dtype=np.float32)
self.assertEqual(phase.shape, expected.shape)
self.assertTrue(np.allclose(phase, expected, atol=1e-6))
def test_decimate_curve_for_display_preserves_small_series(self): def test_decimate_curve_for_display_preserves_small_series(self):
xs = np.linspace(3.3, 14.3, 64, dtype=np.float64) xs = np.linspace(3.3, 14.3, 64, dtype=np.float64)
ys = np.linspace(-1.0, 1.0, 64, dtype=np.float32) ys = np.linspace(-1.0, 1.0, 64, dtype=np.float32)