diff --git a/gr-hamnet70/grc/CMakeLists.txt b/gr-hamnet70/grc/CMakeLists.txt
index 8ff9626..aedba5e 100644
--- a/gr-hamnet70/grc/CMakeLists.txt
+++ b/gr-hamnet70/grc/CMakeLists.txt
@@ -24,5 +24,7 @@ install(FILES
hamnet70_pid_controller.xml
hamnet70_insert_delayed_tag.xml
hamnet70_scrambler.xml
- hamnet70_async_scrambler.xml DESTINATION share/gnuradio/grc/blocks
+ hamnet70_async_scrambler.xml
+ hamnet70_insert_pilot_symbols.xml
+ hamnet70_correct_frequency_from_pilot_syms.xml DESTINATION share/gnuradio/grc/blocks
)
diff --git a/gr-hamnet70/grc/hamnet70_correct_frequency_from_pilot_syms.xml b/gr-hamnet70/grc/hamnet70_correct_frequency_from_pilot_syms.xml
new file mode 100644
index 0000000..196ab09
--- /dev/null
+++ b/gr-hamnet70/grc/hamnet70_correct_frequency_from_pilot_syms.xml
@@ -0,0 +1,38 @@
+
+
+ Correct Frequency from Pilot Symbols
+ hamnet70_correct_frequency_from_pilot_syms
+ [hamnet70]
+ import hamnet70
+ hamnet70.correct_frequency_from_pilot_syms($pilot_sequence, $offsets, $phase_ref_offset, $start_tag)
+
+ Pilot Sequence
+ pilot_sequence
+ complex_vector
+
+
+ Insertion Positions
+ offsets
+ int_vector
+
+
+ Phase Reference Index
+ phase_ref_offset
+ int
+
+
+
+ Start Tag Key
+ start_tag
+ string
+
+
+
+ in
+ complex
+
+
+
diff --git a/gr-hamnet70/grc/hamnet70_insert_pilot_symbols.xml b/gr-hamnet70/grc/hamnet70_insert_pilot_symbols.xml
new file mode 100644
index 0000000..024699b
--- /dev/null
+++ b/gr-hamnet70/grc/hamnet70_insert_pilot_symbols.xml
@@ -0,0 +1,32 @@
+
+
+ Insert Pilot Symbols
+ hamnet70_insert_pilot_symbols
+ [hamnet70]
+ import hamnet70
+ hamnet70.insert_pilot_symbols($pilot_sequence, $offsets, $length_tag)
+
+ Pilot Sequence
+ pilot_sequence
+ complex_vector
+
+
+ Insertion Positions
+ offsets
+ int_vector
+
+
+ Length Tag Key
+ length_tag
+ string
+
+
+
+ in
+ complex
+
+
+
diff --git a/gr-hamnet70/include/hamnet70/CMakeLists.txt b/gr-hamnet70/include/hamnet70/CMakeLists.txt
index 0b2749f..cdd8f5d 100644
--- a/gr-hamnet70/include/hamnet70/CMakeLists.txt
+++ b/gr-hamnet70/include/hamnet70/CMakeLists.txt
@@ -29,5 +29,7 @@ install(FILES
pid_controller.h
insert_delayed_tag.h
scrambler.h
- async_scrambler.h DESTINATION include/hamnet70
+ async_scrambler.h
+ insert_pilot_symbols.h
+ correct_frequency_from_pilot_syms.h DESTINATION include/hamnet70
)
diff --git a/gr-hamnet70/include/hamnet70/correct_frequency_from_pilot_syms.h b/gr-hamnet70/include/hamnet70/correct_frequency_from_pilot_syms.h
new file mode 100644
index 0000000..c5259d7
--- /dev/null
+++ b/gr-hamnet70/include/hamnet70/correct_frequency_from_pilot_syms.h
@@ -0,0 +1,56 @@
+/* -*- 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_CORRECT_FREQUENCY_FROM_PILOT_SYMS_H
+#define INCLUDED_HAMNET70_CORRECT_FREQUENCY_FROM_PILOT_SYMS_H
+
+#include
+#include
+
+namespace gr {
+ namespace hamnet70 {
+
+ /*!
+ * \brief <+description of block+>
+ * \ingroup hamnet70
+ *
+ */
+ class HAMNET70_API correct_frequency_from_pilot_syms : virtual public gr::block
+ {
+ public:
+ typedef boost::shared_ptr sptr;
+
+ /*!
+ * \brief Return a shared_ptr to a new instance of hamnet70::correct_frequency_from_pilot_syms.
+ *
+ * To avoid accidental use of raw pointers, hamnet70::correct_frequency_from_pilot_syms's
+ * constructor is in a private implementation
+ * class. hamnet70::correct_frequency_from_pilot_syms::make is the public interface for
+ * creating new instances.
+ */
+ static sptr make(const std::vector &pilot_sequence, const std::vector &offsets, size_t phase_ref_offset = 0, const std::string &start_tag = "corr_est");
+ };
+
+ } // namespace hamnet70
+} // namespace gr
+
+#endif /* INCLUDED_HAMNET70_CORRECT_FREQUENCY_FROM_PILOT_SYMS_H */
+
diff --git a/gr-hamnet70/include/hamnet70/insert_pilot_symbols.h b/gr-hamnet70/include/hamnet70/insert_pilot_symbols.h
new file mode 100644
index 0000000..d33521c
--- /dev/null
+++ b/gr-hamnet70/include/hamnet70/insert_pilot_symbols.h
@@ -0,0 +1,56 @@
+/* -*- 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_INSERT_PILOT_SYMBOLS_H
+#define INCLUDED_HAMNET70_INSERT_PILOT_SYMBOLS_H
+
+#include
+#include
+
+namespace gr {
+ namespace hamnet70 {
+
+ /*!
+ * \brief <+description of block+>
+ * \ingroup hamnet70
+ *
+ */
+ class HAMNET70_API insert_pilot_symbols : virtual public gr::tagged_stream_block
+ {
+ public:
+ typedef boost::shared_ptr sptr;
+
+ /*!
+ * \brief Return a shared_ptr to a new instance of hamnet70::insert_pilot_symbols.
+ *
+ * To avoid accidental use of raw pointers, hamnet70::insert_pilot_symbols's
+ * constructor is in a private implementation
+ * class. hamnet70::insert_pilot_symbols::make is the public interface for
+ * creating new instances.
+ */
+ static sptr make(const std::vector &pilot_sequence, const std::vector &offsets, const std::string &length_tag);
+ };
+
+ } // namespace hamnet70
+} // namespace gr
+
+#endif /* INCLUDED_HAMNET70_INSERT_PILOT_SYMBOLS_H */
+
diff --git a/gr-hamnet70/lib/CMakeLists.txt b/gr-hamnet70/lib/CMakeLists.txt
index 1143942..7d8617f 100644
--- a/gr-hamnet70/lib/CMakeLists.txt
+++ b/gr-hamnet70/lib/CMakeLists.txt
@@ -33,6 +33,8 @@ list(APPEND hamnet70_sources
insert_delayed_tag_impl.cc
scrambler_impl.cc
async_scrambler_impl.cc
+ insert_pilot_symbols_impl.cc
+ correct_frequency_from_pilot_syms_impl.cc
)
set(hamnet70_sources "${hamnet70_sources}" PARENT_SCOPE)
diff --git a/gr-hamnet70/lib/correct_frequency_from_pilot_syms_impl.cc b/gr-hamnet70/lib/correct_frequency_from_pilot_syms_impl.cc
new file mode 100644
index 0000000..1fe3bdc
--- /dev/null
+++ b/gr-hamnet70/lib/correct_frequency_from_pilot_syms_impl.cc
@@ -0,0 +1,210 @@
+/* -*- 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
+#include "correct_frequency_from_pilot_syms_impl.h"
+
+namespace gr {
+ namespace hamnet70 {
+
+ correct_frequency_from_pilot_syms::sptr
+ correct_frequency_from_pilot_syms::make(const std::vector &pilot_sequence, const std::vector &offsets, size_t phase_ref_offset, const std::string &start_tag)
+ {
+ return gnuradio::get_initial_sptr
+ (new correct_frequency_from_pilot_syms_impl(pilot_sequence, offsets, phase_ref_offset, start_tag));
+ }
+
+ /*
+ * The private constructor
+ */
+ correct_frequency_from_pilot_syms_impl::correct_frequency_from_pilot_syms_impl(const std::vector &pilot_sequence, const std::vector &offsets, size_t phase_ref_offset, const std::string &start_tag)
+ : gr::block("correct_frequency_from_pilot_syms",
+ gr::io_signature::make(1, 1, sizeof(gr_complex)),
+ gr::io_signature::make(1, 1, sizeof(gr_complex))),
+ d_pilot_sequence(pilot_sequence),
+ d_offsets(offsets),
+ d_phase_ref_offset(phase_ref_offset),
+ d_start_tag(pmt::intern(start_tag)),
+ d_items_required(*std::max_element(offsets.begin(), offsets.end()) + pilot_sequence.size()),
+ d_tag_found(false),
+ d_phase_inc_per_symbol(0.0f),
+ d_current_phase(0.0f)
+ {
+ set_tag_propagation_policy(TPP_CUSTOM);
+ }
+
+ /*
+ * Our virtual destructor.
+ */
+ correct_frequency_from_pilot_syms_impl::~correct_frequency_from_pilot_syms_impl()
+ {
+ }
+
+ void
+ correct_frequency_from_pilot_syms_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required)
+ {
+ ninput_items_required[0] = noutput_items + d_pilot_sequence.size() * d_offsets.size();
+ }
+
+ int
+ correct_frequency_from_pilot_syms_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];
+ gr_complex *out = (gr_complex *) output_items[0];
+
+ int consumed = 0, produced = 0;
+
+ std::vector tags;
+ get_tags_in_window(tags, 0, 0, ninput_items[0], d_start_tag);
+ size_t tagidx = 0;
+
+ for(int i = 0; i < ninput_items[0]; i++) {
+ if((tagidx < tags.size()) && (tags[tagidx].offset == nitems_read(0) + i)) {
+ d_packet.clear();
+ d_tags_in_packet.clear();
+ d_tag_found = true;
+
+ tagidx++;
+ }
+
+ if(!d_tag_found) {
+ // tag propagation
+ std::vector prop_tags;
+ get_tags_in_window(prop_tags, 0, consumed, consumed+1);
+
+ for(tag_t &tag: prop_tags) {
+ tag.offset = nitems_written(0) + produced;
+ add_item_tag(0, tag);
+ }
+
+ // calculate sample
+ d_current_phase += d_phase_inc_per_symbol;
+ out[produced++] = in[consumed++] * gr_expj(d_current_phase);
+ } else if(d_tag_found && d_packet.size() < d_items_required) {
+ // get and store tags for later insertion in the output stream
+ std::vector prop_tags;
+ get_tags_in_window(prop_tags, 0, consumed, consumed+1);
+
+ for(tag_t &tag: prop_tags) {
+ tag.offset = d_packet.size();
+ d_tags_in_packet.push_back(tag);
+ }
+
+ d_packet.push_back(in[consumed++]);
+ } else if(d_packet.size() == d_items_required) {
+
+ // frequency estimation
+ float phase_sum = 0.0f;
+ size_t last_off = d_phase_ref_offset;
+ float last_phase = 0.0f;
+
+ for(size_t off: d_offsets) {
+ gr_complex sum(0, 0);
+
+ size_t n = 0;
+ for(const gr_complex &ref_sym: d_pilot_sequence) {
+ sum += d_packet[off+n] * conj(ref_sym);
+ n++;
+ }
+
+ sum /= n;
+
+ float phase = gr::fast_atan2f(sum); // FIXME? unwrap
+ phase_sum += (phase - last_phase) / (off - last_off);
+ last_phase = phase;
+ last_off = off;
+ }
+
+ d_phase_inc_per_symbol = -phase_sum / d_offsets.size();
+ d_current_phase = (-(int)d_phase_ref_offset - 1) * d_phase_inc_per_symbol;
+
+ //std::cout << "initial phase: " << d_current_phase << std::endl;
+ //std::cout << "phase increment: " << d_phase_inc_per_symbol << std::endl;
+
+ size_t drop_start = 1;
+ size_t drop_end = 0;
+ size_t next_off_idx = 0;
+
+ //std::cout << "packet = [";
+
+ std::vector::iterator tag_iter = d_tags_in_packet.begin();
+
+ for(size_t i = 0; i < d_packet.size(); i++) {
+ d_current_phase += d_phase_inc_per_symbol;
+
+ if(i == drop_end) {
+ if(next_off_idx >= d_offsets.size()) {
+ drop_end = drop_start = d_packet.size(); // index cannot be reached
+ } else {
+ drop_start = d_offsets[next_off_idx];
+ drop_end = d_offsets[next_off_idx] + d_pilot_sequence.size();
+
+ next_off_idx++;
+ }
+ }
+
+ if(i >= drop_start) {
+ continue;
+ }
+
+ // restore tags
+ while(tag_iter != d_tags_in_packet.end() &&
+ tag_iter->offset <= i) {
+ tag_iter->offset = nitems_written(0) + produced;
+ add_item_tag(0, *tag_iter);
+ tag_iter++;
+ }
+
+ gr_complex &item = d_packet[i];
+ out[produced++] = item * gr_expj(d_current_phase);
+
+ gr_complex &c = out[produced-1];
+ //std::cout << c.real() << "+" << c.imag() << "j, ";
+ }
+
+ //std::cout << "]" << std::endl;
+
+ d_tag_found = false;
+ }
+ }
+
+
+ // Tell runtime system how many input items we consumed on
+ // each input stream.
+ consume_each (consumed);
+
+ // Tell runtime system how many output items we produced.
+ return produced;
+ }
+
+ } /* namespace hamnet70 */
+} /* namespace gr */
+
diff --git a/gr-hamnet70/lib/correct_frequency_from_pilot_syms_impl.h b/gr-hamnet70/lib/correct_frequency_from_pilot_syms_impl.h
new file mode 100644
index 0000000..5eec2e3
--- /dev/null
+++ b/gr-hamnet70/lib/correct_frequency_from_pilot_syms_impl.h
@@ -0,0 +1,65 @@
+/* -*- 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_CORRECT_FREQUENCY_FROM_PILOT_SYMS_IMPL_H
+#define INCLUDED_HAMNET70_CORRECT_FREQUENCY_FROM_PILOT_SYMS_IMPL_H
+
+#include
+
+#include