<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Traitement Du Signal | Valentin Caries</title><link>https://vcaries.github.io/tag/traitement-du-signal/</link><atom:link href="https://vcaries.github.io/tag/traitement-du-signal/index.xml" rel="self" type="application/rss+xml"/><description>Traitement Du Signal</description><generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>fr-fr</language><lastBuildDate>Sat, 12 Sep 2026 00:00:00 +0000</lastBuildDate><image><url>https://vcaries.github.io/media/icon_hu536d0651d21529ac336731b24f3e073f_144279_512x512_fill_lanczos_center_3.png</url><title>Traitement Du Signal</title><link>https://vcaries.github.io/tag/traitement-du-signal/</link></image><item><title>Analyse automatisée de chromatogrammes GC-MS : du signal brut aux pics quantifiés</title><link>https://vcaries.github.io/project/chromatogram-analysis/</link><pubDate>Sat, 12 Sep 2026 00:00:00 +0000</pubDate><guid>https://vcaries.github.io/project/chromatogram-analysis/</guid><description>&lt;h2 id="en-une-minute">En une minute&lt;/h2>
&lt;p>J&amp;rsquo;ai développé un &lt;strong>package Python qui automatise l&amp;rsquo;analyse de chromatogrammes GC-MS&lt;/strong>, du fichier brut de l&amp;rsquo;instrument jusqu&amp;rsquo;à une table de pics quantifiés. La chromatographie en phase gazeuse couplée à la spectrométrie de masse sépare les composés d&amp;rsquo;un échantillon et enregistre, à chaque instant, le signal qui sort de la colonne. Chaque composé forme un pic, dont l&amp;rsquo;aire mesure la quantité présente dans l&amp;rsquo;échantillon. En pratique, ces pics sont souvent repérés, bornés et intégrés à la main dans le logiciel du constructeur, puis recopiés dans des tableurs. Le résultat dépend alors de l&amp;rsquo;opérateur, demande beaucoup de temps dès que les analyses se multiplient, et reste difficile à reproduire ou à auditer.&lt;/p>
&lt;p>Le pipeline remplace cette chaîne manuelle par une suite déterministe d&amp;rsquo;étapes de traitement du signal éprouvées. Il lit directement les fichiers binaires du constructeur et reconstruit le chromatogramme en courant ionique total. Il le lisse par un filtre de &lt;strong>Savitzky–Golay&lt;/strong> et estime la ligne de base par &lt;strong>moindres carrés asymétriques&lt;/strong>. Il détecte ensuite les pics par leur &lt;strong>proéminence topographique&lt;/strong> rapportée à une estimation robuste du bruit, puis borne chacun d&amp;rsquo;eux aux vallées. Par défaut, les aires sont mesurées par une réimplémentation de la &lt;strong>méthodologie d&amp;rsquo;intégration d&amp;rsquo;Agilent ChemStation&lt;/strong> : ligne de base construite, coupures verticales ou lignes de base de vallée pour les pics fusionnés, et code de séparation. Chaque étape est une fonction pure de son entrée et d&amp;rsquo;un unique jeu de paramètres versionné, si bien qu&amp;rsquo;une même analyse redonne toujours les mêmes nombres.&lt;/p>
&lt;p>Il devient ainsi possible de mener une analyse reproductible, scriptable sur des séries entières d&amp;rsquo;acquisitions, inspectable pic par pic et confrontable aux résultats manuels. La même bibliothèque alimente un outil en ligne de commande, une application de bureau, des rapports HTML interactifs autonomes dans lesquels chaque pic peut être réintégré à la souris, et des tables CSV, JSON, Parquet ou xlsx prêtes pour l&amp;rsquo;analyse statistique.&lt;/p>
&lt;p>&lt;strong>À propos des figures.&lt;/strong> Les données analysées dans ce projet sont confidentielles. Tous les chromatogrammes, figures et captures d&amp;rsquo;écran de cette page ont été produits à partir de &lt;strong>données synthétiques générées spécifiquement pour cette démonstration&lt;/strong>. Aucun ne correspond aux chromatogrammes réels traités par le logiciel. Le signal synthétique passe néanmoins par le véritable code du package : ce que montrent les figures est bien ce que fait le logiciel.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/overview.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/overview.png" alt="Un chromatogramme synthétique dont chaque pic détecté est intégré, avec deux régions agrandies" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 1.&lt;/strong> Une acquisition synthétique traitée de bout en bout. (a) Le courant ionique total brut, avec chaque apex détecté marqué et chaque aire intégrée ombrée. (b) Trois pics co-élués : les deux premiers partagent une ligne de base et sont séparés par une coupure verticale, tandis que le troisième revient à la ligne de base. Les étiquettes de deux lettres sont les codes de séparation attribués par l'intégrateur. (c) Des pics mineurs sur une ligne de base qui dérive lentement, chacun intégré au-dessus de sa propre ligne de base construite. &lt;em>(Cliquez sur une figure pour l'ouvrir en taille réelle.)&lt;/em>&lt;/figcaption>
&lt;/figure>
&lt;h3 id="points-clés">Points clés&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Un pipeline de bout en bout.&lt;/strong> Lecture du format binaire, lissage, correction de ligne de base, estimation du bruit, détection, intégration, identification par temps de rétention, quantification relative et validation, avec des algorithmes sélectionnés par configuration derrière des interfaces interchangeables.&lt;/li>
&lt;li>&lt;strong>Une méthodologie constructeur, réimplémentée à partir de sa documentation.&lt;/strong> Regroupement des pics, arbitrage entre coupure verticale et ligne de base de vallée par le rapport pic/vallée, gestion des pénétrations de ligne de base, hauteur, largeur et codes de séparation. Chaque aire est accompagnée de son unité, explicitement nommée.&lt;/li>
&lt;li>&lt;strong>Validé face au travail manuel.&lt;/strong> La détection retrouve &lt;strong>93 %&lt;/strong> des composés identifiés manuellement à moins de 3 s (erreur médiane sur le temps de rétention ≈ 0,1 s). Avec les bornes d&amp;rsquo;intégration de l&amp;rsquo;opérateur, les aires concordent avec les aires de référence intégrées à la main à &lt;strong>3,5 % en médiane&lt;/strong> sur les pics résolus jusqu&amp;rsquo;à la ligne de base.&lt;/li>
&lt;li>&lt;strong>Reproductible par construction.&lt;/strong> Un jeu de paramètres figé et hachable, une traçabilité des traitements attachée à chaque signal, et un test de non-régression sur fichiers de référence qui fige chaque apex et chaque borne détectés.&lt;/li>
&lt;li>&lt;strong>Utilisable sans programmer.&lt;/strong> Une interface en ligne de commande, une interface graphique distribuée sous forme d&amp;rsquo;exécutable Windows autonome, et des rapports interactifs qui ne demandent qu&amp;rsquo;un navigateur.&lt;/li>
&lt;/ul>
&lt;h2 id="pourquoi-automatiser-lanalyse-des-chromatogrammes-">Pourquoi automatiser l&amp;rsquo;analyse des chromatogrammes ?&lt;/h2>
&lt;p>Une acquisition GC-MS compte des milliers de scans, et un échantillon riche peut présenter bien plus d&amp;rsquo;une centaine de pics distincts. Les transformer en nombres passe généralement par trois étapes manuelles : reconnaître les pics pertinents, décider où chacun commence et se termine, puis l&amp;rsquo;intégrer. Chaque étape cache un choix. Où passe exactement la ligne de base sous un pic posé sur un fond qui dérive ? Où s&amp;rsquo;arrête un pic quand il chevauche son voisin ? Une petite bosse est-elle un composé ou du bruit ?&lt;/p>
&lt;p>Quand ces décisions se prennent à l&amp;rsquo;œil, trois difficultés apparaissent. &lt;strong>La reproductibilité&lt;/strong> : deux opérateurs, ou le même opérateur un mois plus tard, ne tracent pas les mêmes bornes, et l&amp;rsquo;aire suit les bornes. &lt;strong>La traçabilité&lt;/strong> : un nombre dans un tableur ne dit pas comment il a été obtenu. &lt;strong>Le passage à l&amp;rsquo;échelle&lt;/strong> : l&amp;rsquo;effort croît avec le nombre d&amp;rsquo;acquisitions et devient vite le goulot d&amp;rsquo;étranglement d&amp;rsquo;une étude.&lt;/p>
&lt;p>L&amp;rsquo;objectif du projet n&amp;rsquo;était donc pas seulement de calculer des aires, mais de rendre chaque décision explicite, paramétrée et répétable, puis de démontrer sur données réelles que le résultat automatique reproduit le résultat manuel avant de s&amp;rsquo;y fier.&lt;/p>
&lt;h2 id="du-fichier-brut-au-signal">Du fichier brut au signal&lt;/h2>
&lt;p>L&amp;rsquo;instrument enregistre chaque acquisition dans un fichier binaire au format propriétaire historique du constructeur. Plutôt que de dépendre d&amp;rsquo;un logiciel propriétaire ou d&amp;rsquo;une bibliothèque native, le package embarque un &lt;strong>lecteur sans dépendance&lt;/strong>, écrit avec la bibliothèque standard et NumPy. Il lit l&amp;rsquo;en-tête du fichier (nom d&amp;rsquo;échantillon, méthode, date d&amp;rsquo;acquisition) et le répertoire des scans, qui stocke le temps de rétention et le courant ionique total de chaque scan. Le &lt;strong>chromatogramme en courant ionique total (TIC)&lt;/strong>, somme des intensités de tous les ions d&amp;rsquo;un scan, se reconstruit ainsi sans perte, sans décoder les spectres de masse individuels. La structure binaire est documentée dans le lecteur lui-même : la spécification du format vit à côté du code qui l&amp;rsquo;implémente.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/raw-chromatogram.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/raw-chromatogram.png" alt="Un chromatogramme synthétique brut avec un zoom sur des pics mineurs et le bruit de ligne de base" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 2.&lt;/strong> Le signal brut synthétique utilisé tout au long de cette page. Les pics couvrent plus de deux ordres de grandeur, certains présentent une traînée, d'autres co-éluent, et la ligne de base monte lentement en fin d'analyse. Le zoom montre ce qui est invisible à pleine échelle : des pics mineurs, un bruit corrélé d'un scan à l'autre, et la ligne de base sous-jacente à partir de laquelle le signal synthétique a été construit (en pointillés).&lt;/figcaption>
&lt;/figure>
&lt;h2 id="la-chaîne-de-traitement">La chaîne de traitement&lt;/h2>
&lt;p>Chaque étape est une fonction pure &lt;code>(entrée, paramètres) → sortie&lt;/code>, et chaque transformation du signal ajoute son nom à l&amp;rsquo;historique de traitement porté par le signal. Tout résultat peut ainsi être rattaché aux traitements exacts qui l&amp;rsquo;ont produit.&lt;/p>
&lt;div class="mermaid">flowchart TD
A["Fichier brut constructeur"] --> B["Lecture&lt;br/>courant ionique total"]
B --> C["Lissage&lt;br/>Savitzky–Golay"]
C --> D["Ligne de base&lt;br/>moindres carrés asymétriques"]
D --> E["Détection&lt;br/>proéminence vs bruit"]
E --> F["Bornes&lt;br/>aux vallées"]
F --> G["Intégration&lt;br/>méthode constructeur sur signal brut"]
R["Table de référence&lt;br/>(composé, temps de rétention)"] --> H
G --> H["Identification&lt;br/>par temps de rétention"]
H --> I["Quantification, validation, rapports"]
&lt;/div>
&lt;h3 id="lissage">Lissage&lt;/h3>
&lt;p>Le TIC est d&amp;rsquo;abord lissé par un &lt;strong>filtre de Savitzky–Golay&lt;/strong> : sur une fenêtre glissante de 11 scans, un polynôme cubique est ajusté par moindres carrés puis évalué au centre. Contrairement à une moyenne glissante, le polynôme local épouse la courbure du pic : le bruit diminue sans écraser l&amp;rsquo;apex ni élargir le pic. C&amp;rsquo;est essentiel, car la détection comme l&amp;rsquo;intégration dépendent de la forme des pics.&lt;/p>
&lt;h3 id="correction-de-ligne-de-base">Correction de ligne de base&lt;/h3>
&lt;p>Le fond qui varie lentement (ressuage de colonne, dérive du détecteur) est estimé par &lt;strong>moindres carrés asymétriques (AsLS)&lt;/strong>. La ligne de base $z$ minimise un ajustement pondéré au signal $y$ augmenté d&amp;rsquo;une pénalité de rugosité :&lt;/p>
$$S = \sum_i w_i\,(y_i - z_i)^2 + \lambda \sum_i \left(\Delta^2 z_i\right)^2$$
&lt;p>L&amp;rsquo;asymétrie tient aux poids. Les points situés au-dessus de l&amp;rsquo;estimation courante, vraisemblablement des pics, reçoivent un faible poids $p$, ceux situés en dessous reçoivent $1 - p$. En itérant, la courbe se loge dans les vallées et ignore les pics. Avec les valeurs par défaut $\lambda = 10^5$ et $p = 0{,}01$, chaque itération résout un système linéaire creux, ce qui garde la méthode rapide sur des acquisitions de plusieurs milliers de scans. L&amp;rsquo;AsLS ne demande ni points d&amp;rsquo;ancrage manuels ni forme de ligne de base supposée.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/preprocessing.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/preprocessing.png" alt="Lissage de Savitzky-Golay sur un pic mineur, et ligne de base AsLS sur toute l'acquisition" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 3.&lt;/strong> (a) Lissage de Savitzky–Golay sur un pic mineur : le bruit d'un scan à l'autre diminue tandis que le pic conserve sa hauteur et sa largeur. (b) La ligne de base AsLS sur toute l'acquisition synthétique, en échelle logarithmique. Elle suit la montée du fond, mais se courbe aussi sous les plus grands pics, là où une courbe unique et raide ne peut pas épouser exactement les vallées. C'est une limite connue d'une ligne de base globale. Le signal corrigé sert à la détection, tandis que la mesure d'aire par défaut construit sa propre ligne de base, localement, à partir des bornes des pics (figure 5).&lt;/figcaption>
&lt;/figure>
&lt;h3 id="estimation-du-bruit-et-détection-des-pics">Estimation du bruit et détection des pics&lt;/h3>
&lt;p>La détection a besoin d&amp;rsquo;une échelle de référence. Le niveau de bruit est donc estimé de façon robuste à partir de l&amp;rsquo;&lt;strong>écart absolu médian des différences successives&lt;/strong> :&lt;/p>
$$\hat\sigma = \frac{\text{médiane}\left(|\Delta y|\right)}{\sqrt{2}\times 0{,}6745}$$
&lt;p>La différenciation élimine le fond lent, la médiane ignore la minorité de grandes valeurs dues aux pics, et les deux constantes ramènent le résultat à un écart-type gaussien.&lt;/p>
&lt;p>Les pics sont alors les maxima locaux du signal corrigé dont la &lt;strong>proéminence topographique&lt;/strong> dépasse un seuil : par défaut cinq fois $\hat\sigma$, ou un minimum fixé explicitement par l&amp;rsquo;analyste. La proéminence mesure de combien un maximum s&amp;rsquo;élève au-dessus du plus haut des deux points bas qui le séparent, de part et d&amp;rsquo;autre, d&amp;rsquo;un relief plus élevé. Contrairement à la hauteur brute, elle reste insensible à un décalage résiduel et à un pic posé sur le flanc d&amp;rsquo;un pic plus grand.&lt;/p>
&lt;h3 id="bornes-dintégration">Bornes d&amp;rsquo;intégration&lt;/h3>
&lt;p>Chaque pic détecté reçoit ensuite deux bornes d&amp;rsquo;intégration. Deux pics voisins sont séparés à la &lt;strong>vallée&lt;/strong>, le minimum du signal entre leurs apex, si bien que leurs fenêtres se touchent sans se chevaucher. C&amp;rsquo;est la règle classique de la perpendiculaire abaissée des systèmes de traitement chromatographique. Les bords extérieurs descendent depuis l&amp;rsquo;apex jusqu&amp;rsquo;au premier minimum local. Une règle antérieure laissait les fenêtres se chevaucher, de sorte qu&amp;rsquo;une même portion de signal pouvait compter dans deux pics. Sur les données du projet, environ 29 % de l&amp;rsquo;aire totale étaient ainsi comptés deux fois, et la règle des vallées supprime ce double comptage sans déplacer un seul apex.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/peak-detection.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/peak-detection.png" alt="Apex détectés, proéminences et bornes d'intégration sur le signal synthétique corrigé" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 4.&lt;/strong> Détection sur le signal synthétique corrigé de sa ligne de base. (a) Deux pics mineurs et (b) des pics plus grands suivent les mêmes règles : un apex (en noir), sa proéminence (barre orange) et des bornes d'intégration aux vallées (en pointillés). (c) Les 43 pics détectés sur l'ensemble de l'acquisition. Pour ces figures, la proéminence minimale a été fixée explicitement à 9 000 coups, paramètre exposé dans l'outil en ligne de commande et dans l'application de bureau. Tous les autres réglages sont les valeurs par défaut du package.&lt;/figcaption>
&lt;/figure>
&lt;h2 id="mesurer-laire-des-pics">Mesurer l&amp;rsquo;aire des pics&lt;/h2>
&lt;h3 id="deux-familles-de-méthodes-dintégration">Deux familles de méthodes d&amp;rsquo;intégration&lt;/h3>
&lt;p>L&amp;rsquo;intégration est volontairement séparée de la détection. La détection produit une géométrie (un apex et deux bornes), l&amp;rsquo;intégration consomme des bornes et un signal. La jonction est un objet explicite, &lt;code>IntegrationBounds&lt;/code>, qui mémorise l&amp;rsquo;origine de ses bornes : le détecteur, un opérateur qui les a déplacées dans le rapport, ou un jeu de résultats externe. Les trois chemins aboutissent au même intégrateur, ce qui permet de comparer une méthode à une référence sans que des écarts de détection ne faussent la comparaison.&lt;/p>
&lt;p>Les méthodes sont enregistrées par nom dans un petit &lt;strong>registre&lt;/strong>, avec le signal dont chacune a besoin. Ce détail évite une catégorie d&amp;rsquo;erreurs silencieuses : l&amp;rsquo;intégration numérique attend un signal déjà corrigé de sa ligne de base, alors que la méthode constructeur construit sa propre ligne de base et en soustrairait deux si on lui fournissait le signal corrigé. Le registre choisit donc le bon signal, sans que l&amp;rsquo;appelant ait à le savoir. Deux règles numériques (trapèzes et Simpson) intègrent le signal corrigé par AsLS. La méthode par défaut applique la méthodologie constructeur au signal brut.&lt;/p>
&lt;h3 id="la-méthodologie-constructeur--groupes-coupures-verticales-et-lignes-de-base-de-vallée">La méthodologie constructeur : groupes, coupures verticales et lignes de base de vallée&lt;/h3>
&lt;p>La méthode par défaut, &lt;code>chemstation&lt;/code>, implémente la mesure d&amp;rsquo;aire décrite dans la documentation ChemStation d&amp;rsquo;Agilent. Seule la mesure d&amp;rsquo;aire entrait dans le périmètre, pas l&amp;rsquo;algorithme de détection du constructeur. Elle se reconstruit en trois temps.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Regroupement.&lt;/strong> Les pics dont le signal revient à la ligne de base entre eux sont intégrés indépendamment. Deux pics voisins dont la vallée commune reste au-dessus de la corde reliant leurs bornes extérieures forment un groupe et partagent une même ligne de base.&lt;/li>
&lt;li>&lt;strong>Coupure verticale ou ligne de base de vallée.&lt;/strong> Dans un groupe, chaque vallée est arbitrée par le rapport pic/vallée défini ci-dessous. Sous un seuil configurable (10 par défaut), une coupure verticale sépare les deux pics. Au-delà, la vallée devient un point d&amp;rsquo;ancrage de la ligne de base.&lt;/li>
&lt;li>&lt;strong>Aire.&lt;/strong> Le signal est intégré au-dessus de la ligne de base affine par morceaux ainsi obtenue, entre les bornes de chaque pic. Là où le signal passe sous la ligne de base, la contribution négative est écrêtée et le pic est signalé : une pénétration de ligne de base ne peut jamais retrancher de l&amp;rsquo;aire.&lt;/li>
&lt;/ol>
&lt;p>Le rapport pic/vallée compare la plus petite des hauteurs des deux pics voisins à la hauteur de la vallée qui les sépare, toutes mesurées au-dessus de la ligne de base provisoire :&lt;/p>
$$\text{rapport} = \frac{\min(H_1, H_2)}{H_v}$$
&lt;p>Une vallée qui redescend près de la ligne de base donne un rapport élevé et devient un point d&amp;rsquo;ancrage, tandis qu&amp;rsquo;un léger creux entre deux pics fusionnés donne un rapport faible et se traite par une coupure verticale.&lt;/p>
&lt;p>Chaque pic reçoit aussi une &lt;strong>hauteur&lt;/strong> (son plus grand écart au-dessus de la ligne de base), une &lt;strong>largeur&lt;/strong> selon la convention du constructeur $\text{largeur} = \text{aire}/\text{hauteur}$, et un &lt;strong>code de séparation&lt;/strong> de deux caractères qui décrit son début et sa fin : &lt;code>B&lt;/code> sur la ligne de base, &lt;code>V&lt;/code> sur une coupure verticale, &lt;code>P&lt;/code> là où la ligne de base a été pénétrée.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/integration.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/integration.png" alt="Les mêmes pics intégrés par la méthode des trapèzes et par la méthodologie constructeur" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 5.&lt;/strong> Intégration du triplet synthétique. (a) La méthode des trapèzes sur le signal corrigé par AsLS, entre les bornes détectées. (b) La méthodologie constructeur sur le signal brut : une ligne de base construite passant par ses points d'ancrage, une coupure verticale entre les deux premiers pics (codes &lt;code>BV&lt;/code> et &lt;code>VB&lt;/code>), et un troisième pic résolu jusqu'à la ligne de base (&lt;code>BB&lt;/code>). (c) La hauteur et la largeur du rectangle équivalent, reportées pour un pic isolé. (d) Les aires obtenues : les bornes sont identiques, mais le signal et la ligne de base diffèrent, et les aires aussi.&lt;/figcaption>
&lt;/figure>
&lt;h3 id="des-unités-jamais-confondues">Des unités jamais confondues&lt;/h3>
&lt;p>Une aire n&amp;rsquo;a pas de sens sans son unité, et les unités en jeu diffèrent de plusieurs ordres de grandeur. Le package exprime chaque aire en &lt;code>counts·min&lt;/code> (l&amp;rsquo;unité pivot), en &lt;code>counts·s&lt;/code> et en &lt;code>counts·ms&lt;/code>, l&amp;rsquo;unité utilisée en interne par l&amp;rsquo;intégrateur du constructeur. Une quatrième unité, clairement étiquetée &lt;strong>équivalent référence&lt;/strong>, applique un facteur d&amp;rsquo;échelle empirique pour placer les aires calculées à côté des aires de référence utilisées en validation. Ce facteur ne découlant pas de la méthodologie publiée, il est tenu à l&amp;rsquo;écart des trois unités physiques, calibré une fois pour toutes de manière reproductible depuis le code, et jamais réajusté acquisition par acquisition : un tel ajustement masquerait précisément les écarts que la validation doit révéler.&lt;/p>
&lt;h2 id="des-pics-aux-résultats">Des pics aux résultats&lt;/h2>
&lt;h3 id="identification-et-quantification-relative">Identification et quantification relative&lt;/h3>
&lt;p>Une table de référence recense les composés identifiés par un analyste et leurs temps de rétention. Chaque composé est associé à l&amp;rsquo;&lt;strong>apex détecté le plus proche dans une tolérance&lt;/strong> donnée (±0,05 min, soit 3 s, par défaut). Les composés sans pic dans la tolérance sont signalés comme non appariés au lieu d&amp;rsquo;être écartés en silence.&lt;/p>
&lt;p>Faute d&amp;rsquo;étalons de calibration, les concentrations absolues ne sont pas accessibles. La lecture quantitative repose donc sur la &lt;strong>normalisation des aires&lt;/strong> : l&amp;rsquo;aire de chaque pic exprimée en pourcentage de l&amp;rsquo;aire totale intégrée de son acquisition. C&amp;rsquo;est une mesure relative, calculée au sein d&amp;rsquo;une acquisition et dans une seule unité, si bien que le choix de l&amp;rsquo;unité s&amp;rsquo;élimine.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/relative-areas.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/relative-areas.png" alt="Aires relatives des plus grands pics synthétiques avec leurs codes de séparation" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 6.&lt;/strong> Aires relatives issues de la table de pics produite par le package pour l'acquisition synthétique : les douze plus grands pics, repérés par leur temps de rétention et leur code de séparation, les autres étant regroupés. La somme des parts vaut 100 % sur l'acquisition.&lt;/figcaption>
&lt;/figure>
&lt;h3 id="rapports-interactifs-et-exports-structurés">Rapports interactifs et exports structurés&lt;/h3>
&lt;p>Pour l&amp;rsquo;inspection, le package génère pour chaque acquisition un &lt;strong>rapport HTML interactif autonome&lt;/strong> (Plotly). Le rapport présente le chromatogramme et sa ligne de base, chaque pic détecté, les composés appariés colorés selon leur statut de validation, des indicateurs de synthèse et une table de résultats. Un clic sur un pic l&amp;rsquo;ombre et l&amp;rsquo;intègre. Deux bornes peuvent alors être déplacées à la souris, et l&amp;rsquo;aire est recalculée en direct dans chaque unité, avec sa part dans l&amp;rsquo;acquisition. On peut changer de méthode d&amp;rsquo;intégration, puis nommer n&amp;rsquo;importe quel pic, même absent de la référence, et l&amp;rsquo;ajouter à la table. Celle-ci se télécharge en CSV, JSON ou xlsx. Le fichier xlsx est écrit dans le navigateur, sans aucune dépendance, si bien que le rapport ne demande aucun serveur.&lt;/p>
&lt;figure>
&lt;a href="https://vcaries.github.io/media/chromatogram-analysis/interactive-report.png" target="_blank" rel="noopener">&lt;img src="https://vcaries.github.io/media/chromatogram-analysis/interactive-report.png" alt="Capture d'écran du rapport HTML interactif généré pour l'acquisition synthétique" style="width:100%;height:auto;">&lt;/a>
&lt;figcaption>&lt;strong>Figure 7.&lt;/strong> Le rapport interactif généré par le package pour l'acquisition synthétique, avec des composés de référence fictifs. La vue est zoomée sur le triplet et le pic central a été cliqué : ses bornes apparaissent sous forme de lignes pointillées déplaçables, et le panneau donne son aire dans les quatre unités ainsi que sa part dans l'acquisition.&lt;/figcaption>
&lt;/figure>
&lt;p>Pour l&amp;rsquo;analyse en aval, les exports sont des &lt;strong>tables au format « tidy »&lt;/strong>, une ligne par composé avec un identifiant d&amp;rsquo;acquisition, en CSV, JSON, Parquet ou xlsx, par acquisition et pour une série complète. Chaque colonne porteuse d&amp;rsquo;une unité la nomme dans son en-tête, et chaque ligne indique la méthode d&amp;rsquo;intégration qui l&amp;rsquo;a produite. Une commande ciblée permet aussi d&amp;rsquo;intégrer le pic le plus proche de n&amp;rsquo;importe quel temps de rétention, qu&amp;rsquo;il figure ou non dans la référence.&lt;/p>
&lt;h3 id="trois-interfaces-une-seule-bibliothèque">Trois interfaces, une seule bibliothèque&lt;/h3>
&lt;p>Toute la logique réside dans une bibliothèque Python typée. Un &lt;strong>outil en ligne de commande&lt;/strong> l&amp;rsquo;expose sous forme de commandes &lt;code>analyze&lt;/code>, &lt;code>validate&lt;/code>, &lt;code>report&lt;/code>, &lt;code>export&lt;/code> et &lt;code>integrate&lt;/code>, qui acceptent une acquisition isolée ou des dossiers entiers. Une &lt;strong>interface graphique&lt;/strong> (Tkinter) propose les mêmes commandes avec des sélecteurs de fichiers natifs, une aide contextuelle sur chaque paramètre et un traitement en tâche de fond. Elle est aussi distribuée sous forme d&amp;rsquo;&lt;strong>exécutable Windows autonome&lt;/strong>, sans installation de Python. Les interfaces restent de simples coques : le menu d&amp;rsquo;intégration de l&amp;rsquo;interface graphique, par exemple, est alimenté par le registre des méthodes, et ne peut donc jamais proposer une méthode déclarée mais non implémentée.&lt;/p>
&lt;h2 id="validation-face-aux-résultats-manuels">Validation face aux résultats manuels&lt;/h2>
&lt;p>Automatiser une analyse n&amp;rsquo;a d&amp;rsquo;intérêt que si l&amp;rsquo;on peut se fier au résultat. La validation fait donc partie intégrante du package, et elle a été menée sur données réelles (ces données restent confidentielles : seuls des résultats agrégés sont présentés ici).&lt;/p>
&lt;p>&lt;strong>Identification.&lt;/strong> Sur les acquisitions qui disposent à la fois des données brutes et d&amp;rsquo;une table d&amp;rsquo;identification manuelle, la détection place un pic à moins de 3 s du temps de rétention indiqué pour &lt;strong>209 composés sur 225 (93 %)&lt;/strong>, avec une &lt;strong>erreur absolue médiane d&amp;rsquo;environ 0,1 s&lt;/strong>. Les composés non appariés sont signalés, pas masqués. Ils correspondent à des identifications faites à partir des spectres de masse, là où aucun pic distinct n&amp;rsquo;apparaît sur le courant ionique total.&lt;/p>
&lt;p>&lt;strong>Aires.&lt;/strong> Les aires calculées ont été comparées à un jeu de résultats de référence : 50 pics intégrés à la main par un opérateur, sur quatre acquisitions. Un écart global unique masquerait l&amp;rsquo;étape en désaccord. La comparaison est donc découpée en trois niveaux, chacun figeant une étape :&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Niveau&lt;/th>
&lt;th>Bornes d&amp;rsquo;intégration&lt;/th>
&lt;th>Un écart met en cause&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Intégration&lt;/td>
&lt;td>les bornes de la référence&lt;/td>
&lt;td>la méthode d&amp;rsquo;intégration, la construction de la ligne de base ou l&amp;rsquo;unité&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bornes&lt;/td>
&lt;td>bornes détectées comparées à celles de la référence&lt;/td>
&lt;td>la détection des pics ou le placement des bornes&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Bout en bout&lt;/td>
&lt;td>bornes détectées&lt;/td>
&lt;td>les deux combinés&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Les &lt;strong>50 pics de référence sont tous appariés&lt;/strong> à un pic détecté. Avec les bornes de la référence, les aires concordent à &lt;strong>3,5 % en médiane&lt;/strong> sur les fenêtres qui commencent et se terminent sur la ligne de base. De bout en bout, l&amp;rsquo;écart médian atteint 26,5 %, et les niveaux montrent qu&amp;rsquo;il provient du placement des bornes et non de la méthode d&amp;rsquo;intégration : les fenêtres de vallée à vallée du détecteur sont systématiquement plus larges que les fenêtres étroites tracées à la main par l&amp;rsquo;opérateur. La validation signale aussi deux facteurs de confusion au lieu de les gommer : tous les pics de référence ont été intégrés manuellement, et environ la moitié des fenêtres de référence commencent ou se terminent à mi-hauteur sur le flanc d&amp;rsquo;un pic, là où aucune règle automatique ne pourrait les reproduire exactement.&lt;/p>
&lt;h2 id="architecture-logicielle-et-reproductibilité">Architecture logicielle et reproductibilité&lt;/h2>
&lt;p>Le package est organisé en couches strictement séparées : configuration, modèles de données, entrées-sorties, prétraitement, algorithmes, interprétation, validation, présentation, orchestration et interfaces. Chaque étape algorithmique se trouve derrière une interface de stratégie : on peut ajouter une nouvelle méthode de ligne de base ou d&amp;rsquo;intégration sans toucher au reste du pipeline.&lt;/p>
&lt;p>La reproductibilité repose sur trois mécanismes. Les paramètres de traitement forment un objet unique, validé et &lt;strong>figé&lt;/strong>, dont une courte &lt;strong>empreinte&lt;/strong> (un hachage de son contenu) identifie la configuration exacte à l&amp;rsquo;origine de chaque résultat. Chaque signal porte un &lt;strong>historique de traitement&lt;/strong> qui nomme les transformations déjà appliquées. Enfin, un &lt;strong>test de non-régression sur fichiers de référence&lt;/strong> fige chaque apex et chaque borne détectés sur des acquisitions de référence, de sorte qu&amp;rsquo;aucune modification de la détection ne peut passer inaperçue. Lorsque la méthode d&amp;rsquo;intégration par défaut a changé, ce test a prouvé que l&amp;rsquo;ensemble des pics détectés restait inchangé.&lt;/p>
&lt;p>Le code est typé (&lt;code>mypy --strict&lt;/code>), vérifié et formaté (&lt;code>ruff&lt;/code>), couvert par une suite d&amp;rsquo;un peu plus de 300 tests exécutée en intégration continue, et publié avec un versionnage sémantique et un journal des modifications. La justification scientifique, les hypothèses et les références bibliographiques de chaque étape sont documentées à côté du code.&lt;/p>
&lt;h2 id="limites-et-perspectives">Limites et perspectives&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Une seule dimension du signal.&lt;/strong> Le pipeline travaille sur le courant ionique total : deux composés qui co-éluent mais diffèrent en masse fusionnent en un seul pic. Les chromatogrammes d&amp;rsquo;ions extraits permettraient de les séparer.&lt;/li>
&lt;li>&lt;strong>Une séparation des pics sans modèle.&lt;/strong> Les pics fusionnés sont séparés par coupure verticale ou ligne de base de vallée, sans ajustement de forme. Pour des pics très imbriqués, une déconvolution par gaussiennes ou gaussiennes exponentiellement modifiées répartirait l&amp;rsquo;aire plus finement.&lt;/li>
&lt;li>&lt;strong>La sensibilité de détection est un paramètre.&lt;/strong> Le seuil de proéminence décide du nombre de pics mineurs retenus, et le choix des pics qui méritent d&amp;rsquo;être rapportés reste une décision distincte.&lt;/li>
&lt;li>&lt;strong>Une quantification relative, pas absolue.&lt;/strong> Les pourcentages d&amp;rsquo;aire supposent des réponses du détecteur comparables d&amp;rsquo;un composé à l&amp;rsquo;autre, ce qui n&amp;rsquo;est qu&amp;rsquo;approximativement vrai en GC-MS.&lt;/li>
&lt;li>&lt;strong>Une identité fondée sur le seul temps de rétention.&lt;/strong> Les indices de rétention calés sur une série de n-alcanes et la comparaison à des bibliothèques de spectres sont les prochaines étapes naturelles vers une identification indépendante de l&amp;rsquo;instrument.&lt;/li>
&lt;/ul>
&lt;h2 id="compétences-démontrées">Compétences démontrées&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Traitement du signal et méthodes numériques :&lt;/strong> filtrage de Savitzky–Golay, moindres carrés asymétriques pénalisés sur systèmes creux, estimation robuste du bruit, détection par proéminence et intégration numérique.&lt;/li>
&lt;li>&lt;strong>Sciences analytiques :&lt;/strong> structure des données GC-MS, conventions d&amp;rsquo;intégration chromatographique (perpendiculaire abaissée, rapport pic/vallée, codes de séparation), identification par temps de rétention et normalisation des aires.&lt;/li>
&lt;li>&lt;strong>Rétro-ingénierie et normes :&lt;/strong> un lecteur sans dépendance pour un format binaire propriétaire, et une méthodologie d&amp;rsquo;intégration réimplémentée à partir de sa documentation publiée.&lt;/li>
&lt;li>&lt;strong>Validation et rigueur scientifique :&lt;/strong> une comparaison par niveaux aux résultats manuels qui distingue les erreurs de détection des erreurs d&amp;rsquo;intégration, avec des facteurs de confusion exposés plutôt qu&amp;rsquo;ajustés.&lt;/li>
&lt;li>&lt;strong>Génie logiciel :&lt;/strong> un package Python en couches, typé et testé, avec interfaces de stratégie, registre de méthodes, paramètres versionnés, traçabilité des traitements, tests de non-régression et intégration continue.&lt;/li>
&lt;li>&lt;strong>Mise à disposition :&lt;/strong> une interface en ligne de commande, une application de bureau empaquetée en exécutable autonome, et des rapports interactifs autonomes pensés pour des utilisateurs qui ne programment pas.&lt;/li>
&lt;/ul>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>Intégrer un pic tient en quelques lignes de code. Produire des aires qu&amp;rsquo;un laboratoire peut croire, relancer et auditer est un projet d&amp;rsquo;ingénierie. Ce package transforme un protocole manuel, dépendant de l&amp;rsquo;opérateur, en un pipeline déterministe où chaque décision (lissage, ligne de base, seuil de détection, bornes, règle d&amp;rsquo;intégration, unité) est explicite, paramétrée et enregistrée. Il réimplémente la méthodologie d&amp;rsquo;intégration du constructeur plutôt que d&amp;rsquo;en inventer une nouvelle, et mesure sa propre concordance avec les résultats manuels avant de demander à quiconque de s&amp;rsquo;y fier. Par la ligne de commande, une application de bureau ou un simple fichier HTML, il met cette analyse entre les mains de ceux qui produisent les données.&lt;/p></description></item></channel></rss>