arccos to apply
This commit is contained in:
@ -227,7 +227,7 @@ class AppState:
|
||||
bg_stage = "bg[sub]" if self.background is not None else "bg[missing]"
|
||||
return (
|
||||
f"pipeline ch{ch_txt}: parsed -> {reader_stage} -> raw -> "
|
||||
f"live-calib-ref -> {calib_stage} -> {bg_stage} -> ring -> IFFT(dB)"
|
||||
f"live-calib-ref -> {calib_stage} -> {bg_stage} -> ring -> IFFT(abs, depth_m)"
|
||||
)
|
||||
|
||||
calib_stage = self.format_calib_source_status()
|
||||
@ -235,7 +235,7 @@ class AppState:
|
||||
|
||||
return (
|
||||
f"pipeline ch{ch_txt}: parsed -> {reader_stage} -> raw -> "
|
||||
f"{calib_stage} -> {bg_stage} -> ring -> IFFT(dB)"
|
||||
f"{calib_stage} -> {bg_stage} -> ring -> IFFT(abs, depth_m)"
|
||||
)
|
||||
|
||||
def _format_summary(self, summary) -> str:
|
||||
|
||||
@ -6,10 +6,11 @@ from typing import Optional, Tuple
|
||||
import numpy as np
|
||||
|
||||
from rfg_adc_plotter.constants import (
|
||||
IFFT_LEN,
|
||||
FREQ_MAX_GHZ,
|
||||
FREQ_MIN_GHZ,
|
||||
WF_WIDTH,
|
||||
)
|
||||
from rfg_adc_plotter.processing.fourier import build_ifft_time_axis_ns, compute_ifft_db_profile
|
||||
from rfg_adc_plotter.processing.fourier import compute_ifft_profile_from_sweep
|
||||
|
||||
|
||||
class RingBuffer:
|
||||
@ -21,7 +22,8 @@ class RingBuffer:
|
||||
|
||||
def __init__(self, max_sweeps: int):
|
||||
self.max_sweeps = max_sweeps
|
||||
self.fft_bins = IFFT_LEN # = 1953 (полная длина IFFT-результата)
|
||||
# Размер IFFT-профиля теперь динамический и определяется по первому успешному свипу.
|
||||
self.fft_bins = 0
|
||||
|
||||
# Инициализируются при первом свипе (ensure_init)
|
||||
self.ring: Optional[np.ndarray] = None # (max_sweeps, WF_WIDTH)
|
||||
@ -30,7 +32,7 @@ class RingBuffer:
|
||||
self.head: int = 0
|
||||
self.width: Optional[int] = None
|
||||
self.x_shared: Optional[np.ndarray] = None
|
||||
self.fft_time_axis: Optional[np.ndarray] = None # временная ось IFFT в нс
|
||||
self.fft_depth_axis_m: Optional[np.ndarray] = None # ось глубины IFFT в метрах
|
||||
self.y_min_fft: Optional[float] = None
|
||||
self.y_max_fft: Optional[float] = None
|
||||
# FFT последнего свипа (для отображения без повторного вычисления)
|
||||
@ -40,19 +42,21 @@ class RingBuffer:
|
||||
def is_ready(self) -> bool:
|
||||
return self.ring is not None
|
||||
|
||||
@property
|
||||
def fft_time_axis(self) -> Optional[np.ndarray]:
|
||||
"""Legacy alias: старое имя поля (раньше было время в нс, теперь глубина в м)."""
|
||||
return self.fft_depth_axis_m
|
||||
|
||||
def ensure_init(self, sweep_width: int):
|
||||
"""Инициализировать буферы при первом свипе. Повторные вызовы — no-op (кроме x_shared)."""
|
||||
if self.ring is None:
|
||||
self.width = WF_WIDTH
|
||||
self.ring = np.full((self.max_sweeps, self.width), np.nan, dtype=np.float32)
|
||||
self.ring_time = np.full((self.max_sweeps,), np.nan, dtype=np.float64)
|
||||
self.ring_fft = np.full((self.max_sweeps, self.fft_bins), np.nan, dtype=np.float32)
|
||||
# Временная ось IFFT вынесена в processing.fourier для явного pipeline.
|
||||
self.fft_time_axis = build_ifft_time_axis_ns()
|
||||
self.head = 0
|
||||
# Обновляем x_shared если пришёл свип большего размера
|
||||
if self.x_shared is None or sweep_width > self.x_shared.size:
|
||||
self.x_shared = np.linspace(3.323, 14.323, sweep_width, dtype=np.float32)
|
||||
self.x_shared = np.linspace(FREQ_MIN_GHZ, FREQ_MAX_GHZ, sweep_width, dtype=np.float32)
|
||||
|
||||
def push(self, s: np.ndarray):
|
||||
"""Добавить строку свипа в кольцевой буфер, вычислить FFT-строку."""
|
||||
@ -69,8 +73,43 @@ class RingBuffer:
|
||||
self._push_fft(s)
|
||||
|
||||
def _push_fft(self, s: np.ndarray):
|
||||
fft_row = compute_ifft_db_profile(s)
|
||||
depth_axis_m, fft_row = compute_ifft_profile_from_sweep(s)
|
||||
fft_row = np.asarray(fft_row, dtype=np.float32).ravel()
|
||||
depth_axis_m = np.asarray(depth_axis_m, dtype=np.float32).ravel()
|
||||
|
||||
n = min(int(fft_row.size), int(depth_axis_m.size))
|
||||
if n <= 0:
|
||||
return
|
||||
if n != fft_row.size:
|
||||
fft_row = fft_row[:n]
|
||||
if n != depth_axis_m.size:
|
||||
depth_axis_m = depth_axis_m[:n]
|
||||
|
||||
needs_reset = (
|
||||
self.ring_fft is None
|
||||
or self.fft_depth_axis_m is None
|
||||
or self.fft_bins != n
|
||||
or self.ring_fft.shape != (self.max_sweeps, n)
|
||||
or self.fft_depth_axis_m.size != n
|
||||
)
|
||||
if (not needs_reset) and n > 0:
|
||||
prev_axis = self.fft_depth_axis_m
|
||||
assert prev_axis is not None
|
||||
if prev_axis.size != n:
|
||||
needs_reset = True
|
||||
else:
|
||||
# Если ось изменилась (например, изменилась длина/частотная сетка), сбрасываем FFT-водопад.
|
||||
if not np.allclose(prev_axis[[0, -1]], depth_axis_m[[0, -1]], rtol=1e-6, atol=1e-9):
|
||||
needs_reset = True
|
||||
|
||||
if needs_reset:
|
||||
self.fft_bins = n
|
||||
self.ring_fft = np.full((self.max_sweeps, n), np.nan, dtype=np.float32)
|
||||
self.fft_depth_axis_m = depth_axis_m.astype(np.float32, copy=True)
|
||||
self.y_min_fft = None
|
||||
self.y_max_fft = None
|
||||
|
||||
assert self.ring_fft is not None
|
||||
prev_head = (self.head - 1) % self.ring_fft.shape[0]
|
||||
self.ring_fft[prev_head, :] = fft_row
|
||||
self.last_fft_vals = fft_row
|
||||
|
||||
Reference in New Issue
Block a user