diff --git a/gr-hamnet70/grc/CMakeLists.txt b/gr-hamnet70/grc/CMakeLists.txt index 7afe598..0ce06b8 100644 --- a/gr-hamnet70/grc/CMakeLists.txt +++ b/gr-hamnet70/grc/CMakeLists.txt @@ -27,5 +27,6 @@ install(FILES hamnet70_async_scrambler.block.yml hamnet70_insert_pilot_symbols.block.yml hamnet70_correct_frequency_from_pilot_syms.block.yml - hamnet70_symbol_interleaver.block.yml DESTINATION share/gnuradio/grc/blocks + hamnet70_symbol_interleaver.block.yml + hamnet70_qam_phase_tracker.block.yml DESTINATION share/gnuradio/grc/blocks ) diff --git a/gr-hamnet70/grc/hamnet70_qam_phase_tracker.block.yml b/gr-hamnet70/grc/hamnet70_qam_phase_tracker.block.yml new file mode 100644 index 0000000..8fa0700 --- /dev/null +++ b/gr-hamnet70/grc/hamnet70_qam_phase_tracker.block.yml @@ -0,0 +1,28 @@ +id: hamnet70_qam_phase_tracker +label: QAM Phase Tracker +category: '[hamnet70]' + +templates: + imports: import hamnet70 + make: hamnet70.qam_phase_tracker(${symbols}, ${alpha}, ${start_tag}) + +parameters: +- id: symbols + label: Constellation Symbols + dtype: complex_vector +- id: alpha + label: Alpha + dtype: float +- id: start_tag + label: Start Tag + dtype: string + +inputs: +- domain: stream + dtype: complex + +outputs: +- domain: stream + dtype: complex + +file_format: 1 diff --git a/gr-hamnet70/include/hamnet70/CMakeLists.txt b/gr-hamnet70/include/hamnet70/CMakeLists.txt index 9adbe52..e0d0768 100644 --- a/gr-hamnet70/include/hamnet70/CMakeLists.txt +++ b/gr-hamnet70/include/hamnet70/CMakeLists.txt @@ -32,5 +32,6 @@ install(FILES async_scrambler.h insert_pilot_symbols.h correct_frequency_from_pilot_syms.h - symbol_interleaver.h DESTINATION include/hamnet70 + symbol_interleaver.h + qam_phase_tracker.h DESTINATION include/hamnet70 ) diff --git a/gr-hamnet70/include/hamnet70/qam_phase_tracker.h b/gr-hamnet70/include/hamnet70/qam_phase_tracker.h new file mode 100644 index 0000000..6c828bf --- /dev/null +++ b/gr-hamnet70/include/hamnet70/qam_phase_tracker.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Thomas Kolb. + * + * 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_HAMNET70_QAM_PHASE_TRACKER_H +#define INCLUDED_HAMNET70_QAM_PHASE_TRACKER_H + +#include +#include + +namespace gr { + namespace hamnet70 { + + /*! + * \brief <+description of block+> + * \ingroup hamnet70 + * + */ + class HAMNET70_API qam_phase_tracker : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of hamnet70::qam_phase_tracker. + * + * To avoid accidental use of raw pointers, hamnet70::qam_phase_tracker's + * constructor is in a private implementation + * class. hamnet70::qam_phase_tracker::make is the public interface for + * creating new instances. + */ + static sptr make(const std::vector &symbols, float alpha, const std::string &start_tag); + }; + + } // namespace hamnet70 +} // namespace gr + +#endif /* INCLUDED_HAMNET70_QAM_PHASE_TRACKER_H */ + diff --git a/gr-hamnet70/lib/CMakeLists.txt b/gr-hamnet70/lib/CMakeLists.txt index c6822d0..72fb0ed 100644 --- a/gr-hamnet70/lib/CMakeLists.txt +++ b/gr-hamnet70/lib/CMakeLists.txt @@ -34,6 +34,7 @@ list(APPEND hamnet70_sources insert_pilot_symbols_impl.cc correct_frequency_from_pilot_syms_impl.cc symbol_interleaver_impl.cc + qam_phase_tracker_impl.cc ) set(hamnet70_sources "${hamnet70_sources}" PARENT_SCOPE) diff --git a/gr-hamnet70/lib/qam_phase_tracker_impl.cc b/gr-hamnet70/lib/qam_phase_tracker_impl.cc new file mode 100644 index 0000000..2f1d143 --- /dev/null +++ b/gr-hamnet70/lib/qam_phase_tracker_impl.cc @@ -0,0 +1,132 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Thomas Kolb. + * + * 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 +#include +#include +#include "qam_phase_tracker_impl.h" + +namespace gr { + namespace hamnet70 { + + qam_phase_tracker::sptr + qam_phase_tracker::make(const std::vector &symbols, float alpha, const std::string &start_tag) + { + return gnuradio::get_initial_sptr + (new qam_phase_tracker_impl(symbols, alpha, start_tag)); + } + + + /* + * The private constructor + */ + qam_phase_tracker_impl::qam_phase_tracker_impl(const std::vector &symbols, float alpha, const std::string &start_tag) + : gr::sync_block("qam_phase_tracker", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_alpha(alpha), + d_startTag(pmt::intern(start_tag)), + d_avgPhaseOffset(0.0f) + { + // use only symbols in the upper right quadrant + for(auto s : symbols) { + if(s.real() >= 0 && s.imag() >= 0) { + d_refSymbols.push_back(s); + d_refPhase.push_back(gr::fast_atan2f(s)); + } + } + } + + /* + * Our virtual destructor. + */ + qam_phase_tracker_impl::~qam_phase_tracker_impl() + { + } + + int + qam_phase_tracker_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + for(int i = 0; i < noutput_items; i++) { + out[i] = in[i] * gr_expj(-d_avgPhaseOffset); + + std::vector tags; + get_tags_in_window(tags, 0, i, i+1, d_startTag); + + if(tags.size() > 0) { + // start tag found on this item -> reset average + d_avgPhaseOffset = 0; + } + + // update average phase offset from current symbol + + gr_complex rotated = out[i]; + + float re = rotated.real(); + float im = rotated.imag(); + + // normalize to positive quadrant + if(re < 0 && im > 0) { + rotated *= gr_expj(-M_PI/2); + } else if(re < 0 && im < 0) { + rotated *= -1; + } else if(im < 0) { // && re > 0 + rotated *= gr_expj(M_PI/2); + } // else already ok + + // find closest reference symbol + float min_dist = 1e9; + size_t closest_idx; + + for(size_t r = 0; r < d_refSymbols.size(); r++) { + float d = std::norm(d_refSymbols[r] - rotated); + + if(d < min_dist) { + closest_idx = r; + min_dist = d; + } + } + + float phase = gr::fast_atan2f(rotated); + float delta_phase = phase - d_refPhase[closest_idx]; + + if(delta_phase > M_PI/4 || delta_phase < -M_PI/4) { + continue; + } + + d_avgPhaseOffset += d_alpha * delta_phase; + } + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace hamnet70 */ +} /* namespace gr */ + diff --git a/gr-hamnet70/lib/qam_phase_tracker_impl.h b/gr-hamnet70/lib/qam_phase_tracker_impl.h new file mode 100644 index 0000000..686cdd4 --- /dev/null +++ b/gr-hamnet70/lib/qam_phase_tracker_impl.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2019 Thomas Kolb. + * + * 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_HAMNET70_QAM_PHASE_TRACKER_IMPL_H +#define INCLUDED_HAMNET70_QAM_PHASE_TRACKER_IMPL_H + +#include + +namespace gr { + namespace hamnet70 { + + class qam_phase_tracker_impl : public qam_phase_tracker + { + private: + pmt::pmt_t d_startTag; + float d_alpha; + float d_avgPhaseOffset; + std::vector d_refSymbols; + std::vector d_refPhase; + + public: + qam_phase_tracker_impl(const std::vector &symbols, float alpha, const std::string &start_tag); + ~qam_phase_tracker_impl(); + + // Where all the action really happens + int work( + int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ); + }; + + } // namespace hamnet70 +} // namespace gr + +#endif /* INCLUDED_HAMNET70_QAM_PHASE_TRACKER_IMPL_H */ + diff --git a/gr-hamnet70/python/CMakeLists.txt b/gr-hamnet70/python/CMakeLists.txt index 4e8c047..69aee35 100644 --- a/gr-hamnet70/python/CMakeLists.txt +++ b/gr-hamnet70/python/CMakeLists.txt @@ -52,3 +52,4 @@ set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) #GR_ADD_TEST(qa_insert_pilot_symbols ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_insert_pilot_symbols.py) #GR_ADD_TEST(qa_correct_frequency_from_pilot_syms ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_correct_frequency_from_pilot_syms.py) #GR_ADD_TEST(qa_symbol_interleaver ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_symbol_interleaver.py) +GR_ADD_TEST(qa_qam_phase_tracker ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_qam_phase_tracker.py) diff --git a/gr-hamnet70/python/qa_qam_phase_tracker.py b/gr-hamnet70/python/qa_qam_phase_tracker.py new file mode 100755 index 0000000..fd65d8a --- /dev/null +++ b/gr-hamnet70/python/qa_qam_phase_tracker.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2019 Thomas Kolb. +# +# 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. +# + +from gnuradio import gr, gr_unittest +from gnuradio import blocks +import hamnet70_swig as hamnet70 + +class qa_qam_phase_tracker(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_001_t(self): + # set up fg + self.tb.run() + # check data + + +if __name__ == '__main__': + gr_unittest.run(qa_qam_phase_tracker) diff --git a/gr-hamnet70/swig/hamnet70_swig.i b/gr-hamnet70/swig/hamnet70_swig.i index 45f3e61..dc7a0be 100644 --- a/gr-hamnet70/swig/hamnet70_swig.i +++ b/gr-hamnet70/swig/hamnet70_swig.i @@ -18,6 +18,7 @@ #include "hamnet70/insert_pilot_symbols.h" #include "hamnet70/correct_frequency_from_pilot_syms.h" #include "hamnet70/symbol_interleaver.h" +#include "hamnet70/qam_phase_tracker.h" %} @@ -42,3 +43,5 @@ GR_SWIG_BLOCK_MAGIC2(hamnet70, insert_pilot_symbols); GR_SWIG_BLOCK_MAGIC2(hamnet70, correct_frequency_from_pilot_syms); %include "hamnet70/symbol_interleaver.h" GR_SWIG_BLOCK_MAGIC2(hamnet70, symbol_interleaver); +%include "hamnet70/qam_phase_tracker.h" +GR_SWIG_BLOCK_MAGIC2(hamnet70, qam_phase_tracker);