- Python 91.1%
- Jupyter Notebook 8.9%
| Fichier | Dernier message de commit | Date du dernier commit |
|---|---|---|
| notebooks | ||
| scripts | ||
| src/calypso | ||
| tests | ||
| .gitignore | ||
| pyproject.toml | ||
| README.md | ||
| requirements.txt | ||
calypso-alignement
Alignement temporel des signaux bracelet (BVP) et de l'ECG (MFF EGI) du protocole ARCHE.
Le problème que ce dépôt résout : l'horodatage absolu enregistré dans les fichiers MFF
est incorrect, avec un décalage qui peut atteindre plusieurs jours, alors que le bracelet
EmbracePlus horodate ses signaux dans un référentiel UTC fiable.
Pour comparer battement à battement le BVP du poignet et l'ECG de référence, il faut
reconstruire l'instant UTC réel du début du MFF. La vidéo de la session sert de pont :
les appuis-bouton du bracelet (tags), visibles à l'image, calent la vidéo sur l'horloge
UTC ; les allumages de la LED de stimulus, visibles à l'image et enregistrés comme
événements dans le MFF, calent le MFF sur la vidéo. Une fois cet instant reconstruit,
deux étages automatiques inventorient puis extraient les portions temporelles communes
aux signaux BVP et ECG, livrées en .npz prêts à l'analyse.
calypso-alignement/
├── src/calypso/
│ ├── config.py racine des données, fréquences, canal ECG
│ ├── io/ lecture bracelet (CSV), tags, MFF, vidéo, helpers T6s
│ ├── alignement/
│ │ ├── video_sync.py matching LED ↔ stimulus, synthèse par sujet
│ │ └── segments.py les deux étages automatiques + AlignedSegment
│ ├── quality/ audit qualité de l'ECG de référence
│ ├── plots/ figures de contrôle de la synchronisation
│ └── utils/i18n.py libellés des figures (fr/en)
├── notebooks/
│ ├── synchronisation_bvp_video_ecg.ipynb LE notebook à copier par sujet
│ └── WORKLIST_T6S.md la carte des sujets : vidéo, canal ECG, cas DJI
├── scripts/ outils T6s : audit ECG, cache, vidéos DJI, extraction
├── tests/run_checks.py vérifications de base
├── requirements.txt
└── pyproject.toml
Installation
Python 3.12 minimum.
git clone https://git.interactions-team.fr/aya.bayna/arche-alignement.git && cd arche-alignement
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pip install -e .
Pour vérifier que tout est en place : python tests/run_checks.py (tout est
synthétique, aucune donnée requise).
Puis ouvrir src/calypso/config.py et régler DATA_ROOT : soit le disque dur du
protocole (/Volumes/ARCHE), soit une racine locale où les données ont été copiées.
DATA_ROOT définit les emplacements par défaut de la cohorte historique et des sorties
locales ; les outils propres à la cohorte T6s recherchent séparément le dossier
Video_ECG parmi les points de montage connus (voir calypso.io.t6s) ; et les
principales fonctions génériques acceptent leurs chemins d'entrée et de sortie en
argument.
Où vivent les données
Le bracelet, un dossier par participant, une sous-arborescence par date :
<racine bracelet>/Patient_<id>/<AAAA-MM-JJ>/
├── CSV_files_<...>_<horodatage>/ un dossier par segment d'enregistrement
│ ├── bvp.csv en-tête : timestampStart (µs UTC), samplingFrequency
│ ├── accelerometer.csv, eda.csv, temperature.csv
├── CSV_merged/tags.csv les appuis-bouton, horodatés en µs UTC
Cette organisation correspond à la cohorte historique. Dans la cohorte T6s, les tags
peuvent être répartis entre plusieurs CSV_files_*/tags.csv à la suite des redémarrages
du bracelet : le notebook les recherche, les fusionne et les dédoublonne automatiquement.
Les MFF : <DATA_ROOT>/EEG_ECG/<id>_*.mff pour la cohorte historique ; pour la cohorte
T6s, Video_ECG/ECG/*.mff et Video_ECG/videos/<n>/ sur le disque, retrouvés
automatiquement par calypso.io.t6s quel que soit le point de montage.
Aligner un nouveau sujet : le notebook
Copier notebooks/synchronisation_bvp_video_ecg.ipynb, le renommer pour le sujet,
régler NUM, puis dérouler. notebooks/WORKLIST_T6S.md donne, sujet par sujet, la vidéo
à prendre, le canal ECG et la marche à suivre des sujets DJI multi-parties. Le notebook
est écrit comme un tutoriel : chaque cellule dit ce qu'elle attend, et les valeurs
affichées sont celles d'un sujet d'exemple, à remplacer. Quatre gestes restent humains,
tout le reste est automatique :
- cliquer le centre de la LED sur l'image affichée (la ROI), puis lancer le scan (long la première fois, mis en cache ensuite) ;
- régler le seuil de détection des allumages sur la courbe affichée ;
- repérer le premier tag visible dans la vidéo (
T_APPROX_S), puis choisir la frame exacte de l'appui dans la grille fine (FRAME_TAG) : la calibration UTC de la vidéo se joue là, à une frame près ; - identifier ce tag : le notebook trace le motif des LED sous chaque hypothèse
(
WHICH_TAG= 1, 2, 3…), et le choix cohérent se règle en configuration.
Les calculs et les exports s'enchaînent ensuite automatiquement (matching LED ↔ stimulus
avec offset auto-estimé, synthèse par sujet ajoutée à
data/processed/alignment/video_alignment_summary.csv), mais l'acceptation de la
synchronisation reste humaine : elle s'appuie sur le nombre de LED appariées
(n_led_matched), la dispersion des écarts (std_delta_s), l'évolution de l'offset et
les figures de diagnostic ; aucune métrique isolée ne suffit à valider un sujet.
Deux confirmations explicites jalonnent le parcours : le calcul final de l'ancre UTC
exige d'avoir confirmé la configuration du sujet (CONFIGURATION_CONFIRMEE), et l'export
refuse de partir tant que VALIDATION_HUMAINE n'a pas été passé à True après examen
des figures ; la synthèse enregistre ce drapeau avec le reste de la configuration.
Cohorte historique : inventaire et extraction génériques
Une fois le summary rempli, tout se fait en deux appels :
from calypso.alignement.segments import build_segments_table, extract_aligned, load_aligned
table = build_segments_table() # inventaire léger : métadonnées seules
segments = extract_aligned(table) # découpe et écrit un .npz par segment
build_segments_table liste les segments bracelet de chaque sujet du summary, calcule
leur recouvrement avec la fenêtre du MFF et produit segments_table.csv (statuts
aligne_total / aligne_partiel / hors_experience). extract_aligned charge alors
BVP, ECG et, quand ils existent, ACC/EDA/TEMP, découpe la fenêtre commune et écrit un
AlignedSegment par segment sous data/processed/aligned/<sujet>/<segment>.npz. Chaque
signal reste à sa fréquence native. load_aligned relit un .npz en AlignedSegment,
avec les axes de temps en propriétés (seg.t_bvp, seg.t_ecg).
La couche de lecture prend en charge les MFF des deux cohortes : lecture MNE pour les
MFF avec EEG, repli automatique sur mffpy pour les MFF « PNS-only » (ECG seul, cohorte
T6s), où le canal ECG se choisit par indice (canal_pns, 0 par défaut).
Cohorte T6s : préparation et extraction
Pour T6s, l'ECG est d'abord mis en cache et audité, une fois pour toute la cohorte (disque branché) :
python scripts/cache_t6s_from_disk.py
python scripts/audit_ecg_t6s_raw.py
Après la synchronisation LED d'un sujet, lancer :
python scripts/extract_aligned_t6s.py
Ce script lit l'ECG depuis le cache local, sélectionne le canal retenu par l'audit
qualité pour chaque sujet, et écrit les segments sous data/processed/aligned_t6s/,
que l'audit de cohorte relit via son paramètre aligned_dir.
Cas particuliers T6s : les scripts
scripts/audit_ecg_t6s_raw.py: audite l'ECG brut de chaque sujet avant tout alignement, afin d'identifier en amont les ECG inexploitables ; produit le tableau qualité dont l'extraction se sert pour choisir le canal par sujet.scripts/cache_t6s_from_disk.py: constitue un cache local autonome de l'ECG de chaque sujet (les 2 canaux, la fréquence, les événements) pour travailler sans le disque dur branché.scripts/led_scan_multi.py: la caméra DJI coupe ses fichiers tous les ~4 Go ; ce script scanne chaque partie et recolle les séries temporelles du scan LED, sans concaténer les vidéos.scripts/merge_dji_t6s.py: l'alternative quand on préfère fusionner les parties en un fichier local (concat sans réencodage), avec--checket--clean.scripts/extract_aligned_t6s.py: l'étage d'extraction adapté à la cohorte T6s (cache ECG local, canal par sujet issu de l'audit qualité).
Contrôler la qualité
calypso.quality note l'ECG de référence fenêtre par fenêtre (l'étiquette n'est fiable
que si la référence l'est) : assess_ecg_cohort parcourt les .npz alignés (paramètre
aligned_dir pour pointer aligned/ ou aligned_t6s/). calypso.plots.sync_plots
trace les figures de contrôle de la synchronisation (paires LED↔stimulus, dérive,
résidus).
Provenance
Pipeline conçu et développé dans le cadre du projet CALYPSO (2026) pour l'équipe INTERACTIONS. Les données du protocole ARCHE restent sur leurs supports internes : ce dépôt contient le code seul.