Aucune description
  • Python 91.1%
  • Jupyter Notebook 8.9%
Aller au fichier
Fichiers du dépôt (dernière modification en premier)
Fichier Dernier message de commit Date du dernier commit
2026-08-29 20:17:33 +02:00
notebooks Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
scripts Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
src/calypso Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
tests Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
.gitignore Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
pyproject.toml Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
README.md Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00
requirements.txt Livraison de la pipeline d'alignement BVP/ECG : package, notebook de sync, worklist, scripts T6s, tests 2026-08-29 20:17:33 +02:00

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 :

  1. 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) ;
  2. régler le seuil de détection des allumages sur la courbe affichée ;
  3. 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 ;
  4. 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 --check et --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.