docs(flomni): realtime_system in the user guide; FZP how-tos with the loop-settings profiles

- user guide: detector-trigger commands under flomni.realtime_system.trigger_* (old names still work), new section
  "Real-time loop settings (expert)"
- calibration how-to: steps 1-3 as profiles fzp_off / fzp_calibration / production (+ fast_scan); trigger values are
  OnTargetTrigger parameters; move-beyond sizing with the loop-settings rule (0.6 x stroke - Abbe limit)
- range how-to: FZP range through the loop settings (Ub / Lb and Feedforward limits together)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019aWcwG89wi7oVyrefukXX6
This commit is contained in:
Claude committed 2026-10-23 12:55:32 +00:00
1 parent 79f5cced42
commit 6dbf8784ff
3 files changed
+59 -11

No files matched your search

@@ -102,8 +102,9 @@ correction (−4 before 2026-10-19, now 0: replaced by the feedforward).
- FZP range: `PID_x_fzp` / `PID_y_fzp` `Ub` / `Lb` are ±1.5 V in operation (the cap sensors are calibrated over
about ±2 V only). For the field of view above (2.8 × 1.8 µm) widen them, e.g. to ±10 V (FZP ≈ 0.13 µm/V in x,
≈ 0.05 µm/V in y). The feedforward stays off (`enable` 0,0) during this scan.
- The detector trigger (`OnTargetTrigger`) checks the relative error sample vs FZP (tolerance / hold time from the
ConstEmitter, BEC `interferometer_trigger_*`, default 10 nm / 3 ms) and waits `MinDelay_ms` (15 ms).
- The detector trigger (`OnTargetTrigger`) checks the relative error sample vs FZP (parameters
`ontarget_tolerance_um` / `ontarget_hold_ms`, BEC `flomni.realtime_system.trigger_*`, default 10 nm / 3 ms; until
2026-10-23 ConstEmitter lines) and waits `MinDelay_ms` (15 ms).
**Step 3, default operating values (replace the values in the text above):**
@@ -133,6 +134,24 @@ over a wider range the FZP can take the small steps alone (flOMNI `feedback_repo
Measured with 101 ms exposures: 0.2–1 µm steps trigger after 4.5–5.8 ms instead of 17–32 ms; the error during the
exposure grows with the step (1 µm: ≈ 6 nm max instead of 2.5 nm), so the setting depends on the experiment.
## With the loop settings (since 2026-10-23)
The steps above are profiles of the loop settings (web HMI tab *Loop settings*, BEC `flomni.realtime_system`;
flOMNI `FeedbackLoop/loopsettings/`). The rules keep the modules consistent, so the individual parameters above do
not have to be set by hand:
| Step | Profile | BEC |
|---|---|---|
| 1, FZP disabled (alignment, affine matrix) | `fzp_off` | `flomni.realtime_system.apply_profile("fzp_off")` |
| 2, FZP-only calibration scan (clear `MatrixCorr` first: not part of the settings) | `fzp_calibration` | `apply_profile("fzp_calibration")` |
| 3, back to operation | `production` | `apply_profile("production")` |
| afterwards, faster scans (calibrated over ±7 V) | `fast_scan` | `apply_profile("fast_scan")` |
Single values: `flomni.realtime_system.set(fzp_range_V_x=7, fzp_range_V_y=7)`,
`set(move_beyond_um_x=0.3)`, `set(exposure_during_motion=1)`; refused with the reason if a rule objects
(`adjust=True` changes the dependent settings too). FZP settings only between scans. Live only until
`save_as_default()`.
## Move-beyond (`PID_x` / `PID_y` `FAST_FZP_PID_LOOP(0)` < 0), 2026-10-23
**What it does** (`PID.cpp`, unchanged since the original loop). Only in point-by-point scans (scan state 2). The
@@ -153,7 +172,9 @@ target) and `AbbeCorrection` (Chan corrected for the stage tilt, see below). The
target and Chan, so it supplies the +m offset of the FZP directly (static term m / K).
**Sizing.** During the exposure the FZP has to hold m + Abbe correction + noise / settling inside its stroke:
|m| ≤ R − reserve, as a rule ≈ R / 2. R per axis = `Ub` × K (K ≈ 0.13 µm/V x, ≈ 0.05 µm/V y):
|m| ≤ R − reserve, as a rule ≈ R / 2. R per axis = `Ub` × K (K ≈ 0.13 µm/V x, ≈ 0.05 µm/V y). The loop settings
refuse more than 0.6 × R minus the Abbe limit (rule `move_beyond_*_fits`, constant `move_beyond_fraction`; the
tested ±7 V values are 0.56 × R):
| FZP `Ub`/`Lb` | R x / y | move-beyond x / y (≈ R/2) |
|---|---|---|
@@ -33,9 +33,14 @@ Changing the FZP range now involves, in addition to the text above:
small range. `use_final` 1 + `WaitForSlew` 0 ("exposure during the motion") only makes sense when the FZP range
covers the scan step; steps larger than the range then still wait for the sample stage.
- Move-beyond (0) must fit into the stroke: the FZP holds it during the exposure, together with the Abbe correction
(up to `correction_limit_um` 0.1 µm when enabled) and noise. Rule ≈ half the stroke: at ±1.5 V ≈ −0.1 µm (x),
(up to `correction_limit_um` 0.1 µm when enabled) and noise. Rule ≈ half the stroke (the loop settings refuse more than 0.6 × stroke minus the Abbe limit): at ±1.5 V ≈ −0.1 µm (x),
≈ −0.04 µm (y); at ±7 V −0.5 / −0.2 µm (tested). Production: 0. Details: calibration how-to, section "Move-beyond".
- (5) compares the real FZP drive incl. the feedforward (input 8 of `PID_x` / `PID_y` = `Feedforward` output since
2026-10-23; before it was the FZP PID output without the feedforward).
- After a change: web HMI tab **Loop check** level 1 (expected settings) and, with the beamline ready, the scan test
(level 4: positioning time, stability during the exposure per step size).
**With the loop settings (since 2026-10-23):** `flomni.realtime_system.set(fzp_range_V_x=..., fzp_range_V_y=...)`
(web HMI tab *Loop settings*) sets `PID_*_fzp` `Ub` / `Lb` and the `Feedforward` limits together; a move-beyond that
no longer fits is refused, or clamped with `adjust=True` (rule `move_beyond_*_fits`). `FreqGen` limits stay
manual (measurements only).
+29 -7
View File
@@ -224,18 +224,19 @@ In step scans the detector is triggered when the sample is stable at the scan po
sample vs FZP (interferometer minus FZP cap sensor) must stay within a tolerance in x and in y (each averaged
over 0.5 ms) for a hold time. Both values are live and can be changed between scans:
- `flomni.interferometer_trigger_show()` — current tolerance and hold time
- `flomni.interferometer_trigger_set_tolerance_nm(10)` — tolerance per axis in nm: about 30 for a fast
- `flomni.realtime_system.trigger_show()` — current tolerance, hold time, minimum delay, trigger after a move
- `flomni.realtime_system.trigger_set_tolerance_nm(10)` — tolerance per axis in nm: about 30 for a fast
low-resolution scan, 10 standard, 2 for the highest resolution (a few ms more per point);
0 selects the former criterion (on-target flags of the FZP loops)
- `flomni.interferometer_trigger_set_hold_ms(3)` — hold time in ms
- `flomni.interferometer_trigger_set_after_move(True)` — additionally one trigger after every position change
- `flomni.realtime_system.trigger_set_hold_ms(3)` — hold time in ms
- `flomni.realtime_system.trigger_set_after_move(True)` — additionally one trigger after every position change
of the sample stage (e.g. `umv(dev.rtx, ...)`), as soon as the position is stable with the same tolerance and
hold time; `False` (default): triggers at scan points only
- `dev.rtx.controller.move_xyz(x, y, z)` — moves rtx, rty and rtz with one command (one trigger for the move)
- `flomni.interferometer_trigger_help()` — this list
After a restart of the control loop the start values (10 nm, 3 ms) apply again. Measured with 3 µm steps
The former names `flomni.interferometer_trigger_*` still work (they print the new name). The values are live; after
a restart of the control loop the values of the loop's parameter files (10 nm, 3 ms) apply again, unless they were
saved with `flomni.realtime_system.save_as_default()`. Measured with 3 µm steps
(2026-10-20): the trigger comes about 36 ms (x) / 48 ms (y) after the step at 10 nm, 40 / 55 ms at 2 nm;
after the trigger the position stays within about 4 nm even at a 30 nm tolerance.
@@ -781,10 +782,31 @@ removed later.
[See short version](flomni.md#sample-storage-and-transfer)
### Real-time loop settings (expert): `flomni.realtime_system`
The operating settings of the real-time loop — FZP scanner on/off, FZP range, feedforward, move-beyond, exposure
during the motion, Abbe correction, detector trigger, laser tracker targets and thresholds — with the rules between
them. The rules and the mapping onto the loop parameters are kept on the loop machine (web HMI tab *Loop settings*,
`http://mpc2844:8080/?tab=settings`; definition in the flOMNI control repository,
`FeedbackLoop/loopsettings/flomni.json` and `README.md`); BEC and the web page use the same rules.
- `flomni.realtime_system.show()` — all settings with live and saved value, violated rules, scan state
(`show(expert=True)` also the FZP calibration group)
- `flomni.realtime_system.set(name=value, ...)` — change; refused (with the reason) if a rule objects, e.g. the
feedforward must be off while the FZP loop is off; `set(..., adjust=True)` changes the dependent settings too
- `flomni.realtime_system.check(name=value)` — dry run
- `flomni.realtime_system.profiles()`, `apply_profile("production" | "fzp_off" | "fzp_calibration" | "fast_scan")`
- `flomni.realtime_system.unsaved()`, `save_as_default()` — the changes are live only until the next start of the
control loop; `save_as_default()` writes them into the loop's parameter files
- `flomni.realtime_system.help()`
FZP settings can only be changed between scans. BEC needs the API token of the web HMI in `~/.flomni_webhmi_token`
(local contact; flOMNI `FeedbackLoop/loopsettings/README.md`).
### Detector trigger and interferometer tuning
The trigger tolerance and hold time: [Detector trigger: position stability](#detector-trigger-position-stability)
(`flomni.interferometer_trigger_*`). The control loops of the sample stage, the FZP scanner and the laser
(`flomni.realtime_system.trigger_*`). The control loops of the sample stage, the FZP scanner and the laser
tracker were characterized and retuned in October 2026; results, the present parameters and how to retune them
are documented in the flOMNI control repository (`FeedbackLoop/feedback_report.md` with PDF,
`FeedbackLoop/tuning_guide.md`).