
Quelques retours sur la conférence européenne dédiée au logiciel libre de traitement de signaux radiofréquences échantillonnés en temps discret GNU Radio, et le développement de blocs Python dédiés au traitement du signal en flux tendu.
La conférence European GNU Radio Days (Fig. 1), qui vise à regrouper les utilisateurs et développeurs de l’infrastructure libre de traitement numérique de signaux radiofréquences GNU Radio, a vu sa septième édition organisée en Allemagne dans les locaux de l’accélérateur d’ions GSI (GSI Helmholtzzentrum für Schwerionenforschung) près de Darmstadt. Ce grand instrument est en effet utilisateur de GNU Radio dans sa gestion des signaux radiofréquences nécessaires à accélérer les ions, et plusieurs centaines de points de mesure à base de systèmes commerciaux accessibles au grand public sont disséminés sur les accélérateurs linéaire et circulaire pour surveiller les instruments qui ne sont pas munis par défaut de systèmes de supervision. Alors que GNU Radio est l’héritage d’un long développement initié en 2001, un développement totalement innovant est engagé comme une potentielle refonte de GNU Radio. Josh Morman en particulier, maintenant président du projet GNU Radio, a participé à la réflexion sur l’architecture des interfaces et du code. La conférence, qui s’est tenue pendant la dernière semaine d’août au GSI/FAIR, fut l’opportunité d’annoncer officiellement le développement de GNU Radio 4.0 et introduire les développeurs aux nouveaux concepts [1] proposés dans cette refonte de notre infrastructure favorite de traitement de signaux radiofréquences échantillonnés en temps discret.
1. Aspects historiques
Après plusieurs mises en contexte de la recherche sur les ions et l’état exotique de la matière dans des situations aussi variées que les premières étapes de l’expansion de l’univers aux étoiles les plus denses, sujets d’étude de GSI [2, 3], la parole fut donnée à Eric Blossom (Fig. 2), créateur de la première version de GNU Radio [4]. Son travail, hérité d’un premier travail mené au MIT nommé pspectra dont les sources ont maintenant disparu, fut poursuivi sous les auspices bienveillants de John Gilmore, fondateur de l’EFF. Eric insiste sur l’aspect collaboratif du travail qui passe par des relations personnelles autant que sur des aspects techniques, et décrit l’évolution de ses collaborations au cours de développement de GNU Radio et en particulier la nécessité de trouver un financement pérenne – potentiellement étatique, mais aussi de mécénat – pour développer un projet aussi imposant qu’une infrastructure de radio logicielle qu’un bénévole, aussi motivé fût-il, ne pourrait probablement pas mener à terme. Eric est désormais employé par Planet Labs [5], société qui lance des essaims de satellites en orbite basse pour la prise de vues depuis l’espace : la radio logicielle n’a pas encore sa place sur les véhicules spatiaux, mais deux présentations portent sur le prototypage rapide de stations au sol pour la réception de signaux venus de l’espace [6, 7].
Du point de vue de GSI/FAIR, l’intérêt pour la radio logicielle vient de l’ambition de surveiller l’accélérateur en temps réel, notamment par la signature électromagnétique des ions en mouvement, et réagir à des événements. Une dichotomie est mise en évidence entre le principe sous-jacent de la radio logicielle et de GNU Radio en particulier qu’est le flux continu de données acquises par le convertisseur analogique numérique – mode streaming – et l’encapsulation d’informations dans des paquets disjoints. La gestion des paquets – PDU pour Protocol Data Unit – a été ajoutée de façon quelque peu ad hoc dans GNU Radio et la refonte de GNU Radio 4 vise à corriger une telle déficience. Dans le cas de GSI, un PDU est la détection d’un événement qu’il faut propager le long de la chaîne de traitement. Dans le cas d’une communication numérique, il s’agit de la détection du préambule d’un paquet, par exemple par son mot de synchronisation, qui déclenche le décodage de l’entête qui contient les informations pour ensuite décoder le contenu du message. GNU Radio 4 étend le PDU à tout type de structure, dont la valeur scalaire (entier, réel ou complexe) n’est qu’un cas particulier, et intègre donc naturellement le concept de paquet. Cette dichotomie entre stream de GNU Radio et paquets a aussi été mise en évidence dans le lien entre RFNoC qu’utilise Ettus Research pour router des paquets d’informations entre blocs de traitement au sein du FPGA chargé de l’acquisition des données et potentiellement utilisé comme co-processeur, et GNU Radio.
L'équipe de GSI insiste sur une utilisation des toutes dernières moutures du C++ en exploitant les templates dans un objectif de vitesse en optimisant le code au travers des blocs individuels de traitement et en visant à tirer le meilleur parti des instructions SIMD par le processeur, et non par une bibliothèque dédiée telle que le propose VOLK actuellement. Cette approche, bien que démontrant d’excellentes performances en termes de temps d’exécution [1], présente pour le moment un inconvénient rédhibitoire : toute la chaîne de traitement doit être recompilée à chaque modification, et compte tenu du nombre d’optimisations possibles en observant ce qui se passe dans l’ensemble de la chaîne et pas juste dans chaque bloc individuel, ainsi que la multiplication des types de variables supportés par types polymorphes (PMT), la compilation s’avère très longue, de plusieurs minutes à plusieurs dizaines de minutes. Cet aspect pourrait passer anodin, si ce n’est que GNU Radio est promu comme un environnement de prototypage rapide et interactif : modifier un paramètre de bloc et relancer le traitement dans GNU Radio Companion est instantané lors de la génération du code Python qui instancie les bibliothèques contenant les méthodes de chaque bloc de traitement. Ce problème devra être réglé pour que GNU Radio 4 soit exploitable : des pistes pourraient venir de LLVM avec Clang qui met moins de la moitié du temps de compilation que GCC pour un exécutable au moins aussi rapide, mais trop long pour considérer le développement de la chaîne de traitement comme interactif. Le lien entre C++ et Python, tel qu’il existe aujourd’hui dans GNU Radio 3.x, fournira une capacité d’intégrer les blocs de traitement sous forme de greffons précompilés et retrouver l’interactivité actuelle. Les auteurs de GNU Radio 4.0 nous informent que désactiver les diverses optimisations et analyses statiques de code permet d’abaisser le temps de compilation sous la barre des 2 minutes.
Parmi les bénéfices de la refonte du code au cœur de GNU Radio avec la proposition de la version 4 :
- accélération de la gestion des tampons et de la vitesse de calcul en général, notamment par une utilisation efficace de SIMD ;
- transition d’un traitement en flux tendu vers un traitement par paquets ;
- organisation du code pour permettre une reconfiguration par le développeur de la stratégie d’ordonnancement selon divers critères (débit, latences, prise en compte des ressources matérielles). Les auteurs de GNU Radio 4.0 prévoient d’ouvrir un concours pour sélectionner le meilleur ordonnanceur ;
- intégration aisée dans tout matériel, indépendant d’une dépendance à un fournisseur spécifique, et en particulier en visant les applications embarquées, même en l’absence de système d’exploitation ;
- exploitation des dernières évolutions du C++ pour produire un code plus « propre » visant une meilleure accessibilité aux utilisateurs et développeurs de modules hors cœur (Out Of Tree modules) ;
et ce, avec une diffusion des codes en suivant la philosophie promue par la FSFE (Free Software Foundation Europe) de Public Money, Public Code [8] par des auteurs financés par un institut de recherche public (Fig. 3).
Les développeurs de GNU Radio 4.0 envisagent de passer en licence LGPL dans l’espoir d’attirer des utilisateurs et donc potentiellement des contributeurs de sociétés privées. Cette ouverture des logiciels libres vers les acteurs privés ne me semble pas souhaitable. En effet, il me semble que cette idée que des sociétés privées – et en particulier du complexe militaro-industriel français – vont contribuer à du logiciel libre me paraît non seulement naïve et contraire aux observations, mais dangereuses pour le logiciel libre puisque la société privée s’approprie les quelques projets qui ont péniblement émergé, pour suffisamment en modifier l’API ou le protocole pour garantir un monopole et une incompatibilité avec la solution originale qui va être noyée dans le marketing faute de ressources d’une communauté de libristes obsédés par la technique, tel que nous le constatons par exemple pour White Rabbit. Une GPLv3 garantit au moins la protection de la FSF (https://en.wikipedia.org/wiki/Free_Software_Foundation,_Inc._v._Cisco_Systems,_Inc.), quitte à repousser les contributeurs privés, qui sont de toute façon peu enclins à participer activement à des développements libres. On notera que GSI/FAIR – comme nombre d’accélérateurs de particules et détecteurs distribués de rayons cosmiques – est contributeur et développeur de plateformes White Rabbit dédiées à leur contrôle de l’accélérateur sous forme de cartes PCIe. Les développeurs autour de Dietrich Beck ont eu la gentillesse de me prêter gracieusement certaines de ces cartes pour que je puisse illustrer le bénéfice mutuel de GNU Radio et White Rabbit pour former un système distribué cohérent et synchrone de génération et d’acquisition de signaux radiofréquences, démontré avec la mesure de direction d’arrivée de signaux issus du RADAR GRAVES et réfléchis par des avions, depuis un site situé à une quarantaine de kilomètres de l’émetteur [9].
Josh Morman, président actuel de GNU Radio, fait un récapitulatif de l’état d’avancement du logiciel [10], avec la promesse de maintenir 3.10 aussi longtemps que nécessaire tant que 4 ne sera pas utilisable (Fig. 4) et que les blocs de traitement actuels n’auront pas été implémentés pour la nouvelle version, puisque rien n’est compatible, de l’API existante aux chaînes décrites pour le moment en YAML dans GNU Radio Companion. GSI dédie actuellement du personnel à ce projet, mais en vue de répondre aux besoins de l’accélérateur : la communauté de développeurs devra mettre la main à la pâte pour obtenir les liens vers Python ou une interface graphique comparable à GNU Radio Companion. En vue d’évaluer l’utilisation de GNU Radio 4.0, l’auteur expérimenté qu’est Daniel Estévez est financé pour démontrer le gain en débit d’un radio-modem numérique sous GNU Radio 4.0 et fait part de son expérience [11].
2. Tutoriels
Pour entrer dans des considérations plus techniques, l’auteur de cette prose a été sollicité pour introduire GNU Radio 3.10 aux non-développeurs de la conférence, et en particulier les chercheurs et ingénieurs de GSI qui auraient entendu parler du logiciel sans s’en être approprié les concepts et le maniement. Il est intéressant de noter que le changement de paradigme qui semblait avoir repoussé certains de ces utilisateurs est le passage au traitement d’un flux continu de données par des blocs agencés séquentiellement, plutôt que par un programme statique bouclant sur des paquets d’éléments acquis par une interface de conversion analogique numérique. Ainsi, l’objectif était d’attirer des utilisateurs qui connaissent déjà la programmation Python, qui post-traitent déjà des fichiers de données, mais cette fois les amener à du traitement temps réel bénéficiant de la mise en forme et du prétraitement par une chaîne GNU Radio.
Après une rapide introduction des concepts de base – couleurs associées aux types de données transmises entre blocs de traitement, échantillonnage en temps discret, tension imaginaire et fréquence négative, repliement spectral – nous avons abordé trois types d’interaction de GNU Radio avec Python :
- L’insertion de quelques lignes de code Python dans la chaîne de traitement produite par GNU Radio Companion.
- L’insertion d’un code conséquent Python dans le code source produit par GNU Radio Companion.
- Le traitement du flux IQ par un bloc de traitement écrit en Python.
Ces trois points définissent la séquence des sections qui suivent pour en développer les principes.
2.1 Python Snippet
Le premier cas est le plus simple : nous voulons afficher la longueur d’un vecteur lors de l’exécution d’une chaîne de traitement. Considérons le cas trivial d’un filtre passe-bas (Fig. 5) : ce filtre est caractérisé par une fréquence de coupure et une bande de transition. La fréquence de coupure se comprend bien – la fréquence à laquelle l’amplitude du signal transmis par le filtre commence à décroître – mais qu’est-ce que la bande de transition ? Il s’agit d’un paramètre, que nous noterons δ f, qui détermine à quel écart de la fréquence de coupure l’amplitude du signal transmis par le filtre doit avoir baissé. Un utilisateur naïf pourrait se dire que le signal doit passer « instantanément » d’une fonction de transfert passante (amplitude unitaire) à coupante (amplitude nulle). Un tel filtre ne peut exister, ou nécessite un nombre infini de coefficients. De toute façon, GNU Radio Companion nous insulte si nous choisissons une bande de transition nulle en disant IndexError: firdes check failed: transition_width > 0. Comment donc choisir δ f ?
L’argumentaire est le suivant : si nous définissons une bande de transition δ f, il faut que la transformée de Fourier puisse déterminer l’amplitude à une fréquence f et une fréquence adjacente f+δ f, donc avoir une résolution spectrale d’au moins δ f. Une transformée de Fourier d’un signal temporel sur N points donne un signal dans le domaine spectral sur N points aussi, dans une gamme de fréquences s’étendant de −fs/2 à +fs/2−fs/N avec fs la fréquence d’échantillonnage en temps discret du signal. Nous approximerons pour cette discussion la borne supérieure à +fs/2 en supposant N grand. Ainsi, la résolution spectrale du spectre est fs/N, et cette résolution doit être au moins δ f, ou en d’autres termes N>fs/δ f. Nous voyons que si fs est petit, N va devenir démesurément grand. Or, l’expression temporelle d’un filtre, défini par son gabarit dans le domaine spectral, est un filtre à réponse impulsionnelle finie (FIR) reliant sortie y avec valeurs passées des entrées x par
et il s’agit bien du même N que précédemment par bijection de la transformée de Fourier. Ainsi donc, lorsque nous exprimons un filtre, chaque échantillon de sortie nécessite N multiplications, et on voit bien que choisir N trop grand, ou δ f trop petit, va nécessiter trop de ressources de calcul, même sur un processeur moderne.
Ainsi donc, nous affirmons que GNU Radio choisit N le nombre de coefficients de l’ordre de fs/δ f, et nous voulons le vérifier expérimentalement.
Pour ce faire (Fig. 5), nous affichons l’identifiant (arbitraire) attribué par GNU Radio Companion à chaque bloc (View → Show All Block IDs) afin de connaître le nom de la variable attribué au filtre passe-bas, et sachant que la classe attribuée aux filtres passe-bas contient une méthode taps() pour obtenir les coefficients de pondération bk, nous désirons print(len(self.low_pass_filter_0.taps())). Cependant, si nous insérons cette expression dans le code Python produit par GNU Radio Companion, la procédure est irréversible et ne permet pas de revenir à une modification sur l’interface graphique, ou la régénération du code Python depuis l’interface graphique va effacer notre ajout.
La solution est d’insérer un Python Snippet dont l’expression Python ci-dessus est insérée dans la Section of Flowgraph: Main -- After Start. Ainsi, le code Python est appelé après initialisation des variables, et en choisissant une bande de transition égale à samp_rate/128 dans le filtre passe-bas, nous sommes informés que le nombre de coefficients est 309. Si nous divisons par 10 la bande de transition pour choisir samp_rate/1280, nous constatons que le nombre de coefficients croît bien à 3083 donc d’un facteur 10, la théorie est vérifiée.
2.2 Python Module
Il est fondamental de comprendre que les Python Snippets et Python Modules ne peuvent pas accéder aux données IQ à traiter, mais ne peuvent qu’agir sur le comportement des blocs de traitement et les variables qui en définissent le comportement. Afin de pouvoir interagir avec les données radiofréquences, il faut créer un Python Block (section suivante). Néanmoins, le Python Module peut être fort utile : prenons l’exemple d’un thread exécuté en parallèle de l’ordonnanceur de l’interface graphique QT, lancé lors d’une chaîne de traitement produit par GNU Radio Companion en mode QT GUI. Ce code peut contenir une fonction aussi complexe que nous le désirons, faisant appel à autant de classes que nécessaire, et être lancé depuis le Python Snippet que nous venons de voir sous forme de thread indépendant de l’exécution du père (Fig. 6).
2.3 Python Block
Les utilisateurs au GSI/FAIR (Fig. 7) de GNU Radio analysent la distribution des vitesses des ions dans la boucle de stockage en observant les signaux issus d’antennes placées à proximité des particules en mouvement [13]. Leur objectif est d’avoir une distribution aussi uniforme que possible : comme toute particule chargée en mouvement émet un champ électromagnétique, la distribution des fréquences sur le spectre des signaux acquis est directement représentative de la distribution des vitesses. L’objectif serait donc d’avoir une distribution aussi resserrée que possible. Comme la fonction qui se représente avec le moins de paramètres (de « moments ») est la gaussienne, il nous est demandé s’il est possible d’ajuster les paramètres que sont l’amplitude A, la moyenne µ et l’écart type σ de la gaussienne
connaissant les observations aux abscisses x. Afin de démontrer ce principe, nous produisons une distribution gaussienne pour effectuer nos développements, non pas sur un spectre en fréquences, mais sur les amplitudes d’un bruit caractérisé par AWGN (Additive White Gaussian Noise) dans lequel toutes les fréquences sont représentées avec la même puissance (« bruit ») avec une distribution d’amplitudes qui suit une distribution gaussienne. Cette distribution est proposée dans GNU Radio sous la forme du Noise Source, ce dont nous pouvons nous convaincre en observant sur un Histogram Sink la distribution des amplitudes (Fig. 8). Un point de départ nous est fourni par Shahab Sanjari avec son dépôt https://github.com/xaratustrah/curve-fitting/blob/main/curve_fit.py qu’il utilise actuellement en post-traitement et désire insérer dans la chaîne d’analyse en temps réel GNU Radio.
Le tutoriel https://wiki.gnuradio.org/index.php?title=Creating_Your_First_Block et le motif (template) de bloc de traitement sont limpides et permettent de rapidement commencer le développement, si ce n’est que pour pouvoir tracer un histogramme, il faut avoir accumulé un nombre minimum de points avant de pouvoir remplir les cases correspondant aux différentes valeurs possibles d’amplitudes. Afin de garantir un nombre minimum de points, nous convertissons le flux continu de données (stream) en un vecteur de longueur correspondant au nombre de points que nous désirons distribuer dans les cases de l’histogramme. Un second tutoriel https://wiki.gnuradio.org/index.php?title=Python_Block_with_Vectors indique comment fournir au bloc des entrées qui ne sont pas scalaires, mais des vecteurs sous la forme de in_sig=[(np.float32,vectorSize)]. De cette façon, le flux de données acquis par la fonction work exécutée en boucle infinie est une structure à trois dimensions telle que le démontre
qui indique 8 1024 8192 qui s’interprète comme :
- input_items[0], car nous avons une entrée. Si le bloc avait plusieurs entrées, cet indice indiquerait de quelle entrée il s’agit ;
- input_items[0][k] indique le k-ième vecteur, puisque l’ordonnanceur GNU Radio n’a aucune raison de nous fournir un seul vecteur, mais peut avoir accumulé suffisamment de points en amont pour fournir plusieurs vecteurs ;
- input_items[0][k][m] est le m-ième point du k-ième vecteur. Cependant, chaque vecteur contient bien les 1024 points requis par la conversion de stream en vector en amont de ce bloc dédié.
Une fois cette structure comprise, la suite est limpide. Nous calculons l’histogramme des points en entrée supposés dans l’intervalle [−1, +1] au moyen de Numpy par
puis effectuons l’ajustement gaussien avec la fonction définie dans fit_function() des mesures issues de l’histogramme. Seule subtilité, comme les intervalles et les piquets, le vecteur x issu de np.histogram() contient les extrémités de chaque classe, donc n+1 valeurs s’il y a n classes. Nous déduisons la valeur moyenne de chaque classe comme x=0.5*(x[0:-1]+x[1:]) qui a bien n valeurs comme y. Finalement, nous affichons l’amplitude, la valeur moyenne et l’écart type, et renvoyons pour traitement ultérieur ce dernier paramètre qui alimente dans notre chaîne de traitement un QT GUI Number Sink.
Le lecteur qui exécute ce code pourra se convaincre que la valeur moyenne introduite par le bloc Add Const est bien identifiée dans le second paramètre µ de l’ajustement, tandis que l’« amplitude » telle que l’appelle ce paramètre du bloc source de bruit est bien identifiée par l’écart type. Seule petite subtilité : l’écart type σ n’apparaît que par son carré dans l’équation d’ajustement, et les deux solutions de σ positive ou négative sont parfois atteintes selon la nature du bruit et le cheminement de la descente de gradient. Puisque nous savons qu’un écart type est forcément positif, nous affichons la valeur absolue. Notez que nous ne fournissons pas ici le dernier paramètre optionnel que sont les conditions initiales – qui sont bien connues dans le cas d’une gaussienne comme valeur moyenne numpy.mean() et écart type numpy.std() – et par défaut le point de départ de la recherche de solution prend 1,0 pour tous les paramètres.
Le dernier paramètre qu’est l’amplitude de l’histogramme n’a pas d’intérêt et nous ne nous attarderons pas dessus – il est principalement dépendant du nombre de points analysés et de leur étalement dans les diverses classes de l’histogramme.
Conclusion
La radio logicielle, et GNU Radio en particulier, a vu son apogée autour de 2017 (Fig. 9), combinaison d’un environnement logiciel stable et simple de prise en main, et de matériel peu coûteux – récepteurs de télévision numérique terrestre RTL-SDR détournés de leur usage initial – permettant d’aborder nombre de protocoles de communication radiofréquences.
Sept ans plus tard, les contributions scientifiques et techniques s’épuisent, probablement parce que l’outil est devenu tellement courant et adopté qu’il ne mérite plus à être mentionné (qui cite l’utilisation d’un oscilloscope dans une mesure électronique ?). Pourtant, le développement de GNU Radio se poursuit, notamment pour tirer parti des dernières évolutions des plateformes de calcul hétérogènes, tentant d’aborder de façon transparente CPU généralistes, GPU et FPGA pour distribuer sur les ressources les plus appropriées les diverses étapes d’une chaîne de traitement. La cinquantaine de participants à la conférence a conclu les échanges sur les utilisations innovantes de la radio logicielle, même pour éventuellement détecter en temps réel un ion rare qu’il faut absolument capturer avant qu’il ne disparaisse. Les vidéos des présentations de la conférence sont disponibles sur le canal European GNU Radio Days sur YouTube à https://youtube.com/@europeangnuradiodays1445 dans la série « European GNU Radio Days 2024 » avec leurs transparents comme liens dans le programme à https://events.gnuradio.org/event/23/.
Remerciements
Cyrille Morin a relu les codes Python pour tenter d’en éliminer les plus grossières maladresses, mais toute erreur résiduelle ne peut être imputée qu’à l’auteur de ces lignes.
Références
[1] GNU Radio 4.0 Developer Tutorials à
https://www.youtube.com/playlist?list=PLCfH8xIFcsLlkmVHKLjCr1UaYiMwewiFS
[2] J. Messchendorp, Pushing boundaries: femtoscale research with large-scale tech (in accelerator-driven nuclear physics), European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=66kqn-2W6I8
[3] J. Stadlmann, ... and one to accelerate them all, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=CiaVABVZ71U
[4] E. Blossom, GNU Radio: lessons from the past, recommendations for taking it to the Future, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=fMxardgX1Ao
[5] K. Devaraj, M. Ligon, E. Blossom & al., Planet high speed radio: Crossing Gbps from a 3U cubesat, Proc. Small Satellites (2019).
[6] C.G. Karaköse, Design and implementation of high-speed data link receiver with GNU Radio, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=jxqQcORWem4
[7] G. Ari Özcan, Design and Implementation of an Adaptive Data Rate LoRa Modem for LEO Satellites Using SD, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=Jc0aT4i2VaM
[8] https://wiki.fsfe.org/Activities/PMPC et https://publiccode.eum/
[9] J.-M Friedt, Distributed coherent SDR systems: GNU Radio rides the White Rabbit, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=iyUabco0z4A
[10] J. Morman, GNU Radio Project Overview and Update, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=89l9_7PitTE
[11] D. Estévez, gr4-packet-modem: a QPSK packet modem for GNU Radio 4.0, European GNU Radio Days (2024), vidéo à https://www.youtube.com/watch?v=1EPuhaIjxCk
[12] M.S. Sanjari & al., A 410 MHz resonant cavity pickup for heavy ion storage rings, Rev. Sci. Instrum. 91(8) 083303 (2020).
[13] P. Kienle, F. Bosch, P. Bühler, T. Faestermann, Yu A. Litvinov, N. Winckler, M. S. Sanjari & al., High-resolution measurement of the time-modulated orbital electron capture and of the β+ decay of hydrogen-like 142Pm60+ ions, Physics Letters B 726 (4-5) 638–645 (2013).