- Remplace le continuum exponentiel par un modèle réaliste CsI(Tl) dans l'entraînement (bosse asymétrique ~110 keV + queue Compton) - Ajoute l'injection de background mesuré (70% mesuré / 30% synthétique) via --measured_background et MEASURED_BACKGROUND_PATH - Ajoute l'endpoint /api/background/continuum et le toggle "Continuum CsI" sur le dashboard background - Exclut le canal 1023 (overflow bin) de l'affichage web (NUM_CHANNELS=1023) - Corrige le lissage Gaussien du background (normalisation locale aux bords) - Met à jour README.md, CLAUDE.md, TUTORIEL.md, TOTO.md, vega_ml/README.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
16 KiB
Tutoriel : Radiacode 103 — Du debut a la detection d'isotopes
Ce tutoriel explique chaque etape du pipeline, pourquoi les durees sont ce qu'elles sont, et comment interpreter les resultats.
1. Pre-requis materiels
| Element | Detail |
|---|---|
| Radiacode 103 | Spectrometre gamma CsI(Tl), 1024 canaux, USB |
| Machine GPU | NVIDIA avec drivers + nvidia-container-toolkit |
| Docker | Version 20.10+ avec Docker Compose V2 (docker compose) |
| Cable USB | Pour connecter le Radiacode a la machine |
Verifier que le Radiacode est bien detecte :
lsusb | grep -i radiacode
# Doit afficher : ID 0483:f123 RadiaCode RadiaCode-103
Verifier le GPU :
nvidia-smi
# Doit afficher votre carte NVIDIA
2. Builder les images Docker (~5 min)
docker compose build
Deux images sont construites :
radiacode_103-train: PyTorch 2.7.0 + CUDA 12.8 (pour l'entrainement sur GPU)radiacode_103-detect: Python 3.11 + radiacode + PyTorch CPU (pour la detection)
Pourquoi PyTorch 2.7.0 ? Les cartes RTX 50-series (Blackwell, compute capability sm_120) ne sont pas supportees par PyTorch < 2.7. Si vous avez une carte plus ancienne (RTX 30/40-series), PyTorch 2.4.0 suffit.
3. Entrainer le modele (~45 min sur RTX 5060 Ti)
docker compose run --rm train
Cette commande lance deux phases automatiquement :
Phase 1 : Generation des spectres synthetiques (~10 min)
Le generateur cree 50 000 spectres 1D simulant la physique reelle :
| Type | Nombre | Description |
|---|---|---|
| Mono-isotope | 20 000 | Un seul isotope + background |
| Bi-isotope | 15 000 | Deux isotopes + background |
| Multi-isotope | 10 000 | 3-5 isotopes + background |
| Background seul | 5 000 | Background environnemental uniquement |
Pourquoi des durees de 12-24h ?
Les spectres synthetiques simulent des acquisitions de 12 a 24 heures (43200-86400 secondes). C'est volontaire :
-
Bruit Poissonnien : La statistique de comptage suit une loi de Poisson. Pour un canal avec N comptages, l'ecart-type est sqrt(N). Le rapport signal/bruit s'ameliore en sqrt(N), donc en sqrt(duree).
- A 6.5 CPS/canal moyen et 1024 canaux, apres 1h on a ~23 comptages/canal (SNR ~5)
- Apres 24h on a ~560 comptages/canal (SNR ~23)
- Apres 1 semaine ~3900 comptages/canal (SNR ~63)
-
Conditions reelles : Le detecteur sera utilise en continu pendant des jours. Le modele doit voir des spectres avec le meme niveau de bruit que les mesures reelles.
-
Sensibilite : Les isotopes a faible activite (1-5 Bq) ne sont detectables qu'apres plusieurs heures d'accumulation. Le modele doit apprendre cette relation.
Ce que le generateur simule physiquement :
- Pics photoelectriques : Gaussiennes dont la largeur (FWHM) depend de l'energie. Pour le CsI(Tl) du Radiacode 103, FWHM = 8.4% a 662 keV, avec la relation FWHM(E) = FWHM_662 * sqrt(E/662).
- Continuum Compton : Distribution de Klein-Nishina simplifiee sous chaque pic, simulant la diffusion des photons gamma.
- Bruit Poissonnien : Chaque canal est echantillonne depuis une loi Poisson(lambda), ce qui reproduit exactement les fluctuations statistiques reelles.
- Background environnemental : Continuum CsI(Tl) realiste (bosse asymetrique a ~110 keV + queue Compton exponentielle) + pics de 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 des activites aleatoires realistes.
- Efficacite du detecteur : Modele phenomenologique tenant compte de l'absorption basse energie et de la penetration haute energie du scintillateur CsI(Tl) de 1 cm3.
Entrainement hybride (optionnel mais recommande) :
Si vous avez capture un fichier background_24h.npy, le generateur peut l'utiliser pour rendre les spectres synthetiques plus realistes. Le background mesure est melange a 70% avec le modele synthetique (30%), et les pics isotopiques sont ajoutes avec variation aleatoire par-dessus.
# Avec background mesure (recommande si disponible)
docker compose run --rm train
# Le fichier /data/background_24h.npy est automatiquement utilise
# grace a MEASURED_BACKGROUND_PATH dans docker-compose.yml
Phase 2 : Entrainement du VegaModel (~35 min sur RTX 5060 Ti)
Le modele VegaModel est un CNN-FCNN multi-tache :
Entree : spectre 1D (1023 canaux, 20-3000 keV)
|
|-- Bloc CNN 1 : Conv1d(1, 64, 7) -> BN -> LeakyReLU -> MaxPool
|-- Bloc CNN 2 : Conv1d(64, 128, 5) -> BN -> LeakyReLU -> MaxPool
|-- Bloc CNN 3 : Conv1d(128, 256, 3) -> BN -> LeakyReLU -> MaxPool
|
|-- Tete classification : FC(256->512->256->82) -> Sigmoid
| 82 isotopes, probabilite de presence [0, 1]
|
+-- Tete regression : FC(256->512->256->82)
Activite estimee en Bq pour chaque isotope
- 34 493 156 parametres au total
- Fonction de perte : BCE (classification) + Huber ponderee (regression sur isotopes presents uniquement)
- Mixed precision (AMP) : Acceleration sur GPU via float16
- Early stopping : Patience de 10 epochs sans amelioration
Resultats typiques :
| Metrique | Valeur |
|---|---|
| Val accuracy | 99.89% |
| AUC macro | 0.995 |
| Precision | 99.8% |
| Recall | 95.6% |
| Exact match | 93.5% |
| Best val loss | 0.0051 |
Fichiers generes dans models/ :
| Fichier | Taille | Description |
|---|---|---|
vega_best.pt |
395 Mo | Meilleur modele (checkpoint avec val loss minimale) |
vega_final.pt |
395 Mo | Modele final (epoch 100) |
vega_isotope_index.txt |
546 o | Liste des 82 isotopes detectables |
vega_history.json |
75 Ko | Metriques d'entrainement par epoch |
Note
: Seul
vega_best.ptetvega_isotope_index.txtsont necessaires pour la detection. Les checkpoints par epoch (vega_epoch_*.pt) peuvent etre supprimes pour gagner ~39 Go.
4. Capturer le bruit de fond (24h)
Cette etape est critique et ne doit pas etre ignoree. Placez le detecteur dans un endroit sans source radioactive connue.
docker compose run --rm -d --name radiacode-bg \
-e TARGET_DURATION=86400 -e SAMPLE_INTERVAL=60 \
detect python capture_background.py
Pourquoi 24h ?
Le background environnemental n'est pas constant. Il varie selon :
- Le radon : Concentration dans l'air qui varie avec la ventilation, la meteo, l'heure du jour (cycle diurne)
- Le thorium : Present dans les materiaux de construction (beton, brique), relativement stable mais varie lentement
- Le potassium-40 : Partout dans la nature (aliments, corps humain), assez stable
- Les rayons cosmiques : Varient avec l'altitude et l'activite solaire
Un echantillonnage de 24h capture un cycle complet de ces variations, donnant un background de reference representative.
Pourquoi pas moins ?
| Duree | CPS/canal | SNR/canal | Pics visibles |
|---|---|---|---|
| 1h | ~23 | ~5 | Aucun pic clair |
| 4h | ~94 | ~10 | K-40 commence a emerger |
| 12h | ~280 | ~17 | K-40, Bi-214 visibles |
| 24h | ~560 | ~24 | Tous les pics de background nets |
| 48h | ~1120 | ~33 | Pics tres nets, variations capturees |
A 24h, les principaux pics du background sont clairement identifiables :
- K-40 a 1460 keV : Toujours present (~5-15 Bq dans l'environnement)
- Bi-214 a 609 keV : Fille du radon
- Pb-214 a 295 et 352 keV : Fille du radon
- Tl-208 a 2614 keV : Fille du thorium
Suivre la progression
# Voir les logs
docker logs -f radiacode-bg
# Lire le snapshot JSON
cat data/background_snapshot.json | python3 -m json.tool | head -20
Le snapshot montre en temps reel les pics detectes, le CPS moyen et la duree ecoulee.
Le script gere les deconnexions
Si le Radiacode est debranche pendant la capture, le script se reconnecte automatiquement et reprend l'accumulation. Les donnees deja collectees ne sont pas perdues.
A la fin (24h plus tard)
Le fichier data/background_24h.npy est genere avec :
{
"counts": np.array, # 1024 canaux, comptages cumules
"duration": float, # live time en secondes
"timestamp": float # timestamp Unix
}
5. Lancer la detection continue + dashboard
docker compose up detect web
Le dashboard est accessible sur http://localhost:8080 avec quatre onglets :
- Spectre : Spectre cumule en temps reel, soustraction du background, lignes d'energie des isotopes detectes
- Background : Spectre du bruit de fond (live et 24h), modele theorique CsI(Tl), pics detectes
- CPS : Evolution du comptage par seconde dans le temps (1h a 30 jours)
- Historique : Liste des rapports quotidiens avec isotopes detectes
Comment ca marche
Toutes les 60 secondes, le moniteur :
1. Echantillonnage
Radiacode.spectrum() -> 1024 canaux + duree
cumulated_counts += counts
cumulated_live_time += duration.total_seconds()
Radiacode.spectrum_reset()
2. A 00h00 chaque jour : Rapport
Si live_time > 1h :
rate = cumulated_counts / cumulated_live_time
bg_rate = bg_counts / bg_live_time
net_rate = clip(rate - bg_rate, 0, None)
normalized = net_rate / net_rate.max()
logits, activities = model(normalized)
probs = sigmoid(logits)
Pour chaque isotope avec prob > 0.5 :
rapport[name, prob%, activite_bq]
Sauvegarder dans logs/report_YYYY-MM-DD.json
Reset cumulateurs
3. Si detecteur debranche :
Attendre 60s, retenter la connexion
Les donnees cumulees sont conservees
Pourquoi soustraire le background ?
Le modele est entraite avec du background synthetique realiste (continuum CsI(Tl) + pics environnementaux), mais le background reel varie selon l'emplacement. La soustraction reelle ameliore la detection :
- Sans soustraction : Le modele voit K-40 a 1460 keV et peut le signaler comme isotope detecte, meme si c'est juste du background
- Avec soustraction : Le pic de K-40 du background est elimine, seul un signal supplementaire est analyse
- Resultat : Moins de faux positifs, meilleure sensibilite pour les isotopes faibles
6. Interpreter les rapports
Chaque jour a REPORT_HOUR (00h00 par defaut), un rapport JSON est genere dans logs/ :
{
"date": "2026-05-20T00:00:00",
"live_time_hours": 18.5,
"total_counts": 434500,
"cps_mean": 6.52,
"background_subtracted": true,
"isotopes_detected": [
{
"isotope": "Cs-137",
"probability": 0.97,
"activity_bq": 12.3
},
{
"isotope": "K-40",
"probability": 0.85,
"activity_bq": 8.1
}
]
}
Champs du rapport
| Champ | Description |
|---|---|
live_time_hours |
Temps effectif d'acquisition (sans les trous de deconnexion) |
total_counts |
Nombre total de coups cumules |
cps_mean |
Comptage par seconde moyen |
background_subtracted |
true si le background a ete soustrait |
isotopes_detected |
Liste des isotopes avec probabilite > seuil (0.5 par defaut) |
Interpretation des resultats
- Probabilite > 95% : Detection certaine, l'isotope est present
- Probabilite 70-95% : Detection probable, a confirmer avec plus de donnees
- Probabilite 50-70% : Detection incertaine, probablement du bruit ou une confusion spectrale
- Probabilite < 50% : Non detecte (en dessous du seuil)
Isotopes de background frequents (normaux, pas une alerte) :
- K-40 : Toujours present dans l'environnement (~5-15 Bq)
- Bi-214 / Pb-214 : Filles du radon, varient selon la ventilation
- Ac-228 / Pb-212 / Tl-208 : Chaine du thorium, presents dans les materiaux de construction
Isotopes d'interet (a surveiller) :
- Cs-137 : Marqueur de contamination (accident nucleaire, sources industrielles)
- Co-60 : Source medicale/industrielle
- I-131 : Marqueur medical (scintigraphie thyroidienne)
- Am-241 : Source de calibration, detecteurs de fumee
- Ir-192 : Source industrielle (radiographie gamma)
7. Tester avec une source connue
Si vous avez une source radioactive connue (par ex. Cs-137) :
- Placez la source pres du detecteur
- Lancez le moniteur
- Attendez au moins 1 heure d'acquisition (MIN_LIVE_TIME=3600)
- Forcez un rapport manuel :
docker compose exec detect python -c "
from radiacode_monitor import RadiacodeMonitor
m = RadiacodeMonitor()
m.generate_report()
"
Pour un Cs-137 (662 keV, ~10 uSv/h a 10 cm), le resultat attendu est :
- Cs-137 detecte avec probabilite > 90%
- Activite estimee approximative (la calibration exacte necessite un etalonnage)
8. Nettoyer les checkpoints (~39 Go a recuperer)
Apres l'entrainement, seuls vega_best.pt et vega_isotope_index.txt sont necessaires :
# Supprimer les checkpoints intermediaires
rm models/vega_epoch_*.pt models/vega_final.pt
# Verifier
ls -lh models/
# vega_best.pt vega_history.json vega_isotope_index.txt
9. Transfer vers Raspberry Pi 4 (production)
Quand le pipeline fonctionne sur la machine GPU :
-
Copier les fichiers du modele :
scp models/vega_best.pt models/vega_isotope_index.txt pi@raspberrypi:~/radiacode_103/models/ -
Capturer le background sur le Pi (emplacement final) :
docker compose run --rm -d --name radiacode-bg \ -e TARGET_DURATION=86400 -e SAMPLE_INTERVAL=60 \ detect python capture_background.py -
Adapter
docker-compose.ymlsur le Pi :- Retirer
deploy.resources.reservations.devices(pas de GPU) - Mettre
VEGA_DEVICE=cpu - Le detect/Dockerfile fonctionne sur ARM64 (PyTorch a des wheels ARM)
- Retirer
-
Lancer :
docker compose up detect
L'inference CPU sur Pi 4 prend environ 0.5-1 seconde par spectre, ce qui est suffisant pour un rapport quotidien.
10. Variables d'environnement de reference
Entrainement (docker-compose.yml - 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 secondes) |
MAX_DURATION |
86400 |
Duree max des spectres (24h en secondes) |
NVIDIA_VISIBLE_DEVICES |
1 |
GPU a utiliser (0 ou 1) |
CUDA_VISIBLE_DEVICES |
1 |
GPU visible par CUDA |
MEASURED_BACKGROUND_PATH |
/data/background_24h.npy |
Background mesure pour entrainement hybride |
Detection (docker-compose.yml - service detect)
| Variable | Defaut | Description |
|---|---|---|
MODEL_PATH |
/models/vega_best.pt |
Chemin du modele |
ISOTOPE_INDEX_PATH |
/models/vega_isotope_index.txt |
Index des isotopes |
BACKGROUND_PATH |
/data/background_24h.npy |
Fichier background |
VEGA_DEVICE |
cpu |
Device PyTorch |
THRESHOLD |
0.5 |
Seuil de probabilite |
SAMPLE_INTERVAL |
60 |
Intervalle d'echantillonnage (s) |
REPORT_HOUR |
0 |
Heure du rapport quotidien |
MIN_LIVE_TIME |
3600 |
Live time min pour rapport (s) |
Dashboard (docker-compose.yml - service web)
| Variable | Defaut | Description |
|---|---|---|
ENERGY_CALIBRATION_OFFSET |
0.33 |
Calibration energetique offset (keV) |
ENERGY_CALIBRATION_SLOPE |
2.97 |
Calibration energetique pente (keV/canal) |
Capture de background
| Variable | Defaut | Description |
|---|---|---|
TARGET_DURATION |
86400 |
Duree de capture (24h en secondes) |
SAMPLE_INTERVAL |
60 |
Intervalle entre echantillons (s) |
BACKGROUND_PATH |
/data/background_24h.npy |
Fichier de sortie |