Two strands of in-progress work, committed together because they overlap
in sras_workers.py and main_window.py.
Min peak frequency floor:
- CACH tail bumped to version 4, adding u32 min_freq_khz provenance in
fixed-point kHz (a float32 20.1 reads back as 20.10000038 and would
report a spurious mismatch forever). v1-v3 tails read as no floor.
- Stored FFT caches are accepted when the reader's floor is at or above
the stored one, since a higher floor is re-applicable by masking.
- Floor plumbed through compute_rf_image, BatchCacheWorker and the viewer.
Batch Export View as Images:
- New sras_render.py holds draw_view_image, shared by the Qt canvas and
the headless exporter so a PNG cannot drift from what the GUI shows.
Deliberately Qt-free so it is importable in a pool subprocess.
- BatchExportImagesWorker renders the current view settings across many
files, process-pooled with an inline fallback, reporting per-file
output names so the caller can flag same-stem collisions.
- _axes_extent extracted into sras_format for both render paths.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drop the coarse+fine zoom refinement, the SciPy FFT backend, and the
exact= audit path in favor of a single always-on full-transform peak
search (_peak_bins). Block size is now derived from a per-thread memory
budget (_fft_block_for/SRAS_FFT_PLAN_BUDGET_MB) instead of a fixed
constant, so the existing block-parallel PyFFTW pool stays memory-safe
at high pad factors without the zoom algorithm's bookkeeping. Also
removes the now-unused threadpoolctl dependency and the FFT backend
selector from the UI.
Also includes a pre-existing min_freq_mhz peak-search floor (excludes
bins below a caller-supplied frequency from the argmax) that was
already implemented and tested in the working tree.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The display path hardcoded row_avg_n=0 when checking a file's stored FFT
cache, since the main window has no row-averaging control (only the
batch-only RowAverageFftOptionsDialog). Once a file was batch-computed with
row-averaging, every view switch saw a phantom provenance mismatch and
silently launched a full raw recompute, discarding the precomputed data.
The display now asks for the stored image at the settings it was actually
computed under (bg-sub/pad/row-averaging), rather than the window's live
controls, so a stored or already-computed image is always shown once
present. Those controls now only affect a first-time compute for an
uncached angle or an explicit batch recompute -- never what's already on
screen. DC threshold is unaffected: it stays live, since re-masking a
cached image is free.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>