Editing Guided Tutorial GNU Radio in C++

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 1: Line 1:
[[Category:Guided Tutorials]]
+
< [[Guided_Tutorial_GNU_Radio_in_Python|Previous: Programming GNU Radio in Python]]
 +
> [[Guided_Tutorial_Programming_Topics|Next: Programming Topics]]
  
 
= Tutorial: Working with GNU Radio in C++ =
 
= Tutorial: Working with GNU Radio in C++ =
Line 21: Line 22:
 
* Knowledge of C++
 
* Knowledge of C++
 
* Previous tutorials recommended:
 
* Previous tutorials recommended:
** [[Guided_Tutorial_Introduction|'''A brief introduction to GNU Radio, SDR, and DSP''']]
+
** [[Guided_Tutorial_Introduction|Tutorials Introductions]]
** [[Guided_Tutorial_GRC|'''Intro to GR usage: GRC and flowgraphs''']]
+
** [[Guided_Tutorial_GRC|GRC Tutorial]]
 +
** [[Guided_Tutorial_GNU_Radio_in_Python|Programming GR in Python]]
  
= Creating our OOT module =
+
-----
  
We will now use gr_modtool to create an OOT module and write our block in C++.
+
= 4.1 C++ or Python? =
  
== Objective ==
+
This is a standard question that every one of us needs to consider before starting our own OOT module. Tutorial 3 already addressed ways to select the programming language of choice for the blocks in OOT module using <code>gr_modtool</code>
  
When this tutorial is complete, we will be able to build this flow graph:
+
$ gr_modtool add -t sync -l python
 +
or
  
[[File:Tutorial4_fg.png]]
+
$ gr_modtool add -t sync -l cpp # This is the default
  
The flowgraph demonstrates a QPSK transceiver chain with the block '''My QPSK Demodulator''' block module under the OOT '''tutorial'''. We will be building this block using C++. All other blocks are standard GNU Radio blocks.
+
Apart from the compiler and interpreter, there are many differences out there. To decide upon the choice of the programming language, it is important that we limit the differences from the GNU Radio perspective. Primarily, it depends more on the objective of the OOT module. As far as the performance is concerned, implementing the blocks in C++ makes more sense, and if the performance of the OOT module is the not main issue Python would be a good choice, as it is concise yet simple. Moreover, Python allows faster prototyping as we don't have to compile to test the modules.
  
'''My QPSK Demodulator''' consumes QPSK symbols which are complex values at the input and produces the alphabets as bytes at output. The output screen looks like this:
+
= 4.2 Maneuvering our OOT module =
  
[[File:Tutorial4_out.png|700px]]
+
Introduced in tutorial 3, we will now extend the usage of gr_modtool to create an OOT module and write our blocks in C++.
  
== Step 1: Create an OOT module <code>gr-tutorial</code> ==
+
For a detailed explanation of <code>gr_modtool</code> commands, go [http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_GNU_Radio_in_Python#321-Using-gr_modtool here], or have a quick peek at the cheat sheet.
  
xyz@comp:mydir$ gr_modtool newmod tutorial
+
{{collapse(gr_modtool cheat sheet)<br />
Creating out-of-tree module in ./gr-tutorial... Done.
+
|'''Name'''| '''Alias'''| '''Description''' |<br />
Use 'gr_modtool add' to add a new block to this currently empty module.
+
|help| h | Enlist the operations available|<br />
 +
|disable| dis | Disable block (comments out CMake entries for files)|<br />
 +
|info| getinfo, inf | Return information about a given module |<br />
 +
|remove| rm, del| Remove block (delete files and remove Makefile entries)|<br />
 +
|makexml| mx| Make XML file for GRC block bindings (Experimental feature!)|<br />
 +
|add| insert| Add block to the out-of-tree module.|<br />
 +
|newmod| nm,create| Create a new out-of-tree module |<br />
 +
}}
  
Take a look at the directory structure of our <code>gr-tutorial</code>
+
== 4.2.1 Objective ==
  
xyz@comp:mydir$ cd ~/gr-tutorial
+
When this tutorial is complete, we will be able to build this flow graph:
xyz@comp:mydir/gr-tutorial$ ls
 
apps  cmake  CMakeLists.txt  docs  examples  grc  include  lib  MANIFEST.md  python  swig
 
  
Note: The file MANIFEST.md was not added prior to GR 3.8.
+
[[File:https://raw.githubusercontent.com/gnuradio/gr-tutorial/master/examples/tutorial4/figs/Tut4_My_QPSK_demod_flowgraph.png|600px|Tut4_My_QPSK_demod_flowgraph.png]]
  
== Step 2: Insert My QPSK Demodulator block into the OOT module ==
+
The flowgraph demonstrates a QPSK transceiver chain with the block '''My QPSK Demodulator''' block module under the OOT '''tutorial'''. We will be building this block using C++. All other blocks are standard GNU Radio blocks.
  
Again using <code>gr_modtool</code>, inside <code>gr-tutorial</code>, we create our <code>my_qpsk_demod</code> block:
+
As in the previous tutorial, '''My QPSK Demodulator''' consumes QPSK symbols which are complex valued floats at the input and produces the alphabets as bytes at output. We will plot the binary values (from 0 through 3) as well as the transmitted complex symbols during operation.
  
xyz@comp:mydir/gr-tutorial$ gr_modtool add my_qpsk_demod_cb
+
Alright, lets get started.
GNU Radio module name identified: tutorial
 
('sink', 'source', 'sync', 'decimator', 'interpolator', 'general', 'tagged_stream', 'hier', 'noblock')
 
Enter block type: general
 
Language (python/cpp): cpp
 
Language: C++
 
Block/code identifier: my_qpsk_demod_cb
 
Please specify the copyright holder: gnuradio.org
 
Enter valid argument list, including default arguments:
 
bool gray_code
 
Add Python QA code? [Y/n] Y
 
Add C++ QA code? [y/N] N
 
Adding file 'lib/my_qpsk_demod_cb_impl.h'...
 
Adding file 'lib/my_qpsk_demod_cb_impl.cc'...
 
Adding file 'include/tutorial/my_qpsk_demod_cb.h'...
 
Editing swig/tutorial_swig.i...
 
Adding file 'python/qa_my_qpsk_demod_cb.py'...
 
Editing python/CMakeLists.txt...
 
Adding file 'grc/tutorial_my_qpsk_demod_cb.block.yml'...
 
Editing grc/CMakeLists.txt...
 
  
Unlike creating an OOT module, creating a block using <code>gr_modtool</code> demands inputs from the user. To follow the command line user interaction, let's decompose the information above.
+
== 4.2.2 Step 1: Create an OOT module <code>gr-tutorial</code> ==
  
xyz@comp:mydir/gr-tutorial$ gr_modtool add my_qpsk_demod_cb
+
<pre>
 +
xyz@comp:mydir$ gr_modtool nm tutorial
 +
Creating out-of-tree module in ./gr-tutorial... Done.
 +
Use 'gr_modtool add' to add a new block to this currently empty module.
 +
xyz@comp:mydir$ ls
 +
xyz@comp:mydir$ gr-tutorial</pre>
 +
Have a look into the dir structure of our <code>gr-tutorial</code>
  
<code>my_qpsk_demod_cb</code> represents the class name of the block, where the suffix, 'cb' is added to the block name, which conforms to the GNU Radio nomenclature. 'cb' states the block takes complex data as input and produces bytes as output.
+
<pre>
 +
xyz@comp:mydir$ cd gr-tutorial
 +
xyz@comp:mydir/gr-tutorial$ ls
 +
apps  cmake  CMakeLists.txt  docs  examples  grc  include  lib  python  swig</pre>
 +
== 4.2.3 Step 2: Insert My QPSK Demodulator block into the OOT module ==
  
Enter code type: general
+
Again using <code>gr_modtool</code>, inside <code>gr-tutorial</code>, we create our <code>my_qpsk_demod</code> block:
  
In GNU Radio, there exist different kinds of blocks with the different possibilities listed above (since 3.8). Depending on the choice of our block, <code>gr_modtool</code> adds the corresponding code and functions. As illustrated, for <code>my_qpsk_demod_cb</code> block, we opt for a general block.
+
<pre>
 +
xyz@comp:mydir/gr-tutorial$ gr_modtool add my_qpsk_demod_cb
 +
GNU Radio module name identified: tutorial
 +
Enter code type: general
 +
Language: C++
 +
Block/code identifier: my_qpsk_demod_cb
 +
Enter valid argument list, including default arguments:  bool gray_code
 +
Add Python QA code? [Y/n]
 +
Add C++ QA code? [y/N] Y
 +
Adding file 'my_qpsk_demod_cb_impl.h'...
 +
Adding file 'my_qpsk_demod_cb_impl.cc'...
 +
Adding file 'my_qpsk_demod_cb.h'...
 +
Editing swig/qpsk_demod_swig.i...
 +
Adding file 'qa_my_qpsk_demod_cb.py'...
 +
Editing python/CMakeLists.txt...
 +
Adding file 'qpsk_demod_my_qpsk_demod_cb.xml'...
 +
Editing grc/CMakeLists.txt...</pre>
 +
Unlike when creating an OOT module, creating a block using <code>gr_modtool</code> demand inputs from the user. To follow the command line user interaction, let's decompose the information above.
  
  Please specify the copyright holder:
+
  xyz@comp:mydir/gr-tutorial$ gr_modtool add my_qpsk_demod_cb
 +
<code>my_qpsk_demod_cb</code> represents class name of the block, where the suffix, 'cb' is added to the block name, which conform to the GNU Radio nomenclature. 'cb' states the block established that takes complex data as input and spits byte as output.
  
Since version 3.8, the tool asks for a copyright holder for the code you are about to write. The implications of what you write in that line are legal and not computational.
+
Enter code type: general
 
+
In GNU Radio, there exist different kinds of blocks: general, sync, interpolator/decimator, source/sink, Hierarchical, etc. Depending on the choice of our block, <code>gr_modtool</code> adds the corresponding code and functions. As illustrated, for <code>my_qpsk_demod_cb</code> block, we opt for a general block. The following [http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_GNU_Radio_in_C++#432-Specific-block-categories section] will discuss the purpose of the specific blocks in detail.<br />
For <code>my_qpsk_demod_cb</code>, gray_code is selected to be "default arguments".
+
In many cases, the block demands a user interface. For <code>my_qpsk_demod_cb</code>, gray_code is selected to be &quot;default arguments&quot;.
  
 
  Enter valid argument list, including default arguments:  bool gray_code
 
  Enter valid argument list, including default arguments:  bool gray_code
 +
Moreover, GNU Radio provides an option of writing test cases. This provides quality assurance to the code written. If selected, the <code>gr_modtool</code> adds the quality assurance files corresponding to python and C++.
  
GNU Radio provides an option of writing test cases. This provides quality assurance to the code written. If selected, the <code>gr_modtool</code> adds the quality assurance files corresponding to python and C++.
+
<pre>
 +
Add Python QA code? [Y/n]
 +
Add C++ QA code? [y/N] y</pre>
 +
With this, we have already established the GNU Radio semantics for our block coupled with the OOT module. In the following sections, we will focus on the implementation of our block.<br />
 +
The detailed description of coding structure for the block can be found [http://gnuradio.org/redmine/projects/gnuradio/wiki/BlocksCodingGuide#Public-Header-Files here]
  
Add Python QA code? [Y/n]
+
== 4.2.4 Step 3: Fleshing out the code ==
Add C++ QA code? [y/N] y
 
  
With this, we have already established the GNU Radio semantics for our block coupled with the OOT module. In the following sections, we will focus on the implementation of our block.
+
The next step is to implement the logic for our block. This is done inside the work function which is defined in the source file <code>my_qpsk_demod_cb_impl.cc</code> inside the <code>lib/</code> folder. The skeleton of the <code>my_qpsk_demod_cb_impl.cc</code> has the following structure:
 
 
The detailed description of coding structure for the block can be found [[BlocksCodingGuide|here]].
 
 
 
== Step 3: Fleshing out the code ==
 
 
 
The next step is to implement the logic for our block. Use your text editor on the file <code>~/gr-tutorial/lib/my_qpsk_demod_cb_impl.cc</code>.
 
 
 
The completed code is listed at the end of this section, but study the following first!
 
 
 
The skeleton of the <code>my_qpsk_demod_cb_impl.cc</code> has the following structure:
 
  
 
<syntaxhighlight lang="cpp" line="line">
 
<syntaxhighlight lang="cpp" line="line">
Line 119: Line 130:
 
     */
 
     */
 
     my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
 
     my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
       : gr::block("my_qpsk_demod_cb",
+
       : gr::block(&quot;my_qpsk_demod_cb&quot;,
 
               gr::io_signature::make(<+MIN_IN+>, <+MAX_IN+>, sizeof(<+ITYPE+>)),
 
               gr::io_signature::make(<+MIN_IN+>, <+MAX_IN+>, sizeof(<+ITYPE+>)),
 
               gr::io_signature::make(<+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>)))
 
               gr::io_signature::make(<+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>)))
 
     {}
 
     {}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
* <code>my_qpsk_demod_cb_impl()</code> is the constructor of the block <code>my_qpsk_demod</code>. <code>my_qpsk_demod_cb_impl()</code> calls the constructor of the base class block <code>gr::block(...)</code> defined [http://gnuradio.org/doc/doxygen/basic__block_8h_source.html here].
 
* <code>my_qpsk_demod_cb_impl()</code> is the constructor of the block <code>my_qpsk_demod</code>. <code>my_qpsk_demod_cb_impl()</code> calls the constructor of the base class block <code>gr::block(...)</code> defined [http://gnuradio.org/doc/doxygen/basic__block_8h_source.html here].
  
 
* The arguments inside <code>gr::block(...)</code> represents the block name and a call to the make function.
 
* The arguments inside <code>gr::block(...)</code> represents the block name and a call to the make function.
  
* The make function <code>gr::io_signature::make(<+MIN_IN+>, <+MAX_IN+>, sizeof(<+ITYPE+>))</code> and <code>gr::io_signature::make(<+MIN_OUT+>, <+MAX_OUT+>, sizeof(<+OTYPE+>))</code> is a member function of the class <code>gr::io_signature</code> that signifies the input and output port/s.
+
* The make function <code>gr::io_signature::make(&lt;+MIN_IN+&gt;, &lt;+MAX_IN+&gt;, sizeof(&lt;+ITYPE+&gt;))</code> and <code>gr::io_signature::make(&lt;+MIN_OUT+&gt;, &lt;+MAX_OUT+&gt;, sizeof(&lt;+OTYPE+&gt;)</code> is a member function of the class <code>gr::io_signature</code> that signifies the input and output port/s.
  
* <''MIN_OUT''> and <''MAX_OUT''> represents the maximum and number of ports.
+
* &lt;''MIN_OUT''&gt; and &lt;''MAX_OUT''&gt; represents the maximum and number of ports.
  
 
* <ITYPE> and <OTYPE> indicates the datatypes for the input and output port/s which needs to be filled out manually.<br />
 
* <ITYPE> and <OTYPE> indicates the datatypes for the input and output port/s which needs to be filled out manually.<br />
Line 141: Line 151:
 
     */
 
     */
 
     my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
 
     my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
       : gr::block("my_qpsk_demod_cb",
+
       : gr::block(&quot;my_qpsk_demod_cb&quot;,
 
               gr::io_signature::make(1, 1, sizeof(gr_complex)),
 
               gr::io_signature::make(1, 1, sizeof(gr_complex)),
 
               gr::io_signature::make(1, 1, sizeof(char))),
 
               gr::io_signature::make(1, 1, sizeof(char))),
Line 147: Line 157:
 
     {}
 
     {}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
The option <code>gray_code</code> is copied to the class attribute <code>d_gray_code</code>. Note that we need<br />
 
The option <code>gray_code</code> is copied to the class attribute <code>d_gray_code</code>. Note that we need<br />
 
to declare this a private member of the class in the header file <code>my_qpsk_demod_cb_impl.h</code>,
 
to declare this a private member of the class in the header file <code>my_qpsk_demod_cb_impl.h</code>,
Line 155: Line 164:
 
       bool d_gray_code;
 
       bool d_gray_code;
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
Also inside this class is the method <code>general_work()</code>, which is pure virtual in <code>gr::block</code>, so we definitely need to override that. After running <code>gr_modtool</code>,<br />
Also inside this class is the method <code>general_work()</code>, which is pure virtual in <code>gr::block</code>, so we definitely need to override that. After running <code>gr_modtool</code>, the skeleton version of this function will look something like this:
+
the skeleton version of this function will look something like this:
  
 
<syntaxhighlight lang="cpp" line="line">
 
<syntaxhighlight lang="cpp" line="line">
 
int
 
int
 
my_qpsk_demod_cb_impl::general_work (int noutput_items,
 
my_qpsk_demod_cb_impl::general_work (int noutput_items,
                   gr_vector_int &ninput_items,
+
                   gr_vector_int &amp;ninput_items,
                   gr_vector_const_void_star &input_items,
+
                   gr_vector_const_void_star &amp;input_items,
                   gr_vector_void_star &output_items)
+
                   gr_vector_void_star &amp;output_items)
 
{
 
{
     const <+ITYPE*> *in = (const <+ITYPE*> *) input_items[0];
+
     const &lt;+ITYPE*&gt; *in = (const &lt;+ITYPE*&gt; *) input_items[0];
     <+OTYPE*> *out = (<+OTYPE*> *) output_items[0];
+
     &lt;+OTYPE*&gt; *out = (&lt;+OTYPE*&gt; *) output_items[0];
  
     // Do <+signal processing+>
+
     // Do &lt;+signal processing+&gt;
 
     // Tell runtime system how many input items we consumed on
 
     // Tell runtime system how many input items we consumed on
 
     // each input stream.
 
     // each input stream.
Line 177: Line 186:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
There is one pointer to the input- and one pointer to the output buffer, respectively, and a for-loop which processes the items in the input buffer and copies them to the output buffer. Once the demodulation logic is implemented, the structure of the work function has the form
 
There is one pointer to the input- and one pointer to the output buffer, respectively, and a for-loop which processes the items in the input buffer and copies them to the output buffer. Once the demodulation logic is implemented, the structure of the work function has the form
  
Line 183: Line 191:
 
     int
 
     int
 
     my_qpsk_demod_cb_impl::general_work (int noutput_items,
 
     my_qpsk_demod_cb_impl::general_work (int noutput_items,
                       gr_vector_int &ninput_items,
+
                       gr_vector_int &amp;ninput_items,
                       gr_vector_const_void_star &input_items,
+
                       gr_vector_const_void_star &amp;input_items,
                       gr_vector_void_star &output_items)
+
                       gr_vector_void_star &amp;output_items)
 
     {
 
     {
 
         const gr_complex *in = (const gr_complex *) input_items[0];
 
         const gr_complex *in = (const gr_complex *) input_items[0];
Line 191: Line 199:
 
         gr_complex origin = gr_complex(0,0);
 
         gr_complex origin = gr_complex(0,0);
 
         // Perform ML decoding over the input iq data to generate alphabets
 
         // Perform ML decoding over the input iq data to generate alphabets
         for(int i = 0; i < noutput_items; i++)
+
         for(int i = 0; i &lt; noutput_items; i++)
 
         {
 
         {
 
                 // ML decoder, determine the minimum distance from all constellation points
 
                 // ML decoder, determine the minimum distance from all constellation points
Line 205: Line 213:
 
     }
 
     }
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
This work function calls another function <code>get_minimum_distances(const gr_complex &amp;sample)</code>, which we also need to add:
This work function calls another function <code>get_minimum_distances(const gr_complex &sample)</code>, which we also need to add:
 
  
 
<syntaxhighlight lang="cpp" line="line">
 
<syntaxhighlight lang="cpp" line="line">
 
     unsigned char
 
     unsigned char
     my_qpsk_demod_cb_impl::get_minimum_distances(const gr_complex &sample)
+
     my_qpsk_demod_cb_impl::get_minimum_distances(const gr_complex &amp;sample)
 
     {
 
     {
 
       if (d_gray_code) {
 
       if (d_gray_code) {
 
         unsigned char bit0 = 0;
 
         unsigned char bit0 = 0;
 
         unsigned char bit1 = 0;
 
         unsigned char bit1 = 0;
         // The two left quadrants (quadrature component < 0) have this bit set to 1
+
         // The two left quadrants (quadrature component &lt; 0) have this bit set to 1
         if (sample.real() < 0) {
+
         if (sample.real() &lt; 0) {
 
           bit0 = 0x01;
 
           bit0 = 0x01;
 
         }
 
         }
         // The two lower quadrants (in-phase component < 0) have this bit set to 1
+
         // The two lower quadrants (in-phase component &lt; 0) have this bit set to 1
         if (sample.imag() < 0) {
+
         if (sample.imag() &lt; 0) {
           bit1 = 0x01 << 1;
+
           bit1 = 0x01 &lt;&lt; 1;
 
         }
 
         }
 
         return bit0 | bit1;
 
         return bit0 | bit1;
 
       } else {
 
       } else {
 
         // For non-gray code, we can't simply decide on signs, so we check every single quadrant.
 
         // For non-gray code, we can't simply decide on signs, so we check every single quadrant.
         if (sample.imag() >= 0 and sample.real() >= 0) {
+
         if (sample.imag() &gt;= 0 and sample.real() &gt;= 0) {
 
           return 0x00;
 
           return 0x00;
 
         }
 
         }
         else if (sample.imag() >= 0 and sample.real() < 0) {
+
         else if (sample.imag() &gt;= 0 and sample.real() &lt; 0) {
 
           return 0x01;
 
           return 0x01;
 
         }
 
         }
         else if (sample.imag() < 0 and sample.real() < 0) {
+
         else if (sample.imag() &lt; 0 and sample.real() &lt; 0) {
 
           return 0x02;
 
           return 0x02;
 
         }
 
         }
         else if (sample.imag() < 0 and sample.real() >= 0) {
+
         else if (sample.imag() &lt; 0 and sample.real() &gt;= 0) {
 
           return 0x03;
 
           return 0x03;
 
         }
 
         }
Line 242: Line 249:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Note: the get_minimum_distances function declaration also needs to be added to the class header (<code>my_qpsk_demod_cb_impl.h</code>).
+
Note the function declaration also needs to be added to the class header (<code>my_qpsk_demod_cb_impl.h</code>).<br />
 
 
 
The function <code>get_minimum_distances</code> is a maximum likelihood decoder for the QPSK demodulater. Theoretically, the function should compute the distance from each ideal QPSK symbol to the received symbol (It is mathematically equivalent to determining the Voronoi regions of the received sample). For a QPSK signal, these Voronoi regions are simply four quadrants in the complex plane. Hence, to decode the sample into bits, it makes sense to map the received sample to these quadrants.
 
The function <code>get_minimum_distances</code> is a maximum likelihood decoder for the QPSK demodulater. Theoretically, the function should compute the distance from each ideal QPSK symbol to the received symbol (It is mathematically equivalent to determining the Voronoi regions of the received sample). For a QPSK signal, these Voronoi regions are simply four quadrants in the complex plane. Hence, to decode the sample into bits, it makes sense to map the received sample to these quadrants.
  
Line 254: Line 260:
 
   void
 
   void
 
   gr::block::forecast(int noutput_items,
 
   gr::block::forecast(int noutput_items,
                     gr_vector_int &ninput_items_required)
+
                     gr_vector_int &amp;ninput_items_required)
 
   {
 
   {
 
     unsigned ninputs = ninput_items_required.size ();
 
     unsigned ninputs = ninput_items_required.size ();
     for(unsigned i = 0; i < ninputs; i++)
+
     for(unsigned i = 0; i &lt; ninputs; i++)
 
       ninput_items_required[i] = noutput_items;
 
       ninput_items_required[i] = noutput_items;
 
   }
 
   }
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
Although the 1:1 implementation worked for <code>my_qpsk_demod_cb</code>, it wouldn't be appropriate for interpolators, decimators, or blocks with a more complicated relationship between <code>noutput_items</code> and the input requirements. That said, by deriving your classes from <code>gr::sync_block</code>, <code>gr::sync_interpolator</code> or <code>gr::sync_decimator</code> instead of <code>gr::block</code>, you can often avoid implementing <code>forecast</code>.
 
Although the 1:1 implementation worked for <code>my_qpsk_demod_cb</code>, it wouldn't be appropriate for interpolators, decimators, or blocks with a more complicated relationship between <code>noutput_items</code> and the input requirements. That said, by deriving your classes from <code>gr::sync_block</code>, <code>gr::sync_interpolator</code> or <code>gr::sync_decimator</code> instead of <code>gr::block</code>, you can often avoid implementing <code>forecast</code>.
  
 
Refilling the private constructor and overriding the <code>general_work()</code> and <code>forecast()</code> will suffice the coding structure of our block. However, in the <code>gr::block</code> class there exists more specific functions. These functions are covered under [http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_GNU_Radio_in_C++#Advanced-topics advanced topics section]
 
Refilling the private constructor and overriding the <code>general_work()</code> and <code>forecast()</code> will suffice the coding structure of our block. However, in the <code>gr::block</code> class there exists more specific functions. These functions are covered under [http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_GNU_Radio_in_C++#Advanced-topics advanced topics section]
  
Here is the completed source code:
+
== 4.2.5 Step 4: Flesh out the XML file ==
 
 
<syntaxhighlight lang="cpp" line="line">
 
/* -*- c++ -*- */
 
/*
 
* my_qpsk_demod_cb_impl.h
 
*
 
* This is free software; you can redistribute it and/or modify
 
* it under the terms of the GNU General Public License as published by
 
* the Free Software Foundation; either version 3, or (at your option)
 
* any later version.
 
*
 
* This software is distributed in the hope that it will be useful,
 
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
* GNU General Public License for more details.
 
*
 
* You should have received a copy of the GNU General Public License
 
* along with this software; see the file COPYING.  If not, write to
 
* the Free Software Foundation, Inc., 51 Franklin Street,
 
* Boston, MA 02110-1301, USA.
 
*/
 
 
 
#ifndef INCLUDED_TUTORIAL_MY_QPSK_DEMOD_CB_IMPL_H
 
#define INCLUDED_TUTORIAL_MY_QPSK_DEMOD_CB_IMPL_H
 
 
 
#include <tutorial/my_qpsk_demod_cb.h>
 
 
 
namespace gr {
 
  namespace tutorial {
 
 
 
    class my_qpsk_demod_cb_impl : public my_qpsk_demod_cb
 
    {
 
    private:
 
      bool d_gray_code;
 
 
 
    public:
 
      my_qpsk_demod_cb_impl(bool gray_code);
 
      ~my_qpsk_demod_cb_impl();
 
      unsigned char get_minimum_distances(const gr_complex &sample);
 
 
 
      // Where all the action really happens
 
      void forecast (int noutput_items, gr_vector_int &ninput_items_required);
 
 
 
      int general_work(int noutput_items,
 
          gr_vector_int &ninput_items,
 
          gr_vector_const_void_star &input_items,
 
          gr_vector_void_star &output_items);
 
    };
 
 
 
  } // namespace tutorial
 
} // namespace gr
 
 
 
#endif /* INCLUDED_TUTORIAL_MY_QPSK_DEMOD_CB_IMPL_H */
 
</syntaxhighlight>
 
 
 
<syntaxhighlight lang="cpp" line="line">
 
/* -*- c++ -*- */
 
/*
 
* my_qpsk_demod_cb_impl.cc
 
*
 
* This is free software; you can redistribute it and/or modify
 
* it under the terms of the GNU General Public License as published by
 
* the Free Software Foundation; either version 3, or (at your option)
 
* any later version.
 
*
 
* This software is distributed in the hope that it will be useful,
 
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
* GNU General Public License for more details.
 
*
 
* You should have received a copy of the GNU General Public License
 
* along with this software; see the file COPYING.  If not, write to
 
* the Free Software Foundation, Inc., 51 Franklin Street,
 
* Boston, MA 02110-1301, USA.
 
*/
 
 
 
#ifdef HAVE_CONFIG_H
 
#include "config.h"
 
#endif
 
 
 
#include <gnuradio/io_signature.h>
 
#include "my_qpsk_demod_cb_impl.h"
 
 
 
namespace gr {
 
  namespace tutorial {
 
 
 
    my_qpsk_demod_cb::sptr
 
    my_qpsk_demod_cb::make(bool gray_code)
 
    {
 
      return gnuradio::get_initial_sptr
 
        (new my_qpsk_demod_cb_impl(gray_code));
 
    }
 
 
 
    /*
 
    * The private constructor
 
    */
 
    my_qpsk_demod_cb_impl::my_qpsk_demod_cb_impl(bool gray_code)
 
      : gr::block("my_qpsk_demod_cb",
 
              gr::io_signature::make(1, 1, sizeof(gr_complex)),
 
              gr::io_signature::make(1, 1, sizeof(char))),
 
        d_gray_code(gray_code)
 
    {
 
    }
 
 
 
    /*
 
    * Our virtual destructor.
 
    */
 
    my_qpsk_demod_cb_impl::~my_qpsk_demod_cb_impl()
 
    {
 
    }
 
 
 
    void
 
    my_qpsk_demod_cb_impl::forecast(int noutput_items,
 
                    gr_vector_int &ninput_items_required)
 
    {
 
    unsigned ninputs = ninput_items_required.size ();
 
    for(unsigned i = 0; i < ninputs; i++)
 
      ninput_items_required[i] = noutput_items;
 
    }
 
 
 
    unsigned char
 
    my_qpsk_demod_cb_impl::get_minimum_distances(const gr_complex &sample)
 
    {
 
      if (d_gray_code) {
 
        unsigned char bit0 = 0;
 
        unsigned char bit1 = 0;
 
        // The two left quadrants (quadrature component < 0) have this bit set to 1
 
        if (sample.real() < 0) {
 
          bit0 = 0x01;
 
        }
 
        // The two lower quadrants (in-phase component < 0) have this bit set to 1
 
        if (sample.imag() < 0) {
 
          bit1 = 0x01 << 1;
 
        }
 
        return bit0 | bit1;
 
      } else {
 
        // For non-gray code, we can't simply decide on signs, so we check every single quadrant.
 
        if (sample.imag() >= 0 and sample.real() >= 0) {
 
          return 0x00;
 
        }
 
        else if (sample.imag() >= 0 and sample.real() < 0) {
 
          return 0x01;
 
        }
 
        else if (sample.imag() < 0 and sample.real() < 0) {
 
          return 0x02;
 
        }
 
        else if (sample.imag() < 0 and sample.real() >= 0) {
 
          return 0x03;
 
        }
 
      }
 
    }
 
 
 
    int
 
    my_qpsk_demod_cb_impl::general_work (int noutput_items,
 
                      gr_vector_int &ninput_items,
 
                      gr_vector_const_void_star &input_items,
 
                      gr_vector_void_star &output_items)
 
    {
 
        const gr_complex *in = (const gr_complex *) input_items[0];
 
        unsigned char *out = (unsigned char *) output_items[0];
 
        gr_complex origin = gr_complex(0,0);
 
        // Perform ML decoding over the input iq data to generate alphabets
 
        for(int i = 0; i < noutput_items; i++)
 
        {
 
                // ML decoder, determine the minimum distance from all constellation points
 
                out[i] = get_minimum_distances(in[i]);
 
        }
 
        // Tell runtime system how many input items we consumed on
 
        // each input stream.
 
        consume_each (noutput_items);
 
        // Tell runtime system how many output items we produced.
 
        return noutput_items;
 
    }
 
  
  } /* namespace tutorial */
+
The .xml provides the user interface between the OOT module displayed in the GRC and the source code. Moreover, the XML file defines an interface to pass the parameters specific for the module. Hence, to access the module inside GRC, it is important to modify the .xml files manually. The XML file for our block is named as <code>demod_my_qpsk_demod_cb.xml</code> inside the <code>grc/</code> folder. Presently, the <code>gr_modtool</code>'s version looks like:
} /* namespace gr */
 
</syntaxhighlight>
 
  
== Step 4: Flesh out the XML file ==
+
{{collapse(Default version:)
  
In GNU Radio 3.7 the .xml provides the user interface between the OOT module displayed in the GRC and the source code. For GNU Radio 3.8 and newer, see the next section which describes the YAML format. Moreover, the XML file defines an interface to pass the parameters specific for the module. Hence, to access the module inside GRC, it is important to modify the .xml files manually. The XML file for our block is named as <code>demod_my_qpsk_demod_cb.xml</code> inside the <code>grc/</code> folder. Presently, the <code>gr_modtool</code>'s version looks like:
 
 
Default version:
 
 
<pre>
 
<pre>
<?xml version="1.0"?>
 
<block>
 
  <name>my_qpsk_demod_cb</name>
 
  <key>tutorial_my_qpsk_demod_cb</key>
 
  <category>tutorial</category>
 
  <import>import tutorial</import>
 
  <make>tutorial.my_qpsk_demod_cb($gray_code)</make>
 
  <!-- Make one 'param' node for every Parameter you want settable from the GUI.
 
      Sub-nodes:
 
      * name
 
      * key (makes the value accessible as $keyname, e.g. in the make node)
 
      * type -->
 
  <param>
 
    <name>...</name>
 
    <key>...</key>
 
    <type>...</type>
 
  </param>
 
  
   <!-- Make one 'sink' node per input. Sub-nodes:
+
   my_qpsk_demod_cb
      * name (an identifier for the GUI)
+
  tutorial_my_qpsk_demod_cb
      * type
+
  tutorial
      * vlen
+
  import tutorial
      * optional (set to 1 for optional inputs) -->
+
  tutorial.my_qpsk_demod_cb($gray_code)
   <sink>
+
    
     <name>in</name>
+
 
     <type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
+
     ...
   </sink>
+
     ...
 +
    ...
 +
    
  
   <!-- Make one 'source' node per output. Sub-nodes:
+
    
      * name (an identifier for the GUI)
+
    
      * type
+
     in
      * vlen
+
      
      * optional (set to 1 for optional inputs) -->
+
    
   <source>
 
     <name>out</name>
 
     <type><!-- e.g. int, float, complex, byte, short, xxx_vector, ...--></type>
 
   </source>
 
</block>
 
  
 +
 
 +
 
 +
    out
 +
   
 +
 
 
</pre>
 
</pre>
 +
}}
  
 +
The parameter <code>gray_code</code> can be put under the <code>&lt;parameter&gt;</code> tag.
  
The parameter <code>gray_code</code> can be put under the <code><parameter></code> tag.
+
{{collapse(Adding parameter tag:)
 
 
Adding parameter tag:
 
  
 
<pre>
 
<pre>
   <?xml version="1.0"?>
+
    
  <param>
+
     Gray Code
     <name>Gray Code</name>
+
     gray_code
     <key>gray_code</key>
+
     True
     <value>True</value>
+
     bool
     <type>bool</type>
+
      
     <option>
+
       Yes
       <name>Yes</name>
+
       True
       <key>True</key>
+
      
     </option>
+
      
     <option>
+
       No
       <name>No</name>
+
       False
       <key>False</key>
+
      
     </option>
 
  </param> 
 
 
   </pre>
 
   </pre>
 +
}}
  
 +
Like the work function, the datatypes for the input and output ports represented by <code>&lt;sink&gt;</code> and <code>&lt;source&gt;</code> tags should be modified.
  
Like the work function, the datatypes for the input and output ports represented by <code><sink></code> and <code><nowiki><source></nowiki></code> tags should be modified.
+
{{collapse(Modifying source and sink tag:)
 
 
Modifying source and sink tag:
 
  
 
<pre>   
 
<pre>   
<sink>
+
     in
     <name>in</name>
+
     complex
     <type>complex</type>
 
  </sink>
 
 
   </pre>
 
   </pre>
 
<pre>   
 
<pre>   
<source>
+
     out
     <name>out</name>
+
     byte
     <type>byte</type>
 
  </source>
 
 
   </pre>
 
   </pre>
 +
}}
  
 +
After all the necessary modification the &quot;tutorial_my_qpsk_demod_cb.xml&quot; looks like this:
  
After all the necessary modification the "tutorial_my_qpsk_demod_cb.xml" looks like this:
+
{{collapse(Modified version:)
 
 
Modified version:
 
  
 
<pre>
 
<pre>
<?xml version="1.0"?>
 
<block>
 
  <name>My QPSK Demodulator</name>
 
  <key>tutorial_my_qpsk_demod_cb</key>
 
  <category>tutorial</category>
 
  <import>import tutorial</import>
 
  <make>tutorial.my_qpsk_demod_cb($gray_code)</make>
 
  <param>
 
    <name>Gray Code</name>
 
    <key>gray_code</key>
 
    <value>True</value>
 
    <type>bool</type>
 
    <option>
 
      <name>Yes</name>
 
      <key>True</key>
 
    </option>
 
    <option>
 
      <name>No</name>
 
      <key>False</key>
 
    </option>
 
  </param>
 
  <sink>
 
    <name>in</name>
 
    <type>complex</type>
 
  </sink>
 
  <source>
 
    <name>out</name>
 
    <type>byte</type>
 
  </source>
 
</block>
 
  
 +
  My QPSK Demodulator
 +
  tutorial_my_qpsk_demod_cb
 +
  tutorial
 +
  import tutorial
 +
  tutorial.my_qpsk_demod_cb($gray_code)
 +
 
 +
    Gray Code
 +
    gray_code
 +
    True
 +
    bool
 +
   
 +
      Yes
 +
      True
 +
   
 +
   
 +
      No
 +
      False
 +
   
 +
 
 +
 
 +
    in
 +
    complex
 +
 
 +
 
 +
    out
 +
    byte
 +
 
 
</pre>
 
</pre>
 +
}}
  
== Step 4 bis: Flesh out the YAML file ==
+
== 4.2.6 Step 5: Install my_qpsk_demod in grc ==
  
Since version 3.8, GNU Radio has replaced the XML files by YAML. They work the same but with a different syntax.
+
We have finished the implementation of our block, now it's important use its functionality under GRC. So we build our OOT and install the underlying blocks. To do so, we need to execute the following commands:
  
The .yml provides the user interface between the OOT module displayed in the GRC and the source code. Moreover, the YAML file defines an interface to pass the parameters specific for the module. Hence, to access the module inside GRC, it is important to modify the .yml files manually. The YAML file for our block is named as <code>tutorial_my_qpsk_demod_cb.block.yml</code> inside the <code>grc/</code> folder. Presently, the <code>gr_modtool</code>'s version looks like:
+
{{collapse(sequence:)
  
Default version:
 
 
<pre>
 
<pre>
id: tutorial_my_qpsk_demod_cb
+
xyz@comp:mydir/gr-tutorial$ mkdir build
label: my_qpsk_demod_cb
+
xyz@comp:mydir/gr-tutorial$ cd build
category: '[tutorial]'
+
xyz@comp:mydir/gr-tutorial/build$ cmake ..
 
+
-- Build type not specified: defaulting to release.
templates:
+
Checking for GNU Radio Module: RUNTIME
  imports: import tutorial
+
* INCLUDES=/usr/local/include
  make: tutorial.my_qpsk_demod_cb(${gray_code})
+
* LIBS=/usr/local/lib/libgnuradio-runtime.so;/usr/local/lib/libgnuradio-pmt.so
 
+
GNURADIO_RUNTIME_FOUND = TRUE
#  Make one 'parameters' list entry for every parameter you want settable from the GUI.
+
-- Configuring done
#    Keys include:
+
-- Generating done
#    * id (makes the value accessible as \$keyname, e.g. in the make entry)
+
-- Build files have been written to: pathtomyhomefolder/mydir/gr-qpsk_demod/build
#    * label (label shown in the GUI)
+
xyz@comp:mydir/gr-demod/build$make
#    * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
+
[  7%] Built target gnuradio-tutorial
parameters:
+
[ 23%] Built target test-tutorial
- id: ...
+
[ 23%] Built target tutorial_swig_swig_doc
  label: ...
+
[ 30%] Built target _tutorial_swig_swig_tag
  dtype: ...
+
[ 38%] Swig source
- id: ...
+
Scanning dependencies of target _tutorial_swig
  label: ...
+
[ 46%] Building CXX object swig/CMakeFiles/_tutorial_swig.dir/tutorial_swigPYTHON_wrap.cxx.o
  dtype: ...
+
Linking CXX shared module _tutorial_swig.so
 
+
[ 53%] Built target _tutorial_swig
#  Make one 'inputs' list entry per input and one 'outputs' list entry per output.
+
[ 61%] Generating tutorial_swig.pyc
#  Keys include:
+
[ 69%] Generating tutorial_swig.pyo
#      * label (an identifier for the GUI)
+
[ 84%] Built target pygen_swig_2598c
#      * domain (optional - stream or message. Default is stream)
+
[100%] Built target pygen_python_6ab2e
#      * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...)
+
[100%] Built target pygen_apps_9a6dd
#      * vlen (optional - data stream vector length. Default is 1)
 
#      * optional (optional - set to 1 for optional inputs. Default is 0)
 
inputs:
 
- label: ...
 
  domain: ...
 
  dtype: ...
 
  vlen: ...
 
  optional: ...
 
  
outputs:
+
xyz@comp:mydir/gr-qpsk_demod/build$ sudo make install
- label: ...
+
[  7%] Built target gnuradio-tutorial
  domain: ...
+
[ 23%] Built target test-tutorial
  dtype: ...
+
[ 23%] Built target tutorial_swig_swig_doc
  vlen: ...
+
[ 30%] Built target _tutorial_swig_swig_tag
  optional: ...
+
[ 53%] Built target _tutorial_swig
 +
[ 84%] Built target pygen_swig_2598c
 +
[100%] Built target pygen_python_6ab2e
 +
[100%] Built target pygen_apps_9a6dd
 +
Install the project...
 +
-- Install configuration: &quot;Release&quot;
 +
-- Up-to-date: /usr/local/lib/cmake/tutorial/demodConfig.cmake
 +
-- Up-to-date: /usr/local/include/tutorial/api.h
 +
-- Up-to-date: /usr/local/include/tutorial/my_qpsk_demod_cb.h
 +
-- Up-to-date: /usr/local/lib/libgnuradio-tutorial.so
 +
-- Installing: /usr/local/lib/python2.7/dist-packages/tutorial/_tutorial_swig.so
 +
-- Removed runtime path from &quot;/usr/local/lib/python2.7/dist-packages/tutorial/_tutorial_swig.so&quot;
 +
-- Installing: /usr/local/lib/python2.7/dist-packages/tutorial/tutorial_swig.py
 +
-- Installing: /usr/local/lib/python2.7/dist-packages/tutorial/tutorial_swig.pyc
 +
-- Installing: /usr/local/lib/python2.7/dist-packages/tutorial/tutorial_swig.pyo
 +
-- Up-to-date: /usr/local/include/tutorial/tutorial/swig/tutorial_swig.i
 +
-- Installing: /usr/local/include/tutorial/tutorial/swig/tutorial_swig_doc.i
 +
-- Up-to-date: /usr/local/lib/python2.7/dist-packages/tutorial/__init__.py
 +
-- Up-to-date: /usr/local/lib/python2.7/dist-packages/tutorial/__init__.pyc
 +
-- Up-to-date: /usr/local/lib/python2.7/dist-packages/tutorial/__init__.pyo
 +
-- Up-to-date: /usr/local/share/gnuradio/grc/blocks/tutorial_my_qpsk_cb.xml
  
#  'file_format' specifies the version of the GRC yml format used in the file
+
xyz@comp:mydir/gr-qpsk_demod/build$ sudo ldconfig
#  and should usually not be changed.
 
file_format: 1
 
 
</pre>
 
</pre>
 +
}}
  
 +
== 4.2.7 Step 6: Quality Assurance (Unit Testing) ==
  
The parameter <code>gray_code</code> can be put under the <code>parameters</code> tag.
+
[[File:https://raw.githubusercontent.com/gnuradio/gr-tutorial/master/examples/tutorial4/figs/Constellation_diagram.png|600px|Constellation_diagram.grc]]
 
 
Adding parameter tag:
 
  
<pre>
+
Figure above represents the constellation diagram (displayed in accordance to the Qt GUI Constellation Sink) of the QPSK modulated input fed to out OOT module. The task of our QPSK demodulator is to demodulate this complex valued input stream and to produce stream of quaternary alphabets (0,1,2,3) or simply bytes as output.
parameters:
 
- id: gray_code
 
  label: Gray Code
 
  dtype: bool
 
  default: 'True'
 
</pre>
 
  
 +
By following the steps of writing the OOT module, we did manage to produce the byte stream at the output of QPSK demodulator, still, it doesn't guarantee the correct working of our block. In this situation, it becomes significant to write unit test for our module that certifies the clean implementation of the QPSK demodulator.
  
Like the work function, the datatypes for the input and output ports represented by <code>input</code> and <code><nowiki>output</nowiki></code> tags should be modified.
+
Below we see the source of code of the <code>qa_qpsk_demod.py</code> can be found under <code>python/</code>
  
Modifying source and sink tag:
+
{{collapse(Full QA code)
 
 
<pre> 
 
inputs:
 
- label: in
 
  dtype: complex
 
</pre>
 
<pre> 
 
outputs:
 
- label: out
 
  dtype: byte
 
</pre>
 
 
 
 
 
After all the necessary modification the "tutorial_my_qpsk_demod_cb.block.yml" looks like this:
 
 
 
Modified version:
 
 
 
<pre>
 
id: tutorial_my_qpsk_demod_cb
 
label: My QPSK Demodulator
 
category: '[tutorial]'
 
 
 
templates:
 
  imports: import tutorial
 
  make: tutorial.my_qpsk_demod_cb(${gray_code})
 
 
 
parameters:
 
- id: gray_code
 
  label: Gray Code
 
  dtype: bool
 
  default: 'True'
 
 
 
inputs:
 
- label: in
 
  dtype: complex
 
outputs:
 
- label: out
 
  dtype: byte
 
 
 
file_format: 1
 
</pre>
 
 
 
== Step 5: Install my_qpsk_demod in grc ==
 
 
 
Now that we have finished the implementation of our block, we need to build and install it. To do so, execute the following commands:
 
 
 
<pre>
 
cd ~/gr-tutorial
 
mkdir build
 
cd build
 
cmake ../
 
make
 
sudo make install
 
sudo ldconfig
 
</pre>
 
 
 
== Step 6: Quality Assurance (Unit Testing) ==
 
 
 
In the previous steps of writing the OOT module, we produced the QPSK demodulator, but it doesn't guarantee the correct working of our block. In this situation, it becomes significant to write a unit test for our module that certifies the clean implementation of the QPSK demodulator.
 
 
 
Below is the source of code of the <code>qa_qpsk_demod.py</code> can be found under <code>python/</code>
 
 
 
Full QA code
 
  
 
<syntaxhighlight lang="python" line="line">
 
<syntaxhighlight lang="python" line="line">
Line 723: Line 468:
  
 
     def test_001_gray_code_enabled (self):
 
     def test_001_gray_code_enabled (self):
         # "Construct the Iphase and Qphase components"
+
         # &quot;Construct the Iphase and Qphase components&quot;
 
         Iphase = array([ 1, -1, -1,  1])
 
         Iphase = array([ 1, -1, -1,  1])
 
         Qphase = array([ 1,  1, -1, -1])
 
         Qphase = array([ 1,  1, -1, -1])
 
         src_data = Iphase + 1j*Qphase;
 
         src_data = Iphase + 1j*Qphase;
         # "Enable Gray code"
+
         # &quot;Enable Gray code&quot;
 
         gray_code =  True;
 
         gray_code =  True;
         # "Determine the expected result"
+
         # &quot;Determine the expected result&quot;
 
         expected_result = (0,1,3,2)
 
         expected_result = (0,1,3,2)
         # "Create a complex vector source"
+
         # &quot;Create a complex vector source&quot;
 
         src = blocks.vector_source_c(src_data)
 
         src = blocks.vector_source_c(src_data)
         # "Instantiate the test module"
+
         # &quot;Instantiate the test module&quot;
 
         qpsk_demod = tutorial.my_qpsk_demod_cb(gray_code)
 
         qpsk_demod = tutorial.my_qpsk_demod_cb(gray_code)
         # "Instantiate the binary sink"
+
         # &quot;Instantiate the binary sink&quot;
 
         dst = blocks.vector_sink_b();
 
         dst = blocks.vector_sink_b();
         # "Construct the flowgraph"
+
         # &quot;Construct the flowgraph&quot;
 
         self.tb.connect(src,qpsk_demod)
 
         self.tb.connect(src,qpsk_demod)
 
         self.tb.connect(qpsk_demod,dst)
 
         self.tb.connect(qpsk_demod,dst)
         # "Create the flow graph"
+
         # &quot;Create the flow graph&quot;
 
         self.tb.run ()
 
         self.tb.run ()
 
         # check data
 
         # check data
Line 748: Line 493:
  
 
     def test_002_gray_code_disabled (self):
 
     def test_002_gray_code_disabled (self):
         # "Construct the Iphase and Qphase components"
+
         # &quot;Construct the Iphase and Qphase components&quot;
 
         Iphase = array([ 1, -1, -1,  1])
 
         Iphase = array([ 1, -1, -1,  1])
 
         Qphase = array([ 1,  1, -1, -1])
 
         Qphase = array([ 1,  1, -1, -1])
 
         src_data = Iphase + 1j*Qphase;
 
         src_data = Iphase + 1j*Qphase;
         # "Enable Gray code"
+
         # &quot;Enable Gray code&quot;
 
         gray_code =  False;
 
         gray_code =  False;
         # "Determine the expected result"
+
         # &quot;Determine the expected result&quot;
 
         expected_result = (0,1,2,3)
 
         expected_result = (0,1,2,3)
         # "Create a complex vector source"
+
         # &quot;Create a complex vector source&quot;
 
         src = blocks.vector_source_c(src_data)
 
         src = blocks.vector_source_c(src_data)
         # "Instantiate the test module"
+
         # &quot;Instantiate the test module&quot;
 
         qpsk_demod = tutorial.my_qpsk_demod_cb(gray_code)
 
         qpsk_demod = tutorial.my_qpsk_demod_cb(gray_code)
         # "Instantiate the binary sink"
+
         # &quot;Instantiate the binary sink&quot;
 
         dst = blocks.vector_sink_b();
 
         dst = blocks.vector_sink_b();
         # "Construct the flowgraph"
+
         # &quot;Construct the flowgraph&quot;
 
         self.tb.connect(src,qpsk_demod)
 
         self.tb.connect(src,qpsk_demod)
 
         self.tb.connect(qpsk_demod,dst)
 
         self.tb.connect(qpsk_demod,dst)
         # "Create the flow graph"
+
         # &quot;Create the flow graph&quot;
 
         self.tb.run ()
 
         self.tb.run ()
 
         # check data
 
         # check data
Line 773: Line 518:
  
 
if __name__ == '__main__':
 
if __name__ == '__main__':
     gr_unittest.run(qa_qpsk_demod, "qa_qpsk_demod.xml")
+
     gr_unittest.run(qa_qpsk_demod, &quot;qa_qpsk_demod.xml&quot;)
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
}}
  
 
+
It can be easily noticed that the <code>qa_qpsk_demod</code> is implemented in python, in spite of we opted C++ in the first case for writing our blocks. This is because, GNU Radio inherits the [https://docs.python.org/2/library/unittest.html python unittest framework] to support quality assurance. And, if you remember it correctly from previous tutorials, swig as part of GNU Radio framework, provides python bindings for the C++ code. Hence, we are able to write the unit test for our block <code>qa_qpsk_demod</code> in python.
Obviously the <code>qa_qpsk_demod</code> is implemented in python, in spite of we opted C++ in the first case for writing our blocks. This is because GNU Radio inherits the [https://docs.python.org/2/library/unittest.html python unittest framework] to support quality assurance. And, if you remember it correctly from previous tutorials, swig as part of GNU Radio framework, provides python bindings for the C++ code. Hence, we are able to write the unit test for our block <code>qa_qpsk_demod</code> in Python.
 
  
 
So lets gather a bit of know how on how to write test cases for the block. Okay, lets consider the header part first:
 
So lets gather a bit of know how on how to write test cases for the block. Okay, lets consider the header part first:
Line 787: Line 532:
 
from numpy import array
 
from numpy import array
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
<code>from gnuradio import gr, gr_unittest</code> and <code>from gnuradio import blocks</code> are the standard lines that includes gr, gr_unittest functionality in the <code>qa_</code> file. <code>import tutorial_swig as tutorial</code> import the python bidden version of our module, which provides an access our block <code>my_qpsk_demod_cb</code>. Finally, <code>from numpy import array</code> includes array.
 
<code>from gnuradio import gr, gr_unittest</code> and <code>from gnuradio import blocks</code> are the standard lines that includes gr, gr_unittest functionality in the <code>qa_</code> file. <code>import tutorial_swig as tutorial</code> import the python bidden version of our module, which provides an access our block <code>my_qpsk_demod_cb</code>. Finally, <code>from numpy import array</code> includes array.
  
Line 794: Line 538:
 
     gr_unittest.run(qa_qpsk_demod, "qa_qpsk_demod.xml")
 
     gr_unittest.run(qa_qpsk_demod, "qa_qpsk_demod.xml")
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
The <code>qa_</code> file execution start by calling this function. The <code>gr_unittest</code> automatically calls the functions in a specific order <code>def setUp (self)</code> for creating the top block at the start, <code>tearDown (self)</code> for deleting the top block at the end. In between the <code>setUp</code> and <code>tearDown</code> the test cases defined are executed. The methods starting with prefix <code>test_</code> are recognized as test cases by <code>gr_unittest</code>. We have defined two test cases <code>test_001_gray_code_enabled</code> and <code>test_002_gray_code_disabled</code>. The usual structure of a test cases comprises of a known input data and the expected output. A flowgraph is created to include the source (input data), block to be tested (processor) and sink (resulted output data). In the end the expected output is compared with the resulted output data.
 
The <code>qa_</code> file execution start by calling this function. The <code>gr_unittest</code> automatically calls the functions in a specific order <code>def setUp (self)</code> for creating the top block at the start, <code>tearDown (self)</code> for deleting the top block at the end. In between the <code>setUp</code> and <code>tearDown</code> the test cases defined are executed. The methods starting with prefix <code>test_</code> are recognized as test cases by <code>gr_unittest</code>. We have defined two test cases <code>test_001_gray_code_enabled</code> and <code>test_002_gray_code_disabled</code>. The usual structure of a test cases comprises of a known input data and the expected output. A flowgraph is created to include the source (input data), block to be tested (processor) and sink (resulted output data). In the end the expected output is compared with the resulted output data.
  
Line 803: Line 546:
 
self.assertEqual(len(expected_result), len(result_data))
 
self.assertEqual(len(expected_result), len(result_data))
 
</syntaxhighlight>
 
</syntaxhighlight>
determine the result of test cases as passed or failed. The test cases are executed before installation of the module by running <code>make test</code> yielding the following output:
+
determine the result of test cases as passed or failed. The test cases are executed before installation of the module by running <code>make test</code>:<br />
 +
{{collapse(Output)
 +
 
 
<pre>
 
<pre>
barry@barry:~/gr-tutorial/build$ make test
+
xyz@comp:mydir/gr-tutorial/build$ make test
 
Running tests...
 
Running tests...
Test project /home/barry/gr-tutorial/build
+
Test project /home/kaushik/src/gr-tutorial/build
 
     Start 1: test_tutorial
 
     Start 1: test_tutorial
1/2 Test #1: test_tutorial ....................  Passed    0.02 sec
+
1/3 Test #1: test_tutorial ....................  Passed    0.11 sec
     Start 2: qa_my_qpsk_demod_cb
+
     Start 2: qa_chat_sanitizer
2/2 Test #2: qa_my_qpsk_demod_cb ..............  Passed    1.01 sec
+
2/3 Test #2: qa_chat_sanitizer ................***Failed    0.04 sec
 +
    Start 3: qa_qpsk_demod
 +
3/3 Test #3: qa_qpsk_demod ....................  Passed    2.00 sec
 +
 
 +
67% tests passed, 1 tests failed out of 3
  
100% tests passed, 0 tests failed out of 2
+
Total Test time (real) =  2.34 sec
  
Total Test time (real) =  1.04 sec
+
The following tests FAILED:
</pre>
+
      2 - qa_chat_sanitizer (Failed)
 +
Errors while running CTest
 +
make: *** [test] Fehler 8</pre>
 +
}}
  
 +
In the output above, one of the test failed, however, Test 3 belonging to the <code>qa_qpsk_demod</code>, claims to have passed the test cases.<br />
 
Congratulations, we have just finished writing our OOT module <code>gr-tutorial</code> and a C++ block <code>my_qpsk_demodulator</code>.
 
Congratulations, we have just finished writing our OOT module <code>gr-tutorial</code> and a C++ block <code>my_qpsk_demodulator</code>.
  
= Advanced topics =
+
= 4.3 Advanced topics =
  
 
The topics discussed until now have laid the foundation for designing the OOT module independently. However, the GNU Radio jargon extends further beyond these. Therefore, under this section, we drift from the QPSK demodulator and focus on the features that are rarely used or are more specific to the implementation.
 
The topics discussed until now have laid the foundation for designing the OOT module independently. However, the GNU Radio jargon extends further beyond these. Therefore, under this section, we drift from the QPSK demodulator and focus on the features that are rarely used or are more specific to the implementation.
Line 826: Line 579:
 
To add physical meaning to the discussion, we have taken assistance of the existing modules. The source code excerpts are included thereof. Enthusiastic readers are suggested to open the source code in parallel and play around with their functionalities.
 
To add physical meaning to the discussion, we have taken assistance of the existing modules. The source code excerpts are included thereof. Enthusiastic readers are suggested to open the source code in parallel and play around with their functionalities.
  
== Specific functions related to block ==
+
== 4.3.1 Specific functions related to block ==
  
 
In the last section, we managed out implementation of our block by defining functions like <code>general_work</code> and <code>forecast()</code>. But sometimes special functions need to be defined for the implementation. The list is long, but we try to discuss same of these functions in the following subsections.
 
In the last section, we managed out implementation of our block by defining functions like <code>general_work</code> and <code>forecast()</code>. But sometimes special functions need to be defined for the implementation. The list is long, but we try to discuss same of these functions in the following subsections.
  
=== set_history() ===
+
=== 4.3.1.1 set_history() ===
  
 
If your block needs a history (i.e., something like an FIR filter), call this in the constructor.<br />
 
If your block needs a history (i.e., something like an FIR filter), call this in the constructor.<br />
Here is an example
+
Here is an<br />
 +
{{collapse(example)
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
test::test(const std::string &name,
+
test::test(const std::string &amp;name,
 
             int min_inputs, int max_inputs,
 
             int min_inputs, int max_inputs,
 
             unsigned int sizeof_input_item,
 
             unsigned int sizeof_input_item,
Line 865: Line 619:
 
   }
 
   }
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
}}
  
 
GNU Radio then makes sure you have the given number of 'old' items available.
 
GNU Radio then makes sure you have the given number of 'old' items available.
Line 882: Line 636:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
=== 4.3.1.2 set_output_multiple() ===
=== set_output_multiple() ===
 
  
 
When implementing your <code>general_work()</code> routine, it's occasionally convenient to have the run time system ensure that you are only asked to produce a number of output items that is a multiple of some particular value. This might occur if your algorithm naturally applies to a fixed sized block of data. Call <code>set_output_multiple</code> in your constructor to specify this requirement,
 
When implementing your <code>general_work()</code> routine, it's occasionally convenient to have the run time system ensure that you are only asked to produce a number of output items that is a multiple of some particular value. This might occur if your algorithm naturally applies to a fixed sized block of data. Call <code>set_output_multiple</code> in your constructor to specify this requirement,
Line 890: Line 643:
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
test::test(const std::string &name,
+
test::test(const std::string &amp;name,
 
             int min_inputs, int max_inputs,
 
             int min_inputs, int max_inputs,
 
             unsigned int sizeof_input_item,
 
             unsigned int sizeof_input_item,
Line 929: Line 682:
 
<syntaxhighlight lang="cpp">void gr_block::set_output_multiple (int multiple)
 
<syntaxhighlight lang="cpp">void gr_block::set_output_multiple (int multiple)
 
{
 
{
   if (multiple < 1)
+
   if (multiple &lt; 1)
     throw std::invalid_argument ("gr_block::set_output_multiple");
+
     throw std::invalid_argument (&quot;gr_block::set_output_multiple&quot;);
  
 
   d_output_multiple_set = true;
 
   d_output_multiple_set = true;
 
   d_output_multiple = multiple;
 
   d_output_multiple = multiple;
 
}</syntaxhighlight>
 
}</syntaxhighlight>
 
+
== 4.3.2 Specific block categories ==
== Specific block categories ==
 
  
 
Again the implementation of the <code>my_qpsk_demod_cb</code> was done using a general block. However, GNU Radio includes some blocks with special functionality. A brief overview of these blocks is described in the table.
 
Again the implementation of the <code>my_qpsk_demod_cb</code> was done using a general block. However, GNU Radio includes some blocks with special functionality. A brief overview of these blocks is described in the table.
Line 962: Line 714:
 
In the next subsections we discuss these blocks in detail. Again, enthusiastic readers can find these blocks in the GNU Radio source code.
 
In the next subsections we discuss these blocks in detail. Again, enthusiastic readers can find these blocks in the GNU Radio source code.
  
=== General ===
+
=== 4.3.2.1 General ===
  
 
<syntaxhighlight lang="cpp">howto_square_ff::howto_square_ff ()
 
<syntaxhighlight lang="cpp">howto_square_ff::howto_square_ff ()
: gr::block("square_ff",
+
: gr::block(&quot;square_ff&quot;,
 
gr::io_signature::make(MIN_IN, MAX_IN, sizeof (float)),
 
gr::io_signature::make(MIN_IN, MAX_IN, sizeof (float)),
 
gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (float)))
 
gr::io_signature::make(MIN_OUT, MAX_OUT, sizeof (float)))
Line 972: Line 724:
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
=== 4.3.2.2 Source and Sinks ===
=== Source and Sinks ===
 
  
 
==== Source ====
 
==== Source ====
Line 980: Line 731:
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &device_addr,
+
usrp_source_impl::usrp_source_impl(const ::uhd::device_addr_t &amp;device_addr,
                                   const ::uhd::stream_args_t &stream_args):
+
                                   const ::uhd::stream_args_t &amp;stream_args):
       sync_block("gr uhd usrp source",
+
       sync_block(&quot;gr uhd usrp source&quot;,
 
                     io_signature::make(0, 0, 0),
 
                     io_signature::make(0, 0, 0),
 
                     args_to_io_sig(stream_args)),
 
                     args_to_io_sig(stream_args)),
Line 995: Line 746:
  
 
* <code>io_signature::make(0, 0, 0)</code> sets the input items to 0, in indicates there are no input streams.
 
* <code>io_signature::make(0, 0, 0)</code> sets the input items to 0, in indicates there are no input streams.
* Because it connected with the hardware USRP, the <code>gr uhd usrp source</code> is a sub class of <code>sync_block</code>.
+
* Because it connected with the hardware USRP, the <code>gr uhd usrp sink</code> is a sub class of <code>sync_block</code>.
  
 
==== Sink ====
 
==== Sink ====
Line 1,002: Line 753:
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
usrp_sink_impl::usrp_sink_impl(const ::uhd::device_addr_t &device_addr,
+
usrp_sink_impl::usrp_sink_impl(const ::uhd::device_addr_t &amp;device_addr,
                                   const ::uhd::stream_args_t &stream_args)
+
                                   const ::uhd::stream_args_t &amp;stream_args)
       : sync_block("gr uhd usrp sink",
+
       : sync_block(&quot;gr uhd usrp sink&quot;,
 
                       args_to_io_sig(stream_args),
 
                       args_to_io_sig(stream_args),
 
                       io_signature::make(0, 0, 0)),
 
                       io_signature::make(0, 0, 0)),
Line 1,018: Line 769:
 
* Because it connected with the hardware USRP, the <code>gr uhd usrp sink</code> is a sub class of <code>sync_block</code>.
 
* Because it connected with the hardware USRP, the <code>gr uhd usrp sink</code> is a sub class of <code>sync_block</code>.
  
=== Sync ===
+
=== 4.3.2.3 Sync ===
  
 
The sync block allows users to write blocks that consume and produce an equal number of items per port. A sync block may have any number of inputs or outputs. When a sync block has zero inputs, its called a source. When a sync block has zero outputs, its called a sink.
 
The sync block allows users to write blocks that consume and produce an equal number of items per port. A sync block may have any number of inputs or outputs. When a sync block has zero inputs, its called a source. When a sync block has zero outputs, its called a sink.
Line 1,025: Line 776:
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
#include <gnuradio/sync_block.h>
+
#include  
  
 
class my_sync_block : public gr_sync_block
 
class my_sync_block : public gr_sync_block
Line 1,031: Line 782:
 
public:
 
public:
 
   my_sync_block(...):
 
   my_sync_block(...):
     gr_sync_block("my block",
+
     gr_sync_block(&quot;my block&quot;,
 
                   gr::io_signature::make(1, 1, sizeof(int32_t)),
 
                   gr::io_signature::make(1, 1, sizeof(int32_t)),
 
                   gr::io_signature::make(1, 1, sizeof(int32_t)))
 
                   gr::io_signature::make(1, 1, sizeof(int32_t)))
Line 1,039: Line 790:
  
 
   int work(int noutput_items,
 
   int work(int noutput_items,
           gr_vector_const_void_star &input_items,
+
           gr_vector_const_void_star &amp;input_items,
           gr_vector_void_star &output_items)
+
           gr_vector_void_star &amp;output_items)
 
   {
 
   {
 
     //work stuff...
 
     //work stuff...
Line 1,053: Line 804:
 
* an output signature of gr::io_signature::make(0, 0, 0) makes this a sink block
 
* an output signature of gr::io_signature::make(0, 0, 0) makes this a sink block
  
=== Rate changing blocks: Interpolation and Decimation ===
+
=== 4.3.2.4 Rate changing blocks: Interpolators and Decimators ===
  
==== Decimation ====
+
==== Decimators ====
  
 
The decimation block is another type of fixed rate block where the number of input items is a fixed multiple of the number of output items.
 
The decimation block is another type of fixed rate block where the number of input items is a fixed multiple of the number of output items.
Line 1,062: Line 813:
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
#include <gr_sync_decimator.h>
+
#include  
  
 
class my_decim_block : public gr_sync_decimator
 
class my_decim_block : public gr_sync_decimator
Line 1,068: Line 819:
 
public:
 
public:
 
   my_decim_block(...):
 
   my_decim_block(...):
     gr_sync_decimator("my decim block",  
+
     gr_sync_decimator(&quot;my decim block&quot;,  
 
                       in_sig,
 
                       in_sig,
 
                       out_sig,
 
                       out_sig,
Line 1,091: Line 842:
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
#include <gnuradio/sync_interpolator.h>
+
#include  
  
 
class my_interp_block : public gr_sync_interpolator
 
class my_interp_block : public gr_sync_interpolator
Line 1,097: Line 848:
 
public:
 
public:
 
   my_interp_block(...):
 
   my_interp_block(...):
     gr_sync_interpolator("my interp block",
+
     gr_sync_interpolator(&quot;my interp block&quot;,
 
                         in_sig,
 
                         in_sig,
 
                         out_sig,
 
                         out_sig,
Line 1,114: Line 865:
 
* The user must assume that the number of input items = noutput_items/interpolation
 
* The user must assume that the number of input items = noutput_items/interpolation
  
=== Hierarchical blocks ===
+
=== 4.3.2.5 Hierarchical blocks ===
  
Hierarchical blocks are blocks that are made up of other blocks. They instantiate the other GNU Radio blocks (or other hierarchical blocks) and connect them together. A hierarchical block has a "connect" function for this purpose.
+
Hierarchical blocks are blocks that are made up of other blocks. They instantiate the other GNU Radio blocks (or other hierarchical blocks) and connect them together. A hierarchical block has a &quot;connect&quot; function for this purpose.
  
 
When to use hierarchical blocks?
 
When to use hierarchical blocks?
Line 1,122: Line 873:
 
Hierarchical blocks provides us modularity in our flowgraphs by abstracting simple blocks, that is hierarchical block helps us define our specific blocks at the same time provide us the flexibility to change it, example, we would like to test effect of different modulation schemes for a given channel model. However our synchronization algorithms are specific or newly published. We define our hier block as gr-my_sync that does synchronization followed equalizer and demodulation. We start with BPSK, the flowgraph looks like
 
Hierarchical blocks provides us modularity in our flowgraphs by abstracting simple blocks, that is hierarchical block helps us define our specific blocks at the same time provide us the flexibility to change it, example, we would like to test effect of different modulation schemes for a given channel model. However our synchronization algorithms are specific or newly published. We define our hier block as gr-my_sync that does synchronization followed equalizer and demodulation. We start with BPSK, the flowgraph looks like
  
gr-tx ---> gr-channel --> gr-my_sync --> gr-equalizer --> gr-bpsk_demod
+
gr-tx ---<s>&gt; gr-channel --</s>&gt; gr-my_sync --<s>&gt; gr-equalizer --</s>&gt; gr-bpsk_demod
  
 
Now, our flowgraph looks decent. Secondly, we abstracted the complex functionality of our synchronization. Shifting to QPSK, where the synchronization algorithm remains the same, we just replace the gr-bpsk_demod with gr-qpsk_demod
 
Now, our flowgraph looks decent. Secondly, we abstracted the complex functionality of our synchronization. Shifting to QPSK, where the synchronization algorithm remains the same, we just replace the gr-bpsk_demod with gr-qpsk_demod
  
gr-tx ---> gr-channel --> gr-my_sync --> gr-equalizer --> gr-qpsk_demod
+
gr-tx ---<s>&gt; gr-channel --</s>&gt; gr-my_sync --<s>&gt; gr-equalizer --</s>&gt; gr-qpsk_demod
  
 
How to build hierarchical blocks in GNU Radio?
 
How to build hierarchical blocks in GNU Radio?
  
Hierarchical blocks define an input and output stream much like normal blocks. For '''I''' input streams, let '''i''' be a value between 0 and '''I'''-1. To connect input '''i''' to a hierarchical block, the source is (in Python):
+
Hierarchical blocks define an input and output stream much like normal blocks. To connect input '''i''' to a hierarchical block, the source is (in Python):
  
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
self.connect((self, <i>), <block>)
+
self.connect((self, i), <block>)
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 1,139: Line 890:
  
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
self.connect(<block>, (self, <o>))
+
self.connect(<block>, (self, o))
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Line 1,153: Line 904:
  
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
gr.hier_block2.__init__(self, "ofdm_receiver",
+
gr.hier_block2.__init__(self, &quot;ofdm_receiver&quot;,
 
                         gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
 
                         gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
 
                         gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature
 
                         gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature
Line 1,164: Line 915:
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
 
chan_coeffs = filter.firdes.low_pass (1.0,                    # gain
 
chan_coeffs = filter.firdes.low_pass (1.0,                    # gain
                                      1.0,                    # sampling rate
+
                                              1.0,                    # sampling rate
                                      bw+tb,                  # midpoint of trans. band
+
                                              bw+tb,                  # midpoint of trans. band
                                      tb,                      # width of trans. band
+
                                              tb,                      # width of trans. band
                                      filter.firdes.WIN_HAMMING)  # filter type
+
                                              filter.firdes.WIN_HAMMING)  # filter type
 
self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs)
 
self.chan_filt = filter.fft_filter_ccc(1, chan_coeffs)
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 1,196: Line 947:
  
 
<syntaxhighlight lang="python">
 
<syntaxhighlight lang="python">
self.connect(self, self.chan_filt) # filter the input channel
+
self.connect(self, self.chan_filt)                           # filter the input channel
 
</syntaxhighlight>
 
</syntaxhighlight>
 
Connection between the channel filter block to the OFDM synchronization block.
 
Connection between the channel filter block to the OFDM synchronization block.
Line 1,209: Line 960:
 
Underneath is instant of the hierarchical block. Don't panic by looking at its size, we just need to grab the concept behind creating hierarchical blocks.
 
Underneath is instant of the hierarchical block. Don't panic by looking at its size, we just need to grab the concept behind creating hierarchical blocks.
  
OFDM impl
+
{{collapse(OFDM impl)
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl(int fft_len, int cp_len, bool use_even_carriers)
 
ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl(int fft_len, int cp_len, bool use_even_carriers)
         : hier_block2 ("ofdm_sync_sc_cfb",
+
         : hier_block2 (&quot;ofdm_sync_sc_cfb&quot;,
 
                       io_signature::make(1, 1, sizeof (gr_complex)),
 
                       io_signature::make(1, 1, sizeof (gr_complex)),
 
#ifndef SYNC_ADD_DEBUG_OUTPUT
 
#ifndef SYNC_ADD_DEBUG_OUTPUT
Line 1,276: Line 1,027:
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
 
ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl(int fft_len, int cp_len, bool use_even_carriers)
 
ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl(int fft_len, int cp_len, bool use_even_carriers)
         : hier_block2 ("ofdm_sync_sc_cfb",
+
         : hier_block2 (&quot;ofdm_sync_sc_cfb&quot;,
 
                       io_signature::make(1, 1, sizeof (gr_complex)),
 
                       io_signature::make(1, 1, sizeof (gr_complex)),
 
#ifndef SYNC_ADD_DEBUG_OUTPUT
 
#ifndef SYNC_ADD_DEBUG_OUTPUT
Line 1,283: Line 1,034:
 
                   io_signature::make3(3, 3, sizeof (float), sizeof (unsigned char), sizeof (float)))
 
                   io_signature::make3(3, 3, sizeof (float), sizeof (unsigned char), sizeof (float)))
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
}}
  
 
+
where <code>ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl</code> is the constructor with parameters <code>int fft_len, int cp_len, bool use_even_carriers</code> and <code>hier_block2</code> is the base class. The block name <code>&quot;ofdm_sync_sc_cfb&quot;</code> is defined following the GNU Radio block naming style.
where <code>ofdm_sync_sc_cfb_impl::ofdm_sync_sc_cfb_impl</code> is the constructor with parameters <code>int fft_len, int cp_len, bool use_even_carriers</code> and <code>hier_block2</code> is the base class. The block name <code>"ofdm_sync_sc_cfb"</code> is defined following the GNU Radio block naming style.
 
  
 
<code>io_signature::make(1, 1, sizeof (gr_complex))</code> defines my input items and the output items are either<br />
 
<code>io_signature::make(1, 1, sizeof (gr_complex))</code> defines my input items and the output items are either<br />
Line 1,302: Line 1,053:
 
connect(normalizer_magsquare, 0, normalizer_ma, 0);
 
connect(normalizer_magsquare, 0, normalizer_ma, 0);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 +
= 4.4 Closing note =
 +
 +
At this point, we are qualified enough to write our own OOT module and include blocks within (either in Python or C++ depending on what we choose). To strengthen the things we learned in this tutorial, its time to go through a small quiz in the following section. The next [http://gnuradio.org/redmine/projects/gnuradio/wiki/Guided_Tutorial_Programming_Topics tutorial], illustrates different ways, synchronous and asynchronous, of communication among the blocks.
 +
 +
= 4.5 Quiz =
 +
 +
* What will change if we decide to shift our modulation scheme form QPSK to 8 PSK/4-QAM/16-QAM?
 +
* If we think of porting the QPSK demodulator to a generic demodulator, does the usage of hierarchical block makes sense?
 +
* How does noise affect our system?
 +
 +
-----
 +
 +
&lt; [[Guided_Tutorial_GNU_Radio_in_Python|Previous: Programming GNU Radio in Python]]
 +
&gt; [[Guided_Tutorial_Programming_Topics|Next: Programming Topics]]
 +
 +
[1] http://radioware.nd.edu/documentation/advanced-gnuradio/writing-a-signal-processing-block-for-gnu-radio-part-i
 +
 +
[[Category:Guided Tutorials]]

Please note that all contributions to GNU Radio are considered to be released under the Creative Commons Attribution-ShareAlike (see GNU Radio:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To edit this page, please answer the question that appears below (more info):

Cancel | Editing help (opens in new window)