Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SigMF API
sigmf.convert.wav
sigmf.error
sigmf.schema
sigmf.siggen
sigmf.hashing
sigmf.sigmffile
sigmf.utils
Expand Down
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ To get started, see `quickstart`.
quickstart
advanced
converters
siggen
developers

.. toctree::
Expand Down
104 changes: 104 additions & 0 deletions docs/source/siggen.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
================
Signal Generator
================

The :class:`~sigmf.siggen.SigMFGenerator` class provides a builder-pattern API
for creating synthetic RF signals as SigMF files. It is intended for generating
test signals and example files during development and testing.

Signals are complex baseband (``cf32_le``) and support tones, linear frequency
sweeps, additive white Gaussian noise, and frequency/phase offsets. All
parameters can be left unspecified and randomized with a seed for
reproducibility.

-----------
Basic Usage
-----------

.. code-block:: python

from sigmf.siggen import SigMFGenerator

# generate a 1 kHz tone at 48 kHz sample rate for 1 second
signal = SigMFGenerator().tone(1000).sample_rate(48000).duration(1.0).generate()
signal.read_samples() # complex64 numpy array

The returned object is a standard :class:`~sigmf.sigmffile.SigMFFile` backed by
an in-memory buffer, so all the usual metadata and data access methods work.

--------------------
Combining Components
--------------------

Chain multiple ``.tone()`` and ``.sweep()`` calls to build multi-component
signals. Each component gets its own annotation with frequency bounds and a
label.

.. code-block:: python

signal = (
SigMFGenerator()
.tone(1000)
.tone(-2500)
.sweep(500, 4000)
.sample_rate(48000)
.duration(0.5)
.snr(20)
.generate()
)

# each component is annotated individually
for annotation in signal.get_annotations():
print(annotation)

---------------------
Random Test Signals
---------------------

Calling ``.generate()`` with no components produces a fully random signal.
A seed ensures reproducibility across runs.

.. code-block:: python

# deterministic random signal
signal = SigMFGenerator(seed=0xDEADBEEF).generate()

# the number and type of components are randomly chosen
print(signal.description) # e.g. "synthetic signal with 3 tones and 2 sweeps"
print(signal.get_annotations()) # one annotation per component

Without a seed, each call produces a different signal.

----------------------------
Metadata & Annotations
----------------------------

Annotations are automatically created for each signal component, noise floor,
and any applied frequency or phase offsets. Metadata fields like description,
author, and comment can be set via the builder.

.. code-block:: python

signal = (
SigMFGenerator()
.tone(440)
.sample_rate(44100)
.duration(1.0)
.snr(25)
.frequency_offset(1000)
.author("test@example.com")
.description("test tone with noise")
.comment("for unit testing")
.generate()
)

print(signal.get_global_info())
print(signal.get_annotations())

---------
API
---------

.. autoclass:: sigmf.siggen.SigMFGenerator
:members:
:undoc-members:
14 changes: 12 additions & 2 deletions sigmf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,21 @@
# SPDX-License-Identifier: LGPL-3.0-or-later

# version of this python module
__version__ = "1.8.0"
__version__ = "1.9.0"
# matching version of the SigMF specification
__specification__ = "1.2.6"

from . import archive, archivereader, error, schema, sigmffile, utils, validate
from . import (
archive,
archivereader,
error,
schema,
siggen,
sigmffile,
utils,
validate,
)
from .archive import SigMFArchive
from .archivereader import SigMFArchiveReader
from .siggen import SigMFGenerator
from .sigmffile import SigMFCollection, SigMFFile, fromarchive, fromfile
4 changes: 4 additions & 0 deletions sigmf/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ def __init__(self, file_path, file_type="File"):

class SigMFConversionError(SigMFError):
"""Exceptions related to converting to SigMF format."""


class SigMFGeneratorError(SigMFError):
"""Exceptions related to synthetic signal generation."""
Loading
Loading