Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TSFR Edition #16 - Time Series et santé: datalogger médical 100hz, retour d'expérience après un an

TSFR Edition #16 - Time Series et santé: datalogger médical 100hz, retour d'expérience après un an

Pour cette 16ème édition, nous allons bénéficier d’un retour d’expérience d’utilisation de séries temporelles dans le domaine de la santé.

Le CHRU de Brest a décidé en 2020 d’acquérir la tension artérielle et la pression intracrânienne en continu de tous ses patients en réanimation, avec une résolution inégalée jusqu’ici. Découvrez cette aventure, de la conception à l’exploitation des 10 milliards de points résultant.

Pour nous raconter ce beau projet, nous aurons comme orateurs :

Pierre PAPIN : Électronicien passionné d’informatique, après 13 ans chez renault sport, je combine ces deux passions en un métier: développeur chez SenX. Quand un projet de collecte de données nécessite du hardware, je réalise la carte électronique, le soft embarqué, et toutes les couches nécessaires pour envoyer les données dans Warp 10. Armé de mon fer à souder et d’un stock de composants, j’ai participé au développement du respirateur open source Makair en mars 2020.

Arnaud MORE : Étudiant en dernière année de l’ENIB (École Nationale d’Ingénieur de Brest), école d’ingénieur généraliste, je réalise un parcours bi-diplomant en partenariat avec l’UBO afin de me spécialiser en traitement du signal. Actuellement en stage de fin d’études au CHRU de la cavale-blanche à Brest, j’aide les médecins à réaliser un outil d’aide à la décision. Ce stage me permet d’allier mes passions pour la médecine et l’ingénierie au sein d’un même projet.

TimeSeriesFr

June 07, 2022
Tweet

More Decks by TimeSeriesFr

Other Decks in Technology

Transcript

  1. Predict
    Datalogger médical pour le
    CHRU du Brest

    View full-size slide

  2. Auteurs
    ▪ Pierre Papin
    Développeur hardware et software chez SenX
    ▪ Arnaud Moré
    Stagiaire ingénieur à l’ENIB, pour le CHRU
    2

    View full-size slide

  3. Introduction
    1
    3

    View full-size slide

  4. L’idée
    Patients en réanimation chirurgicale
    La pression intracrânienne est le facteur important pouvant causer des lésions
    cérébrales irréversibles. La forme de la courbe reflète une pathologie.
    Idée : la forme des courbes de pression intracrânienne, déterminerait l’issue
    autant que la valeur absolue de la pression.
    4

    View full-size slide

  5. Dataset cible
    Pour valider cette hypothèse, il faut un jeu de données :
    PIC, AP, enregistrés à 100Hz en continu.
    PtO2, température, enregistrés toutes les minutes.
    Caractéristiques du patient.
    Traitements administrés au patient.
    5

    View full-size slide

  6. Mon rêve !
    Utiliser un protocole médical ouvert, standard, permettant de streamer les
    données en temps réel !
    HL7, poussé par Philips, est un protocole abominable permettant de transférer
    des waveforms. Il est possible de l’utiliser, mais il faut des mois de
    développement.
    Et les petits appareils ultra spécialisés pour la PIC et la PtO2 ne sont pas
    compatibles.
    7

    View full-size slide

  7. La réalité
    PtO2 et température monitorés par
    Integra Licox.
    Cet appareil a une sortie USB prévue
    pour un module type FTDI
    (USB->RS232)
    La documentation du protocole est
    disponible.
    8

    View full-size slide

  8. La réalité
    La PIC est monitorée par un Sophysa
    Pressio2
    Cet appareil a une sortie mini usb
    reconnue comme un port série par
    l’hôte. Le protocole est disponible.
    9

    View full-size slide

  9. La réalité
    AP monitorée par un super
    moniteur Edwards Life Science.
    Il y a un port ethernet, mais rien
    de prévu pour streamer les
    données.
    Après activation de l’option, il y a
    une option pour exporter les
    données au format csv avec un
    point toutes les 5 secondes…
    10

    View full-size slide

  10. Et à l’hôpital ?
    À l'hôpital, le poste de soin regroupe toutes les données patients des
    chambres du service.
    C’est une solution vendue par Philips, qui permet de visualiser à distance les
    courbes (basse résolution) des appareils Philips.
    Donc, au pied du lit, on connecte le plus d’appareils possible à une centrale
    Philips, par des liaisons… analogiques !
    Philips peut aussi stocker les données… en blob binaire dans une base SQL.
    11

    View full-size slide

  11. Deux liaisons séries et …
    Le moniteur Edwards Life Science dispose d’une seconde sortie analogique
    que je peux utiliser. Elle respecte le standard(*) médical, à savoir une jauge de
    contrainte émulée dont la sortie est calibrée à :
    20,5µV /mmHg
    12

    View full-size slide

  12. Architecture Hardware
    13

    View full-size slide

  13. Solution AP
    Création d’un hardware spécifique pour convertir l’AP en un protocole série.
    14
    Acquisition de la pression artérielle, sortie
    sur un protocole série via un arduino nano.
    + Watchdog hardware pour le Rpi.
    RTC pour le
    raspberry

    View full-size slide

  14. Intégration
    15

    View full-size slide

  15. Intégration
    16

    View full-size slide

  16. Logiciel embarqué
    3
    17

    View full-size slide

  17. Modélisation et données de santé
    Éviter de stocker des données de santé en zone HDS ! Séparer les données brutes
    des données confidentielles, en faisant le lien par un changement de patient :
    PIC, AP, enregistrés à 100Hz en continu.
    PtO2, température, enregistrés toutes les minutes.
    Caractéristiques du patient.
    Traitements administrés au patient.
    18
    time series, label = numéro
    de série du datalogger
    Confidentiel, reste géré par
    le CHRU

    View full-size slide

  18. Modélisation et données de santé
    PIC, AP, enregistrés à 100Hz en continu.
    PtO2, température, enregistrés toutes les minutes.
    Une GTS contenant un nom de patient aléatoire
    Le nom de patient aléatoire est noté dans les données cliniques.
    Caractéristiques du patient.
    Traitements administrés au patient.
    19
    time series, label = numéro
    de série du datalogger
    Confidentiel, reste géré par
    le CHRU

    View full-size slide

  19. Modélisation et données de santé
    Sur l’IHM, il y a bouton “nouveau patient”
    20

    View full-size slide

  20. Fonctionnalités annexes
    Un bouton “nouveau patient” crée un point dans une GTS (type STRING).
    Utilisation théorique : création d’un nouveau patient à chaque nouveau patient.
    En pratique : ça dépend si le médecin/infirmier est formé…
    Un bouton “soins en cours” crée un point dans une GTS (true).
    Utilisation théorique : l’infirmière appui sur le bouton avant de “remuer” le patient
    (ce qui perturbe fortement les courbes de pression)
    En pratique : … … parfois avant, parfois après, parfois jamais.
    21

    View full-size slide

  21. Architecture
    22
    IHM
    Python + Kivy
    Collecte des
    liaisons série
    Java
    Warp 10
    API
    api/v0/exec api/v0/exec
    1 3
    2
    Warp 10
    (SAAS)
    4

    View full-size slide

  22. 1/ Collecte vers Warp 10
    L’applicatif de collecte génère le WarpScript suivant:
    23
    <'
    1654596856720463// AP{} 34.1
    =1654596892170438// 35.2
    =1654596892180438// 35.6
    (...)
    '>
    @predict/storeData

    View full-size slide

  23. 2/ Affichage temps réel
    Pour chaque appareil, l’IHM python+kivy interroge une API:
    curl http://localhost:12345/api/LicoxPtO2/1/
    # {"lastValue":0,"freshValue":true,"serialIsConnected":true}
    Pour ces requêtes régulières, pycurl préférable à request.
    24

    View full-size slide

  24. 3/ Gestion du pseudo de patient
    L’IHM peut créer un patient, ou afficher le patient en cours, en interrogeant
    Warp 10 directement.
    r = requests.post(WARP10_ENDPOINT, data="""
    @predict/currentPatient
    """, timeout=5)
    if (r.status_code == 200):
    lastPatient = r.json()[0]
    Pour plus de souplesse dans la gestion du code, utilisation d’une macro.
    25

    View full-size slide

  25. 4/ Synchro SAAS
    Modèle classique
    26

    View full-size slide

  26. 4/ Synchro SAAS
    Warp 10 : les endpoints sont exposés.
    Chaque datalogger écrit dans la base grâce à son token.
    27

    View full-size slide

  27. 4/ Synchro SAAS, concrètement
    L’instance Warp 10 sur chaque datalogger, va essayer toutes les minutes de
    recopier les GTS locales vers l’instance Warp 10 SAAS.
    Un seul WarpScript suffit, placé dans /opt/warp10/warpscript/predict/60000/
    28

    View full-size slide

  28. 4/ Synchro SAAS, concrètement
    ▪ Chercher T = timestamp de la dernière synchronisation réussie (FETCH)
    ▪ Récupérer les GTS entre T et T + 8h (FETCH)
    ▪ Compresser et sérialiser les données (WRAP)
    ▪ Construire un WarpScript contenant les données sérialisées, le token d’
    écriture, et les instructions pour décompresser et UPDATE les données
    ▪ Exécuter ce WarpScript sur l’instance Warp 10 distante (REXECZ)
    ▪ Si succès, écrire T+8h en valeur de la dernière synchro réussie (UPDATE)
    Pour tracer la dernière synchro réussie, utilisation d’une GTS nommée “upload”, par
    exemple.
    29

    View full-size slide

  29. Disque et suppression des données
    Sur le datalogger, utilisation d’une carte SD
    industrielle donnée pour 30k cycle d’écriture.
    LevelDB est agressif pour les cartes SD. Les
    suppressions régulières entraînent des
    compactions durant lesquelles il faut réécrire
    beaucoup de fichiers.
    Solution : plugin “leveldb” de Warp 10.
    30

    View full-size slide

  30. Disque et suppression des données
    Tous les jours, supprimer les données de plus de 30 jours. Un seul WarpScript
    suffit, placé dans /opt/warp10/warpscript/predict/86400000/
    30 d 'historylength' STORE
    NOW $historylength - 'deletestopTS' STORE
    'read' @predict/localToken
    '~.*'
    {}
    $deletestopTS
    100000
    @senx/leveldb/purge
    L’utilisation du plugin “leveldb” permet de supprimer directement les fichiers
    .sst, sans nécessité d’attendre une compaction.
    31
    😄

    View full-size slide

  31. Espace disque disponible (sur carte SD 16go)
    32

    View full-size slide

  32. 2 ans plus tard…
    4
    33

    View full-size slide

  33. 10 milliards de points
    34

    View full-size slide

  34. Performances en lecture en BDD
    300 000 à 1 000 000 de points par seconde
    Pour relire 10 milliards de points : ~5 heures
    Bien, mais largement perfectible, grâce aux HFiles !
    35

    View full-size slide

  35. HFiles ?
    Les History Files, ou HFiles, sont des conteneurs de stockage à très haute
    densité qui peuvent contenir des centaines de milliards de points de mesure
    provenant de millions de séries.
    ▪ Format spécifique Warp 10.
    ▪ Lecteur gratuit, générateur sous licence.
    ▪ Input format Spark inclus dans le lecteur.
    Le contenu de l’étude tient dans un fichier de 13go, soit 1.3 datapoints par octet
    (sans aucune altération).
    36

    View full-size slide

  36. HFile, comment ça marche ?
    37
    {
    'token' 'MyReadToken'
    'selector' '~.*{}'
    'end' NOW
    'timespan' 100 d
    // encoder to encoder macro. cannot change class and labels here, but can COMPACT
    'macro' <% {} ->GTS COMPACT %>
    'path' 'file257'
    //'checksums' false // extra checksum for file for hdfs filesystem
    'secret' 'myhfstoresecret'
    } HFDUMP
    La création des fichiers peut être automatisée depuis Warp 10.

    View full-size slide

  37. HFile, lecture
    38
    {
    'store' 'predictraw'
    'token' $hfToken
    'class' '~.*'
    'labels' {}
    'end' $end
    'timespan' $timespan
    // 'count' 100 // you can limit
    'lineage' 'hf' // add a "hf" attribute with list of hfiles the data come from
    } HFFETCH
    ->GTS
    HFFETCH peut être remplacé par FETCH.
    ~ 10 millions de points par seconde en lecture par thread, selon le hardware.

    View full-size slide

  38. Recommandation pour HFile
    Le fichier HFile va contenir un encodeur de possiblement 1 milliard de points
    pour la pression artérielle de chaque datalogger.
    Chaque lecture va donc nécessiter de charger l’encodeur entier et le
    décompresser. Il faut donc BEAUCOUP de ram si on fait un seul fichier HFile
    avec quelques GTS de 1 milliards de points.
    Pour Predict, on a choisi de découper en 1 HFile / jour (500 fichiers).
    39
    java.lang.OutOfMemoryError: Java heap space

    View full-size slide

  39. Config d’Arnaud
    Faute d’avoir un cluster hadoop au CHRU…
    Un laptop, 16go de RAM
    Warp 10 avec :
    - extension HFStore
    - plugin Jupyter
    Jupyter + python
    40

    View full-size slide

  40. Exploitation des
    données
    5
    41

    View full-size slide

  41. Exploration des données : courbe PA
    42
    Calibration
    Saturation
    Bruit
    Arythmie

    View full-size slide

  42. Profil matriciel
    43

    View full-size slide

  43. Résultat profil matriciel
    44

    View full-size slide

  44. Exploration des données : courbe PIC
    45

    View full-size slide

  45. Reste des données
    46
    Changement de patient mal placé
    Changement de patient correct

    View full-size slide

  46. Exploration des données : temps d’exécution
    47
    Quelques chiffres :
    ▪ 1 seconde pour fetch 1 journée de data ( + 8 millions de points )
    ▪ Profil matriciel assez lourd : ~20 secondes pour traiter 5 minutes de
    données, 12 threads en parallèle (~ 20 secondes par heure de data)
    ▪ Nettoyage de la PIC beaucoup plus rapide, quelques secondes par
    période de 5 minutes

    View full-size slide

  47. Analyse de forme de la courbe
    48

    View full-size slide

  48. Analyse de forme de la courbe
    49
    Entraînement :
    2500 images classifiées :
    -2000 pour l’entraînement
    -250 de validation
    -250 de test
    Moins de 10 % d’erreurs
    Généralisation :
    Sur 7500 images prises
    aléatoirement
    1: 547
    2: 530
    3: 198
    4: 763
    5: 544
    6: 663
    7: 494
    8: 525
    9: 996
    10: 336
    11: 1116
    12: 902

    View full-size slide

  49. Résultat de l’analyse de la forme
    50

    View full-size slide

  50. Résultat de l’analyse de la forme
    51

    View full-size slide