diff --git a/content-es/iq_files.rst b/content-es/iq_files.rst index 6cbe2a6..4725ce6 100644 --- a/content-es/iq_files.rst +++ b/content-es/iq_files.rst @@ -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 `_. 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 `_. 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 `_. 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 `_. 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: @@ -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 # @@ -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, @@ -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 @@ -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 `_. +Para más detalles consulte `the SigMF Python documentation `_. 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: @@ -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 `_) 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 `_) 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 @@ -253,26 +255,28 @@ El código Python utilizado para leer el archivo del logotipo (ubicado `aqui `_. 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 `_. 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:: @@ -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 # @@ -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, @@ -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 @@ -218,7 +217,7 @@ 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 `_. +Pour plus de détails, voir la référence `the SigMF Python documentation `_. 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 : @@ -226,13 +225,16 @@ Un petit bonus pour ceux qui ont lu jusqu'ici: le logo SigMF est en fait stocké :scale: 100 % :align: center -Le code Python utilisé pour lire le fichier du logo (situé `ici `_) 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 `_) 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 @@ -246,26 +248,28 @@ Le code Python utilisé pour lire le fichier du logo (situé `ici `_. By using an open standard like SigMF, multiple parties can share RF recordings more easily, and use different tools to operate on the same datasets, such as `IQEngine `_. It also prevents "bitrot" of RF datasets where details of the capture are lost over time due to details of the recording not being collocated with the recording itself. +Luckily, there is now an open standard that specifies a metadata format used to describe signal recordings, known as `SigMF `_. By using an open standard like SigMF, multiple parties can share RF recordings more easily, and use different tools to operate on the same datasets, such as `IQEngine `_. It also prevents "bitrot" of RF datasets where details of the capture are lost over time due to details of the recording not being collocated with the recording itself. The most simple (and minimal) way to use the SigMF standard to describe a binary IQ file you have created is to rename the .iq file to .sigmf-data and create a new file with the same name but .sigmf-meta extension, and make sure the datatype field in the meta file matches the binary format of your data file. This meta file is a plaintext file filled with json, so you can simply open it with a text editor and fill it out manually (later we will discuss doing this programmatically). Here is an example .sigmf-meta file you can use as a template: @@ -165,17 +165,16 @@ If you are capturing your RF recording from within Python, e.g., using the Pytho .. code-block:: bash - cd ~ - git clone https://github.com/gnuradio/SigMF.git - cd SigMF - sudo pip install . + pip install sigmf The Python code to write the .sigmf-meta file for the example towards the beginning of this chapter, where we saved bpsk_in_noise.iq, is shown below: .. code-block:: python - import numpy as np import datetime as dt + + import numpy as np + import sigmf from sigmf import SigMFFile # @@ -185,7 +184,7 @@ The Python code to write the .sigmf-meta file for the example towards the beginn # 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, @@ -198,7 +197,7 @@ The Python code to write the .sigmf-meta file for the example towards the beginn # 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 @@ -224,7 +223,7 @@ To read in a SigMF recording into Python, use the following code. In this examp sample_count = signal.sample_count signal_duration = sample_count / sample_rate -For more details reference `the SigMF documentation `_. +For more details reference `the SigMF Python documentation `_. A little bonus for those who read this far; the SigMF logo is actually stored as a SigMF recording itself, and when the signal is plotted as a constellation (IQ plot) over time, it produces the following animation: @@ -233,13 +232,16 @@ A little bonus for those who read this far; the SigMF logo is actually stored as :align: center :alt: The SigMF logo animation -The Python code used to read in the logo file (located `here `_) and produce the animated gif above is shown below, for those curious: +The Python code used to read in the logo file (located `here `_) and produce the animated gif above is shown below, for those curious: .. 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 @@ -253,26 +255,28 @@ The Python code used to read in the logo file (located `here `_. Використовуючи відкритий стандарт, такий як SigMF, різні сторони можуть легше обмінюватися записами радіосигналів і використовувати різні інструменти для роботи з тими самими наборами даних, такі як `IQEngine `__. Це також запобігає "бітротству" наборів радіочастотних даних, коли деталі захоплення втрачаються з часом через те, що деталі запису не співпадають із самим записом. +На щастя, зараз існує відкритий стандарт, який визначає формат метаданих для опису записів сигналів, відомий як `SigMF `_. Використовуючи відкритий стандарт, такий як SigMF, різні сторони можуть легше обмінюватися записами радіосигналів і використовувати різні інструменти для роботи з тими самими наборами даних, такі як `IQEngine `__. Це також запобігає "бітротству" наборів радіочастотних даних, коли деталі захоплення втрачаються з часом через те, що деталі запису не співпадають із самим записом. Найпростіший (і мінімальний) спосіб використання стандарту SigMF для опису створеного вами бінарного IQ-файлу - перейменувати файл .iq на .sigmf-data і створити новий файл з тим самим ім'ям, але з розширенням .sigmf-meta, і переконатися, що поле типу даних у метафайлі відповідає бінарному формату вашого файлу даних. Цей метафайл є звичайним текстовим файлом, заповненим json, тому ви можете просто відкрити його за допомогою текстового редактора і заповнити вручну (пізніше ми обговоримо, як зробити це програмно). Ось приклад .sigmf-meta файлу, який ви можете використовувати як шаблон: @@ -165,17 +165,16 @@ SigMF та анотування IQ файлів .. code-block:: bash - cd ~ - git clone https://github.com/gnuradio/SigMF.git - cd SigMF - sudo pip install . + pip install sigmf Нижче наведено код Python для написання файлу .sigmf-meta для прикладу на початку цієї глави, куди ми зберегли bpsk_in_noise.iq: .. code-block:: python - import numpy as np import datetime as dt + + import numpy as np + import sigmf from sigmf import SigMFFile # <код з прикладу @@ -185,12 +184,12 @@ SigMF та анотування IQ файлів # створюємо метадані meta = SigMFFile( - data_file='example.sigmf-data', # розширення необов'язкове + data_file='bpsk_in_noise.sigmf-data', # extension is optional global_info = { SigMFFile.DATATYPE_KEY: 'cf32_le', SigMFFile.SAMPLE_RATE_KEY: 8000000, - SigMFFile.AUTHOR_KEY: 'Ваше ім'я та/або email', - SigMFFile.DESCRIPTION_KEY: 'Імітація BPSK з шумом', + SigMFFile.AUTHOR_KEY: 'Your name and/or email', + SigMFFile.DESCRIPTION_KEY: 'Simulation of BPSK with noise', SigMFFile.VERSION_KEY: sigmf.__version__, } ) @@ -198,7 +197,7 @@ SigMF та анотування IQ файлів # створити ключ захоплення з часовим індексом 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(), }) # перевірка на помилки та запис на диск @@ -224,7 +223,7 @@ SigMF та анотування IQ файлів sample_count = signal.sample_count signal_duration = sample_count / sample_rate -За більш детальною інформацією зверніться до `документації SigMF `_. +За більш детальною інформацією зверніться до `документації SigMF Python `_. Невеликий бонус для тих, хто дочитав до цього місця: логотип SigMF фактично зберігається як сам запис SigMF, і коли сигнал будується у вигляді сузір'я (IQ-діаграма) у часі, він створює наступну анімацію: @@ -233,13 +232,16 @@ SigMF та анотування IQ файлів :align: center :alt: Анімація логотипу SigMF -Код на Python, який використовується для зчитування файлу логотипу (розташованого `тут `_) і створення анімованого gif-файлу, показано нижче, для тих, кому цікаво: +Код на Python, який використовується для зчитування файлу логотипу (розташованого `тут `_) і створення анімованого gif-файлу, показано нижче, для тих, кому цікаво: .. 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 # Завантажуємо набір даних @@ -253,26 +255,28 @@ SigMF та анотування IQ файлів 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) - # Побудувати графік кадру - 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]) # зберігаємо вісь постійною - ax.set_facecolor('black') # колір фону - - # Зберегти графік у файл - filename = '/tmp/sigmf_logo_' + str(i) + '.png' - fig.savefig(filename, bbox_inches='tight') - filenames.append(filename) - - # Створюємо анімований 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}") + # Побудувати графік кадру + 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]) # зберігаємо вісь постійною + ax.set_facecolor('black') # колір фону + + # Зберегти графік у файл + filename = output_dir.joinpath(f"sigmf_logo_{i}.png") + fig.savefig(filename, bbox_inches='tight') + plt.close() + filenames.append(filename) + + # Створюємо анімований gif + images = [iio.imread(f) for f in filenames] + iio.imwrite('sigmf_logo.gif', images, fps=20) diff --git a/content-zh/iq_files.rst b/content-zh/iq_files.rst index b69d4b8..316fe45 100644 --- a/content-zh/iq_files.rst +++ b/content-zh/iq_files.rst @@ -195,7 +195,7 @@ SigMF 与 IQ 文件标注 索引是一个从 0 递增的整数,唯一对应到一个位置上递增的采样点(即一个复数)。 比如,假设你知道从第 492342 个样本点到第 528492 个样本点之间有能量,那么你可以读取文件后直接提取对应数组::code:`samples[492342:528493]`。 -幸运的是,目前已经有了针对信号记录的元数据格式的开放标准,称为 `SigMF `_ 。 +幸运的是,目前已经有了针对信号记录的元数据格式的开放标准,称为 `SigMF `_ 。 通过使用 SigMF 这样的开放标准,多方可以更轻松地共享 RF 记录,并使用不同的工具来操作相同的数据集,例如 `IQEngine `_ 。 它还可以防止 RF 数据集的 “位腐烂(Bitrot)”:随着时间的推移,由于一些细节没有与记录本身放在一起,这些细节就因为遗忘而丢失掉了,只能重新花力气和时间分析。 @@ -238,17 +238,16 @@ SigMF 与 IQ 文件标注 .. code-block:: bash - cd ~ - git clone https://github.com/gnuradio/SigMF.git - cd SigMF - sudo pip install . + pip install sigmf 借助这个包,为本章开头部分的例子(当时,我们把信号保存在了 :code:`qpsk_in_noise.iq` 文件中)编写 :code:`.sigmf-meta` 文件的 Python 代码如下: .. code-block:: python - import numpy as np import datetime as dt + + import numpy as np + import sigmf from sigmf import SigMFFile # <来源于上文示例代码> @@ -258,12 +257,12 @@ SigMF 与 IQ 文件标注 # 创建元数据 meta = SigMFFile( - data_file='example.sigmf-data', # 这个后缀可以自定义 + data_file='qpsk_in_noise.sigmf-data', # extension is optional global_info = { SigMFFile.DATATYPE_KEY: 'cf32_le', SigMFFile.SAMPLE_RATE_KEY: 8000000, SigMFFile.AUTHOR_KEY: 'Your name and/or email', - SigMFFile.DESCRIPTION_KEY: 'Simulation of qpsk with noise', + SigMFFile.DESCRIPTION_KEY: 'Simulation of BPSK with noise', SigMFFile.VERSION_KEY: sigmf.__version__, } ) @@ -271,7 +270,7 @@ SigMF 与 IQ 文件标注 # 在索引 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(), }) # 检查错误后保存文件 @@ -298,7 +297,7 @@ SigMF 与 IQ 文件标注 sample_count = signal.sample_count signal_duration = sample_count / sample_rate -更多细节请参考 `SigMF 官方文档 `_. +更多细节请参考 `SigMF Python 官方文档 `_. 谢谢你阅读到这,给你一个小彩蛋:SigMF 的 Logo 实际上是以 SigMF 文件存储的,当该信号的星座图(IQ 图)随时间变化时,它将产生以下动画: @@ -307,13 +306,16 @@ SigMF 与 IQ 文件标注 :align: center :alt: The SigMF logo animation -如果你好奇的话,可以自己试试用下面这段 Python 代码读取它们的 `Logo 文件 `_ 并生成以上的动画。 +如果你好奇的话,可以自己试试用下面这段 Python 代码读取它们的 `Logo 文件 `_ 并生成以上的动画。 .. 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 # 装载数据集 @@ -327,26 +329,28 @@ SigMF 与 IQ 文件标注 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) - # 生成每一帧 - 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]) # 固定坐标轴和坐标点 - ax.set_facecolor('black') # 背景颜色 - - # 将帧保存到文件中 - filename = '/tmp/sigmf_logo_' + str(i) + '.png' - fig.savefig(filename, bbox_inches='tight') - filenames.append(filename) - - # 创建 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}") + # 生成每一帧 + 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]) # 固定坐标轴和坐标点 + ax.set_facecolor('black') # 背景颜色 + + # 将帧保存到文件中 + filename = output_dir.joinpath(f"sigmf_logo_{i}.png") + fig.savefig(filename, bbox_inches='tight') + plt.close() + filenames.append(filename) + + # 创建 gif 图 + images = [iio.imread(f) for f in filenames] + iio.imwrite('sigmf_logo.gif', images, fps=20) ************************************** 面向阵列记录的 SigMF Collection diff --git a/content/iq_files.rst b/content/iq_files.rst index db08f44..c4767c8 100644 --- a/content/iq_files.rst +++ b/content/iq_files.rst @@ -163,7 +163,7 @@ SigMF and Annotating IQ Files Since the IQ file itself doesn't have any metadata associated with it, it's common to have a 2nd file, containing information about the signal, with the same filename but a .txt or other file extension. This should at a minimum include the sample rate used to collect the signal, and the frequency to which the SDR was tuned. After analyzing the signal, the metadata file could include information about sample ranges of interesting features, such as bursts of energy. The sample index is simply an integer that starts at 0 and increments every complex sample. If you knew that there was energy from sample 492342 to 528492, then you could read in the file and pull out that portion of the array: :code:`samples[492342:528493]`. -Luckily, there is now an open standard that specifies a metadata format used to describe signal recordings, known as `SigMF `_. By using an open standard like SigMF, multiple parties can share RF recordings more easily, and use different tools to operate on the same datasets, such as `IQEngine `_. It also prevents "bitrot" of RF datasets where details of the capture are lost over time due to details of the recording not being collocated with the recording itself. +Luckily, there is now an open standard that specifies a metadata format used to describe signal recordings, known as `SigMF `_. By using an open standard like SigMF, multiple parties can share RF recordings more easily, and use different tools to operate on the same datasets, such as `IQEngine `_. It also prevents "bitrot" of RF datasets where details of the capture are lost over time due to details of the recording not being collocated with the recording itself. The most simple (and minimal) way to use the SigMF standard to describe a binary IQ file you have created is to rename the .iq file to .sigmf-data and create a new file with the same name but .sigmf-meta extension, and make sure the datatype field in the meta file matches the binary format of your data file. This meta file is a plaintext file filled with json, so you can simply open it with a text editor and fill it out manually (later we will discuss doing this programmatically). Here is an example .sigmf-meta file you can use as a template: @@ -194,17 +194,16 @@ If you are capturing your RF recording from within Python, e.g., using the Pytho .. code-block:: bash - cd ~ - git clone https://github.com/gnuradio/SigMF.git - cd SigMF - sudo pip install . + pip install sigmf The Python code to write the .sigmf-meta file for the example towards the beginning of this chapter, where we saved :code:`qpsk_in_noise.iq`, is shown below: .. code-block:: python - import numpy as np import datetime as dt + + import numpy as np + import sigmf from sigmf import SigMFFile # @@ -214,7 +213,7 @@ The Python code to write the .sigmf-meta file for the example towards the beginn # create the metadata meta = SigMFFile( - data_file='example.sigmf-data', # extension is optional + data_file='qpsk_in_noise.sigmf-data', # extension is optional global_info = { SigMFFile.DATATYPE_KEY: 'cf32_le', SigMFFile.SAMPLE_RATE_KEY: 8000000, @@ -227,7 +226,7 @@ The Python code to write the .sigmf-meta file for the example towards the beginn # 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 @@ -253,7 +252,7 @@ To read in a SigMF recording into Python, use the following code. In this examp sample_count = signal.sample_count signal_duration = sample_count / sample_rate -For more details reference `the SigMF documentation `_. +For more details reference `the SigMF Python documentation `_. A little bonus for those who read this far; the SigMF logo is actually stored as a SigMF recording itself, and when the signal is plotted as a constellation (IQ plot) over time, it produces the following animation: @@ -262,13 +261,16 @@ A little bonus for those who read this far; the SigMF logo is actually stored as :align: center :alt: The SigMF logo animation -The Python code used to read in the logo file (located `here `_) and produce the animated GIF above is shown below, for those curious: +The Python code used to read in the logo file (located `here `_) and produce the animated GIF above is shown below, for those curious: .. 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 @@ -282,26 +284,28 @@ The Python code used to read in the logo file (located `here