1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
|
/*! \mainpage
\image html gnuradio-logo.svg
Welcome to GNU Radio!
For details about GNU Radio and using it, please see the <a
href="http://gnuradio.org" target="_blank"><b>main project page</b></a>.
Other information about the project and discussion about GNU Radio,
software radio, and communication theory in general can be found at
the <a href="http://www.trondeau.com" target="_blank"><b>GNU Radio blog</b></a>.
\section build Building GNU Radio
See the \ref build_guide page for details about the project's
dependencies and build process.
Once built, look on <a href="http://gnuradio.org" target="_blank">gnuradio.org</a> for
tutorials on using the software system and see \ref
page_exploring_gnuradio for a few simple examples exploring GNU Radio.
\section blocks GNU Radio Blocks
GNU Radio uses discrete signal processing blocks that are connected
together to perform your signal processing application. This manual
contain a list of all GNU Radio <a href="modules.html"><b>C++ Blocks</b></a>.
Please note that at this time, we haven't found an acceptable way to
provide unified documentation for the C++ parts of the system and the
parts written in Python (mostly hierarchical blocks). Until this gets
worked out, please bear with us, or better yet, solve it for us!
\section toc Manual Contents
More details on packages in GNU Radio:
\li \ref page_audio
\li \ref page_digital
\li \ref page_qtgui
\li \ref page_uhd
\li \ref page_vocoder
More details on GNU Radio concepts:
\li \ref page_logger
\li \ref page_pmt
\li \ref page_msg_passing
\li \ref page_stream_tags
\li \ref page_metadata
\li \ref volk_guide
\li \ref page_perf_counters
\li \ref page_pfb
\li \ref page_affinity
\li \ref page_tagged_stream_blocks
\li \ref page_ofdm
\li \ref page_packet_data
\section flowgraph Operating a Flowgraph
The basic data structure in GNU Radio is the flowgraph, which
represents the connections of the blocks through which a continuous
stream of samples flows. The concept of a flowgraph is an acyclic
directional graph with one or more source blocks (to insert samples
into the flowgraph), one or more sink blocks (to terminate or export
samples from the flowgraph), and any signal processing blocks in
between.
A program must at least create a GNU Radio 'top_block', which
represents the top-most structure of the flowgraph. The top blocks
provide the overall control and hold methods such as 'start,' 'stop,'
and 'wait.'
The general construction of a GNU Radio application is to create a
gr_top_block, instantiate the blocks, connect the blocks together, and
then start the gr_top_block. The following program shows how this is
done. A single source and sink are used with a FIR filter between
them.
\code
from gnuradio import gr, blocks, filter, analog
class my_topblock(gr.top_block):
def __init__(self):
gr.top_block.__init__(self)
amp = 1
taps = filter.firdes.low_pass(1, 1, 0.1, 0.01)
self.src = analog.noise_source_c(analog.GR_GAUSSIAN, amp)
self.flt = filter.fir_filter_ccf(1, taps)
self.snk = blocks.null_sink(gr.sizeof_gr_complex)
self.connect(self.src, self.flt, self.snk)
if __name__ == "__main__":
tb = my_topblock()
tb.start()
tb.wait()
\endcode
The 'tb.start()' starts the data flowing through the flowgraph while
the 'tb.wait()' is the equivalent of a thread's 'join' operation and
blocks until the gr_top_block is done.
An alternative to using the 'start' and 'wait' methods, a 'run' method is
also provided for convenience that is a blocking start call;
equivalent to the above 'start' followed by a 'wait.'
\subsection latency Latency and Throughput
By default, GNU Radio runs a scheduler that attempts to optimize
throughput. Using a dynamic scheduler, blocks in a flowgraph pass
chunks of items from sources to sinks. The sizes of these chunks will
vary depending on the speed of processing. For each block, the number
of items is can process is dependent on how much space it has in its
output buffer(s) and how many items are available on the input
buffer(s).
The consequence of this is that often a block may be called with a very
large number of items to process (several thousand). In terms of
speed, this is efficient since now the majority of the processing time
is taken up with processing samples. Smaller chunks mean more calls
into the scheduler to retrieve more data. The downside to this is that
it can lead to large latency while a block is processing a large chunk
of data.
To combat this problem, the gr_top_block can be passed a limit on the
number of output items a block will ever receive. A block may get less
than this number, but never more, and so it serves as an upper limit
to the latency any block will exhibit. By limiting the number of items
per call to a block, though, we increase the overhead of the
scheduler, and so reduce the overall efficiency of the application.
To set the maximum number of output items, we pass a value into the
'start' or 'run' method of the gr_top_block:
\code
tb.start(1000)
tb.wait()
or
tb.run(1000)
\endcode
Using this method, we place a global restriction on the size of items
to all blocks. Each block, though, has the ability to overwrite this
with its own limit. Using the 'set_max_noutput_items(m)' method for an
individual block will overwrite the global setting. For example, in
the following code, the global setting is 1000 items max, except for
the FIR filter, which can receive up to 2000 items.
\code
tb.flt.set_max_noutput_items(2000)
tb.run(1000)
\endcode
In some situations, you might actually want to restrict the size of
the buffer itself. This can help to prevent a buffer who is blocked
for data from just increasing the amount of items in its buffer, which
will then cause an increased latency for new samples. You can set the
size of an output buffer for each output port for every block.
WARNING: This is an advanced feature in GNU Radio and should not be
used without a full understanding of this concept as explained below.
To set the output buffer size of a block, you simply call:
\code
tb.blk0.set_max_output_buffer(2000)
tb.blk1.set_max_output_buffer(1, 2000)
tb.start()
print tb.blk1.max_output_buffer(0)
print tb.blk1.max_output_buffer(1)
\endcode
In the above example, all ports of blk0 are set to a buffer size of
2000 in _items_ (not bytes), and blk1 only sets the size for output
port 1, any and all other ports use the default. The third and fourth
lines just print out the buffer sizes for ports 0 and 1 of blk1. This
is done after start() is called because the values are updated based
on what is actually allocated to the block's buffers.
NOTES:
1. Buffer length assignment is done once at runtime (i.e., when run()
or start() is called). So to set the max buffer lengths, the
set_max_output_buffer calls must be done before this.
2. Once the flowgraph is started, the buffer lengths for a block are
set and cannot be dynamically changed, even during a
lock()/unlock(). If you need to change the buffer size, you will have
to delete the block and rebuild it, and therefore must disconnect and
reconnect the blocks.
3. This can affect throughput. Large buffers are designed to improve
the efficiency and speed of the program at the expense of
latency. Limiting the size of the buffer may decrease performance.
4. The real buffer size is actually based on a minimum granularity of
the system. Typically, this is a page size, which is typically 4096
bytes. This means that any buffer size that is specified with this
command will get rounded up to the nearest granularity (e.g., page)
size. When calling max_output_buffer(port) after the flowgraph is
started, you will get how many items were actually allocated in the
buffer, which may be different than what was initially specified.
\section reconfigure Reconfiguring Flowgraphs
It is possible to reconfigure the flowgraph at runtime. The
reconfiguration is meant for changes in the flowgraph structure, not
individual parameter settings of the blocks. For example, changing the
constant in a gr::blocks::add_const_cc block can be done while the flowgraph is
running using the 'set_k(k)' method.
Reconfiguration is done by locking the flowgraph, which stops it from
running and processing data, performing the reconfiguration, and then
restarting the graph by unlocking it.
The following example code shows a graph that first adds two
gr::analog::noise_source_c blocks and then replaces the
gr::blocks::add_cc block with a gr::blocks::sub_cc block to then
subtract the sources.
\code
from gnuradio import gr, analog, blocks
import time
class mytb(gr.top_block):
def __init__(self):
gr.top_block.__init__(self)
self.src0 = analog.noise_source_c(analog.GR_GAUSSIAN, 1)
self.src1 = analog.noise_source_c(analog.GR_GAUSSIAN, 1)
self.add = blocks.add_cc()
self.sub = blocks.sub_cc()
self.head = blocks.head(gr.sizeof_gr_complex, 1000000)
self.snk = blocks.file_sink(gr.sizeof_gr_complex, "output.32fc")
self.connect(self.src0, (self.add,0))
self.connect(self.src1, (self.add,1))
self.connect(self.add, self.head)
self.connect(self.head, self.snk)
def main():
tb = mytb()
tb.start()
time.sleep(0.01)
# Stop flowgraph and disconnect the add block
tb.lock()
tb.disconnect(tb.add, tb.head)
tb.disconnect(tb.src0, (tb.add,0))
tb.disconnect(tb.src1, (tb.add,1))
# Connect the sub block and restart
tb.connect(tb.sub, tb.head)
tb.connect(tb.src0, (tb.sub,0))
tb.connect(tb.src1, (tb.sub,1))
tb.unlock()
tb.wait()
if __name__ == "__main__":
main()
\endcode
During reconfiguration, the maximum noutput_items value can be changed
either globally using the 'set_max_noutput_items(m)' on the gr_top_block
object or locally using the 'set_max_noutput_items(m)' on any given
block object.
A block also has a 'unset_max_noutput_items()' method that unsets the
local max noutput_items value so that block reverts back to using the
global value.
The following example expands the previous example but sets and resets
the max noutput_items both locally and globally.
\code
from gnuradio import gr, analog, blocks
import time
class mytb(gr.top_block):
def __init__(self):
gr.top_block.__init__(self)
self.src0 = analog.noise_source_c(analog.GR_GAUSSIAN, 1)
self.src1 = analog.noise_source_c(analog.GR_GAUSSIAN, 1)
self.add = blocks.add_cc()
self.sub = blocks.sub_cc()
self.head = blocks.head(gr.sizeof_gr_complex, 1000000)
self.snk = blocks.file_sink(gr.sizeof_gr_complex, "output.32fc")
self.connect(self.src0, (self.add,0))
self.connect(self.src1, (self.add,1))
self.connect(self.add, self.head)
self.connect(self.head, self.snk)
def main():
# Start the gr_top_block after setting some max noutput_items.
tb = mytb()
tb.src1.set_max_noutput_items(2000)
tb.start(100)
time.sleep(0.01)
# Stop flowgraph and disconnect the add block
tb.lock()
tb.disconnect(tb.add, tb.head)
tb.disconnect(tb.src0, (tb.add,0))
tb.disconnect(tb.src1, (tb.add,1))
# Connect the sub block
tb.connect(tb.sub, tb.head)
tb.connect(tb.src0, (tb.sub,0))
tb.connect(tb.src1, (tb.sub,1))
# Set new max_noutput_items for the gr_top_block
# and unset the local value for src1
tb.set_max_noutput_items(1000)
tb.src1.unset_max_noutput_items()
tb.unlock()
tb.wait()
if __name__ == "__main__":
main()
\endcode
\section volk_main Using Volk in GNU Radio
The \ref volk_guide page provides an overview of how to incorporate
and use Volk in GNU Radio blocks.
Many blocks have already been converted to use Volk in their calls, so
they can also serve as examples. See the
gr::blocks::complex_to_<type>.h files for examples of various blocks
that make use of Volk.
\section prefs Configuration / Preference Files
GNU Radio defines some of its basic behavior through a set of
configuration files located in
${prefix}/etc/gnuradio/conf.d. Different components have different
files listed in here for the various properties. These will be read
once when starting a GNU Radio application, so updates during runtime
will not affect them.
The configuration files use the following format:
\code
# Stuff from section 1
[section1]
var1 = value1
var2 = value2 # value of 2
# Stuff from section 2
[section2]
var3 = value3
\endcode
In this file, the hash mark ('#') indicates a comment and blank lines
are ignored. Section labels are defined inside square brackets as a
group distinguisher. All options must be associated with a section
name. The options are listed one per line with the option name is
given followed by an equals ('=') sign and then the value.
All section and option names must not have white spaces. If a value
must have white space, the it MUST be put inside quotes. Any quoted
value will have its white space preserved and the quotes internally
will be stripped. As an example, on Apple desktops, an output device
of "Display Audio" is a possible output device and can be set as:
\code
[audio_osx]
default_output_device = "Display Audio"
\endcode
The result will pass Display Audio to the audio setup.
The value of an option can be a string or number and retrieved through
a few different interfaces. There is a single preference object
created when GNU Radio is launched. In Python, you can get this by
making a new variable:
\code
p = gr.prefs()
\endcode
Similarly, in C++, we get a reference to the object by explicitly
calling for the singleton of the object:
\code
prefs *p = prefs::singleton();
\endcode
The methods associated with this preferences object are (from class gr::prefs):
\code
bool has_section(string section)
bool has_option(string section, string option)
string get_string(string section, string option, string default_val)
bool get_bool(string section, string option, bool default_val)
long get_long(string section, string option, long default_val)
double get_double(string section, string option, double default_val)
\endcode
When setting a Boolean value, we can use 0, 1, "True", "true",
"False", "false", "On", "on", "Off", and "off".
All configuration preferences in these files can also be overloaded by
an environmental variable. The environmental variable is named based
on the section and option name from the configuration file as:
\code
GR_CONF_<SECTION>_<OPTION> = <value>
\endcode
The "GR_CONF_" is a prefix to identify this as a GNU Radio
configuration variable and the section and option names are in
uppercase. The value is the same format that would be used in the
config file itself.
\section oot_config_page Out-of-Tree Configuration
New as of 3.6.5.
Using gr_modtool, each package comes with the ability to easily locate
the gnuradio-runtime library using the 'find_package(GnuradioRuntime)'
cmake command. This only locates the gnuradio-runtime library and
include directory, which is enough for most simple projects.
As projects become more complicated and start needing to rely on other
GNU Radio components like gnuradio-blocks or gnuradio-filter, for
example, and when they become dependent on certain API compatibility
versions of GNU Radio, we need something more. And so we have
introduced the GnuradioConfig.cmake file.
When GNU Radio is installed, it also installs a GNU Radio-specific
cmake config file that we can use for more advanced compatibility
issues of our projects. This tool allows us to specific the API
compatible version and a set of components that are required.
Taking the above example, say we have built against version 3.6.5 with
features that were introduced in this version and we need the blocks
and filter components as well as the main core library. We fist set a
cmake variable GR_REQUIRED_COMPONENTS to the components we need. We
then use the 'find_package' command and also set a minimum required
API compatible version. Since we are on the 3.6 API version, the
minimum required version is "3.6.5". The code in the CMakeLists.txt
file would look like this:
\code
set(GR_REQUIRED_COMPONENTS RUNTIME BLOCKS FILTER)
find_package(Gnuradio 3.6.5)
\endcode
Note that the capitalization is important on both lines.
If the installed version of GNU Radio is 3.6.4 or some other API
version like 3.5 or 3.7, the Cmake configuration will fail with the
version error. Likewise, if libgnuradio-filter was not installed as
part of GNU Radio, the configuration will also fail.
\subsection oot_config_path_page Install Path
Cmake has to know where to find either the package config files or the
GnuradioConfig.cmake script. The package config files are located in
$prefix/lib/pkgconfig while all of the Cmake scripts from GNU Radio
are installed into $prefix/lib/cmake/gnuradio.
If the installed GNU Radio $prefix is '/usr' or '/usr/local', then
everything should work fine. If the GNU Radio install $prefix is
something else, then Cmake must be told where to find it. This can be
done in a few ways:
1. If you are installing the out-of-tree module into the same $prefix,
then you would be setting '-DCMAKE_INSTALL_PREFIX' on the
configuration command line. This is enough to tell Cmake where to look
for the configuration files.
2. Cmake will try to find the package config (*.pc) files. If it can,
these files will instruct Cmake where to look for the rest of the
configuration options. If this is not set, it can be set as:
\code
export PKG_CONFIG_PATH=$prefix/lib/pkgconfg:$PKG_CONFIG_PATH
\endcode
3. Set the CMAKE_PREFIX_PATH environmental variable to $prefix.
\code
export CMAKE_PREFIX_PATH=$prefix:$CMAKE_PREFIX_PATH
\endcode
With method 1, you will be installing your OOT project into the same
$prefix as GNU Radio. With methods 2 and 3, you can install your
component anywhere you like (using -DCMAKE_INSTALL_PREFIX).
*/
|