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 106: Line 106:
 
The detailed description of coding structure for the block can be found [[BlocksCodingGuide|here]].
 
The detailed description of coding structure for the block can be found [[BlocksCodingGuide|here]].
  
== Step 3: Fleshing out the code ==
+
== 4.2.4 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 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 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 124: Line 120:
 
     {}
 
     {}
 
</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].
  
Line 156: Line 151:
 
</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>, the skeleton version of this function will look something like this:
+
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 />
 +
the skeleton version of this function will look something like this:
  
 
<syntaxhighlight lang="cpp" line="line">
 
<syntaxhighlight lang="cpp" line="line">
Line 177: Line 173:
 
}
 
}
 
</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 205: Line 200:
 
     }
 
     }
 
</syntaxhighlight>
 
</syntaxhighlight>
 
 
This work function calls another function <code>get_minimum_distances(const gr_complex &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:
  
Line 242: Line 236:
 
</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 261: Line 254:
 
   }
 
   }
 
</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:
 
 
<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 */
 
} /* namespace gr */
 
</syntaxhighlight>
 
  
 
== Step 4: Flesh out the XML file ==
 
== Step 4: Flesh out the XML file ==

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)