Skip to content

Commit

Permalink
Merge pull request #106 from Teque5/feature/aerospace-corp-python3-an…
Browse files Browse the repository at this point in the history
…d-signal-io

new i/o methods for annotations & samples; +python3
  • Loading branch information
bhilburn committed Oct 7, 2020
2 parents 33bc717 + c7a5779 commit 20a9e42
Show file tree
Hide file tree
Showing 15 changed files with 421 additions and 119 deletions.
12 changes: 12 additions & 0 deletions .gitignore
@@ -1,3 +1,15 @@
# temp files
*.swp
*.pyc
.cache

# setuptools related
build/*
.eggs/*
SigMF.egg-info/*

# pytest & coverage related
.coverage
pytest.xml
coverage.xml
htmlcov/*
52 changes: 52 additions & 0 deletions README.md
Expand Up @@ -39,6 +39,58 @@ maintained for posterity.
Anyone is welcome to get involved - indeed, the more people involved in the
discussions, the more useful the standard is likely to be.

## Installation
After cloning, simply run the setup script for a static installation.

```
python setup.py
```

Alternatively, install the module in developer mode if you plan to experiment
with your own changes.

```
python setup.py develop
```

## Usage example
#### Load a SigMF dataset; read its annotation, metadata, and samples
```python
from sigmf import SigMFFile, sigmffile

# Load a dataset
sigmf_filename = 'datasets/my_dataset.sigmf-meta' # extension is optional
signal = sigmffile.fromfile(sigmf_filename)

# Get some metadata and all annotations
sample_rate = signal.get_global_field(SigMFFile.SAMPLE_RATE_KEY)
sample_count = signal.sample_count
signal_duration = sample_count / sample_rate
annotations = signal.get_annotations()

# Iterate over annotations
for annotation_idx, annotation in enumerate(annotations):
annotation_start_idx = annotation[SigMFFile.START_INDEX_KEY]
annotation_length = annotation[SigMFFile.LENGTH_INDEX_KEY]
annotation_comment = annotation.get(SigMFFile.COMMENT_KEY,
"[annotation {}]".format(annotation_idx))

# Get capture info associated with the start of annotation
capture = signal.get_capture_info(annotation_start_idx)
freq_center = capture.get(SigMFFile.FREQUENCY_KEY, 0)
freq_min = freq_center - 0.5*sample_rate
freq_max = freq_center + 0.5*sample_rate

# Get frequency edges of annotation (default to edges of capture)
freq_start = annotation.get(SigMFFile.FLO_KEY, f_min)
freq_stop = annotation.get(SigMFFile.FHI_KEY, f_max)

# Get the samples corresponding to annotation
samples = signal.read_samples(annotation_start_idx, annotation_length)
```



## Frequently Asked Questions

#### Is this a GNU Radio effort?
Expand Down
3 changes: 2 additions & 1 deletion example_metadata.py
@@ -1,12 +1,13 @@
#
# Warning: this is not strict JSON, this is python to allow inline comment
#
from sigmf import __version__

{
"global": {
"core:datatype": "cf32_le", # The datatype of the recording (here, little-endian complex 32-bit float)
"core:sample_rate": 10000000, # The sample rate of the recording (10 MHz, here).
"core:version": "0.0.1", # Version of the SigMF spec used.
"core:version": __version__, # Version of the SigMF spec used.
"core:description": "An example metadafile for a SigMF recording."
},
"captures": [
Expand Down
11 changes: 6 additions & 5 deletions setup.py
@@ -1,7 +1,5 @@
from setuptools import setup

import sigmf

import os

shortdesc = "Signal Metadata Format Specification"
longdesc = """
Expand All @@ -10,12 +8,15 @@
SigMF can be used to describe general information about a collection
of samples, the characteristics of the system that generated the
samples, and features of the signal itself.
"""

# exec version.py to get __version__ (version.py is the single source of the version)
version_file = os.path.join(os.path.dirname(__file__), 'sigmf', 'version.py')
exec(open(version_file).read())

setup(
name='SigMF',
version=sigmf.__version__,
version=__version__,
description=shortdesc,
long_description=longdesc,
url='https://github.com/gnuradio/SigMF',
Expand Down
23 changes: 14 additions & 9 deletions sigmf/__init__.py
Expand Up @@ -18,13 +18,18 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

__version__ = "0.0.1"
# Use version.py to get the version
# Never define in the __init__.py and import it in setup.py because you can't
# import sigmf in setup.py because you won't have the dependencies yet.
# https://packaging.python.org/guides/single-sourcing-package-version/

import archive
import error
import schema
import sigmffile
import validate
import utils
from archive import SigMFArchive
from sigmffile import SigMFFile
from .version import __version__
from .archive import SigMFArchive
from .sigmffile import SigMFFile

from . import archive
from . import error
from . import schema
from . import sigmffile
from . import validate
from . import utils
8 changes: 4 additions & 4 deletions sigmf/archive.py
Expand Up @@ -75,7 +75,7 @@ def __init__(self, sigmffile, name=None, fileobj=None):

archive_name = self._get_archive_name()
sigmf_fileobj = self._get_output_fileobj()
sigmf_archive = tarfile.TarFile(mode="w",
sigmf_archive = tarfile.TarFile(mode="w",
fileobj=sigmf_fileobj,
format=tarfile.PAX_FORMAT)
tmpdir = tempfile.mkdtemp()
Expand Down Expand Up @@ -150,11 +150,11 @@ def _get_output_fileobj(self):
fileobj = self._get_open_fileobj()
except:
if self.fileobj:
e = "fileobj {!r} is not byte-writable".format(self.fileobj)
err = "fileobj {!r} is not byte-writable".format(self.fileobj)
else:
e = "can't open {!r} for writing".format(self.name)
err = "can't open {!r} for writing".format(self.name)

raise error.SigMFFileError(e)
raise error.SigMFFileError(err)

return fileobj

Expand Down
5 changes: 2 additions & 3 deletions sigmf/sigmf_hash.py
Expand Up @@ -28,8 +28,7 @@ def calculate_sha512(filename):
Returns sha512 of filename
"""
the_hash = hashlib.sha512()
with open(filename, "rb") as f:
for buff in iter(lambda: f.read(4096), b""):
with open(filename, "rb") as handle:
for buff in iter(lambda: handle.read(4096), b""):
the_hash.update(buff)
return the_hash.hexdigest()

0 comments on commit 20a9e42

Please sign in to comment.