### Install Library Files (CMake) Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/lib/CMakeLists.txt This snippet utilizes the 'GrMiscUtils' CMake module to handle the installation of the built library files. It calls the 'gr_library_foo' function, which is presumed to manage the necessary installation steps for the library. ```cmake include(GrMiscUtils) gr_library_foo(gnuradio-spectrumDetect) ``` -------------------------------- ### Import I/Q Dataset Utilities (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/getting_started.ipynb Imports essential classes for working with I/Q datasets in TorchSig. This includes classes for dataset metadata, iterable and static datasets, and dataset creation utilities. These are foundational for generating and managing synthetic or external I/Q data. ```python from torchsig.datasets.dataset_metadata import DatasetMetadata from torchsig.datasets.dataset_metadata import ExternalDatasetMetadata from torchsig.datasets.datasets import TorchSigIterableDataset, StaticTorchSigDataset from torchsig.utils.writer import DatasetCreator ``` -------------------------------- ### Download and Prepare YOLOv8 Model Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb This snippet downloads the yolov8x.pt model if it doesn't exist locally. It uses the `requests` library to fetch the file from a URL and `os` to check for its existence and save it. Ensure `requests` is installed. ```python import requests import os url = "https://github.com/ultralytics/assets/releases/download/v8.2.0/yolov8x.pt" model_filepath = "yolov8x.pt" if not os.path.exists(model_filepath): print(f"Downloading yolov8x.pt from {url}...") response = requests.get(url) if response.status_code == 200: # Write the content to the local file with open(model_filepath, 'wb') as file: file.write(response.content) print(f"File downloaded and saved to: {model_filepath}") else: print(f"Failed to download file. Status code: {response.status_code}") else: print(f"{model_filepath} exists") ``` -------------------------------- ### Instantiate YOLO Model Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb This code snippet instantiates the YOLO model using the downloaded model file. It requires the `ultralytics` library to be installed. The `model_filepath` variable should point to the location of the downloaded model. ```python # instantiate the model from ultralytics import YOLO model = YOLO(model_filepath) ``` -------------------------------- ### Visualize Training Progress Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb This code snippet visualizes the training progress and performance by displaying the `results.png` image generated during training. It uses `matplotlib.pyplot` and `cv2` (OpenCV). Ensure these libraries are installed and the `results.save_dir` is correctly set. ```python # View the training progress and performance import matplotlib.pyplot as plt import cv2 import os results_img = cv2.imread(os.path.join(results.save_dir, "results.png")) plt.figure(figsize = (10,20)) plt.imshow(results_img) ``` -------------------------------- ### Configure Library Build (CMake) Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/lib/CMakeLists.txt This snippet configures the build process for the 'gnuradio-spectrumDetect' shared library using CMake. It includes setting source files, linking against gnuradio-runtime, defining include directories for build and installation, and setting export symbols. Platform-specific installation paths for macOS are also handled. ```cmake include(GrPlatform) #define LIB_SUFFIX list(APPEND spectrumDetect_sources) set(spectrumDetect_sources "${spectrumDetect_sources}" PARENT_SCOPE) if(NOT spectrumDetect_sources) message(STATUS "No C++ sources... skipping lib/") return() endif(NOT spectrumDetect_sources) add_library(gnuradio-spectrumDetect SHARED ${spectrumDetect_sources}) target_link_libraries(gnuradio-spectrumDetect gnuradio::gnuradio-runtime) target_include_directories( gnuradio-spectrumDetect PUBLIC $ PUBLIC $) set_target_properties(gnuradio-spectrumDetect PROPERTIES DEFINE_SYMBOL "gnuradio_spectrumDetect_EXPORTS") if(APPLE) set_target_properties(gnuradio-spectrumDetect PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib") endif(APPLE) ``` -------------------------------- ### Install Doxygen Documentation with CMake Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/docs/doxygen/CMakeLists.txt This CMake snippet handles the installation of generated Doxygen documentation. It uses the `install` command to copy the built documentation directories (XML and HTML) to a specified destination directory, typically defined by `GR_PKG_DOC_DIR`. This ensures that the documentation is available after the project is installed. Dependencies include the `BUILT_DIRS` being populated and the `GR_PKG_DOC_DIR` variable being defined. ```cmake install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR}) ``` -------------------------------- ### Install TorchSig without Docker Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/README.md Steps to clone the torchsig repository, install it using pip, and then build and install the gr-spectrumdetect component. Finally, it downloads the trained model and launches GNU Radio Companion. ```bash git clone https://github.com/TorchDSP/torchsig.git cd torchsig pip install . cd gr-spectrumdetect mkdir build cd build cmake ../ make install cd ../examples/ bash trained_model_download.sh gnuradio-companion example.grc & ``` -------------------------------- ### Version Information Setup - CMake Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/CMakeLists.txt Defines the major, API, ABI, and patch versions for the gr-spectrumDetect module. These version numbers are used for packaging and installation. ```cmake set(VERSION_MAJOR 1) set(VERSION_API 0) set(VERSION_ABI 0) set(VERSION_PATCH 0) ``` -------------------------------- ### Instantiate DatasetMetadata Object Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Demonstrates how to create a `DatasetMetadata` object in Python, specifying essential parameters like `num_iq_samples_dataset`, `fft_size`, `num_signals_max`, and `num_signals_min`. ```python # Option 1: Instantiate DatasetMetadata object from torchsig.datasets.dataset_metadata import DatasetMetadata dataset_metadata_1 = DatasetMetadata( num_iq_samples_dataset = num_iq_samples_dataset, fft_size = fft_size, num_signals_max = num_signals_max, num_signals_min = num_signals_min, ) print(dataset_metadata_1) ``` -------------------------------- ### Install TorchSig from Source Source: https://github.com/torchdsp/torchsig/blob/main/README.md Installs the TorchSig library by cloning the repository and using pip. This method is suitable for development or when needing the latest code. ```shell git clone https://github.com/TorchDSP/torchsig.git cd torchsig pip install -e . ``` -------------------------------- ### Instantiate DatasetMetadata as Dictionary Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Shows an alternative method for creating dataset metadata by instantiating it as a Python dictionary. This approach requires all necessary parameters and allows for optional ones like `impairment_level`. ```python # Option 2: Instantiate as a dictionary object dataset_metadata_2 = dict( num_iq_samples_dataset = num_iq_samples_dataset, fft_size = fft_size, num_signals_max = num_signals_max, num_signals_min = num_signals_min, impairment_level = 0 # Added required parameter ) print(dataset_metadata_2) ``` -------------------------------- ### Install Python Bindings Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/python/spectrumDetect/bindings/CMakeLists.txt This `install` command specifies that the built `spectrumDetect_python` target should be installed. It defines the destination directory as the Python API directory within the GNU Radio installation and assigns it to the 'pythonapi' component for installation management. ```cmake install( TARGETS spectrumDetect_python DESTINATION ${GR_PYTHON_DIR}/gnuradio/spectrumDetect COMPONENT pythonapi) ``` -------------------------------- ### Import Spectrogram Dataset Utilities (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/getting_started.ipynb Imports classes for working with spectrogram image datasets in TorchSig. This includes YOLOFileDataset for YOLO format datasets and CFGSignalProtocolDataset for protocol-based signal datasets. These are used for image-based analysis and manipulation of spectrogram data. ```python from torchsig.image_datasets.datasets.yolo_datasets import YOLOFileDataset from torchsig.image_datasets.datasets.protocols import CFGSignalProtocolDataset ``` -------------------------------- ### Run GNU Radio Companion inside Docker Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/README.md Commands to execute within the Docker container to set up the environment and launch GNU Radio Companion, allowing users to interact with the RF energy detection example. ```bash # source /opt/gnuradio/v3.10/setup_env.sh # cd /build/gr-spectrumdetect/examples/ # gnuradio-companion example.grc & ``` -------------------------------- ### Download Trained Model Script Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/README.md Bash script to download the `detect.pt` file, which contains a trained YOLOv8x model for RF energy detection. This file is essential for the gr-spectrumdetect example. ```bash bash trained_model_download.sh ``` -------------------------------- ### Apply Transforms to Static TorchDSP Dataset Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Demonstrates how to apply custom transforms and target transforms to a static dataset loaded from disk if it was originally saved without them. This allows for flexible data processing after dataset creation. ```python from torchsig.datasets.datasets import StaticTorchSigDataset static_dataset = StaticTorchSigDataset( root = root, target_labels=dataset.target_labels ) static_dataset[10] ``` -------------------------------- ### Visualize Impaired vs. Un-Impaired Data Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Visualizes a comparison between an unimpaired and an impaired dataset usingimshow to display spectrograms. This helps to visually assess the effect of the applied signal impairments. Requires matplotlib. ```python fig = plt.figure(figsize=(12,12)) ax = fig.add_subplot(1,2,1) ax.imshow(next(dataset_unimpaired),cmap='Wistia',vmin=0) ax.set_xlabel('Time Axis') ax.set_ylabel('Frequency Axis') ax.set_title('Un-Impaired Data') ax2 = fig.add_subplot(1,2,2) ax2.imshow(next(dataset_impaired),cmap='Wistia',vmin=0) ax2.set_xlabel('Time Axis') ax2.set_ylabel('Frequency Axis') ax2.set_title('Impaired Data') ``` -------------------------------- ### Define Dataset Variables Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Sets up key variables required for configuring the TorchSigIterableDataset, such as the number of IQ samples, FFT size, and the minimum and maximum number of signals per sample. ```python # Define Variables num_iq_samples_dataset = 4096 # 64^2 fft_size = 64 num_signals_max = 5 num_signals_min = 1 ``` -------------------------------- ### Visualize Class Distribution (Pie Chart) Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Generates a pie chart to visualize the distribution of classes within the dataset. It displays the proportion of each class based on the calculated class counts. Requires matplotlib for plotting. ```python # Class Distribution Pie Chart # by default, the class distribution is None aka uniform print(f"Class Distribution Setting: {dataset.dataset_metadata.class_distribution}") plt.figure(figsize=(15, 15)) plt.pie(class_counts, labels = class_names) plt.title("Class Distribution Pie Chart") ``` -------------------------------- ### Visualize Class Distribution (Bar Chart) Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Creates a bar chart to show the distribution of classes in the dataset. This provides a clear visual comparison of the counts for each modulation class. Requires matplotlib for plotting. ```python # Class Distribution Bar Chart plt.figure(figsize=(18, 4)) plt.bar(class_names, class_counts) plt.xticks(rotation=90) plt.title("Class Distribution Bar Chart") plt.xlabel("Modulation Class Name") plt.ylabel("Counts") ``` -------------------------------- ### Visualize Number of Signals Per Sample Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Generates a histogram to visualize the distribution of the number of signals present in each sample of the dataset. It also displays the total and average number of signals per sample. Requires numpy and matplotlib. ```python # Number of signals per sample Distribution import numpy as np # Default number of signals per sample is 3 print(f"Min num signals Setting: {dataset.dataset_metadata.num_signals_min}") print(f"Max num signals Setting: {dataset.dataset_metadata.num_signals_max}") total = sum(num_signals_per_sample) avg = np.mean(np.asarray(num_signals_per_sample)) plt.figure(figsize=(11,8)) plt.hist(x=num_signals_per_sample, bins=np.arange(max(num_signals_per_sample) + 1) + 0.5) plt.xticks(np.arange(0, max(num_signals_per_sample) + 1, 1).tolist()) plt.title(f"Distribution of Number of Signals Per Sample\nTotal Number: {total}, Average: {avg}") plt.xlabel("Number of Signal Bins") plt.ylabel("Counts") ``` -------------------------------- ### TorchSig Transforms and Functionals Imports Source: https://github.com/torchdsp/torchsig/blob/main/examples/getting_started.ipynb Imports necessary components for TorchSig Transforms, including general transforms, functional operations, and metadata transforms. These are used for modifying signal data and metadata, respectively. ```python from torchsig.transforms.transforms import ... from torchsig.transforms.functional import ... from torchsig.transforms.metadata_transforms import ... ``` -------------------------------- ### Build Documentation Locally with Make HTML Source: https://github.com/torchdsp/torchsig/blob/main/README.md This snippet shows the commands to build the TorchSig documentation locally. It involves navigating to the docs directory, installing dependencies, and then using 'make html' to generate the documentation. Finally, it opens the generated index.html file in Firefox. ```bash cd docs pip install -r docs-requirements.txt make html firefox build/html/index.html ``` -------------------------------- ### Evaluate YOLO Model Predictions Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb This snippet visualizes the predicted and actual labels from the YOLO model evaluation. It loads `val_batch1_labels.jpg` and `val_batch1_pred.jpg` using OpenCV and displays them side-by-side using Matplotlib. This requires `matplotlib` and `cv2` to be installed. ```python label = cv2.imread(os.path.join(results.save_dir, "val_batch1_labels.jpg")) pred = cv2.imread(os.path.join(results.save_dir, "val_batch1_pred.jpg")) f, ax = plt.subplots(1, 2, figsize=(15, 9)) ax[0].imshow(label) ax[0].set_title("Label") ax[1].imshow(pred) ax[1].set_title("Prediction") ``` -------------------------------- ### Create YOLO Dataset Configuration File (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb Generates a `detector_example_yolo.yaml` file, which is required by Ultralytics YOLO models to define dataset paths, number of classes, and class names. It uses the `yaml` library for writing the configuration. This file is crucial for training the YOLO model. ```python # create dataset yaml file for ultralytics import yaml import torch config_name = "detector_example_yolo.yaml" classes = {v: k for v,k in enumerate(class_list)} yolo_config = dict( path = "detector_example", train = "images/train", val = "images/val", nc = num_classes, names = classes ) with open(config_name, 'w+') as file: yaml.dump(yolo_config, file, default_flow_style=False) ``` -------------------------------- ### Get User Input for Image Update and Labels in Python Source: https://github.com/torchdsp/torchsig/blob/main/tools/examples/satnogs_processer.ipynb This Python snippet prompts the user to input the name of the image to update and the labels they wish to edit. This input is used to guide subsequent data processing and annotation modifications. It relies on the built-in `input()` function. ```python #gets the users input on what labels they would like to change changeimagename = input("What image would you like to update EX:1,14") edit = input("What labels would you like to edit") ``` -------------------------------- ### Simulate 8-bit Quantization with Different ADC Configurations Source: https://github.com/torchdsp/torchsig/blob/main/examples/transforms/quantize.ipynb Simulates 8-bit quantization on QPSK data using 'floor' rounding mode. It demonstrates two scenarios: full-scale quantization and saturated ADC quantization, calculating SFDR and ENOB for each to evaluate performance. ```python # quantization: fixed configuration parameters num_bits = 8 rounding_mode = 'floor' # simulate quantization at full scale qpsk_data_full_scale = F.quantize( data = qpsk_data, num_bits = num_bits, ref_level_adjustment_db = 0, rounding_mode=rounding_mode ) full_scale_sfdr = np.mean(np.abs(qpsk_data)**2) / np.mean(np.abs(qpsk_data-qpsk_data_full_scale)**2) full_scale_sfdr_db = 10*np.log10(full_scale_sfdr) enob_full_scale = full_scale_sfdr_db/6.02 # simulate saturated ADC qpsk_data_saturated = F.quantize( data = qpsk_data, num_bits = num_bits, ref_level_adjustment_db = 5, rounding_mode=rounding_mode ) saturated_sfdr = np.mean(np.abs(qpsk_data)**2) / np.mean(np.abs(qpsk_data-qpsk_data_saturated)**2) saturated_sfdr_db = 10*np.log10(saturated_sfdr) enob_saturated = saturated_sfdr_db/6.02 ``` -------------------------------- ### Create and Load TorchSig Dataset Source: https://github.com/torchdsp/torchsig/blob/main/examples/classifier_example.ipynb This snippet shows how to initialize an iterable dataset from metadata, create a dataloader, and then use `DatasetCreator` to build a static dataset. Finally, it demonstrates loading the static dataset and accessing its data. ```python dataset = TorchSigIterableDataset(dataset_metadata_test, transforms=transforms, target_labels=None,)#["class_index"]) dataloader = WorkerSeedingDataLoader(dataset, num_workers=1, batch_size=1, collate_fn = lambda x: x)#default_collate_fn) dc = DatasetCreator( dataloader=dataloader, root = f"{root}/test", overwrite=True, dataset_length=100 ) dc.create() test_dataset = StaticTorchSigDataset( root = f"{root}/test", target_labels=["class_index"] ) data, class_index = test_dataset[0] print(f"Data shape: {data.shape}") print(f"Targets: {class_index}") ``` -------------------------------- ### Apply Transforms to External TorchSig Dataset (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/bring_your_own_data_npy_example.ipynb This Python code illustrates how to use `ExternalTorchSigDataset` with data transformations. By passing a list of transforms (e.g., `ComplexTo2D`) and specifying `target_labels`, you can process and filter the dataset during loading. The example shows how to get the transformed data shape and metadata. ```Python from torchsig.datasets import ExternalTorchSigDataset from torchsig.transforms import ComplexTo2D # Assuming BYODExampleFileHandler is defined as above root = 'datasets/byod_npy_example' custom_dataset_2 = ExternalTorchSigDataset( file_handler = BYODExampleFileHandler(root), transforms = [ComplexTo2D()], target_labels = ["modcod"] ) print(f"Dataset size: {len(custom_dataset_2)}") data, metadata = custom_dataset_2[4] print(f"data: {data.shape}") print(f"metadata: {metadata}") ``` -------------------------------- ### TorchSig Signal Metadata and Signal Object Source: https://github.com/torchdsp/torchsig/blob/main/examples/getting_started.ipynb Defines the core metadata fields (center_freq, bandwidth, start_in_samples, duration_in_samples, snr_db, class_name, class_index) and derived fields for a Signal object. It also introduces SignalMetadataExternal for user-imported data and the Signal object which encapsulates IQ data and metadata. SignalBuilders are responsible for creating Signal objects. ```python from torchsig.signals.signal_types import SignalMetadata, SignalMetadataExternal, Signal ``` -------------------------------- ### Apply Coarse Gain Change to QPSK Signal (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/transforms/coarse_gain_change.ipynb Applies the coarse gain change transform to a QPSK signal. The transform takes the signal data, gain change in dB, and the starting index for the change as input. It outputs the modified signal data. This example visualizes the effect of the gain change on the signal's magnitude. ```python import matplotlib.pyplot as plt import numpy as np import torchsig.transforms.functional as F # Assuming generate_qpsk_signal is defined as above # test data N = 1024 qpsk_data = generate_qpsk_signal(num_iq_samples = N, scale = 1.0).data # add in a tiny amount of noise to avoid log10(0) complex_noise = np.sqrt(1e-6)*(np.random.normal(0,1,N) + 1j*np.random.normal(0,1,N)) qpsk_data += complex_noise impaired_qpsk_data = F.coarse_gain_change( data = qpsk_data, gain_change_db=20, start_idx = N//2 ) fig = plt.figure(figsize=(12,6)) ax = fig.add_subplot(1,1,1) ax.plot(20*np.log10(np.abs(qpsk_data)),label='Input') ax.plot(20*np.log10(np.abs(impaired_qpsk_data)),label='With Gain Change') ax.grid() ax.set_title('Constellation Plot') ax.set_xlabel('Time Index $n$') ax.set_ylabel('Magnitude (dB)') ax.legend(fontsize='large', loc='upper left'); ``` -------------------------------- ### Write Dataset to Disk with TorchDSP DatasetCreator Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Saves a finite dataset to disk using the DatasetCreator. Requires defining dataset metadata, transforms, and a dataloader. It supports overwriting existing datasets and uses HDF5 storage. Ensure 'num_samples' is defined to prevent infinite dataset creation. ```python from torchsig.datasets.dataset_metadata import DatasetMetadata from torchsig.utils.writer import DatasetCreator, default_collate_fn from torchsig.signals.signal_lists import TorchSigSignalLists from torchsig.datasets.datasets import TorchSigIterableDataset from torchsig.utils.data_loading import WorkerSeedingDataLoader from torchsig.transforms.transforms import Spectrogram root = "./datasets/create_dataset_example" class_list = TorchSigSignalLists.all_signals dataset_length = len(class_list) * 10 seed = 123456789 dataset_finite_metadata = DatasetMetadata( num_iq_samples_dataset = num_iq_samples_dataset, fft_size = fft_size, num_signals_max = num_signals_max, num_signals_min = num_signals_min, ) # Don't use target_labels to get Signal objects with rich metadata dataset = TorchSigIterableDataset( dataset_metadata = dataset_finite_metadata, transforms = [Spectrogram(fft_size = fft_size)], target_labels = ["class_name", "start", "stop", "lower_freq", "upper_freq", "snr_db"], ) dataloader = WorkerSeedingDataLoader(dataset, batch_size=11, num_workers=4, collate_fn=default_collate_fn) dataloader.seed(seed) # New simplified DatasetCreator API dataset_creator = DatasetCreator( dataset_length=dataset_length, dataloader = dataloader, root = root, overwrite = True, multithreading=False ) dataset_creator.create() ``` -------------------------------- ### Initialize Spectrogram and YOLO Transforms (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb Sets up the necessary transforms for converting signal data into spectrograms and generating YOLO-compatible labels. It defines variables for dataset size, FFT size, and class lists. Dependencies include `torchsig.transforms` and `tqdm.notebook`. ```python # Variables from torchsig.transforms.transforms import Spectrogram from torchsig.transforms.metadata_transforms import YOLOLabel from torchsig.signals.signal_lists import TorchSigSignalLists from tqdm.notebook import tqdm root = "./datasets/detector_example" fft_size = 1024 num_iq_samples_dataset = fft_size ** 2 class_list = TorchSigSignalLists.all_signals num_classes = len(class_list) num_train = 20 # size of train dataset num_val = 5 # size of validation dataset # transform data into a spectrogram image transforms = [Spectrogram(fft_size=fft_size), YOLOLabel()] # YOLO labels are expected to be (class index, x center, y center, width, height) # all normalized to zero, with (0,0) being upper left corner ``` -------------------------------- ### Set Install Prefix for PyBOMBS - CMake Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/CMakeLists.txt Configures the installation prefix for the project if the PYBOMBS_PREFIX environment variable is set. This is typically used when installing GNU Radio components via PyBOMBS. ```cmake if(DEFINED ENV{PYBOMBS_PREFIX}) set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX} CACHE PATH "") message( STATUS "PyBOMBS installed GNU Radio. Defaulting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}" ) endif() ``` -------------------------------- ### Apple Specific RPATH Configuration - CMake Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/CMakeLists.txt Configures installation name directory and RPATH for dynamic libraries on Apple platforms to ensure correct linking when the library is installed. It also enables building with install RPATH. ```cmake if(APPLE) if(NOT CMAKE_INSTALL_NAME_DIR) set(CMAKE_INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE PATH "Library Install Name Destination Directory" FORCE) endif(NOT CMAKE_INSTALL_NAME_DIR) if(NOT CMAKE_INSTALL_RPATH) set(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE PATH "Library Install RPath" FORCE) endif(NOT CMAKE_INSTALL_RPATH) if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "Do Build Using Library Install RPath" FORCE) endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) endif(APPLE) ``` -------------------------------- ### Implement SpectrogramWriter for PNG and YAML - Python Source: https://github.com/torchdsp/torchsig/blob/main/examples/filehandler_example.ipynb This Python code defines a `SpectrogramWriter` class that inherits from `torchsig.utils.file_handlers.base_handler.FileWriter`. It implements `_setup` to create directories for spectrograms and targets, and `write` to process batches of signals, convert them to spectrograms using OpenCV's colormap, and save them as PNG files. Target labels are extracted from signal metadata and saved as YAML files. The `__len__` method returns the count of saved spectrograms. ```python from torchsig.datasets.dataset_metadata import load_dataset_metadata from torchsig.utils.file_handlers.base_handler import FileWriter, FileReader, BaseFileHandler import cv2 import yaml import pathlib import numpy as np class SpectrogramWriter(FileWriter): def _setup(self) -> None: """Setup directory for storing spectrogram images and targets.""" self.spectrogram_dir = self.root.joinpath("spectrograms") self.target_dir = self.root.joinpath("targets") self.spectrogram_dir.mkdir(parents=True, exist_ok=True) self.target_dir.mkdir(parents=True, exist_ok=True) def write(self, batch_idx: int, batch: list) -> None: """Write a single batch of Signals as spectrograms and targets to disk. Args: batch_idx (int): Index of the batch being written. batch (tuple): List of Signal objects in batch """ for idx, sig in enumerate(batch): spectrogram = sig.data metadatas = sig.get_full_metadata() targets = {i: [] for i in range(len(metadatas))} for i, m in enumerate(metadatas): for k, v in m.to_dict().items(): if v is not None: targets[i].append(v) # First normalize data from (0-255) mi = spectrogram.min() ma = spectrogram.max() spectrogram = ((spectrogram - mi) / (ma - mi)) * 255 # convert to 8-bit spectrogram = spectrogram.astype(np.uint8) # apply colormap spectrogram = cv2.applyColorMap(spectrogram, cv2.COLORMAP_HOT) # Save spectrogram as PNG spectrogram_path = self.spectrogram_dir.joinpath(f"spectrogram_{batch_idx * len(batch) + idx}.png") cv2.imwrite(str(spectrogram_path), spectrogram) # Save target as YAML target_path = self.target_dir.joinpath(f"target_{batch_idx * len(batch) + idx}.yaml") with open(target_path, "w") as f: yaml.dump(targets, f, default_flow_style=False) def __len__(self) -> int: """Return the number of saved spectrograms.""" return len(list(self.spectrogram_dir.glob("spectrogram_*.png"))) ``` -------------------------------- ### Install Python Sources with gr_python_install Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/python/spectrumDetect/CMakeLists.txt Installs Python source files for the spectrumDetect module into the specified GR_PYTHON_DIR. This function is part of the GNU Radio framework and ensures Python modules are correctly placed for import. ```cmake gr_python_install( FILES __init__.py specDetect.py spectrumPlot.py rxTime.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/spectrumDetect ) ``` -------------------------------- ### Read Dataset from Disk with TorchDSP StaticTorchSigDataset Source: https://github.com/torchdsp/torchsig/blob/main/examples/create_dataset_example.ipynb Loads a dataset previously saved to disk using StaticTorchSigDataset. Requires the root directory where the dataset was saved and the target labels used during creation. Allows direct access to individual samples via indexing. ```python from torchsig.datasets.datasets import StaticTorchSigDataset static_dataset = StaticTorchSigDataset( root = root, target_labels=dataset.target_labels ) # can access any sample print(static_dataset[0][1]) print(static_dataset[5]) ``` -------------------------------- ### Set Install Directories - CMake Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/CMakeLists.txt Defines various installation directories for the module, including include files, CMake configuration files, data, documentation, configuration, and library executables. It uses platform-specific variables like LIB_SUFFIX. ```cmake include(GrPlatform) #define LIB_SUFFIX if(NOT CMAKE_MODULES_DIR) set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) endif(NOT CMAKE_MODULES_DIR) set(GR_INCLUDE_DIR include/gnuradio/spectrumDetect) set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/gnuradio-spectrumDetect) set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) ``` -------------------------------- ### Build and Register Unit Tests (CMake) Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/lib/CMakeLists.txt This section configures the build and registration of unit tests for the 'spectrumDetect' component using CMake and the 'GrTest' module. It allows for custom include directories and links against the main library. It iterates through test source files to add individual C++ tests. ```cmake include(GrTest) # If your unit tests require special include paths, add them here #include_directories() # List all files that contain Boost.UTF unit tests here list(APPEND test_spectrumDetect_sources) # Anything we need to link to for the unit tests go here list(APPEND GR_TEST_TARGET_DEPS gnuradio-spectrumDetect) if(NOT test_spectrumDetect_sources) message(STATUS "No C++ unit tests... skipping") return() endif(NOT test_spectrumDetect_sources) foreach(qa_file ${test_spectrumDetect_sources}) gr_add_cpp_test("spectrumDetect_${qa_file}" ${CMAKE_CURRENT_SOURCE_DIR}/${qa_file}) endforeach(qa_file) ``` -------------------------------- ### Generate QPSK Signal for Quantization Tests Source: https://github.com/torchdsp/torchsig/blob/main/examples/transforms/quantize.ipynb Generates a scaled, high SNR baseband QPSK Signal using ConstellationSignalBuilder. It normalizes and scales the signal data, returning a Signal object. This function is used to create test input for quantization experiments. ```python from torchsig.signals.signal_types import Signal from torchsig.datasets.dataset_metadata import DatasetMetadata from torchsig.signals.builders.constellation import ConstellationSignalBuilder import torchsig.transforms.functional as F import numpy as np def generate_qpsk_signal(num_iq_samples: int = 128, scale: float = 1.0) -> Signal: """Generate a scaled, high SNR baseband QPSK Signal. Args: num_iq_samples (int, optional): Length of sample. Defaults to 10. scale (int, optional): scale normalized signal data. Defaults to 1.0. Returns: signal: generated Signal """ sample_rate = 10e6 md = DatasetMetadata( num_iq_samples_dataset = num_iq_samples, fft_size = 4, impairment_level = 0, sample_rate = sample_rate, num_signals_max = 1, num_signals_min = 1, num_signals_distribution = [1.0], snr_db_min = 100.0, snr_db_max = 100.0, signal_duration_min = 1.00*num_iq_samples/sample_rate, signal_duration_max = 1.00*num_iq_samples/sample_rate, signal_bandwidth_min = sample_rate/4, signal_bandwidth_max = sample_rate/4, signal_center_freq_min = 0.0, signal_center_freq_max = 0.0, class_list = ['qpsk'], class_distribution = [1.0], seed = 42 ) builder = ConstellationSignalBuilder( dataset_metadata = md, class_name = 'qpsk', seed = 42 ) signal = builder.build() # normalize, then scale data signal.data = F.normalize( data = signal.data, norm_order = 2, flatten = False ) signal.data = np.multiply(signal.data, scale) return signal ``` -------------------------------- ### Install CMake Configuration for Gnuradio SpectrumDetect Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/CMakeLists.txt This CMake code installs a configuration file for the gnuradio-spectrumDetect library. It ensures that the necessary CMake configuration files are placed in the correct destination directory for CMake to find the library during the build process. This is crucial for dependency management and integration with other CMake projects. ```cmake install(FILES cmake/Modules/gnuradio-spectrumDetectConfig.cmake DESTINATION ${GR_CMAKE_DIR}) ``` -------------------------------- ### Prepare and Write YOLO Dataset Files (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb Organizes and writes the generated spectrogram images and YOLO labels to disk in the format required by YOLO. It creates 'images' and 'labels' directories for training and validation sets. This function uses `cv2` for image writing and `os` for file operations. It handles overwriting existing directories. ```python import cv2 import shutil import os # writes the images to disk under images/ # writes the labels as a txt file under labels/ def prepare_dataset(dataset, train: bool, root: str, start_index: int, stop_index: int): os.makedirs(root, exist_ok = True) train_path = "train" if train else "val" label_dir = f"{root}/labels/{train_path}" image_dir = f"{root}/images/{train_path}" os.makedirs(label_dir, exist_ok = True) os.makedirs(image_dir, exist_ok = True) for i in tqdm(range(start_index, stop_index), desc=f"Writing YOLO {train_path.title()} Dataset"): image, labels = next(dataset) filename_base = str(i).zfill(10) label_filename = f"{label_dir}/{filename_base}.txt" image_filename = f"{image_dir}/{filename_base}.png" with open(label_filename, "w") as f: line = "" f.write("\n".join(f"{x[0]} {x[1]} {x[2]} {x[3]} {x[4]}" for x in labels)) cv2.imwrite(image_filename, image, [cv2.IMWRITE_PNG_COMPRESSION, 9]) if os.path.exists(root): shutil.rmtree(root) prepare_dataset(dataset, train=True, root=root, start_index=1, stop_index = num_train) prepare_dataset(dataset, train=False, root=root, start_index=num_train, stop_index = num_train + num_val) ``` -------------------------------- ### Configure Package Configuration File using CMake Source: https://github.com/torchdsp/torchsig/blob/main/gr-spectrumdetect/CMakeLists.txt This CMake snippet uses the `configure_package_config_file` function to generate a package configuration file. It takes an input template file (`targetConfig.cmake.in`) and produces a generated configuration file (`${target}Config.cmake`) in the binary directory, which is then installed to the specified destination. This is a standard CMake practice for creating installable packages. ```cmake include(CMakePackageConfigHelpers) configure_package_config_file( ${PROJECT_SOURCE_DIR}/cmake/Modules/targetConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/cmake/Modules/${target}Config.cmake INSTALL_DESTINATION ${GR_CMAKE_DIR}) ``` -------------------------------- ### Create and Visualize TorchSig Dataset (Python) Source: https://github.com/torchdsp/torchsig/blob/main/examples/detector_example.ipynb Generates a TorchSig iterable dataset, applies spectrogram and YOLO transforms, and visualizes a sample including bounding boxes for detected signals. It uses `torchsig.datasets` and `matplotlib` for visualization. The output includes data shape, number of signals, and label details. ```python from torchsig.datasets.dataset_metadata import DatasetMetadata from torchsig.datasets.datasets import TorchSigIterableDataset import matplotlib.pyplot as plt from matplotlib.patches import Rectangle # create the NewTorchSigDataset dataset dataset_metadata = DatasetMetadata( num_iq_samples_dataset = num_iq_samples_dataset, fft_size = fft_size, impairment_level = 2, num_signals_min = 1, num_signals_max = 3, ) dataset = TorchSigIterableDataset( dataset_metadata = dataset_metadata, transforms=transforms, target_labels=["yolo_label"] ) # show sample from dataset data, label = next(dataset) print(f"Data shape: {data.shape}") print(f"Number of signals: {len(label)}") nl = "\n" print(f"Labels:\n{nl.join(str(l) for l in label)}") height, width = data.shape fig = plt.figure(figsize=(12,6)) fig.tight_layout() ax = fig.add_subplot(1,1,1) pos = ax.imshow(data,aspect='auto',cmap='Wistia',vmin=dataset_metadata.noise_power_db) fig.colorbar(pos, ax=ax) for t in label: classindex, xcenter, ycenter, normwidth, normheight = t actualwidth = width * normwidth actualheight = height * normheight actualxcenter = xcenter * width actualycenter = ycenter * height x_lowerleft = actualxcenter - (actualwidth / 2) y_lowerleft = actualycenter + (actualheight / 2) # print(x_lowerleft, y_lowerleft, actualwidth, actualheight) ax.add_patch(Rectangle( (x_lowerleft, y_lowerleft), actualwidth, -actualheight, linewidth=1, edgecolor='blue', facecolor='none' )) textDisplay = str(class_list[classindex]) ax.text(x_lowerleft,y_lowerleft,textDisplay, bbox=dict(facecolor='w', alpha=0.5, linewidth=0)) ```