This commit is contained in:
@@ -0,0 +1,450 @@
|
||||
# BEC – Beamline Experiment Control: System Overview
|
||||
|
||||
> **Erstellt:** April 2026
|
||||
> **Zweck:** Referenzdokument für Claude (AI-Assistent) zur Orientierung im BEC-Ökosystem am cSAXS-Beamline (X12SA, PSI).
|
||||
> **Nicht entwickelt von Nutzer:** Der Nutzer entwickelt *BEC-Begleit-Software* für cSAXS und die 3D-Ptychographie-Setups (LamNI, OMNY), nicht den BEC-Kern selbst.
|
||||
|
||||
---
|
||||
|
||||
## 1. Was ist BEC?
|
||||
|
||||
**BEC** steht für **Beamline and Experiment Control**. Es ist ein modulares, microservice-basiertes System zur Steuerung von Experimenten an Großforschungsanlagen (Synchrotrons, Neutronenquellen). Entwickelt am PSI (Paul Scherrer Institut), Schweiz.
|
||||
|
||||
- **Lizenz:** BSD-3-Clause
|
||||
- **Sprache:** Python (>99%)
|
||||
- **Python-Versionen:** 3.11, 3.12, 3.13
|
||||
- **Aktuelle Version:** ~3.117.x (bec-Kern), ~3.5.x (bec_widgets), ~1.36.x (ophyd_devices)
|
||||
- **Kommunikations-Backbone:** Redis (Pub/Sub + Streams)
|
||||
- **Dokumentation:** https://bec.readthedocs.io / https://beamline-experiment-control.readthedocs.io
|
||||
---
|
||||
|
||||
## 2. Architektur-Überblick
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ BEC Ecosystem │
|
||||
│ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ bec_ipython_ │ │ bec_widgets │ ← GUIs (PySide6) │
|
||||
│ │ client (CLI) │ │ (Qt/PySide6) │ │
|
||||
│ └────────┬────────┘ └────────┬────────┘ │
|
||||
│ │ │ │
|
||||
│ └──────────┬───────────┘ │
|
||||
│ │ bec_lib (gemeinsame Bibliothek) │
|
||||
│ │ Redis Connector / Messages / Endpoints │
|
||||
│ │ │
|
||||
│ ┌──────────▼───────────────────────────┐ │
|
||||
│ │ REDIS │ │
|
||||
│ │ (Pub/Sub + Streams, single source │ │
|
||||
│ │ of truth für alle Services) │ │
|
||||
│ └──────────┬───────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────▼──────────────────┐ │
|
||||
│ │ bec_server │ │
|
||||
│ │ ┌─────────────────────┐ │ │
|
||||
│ │ │ device_server │ │ ← ophyd / EPICS │
|
||||
│ │ │ scan_server │ │ │
|
||||
│ │ │ scan_bundler │ │ │
|
||||
│ │ │ file_writer │ │ │
|
||||
│ │ │ data_processing │ │ ← DAP Plugins │
|
||||
│ │ │ scihub │ │ ← Logbook, Atlas │
|
||||
│ │ └─────────────────────┘ │ │
|
||||
│ └──────────┬──────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌──────────▼──────────────────┐ │
|
||||
│ │ Hardware / EPICS IOCs │ │
|
||||
│ │ (Motoren, Detektoren, ...) │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
|
||||
Beamline-spezifische Plugins (z.B. csaxs_bec):
|
||||
- Erweitern device_server, scan_server, file_writer, bec_widgets
|
||||
- Laden über BEC Plugin-System (pyproject.toml entry points)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Kern-Repositories
|
||||
|
||||
Alle unter: https://gitea.psi.ch/bec (Mirrors von https://github.com/bec-project)
|
||||
|
||||
| Repository | Beschreibung | Wichtig für |
|
||||
|---|---|---|
|
||||
| **bec** | Haupt-Monorepo | Alles |
|
||||
| **bec_widgets** | Qt/PySide6 GUI-Toolkit | GUI-Entwicklung |
|
||||
| **ophyd_devices** | Geräteklassen (ophyd-Erweiterung) | Device-Entwicklung |
|
||||
| **csaxs_bec** | cSAXS-spezifische Plugins | cSAXS / LamNI / OMNY |
|
||||
|
||||
---
|
||||
|
||||
## 4. Repository: `bec` (Monorepo)
|
||||
|
||||
**URL:** https://gitea.psi.ch/bec/bec
|
||||
**GitHub:** https://github.com/bec-project/bec
|
||||
**Struktur:**
|
||||
|
||||
```
|
||||
bec/
|
||||
├── bec_lib/ ← Gemeinsame Python-Bibliothek
|
||||
│ └── bec_lib/
|
||||
│ ├── client.py ← BECClient Hauptklasse
|
||||
│ ├── device.py ← Device-Klassen (Wrapper um ophyd)
|
||||
│ ├── devicemanager.py ← DeviceManager (dev.samx, etc.)
|
||||
│ ├── endpoints.py ← Redis Message Endpoints (alle Topics)
|
||||
│ ├── messages.py ← Message-Typen (Pydantic-ähnlich)
|
||||
│ ├── redis_connector.py ← Redis-Verbindung (pub/sub, streams)
|
||||
│ ├── connector.py ← Abstrakte Connector-Klasse
|
||||
│ ├── scan_items.py ← Scan-Objekte
|
||||
│ ├── queue_items.py ← Scan-Queue-Management
|
||||
│ ├── callback_handler.py← Callback-System
|
||||
│ ├── alarm_handler.py ← Alarm-Handling
|
||||
│ ├── bec_service.py ← Basis-Klasse für alle BEC-Services
|
||||
│ ├── bec_errors.py ← Fehlerklassen
|
||||
│ ├── logger.py ← Logging-System
|
||||
│ ├── file_utils.py ← Datei-Hilfsfunktionen
|
||||
│ ├── live_scan_data.py ← Live-Daten während Scan
|
||||
│ ├── dap_plugins.py ← Data Analysis Plugins
|
||||
│ ├── dap_plugin_objects.py
|
||||
│ ├── lmfit_serializer.py← lmfit-Integration (Kurvenanpassung)
|
||||
│ ├── metadata_schema.py ← Scan-Metadata Schema
|
||||
│ ├── plugin_helper.py ← Plugin-Hilfsfunktionen
|
||||
│ ├── logbook_connector.py← Scilog/Logbook
|
||||
│ ├── acl_login.py ← Zugangskontrolle
|
||||
│ ├── bl_state_manager.py← Beamline State
|
||||
│ ├── codecs.py ← Serialisierung (msgpack)
|
||||
│ ├── numpy_encoder.py ← NumPy-Serialisierung
|
||||
│ ├── configs/ ← Default-Konfigurationen
|
||||
│ ├── procedures/ ← Scan-Prozeduren
|
||||
│ └── utils/ ← Hilfsfunktionen
|
||||
│
|
||||
├── bec_server/ ← Server-Seite (alle Microservices)
|
||||
│ └── bec_server/
|
||||
│ ├── device_server/ ← Kommuniziert mit Hardware via ophyd/EPICS
|
||||
│ ├── scan_server/ ← Führt Scans aus, verwaltet Queue
|
||||
│ ├── scan_bundler/ ← Bündelt Scan-Daten (Device + Scan Events)
|
||||
│ ├── file_writer/ ← Schreibt HDF5/NeXus-Dateien
|
||||
│ ├── file_writer_plugins/← Plugin-System für Dateiformat
|
||||
│ ├── data_processing/ ← Online-Datenanalyse (DAP)
|
||||
│ ├── procedures/ ← Server-seitige Prozeduren
|
||||
│ ├── scihub/ ← Anbindung externe Dienste (Atlas, Scilog)
|
||||
│ └── bec_server_utils/ ← CLI-Argument-Parsing
|
||||
│
|
||||
├── bec_ipython_client/ ← IPython CLI Interface
|
||||
│ └── bec_ipython_client/
|
||||
│ ├── bec_startup.py ← Startup-Script (lädt beim `bec`-Command)
|
||||
│ ├── main.py ← Einstiegspunkt
|
||||
│ ├── bec_magics.py ← IPython Magic Commands (%bec, etc.)
|
||||
│ ├── beamline_mixin.py ← Beamline-spezifische Mixins
|
||||
│ ├── callbacks/ ← CLI-Callbacks (Progress, Printing)
|
||||
│ ├── high_level_interfaces/ ← Höhere API (scans, dev, etc.)
|
||||
│ └── plugins/ ← Plugin-Verzeichnis
|
||||
│
|
||||
├── pytest_bec_e2e/ ← End-to-End Tests
|
||||
├── docs/ ← Sphinx-Dokumentation
|
||||
├── bin/ ← Start-Scripts
|
||||
└── bec_config_template.yaml ← Beispiel-Konfiguration
|
||||
```
|
||||
|
||||
### Wichtige Konzepte in bec_lib
|
||||
|
||||
**Redis Endpoints** (`endpoints.py`): Alle Redis-Topics sind hier zentral definiert.
|
||||
Beispiele:
|
||||
- `MessageEndpoints.device_readback(device_name)` → live Gerätewert
|
||||
- `MessageEndpoints.scan_segment` → Scan-Datenpunkte
|
||||
- `MessageEndpoints.scan_status` → Scan-Status
|
||||
**BECClient** (`client.py`): Haupt-Einstiegspunkt für alle Clients:
|
||||
```python
|
||||
from bec_lib.client import BECClient
|
||||
bec = BECClient()
|
||||
bec.start()
|
||||
scans = bec.scans
|
||||
dev = bec.device_manager.devices
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Repository: `ophyd_devices`
|
||||
|
||||
**URL:** https://gitea.psi.ch/bec/ophyd_devices
|
||||
**GitHub:** https://github.com/bec-project/ophyd_devices
|
||||
**Beschreibung:** Erweiterung von [ophyd](https://blueskyproject.io/ophyd/) für Geräte, die nicht durch Standard-EPICS-ophyd abgedeckt sind.
|
||||
|
||||
```
|
||||
ophyd_devices/
|
||||
├── ophyd_devices/
|
||||
│ ├── devices/ ← Konkrete Geräteklassen (EpicsMotor-Subklassen, etc.)
|
||||
│ ├── interfaces/ ← Abstrakte Interface-Klassen (SimplePositioner, etc.)
|
||||
│ ├── sim/ ← Simulierte Geräte für Tests/Demos
|
||||
│ ├── configs/ ← Beispiel-Gerätekonfigurationen (YAML)
|
||||
│ ├── utils/ ← Hilfsfunktionen (Static Device Tests, etc.)
|
||||
│ └── tests/ ← Unit-Tests
|
||||
└── tests/ ← Integrations-Tests
|
||||
```
|
||||
|
||||
**Zentrale Konzepte:**
|
||||
- Geräte erben von ophyd (`Device`, `EpicsMotor`, `EpicsSignal`, etc.)
|
||||
- BEC-spezifische Erweiterungen: Callbacks für Redis, BEC-Signale
|
||||
- `interfaces/` enthält abstrakte Klassen wie `SimplePositioner`
|
||||
- Simulierte Geräte in `sim/` für Offline-Entwicklung
|
||||
---
|
||||
|
||||
## 6. Repository: `bec_widgets`
|
||||
|
||||
**URL:** https://gitea.psi.ch/bec/bec_widgets
|
||||
**GitHub:** https://github.com/bec-project/bec_widgets
|
||||
**Framework:** PySide6 (Qt6)
|
||||
|
||||
```
|
||||
bec_widgets/
|
||||
├── bec_widgets/
|
||||
│ ├── widgets/
|
||||
│ │ ├── plots/ ← Waveform, MultiWaveform, Image/Heatmap
|
||||
│ │ ├── control/ ← PositionerBox, TweakWidget, ScanControl
|
||||
│ │ ├── containers/ ← BECDockArea (Haupt-Layout-Container)
|
||||
│ │ ├── dap/ ← Data Analysis Plugin Widgets (lmfit Dialog)
|
||||
│ │ ├── editors/ ← Code/Config-Editoren
|
||||
│ │ ├── progress/ ← Scan-Fortschrittsanzeige
|
||||
│ │ ├── services/ ← Service-Status-Widgets
|
||||
│ │ ├── utility/ ← Diverse Hilfs-Widgets
|
||||
│ │ └── games/ ← Easter Egg 🎮
|
||||
│ ├── cli/ ← RPC-CLI Bindings (auto-generiert via bw-generate-cli)
|
||||
│ ├── applications/ ← Fertige Anwendungen (BEC Launcher, Designer, Terminal)
|
||||
│ ├── utils/ ← Plugin-Template-Generator, Hilfsfunktionen
|
||||
│ ├── examples/ ← Beispiel-Widgets
|
||||
│ └── assets/ ← Icons, Bilder
|
||||
├── tests/
|
||||
└── docs/
|
||||
```
|
||||
|
||||
**Kern-Konzepte:**
|
||||
- `BECWidget` (Basisklasse): Alle Widgets erben davon. Bietet BEC/Redis-Verbindung, RPC.
|
||||
- `BECDispatcher`: Vermittelt Redis-Events an Qt-Slots.
|
||||
- `USER_ACCESS` Liste: Definiert, welche Methoden über RPC erreichbar sind.
|
||||
- `SafeSlot`: Thread-sicherer Qt-Slot Decorator.
|
||||
- `BECDockArea`: Haupt-GUI-Container mit Drag-and-Drop-Docking.
|
||||
**Widget erstellen (Minimalbeispiel):**
|
||||
```python
|
||||
from bec_widgets import BECWidget, SafeSlot
|
||||
from bec_lib.endpoints import MessageEndpoints
|
||||
|
||||
class MyWidget(BECWidget, QWidget):
|
||||
USER_ACCESS = ["my_method"]
|
||||
|
||||
def __init__(self, parent=None, **kwargs):
|
||||
super().__init__(parent=parent, **kwargs)
|
||||
self.bec_dispatcher.connect_slot(
|
||||
self.on_data,
|
||||
MessageEndpoints.device_readback("samx")
|
||||
)
|
||||
|
||||
@SafeSlot(dict, dict)
|
||||
def on_data(self, data, meta):
|
||||
...
|
||||
```
|
||||
|
||||
**CLI starten:** `bec` → öffnet IPython + BECDockArea GUI
|
||||
**Designer:** `bec-designer` → Qt Designer mit BEC-Widgets
|
||||
**RPC generieren:** `bw-generate-cli --target <plugin-repo>`
|
||||
|
||||
---
|
||||
|
||||
## 7. Repository: `csaxs_bec`
|
||||
|
||||
**URL:** https://gitea.psi.ch/bec/csaxs_bec
|
||||
**Beschreibung:** cSAXS-spezifische Plugins und Konfigurationen für BEC (X12SA Beamline, PSI)
|
||||
|
||||
```
|
||||
csaxs_bec/
|
||||
├── csaxs_bec/
|
||||
│ ├── devices/ ← cSAXS-Hardware-Geräteklassen
|
||||
│ │ ├── epics/ ← Standard EPICS Geräte (MCS-Karte, etc.)
|
||||
│ │ ├── ids_cameras/ ← IDS-Kameras (Alignment-Kameras)
|
||||
│ │ ├── jungfraujoch/ ← JungFrauJoch (JFJ) Detektor-Integration
|
||||
│ │ ├── npoint/ ← nPoint Piezo-Positionierer (Nano-Scans)
|
||||
│ │ ├── omny/ ← OMNY Tomographie-Stage
|
||||
│ │ ├── panda_box/ ← PandaBox Timing/Trigger-System
|
||||
│ │ ├── pseudo_devices/ ← Pseudo-Geräte (berechnete Positionen)
|
||||
│ │ ├── sls_devices/ ← SLS-spezifische Geräte (Synchrotron Light Source)
|
||||
│ │ ├── smaract/ ← SmarAct Piezo-Positionierer
|
||||
│ │ ├── tests_utils/ ← Test-Hilfsfunktionen (patch_dual_pvs)
|
||||
│ │ └── device_list.md ← Dokumentation aller Geräte
|
||||
│ │
|
||||
│ ├── scans/ ← cSAXS-spezifische Scan-Plugins
|
||||
│ │ ├── flomni_fermat_scan.py ← FlOMNI Fermat-Spiral Scan (Ptychographie)
|
||||
│ │ ├── omny_fermat_scan.py ← OMNY Fermat-Spiral Scan
|
||||
│ │ ├── LamNIFermatScan.py ← LamNI Fermat-Scan (3D Ptychographie!)
|
||||
│ │ ├── jungfrau_joch_scan.py ← JFJ-spezifischer Scan
|
||||
│ │ ├── sgalil_grid.py ← SGalil Grid-Scan (Galil-Controller)
|
||||
│ │ ├── owis_grid.py ← OWIS Grid-Scan
|
||||
│ │ ├── scan_plugin_template.py← Vorlage für neue Scan-Plugins
|
||||
│ │ └── metadata_schema/ ← cSAXS Metadata-Schema
|
||||
│ │
|
||||
│ ├── bec_widgets/ ← cSAXS-spezifische GUI-Widgets
|
||||
│ │ ├── widgets/
|
||||
│ │ │ ├── xray_eye/ ← X-Ray Eye Widget (Kamera-Alignment-Tool)
|
||||
│ │ │ └── client.py ← RPC-Client für cSAXS-Widgets
|
||||
│ │ └── auto_updates/ ← Automatische GUI-Updates
|
||||
│ │
|
||||
│ ├── bec_ipython_client/ ← cSAXS CLI-Erweiterungen
|
||||
│ │ └── ... ← Web-Generator, Auth-Integration
|
||||
│ │
|
||||
│ ├── device_configs/ ← YAML-Gerätekonfigurationen
|
||||
│ │ └── ... ← z.B. bec_device_config_sastt.yaml
|
||||
│ │
|
||||
│ ├── file_writer/ ← cSAXS-spezifischer File Writer Plugin
|
||||
│ ├── dap_services/ ← Online Datenanalyse (DAP) Services
|
||||
│ ├── macros/ ← BEC-Makros
|
||||
│ ├── services/ ← Zusatz-Services
|
||||
│ └── deployments/ ← Deployment-Konfigurationen
|
||||
│
|
||||
├── bin/ ← Start-Scripts
|
||||
├── docs/ ← Dokumentation
|
||||
└── tests/ ← Tests
|
||||
```
|
||||
|
||||
### Hardware am cSAXS (X12SA)
|
||||
|
||||
| Gerät | Klasse/Modul | Typ |
|
||||
|---|---|---|
|
||||
| Eiger | EPICS IOC | Röntgen-Flächendetektor |
|
||||
| Pilatus 300K | EPICS IOC | Röntgen-Flächendetektor |
|
||||
| FalconX1 | EPICS IOC | Fluoreszenz-Detektor |
|
||||
| JungFrauJoch (JFJ) | `devices/jungfraujoch/` | Röntgen-Detektor (High-rate) |
|
||||
| OMNY | `devices/omny/` | Tomographie-Drehtisch |
|
||||
| nPoint | `devices/npoint/` | Piezo-Positionierer (Nano) |
|
||||
| SmarAct | `devices/smaract/` | Piezo-Positionierer |
|
||||
| PandaBox | `devices/panda_box/` | Timing/Trigger-System |
|
||||
| MCS-Karte | `devices/epics/` | Multi-Channel Scaler |
|
||||
| IDS-Kameras | `devices/ids_cameras/` | Sichtbare-Licht-Kameras |
|
||||
| SGalil | EPICS/Config | Galil-Motorcontroller |
|
||||
| OWIS | Config | Motorcontroller |
|
||||
| Delay Generator (DDG) | EPICS IOC | Pulsgenerator (Timing) |
|
||||
|
||||
### Scans am cSAXS
|
||||
|
||||
| Scan | Datei | Verwendung |
|
||||
|---|---|---|
|
||||
| `sgalil_grid` | `sgalil_grid.py` | Standard-Raster-Scan (Galil-Controller) |
|
||||
| `omny_fermat_scan` | `omny_fermat_scan.py` | OMNY Fermat-Spiral (Ptychographie) |
|
||||
| `flomni_fermat_scan` | `flomni_fermat_scan.py` | FlOMNI Fermat-Spiral |
|
||||
| `LamNIFermatScan` | `LamNIFermatScan.py` | **3D Ptychographie (LamNI)** |
|
||||
| `jungfrau_joch_scan` | `jungfrau_joch_scan.py` | JFJ-Burst-Akquisition |
|
||||
| `owis_grid` | `owis_grid.py` | OWIS-Raster-Scan |
|
||||
|
||||
---
|
||||
|
||||
## 8. Beamline-Setup: cSAXS (X12SA)
|
||||
|
||||
**Beamline:** X12SA, Paul Scherrer Institut (PSI), Schweiz
|
||||
**Synchrotron:** SLS (Swiss Light Source)
|
||||
|
||||
### 3D Ptychographie / LamNI
|
||||
|
||||
**LamNI** = *Laminar Nano-Imaging* – das 3D Ptychographie-Setup am cSAXS.
|
||||
Relevante Komponenten:
|
||||
- **Scan:** `LamNIFermatScan` (Fermat-Spiral, optimiert für Ptychographie)
|
||||
- **Positionierung:** nPoint Piezo-Stages (Nanometer-Präzision) + übergeordnete Motoren
|
||||
- **Detektor:** Eiger oder ähnlich (kohärentes Streumuster)
|
||||
- **Timing:** PandaBox oder Delay-Generator
|
||||
### OMNY
|
||||
|
||||
OMNY = Tomographie-System mit Drehtisch.
|
||||
- **Scan:** `omny_fermat_scan`
|
||||
- **Gerät:** `devices/omny/`
|
||||
- Verwendet einen dedizierten "Flyer" für kontinuierliche Akquisition
|
||||
### Startup am cSAXS
|
||||
|
||||
```bash
|
||||
# BEC-Server starten (auf pc15543)
|
||||
cd ~/Data10/software
|
||||
source bec_venv/bin/activate
|
||||
bec-server start
|
||||
tmux attach -t bec
|
||||
|
||||
# BEC-Client starten
|
||||
bec
|
||||
|
||||
# Gerätekonfiguration laden
|
||||
bec.config.update_session_with_file('~/Data10/software/csaxs-bec/bec_plugins/configs/bec_device_config_sastt.yaml')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. BEC Plugin-System
|
||||
|
||||
BEC nutzt Python Entry Points für Plugins. Ein Plugin-Paket (z.B. `csaxs_bec`) registriert seine Komponenten in `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[project.entry-points."bec.plugins"]
|
||||
csaxs_bec = "csaxs_bec"
|
||||
|
||||
[project.entry-points."bec.scan_plugins"]
|
||||
csaxs_scans = "csaxs_bec.scans"
|
||||
|
||||
[project.entry-points."bec.file_writer_plugins"]
|
||||
csaxs_writer = "csaxs_bec.file_writer"
|
||||
```
|
||||
|
||||
BEC lädt automatisch alle registrierten Plugins beim Start.
|
||||
|
||||
---
|
||||
|
||||
## 10. Kommunikation & Datenfluss
|
||||
|
||||
```
|
||||
Hardware → EPICS IOC → ophyd (device_server) → Redis
|
||||
↓
|
||||
Client (bec_lib) ← Redis ← scan_bundler ← scan_server
|
||||
↓
|
||||
file_writer → HDF5/NeXus Dateien
|
||||
↓
|
||||
data_processing (DAP) → Online-Analyse
|
||||
```
|
||||
|
||||
**Wichtige Redis Message-Typen** (in `bec_lib/messages.py`):
|
||||
- `DeviceMessage` – Gerätewerte
|
||||
- `ScanMessage` – Scan-Informationen
|
||||
- `BECStatus` – Service-Status
|
||||
- `AlarmMessage` – Alarme/Fehler
|
||||
- `LogMessage` – Log-Einträge
|
||||
- `ScilogMessage` – Logbuch-Einträge
|
||||
---
|
||||
|
||||
## 11. Entwicklungs-Workflow
|
||||
|
||||
### Code-Standards
|
||||
- **Formatter:** Black (`--line-length=100 --skip-magic-trailing-comma`)
|
||||
- **Import-Sortierung:** isort (`--profile=black`)
|
||||
- **Linter:** Pylint
|
||||
- **Tests:** pytest
|
||||
- **Commit-Format:** Conventional Commits (`feat:`, `fix:`, `refactor:`, etc.)
|
||||
### Typisches Widget-Entwicklungs-Muster (csaxs_bec)
|
||||
|
||||
1. Widget-Klasse in `csaxs_bec/bec_widgets/widgets/<name>/` erstellen
|
||||
2. Von `BECWidget` + Qt-Widget erben
|
||||
3. `USER_ACCESS` für RPC definieren
|
||||
4. Auf Redis-Endpoints subscriben via `bec_dispatcher.connect_slot()`
|
||||
5. RPC-Client generieren: `bw-generate-cli --target csaxs_bec`
|
||||
6. Qt-Designer-Plugin wird automatisch registriert
|
||||
### Typisches Scan-Entwicklungs-Muster
|
||||
|
||||
1. Scan-Klasse in `csaxs_bec/scans/` erstellen
|
||||
2. Von BEC-Basis-Scan-Klasse erben
|
||||
3. In `pyproject.toml` registrieren
|
||||
4. Zugriff im Client: `scans.mein_scan(...)`
|
||||
---
|
||||
|
||||
## 12. Nützliche Links
|
||||
|
||||
| Ressource | URL |
|
||||
|---|---|
|
||||
| BEC Gitea | https://gitea.psi.ch/bec |
|
||||
| BEC GitHub | https://github.com/bec-project |
|
||||
| BEC Docs | https://bec.readthedocs.io |
|
||||
| BEC Widgets Docs | https://bec-widgets.readthedocs.io |
|
||||
| ophyd Docs | https://blueskyproject.io/ophyd/ |
|
||||
| cSAXS BEC Repo | https://gitea.psi.ch/bec/csaxs_bec |
|
||||
|
||||
---
|
||||
|
||||
*Dieses Dokument sollte dem Projekt hinzugefügt werden und dient als primäre Referenz für Claude in zukünftigen Gesprächen.*
|
||||
+607
@@ -0,0 +1,607 @@
|
||||
# cSAXS Setups: LamNI, OMNY, FlOMNI – Vollständige technische Referenz
|
||||
|
||||
> **Quellen:** Quellcode `csaxs_bec` + vier peer-reviewed Publikationen:
|
||||
> - Holler et al., *J. Synchrotron Rad.* **27**, 730–736 (2020) → LamNI
|
||||
> - Holler et al., *Rev. Sci. Instrum.* **89**, 043706 (2018) → OMNY
|
||||
> - Holler et al., *Rev. Sci. Instrum.* **83**, 073703 (2012) → FlOMNI (RT-Vorgänger)
|
||||
> - Holler & Raabe, *Opt. Eng.* **54**, 054101 (2015) → Tracking-Interferometer
|
||||
|
||||
---
|
||||
|
||||
## ❗ WICHTIGE KORREKTUR: Was ist LamNI wirklich?
|
||||
|
||||
**LamNI = Laminographic Nano-Imaging** (NICHT "Laminar Nano-Imaging"!)
|
||||
|
||||
LamNI ist ein Instrument für **ptychographische Röntgen-Laminographie** (PyXL).
|
||||
Laminographie unterscheidet sich grundlegend von Tomographie:
|
||||
|
||||
| | Tomographie (OMNY) | Laminographie (LamNI) |
|
||||
|---|---|---|
|
||||
| Rotationsachse | ⊥ zum Röntgenstrahl (90°) | Geneigt zum Strahl (≠ 90°) |
|
||||
| Probenform ideal | Zylindrisch (Pfeiler/Pillar) | Planar (flache Chips, Schichten) |
|
||||
| FOV-Winkelbereich | 0°–180° (vollständig) | 0°–360° (voller Umlauf nötig) |
|
||||
| Fehlende Information | Keine (vollständig) | Missing cone (statt Wedge) |
|
||||
| Präparation | Destruktiv (FIB-Pillar nötig) | Minimal (großflächige Proben!) |
|
||||
| Anwendung bei PSI | OMNY | LamNI |
|
||||
|
||||
**Laminographiewinkel bei LamNI:** 61° (zwischen Rotationsachse und Röntgenstrahl)
|
||||
Erzeugt durch: Erst 15° Kippen um x-Achse, dann 60° um y-Achse.
|
||||
|
||||
**Das erklärt den Code direkt:**
|
||||
```python
|
||||
MOVEMENT_SCALE_X = np.sin(np.radians(15)) * np.cos(np.radians(30))
|
||||
MOVEMENT_SCALE_Y = np.cos(np.radians(15))
|
||||
```
|
||||
Die 15° entsprechen der Stage-Verkippung in x. Die Koordinatentransformation ist notwendig, weil der Piezo-Scanner in der geneigten Stage-Ebene bewegt, die Interferometer aber im Laborrahmen messen.
|
||||
|
||||
---
|
||||
|
||||
## 1. LamNI – Laminographic Nano-Imaging
|
||||
|
||||
### Physikalisches Prinzip
|
||||
|
||||
Kohärente Röntgenstrahlung (~6–10 keV) wird durch eine Fresnel-Zonenplatte (FZP) fokussiert. Die Probe wird in einem Fermat-Spiralmuster abgetastet (Ptychographie). Für die 3D-Information wird die Probe um die geneigte Achse (61° zur Strahlrichtung) rotiert. Das erlaubt die Abbildung **flacher, großflächiger Proben** (ICs, Schichten) ohne destruktive Pillar-Präparation.
|
||||
|
||||
**Anwendungen:**
|
||||
- Integrierte Schaltkreise (IC, 16-nm-Technologie-Knoten demonstriert: 18.9 nm Auflösung)
|
||||
- Magnetische Strukturen (zeitaufgelöste Laminographie, 50 nm / 70 ps)
|
||||
- Großflächige Materialien in 3D
|
||||
### Hardware-Komponenten (aus Paper 2020)
|
||||
|
||||
```
|
||||
LamNI Mechanik (110 × 130 cm Grundplatte, 1 Tonne Gewicht)
|
||||
│
|
||||
├── Röntgenoptik (upstream)
|
||||
│ ├── FZP – auf xyz-Stages (Steinmeyer Mechatronik, Schrittmotoren)
|
||||
│ ├── CS (Central Stop) – auf xy-Stages (SmarAct GmbH)
|
||||
│ ├── OSA (Order Sorting Aperture) – auf xyz-Stages (SmarAct GmbH)
|
||||
│ ├── Flachspiegel (x und y) für Interferometer am FZP-Halter
|
||||
│ └── Helium-Flugrohr (reduziert Luftstreuung)
|
||||
│
|
||||
└── Probenstage (gestapelt)
|
||||
├── Grobe Translationsstages (Steinmeyer Mechatronik, Schrittmotoren)
|
||||
│ └── Für Stitching und Region-of-Interest-Auswahl
|
||||
├── Großer Rotationstisch (air-bearing, 365°, Radius 175 mm)
|
||||
│ ├── Renishaw Tonic Dual-Encoder-System
|
||||
│ ├── Luftlager → nach Rotation abgelassen → mechanisch geklemmt → steifer
|
||||
│ └── Schrittmotor-Antrieb (Steinmeyer Mechatronik)
|
||||
├── Piezo-Scanner (Npoint NPXY100-216)
|
||||
│ ├── 2 Translationsachsen (x, y in Stage-Ebene)
|
||||
│ ├── 100 µm Stellbereich je Achse
|
||||
│ ├── Interne kapazitive Sensoren (nur für Vorpositionierung)
|
||||
│ └── Closed-loop zum exteroceptiven Interferometer (Hauptregelung!)
|
||||
└── Anti-Rotations-Stage (Kugellager, PASSIV – kein Antrieb!)
|
||||
├── Trägt die Interferometer-Spiegel
|
||||
├── Dreht sich NICHT mit dem Probentisch (hält Spiegel senkrecht)
|
||||
├── Passiver Antrieb: Hebelarm + zwei Hardstops am Rotationstisch
|
||||
├── Pneumatische Bremse: Fixiert Spiegel während Scan
|
||||
└── Kapazitive Sensoren (A: Abstand zu Hardstops, B: Winkelmotion)
|
||||
```
|
||||
|
||||
### Device-Namen in BEC (LamNI)
|
||||
|
||||
| BEC-Device | Hardware | Einheit | Anmerkung |
|
||||
|---|---|---|---|
|
||||
| `rtx` | RT-Controller X (Piezo-Scanner Npoint X-Achse) | µm | Interferometer-geregelt |
|
||||
| `rty` | RT-Controller Y (Piezo-Scanner Npoint Y-Achse) | µm | Interferometer-geregelt |
|
||||
| `lsamx` | Koarse-Motor X (Steinmeyer) | mm | Read-only bei aktivem Feedback |
|
||||
| `lsamy` | Koarse-Motor Y (Steinmeyer) | mm | Read-only bei aktivem Feedback |
|
||||
| `lsamrot` | Großer Rotationstisch (air-bearing) | Grad | Laminographie-Winkel |
|
||||
| `loptx` | Optik-Motor X | mm | FZP/OSA-Ausrichtung |
|
||||
| `lopty` | Optik-Motor Y | mm | |
|
||||
| `loptz` | Optik-Motor Z | mm | |
|
||||
|
||||
### Interferometer-System (LamNI)
|
||||
|
||||
- **Typ:** Doppeldurchgang-Flachspiegel (KEIN Tracking-Interferometer!)
|
||||
Grund: 12 mm × 12 mm Scanbereich zu groß für Tracking mit Kugelspiegeln
|
||||
- **Laser:** Zygo Inc., 6 mm Strahldurchmesser
|
||||
- **Gemessen:** Relative Position FZP ↔ Probe (x und y, exteroceptiv)
|
||||
- **Anti-Rotations-Stage** hält Spiegel senkrecht zum Interferometerstrahl während Rotation
|
||||
- **Positionsstabilität:** 1.1 nm Standardabweichung (x und y)
|
||||
- **Positioniergenauigkeit:** 4.4 nm (H), 4.1 nm (V) std (ptychographisch verifiziert)
|
||||
- **Schrittantwort:** < 40 ms für 1.5 µm Schritt
|
||||
### LamNI Geometrie im Detail
|
||||
|
||||
```
|
||||
Koordinatensystem (Labor):
|
||||
z = Röntgenstrahl-Richtung
|
||||
x = horizontal
|
||||
y = vertikal (zeigt nach oben)
|
||||
|
||||
Stage-Verkippung:
|
||||
1. 15° Kippung um x-Achse
|
||||
2. 60° Kippung um y-Achse
|
||||
→ Laminographie-Winkel (Strahl ↔ Rotationsachse) = 61°
|
||||
|
||||
Piezo-Scan-Ebene:
|
||||
= Probenebene (geneigt gegenüber Labor-Koordinaten)
|
||||
|
||||
Interferometer-Messung:
|
||||
= In Laborkoordinaten x und y
|
||||
|
||||
→ Koordinatentransformation notwendig:
|
||||
(Code: lamni_to_stage_coordinates / lamni_from_stage_coordinates)
|
||||
|
||||
Rotation im Code (Winkelkorrektur):
|
||||
alpha = (angle - 300 + 30.538) / 180 * pi
|
||||
→ Die 300° und 30.538° sind mechanische Offsets des Setups
|
||||
```
|
||||
|
||||
### Anti-Rotations-Mechanismus (LamNI-spezifisch)
|
||||
|
||||
```
|
||||
Problem: Interferometer-Spiegel müssen senkrecht zum Strahl bleiben,
|
||||
aber Probe dreht sich mit dem Rotationstisch!
|
||||
|
||||
Lösung: Anti-Rotations-Stage auf dem Piezo-Scanner
|
||||
1. Großer Rotationstisch dreht (z.B. 45°)
|
||||
2. Hebelarm der kleinen Stage berührt Hardstop an der Basis des großen Tisches
|
||||
3. Kleine Stage dreht sich passiv um -45°
|
||||
4. Ergebnis: Spiegel bleiben in Laborkoordinaten ausgerichtet ✓
|
||||
|
||||
Sicherheit:
|
||||
- Kapazitive Sensoren (A): Abstand Hebel ↔ Hardstop überwacht
|
||||
- Kapazitive Sensoren (B): Winkelmotion der kleinen Stage
|
||||
- Pneumatische Bremse: Fixiert Spiegel während Scan
|
||||
- Auto-Entklemmen wenn Hebel zu nah an Hardstop (Sicherheitsmechanismus)
|
||||
|
||||
Prozedur bei Rotationswechsel:
|
||||
1. Piezo auf interne kapazitive Sensoren zentrieren
|
||||
2. Interferometer-Feedback ausschalten
|
||||
3. Bremse der kleinen Stage lösen
|
||||
4. Luftlager einschalten
|
||||
5. Großen Tisch zum Zielwinkel drehen (Encoder-Feedback)
|
||||
6. Kleine Stage klemmen
|
||||
7. Feinausrichtung der kleinen Stage (kap. Sensoren A → Servo-Regelung)
|
||||
8. Luftlager ausschalten (erhöht Steifigkeit)
|
||||
9. Letzten Encoder-Wert speichern (tatsächlicher Winkel für Rekonstruktion)
|
||||
```
|
||||
|
||||
### Scan-Aufruf und Parameter (LamNI)
|
||||
|
||||
```python
|
||||
# Standard LamNI Fermat-Scan
|
||||
scans.lamni_fermat_scan(
|
||||
fov_size=[20], # FOV in Piezo-Ebene [µm], max ~80 µm
|
||||
# [x] = quadratisch, [x,y] = rechteckig
|
||||
step=0.5, # Schrittweite [µm]
|
||||
exp_time=0.1, # Belichtungszeit [s]
|
||||
angle=0, # Laminographie-Rotationswinkel [Grad]
|
||||
center_x=0.02, # Scan-Zentrum X bei 0° [mm] – WIRD rotiert!
|
||||
center_y=0, # Scan-Zentrum Y [mm]
|
||||
shift_x=0, # Zusatzshift X [mm] – wird NICHT rotiert
|
||||
shift_y=0, # Zusatzshift Y [mm]
|
||||
stitch_x=0, # Stitch-Versatz X [µm]
|
||||
stitch_y=0, # Stitch-Versatz Y [µm]
|
||||
fov_circular=0, # Kreisförmiges FOV [µm] (zusätzliches Cropping)
|
||||
stitch_overlap=1, # Stitch-Überlapp [µm]
|
||||
scan_type="fly", # "fly" (HW-getriggert) oder "step"
|
||||
frames_per_trigger=1,
|
||||
)
|
||||
|
||||
# Zu neuem Scan-Zentrum fahren (rotations-kompensiert):
|
||||
scans.lamni_move_to_scan_center(shift_x_mm, shift_y_mm, angle_deg)
|
||||
```
|
||||
|
||||
### LamNI Leistungsdaten
|
||||
|
||||
| Parameter | Wert |
|
||||
|---|---|
|
||||
| Scan-Bereich | 12 mm × 12 mm (über Stitching) |
|
||||
| Piezo-Bereich | 100 µm × 100 µm (Npoint NPXY100-216) |
|
||||
| Positionsstabilität | 1.1 nm std |
|
||||
| Schrittantwort | < 40 ms für 1.5 µm |
|
||||
| Positioniergenauigkeit | 4 nm std (ptychographisch) |
|
||||
| Beste 3D-Auflösung | 18.9 nm (IC 16-nm-Technologie) |
|
||||
| Gewicht | 1 Tonne |
|
||||
| Grundplatte | 110 × 130 cm |
|
||||
|
||||
---
|
||||
|
||||
## 2. OMNY – tOMography Nano crYo Stage
|
||||
|
||||
### Physikalisches Prinzip
|
||||
|
||||
OMNY = kryogene Ptychographie-Tomographie. Die Rotationsachse ist senkrecht zum Röntgenstrahl (klassische Tomographie, 90°). Kryogene Bedingungen (90 K mit LN₂, 10 K mit LHe) schützen strahlungsempfindliche Proben.
|
||||
|
||||
**Betrieb bei cSAXS seit:** Juni 2015
|
||||
**Vakuum:** Ultra-Hochvakuum (10⁻⁷–10⁻⁸ mbar)
|
||||
**Probengeometrie:** Zylindrische Pfeiler (OMNY Pins)
|
||||
|
||||
### Hardware-Komponenten (aus Paper 2018)
|
||||
|
||||
```
|
||||
OMNY Mechanik (Vakuumkammer Ø 110 cm, 4 Tonnen Gewicht)
|
||||
Mineral-Cast-Block: 110 × 110 × 52 cm³
|
||||
│
|
||||
├── Röntgenoptik
|
||||
│ ├── FZP – auf 2D Piezo-Stage (nPoint, Inc., NPXY100D)
|
||||
│ │ └── Controller: NPoint LC.403
|
||||
│ ├── CS (Central Stop) – auf xy-Stage (SmarAct SLC-2430-S-UHV)
|
||||
│ └── OSA – auf xyz-Stage; Cryo 2 gekühlt (90 K)
|
||||
│ └── Spiegel-Mounts: SmarAct STT-25.4-UHV-TI (motorisiert)
|
||||
│
|
||||
├── Probenstage
|
||||
│ ├── 4 Schrittmotor-Stages (xyz + Rotation um y)
|
||||
│ │ ├── Linear: ±5 mm Range (Steinmeyer Mechatronik, Dresden)
|
||||
│ │ ├── Rotation: 365°, Renishaw Tonic UHV Encoder
|
||||
│ │ └── Controller: 3× Galil DMC-4080-D4140
|
||||
│ ├── Delta-Scanner (Tripod-Geometrie, PSI-Eigenentwicklung, Maag et al.)
|
||||
│ │ ├── 3 translatorische DOF, 450 µm Gesamtbereich
|
||||
│ │ ├── Schrittantwort: < 30 ms für ~2 µm Schritte
|
||||
│ │ ├── Lokale Metrologie: attocube Faserinterferometer (nanometrisch!)
|
||||
│ │ ├── Piezo aufgeteilt in 4 unabhängige Stapel:
|
||||
│ │ │ ├── High-Current Stapel: VF-500 Verstärker (1A) – schnelle Bewegung
|
||||
│ │ │ └── Low-Noise Stapel: SVR-150 – Feinregelung (< 10 nm Rauschen)
|
||||
│ │ └── Rotationsmatrix-Korrektur (Delta-Geometrie ≠ xyz des Labors)
|
||||
│ └── Referenzspiegel / Probenhalter (Al, diamantgedreht, Au-beschichtet)
|
||||
│ ├── LT Ultra GmbH (Herstellung)
|
||||
│ ├── Vertikal: Flachfläche für Doppelpass-Interferometer
|
||||
│ ├── Horizontal: Kugelform für Tracking-Interferometer
|
||||
│ ├── Oberflächenfehler < 300 nm, Rauigkeit ~1 nm
|
||||
│ └── Sample direkt montiert (minimiert Dead-Path!)
|
||||
│
|
||||
├── Kryosystem
|
||||
│ ├── Cryo 1: Helitran LT3B (LN₂ oder LHe, offener Kreislauf, leise!)
|
||||
│ │ └── O₂-freies Kupfergeflecht (514 mm) → Referenzspiegel
|
||||
│ │ └── 4 × 16 mm² + 10 × 23 mm² (gestuft für Kraftreduktion)
|
||||
│ ├── Cryo 2: LN₂-Rohrsystem → OSA (90K), Greifer, Parkstation, Therm. Schirm (108K)
|
||||
│ │ └── Thermischer Schirm: SmarAct SLC-1750-S-UHV (kann weggefahren werden)
|
||||
│ └── Aktive Temperaturregelung: Pt100 (Heraeus) + Heizwicklungen (Nichrom)
|
||||
│ └── Stabilität bei LN₂: 90.000 K ± 3.3 mK (über Tage!)
|
||||
│
|
||||
├── Interferometer-System (Zygo Inc.)
|
||||
│ ├── Laser: Modell 7714, 3 mm Strahldurchmesser
|
||||
│ ├── Karten: Modell 4004 + 2400 (VME-Bus)
|
||||
│ ├── VME64-to-PCI Adapter: Abaco Systems Modell 810
|
||||
│ ├── 5 gemessene Größen:
|
||||
│ │ ├── xy: Probe ↔ OSA (Tracking-IF für x, Flach für y)
|
||||
│ │ ├── xy: OSA ↔ FZP (Doppeldurchgang-Flachspiegel)
|
||||
│ │ └── Rotationswinkel um z des Probentisches
|
||||
│ └── Tracking-Interferometer-Stage:
|
||||
│ ├── y-Piezo: Dynamic Structures ZSA-400-PSI (400 µm, 200 Hz)
|
||||
│ ├── z-Stepper + z-Piezo (50 µm): folgt Kugelspiegel-Wobble
|
||||
│ └── Bremse: Piezoelektrisch (erhöht Steifigkeit der y-Stage)
|
||||
│
|
||||
├── Elektronik (National Instruments)
|
||||
│ ├── NI 6259: Analog In/Out (2 Kanäle)
|
||||
│ ├── NI 6733: Analog Out (8 Kanäle, Delta-Scanner + FZP)
|
||||
│ └── NI 6602: Counter/Encoder (attocube-Quadratur-Encoder)
|
||||
│
|
||||
└── Load-Lock (Leica VCT100-basiert, modifiziert)
|
||||
├── Turbomolekularpumpe (nur Befüllung/Transfer)
|
||||
├── Bis 6 OMNY Pins pro Shuttle
|
||||
└── Probengreifer für kryogenen Transfer
|
||||
```
|
||||
|
||||
### OMNY Real-Time-Kontrollsystem (Fig. 7 im Paper)
|
||||
|
||||
```
|
||||
Host-PC: Ubuntu Linux + RTAI 4.0 (Echtzeit-Kernel)
|
||||
Schleifenfrequenz: 2.5 kHz
|
||||
Frühere Kontrolle: SPEC (Certified Scientific Software) → jetzt: BEC!
|
||||
|
||||
Vollständiger Signalfluss:
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 2.5 kHz Loop │
|
||||
│ │
|
||||
│ Zygo-IF ──→ Slew-Rate-Limiter ──→ PID Sample xy │
|
||||
│ │ │ │ │
|
||||
│ │ Trajektorie-Gen. Rotationsmatrix │
|
||||
│ │ │ │
|
||||
│ │ PID Delta xy ──→ VF-500 │
|
||||
│ │ │ SVR-150 │
|
||||
│ Attocube ──→ Delta PID ──→ Range Extension │
|
||||
│ │ │
|
||||
│ Zygo FZP ──→ PID FZP xy ──→ NPoint LC.403 │
|
||||
│ │
|
||||
│ PSD Tracking ──→ PID Tracking yz ──→ ZSA-400-PSI Piezo │
|
||||
│ │
|
||||
│ Position-Sampler: Mean + Std jeder Achse während Belichtung│
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Ethernet → SPEC/BEC (asynchron, nicht Echtzeit)
|
||||
EPICS soft-IOC: Probenpositionen, Temperaturen, Vakuum-Status
|
||||
```
|
||||
|
||||
### OMNY Mikroskop (X-Ray Eye)
|
||||
|
||||
Das interne Mikroskop (X-Ray Eye) hat 3 Modi:
|
||||
|
||||
1. **Weitwinkel** (Übersicht): Edmund Optics Objektiv + IDS UI-524xCP-C
|
||||
2. **Röntgen-Ast**: Szintillator (LuAG:Ce, 0.1 mm) → Mitutoyo 20x → IDS UI-548xCP-M
|
||||
- Optische Auflösung: 1 µm an der Szintillatorebene
|
||||
3. **Sichtbar-Ast**: Leica Plan APO + Leica Z16 APO → IDS UI-548xCP-M
|
||||
- Auflösung: 2.5 µm bei 400 nm, 66.4 mm vor Szintillator
|
||||
Das X-Ray Eye ist die Basis des **`xray_eye`** BEC-Widgets in `csaxs_bec/bec_widgets/widgets/xray_eye/`!
|
||||
|
||||
### Device-Namen in BEC (OMNY)
|
||||
|
||||
| BEC-Device | Hardware | Beschreibung |
|
||||
|---|---|---|
|
||||
| `rtx` | Delta-Scanner X / RT-Controller | Interferometer-geregelt, Flyer-Start |
|
||||
| `rty` | Delta-Scanner Y | |
|
||||
| `rtz` | Delta-Scanner Z | Z-Richtung (Defokussierung) |
|
||||
| `osamroy` | Rotationstisch | Tomographie-Winkel [Grad], 365° |
|
||||
| `osamx` | Koarse-Motor X | Proben-Grobpositionierung |
|
||||
| `rt_omny` | Sync-Flyer-Device | Überwacht Scan-Fortschritt |
|
||||
|
||||
### OMNY Alignment-Prozedur (aus Paper)
|
||||
|
||||
1. **Grob-Alignment**: X-Ray Eye Kamera + GUI (früher LabView, jetzt BEC)
|
||||
- 5 Rotationswinkel gleichmäßig verteilt von 0° bis 180°
|
||||
2. **Fein-Alignment**: 5 Ptychographie-Scans, sinusförmige Kurvenanpassung
|
||||
3. **Affine-Korrektur**: Einmalig pro Run (Flipping-Experiment + FSC-Optimierung)
|
||||
### OMNY Leistungsdaten
|
||||
|
||||
| Parameter | Wert |
|
||||
|---|---|
|
||||
| Probe-Stabilität | < 10 nm std (in-position während Belichtung) |
|
||||
| Positioniergenauigkeit | 8.1 nm (H), 4.7 nm (V) std residues |
|
||||
| Beste 2D-Auflösung | 8.5 nm (FRC, 1-bit Threshold) |
|
||||
| Beste 3D-Auflösung (IC) | 14.6 nm (Nature 2017) |
|
||||
| Beste 3D-Auflösung (biologisch, hochstreuend) | 27 nm (Käferflügelschuppe) |
|
||||
| Biologisch schwach streuend | 111 nm (Chlamydomonas in OMNY, LN₂) |
|
||||
| Probengröße max | ~50.000 µm³ Volumen |
|
||||
| Röntgenenergie | 6.2 keV typisch |
|
||||
| Detektor-Abstand | 7.33 m (Pilatus 2M) |
|
||||
| Temperaturstabilität | 90.000 K ± 3.3 mK (über Tage) |
|
||||
| Experimentlaufzeit | 5–6 Wochen kryogen (ohne Aufwärmen) |
|
||||
|
||||
---
|
||||
|
||||
## 3. FlOMNI – Fly-OMNY (Raumtemperatur, Fly-Scan)
|
||||
|
||||
### Was ist FlOMNI?
|
||||
|
||||
**FlOMNI** ist der **Raumtemperatur**-Nachfolger des ursprünglichen RT-Instruments (Holler 2012). Es ist als **Async Fly-Scan** (`AsyncFlyScanBase`) konzipiert: die Probe bewegt sich kontinuierlich, während die Detektoren laufend aufnehmen. Das 2012er Paper beschreibt den direkten Vorgänger.
|
||||
|
||||
**Grundprinzip des Closed-Loop-Schemas (aus 2012er Paper):**
|
||||
```
|
||||
1. Probe zu Zielposition bewegen (nur interne kapazitive Sensoren)
|
||||
2. Interferometer-Feedback an FZP-Piezo EINSCHALTEN
|
||||
3. Belichtung: FZP kompensiert verbleibende Drift (< 50 nm Amplitude)
|
||||
4. Interferometer-Mittelwert → Input für Ptychographie-Rekonstruktion
|
||||
5. Interferometer-Feedback AUSSCHALTEN, FZP-Piezo zurückzentrieren
|
||||
6. Nächste Position
|
||||
```
|
||||
|
||||
Bei FlOMNI ist dies für kontinuierliche Bewegung optimiert (Fly-Scan).
|
||||
|
||||
### FlOMNI Besonderheiten
|
||||
|
||||
| Merkmal | Wert/Beschreibung |
|
||||
|---|---|
|
||||
| Betrieb | Raumtemperatur, Atmosphäre |
|
||||
| Scan-Modus | Async Fly-Scan |
|
||||
| BEC-Basisklasse | `AsyncFlyScanBase` |
|
||||
| Tracker | **Laser-Tracker** (aktive Strahlverfolgung) |
|
||||
| Trigger | DDG1 (Delay-Generator 1), `EXT_RISING_EDGE` |
|
||||
| Cleanup | DDG1 zurück auf `SINGLE_SHOT` nach Scan |
|
||||
| Scan-Umkehr | Jeder 2. Scan reversed (Redis global var) |
|
||||
| FOV X max | 200 µm |
|
||||
| FOV Y max | 100 µm |
|
||||
| Z-Shift max | ±100 µm |
|
||||
| Probenmagazin | `flomni_sample_storage` – automatischer Probenwechsel! |
|
||||
| Rotation | `fsamroy` (FlOMNI Rotationsmotor) |
|
||||
| Flyer | `rt_positions` (AsyncFlyScanBase Monitor) |
|
||||
| Temp-Monitoring | `flomni_temp_and_humidity.py` |
|
||||
|
||||
### Laser-Tracker (FlOMNI-spezifisch)
|
||||
|
||||
Im Gegensatz zu OMNY (klassisches Tracking-Interferometer) hat FlOMNI einen Laser-Tracker:
|
||||
|
||||
```python
|
||||
# Im Scan-Code (flomni_fermat_scan.py):
|
||||
yield from self.stubs.send_rpc_and_wait("rtx", "controller.laser_tracker_on")
|
||||
tracker_signal = yield from self.stubs.send_rpc_and_wait(
|
||||
"rtx", "controller.laser_tracker_check_signalstrength"
|
||||
)
|
||||
# Ergebnis: "ok", "low", oder "toolow"
|
||||
|
||||
if tracker_signal == "low":
|
||||
# Alarm (WARNING), Scan kann weiterlaufen, Realignment empfohlen
|
||||
elif tracker_signal == "toolow":
|
||||
raise ScanAbortion("Laser-Tracker-Signal zu schwach – Realignment nötig!")
|
||||
|
||||
# Nach Positionierung zum Scan-Zentrum:
|
||||
yield from self.stubs.send_rpc_and_wait(
|
||||
"rtx", "controller.move_samx_to_scan_region", self.cenx
|
||||
)
|
||||
```
|
||||
|
||||
### Device-Namen in BEC (FlOMNI)
|
||||
|
||||
| BEC-Device | Beschreibung |
|
||||
|---|---|
|
||||
| `rtx` | RT-Controller X + Laser-Tracker-Interface |
|
||||
| `rty` | RT-Controller Y |
|
||||
| `rtz` | RT-Controller Z (Defokussierung) |
|
||||
| `fsamroy` | FlOMNI Rotationsmotor [Grad] |
|
||||
| `ddg1` | Delay-Generator 1 (Trigger, EPICS) |
|
||||
| `rt_positions` | Async-Flyer-Device |
|
||||
|
||||
---
|
||||
|
||||
## 4. Tracking-Interferometer – Gemeinsame Schlüsseltechnologie
|
||||
|
||||
Das **Error-Motion-Compensating Tracking Interferometer** (Holler & Raabe, Opt. Eng. 2015, Patent WO 2012079875 A1) ist Grundlage für OMNY (und den RT-Vorgänger/FlOMNI):
|
||||
|
||||
### Das Problem bei rotierenden Proben
|
||||
|
||||
Bei Standard-Interferometern mit Kugelspiegel muss der Kugelspiegel präzise auf der Rotationsachse zentriert sein. Das ist in der Praxis nicht möglich → Kugelspiegel wackelt → Strahl trifft nicht mehr auf Kugelmitte → Signal verloren.
|
||||
|
||||
**Lösung 1 (einfach):** Interferometer auf x/y-Stage, PSD misst Strahlposition → Tracking
|
||||
**Problem:** Tracking-Stage selbst hat Fehlermotion (Kugeellager: ~200 µrad Winkelfehler → ~3 µm Messfehler)
|
||||
|
||||
### Die optische Kompensation (Holler & Raabe 2015)
|
||||
|
||||
```
|
||||
Aufbau (vier polarisierende Strahlteiler PBS1-PBS4, zwei externe Referenzspiegel R1, R2):
|
||||
|
||||
Referenzstrahl: f1,f2 → PBS1 → R1 → PBS1 → PBS2 → R2 → PBS2 → HWP → PBS4
|
||||
Messstrahl: f1,f2 → PBS1 → PBS3 → Kugelspiegel → PBS3 → R2 → PBS4
|
||||
|
||||
Optische Wege:
|
||||
Referenz: 2·(a + b) [a = PBS1 zu R1, b = PBS2 zu R2]
|
||||
Messung: 2·(c + d) [c = PBS1 zu Sphäre, d = PBS3 zu R2]
|
||||
|
||||
OPD = 2·(a+b) - 2·(c+d)
|
||||
|
||||
Wenn Tracking-Stage sich um Δ bewegt (Translation):
|
||||
a,c kürzen sich um Δ; b,d verlängern sich um Δ → OPD unverändert ✓
|
||||
|
||||
Wenn Tracking-Stage sich dreht (Rotation um Zentrum):
|
||||
a,d kürzen sich; b,c verlängern sich → OPD unverändert ✓
|
||||
|
||||
R1 sitzt bei FZP-Position → direkte Differenzmessung Probe ↔ FZP!
|
||||
```
|
||||
|
||||
**PSD misst Kugelposition in x/y:**
|
||||
→ Closed-Loop zum Tracking → Kugel muss NICHT zentriert sein auf Rotationsachse!
|
||||
|
||||
**Ergebnis:**
|
||||
- Ohne Kompensation: ~3 µm Restfehler (Kugeellager-Winkelfehler)
|
||||
- Mit Kompensation: ~15 nm Restfehler (Faktor 200 besser!)
|
||||
- In OMNY verwendet: Positionsstabilität < 10 nm std
|
||||
### Warum LamNI kein Tracking-Interferometer braucht
|
||||
|
||||
Der LamNI-Scan ist 12 mm × 12 mm groß. Das überschreitet die praktikable Reichweite des Tracking-Systems mit Kugelspiegeln (begrenzt durch Tiefenschärfe des fokussierten Laserstrahls). Daher: Flachspiegel + Anti-Rotations-Stage als alternative Lösung.
|
||||
|
||||
---
|
||||
|
||||
## 5. nPoint Piezo-Controller – Zwei verschiedene Rollen!
|
||||
|
||||
| | Bei OMNY | Bei LamNI |
|
||||
|---|---|---|
|
||||
| **Modell** | NPXY100D | NPXY100-216 |
|
||||
| **Steuert** | **FZP-Position** (Röntgenoptik!) | **Probe** (Piezo-Scanner) |
|
||||
| **Controller** | NPoint LC.403 | im RT-Controller integriert |
|
||||
| **Bereich** | klein (Optik-Stabilisierung) | 100 µm × 100 µm |
|
||||
| **Zweck** | FZP in closed-loop zur Interferometermessung | Proben-Scanning für Ptychographie |
|
||||
|
||||
**BEC-Driver:** `csaxs_bec/devices/npoint/npoint.py`
|
||||
- Binary-Protokoll (LC.400/LC.403 Controller)
|
||||
- `0xA0 [addr] 0x55` = Lesen; `0xA2 [addr] [data] 0x55` = Schreiben
|
||||
- Positionsbereich: 0–100% → intern 0–1048574 Integerwert
|
||||
- 3 Achsen pro Controller
|
||||
---
|
||||
|
||||
## 6. RT-Controller (LamNI-spezifisch) – Socket-Protokoll
|
||||
|
||||
Der `RtLamniController` kommuniziert über TCP/IP Socket (ASCII-Kommandos):
|
||||
|
||||
| Kommando | Bedeutung |
|
||||
|---|---|
|
||||
| `J0` | Interferometer-Feedback deaktivieren |
|
||||
| `J4` | Aktuelle Interferometerposition lesen (x, y, ...) |
|
||||
| `J5` | Feedback aktivieren (ohne Reset der Zielposition) |
|
||||
| `J6` | Feedback + Winkelinterferometer-Reset deaktivieren |
|
||||
| `J2` | Feedback-Status + Interferometer-Signalstärke (SSI 0, SSI 1) |
|
||||
| `J3` | SSI-Mittelung triggern (vor J2 aufrufen!) |
|
||||
| `J7` | Winkel-Interferometer: Status, Position, Signalstärke |
|
||||
| `sc` | Scan stoppen + Trajektorie löschen |
|
||||
| `sd` | Punkt-für-Punkt-Scan starten |
|
||||
| `sr` | Scan-Status: (Mode, geplante Pos., aktuelle Pos.) |
|
||||
| `o` | Ist Achse am Ziel? (bool) |
|
||||
| `s{x:.5f},{y:.5f},0` | Position zum Scan-Buffer hinzufügen |
|
||||
| `a{angle_rad}` | Rotationswinkel setzen (rad, mit Mechanik-Offset) |
|
||||
| `V{um_per_s}` | Achsengeschwindigkeit setzen |
|
||||
| `V0` | Maximale Geschwindigkeit |
|
||||
| `As` / `Ar` | Analog-Sampling starten/lesen |
|
||||
| `Ss` / `Sr` | Positions-Sampling starten/lesen |
|
||||
| `pa0,{x}` | Zielposition Achse 0 setzen (für Feedback-Enable) |
|
||||
| `pa1,{y}` | Zielposition Achse 1 setzen |
|
||||
|
||||
**Scan-Status-Modi:**
|
||||
- Mode 0: Direkte Positionierung (kein Scan aktiv)
|
||||
- Mode 2: RT Point-Scan läuft
|
||||
- Mode 3: RT Point-Scan startet
|
||||
**Interferometer-Achsen** (aus `show_signal_strength_interferometer`):
|
||||
- Achse 0: "ST FZP horizontal" (Zonenplatte, horizontal)
|
||||
- Achse 1: "ST FZP vertical" (Zonenplatte, vertikal)
|
||||
- Achse 2: Winkel-Interferometer (Rotation)
|
||||
---
|
||||
|
||||
## 7. Galil Motor-Controller (OMNY)
|
||||
|
||||
**Typ:** Galil DMC-4080-D4140 (3 Einheiten für 19 Stages)
|
||||
**Encoder:** Renishaw Tonic UHV
|
||||
|
||||
Funktionen:
|
||||
- Closed-loop zum Encoder
|
||||
- Following-Error-Überwachung (Schritt- vs. Encoderposition)
|
||||
- Motortemperatur-Überwachung
|
||||
- Automatische Reichweitenerweiterung der Tracking-Piezo-Stages
|
||||
BEC-Treiber: `csaxs_bec/devices/omny/galil/`
|
||||
|
||||
---
|
||||
|
||||
## 8. Detektoren und Röntgenstrahl am cSAXS
|
||||
|
||||
### Röntgenstrahl
|
||||
- **Undulator:** In-Vakuum, 19 mm Periode
|
||||
- **Vertikale Quellgröße:** 20 µm
|
||||
- **Sekundärquelle:** Spalt 20 µm breit, 12.1 m downstream vom Undulator
|
||||
- **Monochromator:** Si(111) Doppelkristall (fixed-exit) + Fused-Silica-Spiegel
|
||||
- **Typische Energie:** 6.2 keV (λ = 0.2 nm)
|
||||
### Detektoren
|
||||
|
||||
| Detektor | Pixelgröße | Verwendung | Abstand (typisch) |
|
||||
|---|---|---|---|
|
||||
| Pilatus 2M | 172 µm | OMNY, LamNI | 7.33 m |
|
||||
| Pilatus 300K | 172 µm | cSAXS Standard | variabel |
|
||||
| Eiger 1.5M | 75 µm | Moderne OMNY/FlOMNI | variabel |
|
||||
| JungFrauJoch (JFJ) | – | Hochrate | variabel |
|
||||
| IDS UI-524xCP-C | – | OMNY Weitwinkel-Kamera | intern |
|
||||
| IDS UI-548xCP-M | – | OMNY Röntgen-Auge + Sichtbar | intern |
|
||||
|
||||
---
|
||||
|
||||
## 9. Gesamtvergleich der drei Setups
|
||||
|
||||
| Eigenschaft | LamNI | OMNY | FlOMNI |
|
||||
|---|---|---|---|
|
||||
| Methode | Ptych. Laminographie | Ptych. Tomographie (kryogen) | Ptych. Tomographie (RT) |
|
||||
| Rotationsachse | 61° geneigt | 90° (senkrecht) | 90° (senkrecht) |
|
||||
| Temperatur | Raumtemperatur | 90 K (LN₂) / 10 K (LHe) | Raumtemperatur |
|
||||
| Vakuum | Nein | UHV (10⁻⁸ mbar) | Nein |
|
||||
| Scan-Modus | Step (HW-getriggert) | Sync Fly-Scan | Async Fly-Scan |
|
||||
| BEC-Basisklasse | `ScanBase` | `SyncFlyScanBase` | `AsyncFlyScanBase` |
|
||||
| FOV (Scanning) | 12 mm × 12 mm (Stitch) | ~50 µm × 50 µm | 200 × 100 µm |
|
||||
| Piezo (Probe) | Npoint NPXY100-216 | Delta-Scanner (PSI) | RT-Scanner |
|
||||
| Piezo (FZP) | xyz-Stages (Steinm.) | Npoint NPXY100D + LC.403 | – |
|
||||
| Interferometer | Flachspiegel + Anti-Rotation | Tracking (Kugelspiegel) | Laser-Tracker |
|
||||
| Positionsstabilität | 1.1 nm | < 10 nm | < 10 nm |
|
||||
| Rotation BEC | `lsamrot` | `osamroy` | `fsamroy` |
|
||||
| Flyer-Device | – | `rt_omny` | `rt_positions` |
|
||||
| Gewicht | 1 Tonne | 4 Tonnen | ähnlich |
|
||||
| Beste Auflösung | 18.9 nm 3D | 8.5 nm 2D / 14.6 nm 3D | ~15 nm |
|
||||
| Probenform | Flach/großflächig | Zylindrisch (OMNY Pins) | Zylindrisch |
|
||||
| Probenmagazin | Nein | Load-Lock (6 Pins/Shuttle) | `flomni_sample_storage` |
|
||||
| Scan-Min. Punkte | 20 (ScanAbortion sonst) | 20 | 20 |
|
||||
|
||||
---
|
||||
|
||||
## 10. Kritische Erkenntnisse für Softwareentwicklung
|
||||
|
||||
1. **LamNI ist LAMINOGRAPHIE** (61° geneigt), nicht Tomographie – beeinflusst alle Positionsberechnungen
|
||||
2. **Koordinatentransformation** im Code physikalisch begründet durch Stage-Verkippung (15°/60°)
|
||||
3. **`rtx`/`rty`** = Piezo-Scanner in Interferometer-Koordinaten (µm), nicht Stage-Koordinaten
|
||||
4. **`lsamx`/`lsamy`** = Koarse-Motoren (mm), werden auf read-only gesetzt bei aktivem Feedback
|
||||
5. **nPoint** steuert bei OMNY die **FZP** (nicht Probe!), bei LamNI die **Probe**
|
||||
6. **OMNY** hat einen eigenen Real-Time-Kernel (RTAI 4.0, 2.5 kHz) – kommuniziert über Ethernet
|
||||
7. **Anti-Rotations-Stage** ist mechanische Besonderheit von LamNI (passiv, Hebelarm)
|
||||
8. **Tracking-Interferometer** (Holler & Raabe 2015) ist Schlüsseltechnologie für OMNY/FlOMNI
|
||||
9. **FlOMNI** hat Laser-Tracker (nicht klassisches Tracking-Interferometer)
|
||||
10. **DDG1** muss bei FlOMNI vor und nach Scan umgeschaltet werden (EXT_RISING_EDGE / SINGLE_SHOT)
|
||||
11. **Trajektorie-Umkehr** (FlOMNI + OMNY) wird in Redis persistent gespeichert
|
||||
12. Die Drift-Korrektur in LamNI läuft in bis zu **2 Iterationen**, Abbruch bei Drift > 150 µm
|
||||
13. **Delta-Scanner (OMNY)**: Tripod-Geometrie → Rotationsmatrix notwendig für xyz-Kontrolle
|
||||
14. **Attocube-Faserinterferometer**: Lokale Metrologie im Delta-Scanner (für schnelle PID-Schleife)
|
||||
15. **OMNY Affine-Korrektur**: Einmalig pro Experimentrun bestimmt (Flipping-Experiment + FSC)
|
||||
16. **OMNY Tracking-Stage y-Piezo** (ZSA-400-PSI, 400 µm, 200 Hz): ähnliche Eigenschaften wie Delta-Scanner – daher geeignet für kontinuierliche Bewegung während Ptychographie
|
||||
---
|
||||
|
||||
*Erstellt April 2026. Quellen: Quellcode csaxs_bec + 4 peer-reviewed Publikationen (Holler et al. 2012, 2015, 2018, 2020).*
|
||||
Reference in New Issue
Block a user