new graphs

This commit is contained in:
awe
2026-06-08 16:03:54 +03:00
parent 8e5057aef6
commit 3f64960542
2 changed files with 132 additions and 38 deletions

View File

@ -950,7 +950,7 @@ def run_pyqtgraph(args) -> None:
p_line_aux_vb = pg.ViewBox()
try:
p_line.showAxis("right")
p_line.getAxis("right").setLabel("√(CH1²+CH2²), В")
p_line.getAxis("right").setLabel("CH1, CH2 (В)")
p_line.scene().addItem(p_line_aux_vb)
p_line.getAxis("right").linkToView(p_line_aux_vb)
p_line_aux_vb.setXLink(p_line)
@ -960,36 +960,28 @@ def run_pyqtgraph(args) -> None:
curve_aux_2 = pg.PlotDataItem(pen=pg.mkPen((170, 70, 255), width=1))
curve_aux_3 = pg.PlotDataItem(pen=pg.mkPen((255, 120, 20), width=1))
curve_aux_4 = pg.PlotDataItem(pen=pg.mkPen((120, 60, 220), width=1))
curve_secondary_ch1 = pg.PlotDataItem(pen=pg.mkPen((0, 200, 100), width=1))
curve_secondary_ch2 = pg.PlotDataItem(pen=pg.mkPen((200, 100, 200), width=1))
if p_line_aux_vb is not None:
p_line_aux_vb.addItem(curve_aux_1)
p_line_aux_vb.addItem(curve_aux_2)
p_line_aux_vb.addItem(curve_aux_3)
p_line_aux_vb.addItem(curve_aux_4)
p_line_aux_vb.addItem(curve_secondary_ch1)
p_line_aux_vb.addItem(curve_secondary_ch2)
else:
p_line.addItem(curve_aux_1)
p_line.addItem(curve_aux_2)
p_line.addItem(curve_aux_3)
p_line.addItem(curve_aux_4)
p_line.addItem(curve_secondary_ch1)
p_line.addItem(curve_secondary_ch2)
else:
curve_aux_1 = p_line.plot(pen=pg.mkPen((255, 170, 40), width=1))
curve_aux_2 = p_line.plot(pen=pg.mkPen((170, 70, 255), width=1))
curve_aux_3 = p_line.plot(pen=pg.mkPen((255, 120, 20), width=1))
curve_aux_4 = p_line.plot(pen=pg.mkPen((120, 60, 220), width=1))
curve_secondary_ch1 = p_line.plot(pen=pg.mkPen((0, 200, 100), width=1))
curve_secondary_ch2 = p_line.plot(pen=pg.mkPen((200, 100, 200), width=1))
curve_calib = p_line.plot(pen=pg.mkPen((220, 60, 60), width=1))
curve_norm = p_line.plot(pen=pg.mkPen((60, 180, 90), width=1))
p_line.setLabel("bottom", "ГГц")
p_line.setLabel("left", "Y")
if bin_iq_power_mode:
try:
p_line.setLabel("left", "CH1²+CH2², В²")
p_line.setLabel("left", "CH1^2 + CH2^2, В^2")
except Exception:
pass
ch_text = pg.TextItem("", anchor=(1, 1))
@ -1024,6 +1016,52 @@ def run_pyqtgraph(args) -> None:
except Exception:
pass
# -- Secondary channel plots (visible only in a800 / bin_iq_power_mode) --
p_secondary_ch = None
p_secondary_amp = None
p_secondary_phase = None
curve_sec_ch1 = None
curve_sec_ch2 = None
curve_sec_amp = None
curve_sec_phase = None
if bin_iq_power_mode:
p_secondary_ch = win.addPlot(row=3, col=0, title="CH1 / CH2 (В)")
p_secondary_ch.showGrid(x=True, y=True, alpha=0.3)
curve_sec_ch1 = p_secondary_ch.plot(pen=pg.mkPen((0, 200, 100), width=1))
curve_sec_ch2 = p_secondary_ch.plot(pen=pg.mkPen((200, 100, 200), width=1))
p_secondary_ch.setLabel("bottom", "ГГц")
p_secondary_ch.setLabel("left", "В")
p_secondary_ch.addLegend()
curve_sec_ch1.setData([], [], name="CH1")
curve_sec_ch2.setData([], [], name="CH2")
try:
p_secondary_ch.setXLink(p_line)
p_secondary_ch.setVisible(False)
except Exception:
pass
p_secondary_amp = win.addPlot(row=3, col=1, title="√(CH1² + CH2²) (В)")
p_secondary_amp.showGrid(x=True, y=True, alpha=0.3)
curve_sec_amp = p_secondary_amp.plot(pen=pg.mkPen((0, 200, 200), width=1))
p_secondary_amp.setLabel("bottom", "ГГц")
p_secondary_amp.setLabel("left", "В")
try:
p_secondary_amp.setXLink(p_line)
p_secondary_amp.setVisible(False)
except Exception:
pass
p_secondary_phase = win.addPlot(row=4, col=0, title="Фаза atan2(CH2, CH1) (рад)")
p_secondary_phase.showGrid(x=True, y=True, alpha=0.3)
curve_sec_phase = p_secondary_phase.plot(pen=pg.mkPen((230, 180, 40), width=1))
p_secondary_phase.setLabel("bottom", "ГГц")
p_secondary_phase.setLabel("left", "рад")
try:
p_secondary_phase.setXLink(p_line)
p_secondary_phase.setVisible(False)
except Exception:
pass
p_img = win.addPlot(row=0, col=1, title="Сырые данные водопад")
p_img.invertY(False)
p_img.showGrid(x=False, y=False)
@ -1239,7 +1277,7 @@ def run_pyqtgraph(args) -> None:
parsed_data_cb = QtWidgets.QCheckBox("данные после парсинга")
if complex_sweep_mode:
try:
parsed_data_cb.setText("√(CH1²+CH2²) (В)" if bin_iq_power_mode else "Сырые Re/Im")
parsed_data_cb.setText("CH1/CH2 (В)" if bin_iq_power_mode else "Сырые Re/Im")
parsed_data_cb.setChecked(False)
except Exception:
pass
@ -1721,15 +1759,15 @@ def run_pyqtgraph(args) -> None:
p_fft.setTitle("FFT: exp(V)")
parsed_data_cb.setText("Сырые log-detector (В)")
elif is_do1_tagged:
p_line.setTitle("DO1 tagged raw: LOW/HIGH CH1²+CH2² (В²)")
p_line.setLabel("left", "CH1²+CH2², В²")
p_line.setTitle("DO1 tagged raw: LOW/HIGH CH1^2 + CH2^2 (В^2)")
p_line.setLabel("left", "CH1^2 + CH2^2, В^2")
p_fft.setTitle("FFT")
parsed_data_cb.setText("DO1 tagged √(CH1²+CH2²) (В)")
parsed_data_cb.setText("DO1 tagged CH1/CH2 (В)")
elif is_bin_iq:
p_line.setTitle("√(CH1²+CH2²) (В) и CH1²+CH2² (В²)")
p_line.setLabel("left", "CH1²+CH2², В²")
p_line.setTitle("CH1^2 + CH2^2 (В^2)")
p_line.setLabel("left", "CH1^2 + CH2^2, В^2")
p_fft.setTitle("FFT: CH1 + i*CH2")
parsed_data_cb.setText("√(CH1²+CH2²) (В)")
parsed_data_cb.setText("CH1/CH2 (В)")
elif complex_sweep_mode:
p_line.setTitle("Сырые данные до FFT")
p_line.setLabel("left", "Y")
@ -1900,6 +1938,8 @@ def run_pyqtgraph(args) -> None:
runtime.current_do1_tagged_aux_high = None
runtime.current_secondary_ch1 = None
runtime.current_secondary_ch2 = None
runtime.current_secondary_magnitude = None
runtime.current_secondary_phase = None
runtime.current_sweep_norm = None
runtime.current_fft_mag = None
runtime.current_fft_db = None
@ -1983,6 +2023,26 @@ def run_pyqtgraph(args) -> None:
)
else:
runtime.current_secondary_ch2 = None
if runtime.full_secondary_magnitude is not None:
runtime.current_secondary_magnitude = apply_working_range_to_signal(
runtime.full_current_freqs,
runtime.full_current_sweep_raw,
runtime.full_secondary_magnitude,
runtime.range_min_ghz,
runtime.range_max_ghz,
)
else:
runtime.current_secondary_magnitude = None
if runtime.full_secondary_phase is not None:
runtime.current_secondary_phase = apply_working_range_to_signal(
runtime.full_current_freqs,
runtime.full_current_sweep_raw,
runtime.full_secondary_phase,
runtime.range_min_ghz,
runtime.range_max_ghz,
)
else:
runtime.current_secondary_phase = None
if runtime.current_sweep_raw.size == 0:
if push_to_ring:
@ -1999,6 +2059,8 @@ def run_pyqtgraph(args) -> None:
runtime.current_do1_tagged_aux_high = None
runtime.current_secondary_ch1 = None
runtime.current_secondary_ch2 = None
runtime.current_secondary_magnitude = None
runtime.current_secondary_phase = None
runtime.current_sweep_norm = None
runtime.current_fft_mag = None
runtime.current_fft_db = None
@ -2758,6 +2820,8 @@ def run_pyqtgraph(args) -> None:
runtime.full_do1_tagged_aux_high_codes = None
runtime.full_secondary_ch1 = None
runtime.full_secondary_ch2 = None
runtime.full_secondary_magnitude = None
runtime.full_secondary_phase = None
signal_kind = get_signal_kind(info)
if signal_kind == "bin_iq_do1_tagged":
calibrated = calibrate_freqs(
@ -2885,24 +2949,24 @@ def run_pyqtgraph(args) -> None:
if isinstance(secondary_payload, dict):
sec_ch1 = secondary_payload.get("ch1")
sec_ch2 = secondary_payload.get("ch2")
if sec_ch1 is not None and sec_ch2 is not None:
sec_ch1_calibrated = np.asarray(
calibrate_freqs({"F": base_freqs, "I": sec_ch1})["I"],
dtype=np.float32,
)
sec_ch2_calibrated = np.asarray(
calibrate_freqs({"F": base_freqs, "I": sec_ch2})["I"],
dtype=np.float32,
)
v_ch1 = convert_tty_i16_to_voltage(sec_ch1_calibrated, tty_range_v)
v_ch2 = convert_tty_i16_to_voltage(sec_ch2_calibrated, tty_range_v)
runtime.full_secondary_ch1 = np.sqrt(v_ch1 ** 2 + v_ch2 ** 2)
elif sec_ch1 is not None:
if sec_ch1 is not None:
sec_ch1_calibrated = np.asarray(
calibrate_freqs({"F": base_freqs, "I": sec_ch1})["I"],
dtype=np.float32,
)
runtime.full_secondary_ch1 = convert_tty_i16_to_voltage(sec_ch1_calibrated, tty_range_v)
if sec_ch2 is not None:
sec_ch2_calibrated = np.asarray(
calibrate_freqs({"F": base_freqs, "I": sec_ch2})["I"],
dtype=np.float32,
)
runtime.full_secondary_ch2 = convert_tty_i16_to_voltage(sec_ch2_calibrated, tty_range_v)
if runtime.full_secondary_ch1 is not None and runtime.full_secondary_ch2 is not None:
w = min(runtime.full_secondary_ch1.size, runtime.full_secondary_ch2.size)
v1 = runtime.full_secondary_ch1[:w]
v2 = runtime.full_secondary_ch2[:w]
runtime.full_secondary_magnitude = np.sqrt(v1 ** 2 + v2 ** 2)
runtime.full_secondary_phase = np.arctan2(v2, v1)
refresh_current_window(push_to_ring=True)
processed_frames += 1
last_packet_processed_at = time.time()
@ -3057,20 +3121,46 @@ def run_pyqtgraph(args) -> None:
clear_curve_if_needed("raw_low", curve_raw_low)
clear_curve_if_needed("raw_high", curve_raw_high)
if runtime.current_secondary_ch1 is not None:
# -- Secondary channel plots (separate graphs) --
has_sec = runtime.current_secondary_ch1 is not None or runtime.current_secondary_ch2 is not None
if p_secondary_ch is not None:
set_item_visible_if_changed("p_secondary_ch", p_secondary_ch, has_sec)
if p_secondary_amp is not None:
set_item_visible_if_changed("p_secondary_amp", p_secondary_amp, runtime.current_secondary_magnitude is not None)
if p_secondary_phase is not None:
set_item_visible_if_changed("p_secondary_phase", p_secondary_phase, runtime.current_secondary_phase is not None)
if curve_sec_ch1 is not None and runtime.current_secondary_ch1 is not None:
sec_width = min(xs.size, runtime.current_secondary_ch1.size)
sec_x1, sec_y1 = decimate_curve_for_display(xs[:sec_width], runtime.current_secondary_ch1[:sec_width])
sec_x1, sec_y1 = sanitize_curve_data_for_display(sec_x1, sec_y1)
set_curve_data("secondary_ch1", curve_secondary_ch1, sec_x1, sec_y1, autoDownsample=False)
else:
clear_curve_if_needed("secondary_ch1", curve_secondary_ch1)
if runtime.current_secondary_ch2 is not None:
set_curve_data("sec_ch1", curve_sec_ch1, sec_x1, sec_y1, autoDownsample=False)
elif curve_sec_ch1 is not None:
clear_curve_if_needed("sec_ch1", curve_sec_ch1)
if curve_sec_ch2 is not None and runtime.current_secondary_ch2 is not None:
sec_width2 = min(xs.size, runtime.current_secondary_ch2.size)
sec_x2, sec_y2 = decimate_curve_for_display(xs[:sec_width2], runtime.current_secondary_ch2[:sec_width2])
sec_x2, sec_y2 = sanitize_curve_data_for_display(sec_x2, sec_y2)
set_curve_data("secondary_ch2", curve_secondary_ch2, sec_x2, sec_y2, autoDownsample=False)
else:
clear_curve_if_needed("secondary_ch2", curve_secondary_ch2)
set_curve_data("sec_ch2", curve_sec_ch2, sec_x2, sec_y2, autoDownsample=False)
elif curve_sec_ch2 is not None:
clear_curve_if_needed("sec_ch2", curve_sec_ch2)
if curve_sec_amp is not None and runtime.current_secondary_magnitude is not None:
amp_w = min(xs.size, runtime.current_secondary_magnitude.size)
amp_x, amp_y = decimate_curve_for_display(xs[:amp_w], runtime.current_secondary_magnitude[:amp_w])
amp_x, amp_y = sanitize_curve_data_for_display(amp_x, amp_y)
set_curve_data("sec_amp", curve_sec_amp, amp_x, amp_y, autoDownsample=False)
elif curve_sec_amp is not None:
clear_curve_if_needed("sec_amp", curve_sec_amp)
if curve_sec_phase is not None and runtime.current_secondary_phase is not None:
ph_w = min(xs.size, runtime.current_secondary_phase.size)
ph_x, ph_y = decimate_curve_for_display(xs[:ph_w], runtime.current_secondary_phase[:ph_w])
ph_x, ph_y = sanitize_curve_data_for_display(ph_x, ph_y)
set_curve_data("sec_phase", curve_sec_phase, ph_x, ph_y, autoDownsample=False)
elif curve_sec_phase is not None:
clear_curve_if_needed("sec_phase", curve_sec_phase)
if active_do1_tagged:
if displayed_tagged_aux_low is not None: