/*! \mainpage
\image html gnuradio-logo.png
Welcome to GNU Radio!
For details about GNU Radio and using it, please see the main project page.
Other information about the project and discussion about GNU Radio,
software radio, and communication theory in general can be found at
the GNU Radio blog.
\section build Building GNU Radio
See the \ref page_build page for details about the project's
dependencies and build process.
\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 C++ Blocks.
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
\li \ref page_pfb
\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, filter
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 = gr.noise_source_c(gr.GR_GAUSSIAN, amp)
self.flt = filter.fir_filter_ccf(1, taps)
self.snk = gr.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
\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_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_noise_source_c blocks and then replaces the gr_add_cc block with a
gr_sub_cc block to then subtract the sources.
\code
from gnuradio import gr
import time
class mytb(gr.top_block):
def __init__(self):
gr.top_block.__init__(self)
self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
self.add = gr.add_cc()
self.sub = gr.sub_cc()
self.head = gr.head(gr.sizeof_gr_complex, 1000000)
self.snk = gr.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
import time
class mytb(gr.top_block):
def __init__(self):
gr.top_block.__init__(self)
self.src0 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
self.src1 = gr.noise_source_c(gr.GR_GAUSSIAN, 1)
self.add = gr.add_cc()
self.sub = gr.sub_cc()
self.head = gr.head(gr.sizeof_gr_complex, 1000000)
self.snk = gr.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_complex_to_xxx.h file for
examples of various blocks that make use of Volk.
*/