Two strands, committed together because they touch the same four files
and answer the same question: an exported PNG must be the image the user
was looking at when they triggered the export.
Dropped view settings (bug fix):
- BatchExportWorker forwarded the DC threshold, bg-sub, pad and row-
averaging to compute_rf_image but never min_freq_mhz, so every RF and
Velocity map was exported with no min peak frequency floor. The pixels
the floor exists to reject came back at their pre-floor peaks.
- That also decided *which source* the image came from: requesting floor
0 makes a stored v7 cache look like a match (cache_mismatch_reasons
only rejects a higher stored floor), so a batch-computed file exported
the cached peak-frequency block verbatim - numbers from an earlier
Batch Compute run, while the screen showed that same cache re-masked
against the live floor. The symptom was a newly loaded file exporting
a stale-looking velocity map, since the floor is a display control
that survives a load while the window's own FFT cache does not.
- export_view_image had the same class of defect with a different
parameter: it dropped row_avg_n, so a file whose stored cache is row-
averaged displayed from the store but exported as a full raw
recompute - a different, and much slower, image. It now reads
sras.precomputed_row_avg_n per file, mirroring _stored_fft_image and
_start_compute, and derived per file for the same reason n_fft is.
Export at the live canvas size:
- Both exporters now take the canvas's current figure size instead of a
hard-coded 7x5. draw_view_image uses aspect="auto", so the figure box
is what sets the map's proportions - a view sized wide on screen was
being squeezed into a different shape on disk. Read at trigger time,
in inches, so a resize mid-batch cannot change images later in the
same run and a HiDPI display exports like a standard one.
- sanitize_figsize clamps a degenerate size (collapsed splitter pane,
minimized window): a wrong-looking aspect ratio must never be the
reason a batch loses an image.
Tests: BatchExportWorker had no coverage at all. Four new tests cover
the floor being applied, a stored cache never being served unfloored,
the menu-to-worker wiring, and the row-averaged cache case; each was
verified to fail against the unfixed code. 166 passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>