right ifft implementation

This commit is contained in:
awe
2026-02-11 18:43:43 +03:00
parent ea57f87920
commit 66b9eee230
5 changed files with 66 additions and 1579 deletions

View File

@ -5,7 +5,15 @@ from typing import Optional, Tuple
import numpy as np
from rfg_adc_plotter.constants import FFT_LEN, WF_WIDTH
from rfg_adc_plotter.constants import (
FFT_LEN,
FREQ_SPAN_GHZ,
IFFT_LEN,
SWEEP_LEN,
WF_WIDTH,
ZEROS_LOW,
ZEROS_MID,
)
class RingBuffer:
@ -17,7 +25,7 @@ class RingBuffer:
def __init__(self, max_sweeps: int):
self.max_sweeps = max_sweeps
self.fft_bins = FFT_LEN // 2 + 1
self.fft_bins = IFFT_LEN # = 1953 (полная длина IFFT-результата)
# Инициализируются при первом свипе (ensure_init)
self.ring: Optional[np.ndarray] = None # (max_sweeps, WF_WIDTH)
@ -26,7 +34,7 @@ class RingBuffer:
self.head: int = 0
self.width: Optional[int] = None
self.x_shared: Optional[np.ndarray] = None
self.freq_shared: Optional[np.ndarray] = None
self.fft_time_axis: Optional[np.ndarray] = None # временная ось IFFT в нс
self.y_min_fft: Optional[float] = None
self.y_max_fft: Optional[float] = None
# FFT последнего свипа (для отображения без повторного вычисления)
@ -43,7 +51,10 @@ class RingBuffer:
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)
self.freq_shared = np.arange(self.fft_bins, dtype=np.int32)
# Временная ось IFFT: шаг dt = 1/(FREQ_SPAN_GHZ*1e9), переведём в нс
self.fft_time_axis = (
np.arange(IFFT_LEN, dtype=np.float64) / (FREQ_SPAN_GHZ * 1e9) * 1e9
).astype(np.float32)
self.head = 0
# Обновляем x_shared если пришёл свип большего размера
if self.x_shared is None or sweep_width > self.x_shared.size:
@ -64,20 +75,29 @@ class RingBuffer:
self._push_fft(s)
def _push_fft(self, s: np.ndarray):
bins = self.ring_fft.shape[1]
take_fft = min(int(s.size), FFT_LEN)
if take_fft <= 0:
bins = self.ring_fft.shape[1] # = IFFT_LEN = 1953
if s is None or s.size == 0:
fft_row = np.full((bins,), np.nan, dtype=np.float32)
else:
fft_in = np.zeros((FFT_LEN,), dtype=np.float32)
seg = np.nan_to_num(s[:take_fft], nan=0.0).astype(np.float32, copy=False)
win = np.hanning(take_fft).astype(np.float32)
fft_in[:take_fft] = seg * win
spec = np.fft.rfft(fft_in)
mag = np.abs(spec).astype(np.float32)
# 1. Взять первые SWEEP_LEN отсчётов (остаток — нули если свип короче)
sig = np.zeros(SWEEP_LEN, dtype=np.float32)
take = min(int(s.size), SWEEP_LEN)
seg = np.nan_to_num(s[:take], nan=0.0).astype(np.float32, copy=False)
sig[:take] = seg
# 2. Собрать двусторонний спектр:
# [ZEROS_LOW нулей | ZEROS_MID нулей | SWEEP_LEN данных]
# = [-14.3..-3.2 ГГц | -3.2..+3.2 ГГц | +3.2..+14.3 ГГц]
data = np.zeros(IFFT_LEN, dtype=np.complex64)
data[ZEROS_LOW + ZEROS_MID:] = sig
# 3. ifftshift + ifft → временной профиль
spec = np.fft.ifftshift(data)
result = np.fft.ifft(spec)
# 4. Амплитуда в дБ
mag = np.abs(result).astype(np.float32)
fft_row = (20.0 * np.log10(mag + 1e-9)).astype(np.float32)
if fft_row.shape[0] != bins:
fft_row = fft_row[:bins]
prev_head = (self.head - 1) % self.ring_fft.shape[0]
self.ring_fft[prev_head, :] = fft_row