fix
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import signal
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from queue import Empty, Queue
|
||||
@ -38,6 +39,7 @@ from rfg_adc_plotter.state import RingBuffer, RuntimeState
|
||||
from rfg_adc_plotter.types import SweepAuxCurves, SweepInfo, SweepPacket
|
||||
|
||||
RAW_PLOT_MAX_POINTS = 4096
|
||||
RAW_WATERFALL_MAX_POINTS = 2048
|
||||
DEBUG_FRAME_LOG_EVERY = 10
|
||||
|
||||
|
||||
@ -603,7 +605,7 @@ def run_pyqtgraph(args) -> None:
|
||||
if finite_f.size > 0:
|
||||
f_min = float(np.min(finite_f))
|
||||
f_max = float(np.max(finite_f))
|
||||
img.setImage(runtime.ring.get_display_raw(), autoLevels=False)
|
||||
img.setImage(runtime.ring.get_display_raw_decimated(RAW_WATERFALL_MAX_POINTS), autoLevels=False)
|
||||
img.setRect(0, f_min, max_sweeps, max(1e-9, f_max - f_min))
|
||||
p_img.setRange(
|
||||
xRange=(0, max_sweeps - 1),
|
||||
@ -714,7 +716,7 @@ def run_pyqtgraph(args) -> None:
|
||||
runtime.current_peak_width = None
|
||||
runtime.current_peak_amplitude = None
|
||||
runtime.peak_candidates = []
|
||||
img.setImage(runtime.ring.get_display_raw(), autoLevels=False)
|
||||
img.setImage(runtime.ring.get_display_raw_decimated(RAW_WATERFALL_MAX_POINTS), autoLevels=False)
|
||||
img_fft.setImage(runtime.ring.get_display_fft_linear(), autoLevels=False)
|
||||
update_physical_axes()
|
||||
|
||||
@ -1242,6 +1244,7 @@ def run_pyqtgraph(args) -> None:
|
||||
pass
|
||||
|
||||
processed_frames = 0
|
||||
ui_started_at = time.perf_counter()
|
||||
|
||||
def refresh_current_fft_cache(sweep_for_fft: np.ndarray, bins: int) -> None:
|
||||
runtime.current_fft_complex = compute_fft_complex_row(
|
||||
@ -1311,10 +1314,13 @@ def run_pyqtgraph(args) -> None:
|
||||
queue_size = queue.qsize()
|
||||
except Exception:
|
||||
queue_size = -1
|
||||
elapsed_s = max(time.perf_counter() - ui_started_at, 1e-9)
|
||||
frames_per_sec = float(processed_frames) / elapsed_s
|
||||
sys.stderr.write(
|
||||
"[debug] ui frames:%d last_sweep:%s ch:%s width:%d queue:%d\n"
|
||||
"[debug] ui frames:%d rate:%.2f/s last_sweep:%s ch:%s width:%d queue:%d\n"
|
||||
% (
|
||||
processed_frames,
|
||||
frames_per_sec,
|
||||
str(info.get("sweep") if isinstance(info, dict) else None),
|
||||
str(info.get("ch") if isinstance(info, dict) else None),
|
||||
int(getattr(sweep, "size", 0)),
|
||||
@ -1640,7 +1646,7 @@ def run_pyqtgraph(args) -> None:
|
||||
runtime.plot_dirty = False
|
||||
|
||||
if changed and runtime.ring.ring is not None:
|
||||
disp = runtime.ring.get_display_raw()
|
||||
disp = runtime.ring.get_display_raw_decimated(RAW_WATERFALL_MAX_POINTS)
|
||||
levels = _visible_levels_pyqtgraph(disp, p_img)
|
||||
if levels is not None:
|
||||
img.setImage(disp, autoLevels=False, levels=levels)
|
||||
|
||||
@ -101,6 +101,7 @@ class SweepReader(threading.Thread):
|
||||
self._src: SerialLineSource | None = None
|
||||
self._frames_read = 0
|
||||
self._frames_dropped = 0
|
||||
self._started_at = time.perf_counter()
|
||||
|
||||
def _build_parser(self):
|
||||
if self._parser_complex_ascii:
|
||||
@ -175,12 +176,15 @@ class SweepReader(threading.Thread):
|
||||
queue_size = self._queue.qsize()
|
||||
except Exception:
|
||||
queue_size = -1
|
||||
elapsed_s = max(time.perf_counter() - self._started_at, 1e-9)
|
||||
frames_per_sec = float(self._frames_read) / elapsed_s
|
||||
sweep_idx = info.get("sweep") if isinstance(info, dict) else None
|
||||
channel = info.get("ch") if isinstance(info, dict) else None
|
||||
sys.stderr.write(
|
||||
"[debug] reader frames:%d last_sweep:%s ch:%s width:%d queue:%d dropped:%d\n"
|
||||
"[debug] reader frames:%d rate:%.2f/s last_sweep:%s ch:%s width:%d queue:%d dropped:%d\n"
|
||||
% (
|
||||
self._frames_read,
|
||||
frames_per_sec,
|
||||
str(sweep_idx),
|
||||
str(channel),
|
||||
int(getattr(sweep, "size", 0)),
|
||||
|
||||
@ -201,6 +201,21 @@ class RingBuffer:
|
||||
base = self.ring if self.head == 0 else np.roll(self.ring, -self.head, axis=0)
|
||||
return base.T
|
||||
|
||||
def get_display_raw_decimated(self, max_points: int) -> np.ndarray:
|
||||
"""Return a display-oriented raw waterfall with optional frequency decimation."""
|
||||
if self.ring is None:
|
||||
return np.zeros((1, 1), dtype=np.float32)
|
||||
|
||||
limit = int(max_points)
|
||||
if limit <= 0 or self.width <= limit:
|
||||
return self.get_display_raw()
|
||||
|
||||
row_order = np.arange(self.ring.shape[0], dtype=np.int64)
|
||||
if self.head:
|
||||
row_order = np.roll(row_order, -self.head)
|
||||
col_idx = np.linspace(0, self.width - 1, limit, dtype=np.int64)
|
||||
return self.ring[np.ix_(row_order, col_idx)].T
|
||||
|
||||
def get_display_fft_linear(self) -> np.ndarray:
|
||||
if self.ring_fft is None:
|
||||
return np.zeros((1, 1), dtype=np.float32)
|
||||
|
||||
@ -41,6 +41,22 @@ class RingBufferTests(unittest.TestCase):
|
||||
self.assertIsNotNone(ring.last_fft_db)
|
||||
self.assertEqual(ring.last_fft_db.shape, (ring.fft_bins,))
|
||||
|
||||
def test_ring_buffer_can_return_decimated_display_raw(self):
|
||||
ring = RingBuffer(max_sweeps=3)
|
||||
sweep_a = np.linspace(0.0, 1.0, 4096, dtype=np.float32)
|
||||
sweep_b = np.linspace(1.0, 2.0, 4096, dtype=np.float32)
|
||||
sweep_c = np.linspace(2.0, 3.0, 4096, dtype=np.float32)
|
||||
freqs = np.linspace(3.3, 14.3, 4096, dtype=np.float64)
|
||||
ring.push(sweep_a, freqs)
|
||||
ring.push(sweep_b, freqs)
|
||||
ring.push(sweep_c, freqs)
|
||||
|
||||
raw = ring.get_display_raw_decimated(256)
|
||||
|
||||
self.assertEqual(raw.shape, (256, 3))
|
||||
self.assertAlmostEqual(float(raw[0, -1]), float(sweep_c[0]), places=6)
|
||||
self.assertAlmostEqual(float(raw[-1, -1]), float(sweep_c[-1]), places=6)
|
||||
|
||||
def test_ring_buffer_can_switch_fft_mode_and_rebuild_fft_rows(self):
|
||||
ring = RingBuffer(max_sweeps=2)
|
||||
sweep = np.linspace(0.0, 1.0, 64, dtype=np.float32)
|
||||
|
||||
Reference in New Issue
Block a user