The viewer could only parse v2-v4 headers while the app has been writing
v6 for some time — it could not open ANY file the current app produces.
It now uses core.sras_format directly (v6 only, per user decision).
New core/sras_analysis.py (Qt-free): ChannelCalibration, image reducers,
and SawPipeline. sras_viewer.py keeps only Qt.
Memory (measured, 92 MB synthetic scan, separate processes):
old eager path +305 MB read()+slice-copy+astype+float32 mean
new mmap path + 31 MB zero-copy view + mean(dtype=)
-> identical DC image; old scaled at ~3.3x file size, new at image size
- load_angle() returns a read-only mmap view instead of reading the whole
data block, then copying it twice
- SAW sweeps keep one scalar per pixel (process_shot_metrics) instead of
retaining 5 full arrays x pixel count in a results list
- CH1 float32 materializes only for pixels passing the DC mask
- matched filter caches the template FFT instead of recomputing per pixel
- opening a new file drops every reference to the old one (compute/
template/diagnostic workers used to pin the previous multi-GB mapping)
Responsiveness:
- 250 ms debounce coalesces spinbox storms into one recompute
- grating change is a display-time scalar multiply, not a full FFT rerun
- colormap/clim reuse the AxesImage (set_data/set_clim) instead of
clf() + rebuilding the colorbar; draw_idle() throughout
- SAW diagnostics (21 pipeline runs) and CSV export moved off the GUI thread
Also: ragged per-angle geometry is respected (v6 angles differ in rows/
frames), truncated scans show only rows present on disk, dead decimation
path and v2 fallback branch removed, scipy added to viewer requirements.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- core/sras_format.py: THE v6 implementation — create_scan_file (writer,
byte-identical to the old one, enforced against the Phase-0 goldens),
SrasFile parser with frontier/truncation walk, and zero-copy mmap
load_angle/load_row views for multi-GB files
- core/scan_geometry.py: ScanPlan/AngleGeometry dataclasses, build_plan
(rotated-bbox trig from MainWindow._build_scan_params), travel-limit
validate_plan (limits now a StageLimits dataclass, not literals buried
in the worker), format_eta + EtaEstimator (bounded deque)
- core/config.py: ScanDefaults dataclass replaces the module-import-time
dict globals. FIXES: editing any main-window port used to rewrite
aui_defaults.json without helios_port, silently reverting the Helios
port every time (test_helios_port_survives_partial_update covers it).
Also drops the inert laser_freq_hz plumbing — scans always used the
LASER_FREQ_HZ constant.
- hardware/serial_util.py: shared 8N1 open + scored port enumeration
(promoted from t3r_control_panel); helios_laser and the panel use it
- sc3_aui_app.py and sras_scan_manager.py migrated onto core (three
format implementations down to one); ScanWorker now takes a ScanPlan
- tests: byte-identical writer vs golden, frontier over every truncation
variant, mmap==eager, geometry vs golden fixtures + invariants, config
round-trip. 28 passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- uc480_camera: drop never-called _capture_paused/get_framerate (the
hardware question _capture_paused encoded is now in KNOWN_ISSUES.md)
- t3r_protocol: drop read_reg/write_reg/decode_reg/Reg (commands never
wired into the driver)
- bbd20x: drop _update0x0212 (never dispatched) and 8 of 9 unused
trigger convenience wrappers; apt_constants: drop TriggerBitsStepper
(servo-only rig)
- ruff --fix: 35 unused imports across all apps; drop unused T3R_BAUD
- genesis_core.py: quarantine warning header; docs/genesis_verification.md
bench checklist for the 7 divergences vs tools/genesis_laser_gui.py
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verified by repo-wide name search + transitive closure over internal
calls: the live apps use 25 methods (plus raw write/query); everything
else — cosmetic label styling, unused getters/setters, transfer_waveform,
acquire_waveform — had no callers. Also: linear-time chunk join in
read_raw instead of quadratic bytes += concat, and a typed except on its
debug path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
app.py was an abandoned skeleton (15 'pass # TODO' handlers, loads a
deleted .qss); everything else was reachable only from it:
ui_mainwindow.py (pyuic6 artifact), sc3-new.ui, motion_worker.py,
genesis_worker.py, coherent_hops_laser.py (stubs), scanning/ (dead C#
port + unused plan generator), config.json, plus helios_diagnostic.py
(sends wrong protocol commands) and helios_terminal.py (worse duplicate
of helios_test_app's Terminal tab).
hardware/__init__.py no longer wildcard-imports every driver, so the
stage driver imports without the uEye camera SDK installed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- ruff config, offscreen smoke tests for all 7 GUI apps/panels
- golden v6 .sras fixtures (complete + 4 truncation variants) generated
by the pre-refactor writer, with expected header/frontier JSON
- golden geometry fixtures from the pre-refactor _build_scan_params
- consistency tests proving current code reproduces the goldens
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Merged four separate hardware control projects into unified platform
- Created unified requirements.txt with all dependencies
- Added comprehensive .gitignore
- Added project overview README
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>