optilaz
| ConvolutionInterpolations.jl@dc9f9806b2 | ||
| laser-dac-rs@92e632ad8d | ||
| laser-optimizer | ||
| lzr@e19b5b3b82 | ||
| OpenIDN-Laser-DAC-Framework@437e7a245c | ||
| .gitignore | ||
| .gitmodules | ||
| COMPARAISON_OPTIMISATION.md | ||
| README.md | ||
optilaz — Laser Optimisation & Interpolation Toolkit.
Objectif final : Une implémentation Rust de la meilleure optimisation possible de traces laser, indépendante du DAC (via
laser-dac-rs), mais dépendante de la vitesse/physique des galvos (velocity planning curvature-aware).
État actuel : État de l'art — revue complète des composants existants, problèmes physiques, algorithmes de référence (lzr v2, papier Abderyim), et moteurs math (convinterp).
Prochaine étape : Digérer toute cette doc/code → implémenter dans
laser-optimizer/(crate Rust autonome, DAC-agnostique).
Structure du repo
lasoptidn/
├── COMPARAISON_OPTIMISATION.md # Doc complète : problème, matrice 7 composants, annexes
├── README.md # Ce fichier (résumé + roadmap)
├── Abderyim_2008_Accurate_Efficient_Laser_Projection.pdf # Papier référence (4 MB, .gitignore)
├── .gitmodules # Submodules
├── OpenIDN-Laser-DAC-Framework/ # Submodule: C++ — Récepteur IDN → DAC (transport pur)
├── laser-dac-rs/ # Submodule: Rust — Backbone DAC + hooks (TransitionFn, OutputFilter)
├── lzr/ # Submodule: C++ — liblzr optimizer v1/v2 + ILDA parser
├── ConvolutionInterpolations.jl/ # Submodule: Julia — Interpolation haute ordre, lazy=true
└── laser-optimizer/ # 🎯 FUTUR : Crate Rust finale (DAC-agnostique, galvo-aware)
Résumé des 4 composants existants (état de l'art)
| Composant | Langage | Rôle | Force | Gap critique pour l'objectif |
|---|---|---|---|---|
| OpenIDN | C++17 | Récepteur IDN réseau → DAC | Transport natif IDN, 4 DACs | Pas d'optimisation (points bruts) |
| laser-dac-rs | Rust | Backbone DAC : abstraction unifiée + hooks | 7 DACs, Frame/Stream API, TransitionFn, OutputFilter, reconnect, watchdog |
Pas d'optimizer (par design) — cible d'intégration |
| lzr optimizer v2 | C++17 | Algo référence : Path discovery + TSP angle-aware + cycles natifs | Architecture modulaire, traversal solve temps/énergie | Interpolation manquante (étape 5), LGPL v3, 1 seul DAC |
| convinterp | Julia/Python/Rust | Moteur math : B-spline ≤13e degré, lazy O(1), dérivées exactes 7e ordre | Seul avec lazy + dérivées + degré élevé | Zéro notion laser/DAC/blanking — moteur à brancher |
Architecture cible (Rust pur, DAC-agnostique)
┌────────────────────────────────────────────────────────────────────────────────────┐
│ laser-optimizer (crate Rust autonome) │
│ ┌──────────────────────────────────────────────────────────────────────────────┐ │
│ │ OPTIMIZATION PIPELINE │ │
│ │ │ │
│ │ INPUT (Frame) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 1. PATH DISCOVERY ← Port lzr v2: split lit/blank/angle │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 2. TRAVERSAL SOLVE ← Port lzr v2: TSP angle-aware + cycles natifs │ │
│ │ │ (Path, PathTraversal, TraversalSolve, cache) │ │
│ │ ▼ │ │
│ │ 3. KEYFRAME EXTRACTION ← Points réordonnés + sens parcours par cycle │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ 4. LAZY INTERPOLATION ← convinterp: Spline1D::builder().lazy(true) │ │
│ │ │ B-spline degré 7 (C⁶), dérivées 1 & 2 exactes │ │
│ │ ▼ │ │
│ │ 5. VELOCITY PLANNING ← κ = |d²p/ds²| → v_max = √(a_max/κ) │ │
│ │ │ Resampling adaptatif PPS-driven │ │
│ │ ▼ │ │
│ │ 6. BLANKING (intra-frame)← lasy: blank_delay_points + angle delay (Eq.1) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ OUTPUT (OptimizedFrame) ← Points denses, PPS-correct, galvo-safe │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────────────────┘
│
▼ (via laser-dac-rs hooks)
┌────────────────────────────────────────────────────────────────────────────────────┐
│ laser-dac-rs (BACKBONE — ne pas modifier) │
│ • TransitionFn → inter-frame blanking courbe (C² via même interpolant lazy) │
│ • OutputFilter → safety clamp, color delay, final PPS resample │
│ • 7 DACs → Helios, EtherDream, IDN, LaserCube, AVB, Oscilloscope, DaisyDAC│
│ • Reconnect, watchdog, metrics │
└────────────────────────────────────────────────────────────────────────────────────┘
Séparation des responsabilités
| Couche | Responsabilité | Implémentation |
|---|---|---|
| laser-optimizer | Algo pur : path discovery, TSP, cycles, interpolation lazy, velocity planning, blanking intra-frame | Nouveau crate — DAC-agnostique, galvo-aware |
| laser-dac-rs | Transport : DAC abstraction, inter-frame transition, output filter, reconnect, watchdog | Existant — ne pas modifier |
| lasy | Papier Abderyim : blanking delay, angle delay linéaire, Eulerian graph min blanks | Dépendance (déjà Rust) |
| convinterp | Math : B-spline lazy, dérivées exactes, resampling | Dépendance (wrapper Rust) |
Problème physique → Contraintes d'implémentation
4 modes de failure (points bruts → galvos)
- Segments longs → coins coupés (galvos trop lents)
- Sauts blank longs → flicker, perte luminosité
- Angles brusques → overshoot/ringing
- Vitesse excessive → distorsion, chauffe, usure
Contrainte fondamentale : Velocity planning curvature-aware
v_max_curvature = √(a_max / κ) (κ = courbure = |d²p/ds²|)
v_target = min(v_max, v_max_curvature)
→ Il faut insérer des points où κ est forte (coins serrés). → Résolution : interpolation lazy (convinterp) + dérivée 2 → κ → resampling adaptatif.
Paramètres galvo (configurables par profil matériel)
| Paramètre | Symbole | Unité | Typique | Source |
|---|---|---|---|---|
| Points/sec DAC | PPS |
pts/s | 30 000 | DAC spec |
| Accélération max | a_max |
rad/s² | ~10⁶ | Galvo spec |
| Vitesse max | v_max |
rad/s | ~10⁴ | Galvo spec |
| Délai blanking | blank_delay_points |
pts | 10–50 | Papier Abderyim + calibration |
| Délai angulaire | radians_per_point |
rad/pt | ~0.001 | Papier Abderyim Eq.1 + calibration |
Roadmap d'implémentation (phases)
Phase 0 — Préparation (maintenant)
- Repo git + submodules + doc complète
- Lire
lzr/lzr/optimizer2/optimizer2.cpp+optimizer2.hpp(algo référence) - Lire
lasy/src/lib.rs(implémentation papier Abderyim) - Expérimenter
convinterp(Python:pip install convinterp) - Tester
laser-dac-rsexamples (cargo run --example frame -- circle)
Phase 1 — Port lzr v2 → Rust (lzr-v2-ported)
- Structures :
Point,Path(avecis_cycle),PathTraversal(entry + direction) - Path discovery : split par blank toggle + angle threshold (135°)
- Traversal Solve : coût temps/énergie, multi-entry pour cycles, cache angles
- Eulerian graph + min blanks (Eq.2:
r = p + n/2) vialasyou réimplémenté - Output :
Vec<Path>réordonnés + parcours optimal par cycle - Tests : comparer sortie vs
lzrC++ sur frames ILDA de test
Phase 2 — Intégration convinterp + velocity planning (laser-optimizer core)
Spline1D::builder().degree(7).lazy(true).build(keyframes)- Dérivée 1 → vitesse, dérivée 2 → accélération/courbure κ
v_target = min(v_max, √(a_max/κ))par point- Resampling adaptatif :
dt = ds / v_target→ plus de points où κ fort convolution_resampleou boucle manuelle PPS-driven- Tests : visualiser courbure + densité points sur formes test (cercle, carré, spirale)
Phase 3 — Blanking intra-frame + papier Abderyim
blank_delay_points: points fixes avant "laser on" après saut (P1)radians_per_point: délai linéaire en radians =angle / radians_per_point(P2, Eq.1)- Intégrer
lasy::blank_segment_points+corner_point_count - Eulerian graph pour min blanks inter-paths (P3, Eq.2)
- Tests : comparer rendu vs papier Fig. 7, 10, 12, 16
Phase 4 — API unifiée + intégration laser-dac-rs
pub fn optimize_frame(input: &Frame, config: &OptimizerConfig) -> OptimizedFrameOptimizerConfig: tous paramètres galvo + papier + PPS- Brancher dans
laser-dac-rsviaOutputFilter(intra-frame) +TransitionFn(inter-frame) - Inter-frame blanking courbe : même interpolant lazy → C² continu
- Tests : end-to-end avec EtherDream/Helios réel
Phase 5 — Polish & production
- Profiling / benchmarks (allocation, latence, PPS soutenu)
- Profils galvo prédéfinis (CT6210, CT6215, DT40, etc.)
- Documentation + exemples
- Publier
laser-optimizersur crates.io
Quick start (pour commencer le développement)
# 1. Explorer l'algo de référence (C++)
cat lzr/lzr/optimizer2/optimizer2.cpp
cat lzr/lzr/optimizer2/optimizer2.hpp
# 2. Comprendre l'implémentation papier Abderyim (Rust)
cat laser-dac-rs/../lasy/src/lib.rs # ou depuis crates.io
# 3. Tester le backbone DAC
cd laser-dac-rs
cargo run --example frame -- circle
cargo run --example transitions -- default
# 4. Expérimenter convinterp (Python le plus simple)
pip install convinterp
python -c "
import convinterp as ci
import numpy as np
x = np.linspace(0, 1, 20)
y = np.sin(2*np.pi*x)
itp = ci.convolution_interpolation(x, y, kernel='b7', lazy=True)
print(itp(0.5)) # évaluation lazy
print(itp.derivative(1, 0.5)) # vitesse
print(itp.derivative(2, 0.5)) # accélération/courbure
"
# 5. Lire la doc complète
cat COMPARAISON_OPTIMISATION.md
Fichiers clés à connaître pour l'implémentation
| Fichier | Contenu | Utilité pour laser-optimizer |
|---|---|---|
lzr/lzr/optimizer2/optimizer2.hpp/.cpp |
Optimizer v2 complet (5 étapes) | Source principale Phase 1 |
lzr/lzr/interpolator.hpp |
Interpolator simple (lin/quad/quart) | Référence interpolation basique |
lasy/src/lib.rs |
Pipeline papier Abderyim (5 étapes) | Blanking/angle delays, Eulerian graph |
laser-dac-rs/src/stream/frame.rs |
FrameStream + hooks TransitionFn/OutputFilter | Points d'intégration Phase 4 |
ConvolutionInterpolations.jl/src/convolution/ |
Kernels, lazy, dérivées, resampling | Spécifications convinterp |
COMPARAISON_OPTIMISATION.md |
Annexes A–E complètes | Référence complète |
Liens utiles
- OpenIDN : https://gitlab.com/laser_light_lab_uni_bonn/OpenIDN-Laser-DAC-Framework
- laser-dac-rs : https://github.com/ModulaserApp/laser-dac-rs
- lzr : https://github.com/brendan-w/lzr
- ConvolutionInterpolations.jl : https://github.com/NikoBiele/ConvolutionInterpolations.jl
- convinterp (PyPI) : https://pypi.org/project/convinterp/
- Papier Abderyim PDF : https://art-science.org/journal/v7n4/v7n4pp155/artsci-v7n4pp155.pdf
- Beamplex (référence pro) : https://beamplex.org/
Notes pour le futur laser-optimizer/
# Structure attendue une fois créé :
laser-optimizer/
├── Cargo.toml
├── src/
│ ├── lib.rs # API publique: optimize_frame(), OptimizerConfig
│ ├── path_discovery.rs # Port lzr v2: split lit/blank/angle
│ ├── traversal_solve.rs # Port lzr v2: TSP angle-aware + cycles
│ ├── interpolation.rs # Wrapper convinterp lazy + velocity planning
│ ├── blanking.rs # Blanking intra-frame (lasy + papier)
│ └── types.rs # Frame, OptimizedFrame, Path, PathTraversal
├── benches/
│ └── optimizer_bench.rs # Criterion benches
├── tests/
│ ├── integration_test.rs # End-to-end avec laser-dac-rs
│ └── test_frames/ # Fichiers ILDA de test
└── examples/
└── basic_usage.rs
Dépendances Cargo.toml (prévisionnel) :
[dependencies]
lasy = "0.4" # Papier Abderyim implémenté
convinterp = { git = "https://github.com/JuliaMath/ConvolutionInterpolations.jl" }
petgraph = "0.6" # Graphes Euler (déjà dans lasy)
nalgebra = "0.32" # Math vectoriel
serde = { version = "1.0", features = ["derive"] }
thiserror = "1.0"