Skip to content

Commit

Permalink
Minor fixes related to SigMF (#47)
Browse files Browse the repository at this point in the history
* Update links to SigMF's GitHub

* Avoid deprecated functions
  • Loading branch information
ghykk authored Sep 16, 2024
1 parent 4421b4f commit 00f2caf
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 189 deletions.
66 changes: 35 additions & 31 deletions content-es/iq_files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ SigMF y Anotación de archivos IQ

Dado que el archivo IQ en sí no tiene ningún metadato asociado, es común tener un segundo archivo que contenga información sobre la señal, con el mismo nombre de archivo pero con .txt u otra extensión de archivo. Esto debe incluir, como mínimo, la frecuencia de muestreo utilizada para recopilar la señal y la frecuencia a la que se sintonizó el SDR. Después de analizar la señal, el archivo de metadatos podría incluir información sobre rangos de muestra de características interesantes, como ráfagas de energía. El índice de muestra es simplemente un número entero que comienza en 0 e incrementa cada muestra compleja. Si supiera que hay energía desde la muestra 492342 a la 528492, entonces podría leer el archivo y extraer esa parte de la matriz: :code:`samples[492342:528493]`.

Afortunadamente, ahora existe un estándar abierto que especifica un formato de metadatos utilizado para describir grabaciones de señales, conocido como `SigMF <https://github.com/gnuradio/SigMF>`_. Al utilizar un estándar abierto como SigMF, varias partes pueden compartir grabaciones de RF más fácilmente y utilizar diferentes herramientas para operar en los mismos conjuntos de datos, como `IQEngine <https://iqengine.org/sigmf>`_. También evita el "bitrot" de conjuntos de datos de RF donde los detalles de la captura se pierden con el tiempo debido a que los detalles de la grabación no se ubican con la grabación misma.
Afortunadamente, ahora existe un estándar abierto que especifica un formato de metadatos utilizado para describir grabaciones de señales, conocido como `SigMF <https://github.com/sigmf/SigMF>`_. Al utilizar un estándar abierto como SigMF, varias partes pueden compartir grabaciones de RF más fácilmente y utilizar diferentes herramientas para operar en los mismos conjuntos de datos, como `IQEngine <https://iqengine.org/sigmf>`_. También evita el "bitrot" de conjuntos de datos de RF donde los detalles de la captura se pierden con el tiempo debido a que los detalles de la grabación no se ubican con la grabación misma.

La forma más sencilla (y mínima) de utilizar el estándar SigMF para describir un archivo IQ binario que haya creado es cambiar el nombre del archivo .iq a .sigmf-data y crear un nuevo archivo con el mismo nombre pero con la extensión .sigmf-meta. y asegúrese de que el campo de tipo de datos en el metaarchivo coincida con el formato binario de su archivo de datos. Este metaarchivo es un archivo de texto sin formato lleno de json, por lo que simplemente puede abrirlo con un editor de texto y completarlo manualmente (más adelante discutiremos cómo hacerlo mediante programación). A continuación se muestra un archivo .sigmf-meta de ejemplo que puede utilizar como plantilla:

Expand Down Expand Up @@ -165,17 +165,16 @@ Si está capturando su grabación de RF desde Python, por ejemplo, utilizando la

.. code-block:: bash
cd ~
git clone https://github.com/gnuradio/SigMF.git
cd SigMF
sudo pip install .
pip install sigmf
El código Python para escribir el archivo .sigmf-meta para el ejemplo del comienzo de este capítulo, donde guardamos bpsk_in_noise.iq, se muestra a continuación:

.. code-block:: python
import numpy as np
import datetime as dt
import numpy as np
import sigmf
from sigmf import SigMFFile
# <code from example>
Expand All @@ -185,7 +184,7 @@ El código Python para escribir el archivo .sigmf-meta para el ejemplo del comie
# create the metadata
meta = SigMFFile(
data_file='example.sigmf-data', # extension is optional
data_file='bpsk_in_noise.sigmf-data', # extension is optional
global_info = {
SigMFFile.DATATYPE_KEY: 'cf32_le',
SigMFFile.SAMPLE_RATE_KEY: 8000000,
Expand All @@ -198,7 +197,7 @@ El código Python para escribir el archivo .sigmf-meta para el ejemplo del comie
# create a capture key at time index 0
meta.add_capture(0, metadata={
SigMFFile.FREQUENCY_KEY: 915000000,
SigMFFile.DATETIME_KEY: dt.datetime.utcnow().isoformat()+'Z',
SigMFFile.DATETIME_KEY: dt.datetime.now(dt.timezone.utc).isoformat(),
})
# check for mistakes and write to disk
Expand All @@ -224,7 +223,7 @@ Para leer una grabación SigMF en Python, utilice el siguiente código. En este
sample_count = signal.sample_count
signal_duration = sample_count / sample_rate
Para más detalles consulte `the SigMF documentation <https://github.com/gnuradio/SigMF>`_.
Para más detalles consulte `the SigMF Python documentation <https://github.com/sigmf/sigmf-python>`_.

Una pequeña ventaja para quienes hayan leído hasta aquí; El logotipo de SigMF en realidad se almacena como una grabación de SigMF y cuando la señal se traza como una constelación (gráfico IQ) a lo largo del tiempo, produce la siguiente animación:

Expand All @@ -233,13 +232,16 @@ Una pequeña ventaja para quienes hayan leído hasta aquí; El logotipo de SigMF
:align: center
:alt: The SigMF logo animation

El código Python utilizado para leer el archivo del logotipo (ubicado `aqui <https://github.com/gnuradio/SigMF/tree/master/logo>`_) y produzca el gif animado que se muestra a continuación, para aquellos curiosos:
El código Python utilizado para leer el archivo del logotipo (ubicado `aqui <https://github.com/sigmf/SigMF/tree/main/logo>`_) y produzca el gif animado que se muestra a continuación, para aquellos curiosos:

.. code-block:: python
from pathlib import Path
from tempfile import TemporaryDirectory
import numpy as np
import matplotlib.pyplot as plt
import imageio
import imageio.v3 as iio
from sigmf import SigMFFile, sigmffile
# Load a dataset
Expand All @@ -253,26 +255,28 @@ El código Python utilizado para leer el archivo del logotipo (ubicado `aqui <ht
sample_count = len(samples)
samples_per_frame = 5000
num_frames = int(sample_count/samples_per_frame)
filenames = []
for i in range(num_frames):
print("frame", i, "out of", num_frames)
# Plot the frame
fig, ax = plt.subplots(figsize=(5, 5))
samples_frame = samples[i*samples_per_frame:(i+1)*samples_per_frame]
ax.plot(np.real(samples_frame), np.imag(samples_frame), color="cyan", marker=".", linestyle="None", markersize=1)
ax.axis([-0.35,0.35,-0.35,0.35]) # keep axis constant
ax.set_facecolor('black') # background color
# Save the plot to a file
filename = '/tmp/sigmf_logo_' + str(i) + '.png'
fig.savefig(filename, bbox_inches='tight')
filenames.append(filename)
# Create animated gif
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('/tmp/sigmf_logo.gif', images, fps=20)
with TemporaryDirectory() as temp_dir:
filenames = []
output_dir = Path(temp_dir)
for i in range(num_frames):
print(f"frame {i} out of {num_frames}")
# Plot the frame
fig, ax = plt.subplots(figsize=(5, 5))
samples_frame = samples[i*samples_per_frame:(i+1)*samples_per_frame]
ax.plot(np.real(samples_frame), np.imag(samples_frame), color="cyan", marker=".", linestyle="None", markersize=1)
ax.axis([-0.35,0.35,-0.35,0.35]) # keep axis constant
ax.set_facecolor('black') # background color
# Save the plot to a file
filename = output_dir.joinpath(f"sigmf_logo_{i}.png")
fig.savefig(filename, bbox_inches='tight')
plt.close()
filenames.append(filename)
# Create animated gif
images = [iio.imread(f) for f in filenames]
iio.imwrite('sigmf_logo.gif', images, fps=20)
66 changes: 35 additions & 31 deletions content-fr/iq_files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ SigMF et l'annotation des fichiers IQ

Comme le fichier IQ lui-même n'est associé à aucune métadonnée, il est courant d'avoir un second fichier contenant des informations sur le signal, portant le même nom de fichier mais une extension .txt ou autre. Ces informations devraient au minimum inclure la fréquence d'échantillonnage utilisée pour collecter le signal, et la fréquence sur laquelle le SDR était accordé. Après l'analyse du signal, le fichier de métadonnées peut inclure des informations sur les plages d'échantillonnage des caractéristiques intéressantes, telles que les rafales d'énergie. L'index d'échantillon est simplement un nombre entier qui commence à 0 et s'incrémente à chaque échantillon complexe. Si vous savez qu'il y a de l'énergie entre les échantillons 492342 et 528492, vous pouvez lire le fichier et extraire cette partie du tableau : :code:`samples[492342:528493]`.

Heureusement, il existe désormais une norme ouverte qui spécifie un format de métadonnées utilisé pour décrire les enregistrements de signaux, connue sous le nom de `SigMF <https://github.com/gnuradio/SigMF>`_. En utilisant une norme ouverte comme SigMF, de multiples parties peuvent partager des enregistrements RF plus facilement, et utiliser différents outils pour opérer sur les mêmes ensembles de données. Cela permet également d'éviter le "bitrot" des ensembles de données RF où les détails de la capture sont perdus au fil du temps en raison de détails de l'enregistrement qui ne sont pas colocalisés avec l'enregistrement lui-même.
Heureusement, il existe désormais une norme ouverte qui spécifie un format de métadonnées utilisé pour décrire les enregistrements de signaux, connue sous le nom de `SigMF <https://github.com/sigmf/SigMF>`_. En utilisant une norme ouverte comme SigMF, de multiples parties peuvent partager des enregistrements RF plus facilement, et utiliser différents outils pour opérer sur les mêmes ensembles de données. Cela permet également d'éviter le "bitrot" des ensembles de données RF où les détails de la capture sont perdus au fil du temps en raison de détails de l'enregistrement qui ne sont pas colocalisés avec l'enregistrement lui-même.
La façon la plus simple (et minimale) d'utiliser le standard SigMF pour décrire un fichier IQ binaire que vous avez créé est de renommer le fichier .iq en .sigmf-data et de créer un nouveau fichier avec le même nom mais l'extension .sigmf-meta, et de s'assurer que le champ datatype dans le méta-fichier correspond au format binaire de votre fichier de données. Ce fichier méta est un fichier en texte clair rempli de json, vous pouvez donc simplement l'ouvrir avec un éditeur de texte et le remplir manuellement (nous verrons plus tard comment le faire de manière automatique). Voici un exemple de fichier .sigmf-meta que vous pouvez utiliser comme modèle :

.. code-block::
Expand Down Expand Up @@ -159,17 +159,16 @@ Si vous capturez votre enregistrement RF à partir de Python, par exemple en uti

.. code-block:: bash
cd ~
git clone https://github.com/gnuradio/SigMF.git
cd SigMF
sudo pip install .
pip install sigmf
Le code Python permettant d'écrire le fichier .sigmf-meta pour l'exemple du début de ce chapitre, où nous avons enregistré bpsk_in_noise.iq, est présenté ci-dessous :

.. code-block:: python
import numpy as np
import datetime as dt
import numpy as np
import sigmf
from sigmf import SigMFFile
# <code pour exemple>
Expand All @@ -179,7 +178,7 @@ Le code Python permettant d'écrire le fichier .sigmf-meta pour l'exemple du dé
# crérer les metadata
meta = SigMFFile(
data_file='example.sigmf-data', # extension optionalle
data_file='bpsk_in_noise.sigmf-data', # extension optionalle
global_info = {
SigMFFile.DATATYPE_KEY: 'cf32_le',
SigMFFile.SAMPLE_RATE_KEY: 8000000,
Expand All @@ -192,7 +191,7 @@ Le code Python permettant d'écrire le fichier .sigmf-meta pour l'exemple du dé
# créer une clé de capture à l'index temporel 0
meta.add_capture(0, metadata={
SigMFFile.FREQUENCY_KEY: 915000000,
SigMFFile.DATETIME_KEY: dt.datetime.utcnow().isoformat()+'Z',
SigMFFile.DATETIME_KEY: dt.datetime.now(dt.timezone.utc).isoformat(),
})
# vérifier les erreurs et écrire sur le disque
Expand All @@ -218,21 +217,24 @@ Pour lire un enregistrement SigMF dans Python, utilisez le code suivant. Dans c
sample_count = signal.sample_count
signal_duration = sample_count / sample_rate
Pour plus de détails, voir la référence `the SigMF documentation <https://github.com/gnuradio/SigMF>`_.
Pour plus de détails, voir la référence `the SigMF Python documentation <https://github.com/sigmf/sigmf-python>`_.

Un petit bonus pour ceux qui ont lu jusqu'ici: le logo SigMF est en fait stocké comme un enregistrement SigMF lui-même, et quand le signal est tracé comme une constellation (IQ plot) dans le temps, il produit l'animation suivante :

.. image:: ../_images/sigmf_logo.gif
:scale: 100 %
:align: center

Le code Python utilisé pour lire le fichier du logo (situé `ici <https://github.com/gnuradio/SigMF/tree/master/logo>`_) et produire le gif animé ci-dessus est présenté ci-dessous, pour les curieux :
Le code Python utilisé pour lire le fichier du logo (situé `ici <https://github.com/sigmf/SigMF/tree/main/logo>`_) et produire le gif animé ci-dessus est présenté ci-dessous, pour les curieux :

.. code-block:: python
from pathlib import Path
from tempfile import TemporaryDirectory
import numpy as np
import matplotlib.pyplot as plt
import imageio
import imageio.v3 as iio
from sigmf import SigMFFile, sigmffile
# charger les données
Expand All @@ -246,26 +248,28 @@ Le code Python utilisé pour lire le fichier du logo (situé `ici <https://githu
sample_count = len(samples)
samples_per_frame = 5000
num_frames = int(sample_count/samples_per_frame)
filenames = []
for i in range(num_frames):
print("frame", i, "out of", num_frames)
# tracer le cadre
fig, ax = plt.subplots(figsize=(5, 5))
samples_frame = samples[i*samples_per_frame:(i+1)*samples_per_frame]
ax.plot(np.real(samples_frame), np.imag(samples_frame), color="cyan", marker=".", linestyle="None", markersize=1)
ax.axis([-0.35,0.35,-0.35,0.35]) # garder les axes existants
ax.set_facecolor('black') # couleur d'arrière plan
# Enregister la figure dans un fichier
filename = '/tmp/sigmf_logo_' + str(i) + '.png'
fig.savefig(filename, bbox_inches='tight')
filenames.append(filename)
# Créer un gif animé
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('/tmp/sigmf_logo.gif', images, fps=20)
with TemporaryDirectory() as temp_dir:
filenames = []
output_dir = Path(temp_dir)
for i in range(num_frames):
print(f"frame {i} out of {num_frames}")
# tracer le cadre
fig, ax = plt.subplots(figsize=(5, 5))
samples_frame = samples[i*samples_per_frame:(i+1)*samples_per_frame]
ax.plot(np.real(samples_frame), np.imag(samples_frame), color="cyan", marker=".", linestyle="None", markersize=1)
ax.axis([-0.35,0.35,-0.35,0.35]) # garder les axes existants
ax.set_facecolor('black') # couleur d'arrière plan
# Enregister la figure dans un fichier
filename = output_dir.joinpath(f"sigmf_logo_{i}.png")
fig.savefig(filename, bbox_inches='tight')
plt.close()
filenames.append(filename)
# Créer un gif animé
images = [iio.imread(f) for f in filenames]
iio.imwrite('sigmf_logo.gif', images, fps=20)
Loading

0 comments on commit 00f2caf

Please sign in to comment.