Skip to content

Commit d36e32f

Browse files
committed
simplify fromarray, sample_rate is not required
1 parent 3d08295 commit d36e32f

4 files changed

Lines changed: 46 additions & 51 deletions

File tree

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,15 @@ import numpy as np
5050
import sigmf
5151

5252
data = np.array([0.1 + 0.2j, 0.3 + 0.4j], dtype=np.complex64)
53-
meta = sigmf.fromarray(data, sample_rate=48000)
53+
meta = sigmf.fromarray(data)
54+
# optional additional metadata
55+
meta.sample_rate = 8000
56+
meta.description = "sample recording"
57+
meta.add_capture(start_index=0, metadata={sigmf.FREQUENCY_KEY: 915e6})
5458
# creates recording.sigmf-data and recording.sigmf-meta
5559
meta.tofile("recording")
60+
# or create compressed archive
61+
meta.tofile("recording.sigmf.gz")
5662
```
5763

5864
### Docs

docs/source/quickstart.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,12 @@ Save a Numpy array as a SigMF Recording
6262
data = np.zeros(1024, dtype=np.complex64)
6363
6464
# create SigMFFile from array — datatype is inferred from the numpy array
65-
meta = sigmf.fromarray(data, sample_rate=48000, frequency=915e6)
65+
meta = sigmf.fromarray(data)
66+
67+
# optional additional metadata
68+
meta.sample_rate = 48000
69+
meta.description = "an example recording"
70+
meta.add_capture(start_index=0, metadata={sigmf.FREQUENCY_KEY: 915e6})
6671
6772
# write to separate .sigmf-meta and .sigmf-data files
6873
meta.tofile("example")

sigmf/sigmffile.py

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,12 +1322,12 @@ def get_dataset_filename_from_metadata(meta_fn, metadata=None):
13221322
return None
13231323

13241324

1325-
def fromarray(data, sample_rate, frequency=None, global_info=None):
1325+
def fromarray(data):
13261326
"""
13271327
Create a SigMFFile from a numpy array.
13281328
1329-
Convenience function that infers the SigMF datatype from the numpy dtype,
1330-
creates an in-memory SigMFFile with a single capture at index 0. The
1329+
Convenience function that infers the SigMF datatype from the numpy dtype
1330+
and creates an in-memory SigMFFile with a single capture at index 0. The
13311331
returned object can then be written to disk using ``tofile()`` or
13321332
``archive()``. For full control over captures, annotations, and global
13331333
fields, use ``SigMFFile`` directly.
@@ -1336,12 +1336,6 @@ def fromarray(data, sample_rate, frequency=None, global_info=None):
13361336
----------
13371337
data : np.ndarray
13381338
Signal samples.
1339-
sample_rate : float
1340-
Sample rate in Hz.
1341-
frequency : float, optional
1342-
Center frequency in Hz for the capture.
1343-
global_info : dict, optional
1344-
Additional global metadata fields to include.
13451339
13461340
Returns
13471341
-------
@@ -1351,37 +1345,26 @@ def fromarray(data, sample_rate, frequency=None, global_info=None):
13511345
Examples
13521346
--------
13531347
>>> import numpy as np
1354-
>>> import tempfile
1348+
>>> import sigmf, tempfile
13551349
>>> from pathlib import Path
1356-
>>> data = np.random.randn(1000) + 1j * np.random.randn(1000)
1357-
>>> meta = fromarray(data, sample_rate=1e6, frequency=915e6) # returns SigMFFile
1350+
>>> data = (np.random.randn(16) + 1j * np.random.randn(16))
1351+
>>> meta = sigmf.fromarray(data)
1352+
>>> meta.sample_rate = 1e6 # set global fields via attribute
1353+
>>> meta.add_capture(0, metadata={sigmf.FREQUENCY_KEY: 915e6}) # add capture metadata
1354+
>>> meta.add_annotation(0, length=len(data), metadata={sigmf.LABEL_KEY: 'example'}) # add annotation
13581355
>>> tmpdir = Path(tempfile.mkdtemp())
13591356
>>> meta.tofile(tmpdir / 'recording') # creates recording.sigmf-meta and recording.sigmf-data
13601357
>>> meta.tofile(tmpdir / 'recording.sigmf') # creates recording.sigmf archive
13611358
"""
1362-
import io
1363-
13641359
# create in-memory data buffer
13651360
data_buffer = io.BytesIO()
13661361
data_buffer.write(data.tobytes())
13671362
data_buffer.seek(0)
13681363

1369-
# build metadata
1370-
info = {
1371-
keys.DATATYPE_KEY: get_data_type_str(data),
1372-
keys.SAMPLE_RATE_KEY: sample_rate,
1373-
}
1374-
if global_info is not None:
1375-
info.update(global_info)
1376-
1377-
capture_meta = None
1378-
if frequency is not None:
1379-
capture_meta = {keys.FREQUENCY_KEY: frequency}
1380-
13811364
# create sigmffile object with in-memory buffer
1382-
meta = SigMFFile(global_info=info)
1365+
meta = SigMFFile(global_info={keys.DATATYPE_KEY: get_data_type_str(data)})
13831366
meta.set_data_file(data_buffer=data_buffer)
1384-
meta.add_capture(0, metadata=capture_meta)
1367+
meta.add_capture(0)
13851368

13861369
return meta
13871370

tests/test_sigmffile.py

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,20 @@
2020
from sigmf import SigMFFile, error, utils
2121
from sigmf.sigmffile import _DeprecatingKey, _SigMFDeprecatingMeta
2222

23-
from .testdata import *
23+
from .testdata import (
24+
TEST_FLOAT32_DATA,
25+
TEST_METADATA,
26+
TEST_U8_DATA0,
27+
TEST_U8_DATA1,
28+
TEST_U8_DATA2,
29+
TEST_U8_DATA3,
30+
TEST_U8_DATA4,
31+
TEST_U8_META0,
32+
TEST_U8_META1,
33+
TEST_U8_META2,
34+
TEST_U8_META3,
35+
TEST_U8_META4,
36+
)
2437

2538

2639
class TestClassMethods(unittest.TestCase):
@@ -140,8 +153,10 @@ def test_set_data_file_with_annotations(self):
140153

141154
class TestMultichannel(unittest.TestCase):
142155
def setUp(self):
143-
# in order to check shapes we need some positive number of samples to work with
144-
# number of samples should be lowest common factor of num_channels
156+
"""
157+
In order to check shapes we need some positive number of samples to work with.
158+
Number of samples should be lowest common factor of num_channels.
159+
"""
145160
self.raw_count = 16
146161
self.lut = {
147162
"i8": np.int8,
@@ -534,19 +549,13 @@ def tearDown(self):
534549

535550
def test_basic_creation(self):
536551
"""test creating SigMFFile from array"""
537-
meta = sigmf.fromarray(TEST_FLOAT32_DATA, sample_rate=4000)
538-
self.assertEqual(meta.get_global_field(sigmf.SAMPLE_RATE_KEY), 4000)
552+
meta = sigmf.fromarray(TEST_FLOAT32_DATA)
539553
self.assertEqual(meta.get_global_field(sigmf.DATATYPE_KEY), "rf32_le")
540554
np.testing.assert_array_equal(TEST_FLOAT32_DATA, meta[:])
541555

542-
def test_with_frequency(self):
543-
"""test that frequency kwarg populates capture metadata"""
544-
meta = sigmf.fromarray(TEST_FLOAT32_DATA, sample_rate=4000, frequency=915e6)
545-
self.assertEqual(meta.get_capture_info(0).get("core:frequency"), 915e6)
546-
547556
def test_write_separate_files(self):
548557
"""test writing to separate meta and data files"""
549-
meta = sigmf.fromarray(TEST_FLOAT32_DATA, sample_rate=4000)
558+
meta = sigmf.fromarray(TEST_FLOAT32_DATA)
550559
path = self.temp_dir / "basic"
551560
meta.tofile(str(path))
552561
self.assertTrue((self.temp_dir / "basic.sigmf-data").exists())
@@ -556,7 +565,7 @@ def test_write_separate_files(self):
556565

557566
def test_write_archive(self):
558567
"""test writing to uncompressed archive"""
559-
meta = sigmf.fromarray(TEST_FLOAT32_DATA, sample_rate=4000)
568+
meta = sigmf.fromarray(TEST_FLOAT32_DATA)
560569
path = self.temp_dir / "archived.sigmf"
561570
meta.tofile(str(path))
562571
self.assertTrue((self.temp_dir / "archived.sigmf").exists())
@@ -567,19 +576,11 @@ def test_write_archive(self):
567576

568577
def test_write_compressed_archive(self):
569578
"""test writing to compressed archive"""
570-
meta = sigmf.fromarray(TEST_FLOAT32_DATA, sample_rate=4000)
579+
meta = sigmf.fromarray(TEST_FLOAT32_DATA)
571580
path = self.temp_dir / "comp.sigmf.xz"
572581
meta.tofile(str(path))
573582
self.assertTrue((self.temp_dir / "comp.sigmf.xz").exists())
574583
self.assertFalse((self.temp_dir / "comp.sigmf-data").exists())
575584
self.assertFalse((self.temp_dir / "comp.sigmf-meta").exists())
576585
loopback = sigmf.fromfile(str(path))
577586
np.testing.assert_array_equal(TEST_FLOAT32_DATA, loopback[:])
578-
579-
def test_with_global_info(self):
580-
"""test that global_info dict is merged into metadata"""
581-
meta = sigmf.fromarray(
582-
TEST_FLOAT32_DATA, sample_rate=4000, global_info={"core:author": "test_author", "core:description": "test"}
583-
)
584-
self.assertEqual(meta.get_global_field("core:author"), "test_author")
585-
self.assertEqual(meta.get_global_field("core:description"), "test")

0 commit comments

Comments
 (0)