diff --git a/bin/debug/scan_artefact_check.py b/bin/debug/scan_artefact_check.py index 0552e26d..83390f67 100755 --- a/bin/debug/scan_artefact_check.py +++ b/bin/debug/scan_artefact_check.py @@ -429,6 +429,51 @@ def check_line_motion_from_motor(signals, motors, meta) -> None: return ratio = spans / median print(f" samples per line : ~{per_line} median line span : {median:.6g}") + + # Enough geometry to check this file against the scan that was intended. + # A step size that disagrees with the scan command means either the wrong + # axis has been identified or the motion was not what was asked for -- and + # both make everything below meaningless. + grid_pts = int(meta.get("frames_per_trigger") or 0) + print(f" fast axis range : {arr.min():.6g} .. {arr.max():.6g}") + if slow_name is not None: + sarr = signals[slow_name] + print(f" slow axis range : {sarr.min():.6g} .. {sarr.max():.6g}" + f" ({found} lines -> {(sarr.max() - sarr.min()) / max(1, found - 1):.4g} per line)") + if grid_pts: + print(f" implied step : {median / grid_pts:.4g} per point" + f" ({median:.4g} over {grid_pts} points)") + print(" ^ compare with the step size in the scan command. A mismatch means") + print(" the wrong axis, the wrong units, or motion that was not commanded.") + + # Whole-line spans only catch a line that never moved. An axis that stalls + # part-way and then continues still spans the full range, so look for runs of + # samples that did not advance. + stalled = [] + for i, sg in enumerate(segs): + if sg.size < 4: + continue + step = np.abs(np.diff(sg)) + typical = float(np.median(step)) + if typical <= 0: + continue + frozen = step < 0.1 * typical + run, longest = 0, 0 + for f in frozen: + run = run + 1 if f else 0 + longest = max(longest, run) + if longest >= 3: + stalled.append((i, longest, sg.size)) + if stalled: + print(f"\n within-line stalls: {len(stalled)} lines contain a run of >=3" + " consecutive samples that did not advance") + report_distribution(np.array([i for i, _, _ in stalled]), found, "within-line stalls") + for i, longest, size in stalled[:10]: + print(f" line {i:>5} {longest} frozen of {size} samples") + print(" A line can span its full range and still have stopped part-way;") + print(" this is the partial-stall case the span check cannot see.") + else: + print(" no within-line stalls either (no run of >=3 frozen samples).") if per_line < 5: print(f" WARNING: only ~{per_line} position samples per line. The motor trace") print(" is far sparser than the data, so a partial stall can hide between")