Jacquin Antoine c764a5c264 Dash web: crosshair, zoom/pan X, scale log/lin, continuum extraction, background resume
- Tooltip entier (intersect:false) + ligne verticale crosshair sur tous les graphes
- Zoom molette/pinch sur l'axe X, pan souris, limites clamped 30-3000 keV
- Toggle échelle log/linéaire onglet Background
- Extraction continuum détecteur (isotope peaks subtracted + Gaussian smoothing)
- Reprise snapshot précédent au démarrage capture_background.py
- Suppression refs "Théorique" et "Bruit capteur" de l'interface
- Plugin chartjs-plugin-zoom + hammerjs via CDN
- Fix Chart constructor spread operator

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-19 23:26:28 +02:00
2026-05-19 13:33:07 +02:00
2026-05-19 13:33:07 +02:00

Radiacode 103 — Identification automatique d'isotopes

Pipeline Docker complet pour la capture, l'analyse et l'identification automatique d'isotopes radioactifs avec un spectrometre gamma Radiacode 103.

Architecture

Radiacode 103 (USB)
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  Conteneur detect (Python 3.11 + PyTorch CPU)          │
│                                                         │
│  capture_background.py  ──>  background_24h.npy (24h)   │
│  radiacode_monitor.py   ──>  rapport JSON quotidien      │
│         │                                               │
│         ├── Echantillonnage chaque 60s                  │
│         ├── Soustraction du background                  │
│         ├── Inference VegaModel (34.5M params, 82 iso)  │
│         └── Rapport quotidien a 00h00                   │
│                                                         │
│  Modele: vega_best.pt (entraite sur RTX 5060 Ti)       │
└─────────────────────────────────────────────────────────┘
        │
        ▼
┌─────────────────────────────────────────────────────────┐
│  Conteneur web (FastAPI + Chart.js)                     │
│                                                         │
│  Dashboard :8080 — Spectre en temps reel,               │
│  background, CPS, historique, isotopes detectes          │
└─────────────────────────────────────────────────────────┘

Demarrage rapide

# 1. Builder les images
docker compose build

# 2. Lancer l'entrainement (GPU, ~45 min)
docker compose run --rm train

# 3. Capturer le bruit de fond (24h, sans source radioactive)
docker compose run --rm -d --name radiacode-bg detect python capture_background.py

# 4. Lancer la detection continue + dashboard
docker compose up detect web

Configuration

Variables d'environnement (dans docker-compose.yml) :

Entrainement (service train)

Variable Defaut Description
NUM_SAMPLES 50000 Nombre de spectres synthetiques
EPOCHS 100 Epochs max d'entrainement
BATCH_SIZE 64 Taille de batch
LEARNING_RATE 0.001 Taux d'apprentissage initial
DETECTOR radiacode_103 Config du detecteur
MIN_DURATION 43200 Duree min des spectres (12h en s)
MAX_DURATION 86400 Duree max des spectres (24h en s)
SEED 42 Graine aleatoire
MEASURED_BACKGROUND_PATH /data/background_24h.npy Background mesure pour entrainement hybride

Detection (service detect)

Variable Defaut Description
MODEL_PATH /models/vega_best.pt Chemin du modele PyTorch
ISOTOPE_INDEX_PATH /models/vega_isotope_index.txt Index des 82 isotopes
BACKGROUND_PATH /data/background_24h.npy Fichier background de reference
THRESHOLD 0.5 Seuil de probabilite pour la detection
SAMPLE_INTERVAL 60 Intervalle d'echantillonnage (s)
REPORT_HOUR 0 Heure du rapport quotidien
MIN_LIVE_TIME 3600 Live time minimum pour un rapport (s)
VEGA_DEVICE cpu Device PyTorch (cpu ou cuda)

Dashboard (service web)

Variable Defaut Description
ENERGY_CALIBRATION_OFFSET 0.33 Calibration energetique (offset keV)
ENERGY_CALIBRATION_SLOPE 2.97 Calibration energetique (pente keV/canal)

Bruit Poissonnien et modele

Physique du bruit

La detection gamma est un processus de comptage intrinsequement stochastique. Chaque canal du spectre suit une loi de Poisson : si un canal accumule en moyenne N comptages, l'ecart-type est sqrt(N). Le rapport signal/bruit s'ameliore donc en sqrt(N) :

  • 6.5 CPS de background sur 1024 canaux -> ~0.006 CPS/canal
  • Apres 1h : ~22 comptages/canal, ecart-type ~4.7, SNR ~5
  • Apres 24h : ~560 comptages/canal, ecart-type ~24, SNR ~23
  • Apres 1 semaine : ~3900 comptages/canal, ecart-type ~62, SNR ~63

C'est pourquoi la capture de background dure 24h : en dessous, les pics du background (K-40 a 1460 keV, Bi-214 a 609 keV, Pb-214 a 352 keV) sont noyes dans le bruit Poissonnien.

Modele VegaModel

Le VegaModel est un CNN-FCNN multi-tache inspire de l'architecture Vega d'Open-RadiaCode-Android :

  • Entree : spectre 1D de 1023 canaux (20-3000 keV), normalise par max
  • Sortie : deux tetes
    • Classification : 82 neurones avec sigmoid (presence/absence de chaque isotope)
    • Regression : 82 neurones (activite estimee en Bq, normalisee a max_activity_bq=1000)
  • Architecture :
    • 3 blocs CNN (64, 128, 256 canaux) avec BatchNorm + LeakyReLU + MaxPool
    • 2 couches FC (512, 256) avec Dropout(0.3)
    • 34 493 156 parametres au total
  • Fonction de perte : VegaLoss = classification_weight * BCE + regression_weight * Huber (ponderee pour ne penaliser l'activite que sur les isotopes presents)
  • Entrainement : 50 000 spectres synthetiques, 100 epochs, AMP (mixed precision), early stopping (patience=10)

Background d'entrainement

Le background synthetique utilise un modele realiste calibre sur les mesures du Radiacode 103 :

  • Continuum CsI(Tl) : Bosse asymetrique a ~110 keV (sigma_gauche=55 keV, sigma_droite=50 keV) + queue Compton exponentielle (0.45exp(-E/240) + 0.04exp(-E/700)) + plancher de bruit. Ce modele remplace l'ancien continuum exponentiel qui ne reproduisait pas la forme reelle du spectre CsI(Tl).
  • Pics environnementaux : K-40 (1460 keV), Pb-214 (295, 352 keV), Bi-214 (609, 1120, 1764 keV), Ac-228 (911 keV), Pb-212 (239 keV), Tl-208 (583, 2614 keV), avec activites aleatoires realistes
  • Entrainement hybride : Si le fichier background_24h.npy est disponible, 70% du background est issu de la mesure reelle (mélange 70% mesuré / 30% synthétique) et 30% du modele synthetique, avec variation stochastique des pics par-dessus. Ceci ameliore la robustesse du modele face aux variations locales du background.

Spectres synthetiques

Les donnees d'entrainement simulent la physique complete :

  1. Pics photoelectriques : Gaussiennes avec FWHM dependant de l'energie (8.4% a 662 keV pour le CsI(Tl))
  2. Continuum Compton : distribution de Klein-Nishina simplifiee sous chaque pic
  3. Bruit Poissonnien : echantillonnage Poisson(N) pour chaque canal, simulant les fluctuations de comptage reelles
  4. Background environnemental : Continuum CsI(Tl) realiste + pics de K-40, radon, thorium avec activites aleatoires
  5. Efficacite du detecteur : modele phenomenologique qui decroit avec l'energie
  6. Durees de 12-24h : suffisamment longues pour que le rapport signal/bruit soit comparable aux mesures reelles

Soustraction du background a l'inference

Le modele est entraine avec du background synthetique inclus, mais a l'inference on soustrait le vrai background mesure :

rate = cumulated_counts / cumulated_live_time       # spectre brut en CPS
bg_rate = bg_counts / bg_live_time                  # background de reference en CPS
net_rate = np.clip(rate - bg_rate, 0, None)         # spectre net (background soustrait)
normalized = net_rate / net_rate.max()               # normalisation pour le modele

Cette approche hybride est optimale :

  • Le modele apprend a ignorer les pics du background pendant l'entrainement
  • La soustraction reelle elimine les variations locales du background
  • Resultat : meilleure sensibilite et moins de faux positifs

Le conteneur train execute deux phases :

  1. Generation des spectres synthetiques : 50 000 spectres 1D (20k mono-isotope, 15k bi-isotope, 10k multi-isotope, 5k background seul) avec des durees de 12-24h
  2. Entrainement VegaModel : CNN-FCNN multi-tache, 82 isotopes, 34.5M parametres

Resultats de l'entrainement sur RTX 5060 Ti :

  • Val accuracy : 99.89%
  • AUC macro : 0.995
  • Best val loss : 0.0051
  • Duree : ~45 min (100 epochs, 25s/epoch)

Detection

Le moniteur radiacode_monitor.py :

  • Echantillonne le spectre toutes les 60 secondes
  • Cumule les comptages et le live time
  • Soustrait le background de reference (si disponible)
  • Execute l'inference VegaModel sur le spectre net
  • Genere un rapport JSON quotidien a REPORT_HOUR

Le rapport contient :

  • Live time et comptages totaux
  • CPS moyen
  • Isotopes detectes avec probabilite et activite estimee (Bq)

Dashboard web

Le conteneur web expose un dashboard sur le port 8080 avec :

  • Onglet Spectre : Spectre cumule en temps reel (lineaire ou log), soustraction du background, lignes d'energie des isotopes detectes, overlay du background de reference
  • Onglet Background : Spectre du bruit de fond (live et 24h), modele theorique CsI(Tl), pics detectes, statistiques (duree, CPS, comptages)
  • Onglet CPS : Evolution du comptage par seconde dans le temps, de 1h a 30 jours
  • Onglet Historique : Liste des rapports quotidiens avec isotopes detectes

Points techniques du dashboard

  • Le canal 1024 (bin de debordement) est exclu de l'affichage — seuls les 1023 premiers canaux sont utilises (20-3036 keV)
  • Le lissage du spectre (Gaussienne sigma=8 canaux) utilise une normalisation locale aux bords pour eviter les artefacts

Capture du bruit de fond

Avant la detection, capturer le background pendant 24h sans source radioactive a proximite :

docker compose run --rm -d --name radiacode-bg \
  -e TARGET_DURATION=86400 -e SAMPLE_INTERVAL=60 \
  detect python capture_background.py

Suivre la progression :

docker logs -f radiacode-bg
cat data/background_snapshot.json

Structure du projet

radiacode_103/
├── docker-compose.yml          # Orchestration des conteneurs
├── CLAUDE.md                   # Guide pour Claude Code
├── TUTORIEL.md                 # Tutoriel detaille
├── TOTO.md                     # Suivi des taches
├── README.md
├── train/
│   ├── Dockerfile              # PyTorch 2.7.0 + CUDA 12.8 (Blackwell)
│   ├── entrypoint.sh           # Generation + entrainement
│   ├── requirements.txt
│   └── vega_ml/                # Code VegaModel
│       ├── synthetic_spectra/  # Generateur de spectres synthetiques
│       │   ├── config.py       # Configurations detecteur (Radiacode 101-110)
│       │   ├── generator.py    # Generateur principal (SpectrumConfig)
│       │   ├── physics/
│       │   │   └── spectrum_physics.py  # Physique + background realiste CsI(Tl)
│       │   └── ground_truth/   # Base de donnees 82 isotopes
│       ├── training/vega/      # Modele, dataset, trainer
│       └── inference/         # Inference
├── detect/
│   ├── Dockerfile              # Python 3.11-slim + radiacode + torch CPU
│   ├── requirements.txt
│   ├── radiacode_monitor.py    # Moniteur principal
│   └── capture_background.py   # Capture du bruit de fond 24h
├── web/
│   ├── Dockerfile              # Python 3.11-slim + FastAPI
│   ├── requirements.txt
│   ├── app/
│   │   ├── main.py             # FastAPI app + routes
│   │   ├── config.py           # Config (canaux, calibration energetique)
│   │   ├── routers/
│   │   │   ├── status.py       # /api/status
│   │   │   ├── spectrum.py     # /api/spectrum/current, /api/spectrum/difference
│   │   │   ├── background.py   # /api/background/*, background theorique
│   │   │   ├── cps.py          # /api/cps/timeline
│   │   │   └── history.py      # /api/history, /api/history/{date}
│   │   └── theoretical_bg.py   # Modele theorique CsI(Tl) pour le dashboard
│   └── static/
│       ├── index.html          # Dashboard SPA
│       ├── css/style.css
│       └── js/                 # app.js, spectrum.js, background.js, cps.js, history.js
├── data/
│   ├── synthetic/spectra/      # 50 000 spectres synthetiques (~4.2 Go)
│   └── background_snapshot.json
├── models/
│   ├── vega_best.pt            # Meilleur modele (395 Mo)
│   ├── vega_final.pt           # Modele final
│   ├── vega_history.json       # Metriques d'entrainement
│   └── vega_isotope_index.txt  # 82 isotopes
└── logs/                        # Rapports quotidiens JSON

Materiel

Composant Modele
Spectrometre Radiacode 103 (CsI(Tl), 1024 canaux, FWHM 8.4% @662 keV)
GPU entrainement NVIDIA RTX 5060 Ti 16 Go (Blackwell, sm_120)
GPU secondaire NVIDIA RTX 4060 Ti 16 Go (Ada Lovelace)
Production (futur) Raspberry Pi 4 8 Go

82 isotopes detectables

Ac-227, Ac-228, Ag-110m, Am-241, Au-198, Ba-133, Ba-137m, Be-7, Bi-210, Bi-211, Bi-212, Bi-214, C-14, Cd-109, Ce-139, Ce-144, Co-57, Co-58, Co-60, Cr-51, Cs-134, Cs-137, Eu-152, Eu-154, F-18, Fe-59, Ga-67, Hf-181, Hg-203, I-123, I-129, I-131, In-111, Ir-192, K-40, Lu-177, Mn-54, Na-22, Pa-231, Pa-234m, Pb-210, Pb-211, Pb-212, Pb-214, Po-210, Po-212, Po-214, Po-216, Po-218, Pr-144, Ra-223, Ra-224, Ra-226, Ra-228, Rh-106, Rn-220, Rn-222, Ru-106, Sb-125, Sc-46, Se-75, Sm-153, Sn-113, Sr-85, Sr-90, Ta-182, Tc-99m, Th-228, Th-230, Th-231, Th-232, Th-234, Tl-201, Tl-207, Tl-208, U-234, U-235, U-238, Xe-133, Y-88, Y-90, Zn-65

Passage en production (Raspberry Pi 4)

  1. Copier models/vega_best.pt et models/vega_isotope_index.txt sur le Pi 4
  2. Capturer le background sur le Pi 4 (emplacement final)
  3. Le meme detect/Dockerfile fonctionne sur ARM64
  4. Adapter docker-compose.yml : retirer deploy.resources.reservations.devices
  5. VEGA_DEVICE=cpu (inference CPU sur Pi 4, ~1s par spectre)
Description
No description provided
Readme 440 MiB
Languages
Python 89.5%
JavaScript 7.4%
CSS 1%
HTML 1%
PowerShell 0.5%
Other 0.6%