You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Tomo flyscan: correct time-based trigger spacing and average PandA angles per projection - #100
Fixes two issues Nghia hit with tomo_flyscan (2026-10-21):
Time-based spacing:pulse_step = move_time / num_pulses → / (num_pulses - 1). 19 projections over 0–180° stepped 9.47° and ended at 170.5°; now 10° and 180°, like position-based. A single pulse keeps move_time as its step.
Averaged angles: with images_to_average > 1, triggers still run evenly from start to stop (no shift, per Nghia). The exporter writes each PandA capture (e.g. rotation_angle) as one value per projection: the mean of that projection's images' angles. The raw capture stays linked as <name>_raw.
The exporter expects Tiled to shape an averaged capture as (projections, images), as ophyd-async's datakey shape implies, and refuses any other shape rather than guess.
Verification: mock/unit tests only. tests/test_flyers.py reproduced the 9.4737° step against main before the fix; tests/test_export_averaging.py covers the averaging helper. Full pytest tests --ignore=tests/gui: 326 passed. Not run on the simulated beamline (its PandA is still a mock, so it would not exercise real trigger timing) or on the real beamline.
…projections
Time-based triggers were spaced by move_time / num_pulses, so 19 projections over 0-180 stepped 9.47 deg and ended at 170.5; they now use num_pulses - 1, as position-based already did. With images_to_average > 1 the triggers are spread over a slightly wider range so each group's mean lands on start + k*(stop - start)/(N - 1). The tomo exporter writes rotation_angle (and any other 2D PandA capture) as one mean per projection, keeping the raw capture as <name>_raw.
Assisted-by: copilot:claude-opus-5-5
…le time-based pulse
average_per_projection now takes num_projections and accepts only (projections, images_to_average), the layout ophyd-async's datakey shape gives Tiled; a captures-first or mismatched array is refused instead of guessed, which a square array could get wrong. A time-based scan with one pulse uses move_time as its step again instead of dividing by zero. Tests for both.
Assisted-by: copilot:claude-opus-5-5
This filter bypasses shape validation for one-dimensional captures even when averaging is enabled. If Tiled supplies a flattened (95,) capture for 19 projections averaged from five images, it remains linked as rotation_angle, pairing 19 frames with 95 angles instead of rejecting the unsupported layout. Validate non-detector captures whenever averaging is enabled, and add an exporter-level test for this case.
Single projection is not centered at the documented first-projection angle
src/hextools/flyers.py:177
With one projection and five images to average, this guard skips centring. For start_position=0 and stop_position=180, the triggers are at 0, 45, 90, 135 and 180 degrees, so the sole projection is centred at 90 rather than the documented first-projection angle of 0. A single unaveraged time-based pulse still fires at 0. Define singleton averaging explicitly, or reject this endpoint combination, and add a regression test.
Export code changes look good to me. I'd like to have clarified whether we want the shifting behavior, and at the very least it should be configurable.
…s images' mean angle
Per Nghia: triggers run evenly from start to stop, and an averaged projection's angle is the mean of the PandA angles of its images. When averaging, every PandA capture goes through the shape check, so a flattened capture is refused.
Assisted-by: copilot:claude-opus-5-5
Nghia does not want the shift — removed in 6ec7d56. Triggers now run evenly from start to stop, and each averaged projection is recorded at the mean of its images' PandA angles (e.g. 5 images → (a0+…+a4)/5).
Anthony Sligar (sligara7)
changed the title
Tomo flyscan: correct time-based trigger spacing and centre averaged projections
Tomo flyscan: correct time-based trigger spacing and average PandA angles per projection
Oct 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes two issues Nghia hit with
tomo_flyscan(2026-10-21):pulse_step = move_time / num_pulses→/ (num_pulses - 1). 19 projections over 0–180° stepped 9.47° and ended at 170.5°; now 10° and 180°, like position-based. A single pulse keepsmove_timeas its step.images_to_average > 1, triggers still run evenly fromstarttostop(no shift, per Nghia). The exporter writes each PandA capture (e.g.rotation_angle) as one value per projection: the mean of that projection's images' angles. The raw capture stays linked as<name>_raw.The exporter expects Tiled to shape an averaged capture as (projections, images), as ophyd-async's datakey shape implies, and refuses any other shape rather than guess.
Verification: mock/unit tests only.
tests/test_flyers.pyreproduced the 9.4737° step againstmainbefore the fix;tests/test_export_averaging.pycovers the averaging helper. Fullpytest tests --ignore=tests/gui: 326 passed. Not run on the simulated beamline (its PandA is still a mock, so it would not exercise real trigger timing) or on the real beamline.