# 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) │ └─────────────────────────────────────────────────────────┘ ``` ## Demarrage rapide ```bash # 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 docker compose up detect ``` ## Configuration Variables d'environnement (dans `docker-compose.yml`) : | 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 (secondes) | | `REPORT_HOUR` | `0` | Heure du rapport quotidien | | `MIN_LIVE_TIME` | `3600` | Live time minimum pour un rapport (secondes) | | `VEGA_DEVICE` | `cpu` | Device PyTorch (`cpu` ou `cuda`) | ## 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 + ReLU + 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 * MSE (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 dans les donnees synthetiques** : K-40, radon (Pb-214, Bi-214), thorium (Ac-228, Pb-212, Tl-208) simules avec des activites aleatoires realistes ### 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 exponentiel + pics de K-40, radon, thorium avec activites aleatoires 5. **Efficacite du detecteur** : modele phenomenologique qui decroit avec l'energie (absorption basse energie + penetration haute 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 : ```python 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 (K-40, radon, thorium) pendant l'entrainement - La soustraction reelle elimine les variations locales du background (emplacement, altitude, materiaux) - 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) ## Capture du bruit de fond Avant la detection, capturer le background pendant 24h sans source radioactive a proximite : ```bash docker compose run --rm -d --name radiacode-bg \ -e TARGET_DURATION=86400 -e SAMPLE_INTERVAL=60 \ detect python capture_background.py ``` Suivre la progression : ```bash docker logs -f radiacode-bg cat data/background_snapshot.json ``` ## Structure du projet ``` radiacode_103/ ├── docker-compose.yml # Orchestration des conteneurs ├── TOTO.md # Suivi des taches ├── README.md ├── train/ │ ├── Dockerfile # PyTorch 2.7.0 + CUDA 12.8 (Blackwell) │ ├── requirements.txt │ ├── entrypoint.sh # Generation + entrainement │ └── vega_ml/ # Code VegaModel (copie d'Open-RadiaCode-Android) │ ├── synthetic_spectra/ # Generateur de spectres synthetiques │ ├── training/vega/ # Modele, dataset, trainer │ └── 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 ├── 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)