optilaz
Find a file
protonphoton 3c5cabd69c sim: simulateur galvo + métriques de qualité (port lj_rust) + fix leak + bench croisé
Port TDD de lj_rust (protonphoton) dans laser-opt :
- src/sim/galvo.rs : miroir 2nd ordre par axe (f_n 2.5 kHz, zeta 0.7),
  garde d'intégration MAX_W_DT (substeps auto), laser_delay en substeps,
  renvoie le 2e tour (régime établi).
- src/sim/metrics.rs : 7 familles de métriques sur la trace simulée —
  déviation mean/p95/max, overshoot/rounding des coins, luminosité cv
  (bins le long des tracés), leak (faisceau allumé en transit), coverage,
  fps/lit_fraction, pics accel/vitesse. Tout relatif à FS=2.0.
- examples/sim_quality_bench.rs -> bench_sim_quality.json (5 formes x
  3 charges x 4 mix, trame jouée à 30 kpps).

Fix leak (TDD, 3 tests blank_tests) : le blank d'approche statique
(13 pts au départ du saut) est remplacé par transit_blanks() — transit
dynamique quintic porté de laser-dac/presentation (Linf -> 0-64 pts +
dwells 100/400 µs). asteroids leak 0.176 -> 0.000, cov 1.000.

Bench croisé (examples/bench_lj_vs_mix.rs -> bench_compare_lj.json) :
pipeline optimize() complet de lj_rust branché en dev-dep (feature
helios rendue optionnelle pour éviter le conflit libusb1-sys), mesuré
par les mêmes métriques. Verdict : lj_rust cov 1.000 / leak 0.000 mais
cv luminosité 0.46-0.56 et nb de points fixé par le temps (526 pts sur
un carré demandé à 10000) ; v2+velocity : leak 0.000, cov >= 0.955,
cv 0.003-0.16 (3-37x mieux), le plus rapide à charge égale.

119 tests verts, 0 warning. README : état au 2026-10-18, pro/con
du bench croisé, quick start à jour.
2026-10-18 12:56:48 +02:00
ConvolutionInterpolations.jl@dc9f9806b2 Add submodules: ConvolutionInterpolations.jl, OpenIDN, laser-dac-rs, lzr 2026-10-04 19:55:44 +02:00
laser-dac-rs@92e632ad8d Add submodules: ConvolutionInterpolations.jl, OpenIDN, laser-dac-rs, lzr 2026-10-04 19:55:44 +02:00
laser-opt sim: simulateur galvo + métriques de qualité (port lj_rust) + fix leak + bench croisé 2026-10-18 12:56:48 +02:00
laser-optimizer benchs and stuffs 2026-10-16 22:28:04 +02:00
lasy@a9e79a5ef1 benchs and stuffs 2026-10-16 22:28:04 +02:00
lzr@e19b5b3b82 Add submodules: ConvolutionInterpolations.jl, OpenIDN, laser-dac-rs, lzr 2026-10-04 19:55:44 +02:00
OpenIDN-Laser-DAC-Framework@437e7a245c Add submodules: ConvolutionInterpolations.jl, OpenIDN, laser-dac-rs, lzr 2026-10-04 19:55:44 +02:00
.gitignore benchs and stuffs 2026-10-16 22:28:04 +02:00
.gitmodules benchs and stuffs 2026-10-16 22:28:04 +02:00
COMPARAISON_OPTIMISATION.md benchs and stuffs 2026-10-16 22:28:04 +02:00
README.md sim: simulateur galvo + métriques de qualité (port lj_rust) + fix leak + bench croisé 2026-10-18 12:56:48 +02:00

optilaz — Laser Optimisation & Interpolation Toolkit.

Lis ce README dans l'ordre : il est écrit pour un nouveau venu (humain ou IA).

  1. Où en est-on → 2. Résultats clés → 3. Structure & technologies (la stack, Linux et macOS) → 4. Quick start (faire tourner) → 5. Roadmap (ce qui est fait/coché) → 6. Architecture & physique (le fond) → 7. Plateformes & patches (macOS).

Où en est-on ? (2026-10-18)

L'implémentation existe et tourne : laser-opt/ — port Rust du meilleur algo connu (lzr v2, sans FFI) + moteur lasy (papier Abderyim 2008) + velocity planning curvature-aware + sorties DAC (EtherDream/IDN). 119 tests verts, 0 warning, matrice de 4 pipelines benchée sur 5 formes × 3 charges : v2+velocity gagnant (couverture lit complète, leak 0.000, 393 µs @10k asteroids — sous la frame 60 Hz).

Nouveau (2026-10-17→18) — simulation + métriques + bench croisé lj_rust :

  • crates/laser-opt/src/sim/ : simulateur galvo 2nd ordre (f_n 2.5 kHz, ζ 0.7, garde d'intégration MAX_W_DT, laser_delay) + 7 familles de métriques de qualité (déviation mean/p95/max, overshoot/rounding des coins, uniformité de luminosité cv, leak = faisceau allumé en transit, coverage, fps/effort) — portés de lj_rust (protonphoton), TDD.
  • Fix leak : le blank d'approche statique (13 pts) remplacé par un transit dynamique quintic (L∞ → 0–64 pts + dwells) — asteroids leak 0.176 → 0.000.
  • Bench croisé (examples/bench_lj_vs_mix.rs → bench_compare_lj.json) : le pipeline optimize() complet de lj_rust branché en dev-dep, mesuré par LES MÊMES métriques. Verdict chiffré ci-dessous.

Ce qui marche : pipeline complet forme → ordre → interpolation → asserts physiques → PNG/JSON → DAC (IDN testé bout-en-bout avec le simulateur, EtherDream attend le matériel).

Ce qui reste (P2) : laser réel EtherDream, GalvoSafety en OutputFilter sur le flux DAC, profils galvo prédéfinis.

La doc pour aller plus loin :

  • laser-opt/DEVBOOK.md — LE journal de développement (point d'entrée pour reprendre) : tous les bugs corrigés (symptôme → cause → fix), les résultats mesurés de chaque phase, les pièges et leçons TDD. Écrit pour être lisible sans contexte.
  • COMPARAISON_OPTIMISATION.md — la référence physique/architecturale (équations galvos, comparatif des composants, annexes interpolation lazy). Sa bannière d'entête dit ce qui est déjà exécuté.
  • laser-opt/bench_mix_matrix.json — les benchs bruts (régénérables : cargo run -p laser-opt --example mix_full_bench).
  • laser-opt/bench_compare_lj.json — le bench croisé vs lj_rust (régénérable : cargo run -p laser-opt --release --example bench_lj_vs_mix).
  • PNG de rendu : laser-opt/out_*.png (5 formes) + laser-opt/bench_*.png (comparatif moteurs).

Pour une IA : donner DEVBOOK.md + COMPARAISON_OPTIMISATION.md + ce README — ça suffit pour connaître l'état exact, les décisions prises et les bugs déjà corrigés (ne pas les re-découvrir).


Bench croisé vs lj_rust (2026-10-18, release, 30 kpps, mêmes formes/charges/métriques)

Le pipeline optimize() complet de lj_rust (stages clean→order→plan→budget→sample) est branché en dev-dependency et mesuré par les mêmes métriques que nos 4 mix (bench_compare_lj.json, 75 lignes).

lj_rust laser-opt v2+velocity
leak (transit allumé) 0.000 partout 0.000 (depuis le fix quintic)
couverture 1.000 partout 0.955–1.000
luminosité (cv, ↓ = mieux) 0.46–0.56 0.003–0.16 (3–37× mieux)
nb de points fixé par le temps (377–1000 pts, ignore la charge) suit la charge demandée (500–10000)
vitesse @10k asteroids 234 µs (1000 pts) 393 µs (10000 pts)
densification des coins non (sampling temporel uniforme) oui (κ Menger, ratio 2×)

Pro lj_rust : blanking propre par construction (un tracé = un run allumé, sauts blank explicites) ; très rapide au point (13–47 ns/pt) ; pipeline en stages purs testables ; le meilleur simulateur/métriques du domaine (portés ici). Con lj_rust : trame sous-échantillonnée à luminosité inégale (cv 0.46–0.56) — pas de densification de coin ; budget en temps ignore la charge ; pas de blanking intra-tracé, pas de GalvoSafety, pas de sorties IDN ; Redis/Valkey en bus (à ne pas prendre). Pro laser-opt : qualité mesurable et supérieure (cv, coverage, budget respecté) ; matrice ordre×interpolation ; GalvoSafety ; sorties IDN réelles ; asserts physiques. Con laser-opt : plus cher au point (146–412 ns/pt) ; V2ApplyPlan reste défaillant (cov 0.92, leak 0.176 — mix écarté) ; LasyNative garde un leak résiduel 0.008–0.015.

Verdict : v2+velocity domine en qualité à budget égal ; de lj_rust on a pris les outils (simulateur, métriques, transition quintic), pas le pipeline.


Résultats clés (détail complet dans laser-opt/DEVBOOK.md)

La découverte qui a débloqué le --mix (2026-10-15)

lasy et lzr v2 font tous les deux ordre et interpolation — les deux étapes sont découplables → 4 pipelines mixtes possibles (2 ordres × 2 interpolations), exposés par --mix :

Étape lasy lzr v2 laser-dac Verdict
Ordre ✅ graphe eulérien ✅ glouton — 2 implémentations
Interpolation ✅ distance_per_point ✅ apply_plan resample Catmull-Rom (device) 2+1
Velocity/coins — — — velocity.rs (maison)
Transition/dwell — — ✅ default_transition unique
Sécurité — — — GalvoSafety unique

Matrice finale (bench_mix_matrix.json, 5 formes × 4 mix × 3 charges)

Après les fixes du 16 oct (allocation cumulative du budget, blanks réservés), les 4 mix sortent 500 exact. État final (matrice du 16 oct, bench_mix_matrix.json) :

Mix Budget @500 Lit (carré+point) Coin varied_angles Temps @500
lasy+native 500 exact 4.400 32 141 µs
lasy+velocity 500 exact 4.400 31 140 µs
v2+apply_plan 500 exact 4.391 (omet le point) 28 103 µs
v2+velocity ✅ 500 exact 4.400 (complet) 31 76 µs

Historique (avant les fixes, matrice du 15 oct) : apply_plan explosait en densité coin (74 → 299 → 1498 @500/2000/10000) et le budget dérivait (510-542) — le velocity resampling corrigeait déjà la sur-densification, les fixes budget/blank ont fait le reste.

GAGNANT v2+velocity : budget exact, couverture lit complète, densité coin saine à toute charge, le plus rapide. Sur le scénario asteroids (6 polylignes disjointes + blanking) : 5 jumps au lieu de 6, lit 3.554u complet, 175 µs @500.

Temps de calcul : pas un critère discriminant

lasy 8-936 µs, v2 3-269 µs (budgets 100-10000, 4 formes, release). Tous < 1 ms → marge ×16 minimum sur la frame 60 Hz (16.7 ms). Ratio v2/lasy 1.8-4.1×.

Physique du budget (500 pts/frame)

30 kpps @ 60 Hz = 500 pts/frame (16.67 ms) — compromis de travail, pas une vérité physique (le kpps mesure la galva, pas le DAC ; EtherDream monte à 100 kpps hardware mais la galva downstream reste le goulot). Amplification input → output mesurée : 45× à 125× (4-9 sommets → 500 pts). Formes toutes en zone safe r_max ≤ 0.78 (marge 20 % vs bords DAC ±1).

Les bugs corrigés en chemin (le DEVBOOK les détaille tous)

  • lasy : segment blank→lit classé Lit → faisceau ALLUMÉ en transit (ligne parasite à travers l'écran) ; nœuds blank exclus du graphe → points isolés jamais tracés
  • port lzr v2 : bug off-by-one C++ (traverse cycle)
  • budget : dérive d'arrondi de l'allocation cumulative (velocity + apply_plan), blanks de saut non réservés, clamp sur la mauvaise dernière traversée
  • κ des bouts de polyligne = κ du premier virage ; Shape.closed ; fusion lasy à couleur égale ; polylignes dégénérées eulériennes filtrées

Structure du repo

optilaz/
├── README.md                            # Ce fichier — point d'entrée
├── COMPARAISON_OPTIMISATION.md          # Référence physique/architecturale + annexes
├── .gitmodules                          # 5 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 (référence portée)
├── ConvolutionInterpolations.jl/        # Submodule: Julia — Interpolation haute ordre, lazy=true (référence)
├── lasy/                                # Submodule: Rust — Papier Abderyim 2008 (eulerian + blanking), patché (bug faisceau allumé en transit)
├── laser-optimizer/                     # Placeholder historique de la roadmap → réalisé par laser-opt/
└── laser-opt/                           # ✅ L'IMPLÉMENTATION (workspace : lib laser-opt + binaire laser-opt-test)
    ├── DEVBOOK.md                       # ← JOURNAL COMPLET : bugs corrigés, résultats, pièges
    ├── SORTIES-TDD.md                   # Décisions + tests TDD de la couche DAC
    └── crates/                          # laser-opt (lib) + laser-opt-test (binaire CLI/webui)

Le papier de référence Abderyim_2008_Accurate_Efficient_Laser_Projection.pdf (4 MB) est dans .gitignore — pas dans le repo.


Technologies utilisées

La stack de l'implémentation (laser-opt/)

Technologie Version Rôle Pourquoi elle
Rust (edition 2021) stable ≥1.96 Tout le code Zero-copy, mono-process, sûr ; le port lzr v2 tourne sans FFI
lasy 0.4.1 (submodule, patché) 0.4.1 Ordre de tracé : graphe eulérien + blanking (papier Abderyim et al. 2008) Seule implémentation du papier ; patché (2 bugs : faisceau allumé en transit, points isolés)
laser-dac-rs 0.14 (submodule) 0.14.0 Backbone DAC : abstraction unifiée 7 DACs + hooks TransitionFn/OutputFilter + presentation (quintic + dwells) + resample Catmull-Rom MIT, Rust pur, cible d'intégration du plan
petgraph 0.5 Graphes (eulérien, pairing) Imposé par lasy — ne pas monter 0.6 (API break)
serde / serde_json 1 Sorties JSON (métriques, benchs) Standard
clap 4 CLI (--shape, --mix, --target, --out-dac, --safety, --web, --png) Standard, derive
anyhow 1 Erreurs du binaire Standard
approx 0.5 Comparaisons flottantes dans les tests Standard

Zéro dépendance plateforme : pas de FFI, pas de C++ compilé, pas de Python/Julia au runtime. Le PNG est écrit à la main (zlib stored blocks + CRC32, zéro crate), la webui aussi (TcpListener, zéro framework HTTP).

Les références (submodules, pas compilées par laser-opt)

Technologie Langage Usage dans ce repo
lzr (liblzr) C++17 Algo de référence porté en Rust (lzr2*.rs) — pas compilé par laser-opt
OpenIDN-Laser-DAC-Framework C++17 Récepteur IDN alternatif (transport pur) — optionnel
ConvolutionInterpolations.jl Julia Référence math interpolation lazy — non intégrée (décision : velocity planning maison, cf. COMPARAISON §verdict)

Protocoles DAC supportés (via laser-dac-rs)

DAC Transport État dans laser-opt
IDN (Open IDN) UDP (wave, scan) ✅ testé bout-en-bout avec le simulateur idn-simulator
EtherDream UDP broadcast 7654 + TCP ✅ code prêt (scan, prepare_stream/begin/data) — attend le DAC réel (P2)
Helios, lasercube, AVB, oscilloscope USB/réseau Disponibles dans laser-dac-rs, non branchés dans le harness

Plateformes : Linux ET macOS

Le code est Rust pur, sans dépendance plateforme — il compile et passe les tests tel quel sur Linux (X11) et macOS :

  • développé sur Linux tl13 (X11) ; recompilation macOS prévue (user sammm, cf. § Plateformes plus bas)
  • la seule partie sensible à la plateforme est la GUI idn-simulator (winit/eframe) : sur Linux sans wayland on force features = ["x11"] (patch documenté), sur macOS le Cargo.toml d'origine du fork convient
  • le mode headless (tests, benchs, asserts, PNG, JSON) ne touche à aucune GUI — CI-able sur les deux OS
  • aucun binaire dans le repo : chaque machine recompile ses artefacts (target/ ignoré)

Les 4 composants d'origine (état de l'art, pourquoi ils sont là)

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)

  1. Segments longs → coins coupés (galvos trop lents)
  2. Sauts blank longs → flicker, perte luminosité
  3. Angles brusques → overshoot/ringing
  4. 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 ✅ (2026-10-14)

  • 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)
  • Tester laser-dac-rs examples + intégration IDN (idn-simulator GUI, webui)
  • Expérimenter convinterp (Python) — remplacé par velocity planning maison (Menger κ, v_target=min(v_max, √(a_max/κ))) dans laser-opt/crates/laser-opt/src/velocity.rs

Phase 1 — Port lzr v2 → Rust ✅ (2026-10-14, dans laser-opt/crates/laser-opt/src/lzr2*.rs)

  • Structures : Point, Path (avec is_cycle), PathTraversal (entry + direction)
  • Traversal Solve : glouton, coût v1 exacte (0.9/0.1), multi-entry cycles, bug off-by-one C++ corrigé
  • Eulerian graph + min blanks via lasy (submodule patché : bug faisceau allumé en transit corrigé)
  • Output : Vec<Path> réordonnés + parcours optimal par cycle
  • Path discovery par angle threshold (135°) : split par blank toggle uniquement (suffisant sur les formes test)
  • Tests : 95 tests verts + 6 asserts physiques (budget exact, pureté, timing couleur, blank delay, densité coin, coins nets)

Phase 2 — Velocity planning curvature-aware ✅ (2026-10-15, laser-opt/.../velocity.rs, sans convinterp)

  • Courbure κ par cercle circonscrit de Menger (3 points consécutifs)
  • v_target = min(v_max, √(a_max/κ)) par point (a_max=100, v_max=12 recalibrés)
  • Resampling adaptatif pondéré len/v_worst — densité coin 125/u vs côté 63/u (ratio 2×)
  • Spline lazy degree 7 (convinterp) : conditionné à un spike de port — le cas laser est couvert par le resampling pondéré
  • Tests : asserts densité coin + coins nets sur 5 formes (dont asteroids multi-polylignes)

Phase 3 — Blanking intra-frame + papier Abderyim ✅ (via lasy, 2026-10-14→16)

  • blank_delay_points : 10 pts, run blank min 13 mesuré (≥ 10 OK)
  • radians_per_point : délai angulaire aux coins (κ des bouts de polyligne = κ du premier virage)
  • lasy::blank_segment_points + corner_point_count intégrés (troncature (rad/rpp) as u32 confirmée)
  • Eulerian graph pour min blanks inter-paths (lasy, patché : nœuds blank ancrés au graphe)
  • Tests : asserts 4 (blank delay) + 5 (densité coin) + 6 (coins nets) verts sur 5 formes × 4 pipelines

Phase 4 — API unifiée + intégration laser-dac-rs ✅ (2026-10-15→16)

  • mix::run_mix(shape, Mix, target, params) — 4 pipelines ordre×interp (--mix lasy+native|lasy+velocity|v2+apply_plan|v2+velocity)
  • Sorties DAC : --out-dac none|etherdream|idn (scan broadcast 7654, TCP/UDP, webui :0.0.0.0:8900)
  • Presentation : present_frame quintic + dwells (end 100 µs / start 400 µs), budget réel mesuré
  • Inter-frame blanking courbe C² (le quintic dac couvre le cas)
  • Tests : end-to-end IDN OK (idn-simulator) ; EtherDream attend le DAC réel (P2)

Phase 5 — Polish & production (en cours)

  • Benchs : matrice 5 formes × 4 mix × 3 charges (bench_mix_matrix.json) + PNG (11 rendus)
  • Simulateur galvo + métriques de qualité (port lj_rust, TDD) + fix leak (transit quintic) + bench croisé vs lj_rust (2026-10-17→18)
  • Documentation : laser-opt/DEVBOOK.md (journal complet), laser-opt/SORTIES-TDD.md
  • Profils galvo prédéfinis (CT6210, CT6215, DT40, etc.)
  • P2 : laser réel EtherDream + GalvoSafety en OutputFilter (--safety non désactivable en prod)
  • Publier sur crates.io

Quick start (état réel, testé)

# 0. Récupérer le repo + submodules
git clone --recurse-submodules https://git.interhacker.space/protonphoton/optilaz
cd optilaz

# 1. Lancer la suite complète (95 tests + 6 asserts × formes)
cd laser-opt
cargo test                                    # 119 tests verts, 0 warning

# 2. Le banc : une forme, un pipeline, asserts + PNG
cargo run -p laser-opt-test -- --shape asteroids --mix v2+velocity --png

# 3. Les benchs qualité (simulateur galvo + métriques)
cargo run -p laser-opt --release --example sim_quality_bench   # 4 mix × 5 formes × 3 charges
cargo run -p laser-opt --release --example bench_lj_vs_mix     # bench croisé vs lj_rust
#    formes : colored_square | open_square | square_with_dot | varied_angles | asteroids
#    mixes  : lasy+native | lasy+velocity | v2+apply_plan | v2+velocity (défaut lasy+native)

# 3. La matrice complète (5 formes × 4 mix × 3 charges + presentation)
cargo run -p laser-opt --example mix_full_bench   # → bench_mix_matrix.json

# 4. Envoyer une trame à un DAC
#    IDN : lance le simulateur d'abord
cd ../laser-dac-rs && cargo build -p idn-simulator
DISPLAY=:0 ./target/debug/idn-simulator --port 7255 &
cd ../laser-opt
cargo run -p laser-opt-test -- --out-dac idn --shape colored_square --target 500
#    EtherDream : scan broadcast 7654 automatique
cargo run -p laser-opt-test -- --out-dac etherdream --shape colored_square --target 500

# 5. Webui (panneau DAC, scan, send) : http://0.0.0.0:8900
cargo run -p laser-opt-test -- --web --out-dac idn

# 6. Doc de dev détaillée (journal T0→P2, pièges, résultats)
cat laser-opt/DEVBOOK.md

État des plateformes (Linux tl13 ↔ macOS)

Tout le développement a été fait sur Linux (tl13, X11). Le repo ne contient aucun binaire (sources + docs + JSON + PNG seulement, target/ ignoré) — pas de mélange Linux/macOS possible. Workflow prévu : pull sur macOS (user sammm) puis recompilation complète — voir ci-dessous. Au pull sur macOS :

  • cargo test dans laser-opt/ doit passer tel quel (Rust pur, aucune dépendance plateforme ; petgraph 0.5, pas de FFI)
  • la GUI idn-simulator (submodule laser-dac-rs) : sur macOS le patch winit x11 ne s'applique pas — garder le Cargo.toml d'origine du fork (winit default features, wayland/x11 inutiles sur mac)
  • --out-dac idn / webui : testables sans matériel (simulateur) ; EtherDream attend un DAC réel
  • les PNG/JSON du repo sont des résultats de référence (générés sur Linux) — les régénérer sur mac écrira par-dessus, c'est voulu

Recompilation sur macOS après pull (ordre recommandé)

# 1. Submodules d'abord (les 5, dont lasy)
git clone --recurse-submodules https://git.interhacker.space/protonphoton/optilaz
# (ou si déjà cloné : git submodule update --init --recursive)

# 2. Le cœur : laser-opt (lib + binaire + tests + benchs) — aucune dépendance plateforme
cd laser-opt && cargo test          # 95 tests attendus verts
cargo run -p laser-opt-test -- --shape asteroids --mix v2+velocity --png

# 3. Les benchs qualité (simulateur galvo + métriques)
cargo run -p laser-opt --release --example sim_quality_bench   # 4 mix × 5 formes × 3 charges
cargo run -p laser-opt --release --example bench_lj_vs_mix     # bench croisé vs lj_rust

# 3. Le simulateur IDN (submodule laser-dac-rs) — sur macOS NE PAS appliquer
#    le patch winit x11 (cf. ci-dessous), compiler le Cargo.toml d'origine
cd ../laser-dac-rs && cargo build -p idn-simulator

# 4. OpenIDN-Laser-DAC-Framework (C++) : optionnel, cmake déjà testé sur Linux
# 5. lzr / ConvolutionInterpolations.jl : références, pas nécessaires pour tourner

À ne PAS recopier depuis Linux : target/ (ignoré de toute façon), les Cargo.lock des submodules modifiés localement (laser-dac-rs), et le patch winit x11 (spécifique X11).


Patch connu sur le submodule laser-dac-rs (non poussé au fork)

tools/idn-simulator/Cargo.toml : ajouter winit = { version = "0.30", default-features = false, features = ["x11"] } pour compiler la GUI sans wayland (testé sur tl13/X11).

Patch connu sur le submodule lasy (non poussé au fork nannou)

src/lib.rs : 2 bugs corrigés dans laser-opt (2026-10-16, voir DEVBOOK § asteroids) :

  • points_to_segments : segment blank→lit classé Lit → faisceau ALLUMÉ en transit (ligne parasite entre polylignes disjointes). Fix : une extrémité blank ⇒ segment Blank.
  • segments_to_point_graph : nœuds blank exclus du graphe → points isolés jamais tracés. Fix : nœuds blank ajoutés (sans arête) comme ancrage du pairing eulérien.