Skip to content

SPECULA science camera: one writer for strehl/tiptilt - #179

Merged
jacotay7 merged 1 commit into
devfrom
fix-specula-strehl-stream
Oct 21, 2026
Merged

jacotay7 merged 1 commit into
devfrom
fix-specula-strehl-stream

Conversation

@jacotay7

Copy link
Copy Markdown
Owner

The oddity

SPECULAScienceCamera.expose() wrote SPECULA's Strehl and a constant 0.0 tip-tilt to the strehl/tiptilt streams. Then integrate() overwrote them with pyRTC's long-exposure estimate (ScienceCamera.compute_strehl), so the streams alternated between the two.

These are different quantities. SPECULA's out_sr is the on-axis Strehl, while pyRTC's estimate is peak-based, the stack convention (aocore CONVENTIONS 4.2). They agree only when the PSF peak sits on axis. In one run with residual tip-tilt they read 0.24 (on-axis) vs 0.40 (peak). pid_optimizer and loop_hyperparams_optimizer use strehl as their objective.

Fix: expose() no longer writes them. Only integrate() publishes strehl/tiptilt, as the OOPAO and HCIPy cameras do. The camera still takes its model PSF from SPECULA's diffraction-limited reference.

On the SHWFS example with turbulence and the loop closed, the stream now reads 0.59–0.70 (std 0.024), against 0.51–0.69 when the two writers were mixed.

Also fixed: a flaky convergence test (regression from #178)

test_specula_loop_converges_after_calibration[pywfs] failed about 3 runs in 4 on dev, always with the same value. Loop.compute_im returns with its last poke frame unconsumed, so the test's first "calibrated" sample was that poke frame (signal RMS 0.31; every later frame reads 0.000). #178 changed the mode shapes, which made that poke frame large enough to push the mean over the bar.

The new testsupport.drain_in_flight_signal(loop) drops one round trip of frames before the measurement; the SPECULA and OOPAO convergence tests now use it. Afterwards the test passed 4 runs out of 4.

Tests

  • New test_specula_science_camera_writes_strehl_only_from_integrate (fake SDK): expose() leaves the stream counts unchanged and integrate() advances them. It fails on the old code.
  • Full suite locally: 751 passed, 2 skipped.
  • The CHANGELOG (Unreleased, Fixed) and AGENTS.md are updated with two gotchas: the stale IM frame, and the single strehl writer vs SPECULA's on-axis value.

🤖 Generated with Claude Code

…ame in tests

SPECULAScienceCamera.expose() also wrote SPECULA's Strehl and a constant 0
tip-tilt, so the streams alternated with integrate()'s long-exposure
estimate. SPECULA's out_sr is the on-axis Strehl and pyrtc's estimate is
peak-based (aocore CONVENTIONS 4.2), so they diverge with residual
tip-tilt, and the optimizers use `strehl` as their objective. Write them
only from integrate(), as the OOPAO and HCIPy cameras do.

While testing: compute_im leaves its last poke frame unconsumed on the
signal stream, and the convergence tests' first "calibrated" sample was
that frame. Since #178 it made the SPECULA PYWFS test fail about 3 runs in
4. Drain the in-flight frames first (testsupport.drain_in_flight_signal).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jacotay7
jacotay7 merged commit cbcafba into dev Oct 21, 2026
14 checks passed
@jacotay7
jacotay7 deleted the fix-specula-strehl-stream branch October 21, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant