commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 02/04: digital: adding use of tanh and snr


From: git
Subject: [Commit-gnuradio] [gnuradio] 02/04: digital: adding use of tanh and snr info to costas loop.
Date: Tue, 21 Oct 2014 21:04:45 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

trondeau pushed a commit to branch master
in repository gnuradio.

commit fdf13bdc0640f4ffa892c9bebedf74274bc6ea82
Author: Tom Rondeau <address@hidden>
Date:   Tue Oct 21 16:07:53 2014 -0400

    digital: adding use of tanh and snr info to costas loop.
---
 gr-digital/grc/digital_costas_loop_cc.xml          | 84 ++++++++++++++--------
 .../include/gnuradio/digital/costas_loop_cc.h      |  9 ++-
 gr-digital/lib/costas_loop_cc_impl.cc              | 68 ++++++++++++++++--
 gr-digital/lib/costas_loop_cc_impl.h               | 45 ++++++++++--
 gr-digital/python/digital/qa_costas_loop_cc.py     | 22 +++---
 5 files changed, 174 insertions(+), 54 deletions(-)

diff --git a/gr-digital/grc/digital_costas_loop_cc.xml 
b/gr-digital/grc/digital_costas_loop_cc.xml
index 668c43d..40db3a4 100644
--- a/gr-digital/grc/digital_costas_loop_cc.xml
+++ b/gr-digital/grc/digital_costas_loop_cc.xml
@@ -5,34 +5,60 @@
 ###################################################
  -->
 <block>
-       <name>Costas Loop</name>
-       <key>digital_costas_loop_cc</key>
-       <import>from gnuradio import digital</import>
-       <make>digital.costas_loop_cc($w, $order)</make>
-       <callback>set_loop_bandwidth($w)</callback>
-       <param>
-               <name>Loop Bandwidth</name>
-               <key>w</key>
-               <type>real</type>
-       </param>
-       <param>
-               <name>Order</name>
-               <key>order</key>
-               <type>int</type>
-       </param>
-       <sink>
-               <name>in</name>
-               <type>complex</type>
-       </sink>
-       <source>
-               <name>out</name>
-               <type>complex</type>
-       </source>
+  <name>Costas Loop</name>
+  <key>digital_costas_loop_cc</key>
+  <import>from gnuradio import digital</import>
+  <make>digital.costas_loop_cc($w, $order, $use_snr)</make>
+  <callback>set_loop_bandwidth($w)</callback>
 
-       <!-- Optional Outputs -->
-       <source>
-               <name>frequency</name>
-               <type>float</type>
-               <optional>1</optional>
-       </source>
+  <param>
+    <name>Loop Bandwidth</name>
+    <key>w</key>
+    <type>real</type>
+  </param>
+
+  <param>
+    <name>Order</name>
+    <key>order</key>
+    <type>int</type>
+  </param>
+
+  <param>
+    <name>Use SNR</name>
+    <key>use_snr</key>
+    <value>False</value>
+    <type>enum</type>
+    <hide>part</hide>
+    <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>
+
+  <sink>
+    <name>noise</name>
+    <type>message</type>
+    <optional>1</optional>
+  </sink>
+
+  <source>
+    <name>out</name>
+    <type>complex</type>
+  </source>
+
+  <!-- Optional Outputs -->
+  <source>
+    <name>frequency</name>
+    <type>float</type>
+    <optional>1</optional>
+  </source>
 </block>
diff --git a/gr-digital/include/gnuradio/digital/costas_loop_cc.h 
b/gr-digital/include/gnuradio/digital/costas_loop_cc.h
index d924d96..ff5b9b9 100644
--- a/gr-digital/include/gnuradio/digital/costas_loop_cc.h
+++ b/gr-digital/include/gnuradio/digital/costas_loop_cc.h
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2006,2011,2012 Free Software Foundation, Inc.
+ * Copyright 2006,2011,2012,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -58,6 +58,9 @@ namespace gr {
      * The Costas loop can have two output streams:
      * \li stream 1 (required) is the baseband I and Q;
      * \li stream 2 (optional) is the normalized frequency of the loop
+     *
+     * There is a single optional message input:
+     * \li noise: A noise floor estimate used to calculate the SNR of a sample.
      */
     class DIGITAL_API costas_loop_cc
       : virtual public sync_block,
@@ -72,8 +75,10 @@ namespace gr {
        *
        * \param loop_bw  internal 2nd order loop bandwidth (~ 2pi/100)
        * \param order the loop order, either 2, 4, or 8
+       * \param use_snr Use or ignore SNR estimates (from noise message port)
+       *        in measurements; also uses tanh instead of slicing.
        */
-      static sptr make(float loop_bw, int order);
+      static sptr make(float loop_bw, int order, bool use_snr=false);
 
       /*!
        * Returns the current value of the loop error.
diff --git a/gr-digital/lib/costas_loop_cc_impl.cc 
b/gr-digital/lib/costas_loop_cc_impl.cc
index 36f95ac..a53045a 100644
--- a/gr-digital/lib/costas_loop_cc_impl.cc
+++ b/gr-digital/lib/costas_loop_cc_impl.cc
@@ -35,37 +35,52 @@ namespace gr {
   namespace digital {
 
     costas_loop_cc::sptr
-    costas_loop_cc::make(float loop_bw, int order)
+    costas_loop_cc::make(float loop_bw, int order, bool use_snr)
     {
       return gnuradio::get_initial_sptr
-       (new costas_loop_cc_impl(loop_bw, order));
+       (new costas_loop_cc_impl(loop_bw, order, use_snr));
     }
 
-    costas_loop_cc_impl::costas_loop_cc_impl(float loop_bw, int order)
+    costas_loop_cc_impl::costas_loop_cc_impl(float loop_bw, int order, bool 
use_snr)
       : sync_block("costas_loop_cc",
                    io_signature::make(1, 1, sizeof(gr_complex)),
                    io_signature::make2(1, 2, sizeof(gr_complex), 
sizeof(float))),
        blocks::control_loop(loop_bw, 1.0, -1.0),
-       d_order(order), d_error(0), d_phase_detector(NULL)
+       d_order(order), d_error(0), d_noise(1.0), d_phase_detector(NULL)
     {
       // Set up the phase detector to use based on the constellation order
       switch(d_order) {
       case 2:
-       d_phase_detector = &costas_loop_cc_impl::phase_detector_2;
+        if(use_snr)
+          d_phase_detector = &costas_loop_cc_impl::phase_detector_snr_2;
+       else
+          d_phase_detector = &costas_loop_cc_impl::phase_detector_2;
        break;
 
       case 4:
-       d_phase_detector = &costas_loop_cc_impl::phase_detector_4;
+        if(use_snr)
+          d_phase_detector = &costas_loop_cc_impl::phase_detector_snr_4;
+       else
+          d_phase_detector = &costas_loop_cc_impl::phase_detector_4;
        break;
 
       case 8:
-       d_phase_detector = &costas_loop_cc_impl::phase_detector_8;
+        if(use_snr)
+          d_phase_detector = &costas_loop_cc_impl::phase_detector_snr_8;
+       else
+          d_phase_detector = &costas_loop_cc_impl::phase_detector_8;
        break;
 
       default:
        throw std::invalid_argument("order must be 2, 4, or 8");
        break;
       }
+
+      message_port_register_in(pmt::mp("noise"));
+      set_msg_handler(
+        pmt::mp("noise"),
+        boost::bind(&costas_loop_cc_impl::handle_set_noise,
+                    this, _1));
     }
 
     costas_loop_cc_impl::~costas_loop_cc_impl()
@@ -114,11 +129,50 @@ namespace gr {
     }
 
     float
+    costas_loop_cc_impl::phase_detector_snr_8(gr_complex sample) const
+    {
+      float K = (sqrt(2.0) - 1);
+      float snr = abs(sample)*abs(sample) / d_noise;
+      if(fabsf(sample.real()) >= fabsf(sample.imag())) {
+       return ((blocks::tanhf_lut(snr*sample.real()) * sample.imag()) -
+          (blocks::tanhf_lut(snr*sample.imag()) * sample.real() * K));
+      }
+      else {
+       return ((blocks::tanhf_lut(snr*sample.real()) * sample.imag() * K) -
+          (blocks::tanhf_lut(snr*sample.imag()) * sample.real()));
+      }
+    }
+
+    float
+    costas_loop_cc_impl::phase_detector_snr_4(gr_complex sample) const
+    {
+      float snr = abs(sample)*abs(sample) / d_noise;
+      return ((blocks::tanhf_lut(snr*sample.real()) * sample.imag()) -
+              (blocks::tanhf_lut(snr*sample.imag()) * sample.real()));
+    }
+
+    float
+    costas_loop_cc_impl::phase_detector_snr_2(gr_complex sample) const
+    {
+      float snr = abs(sample)*abs(sample) / d_noise;
+      return blocks::tanhf_lut(snr*sample.real()) * sample.imag();
+    }
+
+    float
     costas_loop_cc_impl::error() const
     {
       return d_error;
     }
 
+    void
+    costas_loop_cc_impl::handle_set_noise(pmt::pmt_t msg)
+    {
+      if(pmt::is_real(msg)) {
+        d_noise = pmt::to_double(msg);
+        d_noise = powf(10.0f, d_noise/10.0f);
+      }
+    }
+
     int
     costas_loop_cc_impl::work(int noutput_items,
                              gr_vector_const_void_star &input_items,
diff --git a/gr-digital/lib/costas_loop_cc_impl.h 
b/gr-digital/lib/costas_loop_cc_impl.h
index 6657242..ebd05e2 100644
--- a/gr-digital/lib/costas_loop_cc_impl.h
+++ b/gr-digital/lib/costas_loop_cc_impl.h
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2006,2011,2012 Free Software Foundation, Inc.
+ * Copyright 2006,2011,2012,2014 Free Software Foundation, Inc.
  *
  * This file is part of GNU Radio
  *
@@ -34,33 +34,68 @@ namespace gr {
     private:
       int d_order;
       float d_error;
+      float d_noise;
 
-      /*! \brief the phase detector circuit for 8th-order PSK loops
+       /*! \brief the phase detector circuit for 8th-order PSK loops.
+       *
        *  \param sample complex sample
        *  \return the phase error
        */
       float phase_detector_8(gr_complex sample) const;    // for 8PSK
 
-      /*! \brief the phase detector circuit for fourth-order loops
+      /*! \brief the phase detector circuit for fourth-order loops.
+       *
        *  \param sample complex sample
        *  \return the phase error
        */
       float phase_detector_4(gr_complex sample) const;    // for QPSK
 
-      /*! \brief the phase detector circuit for second-order loops
+      /*! \brief the phase detector circuit for second-order loops.
+       *
        *  \param sample a complex sample
        *  \return the phase error
        */
       float phase_detector_2(gr_complex sample) const;    // for BPSK
 
+
+      /*! \brief the phase detector circuit for 8th-order PSK
+       *  loops. Uses tanh instead of slicing and the noise estimate
+       *  from the message port to estimated SNR of the samples.
+       *
+       *  \param sample complex sample
+       *  \return the phase error
+       */
+      float phase_detector_snr_8(gr_complex sample) const;    // for 8PSK
+
+      /*! \brief the phase detector circuit for fourth-order
+       *  loops. Uses tanh instead of slicing and the noise estimate
+       *  from the message port to estimated SNR of the samples.
+       *
+       *  \param sample complex sample
+       *  \return the phase error
+       */
+      float phase_detector_snr_4(gr_complex sample) const;    // for QPSK
+
+      /*! \brief the phase detector circuit for second-order
+       *  loops. Uses tanh instead of slicing and the noise estimate
+       *  from the message port to estimated SNR of the samples.
+       *
+       *  \param sample a complex sample
+       *  \return the phase error
+       */
+      float phase_detector_snr_2(gr_complex sample) const;    // for BPSK
+
+
       float (costas_loop_cc_impl::*d_phase_detector)(gr_complex sample) const;
 
     public:
-      costas_loop_cc_impl(float loop_bw, int order);
+      costas_loop_cc_impl(float loop_bw, int order, bool use_snr=false);
       ~costas_loop_cc_impl();
 
       float error() const;
 
+      void handle_set_noise(pmt::pmt_t msg);
+
       void setup_rpc();
 
       int work(int noutput_items,
diff --git a/gr-digital/python/digital/qa_costas_loop_cc.py 
b/gr-digital/python/digital/qa_costas_loop_cc.py
index 9ecb017..e48f45c 100755
--- a/gr-digital/python/digital/qa_costas_loop_cc.py
+++ b/gr-digital/python/digital/qa_costas_loop_cc.py
@@ -1,24 +1,24 @@
 #!/usr/bin/env python
 #
 # Copyright 2011,2013 Free Software Foundation, Inc.
-# 
+#
 # This file is part of GNU Radio
-# 
+#
 # GNU Radio 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.
-# 
+#
 # GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
 # the Free Software Foundation, Inc., 51 Franklin Street,
 # Boston, MA 02110-1301, USA.
-# 
+#
 
 import random
 import cmath
@@ -46,7 +46,7 @@ class test_costas_loop_cc(gr_unittest.TestCase):
 
         self.tb.connect(self.src, self.test, self.snk)
         self.tb.run()
-        
+
         expected_result = data
         dst_data = self.snk.data()
         self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 5)
@@ -77,7 +77,7 @@ class test_costas_loop_cc(gr_unittest.TestCase):
 
         rot = cmath.exp(0.2j) # some small rotation
         data = [complex(2*random.randint(0,1)-1, 0) for i in xrange(100)]
-        
+
         N = 40 # settling time
         expected_result = data[N:]
         data = [rot*d for d in data]
@@ -89,7 +89,7 @@ class test_costas_loop_cc(gr_unittest.TestCase):
         self.tb.run()
 
         dst_data = self.snk.data()[N:]
-        
+
         # generously compare results; the loop will converge near to, but
         # not exactly on, the target data
         self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 2)
@@ -103,7 +103,7 @@ class test_costas_loop_cc(gr_unittest.TestCase):
         rot = cmath.exp(0.2j) # some small rotation
         data = [complex(2*random.randint(0,1)-1, 2*random.randint(0,1)-1)
                 for i in xrange(100)]
-        
+
         N = 40 # settling time
         expected_result = data[N:]
         data = [rot*d for d in data]
@@ -130,7 +130,7 @@ class test_costas_loop_cc(gr_unittest.TestCase):
         const = psk.psk_constellation(order)
         data = [random.randint(0,7) for i in xrange(100)]
         data = [2*rot*const.points()[d] for d in data]
-        
+
         N = 40 # settling time
         expected_result = data[N:]
 
@@ -144,7 +144,7 @@ class test_costas_loop_cc(gr_unittest.TestCase):
         self.tb.run()
 
         dst_data = self.snk.data()[N:]
-        
+
        # generously compare results; the loop will converge near to, but
         # not exactly on, the target data
         self.assertComplexTuplesAlmostEqual(expected_result, dst_data, 2)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]