From 05f8a8942be749c82f2af4f63418047293e8ab21 Mon Sep 17 00:00:00 2001 From: awe Date: Tue, 9 Jun 2026 19:42:40 +0300 Subject: [PATCH] fix range --- rfg_adc_plotter/constants.py | 3 +++ rfg_adc_plotter/processing/calibration.py | 33 +++++++++++++++++++++-- rfg_vna_viewer.py | 8 +++--- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/rfg_adc_plotter/constants.py b/rfg_adc_plotter/constants.py index 79345c5..454f762 100644 --- a/rfg_adc_plotter/constants.py +++ b/rfg_adc_plotter/constants.py @@ -7,6 +7,9 @@ BACKGROUND_MEDIAN_SWEEPS = 64 SWEEP_FREQ_MIN_GHZ = 3.3 SWEEP_FREQ_MAX_GHZ = 6.3 +PHASE_FREQ_MIN_GHZ = 2.046 +PHASE_FREQ_MAX_GHZ = 5.612 + LOG_BASE = 10.0 LOG_SCALER = 0.001 LOG_POSTSCALER = 10.0 diff --git a/rfg_adc_plotter/processing/calibration.py b/rfg_adc_plotter/processing/calibration.py index 07f268d..fd9268e 100644 --- a/rfg_adc_plotter/processing/calibration.py +++ b/rfg_adc_plotter/processing/calibration.py @@ -3,11 +3,16 @@ from __future__ import annotations from pathlib import Path -from typing import Any, Mapping +from typing import Any, Mapping, Optional import numpy as np -from rfg_adc_plotter.constants import SWEEP_FREQ_MAX_GHZ, SWEEP_FREQ_MIN_GHZ +from rfg_adc_plotter.constants import ( + PHASE_FREQ_MAX_GHZ, + PHASE_FREQ_MIN_GHZ, + SWEEP_FREQ_MAX_GHZ, + SWEEP_FREQ_MIN_GHZ, +) from rfg_adc_plotter.processing.normalization import build_calib_envelopes from rfg_adc_plotter.types import SweepData @@ -92,6 +97,30 @@ def calibrate_freqs(sweep: Mapping[str, Any]) -> SweepData: } +def compute_freqs_from_ref_phase( + ref_ch1: np.ndarray, + ref_ch2: np.ndarray, + f_min_ghz: float = PHASE_FREQ_MIN_GHZ, + f_max_ghz: float = PHASE_FREQ_MAX_GHZ, +) -> Optional[np.ndarray]: + """Compute frequency axis from unwrapped phase of a reference IQ signal. + + Assumes phase depends linearly on frequency: the first sample maps to + *f_min_ghz* and the last sample maps to *f_max_ghz*. + """ + ch1 = np.asarray(ref_ch1, dtype=np.float64).reshape(-1) + ch2 = np.asarray(ref_ch2, dtype=np.float64).reshape(-1) + w = min(ch1.size, ch2.size) + if w < 2: + return None + phase = np.unwrap(np.arctan2(ch2[:w], ch1[:w])) + phi0, phi1 = float(phase[0]), float(phase[-1]) + if abs(phi1 - phi0) < 1e-12: + return None + freqs = f_min_ghz + (phase - phi0) / (phi1 - phi0) * (f_max_ghz - f_min_ghz) + return freqs + + def build_calib_envelope(sweep: np.ndarray) -> np.ndarray: """Build the active calibration envelope from a raw sweep.""" values = np.asarray(sweep, dtype=np.float32).reshape(-1) diff --git a/rfg_vna_viewer.py b/rfg_vna_viewer.py index 4039a4a..6012447 100644 --- a/rfg_vna_viewer.py +++ b/rfg_vna_viewer.py @@ -265,13 +265,15 @@ def make_update(reader, parser, assembler, curves, plots): if n < 2: return - freqs_ghz = np.linspace(F_START_HZ / 1e9, F_STOP_HZ / 1e9, n) - freqs_hz = freqs_ghz * 1e9 - ref_amp, ref_phase = process_reference( sweep["ref_ch1"], sweep["ref_ch2"] ) + # Compute frequency axis from reference signal phase (linear phase-freq model) + phi0, phi1 = ref_phase[0], ref_phase[-1] + freqs_ghz = (F_START_HZ / 1e9) + (ref_phase - phi0) / (phi1 - phi0) * (BW_HZ / 1e9) + freqs_hz = freqs_ghz * 1e9 + # Fix reference phase from the first sweep if state["ref_phase_first"] is None: state["ref_phase_first"] = ref_phase[0]