@@ -18,7 +18,7 @@ the recording of the SigMF logo used in this example `from the specification
1818 from sigmf import SigMFFile, sigmffile
1919
2020 # Load a dataset
21- path = ' logo/sigmf_logo' # extension is optional
21+ path = " logo/sigmf_logo" # extension is optional
2222 signal = sigmffile.fromfile(path)
2323
2424 # Get some metadata and all annotations
@@ -31,13 +31,15 @@ the recording of the SigMF logo used in this example `from the specification
3131 for adx, annotation in enumerate (annotations):
3232 annotation_start_idx = annotation[SigMFFile.START_INDEX_KEY ]
3333 annotation_length = annotation[SigMFFile.LENGTH_INDEX_KEY ]
34- annotation_comment = annotation.get(SigMFFile.COMMENT_KEY , " [annotation {} ]" .format(adx))
34+ annotation_comment = annotation.get(
35+ SigMFFile.COMMENT_KEY , " [annotation {} ]" .format(adx)
36+ )
3537
3638 # Get capture info associated with the start of annotation
3739 capture = signal.get_capture_info(annotation_start_idx)
3840 freq_center = capture.get(SigMFFile.FREQUENCY_KEY , 0 )
39- freq_min = freq_center - 0.5 * sample_rate
40- freq_max = freq_center + 0.5 * sample_rate
41+ freq_min = freq_center - 0.5 * sample_rate
42+ freq_max = freq_center + 0.5 * sample_rate
4143
4244 # Get frequency edges of annotation (default to edges of capture)
4345 freq_start = annotation.get(SigMFFile.FLO_KEY )
@@ -66,34 +68,41 @@ First, create a single SigMF Recording and save it to disk:
6668 data = np.zeros(1024 , dtype = np.complex64)
6769
6870 # write those samples to file in cf32_le
69- data.tofile(' example_cf32.sigmf-data' )
71+ data.tofile(" example_cf32.sigmf-data" )
7072
7173 # create the metadata
7274 meta = SigMFFile(
73- data_file = ' example_cf32.sigmf-data' , # extension is optional
74- global_info = {
75+ data_file = " example_cf32.sigmf-data" , # extension is optional
76+ global_info = {
7577 SigMFFile.DATATYPE_KEY : get_data_type_str(data), # in this case, 'cf32_le'
7678 SigMFFile.SAMPLE_RATE_KEY : 48000 ,
77- SigMFFile.AUTHOR_KEY : ' jane.doe@domain.org' ,
78- SigMFFile.DESCRIPTION_KEY : ' All zero complex float32 example file.' ,
79- }
79+ SigMFFile.AUTHOR_KEY : " jane.doe@domain.org" ,
80+ SigMFFile.DESCRIPTION_KEY : " All zero complex float32 example file." ,
81+ },
8082 )
8183
8284 # create a capture key at time index 0
83- meta.add_capture(0 , metadata = {
84- SigMFFile.FREQUENCY_KEY : 915000000 ,
85- SigMFFile.DATETIME_KEY : get_sigmf_iso8601_datetime_now(),
86- })
85+ meta.add_capture(
86+ 0 ,
87+ metadata = {
88+ SigMFFile.FREQUENCY_KEY : 915000000 ,
89+ SigMFFile.DATETIME_KEY : get_sigmf_iso8601_datetime_now(),
90+ },
91+ )
8792
8893 # add an annotation at sample 100 with length 200 & 10 KHz width
89- meta.add_annotation(100 , 200 , metadata = {
90- SigMFFile.FLO_KEY : 914995000.0 ,
91- SigMFFile.FHI_KEY : 915005000.0 ,
92- SigMFFile.COMMENT_KEY : ' example annotation' ,
93- })
94+ meta.add_annotation(
95+ 100 ,
96+ 200 ,
97+ metadata = {
98+ SigMFFile.FLO_KEY : 914995000.0 ,
99+ SigMFFile.FHI_KEY : 915005000.0 ,
100+ SigMFFile.COMMENT_KEY : " example annotation" ,
101+ },
102+ )
94103
95104 # check for mistakes & write to disk
96- meta.tofile(' example_cf32.sigmf-meta' ) # extension is optional
105+ meta.tofile(" example_cf32.sigmf-meta" ) # extension is optional
97106
98107 Now lets add another SigMF Recording and associate them with a SigMF Collection:
99108
@@ -103,47 +112,50 @@ Now lets add another SigMF Recording and associate them with a SigMF Collection:
103112
104113 data_ci16 = np.zeros(1024 , dtype = np.complex64)
105114
106- # rescale and save as a complex int16 file:
115+ # rescale and save as a complex int16 file:
107116 data_ci16 *= pow (2 , 15 )
108- data_ci16.view(np.float32).astype(np.int16).tofile(' example_ci16.sigmf-data' )
117+ data_ci16.view(np.float32).astype(np.int16).tofile(" example_ci16.sigmf-data" )
109118
110119 # create the metadata for the second file
111120 meta_ci16 = SigMFFile(
112- data_file = ' example_ci16.sigmf-data' , # extension is optional
113- global_info = {
114- SigMFFile.DATATYPE_KEY : ' ci16_le' , # get_data_type_str() is only valid for numpy types
121+ data_file = " example_ci16.sigmf-data" , # extension is optional
122+ global_info = {
123+ SigMFFile.DATATYPE_KEY : " ci16_le" , # get_data_type_str() is only valid for numpy types
115124 SigMFFile.SAMPLE_RATE_KEY : 48000 ,
116- SigMFFile.DESCRIPTION_KEY : ' All zero complex int16 file.' ,
117- }
125+ SigMFFile.DESCRIPTION_KEY : " All zero complex int16 file." ,
126+ },
118127 )
119128 meta_ci16.add_capture(0 , metadata = meta.get_capture_info(0 ))
120- meta_ci16.tofile(' example_ci16.sigmf-meta' )
121-
122- collection = SigMFCollection([' example_cf32.sigmf-meta' , ' example_ci16.sigmf-meta' ],
123- metadata = {' collection' : {
124- SigMFCollection.AUTHOR_KEY : ' sigmf@sigmf.org' ,
125- SigMFCollection.DESCRIPTION_KEY : ' Collection of two all zero files.' ,
129+ meta_ci16.tofile(" example_ci16.sigmf-meta" )
130+
131+ collection = SigMFCollection(
132+ [" example_cf32.sigmf-meta" , " example_ci16.sigmf-meta" ],
133+ metadata = {
134+ " collection" : {
135+ SigMFCollection.AUTHOR_KEY : " sigmf@sigmf.org" ,
136+ SigMFCollection.DESCRIPTION_KEY : " Collection of two all zero files." ,
126137 }
127- }
138+ },
128139 )
129140 streams = collection.get_stream_names()
130141 sigmf = [collection.get_SigMFFile(stream) for stream in streams]
131- collection.tofile(' example_zeros.sigmf-collection' )
142+ collection.tofile(" example_zeros.sigmf-collection" )
132143
133144 The SigMF Collection and its associated Recordings can now be loaded like this:
134145
135146.. code-block :: python
136147
137148 import sigmf
138- collection = sigmf.fromfile(' example_zeros' )
139- ci16_sigmffile = collection.get_SigMFFile(stream_name = ' example_ci16' )
140- cf32_sigmffile = collection.get_SigMFFile(stream_name = ' example_cf32' )
149+
150+ collection = sigmf.fromfile(" example_zeros" )
151+ ci16_sigmffile = collection.get_SigMFFile(stream_name = " example_ci16" )
152+ cf32_sigmffile = collection.get_SigMFFile(stream_name = " example_cf32" )
141153
142154-----------------------------------------------
143155Load a SigMF Archive and slice without untaring
144156-----------------------------------------------
145157
146- Since an *archive * is merely a tarball (uncompressed), and since there any many
158+ Since an *archive * is a tarball (uncompressed by default ), and since there are many
147159excellent tools for manipulating tar files, it's fairly straightforward to
148160access the *data * part of a SigMF archive without un-taring it. This is a
149161compelling feature because **1 ** archives make it harder for the ``-data `` and
@@ -195,3 +207,50 @@ read it, this can be done "in mid air" or "without touching the ground (disk)".
195207 >>> arc[:10]
196208 array([-20.+11.j, -21. -6.j, -17.-20.j, -13.-52.j, 0.-75.j, 22.-58.j,
197209 48.-44.j, 49.-60.j, 31.-56.j, 23.-47.j], dtype=complex64)
210+
211+ ------------------------------
212+ Compressed SigMF Archives
213+ ------------------------------
214+
215+ SigMF archives can be compressed using gzip, xz, or zip.
216+ The file extension determines the archive format:
217+
218+ +---------------------+-------------+
219+ | Extension | Format |
220+ +=====================+=============+
221+ | ``.sigmf `` | uncompressed|
222+ +---------------------+-------------+
223+ | ``.sigmf.gz `` | gzip tar |
224+ +---------------------+-------------+
225+ | ``.sigmf.xz `` | xz tar |
226+ +---------------------+-------------+
227+ | ``.sigmf.zip `` | zip archive |
228+ +---------------------+-------------+
229+
230+ **Writing compressed archives: **
231+
232+ ::
233+
234+ >>> import sigmf
235+ >>> signal = sigmf.sigmffile.fromfile('recording.sigmf-meta')
236+
237+ # extension determines format
238+ >>> signal.tofile('recording.sigmf.xz')
239+ >>> signal.archive('recording.sigmf.gz')
240+
241+ # compression parameter creates archive with correct extension
242+ >>> signal.tofile('recording', compression='xz') # → recording.sigmf.xz
243+ >>> signal.archive('recording', compression='gz') # → recording.sigmf.gz
244+
245+ **Reading compressed archives: **
246+
247+ ::
248+
249+ >>> signal = sigmf.fromfile('recording.sigmf.xz')
250+ >>> signal[:10]
251+ array([-20.+11.j, ...], dtype=complex64)
252+
253+ **Memory behavior: **
254+
255+ Uncompressed ``.sigmf `` archives use ``numpy.memmap `` for zero-copy access.
256+ Compressed archives must decompress into RAM before access.
0 commit comments