diff options
Diffstat (limited to 'gr-digital/lib')
126 files changed, 10521 insertions, 6996 deletions
diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt index c7f73f8505..d47e7fb1f3 100644 --- a/gr-digital/lib/CMakeLists.txt +++ b/gr-digital/lib/CMakeLists.txt @@ -21,10 +21,13 @@ # Setup the include and linker paths ######################################################################## include_directories( - ${CMAKE_CURRENT_BINARY_DIR}/../include ${GR_DIGITAL_INCLUDE_DIRS} + ${GR_BLOCKS_INCLUDE_DIRS} ${GR_ANALOG_INCLUDE_DIRS} + ${GR_FFT_INCLUDE_DIRS} + ${GR_FILTER_INCLUDE_DIRS} ${GNURADIO_CORE_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} ${GRUEL_INCLUDE_DIRS} ${LOG4CXX_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} @@ -33,6 +36,11 @@ include_directories( link_directories(${Boost_LIBRARY_DIRS}) link_directories(${LOG4CXX_LIBRARY_DIRS}) +if(ENABLE_GR_CTRLPORT) + ADD_DEFINITIONS(-DGR_CTRLPORT) + include_directories(${ICE_INCLUDE_DIR}) +endif(ENABLE_GR_CTRLPORT) + ######################################################################## # generate helper scripts to expand templated files ######################################################################## @@ -51,9 +59,8 @@ if __name__ == '__main__': root, inp = sys.argv[1:3] for sig in sys.argv[3:]: name = re.sub ('X+', sig, root) - d = build_utils.standard_dict(name, sig, 'digital') + d = build_utils.standard_impl_dict2(name, sig, 'digital') build_utils.expand_template(d, inp) - ") macro(expand_cc root) @@ -63,10 +70,10 @@ macro(expand_cc root) foreach(sig ${ARGN}) string(REGEX REPLACE "X+" ${sig} name ${root}) list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc) - list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/../include/${name}.h) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h) endforeach(sig) - #create a command to generate the files + #create a command to generate the source files add_custom_command( OUTPUT ${expanded_files_cc} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.cc.t @@ -74,6 +81,15 @@ macro(expand_cc root) ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py ${root} ${root}.cc.t ${ARGN} ) + + #create a command to generate the header file + add_custom_command( + OUTPUT ${expanded_files_h} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.h.t ${ARGN} + ) #make source files depends on headers to force generation set_source_files_properties(${expanded_files_cc} @@ -82,64 +98,63 @@ macro(expand_cc root) #install rules for the generated cc files list(APPEND generated_sources ${expanded_files_cc}) + list(APPEND generated_headers ${expanded_files_h}) endmacro(expand_cc) + ######################################################################## # Invoke macro to generate various sources ######################################################################## -expand_cc(digital_chunks_to_symbols_XX bf bc sf sc if ic) +expand_cc(chunks_to_symbols_XX_impl bf bc sf sc if ic) ######################################################################## # Setup library ######################################################################## - -list(APPEND gr_digital_sources +list(APPEND digital_sources ${generated_sources} - digital_impl_glfsr.cc - digital_impl_mpsk_snr_est.cc - digital_additive_scrambler_bb.cc - digital_binary_slicer_fb.cc - digital_bytes_to_syms.cc - digital_clock_recovery_mm_cc.cc - digital_clock_recovery_mm_ff.cc - digital_cma_equalizer_cc.cc - digital_constellation.cc - digital_constellation_receiver_cb.cc - digital_constellation_decoder_cb.cc - digital_correlate_access_code_bb.cc - digital_correlate_access_code_tag_bb.cc - digital_costas_loop_cc.cc - digital_cpmmod_bc.cc - digital_crc32.cc - digital_descrambler_bb.cc - digital_diff_decoder_bb.cc - digital_diff_encoder_bb.cc - digital_diff_phasor_cc.cc - digital_fll_band_edge_cc.cc - digital_framer_sink_1.cc - digital_glfsr_source_b.cc - digital_glfsr_source_f.cc - digital_gmskmod_bc.cc - digital_lms_dd_equalizer_cc.cc - digital_kurtotic_equalizer_cc.cc - digital_map_bb.cc - digital_mpsk_receiver_cc.cc - digital_mpsk_snr_est_cc.cc - digital_ofdm_cyclic_prefixer.cc - digital_ofdm_frame_acquisition.cc - digital_ofdm_frame_sink.cc - digital_ofdm_insert_preamble.cc - digital_ofdm_mapper_bcv.cc - digital_ofdm_sampler.cc - digital_packet_sink.cc - digital_pfb_clock_sync_ccf.cc - digital_pfb_clock_sync_fff.cc - digital_pn_correlator_cc.cc - digital_probe_density_b.cc - digital_probe_mpsk_snr_est_c.cc - digital_scrambler_bb.cc - digital_simple_framer.cc - digital_simple_correlator.cc + constellation.cc + crc32.cc + glfsr.cc + mpsk_snr_est.cc + additive_scrambler_bb_impl.cc + binary_slicer_fb_impl.cc + clock_recovery_mm_cc_impl.cc + clock_recovery_mm_ff_impl.cc + cma_equalizer_cc_impl.cc + constellation_receiver_cb_impl.cc + constellation_decoder_cb_impl.cc + correlate_access_code_bb_impl.cc + correlate_access_code_tag_bb_impl.cc + costas_loop_cc_impl.cc + cpmmod_bc_impl.cc + descrambler_bb_impl.cc + diff_decoder_bb_impl.cc + diff_encoder_bb_impl.cc + diff_phasor_cc_impl.cc + fll_band_edge_cc_impl.cc + framer_sink_1_impl.cc + glfsr_source_b_impl.cc + glfsr_source_f_impl.cc + kurtotic_equalizer_cc_impl.cc + lms_dd_equalizer_cc_impl.cc + map_bb_impl.cc + mpsk_receiver_cc_impl.cc + mpsk_snr_est_cc_impl.cc + ofdm_cyclic_prefixer_impl.cc + ofdm_frame_acquisition_impl.cc + ofdm_frame_sink_impl.cc + ofdm_insert_preamble_impl.cc + ofdm_mapper_bcv_impl.cc + ofdm_sampler_impl.cc + packet_sink_impl.cc + pfb_clock_sync_ccf_impl.cc + pfb_clock_sync_fff_impl.cc + pn_correlator_cc_impl.cc + probe_density_b_impl.cc + probe_mpsk_snr_est_c_impl.cc + scrambler_bb_impl.cc + simple_framer_impl.cc + simple_correlator_impl.cc ) #Add Windows DLL resource file if using MSVC @@ -157,13 +172,19 @@ IF(MSVC) ENDIF(MSVC) list(APPEND digital_libs + volk gnuradio-core + gnuradio-filter + gnuradio-blocks + gnuradio-analog ${Boost_LIBRARIES} ${LOG4CXX_LIBRARIES} ) -add_library(gnuradio-digital SHARED ${gr_digital_sources}) + +add_library(gnuradio-digital SHARED ${digital_sources}) target_link_libraries(gnuradio-digital ${digital_libs}) GR_LIBRARY_FOO(gnuradio-digital RUNTIME_COMPONENT "digital_runtime" DEVEL_COMPONENT "digital_devel") - -add_dependencies(gnuradio-digital digital_generated_includes digital_generated_swigs gnuradio-analog) +add_dependencies(gnuradio-digital + digital_generated_includes digital_generated_swigs + gnuradio-core gnuradio-filter gnuradio-analog) diff --git a/gr-digital/lib/additive_scrambler_bb_impl.cc b/gr-digital/lib/additive_scrambler_bb_impl.cc new file mode 100644 index 0000000000..8238f2d988 --- /dev/null +++ b/gr-digital/lib/additive_scrambler_bb_impl.cc @@ -0,0 +1,104 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "additive_scrambler_bb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + additive_scrambler_bb::sptr + additive_scrambler_bb::make(int mask, int seed, int len, int count) + { + return gnuradio::get_initial_sptr(new additive_scrambler_bb_impl + (mask, seed, len, count)); + } + + additive_scrambler_bb_impl::additive_scrambler_bb_impl(int mask, + int seed, + int len, + int count) + : gr_sync_block("additive_scrambler_bb", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_lfsr(mask, seed, len), + d_count(count), + d_bits(0), d_len(len), d_seed(seed) + { + } + + additive_scrambler_bb_impl::~additive_scrambler_bb_impl() + { + } + + int + additive_scrambler_bb_impl::mask() const + { + return d_lfsr.mask(); + } + + int + additive_scrambler_bb_impl::seed() const + { + return d_seed; + } + + int + additive_scrambler_bb_impl::len() const + { + return d_len; + } + + int + additive_scrambler_bb_impl::count() const + { + return d_count; + } + + int + additive_scrambler_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *)input_items[0]; + unsigned char *out = (unsigned char *)output_items[0]; + + for(int i = 0; i < noutput_items; i++) { + out[i] = in[i]^d_lfsr.next_bit(); + if(d_count > 0) { + if(++d_bits == d_count) { + d_lfsr.reset(); + d_bits = 0; + } + } + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/additive_scrambler_bb_impl.h b/gr-digital/lib/additive_scrambler_bb_impl.h new file mode 100644 index 0000000000..5a4c2f5025 --- /dev/null +++ b/gr-digital/lib/additive_scrambler_bb_impl.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2010,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_ADDITIVE_SCRAMBLER_BB_IMPL_H +#define INCLUDED_DIGITAL_ADDITIVE_SCRAMBLER_BB_IMPL_H + +#include <digital/additive_scrambler_bb.h> +#include <digital/lfsr.h> + +namespace gr { + namespace digital { + + class additive_scrambler_bb_impl + : public additive_scrambler_bb + { + private: + digital::lfsr d_lfsr; + int d_count; + int d_bits; + int d_len; + int d_seed; + + public: + additive_scrambler_bb_impl(int mask, int seed, + int len, int count=0); + ~additive_scrambler_bb_impl(); + + int mask() const; + int seed() const; + int len() const; + int count() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_ADDITIVE_SCRAMBLER_BB_IMPL_H */ diff --git a/gr-digital/lib/digital_binary_slicer_fb.cc b/gr-digital/lib/binary_slicer_fb_impl.cc index fcdb4291fb..f8a9cf22de 100644 --- a/gr-digital/lib/digital_binary_slicer_fb.cc +++ b/gr-digital/lib/binary_slicer_fb_impl.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2010,2011 Free Software Foundation, Inc. + * Copyright 2006,2010-2012 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,36 +24,43 @@ #include "config.h" #endif -#include <digital_binary_slicer_fb.h> +#include "binary_slicer_fb_impl.h" #include <gr_io_signature.h> #include <gr_math.h> -#include <stdexcept> - -digital_binary_slicer_fb_sptr -digital_make_binary_slicer_fb () -{ - return gnuradio::get_initial_sptr(new digital_binary_slicer_fb ()); -} - -digital_binary_slicer_fb::digital_binary_slicer_fb () - : gr_sync_block ("binary_slicer_fb", - gr_make_io_signature (1, 1, sizeof (float)), - gr_make_io_signature (1, 1, sizeof (unsigned char))) -{ -} - -int -digital_binary_slicer_fb::work (int noutput_items, + +namespace gr { + namespace digital { + + binary_slicer_fb::sptr binary_slicer_fb::make() + { + return gnuradio::get_initial_sptr(new binary_slicer_fb_impl()); + } + + binary_slicer_fb_impl::binary_slicer_fb_impl() + : gr_sync_block("binary_slicer_fb", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(unsigned char))) + { + } + + binary_slicer_fb_impl::~binary_slicer_fb_impl() + { + } + + int + binary_slicer_fb_impl::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - const float *in = (const float *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - + { + const float *in = (const float *)input_items[0]; + unsigned char *out = (unsigned char *)output_items[0]; - for (int i = 0; i < noutput_items; i++){ - out[i] = gr_binary_slicer(in[i]); - } + for(int i = 0; i < noutput_items; i++) { + out[i] = gr_binary_slicer(in[i]); + } - return noutput_items; -} + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/digital_gmskmod_bc.cc b/gr-digital/lib/binary_slicer_fb_impl.h index e53e900370..7416d9cd52 100644 --- a/gr-digital/lib/digital_gmskmod_bc.cc +++ b/gr-digital/lib/binary_slicer_fb_impl.h @@ -1,9 +1,9 @@ /* -*- c++ -*- */ /* - * Copyright 2010 Free Software Foundation, Inc. + * Copyright 2006,2011,2012 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) @@ -20,25 +20,26 @@ * Boston, MA 02110-1301, USA. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#ifndef INCLUDED_DIGITAL_BINARY_SLICER_FB_IMPL_H +#define INCLUDED_DIGITAL_BINARY_SLICER_FB_IMPL_H + +#include <digital/binary_slicer_fb.h> -#include <digital_gmskmod_bc.h> -#include <gr_io_signature.h> +namespace gr { + namespace digital { -// Shared pointer constructor -digital_gmskmod_bc_sptr -digital_make_gmskmod_bc(unsigned samples_per_sym, - double bt, unsigned L) -{ - return gnuradio::get_initial_sptr(new digital_gmskmod_bc(samples_per_sym, bt, L)); -} + class binary_slicer_fb_impl : public binary_slicer_fb + { + public: + binary_slicer_fb_impl(); + ~binary_slicer_fb_impl(); + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; -digital_gmskmod_bc::digital_gmskmod_bc(unsigned samples_per_sym, - double bt, unsigned L) - : digital_cpmmod_bc(gr_cpm::GAUSSIAN, 0.5, samples_per_sym, L, bt) -{ -} + } /* namespace digital */ +} /* namespace gr */ +#endif /* INCLUDED_DIGITAL_BINARY_SLICER_FB_IMPL_H */ diff --git a/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t b/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t new file mode 100644 index 0000000000..39eca32db6 --- /dev/null +++ b/gr-digital/lib/chunks_to_symbols_XX_impl.cc.t @@ -0,0 +1,80 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 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. + */ + +/* @WARNING@ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "@NAME@.h" +#include <gr_io_signature.h> +#include <assert.h> + +namespace gr { + namespace digital { + + @BASE_NAME@::sptr + @BASE_NAME@::make(const std::vector<@O_TYPE@> &symbol_table, const int D) + { + return gnuradio::get_initial_sptr + (new @IMPL_NAME@(symbol_table, D)); + } + + @IMPL_NAME@::@IMPL_NAME@(const std::vector<@O_TYPE@> &symbol_table, const int D) + : gr_sync_interpolator("@BASE_NAME@", + gr_make_io_signature(1, -1, sizeof(@I_TYPE@)), + gr_make_io_signature(1, -1, sizeof(@O_TYPE@)), + D), + d_D(D), d_symbol_table(symbol_table) + { + } + + @IMPL_NAME@::~@IMPL_NAME@() + { + } + + int + @IMPL_NAME@::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + assert(noutput_items % d_D == 0); + assert(input_items.size() == output_items.size()); + int nstreams = input_items.size(); + + for(int m = 0; m < nstreams; m++) { + const @I_TYPE@ *in = (@I_TYPE@*)input_items[m]; + @O_TYPE@ *out = (@O_TYPE@*)output_items[m]; + + // per stream processing + for(int i = 0; i < noutput_items / d_D; i++) { + assert(((unsigned int)in[i]*d_D+d_D) <= d_symbol_table.size()); + memcpy(out, &d_symbol_table[(unsigned int)in[i]*d_D], d_D*sizeof(@O_TYPE@)); + out+=d_D; + } + } + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/chunks_to_symbols_XX_impl.h.t b/gr-digital/lib/chunks_to_symbols_XX_impl.h.t new file mode 100644 index 0000000000..ea44c71ad4 --- /dev/null +++ b/gr-digital/lib/chunks_to_symbols_XX_impl.h.t @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 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. + */ + +/* @WARNING@ */ + +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include <digital/@BASE_NAME@.h> + +namespace gr { + namespace digital { + + class @IMPL_NAME@ : public @BASE_NAME@ + { + private: + int d_D; + std::vector<@O_TYPE@> d_symbol_table; + + public: + @IMPL_NAME@(const std::vector<@O_TYPE@> &symbol_table, const int D = 1); + + ~@IMPL_NAME@(); + + int D() const { return d_D; } + std::vector<@O_TYPE@> symbol_table() const { return d_symbol_table; } + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + bool check_topology(int ninputs, int noutputs) { return ninputs == noutputs; } + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* @GUARD_NAME@ */ diff --git a/gr-digital/lib/clock_recovery_mm_cc_impl.cc b/gr-digital/lib/clock_recovery_mm_cc_impl.cc new file mode 100644 index 0000000000..168d9f7772 --- /dev/null +++ b/gr-digital/lib/clock_recovery_mm_cc_impl.cc @@ -0,0 +1,214 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clock_recovery_mm_cc_impl.h" +#include <gr_io_signature.h> +#include <gr_prefs.h> +#include <gr_math.h> +#include <stdexcept> +#include <iostream> + +namespace gr { + namespace digital { + + static const int FUDGE = 16; + + clock_recovery_mm_cc::sptr + clock_recovery_mm_cc::make(float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit) + { + return gnuradio::get_initial_sptr + (new clock_recovery_mm_cc_impl(omega, gain_omega, + mu, gain_mu, + omega_relative_limit)); + } + + clock_recovery_mm_cc_impl::clock_recovery_mm_cc_impl(float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit) + : gr_block("clock_recovery_mm_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature2(1, 2, sizeof(gr_complex), sizeof(float))), + d_mu(mu), d_omega(omega), d_gain_omega(gain_omega), + d_omega_relative_limit(omega_relative_limit), + d_gain_mu(gain_mu), d_last_sample(0), d_interp(new filter::mmse_fir_interpolator_cc()), + d_verbose(gr_prefs::singleton()->get_bool("clock_recovery_mm_cc", "verbose", false)), + d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0) + { + if(omega <= 0.0) + throw std::out_of_range("clock rate must be > 0"); + if(gain_mu < 0 || gain_omega < 0) + throw std::out_of_range("Gains must be non-negative"); + + set_omega(omega); // also sets min and max omega + set_relative_rate(1.0 / omega); + set_history(3); // ensure 2 extra input samples are available + } + + clock_recovery_mm_cc_impl::~clock_recovery_mm_cc_impl() + { + delete d_interp; + } + + void + clock_recovery_mm_cc_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] = + (int)ceil((noutput_items * d_omega) + d_interp->ntaps()) + FUDGE; + } + + gr_complex + clock_recovery_mm_cc_impl::slicer_0deg(gr_complex sample) + { + float real=0, imag=0; + + if(sample.real() > 0) + real = 1; + if(sample.imag() > 0) + imag = 1; + return gr_complex(real,imag); + } + + gr_complex + clock_recovery_mm_cc_impl::slicer_45deg(gr_complex sample) + { + float real= -1, imag = -1; + if(sample.real() > 0) + real=1; + if(sample.imag() > 0) + imag = 1; + return gr_complex(real,imag); + } + + int + clock_recovery_mm_cc_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]; + float *foptr = (float *)output_items[1]; + + bool write_foptr = output_items.size() >= 2; + + int ii = 0; // input index + int oo = 0; // output index + int ni = ninput_items[0] - d_interp->ntaps() - FUDGE; // don't use more input than this + + assert(d_mu >= 0.0); + assert(d_mu <= 1.0); + + float mm_val = 0; + gr_complex u, x, y; + + // This loop writes the error to the second output, if it exists + if(write_foptr) { + while(oo < noutput_items && ii < ni) { + d_p_2T = d_p_1T; + d_p_1T = d_p_0T; + d_p_0T = d_interp->interpolate(&in[ii], d_mu); + + d_c_2T = d_c_1T; + d_c_1T = d_c_0T; + d_c_0T = slicer_0deg(d_p_0T); + + x = (d_c_0T - d_c_2T) * conj(d_p_1T); + y = (d_p_0T - d_p_2T) * conj(d_c_1T); + u = y - x; + mm_val = u.real(); + out[oo++] = d_p_0T; + + // limit mm_val + mm_val = gr_branchless_clip(mm_val,4.0); + d_omega = d_omega + d_gain_omega * mm_val; + d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); + + d_mu = d_mu + d_omega + d_gain_mu * mm_val; + ii += (int)floor(d_mu); + d_mu -= floor(d_mu); + + // write the error signal to the second output + foptr[oo-1] = mm_val; + + if(ii < 0) // clamp it. This should only happen with bogus input + ii = 0; + } + } + // This loop does not write to the second output (ugly, but faster) + else { + while(oo < noutput_items && ii < ni) { + d_p_2T = d_p_1T; + d_p_1T = d_p_0T; + d_p_0T = d_interp->interpolate(&in[ii], d_mu); + + d_c_2T = d_c_1T; + d_c_1T = d_c_0T; + d_c_0T = slicer_0deg(d_p_0T); + + x = (d_c_0T - d_c_2T) * conj(d_p_1T); + y = (d_p_0T - d_p_2T) * conj(d_c_1T); + u = y - x; + mm_val = u.real(); + out[oo++] = d_p_0T; + + // limit mm_val + mm_val = gr_branchless_clip(mm_val,1.0); + + d_omega = d_omega + d_gain_omega * mm_val; + d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); + + d_mu = d_mu + d_omega + d_gain_mu * mm_val; + ii += (int)floor(d_mu); + d_mu -= floor(d_mu); + + if(d_verbose) { + std::cout << d_omega << "\t" << d_mu << std::endl; + } + + if(ii < 0) // clamp it. This should only happen with bogus input + ii = 0; + } + } + + if(ii > 0) { + if(ii > ninput_items[0]) { + std::cerr << "clock_recovery_mm_cc: ii > ninput_items[0] (" + << ii << " > " << ninput_items[0] << std::endl; + assert(0); + } + consume_each(ii); + } + + return oo; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/clock_recovery_mm_cc_impl.h b/gr-digital/lib/clock_recovery_mm_cc_impl.h new file mode 100644 index 0000000000..fa62bd127f --- /dev/null +++ b/gr-digital/lib/clock_recovery_mm_cc_impl.h @@ -0,0 +1,87 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_CC_IMPL_H +#define INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_CC_IMPL_H + +#include <digital/clock_recovery_mm_cc.h> +#include <filter/mmse_fir_interpolator_cc.h> + +namespace gr { + namespace digital { + + class clock_recovery_mm_cc_impl : public clock_recovery_mm_cc + { + public: + clock_recovery_mm_cc_impl(float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limi); + ~clock_recovery_mm_cc_impl(); + + 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); + + float mu() const { return d_mu;} + float omega() const { return d_omega;} + float gain_mu() const { return d_gain_mu;} + float gain_omega() const { return d_gain_omega;} + + void set_verbose (bool verbose) { d_verbose = verbose; } + void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } + void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } + void set_mu (float mu) { d_mu = mu; } + void set_omega (float omega) { + d_omega = omega; + d_min_omega = omega*(1.0 - d_omega_relative_limit); + d_max_omega = omega*(1.0 + d_omega_relative_limit); + d_omega_mid = 0.5*(d_min_omega+d_max_omega); + } + + private: + float d_mu; // fractional sample position [0.0, 1.0] + float d_omega; // nominal frequency + float d_gain_omega; // gain for adjusting omega + float d_min_omega; // minimum allowed omega + float d_max_omega; // maximum allowed omeg + float d_omega_relative_limit; // used to compute min and max omega + float d_omega_mid; // average omega + float d_gain_mu; // gain for adjusting mu + + gr_complex d_last_sample; + filter::mmse_fir_interpolator_cc *d_interp; + + bool d_verbose; + + gr_complex d_p_2T, d_p_1T, d_p_0T; + gr_complex d_c_2T, d_c_1T, d_c_0T; + + gr_complex slicer_0deg(gr_complex sample); + gr_complex slicer_45deg(gr_complex sample); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_CC_IMPL_H */ diff --git a/gr-digital/lib/clock_recovery_mm_ff_impl.cc b/gr-digital/lib/clock_recovery_mm_ff_impl.cc new file mode 100644 index 0000000000..4ac3e40c5d --- /dev/null +++ b/gr-digital/lib/clock_recovery_mm_ff_impl.cc @@ -0,0 +1,120 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "clock_recovery_mm_ff_impl.h" +#include <gr_io_signature.h> +#include <gr_math.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + clock_recovery_mm_ff::sptr + clock_recovery_mm_ff::make(float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit) + { + return gnuradio::get_initial_sptr + (new clock_recovery_mm_ff_impl(omega, gain_omega, + mu, gain_mu, + omega_relative_limit)); + } + + clock_recovery_mm_ff_impl::clock_recovery_mm_ff_impl(float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limit) + : gr_block("clock_recovery_mm_ff", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(float))), + d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega), + d_omega_relative_limit(omega_relative_limit), + d_last_sample(0), d_interp(new filter::mmse_fir_interpolator_ff()) + { + if(omega < 1) + throw std::out_of_range("clock rate must be > 0"); + if(gain_mu < 0 || gain_omega < 0) + throw std::out_of_range("Gains must be non-negative"); + + set_omega(omega); // also sets min and max omega + set_relative_rate (1.0 / omega); + } + + clock_recovery_mm_ff_impl::~clock_recovery_mm_ff_impl() + { + delete d_interp; + } + + void + clock_recovery_mm_ff_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] = + (int) ceil((noutput_items * d_omega) + d_interp->ntaps()); + } + + static inline float + slice(float x) + { + return x < 0 ? -1.0F : 1.0F; + } + + int + clock_recovery_mm_ff_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 float *in = (const float *)input_items[0]; + float *out = (float *)output_items[0]; + + int ii = 0; // input index + int oo = 0; // output index + int ni = ninput_items[0] - d_interp->ntaps(); // don't use more input than this + float mm_val; + + while(oo < noutput_items && ii < ni ) { + // produce output sample + out[oo] = d_interp->interpolate(&in[ii], d_mu); + mm_val = slice(d_last_sample) * out[oo] - slice(out[oo]) * d_last_sample; + d_last_sample = out[oo]; + + d_omega = d_omega + d_gain_omega * mm_val; + d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); + d_mu = d_mu + d_omega + d_gain_mu * mm_val; + + ii += (int)floor(d_mu); + d_mu = d_mu - floor(d_mu); + oo++; + } + + consume_each(ii); + return oo; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/clock_recovery_mm_ff_impl.h b/gr-digital/lib/clock_recovery_mm_ff_impl.h new file mode 100644 index 0000000000..920a05a496 --- /dev/null +++ b/gr-digital/lib/clock_recovery_mm_ff_impl.h @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_FF_IMPL_H +#define INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_FF_IMPL_H + +#include <digital/clock_recovery_mm_ff.h> +#include <filter/mmse_fir_interpolator_ff.h> + +namespace gr { + namespace digital { + + class clock_recovery_mm_ff_impl : public clock_recovery_mm_ff + { + public: + clock_recovery_mm_ff_impl(float omega, float gain_omega, + float mu, float gain_mu, + float omega_relative_limi); + ~clock_recovery_mm_ff_impl(); + + 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); + + float mu() const { return d_mu;} + float omega() const { return d_omega;} + float gain_mu() const { return d_gain_mu;} + float gain_omega() const { return d_gain_omega;} + + void set_verbose (bool verbose) { d_verbose = verbose; } + void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; } + void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; } + void set_mu (float mu) { d_mu = mu; } + void set_omega (float omega){ + d_omega = omega; + d_min_omega = omega*(1.0 - d_omega_relative_limit); + d_max_omega = omega*(1.0 + d_omega_relative_limit); + d_omega_mid = 0.5*(d_min_omega+d_max_omega); + } + + private: + float d_mu; // fractional sample position [0.0, 1.0] + float d_gain_mu; // gain for adjusting mu + float d_omega; // nominal frequency + float d_gain_omega; // gain for adjusting omega + float d_min_omega; // minimum allowed omega + float d_max_omega; // maximum allowed omeg + float d_omega_relative_limit; // used to compute min and max omega + float d_omega_mid; // average omega + + float d_last_sample; + filter::mmse_fir_interpolator_ff *d_interp; + + bool d_verbose; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CLOCK_RECOVERY_MM_FF_IMPL_H */ diff --git a/gr-digital/lib/cma_equalizer_cc_impl.cc b/gr-digital/lib/cma_equalizer_cc_impl.cc new file mode 100644 index 0000000000..e4e6c56466 --- /dev/null +++ b/gr-digital/lib/cma_equalizer_cc_impl.cc @@ -0,0 +1,131 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cma_equalizer_cc_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + using namespace filter::kernel; + + cma_equalizer_cc::sptr + cma_equalizer_cc::make(int num_taps, float modulus, float mu, int sps) + { + return gnuradio::get_initial_sptr + (new cma_equalizer_cc_impl(num_taps, modulus, mu, sps)); + } + + cma_equalizer_cc_impl::cma_equalizer_cc_impl(int num_taps, float modulus, + float mu, int sps) + : gr_sync_decimator("cma_equalizer_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + sps), + fir_filter_ccc(sps, std::vector<gr_complex>(num_taps, gr_complex(0,0))), + d_new_taps(num_taps, gr_complex(0,0)), + d_updated(false), d_error(gr_complex(0,0)) + { + set_modulus(modulus); + set_gain(mu); + if(num_taps > 0) + d_new_taps[0] = 1.0; + fir_filter_ccc::set_taps(d_new_taps); + + set_history(num_taps); + } + + cma_equalizer_cc_impl::~cma_equalizer_cc_impl() + { + } + + void + cma_equalizer_cc_impl::set_taps(const std::vector<gr_complex> &taps) + { + d_new_taps = taps; + d_updated = true; + } + + std::vector<gr_complex> + cma_equalizer_cc_impl::taps() const + { + return d_taps; + } + + gr_complex + cma_equalizer_cc_impl::error(const gr_complex &out) + { + gr_complex error = out*(norm(out) - d_modulus); + float re = gr_clip(error.real(), 1.0); + float im = gr_clip(error.imag(), 1.0); + return gr_complex(re, im); + } + + void + cma_equalizer_cc_impl::update_tap(gr_complex &tap, const gr_complex &in) + { + // Hn+1 = Hn - mu*conj(Xn)*zn*(|zn|^2 - 1) + tap -= d_mu*conj(in)*d_error; + } + + int + cma_equalizer_cc_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]; + + if(d_updated) { + d_taps = d_new_taps; + set_history(d_taps.size()); + d_updated = false; + return 0; // history requirements may have changed. + } + + int j = 0; + size_t k, l = d_taps.size(); + for(int i = 0; i < noutput_items; i++) { + out[i] = filter(&in[j]); + + // Adjust taps + d_error = error(out[i]); + for(k = 0; k < l; k++) { + // Update tap locally from error. + update_tap(d_taps[k], in[j+k]); + + // Update aligned taps in filter object. + fir_filter_ccc::update_tap(d_taps[k], k); + } + + j += decimation(); + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/cma_equalizer_cc_impl.h b/gr-digital/lib/cma_equalizer_cc_impl.h new file mode 100644 index 0000000000..553501bf46 --- /dev/null +++ b/gr-digital/lib/cma_equalizer_cc_impl.h @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CMA_EQUALIZER_CC_IMPL_H +#define INCLUDED_DIGITAL_CMA_EQUALIZER_CC_IMPL_H + +#include <digital/cma_equalizer_cc.h> +#include <filter/fir_filter.h> +#include <gr_math.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + class cma_equalizer_cc_impl + : public cma_equalizer_cc, filter::kernel::fir_filter_ccc + { + private: + std::vector<gr_complex> d_new_taps; + bool d_updated; + gr_complex d_error; + + float d_modulus; + float d_mu; + + protected: + gr_complex error(const gr_complex &out); + void update_tap(gr_complex &tap, const gr_complex &in); + + public: + cma_equalizer_cc_impl(int num_taps, float modulus, float mu, int sps); + ~cma_equalizer_cc_impl(); + + void set_taps(const std::vector<gr_complex> &taps); + std::vector<gr_complex> taps() const; + + float gain() const + { + return d_mu; + } + + void set_gain(float mu) + { + if(mu < 0.0f || mu > 1.0f) { + throw std::out_of_range("cma_equalizer::set_gain: Gain value must be in [0,1]"); + } + d_mu = mu; + } + + float modulus() const + { + return d_modulus; + } + + void set_modulus(float mod) + { + if(mod < 0) + throw std::out_of_range("cma_equalizer::set_modulus: Modulus value must be >= 0"); + d_modulus = mod; + } + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CMA_EQUALIZER_CC_IMPL_H */ diff --git a/gr-digital/lib/constellation.cc b/gr-digital/lib/constellation.cc new file mode 100644 index 0000000000..d249c493ad --- /dev/null +++ b/gr-digital/lib/constellation.cc @@ -0,0 +1,669 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include <digital/constellation.h> +#include <gr_math.h> +#include <gr_complex.h> +#include <math.h> +#include <iostream> +#include <stdlib.h> +#include <float.h> +#include <stdexcept> + +namespace gr { + namespace digital { + +#define M_TWOPI (2*M_PI) +#define SQRT_TWO 0.707107 + + // Base Constellation Class + constellation::constellation(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality) : + d_constellation(constell), + d_pre_diff_code(pre_diff_code), + d_rotational_symmetry(rotational_symmetry), + d_dimensionality(dimensionality) + { + // Scale constellation points so that average magnitude is 1. + float summed_mag = 0; + unsigned int constsize = d_constellation.size(); + for (unsigned int i=0; i<constsize; i++) { + gr_complex c = d_constellation[i]; + summed_mag += sqrt(c.real()*c.real() + c.imag()*c.imag()); + } + d_scalefactor = constsize/summed_mag; + for (unsigned int i=0; i<constsize; i++) { + d_constellation[i] = d_constellation[i]*d_scalefactor; + } + if(pre_diff_code.size() == 0) + d_apply_pre_diff_code = false; + else if(pre_diff_code.size() != constsize) + throw std::runtime_error("The constellation and pre-diff code must be of the same length."); + else + d_apply_pre_diff_code = true; + calc_arity(); + } + + constellation::constellation() : + d_apply_pre_diff_code(false), + d_rotational_symmetry(0), + d_dimensionality(1) + { + calc_arity(); + } + + constellation::~constellation() + { + } + + //! Returns the constellation points for a symbol value + void + constellation::map_to_points(unsigned int value, gr_complex *points) + { + for(unsigned int i=0; i<d_dimensionality; i++) + points[i] = d_constellation[value*d_dimensionality + i]; + } + + std::vector<gr_complex> + constellation::map_to_points_v(unsigned int value) + { + std::vector<gr_complex> points_v; + points_v.resize(d_dimensionality); + map_to_points(value, &(points_v[0])); + return points_v; + } + + float + constellation::get_distance(unsigned int index, const gr_complex *sample) + { + float dist = 0; + for(unsigned int i=0; i<d_dimensionality; i++) { + dist += norm(sample[i] - d_constellation[index*d_dimensionality + i]); + } + return dist; + } + + unsigned int + constellation::get_closest_point(const gr_complex *sample) + { + unsigned int min_index = 0; + float min_euclid_dist; + float euclid_dist; + + min_euclid_dist = get_distance(0, sample); + min_index = 0; + for(unsigned int j = 1; j < d_arity; j++){ + euclid_dist = get_distance(j, sample); + if(euclid_dist < min_euclid_dist){ + min_euclid_dist = euclid_dist; + min_index = j; + } + } + return min_index; + } + + unsigned int + constellation::decision_maker_pe(const gr_complex *sample, float *phase_error) + { + unsigned int index = decision_maker(sample); + *phase_error = 0; + for(unsigned int d=0; d<d_dimensionality; d++) + *phase_error += -arg(sample[d]*conj(d_constellation[index+d])); + return index; + } + + /* + unsigned int constellation::decision_maker_e(const gr_complex *sample, float *error) + { + unsigned int index = decision_maker(sample); + *error = 0; + for(unsigned int d=0; d<d_dimensionality; d++) + *error += sample[d]*conj(d_constellation[index+d]); + return index; + } + */ + + std::vector<gr_complex> constellation::s_points() + { + if(d_dimensionality != 1) + throw std::runtime_error("s_points only works for dimensionality 1 constellations."); + else + return d_constellation; + } + + std::vector<std::vector<gr_complex> > + constellation::v_points() + { + std::vector<std::vector<gr_complex> > vv_const; + vv_const.resize(d_arity); + for(unsigned int p=0; p<d_arity; p++) { + std::vector<gr_complex> v_const; + v_const.resize(d_dimensionality); + for(unsigned int d=0; d<d_dimensionality; d++) { + v_const[d] = d_constellation[p*d_dimensionality+d]; + } + vv_const[p] = v_const; + } + return vv_const; + } + + void + constellation::calc_metric(const gr_complex *sample, float *metric, + trellis_metric_type_t type) + { + switch(type){ + case TRELLIS_EUCLIDEAN: + calc_euclidean_metric(sample, metric); + break; + case TRELLIS_HARD_SYMBOL: + calc_hard_symbol_metric(sample, metric); + break; + case TRELLIS_HARD_BIT: + throw std::runtime_error("Invalid metric type (not yet implemented)."); + break; + default: + throw std::runtime_error("Invalid metric type."); + } + } + + void + constellation::calc_euclidean_metric(const gr_complex *sample, float *metric) + { + for(unsigned int o=0; o<d_arity; o++) { + metric[o] = get_distance(o, sample); + } + } + + void + constellation::calc_hard_symbol_metric(const gr_complex *sample, float *metric) + { + float minm = FLT_MAX; + unsigned int minmi = 0; + for(unsigned int o=0; o<d_arity; o++) { + float dist = get_distance(o, sample); + if(dist < minm) { + minm = dist; + minmi = o; + } + } + for(unsigned int o=0; o<d_arity; o++) { + metric[o] = (o==minmi?0.0:1.0); + } + } + + void + constellation::calc_arity() + { + if(d_constellation.size() % d_dimensionality != 0) + throw std::runtime_error("Constellation vector size must be a multiple of the dimensionality."); + d_arity = d_constellation.size()/d_dimensionality; + } + + unsigned int + constellation::decision_maker_v(std::vector<gr_complex> sample) + { + assert(sample.size() == d_dimensionality); + return decision_maker(&(sample[0])); + } + + + /********************************************************************/ + + + constellation_calcdist::sptr + constellation_calcdist::make(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality) + { + return constellation_calcdist::sptr(new constellation_calcdist + (constell, pre_diff_code, + rotational_symmetry, dimensionality)); + } + + constellation_calcdist::constellation_calcdist(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality) + : constellation(constell, pre_diff_code, rotational_symmetry, dimensionality) + {} + + // Chooses points base on shortest distance. + // Inefficient. + unsigned int + constellation_calcdist::decision_maker(const gr_complex *sample) + { + return get_closest_point(sample); + } + + + /********************************************************************/ + + + constellation_sector::constellation_sector(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int dimensionality, + unsigned int n_sectors) : + constellation(constell, pre_diff_code, rotational_symmetry, dimensionality), + n_sectors(n_sectors) + { + } + + constellation_sector::~constellation_sector() + { + } + + unsigned int + constellation_sector::decision_maker(const gr_complex *sample) + { + unsigned int sector; + sector = get_sector(sample); + return sector_values[sector]; + } + + void + constellation_sector::find_sector_values() + { + unsigned int i; + sector_values.clear(); + for(i=0; i<n_sectors; i++) { + sector_values.push_back(calc_sector_value(i)); + } + } + + + /********************************************************************/ + + + constellation_rect::sptr + constellation_rect::make(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, + unsigned int imag_sectors, + float width_real_sectors, + float width_imag_sectors) + { + return constellation_rect::sptr(new constellation_rect + (constell, pre_diff_code, + rotational_symmetry, + real_sectors, imag_sectors, + width_real_sectors, + width_imag_sectors)); + } + + constellation_rect::constellation_rect(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, unsigned int imag_sectors, + float width_real_sectors, float width_imag_sectors) : + constellation_sector(constell, pre_diff_code, rotational_symmetry, + 1, real_sectors * imag_sectors), + n_real_sectors(real_sectors), n_imag_sectors(imag_sectors), + d_width_real_sectors(width_real_sectors), d_width_imag_sectors(width_imag_sectors) + { + d_width_real_sectors *= d_scalefactor; + d_width_imag_sectors *= d_scalefactor; + find_sector_values(); + } + + constellation_rect::~constellation_rect() + { + } + + unsigned int + constellation_rect::get_sector(const gr_complex *sample) + { + int real_sector, imag_sector; + unsigned int sector; + + real_sector = int(real(*sample)/d_width_real_sectors + n_real_sectors/2.0); + if(real_sector < 0) + real_sector = 0; + if(real_sector >= (int)n_real_sectors) + real_sector = n_real_sectors-1; + + imag_sector = int(imag(*sample)/d_width_imag_sectors + n_imag_sectors/2.0); + if(imag_sector < 0) + imag_sector = 0; + if(imag_sector >= (int)n_imag_sectors) + imag_sector = n_imag_sectors-1; + + sector = real_sector * n_imag_sectors + imag_sector; + return sector; + } + + unsigned int + constellation_rect::calc_sector_value(unsigned int sector) + { + unsigned int real_sector, imag_sector; + gr_complex sector_center; + unsigned int closest_point; + real_sector = float(sector)/n_imag_sectors; + imag_sector = sector - real_sector * n_imag_sectors; + sector_center = gr_complex((real_sector + 0.5 - n_real_sectors/2.0) * d_width_real_sectors, + (imag_sector + 0.5 - n_imag_sectors/2.0) * d_width_imag_sectors); + closest_point = get_closest_point(§or_center); + return closest_point; + } + + + /********************************************************************/ + + + constellation_expl_rect::sptr + constellation_expl_rect::make(std::vector<gr_complex> constellation, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, + unsigned int imag_sectors, + float width_real_sectors, + float width_imag_sectors, + std::vector<unsigned int> sector_values) + { + return constellation_expl_rect::sptr + (new constellation_expl_rect(constellation, pre_diff_code, + rotational_symmetry, + real_sectors, imag_sectors, + width_real_sectors, width_imag_sectors, + sector_values)); + } + + constellation_expl_rect::constellation_expl_rect(std::vector<gr_complex> constellation, + std::vector<int> pre_diff_code, + unsigned int rotational_symmetry, + unsigned int real_sectors, + unsigned int imag_sectors, + float width_real_sectors, + float width_imag_sectors, + std::vector<unsigned int> sector_values) + : constellation_rect(constellation, pre_diff_code, rotational_symmetry, + real_sectors, imag_sectors, width_real_sectors, width_imag_sectors), + d_sector_values(sector_values) + { + } + + constellation_expl_rect::~constellation_expl_rect() + { + } + + /********************************************************************/ + + + constellation_psk::sptr + constellation_psk::make(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int n_sectors) + { + return constellation_psk::sptr(new constellation_psk + (constell, pre_diff_code, + n_sectors)); + } + + constellation_psk::constellation_psk(std::vector<gr_complex> constell, + std::vector<int> pre_diff_code, + unsigned int n_sectors) : + constellation_sector(constell, pre_diff_code, constell.size(), 1, n_sectors) + { + find_sector_values(); + } + + constellation_psk::~constellation_psk() + { + } + + unsigned int + constellation_psk::get_sector(const gr_complex *sample) + { + float phase = arg(*sample); + float width = M_TWOPI / n_sectors; + int sector = floor(phase/width + 0.5); + if(sector < 0) + sector += n_sectors; + return sector; + } + + unsigned int + constellation_psk::calc_sector_value(unsigned int sector) + { + float phase = sector * M_TWOPI / n_sectors; + gr_complex sector_center = gr_complex(cos(phase), sin(phase)); + unsigned int closest_point = get_closest_point(§or_center); + return closest_point; + } + + + /********************************************************************/ + + + constellation_bpsk::sptr + constellation_bpsk::make() + { + return constellation_bpsk::sptr(new constellation_bpsk()); + } + + constellation_bpsk::constellation_bpsk() + { + d_constellation.resize(2); + d_constellation[0] = gr_complex(-1, 0); + d_constellation[1] = gr_complex(1, 0); + d_rotational_symmetry = 2; + d_dimensionality = 1; + calc_arity(); + } + + constellation_bpsk::~constellation_bpsk() + { + } + + unsigned int + constellation_bpsk::decision_maker(const gr_complex *sample) + { + return (real(*sample) > 0); + } + + + /********************************************************************/ + + + constellation_qpsk::sptr + constellation_qpsk::make() + { + return constellation_qpsk::sptr(new constellation_qpsk()); + } + + constellation_qpsk::constellation_qpsk() + { + d_constellation.resize(4); + // Gray-coded + d_constellation[0] = gr_complex(-SQRT_TWO, -SQRT_TWO); + d_constellation[1] = gr_complex(SQRT_TWO, -SQRT_TWO); + d_constellation[2] = gr_complex(-SQRT_TWO, SQRT_TWO); + d_constellation[3] = gr_complex(SQRT_TWO, SQRT_TWO); + + /* + d_constellation[0] = gr_complex(SQRT_TWO, SQRT_TWO); + d_constellation[1] = gr_complex(-SQRT_TWO, SQRT_TWO); + d_constellation[2] = gr_complex(SQRT_TWO, -SQRT_TWO); + d_constellation[3] = gr_complex(SQRT_TWO, -SQRT_TWO); + */ + + d_pre_diff_code.resize(4); + d_pre_diff_code[0] = 0x0; + d_pre_diff_code[1] = 0x2; + d_pre_diff_code[2] = 0x3; + d_pre_diff_code[3] = 0x1; + + d_rotational_symmetry = 4; + d_dimensionality = 1; + calc_arity(); + } + + constellation_qpsk::~constellation_qpsk() + { + } + + unsigned int + constellation_qpsk::decision_maker(const gr_complex *sample) + { + // Real component determines small bit. + // Imag component determines big bit. + return 2*(imag(*sample)>0) + (real(*sample)>0); + + /* + bool a = real(*sample) > 0; + bool b = imag(*sample) > 0; + if(a) { + if(b) + return 0x0; + else + return 0x1; + } + else { + if(b) + return 0x2; + else + return 0x3; + } + */ + } + + + /********************************************************************/ + + + constellation_dqpsk::sptr + constellation_dqpsk::make() + { + return constellation_dqpsk::sptr(new constellation_dqpsk()); + } + + constellation_dqpsk::constellation_dqpsk() + { + // This constellation is not gray coded, which allows + // us to use differential encodings (through diff_encode and + // diff_decode) on the symbols. + d_constellation.resize(4); + d_constellation[0] = gr_complex(+SQRT_TWO, +SQRT_TWO); + d_constellation[1] = gr_complex(-SQRT_TWO, +SQRT_TWO); + d_constellation[2] = gr_complex(-SQRT_TWO, -SQRT_TWO); + d_constellation[3] = gr_complex(+SQRT_TWO, -SQRT_TWO); + + // Use this mapping to convert to gray code before diff enc. + d_pre_diff_code.resize(4); + d_pre_diff_code[0] = 0x0; + d_pre_diff_code[1] = 0x1; + d_pre_diff_code[2] = 0x3; + d_pre_diff_code[3] = 0x2; + d_apply_pre_diff_code = true; + + d_rotational_symmetry = 4; + d_dimensionality = 1; + calc_arity(); + } + + constellation_dqpsk::~constellation_dqpsk() + { + } + + unsigned int + constellation_dqpsk::decision_maker(const gr_complex *sample) + { + // Slower deicison maker as we can't slice along one axis. + // Maybe there's a better way to do this, still. + + bool a = real(*sample) > 0; + bool b = imag(*sample) > 0; + if(a) { + if(b) + return 0x0; + else + return 0x3; + } + else { + if(b) + return 0x1; + else + return 0x2; + } + } + + + /********************************************************************/ + + + constellation_8psk::sptr + constellation_8psk::make() + { + return constellation_8psk::sptr(new constellation_8psk()); + } + + constellation_8psk::constellation_8psk() + { + float angle = M_PI/8.0; + d_constellation.resize(8); + // Gray-coded + d_constellation[0] = gr_complex(cos( 1*angle), sin( 1*angle)); + d_constellation[1] = gr_complex(cos( 7*angle), sin( 7*angle)); + d_constellation[2] = gr_complex(cos(15*angle), sin(15*angle)); + d_constellation[3] = gr_complex(cos( 9*angle), sin( 9*angle)); + d_constellation[4] = gr_complex(cos( 3*angle), sin( 3*angle)); + d_constellation[5] = gr_complex(cos( 5*angle), sin( 5*angle)); + d_constellation[6] = gr_complex(cos(13*angle), sin(13*angle)); + d_constellation[7] = gr_complex(cos(11*angle), sin(11*angle)); + d_rotational_symmetry = 8; + d_dimensionality = 1; + calc_arity(); + } + + constellation_8psk::~constellation_8psk() + { + } + + unsigned int + constellation_8psk::decision_maker(const gr_complex *sample) + { + unsigned int ret = 0; + + float re = sample->real(); + float im = sample->imag(); + + if(fabsf(re) <= fabsf(im)) + ret = 4; + if(re <= 0) + ret |= 1; + if(im <= 0) + ret |= 2; + + return ret; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/constellation_decoder_cb_impl.cc b/gr-digital/lib/constellation_decoder_cb_impl.cc new file mode 100644 index 0000000000..e764ccc629 --- /dev/null +++ b/gr-digital/lib/constellation_decoder_cb_impl.cc @@ -0,0 +1,84 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "constellation_decoder_cb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + constellation_decoder_cb::sptr + constellation_decoder_cb::make(constellation_sptr constellation) + { + return gnuradio::get_initial_sptr + (new constellation_decoder_cb_impl(constellation)); + } + + constellation_decoder_cb_impl:: + constellation_decoder_cb_impl(constellation_sptr constellation) + : gr_block("constellation_decoder_cb", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_constellation(constellation), + d_dim(constellation->dimensionality()) + { + set_relative_rate(1.0 / ((double)d_dim)); + } + + constellation_decoder_cb_impl::~constellation_decoder_cb_impl() + { + } + + void + constellation_decoder_cb_impl::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned int input_required = noutput_items * d_dim; + + unsigned ninputs = ninput_items_required.size(); + for(unsigned int i = 0; i < ninputs; i++) + ninput_items_required[i] = input_required; + } + + int + constellation_decoder_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) + { + gr_complex const *in = (const gr_complex*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + for(int i = 0; i < noutput_items; i++) { + out[i] = d_constellation->decision_maker(&(in[i*d_dim])); + } + + consume_each(noutput_items * d_dim); + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/constellation_decoder_cb_impl.h b/gr-digital/lib/constellation_decoder_cb_impl.h new file mode 100644 index 0000000000..5972760507 --- /dev/null +++ b/gr-digital/lib/constellation_decoder_cb_impl.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_IMPL_H +#define INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_IMPL_H + +#include <digital/constellation_decoder_cb.h> + +namespace gr { + namespace digital { + + class constellation_decoder_cb_impl : public constellation_decoder_cb + { + private: + constellation_sptr d_constellation; + unsigned int d_dim; + + public: + constellation_decoder_cb_impl(constellation_sptr constellation); + ~constellation_decoder_cb_impl(); + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CONSTELLATION_DECODER_CB_IMPL_H */ diff --git a/gr-digital/lib/constellation_receiver_cb_impl.cc b/gr-digital/lib/constellation_receiver_cb_impl.cc new file mode 100644 index 0000000000..c3203e9079 --- /dev/null +++ b/gr-digital/lib/constellation_receiver_cb_impl.cc @@ -0,0 +1,133 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "constellation_receiver_cb_impl.h" +#include <gr_io_signature.h> +#include <gr_prefs.h> +#include <gr_math.h> +#include <gr_expj.h> +#include <stdexcept> + +namespace gr { + namespace digital { + +#define M_TWOPI (2*M_PI) +#define VERBOSE_MM 0 // Used for debugging symbol timing loop +#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking + + constellation_receiver_cb::sptr + constellation_receiver_cb::make(constellation_sptr constell, + float loop_bw, float fmin, float fmax) + { + return gnuradio::get_initial_sptr + (new constellation_receiver_cb_impl(constell, loop_bw, + fmin, fmax)); + } + + static int ios[] = {sizeof(char), sizeof(float), sizeof(float), sizeof(float), sizeof(gr_complex)}; + static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); + constellation_receiver_cb_impl::constellation_receiver_cb_impl(constellation_sptr constellation, + float loop_bw, float fmin, float fmax) + : gr_block("constellation_receiver_cb", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signaturev(1, 5, iosig)), + gri_control_loop(loop_bw, fmax, fmin), + d_constellation(constellation), + d_current_const_point(0) + { + if(d_constellation->dimensionality() != 1) + throw std::runtime_error("This receiver only works with constellations of dimension 1."); + } + + constellation_receiver_cb_impl::~constellation_receiver_cb_impl() + { + } + + void + constellation_receiver_cb_impl::phase_error_tracking(float phase_error) + { + advance_loop(phase_error); + phase_wrap(); + frequency_limit(); + +#if VERBOSE_COSTAS + printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n", + phase_error, d_phase, d_freq, sample.real(), sample.imag(), + d_constellation->points()[d_current_const_point].real(), + d_constellation->points()[d_current_const_point].imag()); +#endif + } + + int + constellation_receiver_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]; + + int i=0; + + float phase_error; + unsigned int sym_value; + gr_complex sample, nco; + + float *out_err = 0, *out_phase = 0, *out_freq = 0; + gr_complex *out_symbol; + if(output_items.size() == 5) { + out_err = (float*)output_items[1]; + out_phase = (float*)output_items[2]; + out_freq = (float*)output_items[3]; + out_symbol = (gr_complex*)output_items[4]; + } + + while((i < noutput_items) && (i < ninput_items[0])) { + sample = in[i]; + nco = gr_expj(d_phase); // get the NCO value for derotating the current sample + sample = nco*sample; // get the downconverted symbol + + sym_value = d_constellation->decision_maker_pe(&sample, &phase_error); + phase_error_tracking(phase_error); // corrects phase and frequency offsets + + out[i] = sym_value; + + if(output_items.size() == 5) { + out_err[i] = phase_error; + out_phase[i] = d_phase; + out_freq[i] = d_freq; + out_symbol[i] = sample; + } + i++; + } + + consume_each(i); + return i; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/constellation_receiver_cb_impl.h b/gr-digital/lib/constellation_receiver_cb_impl.h new file mode 100644 index 0000000000..50946840ae --- /dev/null +++ b/gr-digital/lib/constellation_receiver_cb_impl.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_IMPL_H +#define INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_IMPL_H + +#include <digital/constellation_receiver_cb.h> +#include <gruel/attributes.h> +#include <gr_complex.h> +#include <gri_control_loop.h> + +namespace gr { + namespace digital { + + class constellation_receiver_cb_impl + : public constellation_receiver_cb, gri_control_loop + { + public: + constellation_receiver_cb_impl(constellation_sptr constell, + float loop_bw, float fmin, float fmax); + + ~constellation_receiver_cb_impl(); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + protected: + void phase_error_tracking(float phase_error); + + private: + unsigned int d_M; + + constellation_sptr d_constellation; + unsigned int d_current_const_point; + + //! delay line length. + static const unsigned int DLLEN = 8; + + //! delay line plus some length for overflow protection + __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN]; + + //! index to delay line + unsigned int d_dl_idx; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CONSTELLATION_RECEIVER_CB_IMPL_H */ diff --git a/gr-digital/lib/correlate_access_code_bb_impl.cc b/gr-digital/lib/correlate_access_code_bb_impl.cc new file mode 100644 index 0000000000..0ada203c65 --- /dev/null +++ b/gr-digital/lib/correlate_access_code_bb_impl.cc @@ -0,0 +1,133 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "correlate_access_code_bb_impl.h" +#include <gr_io_signature.h> +#include <blocks/count_bits.h> +#include <stdexcept> +#include <cstdio> + +namespace gr { + namespace digital { + +#define VERBOSE 0 + + correlate_access_code_bb::sptr + correlate_access_code_bb::make(const std::string &access_code, int threshold) + { + return gnuradio::get_initial_sptr + (new correlate_access_code_bb_impl(access_code, threshold)); + } + + correlate_access_code_bb_impl::correlate_access_code_bb_impl( + const std::string &access_code, int threshold) + : gr_sync_block("correlate_access_code_bb", + gr_make_io_signature(1, 1, sizeof(char)), + gr_make_io_signature(1, 1, sizeof(char))), + d_data_reg(0), d_flag_reg(0), d_flag_bit(0), d_mask(0), + d_threshold(threshold) + { + if(!set_access_code(access_code)) { + throw std::out_of_range ("access_code is > 64 bits"); + } + } + + correlate_access_code_bb_impl::~correlate_access_code_bb_impl() + { + } + + bool + correlate_access_code_bb_impl::set_access_code( + const std::string &access_code) + { + unsigned len = access_code.length(); // # of bytes in string + if(len > 64) + return false; + + // set len top bits to 1. + d_mask = ((~0ULL) >> (64 - len)) << (64 - len); + + d_flag_bit = 1LL << (64 - len); // Where we or-in new flag values. + // new data always goes in 0x0000000000000001 + d_access_code = 0; + for(unsigned i=0; i < 64; i++){ + d_access_code <<= 1; + if(i < len) + d_access_code |= access_code[i] & 1; // look at LSB only + } + + return true; + } + + int + correlate_access_code_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + for(int i = 0; i < noutput_items; i++) { + // compute output value + unsigned int t = 0; + + t |= ((d_data_reg >> 63) & 0x1) << 0; + t |= ((d_flag_reg >> 63) & 0x1) << 1; // flag bit + out[i] = t; + + // compute hamming distance between desired access code and current data + unsigned long long wrong_bits = 0; + unsigned int nwrong = d_threshold+1; + int new_flag = 0; + + wrong_bits = (d_data_reg ^ d_access_code) & d_mask; + nwrong = gr::blocks::count_bits64(wrong_bits); + + // test for access code with up to threshold errors + new_flag = (nwrong <= d_threshold); + +#if VERBOSE + if(new_flag) { + fprintf(stderr, "access code found: %llx\n", d_access_code); + } + else { + fprintf(stderr, "%llx ==> %llx\n", d_access_code, d_data_reg); + } +#endif + + // shift in new data and new flag + d_data_reg = (d_data_reg << 1) | (in[i] & 0x1); + d_flag_reg = (d_flag_reg << 1); + if(new_flag) { + d_flag_reg |= d_flag_bit; + } + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/correlate_access_code_bb_impl.h b/gr-digital/lib/correlate_access_code_bb_impl.h new file mode 100644 index 0000000000..ad44b36400 --- /dev/null +++ b/gr-digital/lib/correlate_access_code_bb_impl.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_BB_IMPL_H +#define INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_BB_IMPL_H + +#include <digital/correlate_access_code_bb.h> + +namespace gr { + namespace digital { + + class correlate_access_code_bb_impl : + public correlate_access_code_bb + { + private: + unsigned long long d_access_code; // access code to locate start of packet + // access code is left justified in the word + unsigned long long d_data_reg; // used to look for access_code + unsigned long long d_flag_reg; // keep track of decisions + unsigned long long d_flag_bit; // mask containing 1 bit which is location of new flag + unsigned long long d_mask; // masks access_code bits (top N bits are set where + // N is the number of bits in the access code) + unsigned int d_threshold; // how many bits may be wrong in sync vector + + public: + correlate_access_code_bb_impl(const std::string &access_code, + int threshold); + ~correlate_access_code_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + bool set_access_code(const std::string &access_code); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_BB_IMPL_H */ diff --git a/gr-digital/lib/correlate_access_code_tag_bb_impl.cc b/gr-digital/lib/correlate_access_code_tag_bb_impl.cc new file mode 100644 index 0000000000..8ac601bb9d --- /dev/null +++ b/gr-digital/lib/correlate_access_code_tag_bb_impl.cc @@ -0,0 +1,136 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "correlate_access_code_tag_bb_impl.h" +#include <gr_io_signature.h> +#include <stdexcept> +#include <blocks/count_bits.h> +#include <cstdio> +#include <iostream> + +namespace gr { + namespace digital { + +#define VERBOSE 0 + + correlate_access_code_tag_bb::sptr + correlate_access_code_tag_bb::make(const std::string &access_code, + int threshold, + const std::string &tag_name) + { + return gnuradio::get_initial_sptr + (new correlate_access_code_tag_bb_impl(access_code, + threshold, tag_name)); + } + + + correlate_access_code_tag_bb_impl::correlate_access_code_tag_bb_impl( + const std::string &access_code, int threshold, const std::string &tag_name) + : gr_sync_block("correlate_access_code_tag_bb", + gr_make_io_signature(1, 1, sizeof(char)), + gr_make_io_signature(1, 1, sizeof(char))), + d_data_reg(0), d_mask(0), + d_threshold(threshold), d_len(0) + { + if(!set_access_code(access_code)) { + throw std::out_of_range ("access_code is > 64 bits"); + } + + std::stringstream str; + str << name() << unique_id(); + d_me = pmt::string_to_symbol(str.str()); + d_key = pmt::string_to_symbol(tag_name); + } + + correlate_access_code_tag_bb_impl::~correlate_access_code_tag_bb_impl() + { + } + + bool + correlate_access_code_tag_bb_impl::set_access_code( + const std::string &access_code) + { + d_len = access_code.length(); // # of bytes in string + if(d_len > 64) + return false; + + // set len top bits to 1. + d_mask = ((~0ULL) >> (64 - d_len)) << (64 - d_len); + + d_access_code = 0; + for(unsigned i=0; i < 64; i++){ + d_access_code <<= 1; + if(i < d_len) + d_access_code |= access_code[i] & 1; // look at LSB only + } + + return true; + } + + int + correlate_access_code_tag_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + uint64_t abs_out_sample_cnt = nitems_written(0); + + for(int i = 0; i < noutput_items; i++) { + out[i] = in[i]; + + // compute hamming distance between desired access code and current data + unsigned long long wrong_bits = 0; + unsigned int nwrong = d_threshold+1; + int new_flag = 0; + + wrong_bits = (d_data_reg ^ d_access_code) & d_mask; + nwrong = gr::blocks::count_bits64(wrong_bits); + + // test for access code with up to threshold errors + new_flag = (nwrong <= d_threshold); + + // shift in new data and new flag + d_data_reg = (d_data_reg << 1) | (in[i] & 0x1); + if(new_flag) { + if(VERBOSE) + std::cerr << "writing tag at sample " << abs_out_sample_cnt + i << std::endl; + add_item_tag(0, //stream ID + abs_out_sample_cnt + i - 64 + d_len, //sample + d_key, //frame info + pmt::pmt_t(), //data (unused) + d_me //block src id + ); + } + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/correlate_access_code_tag_bb_impl.h b/gr-digital/lib/correlate_access_code_tag_bb_impl.h new file mode 100644 index 0000000000..17a016fc9c --- /dev/null +++ b/gr-digital/lib/correlate_access_code_tag_bb_impl.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_TAG_BB_IMPL_H +#define INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_TAG_BB_IMPL_H + +#include <digital/correlate_access_code_tag_bb.h> + +namespace gr { + namespace digital { + + class correlate_access_code_tag_bb_impl : + public correlate_access_code_tag_bb + { + private: + unsigned long long d_access_code; // access code to locate start of packet + // access code is left justified in the word + unsigned long long d_data_reg; // used to look for access_code + unsigned long long d_mask; // masks access_code bits (top N bits are set where + // N is the number of bits in the access code) + unsigned int d_threshold; // how many bits may be wrong in sync vector + unsigned int d_len; // the length of the access code + + pmt::pmt_t d_key, d_me; //d_key is the tag name, d_me is the block name + unique ID + + public: + correlate_access_code_tag_bb_impl(const std::string &access_code, + int threshold, + const std::string &tag_name); + ~correlate_access_code_tag_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + bool set_access_code(const std::string &access_code); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CORRELATE_ACCESS_CODE_TAG_BB_IMPL_H */ diff --git a/gr-digital/lib/costas_loop_cc_impl.cc b/gr-digital/lib/costas_loop_cc_impl.cc new file mode 100644 index 0000000000..5afabf4294 --- /dev/null +++ b/gr-digital/lib/costas_loop_cc_impl.cc @@ -0,0 +1,161 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "costas_loop_cc_impl.h" +#include <gr_io_signature.h> +#include <gr_expj.h> +#include <gr_sincos.h> +#include <gr_math.h> + +namespace gr { + namespace digital { + + costas_loop_cc::sptr + costas_loop_cc::make(float loop_bw, int order) + { + return gnuradio::get_initial_sptr + (new costas_loop_cc_impl(loop_bw, order)); + } + + costas_loop_cc_impl::costas_loop_cc_impl(float loop_bw, int order) + : gr_sync_block("costas_loop_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature2(1, 2, sizeof(gr_complex), sizeof(float))), + gri_control_loop(loop_bw, 1.0, -1.0), + d_order(order), 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; + break; + + case 4: + d_phase_detector = &costas_loop_cc_impl::phase_detector_4; + break; + + case 8: + d_phase_detector = &costas_loop_cc_impl::phase_detector_8; + break; + + default: + throw std::invalid_argument("order must be 2, 4, or 8"); + break; + } + } + + costas_loop_cc_impl::~costas_loop_cc_impl() + { + } + + float + costas_loop_cc_impl::phase_detector_8(gr_complex sample) const + { + /* This technique splits the 8PSK constellation into 2 squashed + QPSK constellations, one when I is larger than Q and one + where Q is larger than I. The error is then calculated + proportionally to these squashed constellations by the const + K = sqrt(2)-1. + + The signal magnitude must be > 1 or K will incorrectly bias + the error value. + + Ref: Z. Huang, Z. Yi, M. Zhang, K. Wang, "8PSK demodulation for + new generation DVB-S2", IEEE Proc. Int. Conf. Communications, + Circuits and Systems, Vol. 2, pp. 1447 - 1450, 2004. + */ + + float K = (sqrt(2.0) - 1); + if(fabsf(sample.real()) >= fabsf(sample.imag())) { + return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() - + (sample.imag()>0 ? 1.0 : -1.0) * sample.real() * K); + } + else { + return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() * K - + (sample.imag()>0 ? 1.0 : -1.0) * sample.real()); + } + } + + float + costas_loop_cc_impl::phase_detector_4(gr_complex sample) const + { + return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() - + (sample.imag()>0 ? 1.0 : -1.0) * sample.real()); + } + + float + costas_loop_cc_impl::phase_detector_2(gr_complex sample) const + { + return (sample.real()*sample.imag()); + } + + int + costas_loop_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *iptr = (gr_complex *) input_items[0]; + gr_complex *optr = (gr_complex *) output_items[0]; + float *foptr = (float *) output_items[1]; + + bool write_foptr = output_items.size() >= 2; + + float error; + gr_complex nco_out; + + if(write_foptr) { + for(int i = 0; i < noutput_items; i++) { + nco_out = gr_expj(-d_phase); + optr[i] = iptr[i] * nco_out; + + error = (*this.*d_phase_detector)(optr[i]); + error = gr_branchless_clip(error, 1.0); + + advance_loop(error); + phase_wrap(); + frequency_limit(); + + foptr[i] = d_freq; + } + } + else { + for(int i = 0; i < noutput_items; i++) { + nco_out = gr_expj(-d_phase); + optr[i] = iptr[i] * nco_out; + + error = (*this.*d_phase_detector)(optr[i]); + error = gr_branchless_clip(error, 1.0); + + advance_loop(error); + phase_wrap(); + frequency_limit(); + } + } + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/costas_loop_cc_impl.h b/gr-digital/lib/costas_loop_cc_impl.h new file mode 100644 index 0000000000..9310368b4d --- /dev/null +++ b/gr-digital/lib/costas_loop_cc_impl.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2011,2012 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. + */ + + +#ifndef INCLUDED_DIGITAL_COSTAS_LOOP_CC_IMPL_H +#define INCLUDED_DIGITAL_COSTAS_LOOP_CC_IMPL_H + +#include <digital/costas_loop_cc.h> +#include <gri_control_loop.h> + +namespace gr { + namespace digital { + + class costas_loop_cc_impl : public costas_loop_cc, gri_control_loop + { + private: + int d_order; + + /*! \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 + * \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 + * \param sample a complex sample + * \return the phase error + */ + float phase_detector_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(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_COSTAS_LOOP_CC_IMPL_H */ diff --git a/gr-digital/lib/cpmmod_bc_impl.cc b/gr-digital/lib/cpmmod_bc_impl.cc new file mode 100644 index 0000000000..763a4cc1e2 --- /dev/null +++ b/gr-digital/lib/cpmmod_bc_impl.cc @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 Free Software Foundation, Inc. + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cpmmod_bc_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + cpmmod_bc::sptr + cpmmod_bc::make(analog::cpm::cpm_type type, float h, + int samples_per_sym, + int L, double beta) + { + return gnuradio::get_initial_sptr + (new cpmmod_bc_impl("cpmmod_bc", + (analog::cpm::cpm_type)type, + h, samples_per_sym, + L, beta)); + } + + cpmmod_bc::sptr + cpmmod_bc::make_gmskmod_bc(int samples_per_sym, + int L, double beta) + { + return gnuradio::get_initial_sptr + (new cpmmod_bc_impl("gmskmod_bc", + analog::cpm::GAUSSIAN, 0.5, + samples_per_sym, + L, beta)); + } + + cpmmod_bc_impl::cpmmod_bc_impl(const std::string &name, + analog::cpm::cpm_type type, float h, + int samples_per_sym, + int L, double beta) + : gr_hier_block2(name, + gr_make_io_signature(1, 1, sizeof(char)), + gr_make_io_signature2(1, 1, sizeof(gr_complex), sizeof(float))), + d_type(type), d_index(h), d_sps(samples_per_sym), d_length(L), d_beta(beta), + d_taps(analog::cpm::phase_response(type, samples_per_sym, L, beta)), + d_char_to_float(blocks::char_to_float::make()), + d_pulse_shaper(filter::interp_fir_filter_fff::make(samples_per_sym, d_taps)), + d_fm(analog::frequency_modulator_fc::make(M_PI * h)) + { + switch(type) { + case analog::cpm::LRC: + case analog::cpm::LSRC: + case analog::cpm::LREC: + case analog::cpm::TFM: + case analog::cpm::GAUSSIAN: + break; + + default: + throw std::invalid_argument("cpmmod_bc_impl: invalid CPM type"); + } + + connect(self(), 0, d_char_to_float, 0); + connect(d_char_to_float, 0, d_pulse_shaper, 0); + connect(d_pulse_shaper, 0, d_fm, 0); + connect(d_fm, 0, self(), 0); + } + + cpmmod_bc_impl::~cpmmod_bc_impl() + { + } + + std::vector<float> + cpmmod_bc_impl::taps() const + { + return d_taps; + } + + int + cpmmod_bc_impl::type() const + { + return d_type; + } + + float + cpmmod_bc_impl::index() const + { + return d_index; + } + + int + cpmmod_bc_impl::samples_per_sym() const + { + return d_sps; + } + + int + cpmmod_bc_impl::length() const + { + return d_length; + } + + double cpmmod_bc_impl::beta() const + { + return d_beta; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/cpmmod_bc_impl.h b/gr-digital/lib/cpmmod_bc_impl.h new file mode 100644 index 0000000000..9cfec4959e --- /dev/null +++ b/gr-digital/lib/cpmmod_bc_impl.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_CPMMOD_BC_IMPL_H +#define INCLUDED_DIGITAL_CPMMOD_BC_IMPL_H + +#include <digital/cpmmod_bc.h> +#include <blocks/char_to_float.h> +#include <analog/frequency_modulator_fc.h> +#include <filter/interp_fir_filter_fff.h> + +namespace gr { + namespace digital { + + class cpmmod_bc_impl : public cpmmod_bc + { + private: + int d_type; + float d_index; + int d_sps; + int d_length; + double d_beta; + + protected: + std::vector<float> d_taps; + gr::blocks::char_to_float::sptr d_char_to_float; + gr::filter::interp_fir_filter_fff::sptr d_pulse_shaper; + analog::frequency_modulator_fc::sptr d_fm; + + public: + cpmmod_bc_impl(const std::string &name, + analog::cpm::cpm_type type, float h, + int samples_per_sym, + int L, double beta=0.3); + ~cpmmod_bc_impl(); + + std::vector<float> taps() const; + int type() const; + float index() const; + int samples_per_sym() const; + int length() const; + double beta() const; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_CPMMOD_BC_IMPL_H */ + diff --git a/gr-digital/lib/crc32.cc b/gr-digital/lib/crc32.cc new file mode 100644 index 0000000000..b203727114 --- /dev/null +++ b/gr-digital/lib/crc32.cc @@ -0,0 +1,136 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2011,2012 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. + */ + +/* + * See also ISO 3309 [ISO-3309] or ITU-T V.42 [ITU-V42] for a formal specification. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <digital/crc32.h> + +namespace gr { + namespace digital { + + // Automatically generated CRC function + // polynomial: 0x104C11DB7 + unsigned int + update_crc32(unsigned int crc, const unsigned char *data, size_t len) + { + static const unsigned int table[256] = { + 0x00000000U,0x04C11DB7U,0x09823B6EU,0x0D4326D9U, + 0x130476DCU,0x17C56B6BU,0x1A864DB2U,0x1E475005U, + 0x2608EDB8U,0x22C9F00FU,0x2F8AD6D6U,0x2B4BCB61U, + 0x350C9B64U,0x31CD86D3U,0x3C8EA00AU,0x384FBDBDU, + 0x4C11DB70U,0x48D0C6C7U,0x4593E01EU,0x4152FDA9U, + 0x5F15ADACU,0x5BD4B01BU,0x569796C2U,0x52568B75U, + 0x6A1936C8U,0x6ED82B7FU,0x639B0DA6U,0x675A1011U, + 0x791D4014U,0x7DDC5DA3U,0x709F7B7AU,0x745E66CDU, + 0x9823B6E0U,0x9CE2AB57U,0x91A18D8EU,0x95609039U, + 0x8B27C03CU,0x8FE6DD8BU,0x82A5FB52U,0x8664E6E5U, + 0xBE2B5B58U,0xBAEA46EFU,0xB7A96036U,0xB3687D81U, + 0xAD2F2D84U,0xA9EE3033U,0xA4AD16EAU,0xA06C0B5DU, + 0xD4326D90U,0xD0F37027U,0xDDB056FEU,0xD9714B49U, + 0xC7361B4CU,0xC3F706FBU,0xCEB42022U,0xCA753D95U, + 0xF23A8028U,0xF6FB9D9FU,0xFBB8BB46U,0xFF79A6F1U, + 0xE13EF6F4U,0xE5FFEB43U,0xE8BCCD9AU,0xEC7DD02DU, + 0x34867077U,0x30476DC0U,0x3D044B19U,0x39C556AEU, + 0x278206ABU,0x23431B1CU,0x2E003DC5U,0x2AC12072U, + 0x128E9DCFU,0x164F8078U,0x1B0CA6A1U,0x1FCDBB16U, + 0x018AEB13U,0x054BF6A4U,0x0808D07DU,0x0CC9CDCAU, + 0x7897AB07U,0x7C56B6B0U,0x71159069U,0x75D48DDEU, + 0x6B93DDDBU,0x6F52C06CU,0x6211E6B5U,0x66D0FB02U, + 0x5E9F46BFU,0x5A5E5B08U,0x571D7DD1U,0x53DC6066U, + 0x4D9B3063U,0x495A2DD4U,0x44190B0DU,0x40D816BAU, + 0xACA5C697U,0xA864DB20U,0xA527FDF9U,0xA1E6E04EU, + 0xBFA1B04BU,0xBB60ADFCU,0xB6238B25U,0xB2E29692U, + 0x8AAD2B2FU,0x8E6C3698U,0x832F1041U,0x87EE0DF6U, + 0x99A95DF3U,0x9D684044U,0x902B669DU,0x94EA7B2AU, + 0xE0B41DE7U,0xE4750050U,0xE9362689U,0xEDF73B3EU, + 0xF3B06B3BU,0xF771768CU,0xFA325055U,0xFEF34DE2U, + 0xC6BCF05FU,0xC27DEDE8U,0xCF3ECB31U,0xCBFFD686U, + 0xD5B88683U,0xD1799B34U,0xDC3ABDEDU,0xD8FBA05AU, + 0x690CE0EEU,0x6DCDFD59U,0x608EDB80U,0x644FC637U, + 0x7A089632U,0x7EC98B85U,0x738AAD5CU,0x774BB0EBU, + 0x4F040D56U,0x4BC510E1U,0x46863638U,0x42472B8FU, + 0x5C007B8AU,0x58C1663DU,0x558240E4U,0x51435D53U, + 0x251D3B9EU,0x21DC2629U,0x2C9F00F0U,0x285E1D47U, + 0x36194D42U,0x32D850F5U,0x3F9B762CU,0x3B5A6B9BU, + 0x0315D626U,0x07D4CB91U,0x0A97ED48U,0x0E56F0FFU, + 0x1011A0FAU,0x14D0BD4DU,0x19939B94U,0x1D528623U, + 0xF12F560EU,0xF5EE4BB9U,0xF8AD6D60U,0xFC6C70D7U, + 0xE22B20D2U,0xE6EA3D65U,0xEBA91BBCU,0xEF68060BU, + 0xD727BBB6U,0xD3E6A601U,0xDEA580D8U,0xDA649D6FU, + 0xC423CD6AU,0xC0E2D0DDU,0xCDA1F604U,0xC960EBB3U, + 0xBD3E8D7EU,0xB9FF90C9U,0xB4BCB610U,0xB07DABA7U, + 0xAE3AFBA2U,0xAAFBE615U,0xA7B8C0CCU,0xA379DD7BU, + 0x9B3660C6U,0x9FF77D71U,0x92B45BA8U,0x9675461FU, + 0x8832161AU,0x8CF30BADU,0x81B02D74U,0x857130C3U, + 0x5D8A9099U,0x594B8D2EU,0x5408ABF7U,0x50C9B640U, + 0x4E8EE645U,0x4A4FFBF2U,0x470CDD2BU,0x43CDC09CU, + 0x7B827D21U,0x7F436096U,0x7200464FU,0x76C15BF8U, + 0x68860BFDU,0x6C47164AU,0x61043093U,0x65C52D24U, + 0x119B4BE9U,0x155A565EU,0x18197087U,0x1CD86D30U, + 0x029F3D35U,0x065E2082U,0x0B1D065BU,0x0FDC1BECU, + 0x3793A651U,0x3352BBE6U,0x3E119D3FU,0x3AD08088U, + 0x2497D08DU,0x2056CD3AU,0x2D15EBE3U,0x29D4F654U, + 0xC5A92679U,0xC1683BCEU,0xCC2B1D17U,0xC8EA00A0U, + 0xD6AD50A5U,0xD26C4D12U,0xDF2F6BCBU,0xDBEE767CU, + 0xE3A1CBC1U,0xE760D676U,0xEA23F0AFU,0xEEE2ED18U, + 0xF0A5BD1DU,0xF464A0AAU,0xF9278673U,0xFDE69BC4U, + 0x89B8FD09U,0x8D79E0BEU,0x803AC667U,0x84FBDBD0U, + 0x9ABC8BD5U,0x9E7D9662U,0x933EB0BBU,0x97FFAD0CU, + 0xAFB010B1U,0xAB710D06U,0xA6322BDFU,0xA2F33668U, + 0xBCB4666DU,0xB8757BDAU,0xB5365D03U,0xB1F740B4U, + }; + + while(len > 0) + { + crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8); + data++; + len--; + } + return crc; + } + + unsigned int + update_crc32(unsigned int crc, const std::string s) + { + return update_crc32(crc, (const unsigned char *)s.data(), s.size()); + } + + unsigned int + crc32(const unsigned char *buf, size_t len) + { + return update_crc32(0xffffffff, buf, len) ^ 0xffffffff; + } + + unsigned int + crc32(const std::string s) + { + return crc32((const unsigned char *) s.data(), s.size()); + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/descrambler_bb_impl.cc b/gr-digital/lib/descrambler_bb_impl.cc new file mode 100644 index 0000000000..8124df37ef --- /dev/null +++ b/gr-digital/lib/descrambler_bb_impl.cc @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "descrambler_bb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + descrambler_bb::sptr + descrambler_bb::make(int mask, int seed, int len) + { + return gnuradio::get_initial_sptr + (new descrambler_bb_impl(mask, seed, len)); + } + + descrambler_bb_impl::descrambler_bb_impl(int mask, int seed, int len) + : gr_sync_block("descrambler_bb", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_lfsr(mask, seed, len) + { + } + + descrambler_bb_impl::~descrambler_bb_impl() + { + } + + int + descrambler_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + for(int i = 0; i < noutput_items; i++) { + out[i] = d_lfsr.next_bit_descramble(in[i]); + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/digital_cma_equalizer_cc.cc b/gr-digital/lib/descrambler_bb_impl.h index c6c46c2d8c..4f07b7c329 100644 --- a/gr-digital/lib/digital_cma_equalizer_cc.cc +++ b/gr-digital/lib/descrambler_bb_impl.h @@ -1,46 +1,49 @@ /* -*- c++ -*- */ /* - * Copyright 2011 Free Software Foundation, Inc. - * + * Copyright 2008,2012 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. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_cma_equalizer_cc.h> -#include <cstdio> - -digital_cma_equalizer_cc_sptr -digital_make_cma_equalizer_cc(int num_taps, float modulus, float mu, int sps) -{ - return gnuradio::get_initial_sptr(new digital_cma_equalizer_cc(num_taps, modulus, - mu, sps)); -} - -digital_cma_equalizer_cc::digital_cma_equalizer_cc(int num_taps, float modulus, - float mu, int sps) - : gr_adaptive_fir_ccc("cma_equalizer_cc", sps, - std::vector<gr_complex>(num_taps, gr_complex(0,0))) -{ - set_modulus(modulus); - set_gain(mu); - if (num_taps > 0) - d_taps[0] = 1.0; -} +#ifndef INCLUDED_GR_DESCRAMBLER_BB_IMPL_H +#define INCLUDED_GR_DESCRAMBLER_BB_IMPL_H + +#include <digital/descrambler_bb.h> +#include <digital/lfsr.h> + +namespace gr { + namespace digital { + + class descrambler_bb_impl : public descrambler_bb + { + private: + digital::lfsr d_lfsr; + + public: + descrambler_bb_impl(int mask, int seed, int len); + ~descrambler_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_DESCRAMBLER_BB_IMPL_H */ diff --git a/gr-digital/lib/diff_decoder_bb_impl.cc b/gr-digital/lib/diff_decoder_bb_impl.cc new file mode 100644 index 0000000000..74c247a830 --- /dev/null +++ b/gr-digital/lib/diff_decoder_bb_impl.cc @@ -0,0 +1,71 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "diff_decoder_bb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + diff_decoder_bb::sptr + diff_decoder_bb::make(unsigned int modulus) + { + return gnuradio::get_initial_sptr + (new diff_decoder_bb_impl(modulus)); + } + + diff_decoder_bb_impl::diff_decoder_bb_impl(unsigned int modulus) + : gr_sync_block("diff_decoder_bb", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_modulus(modulus) + { + set_history(2); // need to look at two inputs + } + + diff_decoder_bb_impl::~diff_decoder_bb_impl() + { + } + + int + diff_decoder_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + in += 1; // ensure that in[-1] is valid + + unsigned modulus = d_modulus; + + for(int i = 0; i < noutput_items; i++) { + out[i] = (in[i] - in[i-1]) % modulus; + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/digital_kurtotic_equalizer_cc.cc b/gr-digital/lib/diff_decoder_bb_impl.h index c95b560216..56a15ba128 100644 --- a/gr-digital/lib/digital_kurtotic_equalizer_cc.cc +++ b/gr-digital/lib/diff_decoder_bb_impl.h @@ -1,51 +1,49 @@ /* -*- c++ -*- */ /* - * Copyright 2011 Free Software Foundation, Inc. - * + * Copyright 2006,2012 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. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#ifndef INCLUDED_GR_DIFF_DECODER_BB_IMPL_H +#define INCLUDED_GR_DIFF_DECODER_BB_IMPL_H -#include <digital_kurtotic_equalizer_cc.h> +#include <digital/diff_decoder_bb.h> +#include <gr_sync_block.h> -digital_kurtotic_equalizer_cc_sptr -digital_make_kurtotic_equalizer_cc(int num_taps, float mu) -{ - return gnuradio::get_initial_sptr(new digital_kurtotic_equalizer_cc(num_taps, mu)); -} +namespace gr { + namespace digital { -digital_kurtotic_equalizer_cc::digital_kurtotic_equalizer_cc(int num_taps, float mu) - : gr_adaptive_fir_ccc("kurtotic_equalizer_cc", 1, std::vector<gr_complex>(num_taps)) -{ - set_gain(mu); - if (num_taps > 0) - d_taps[0] = 1.0; + class diff_decoder_bb_impl : public diff_decoder_bb + { + public: + diff_decoder_bb_impl(unsigned int modulus); + ~diff_decoder_bb_impl(); - d_alpha_p = 0.01; - d_alpha_q = 0.01; - d_alpha_m = 0.01; + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); - d_p = 0.0f; - d_m = 0.0f; - d_q = gr_complex(0,0); - d_u = gr_complex(0,0); -} + private: + unsigned int d_modulus; + }; + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_DIFF_DECODER_BB_IMPL_H */ diff --git a/gr-digital/lib/diff_encoder_bb_impl.cc b/gr-digital/lib/diff_encoder_bb_impl.cc new file mode 100644 index 0000000000..411efe006c --- /dev/null +++ b/gr-digital/lib/diff_encoder_bb_impl.cc @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "diff_encoder_bb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + diff_encoder_bb::sptr + diff_encoder_bb::make(unsigned int modulus) + { + return gnuradio::get_initial_sptr + (new diff_encoder_bb_impl(modulus)); + } + + diff_encoder_bb_impl::diff_encoder_bb_impl(unsigned int modulus) + : gr_sync_block("diff_encoder_bb", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_last_out(0), d_modulus(modulus) + { + } + + diff_encoder_bb_impl::~diff_encoder_bb_impl() + { + } + + int + diff_encoder_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + unsigned last_out = d_last_out; + unsigned modulus = d_modulus; + + for(int i = 0; i < noutput_items; i++) { + out[i] = (in[i] + last_out) % modulus; + last_out = out[i]; + } + + d_last_out = last_out; + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/diff_encoder_bb_impl.h b/gr-digital/lib/diff_encoder_bb_impl.h new file mode 100644 index 0000000000..e088d79f86 --- /dev/null +++ b/gr-digital/lib/diff_encoder_bb_impl.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2012 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. + */ + +#ifndef INCLUDED_GR_DIFF_ENCODER_BB_IMPL_H +#define INCLUDED_GR_DIFF_ENCODER_BB_IMPL_H + +#include <digital/diff_encoder_bb.h> + +namespace gr { + namespace digital { + + class diff_encoder_bb_impl : public diff_encoder_bb + { + public: + diff_encoder_bb_impl(unsigned int modulus); + ~diff_encoder_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + private: + unsigned int d_last_out; + unsigned int d_modulus; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_DIFF_ENCODER_BB_IMPL_H */ diff --git a/gr-digital/lib/digital_diff_phasor_cc.cc b/gr-digital/lib/diff_phasor_cc_impl.cc index 8313a4de89..0e7a108121 100644 --- a/gr-digital/lib/digital_diff_phasor_cc.cc +++ b/gr-digital/lib/diff_phasor_cc_impl.cc @@ -24,38 +24,46 @@ #include "config.h" #endif -#include <digital_diff_phasor_cc.h> +#include "diff_phasor_cc_impl.h" #include <gr_io_signature.h> -digital_diff_phasor_cc_sptr -digital_make_diff_phasor_cc () -{ - return gnuradio::get_initial_sptr(new digital_diff_phasor_cc()); -} +namespace gr { + namespace digital { -digital_diff_phasor_cc::digital_diff_phasor_cc () - : gr_sync_block ("diff_phasor_cc", - gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (gr_complex))) -{ - set_history(2); -} + diff_phasor_cc::sptr + diff_phasor_cc::make() + { + return gnuradio::get_initial_sptr + (new diff_phasor_cc_impl()); + } + diff_phasor_cc_impl::diff_phasor_cc_impl() + : gr_sync_block("diff_phasor_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))) + { + set_history(2); + } -digital_diff_phasor_cc::~digital_diff_phasor_cc(){} + diff_phasor_cc_impl::~diff_phasor_cc_impl() + { + } -int -digital_diff_phasor_cc::work (int noutput_items, + int + diff_phasor_cc_impl::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) -{ - gr_complex const *in = (const gr_complex *) input_items[0]; - gr_complex *out = (gr_complex *) output_items[0]; - in += 1; // ensure that i - 1 is valid. + { + gr_complex const *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + in += 1; // ensure that i - 1 is valid. - for(int i = 0; i < noutput_items; i++) { - out[i] = in[i] * conj(in[i-1]); - } + for(int i = 0; i < noutput_items; i++) { + out[i] = in[i] * conj(in[i-1]); + } - return noutput_items; -} + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/diff_phasor_cc_impl.h b/gr-digital/lib/diff_phasor_cc_impl.h new file mode 100644 index 0000000000..844fc826d8 --- /dev/null +++ b/gr-digital/lib/diff_phasor_cc_impl.h @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2012 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. + */ + +#ifndef INCLUDED_GR_DIFF_PHASOR_CC_IMPL_H +#define INCLUDED_GR_DIFF_PHASOR_CC_IMPL_H + +#include <digital/diff_phasor_cc.h> +#include <gr_sync_block.h> + +namespace gr { + namespace digital { + + class diff_phasor_cc_impl : public diff_phasor_cc + { + public: + diff_phasor_cc_impl(); + ~diff_phasor_cc_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_DIFF_PHASOR_CC_IMPL_H */ diff --git a/gr-digital/lib/digital_additive_scrambler_bb.cc b/gr-digital/lib/digital_additive_scrambler_bb.cc deleted file mode 100644 index a8affaa78f..0000000000 --- a/gr-digital/lib/digital_additive_scrambler_bb.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_additive_scrambler_bb.h> -#include <gr_io_signature.h> - -digital_additive_scrambler_bb_sptr -digital_make_additive_scrambler_bb(int mask, int seed, int len, int count) -{ - return gnuradio::get_initial_sptr(new digital_additive_scrambler_bb - (mask, seed, len, count)); -} - -digital_additive_scrambler_bb::digital_additive_scrambler_bb(int mask, - int seed, - int len, - int count) - : gr_sync_block("additive_scrambler_bb", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_lfsr(mask, seed, len), - d_count(count), - d_bits(0) -{ -} - -int -digital_additive_scrambler_bb::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - for (int i = 0; i < noutput_items; i++) { - out[i] = in[i]^d_lfsr.next_bit(); - if (d_count > 0) { - if (++d_bits == d_count) { - d_lfsr.reset(); - d_bits = 0; - } - } - } - - return noutput_items; -} diff --git a/gr-digital/lib/digital_bytes_to_syms.cc b/gr-digital/lib/digital_bytes_to_syms.cc deleted file mode 100644 index f8bd82d5b8..0000000000 --- a/gr-digital/lib/digital_bytes_to_syms.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_bytes_to_syms.h> -#include <gr_io_signature.h> -#include <assert.h> - -static const int BITS_PER_BYTE = 8; - -digital_bytes_to_syms_sptr -digital_make_bytes_to_syms () -{ - return gnuradio::get_initial_sptr(new digital_bytes_to_syms ()); -} - -digital_bytes_to_syms::digital_bytes_to_syms () - : gr_sync_interpolator ("bytes_to_syms", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (float)), - BITS_PER_BYTE) -{ -} - -int -digital_bytes_to_syms::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (unsigned char *) input_items[0]; - float *out = (float *) output_items[0]; - - assert (noutput_items % BITS_PER_BYTE == 0); - - for (int i = 0; i < noutput_items / BITS_PER_BYTE; i++) { - int x = in[i]; - - *out++ = (((x >> 7) & 0x1) << 1) - 1; - *out++ = (((x >> 6) & 0x1) << 1) - 1; - *out++ = (((x >> 5) & 0x1) << 1) - 1; - *out++ = (((x >> 4) & 0x1) << 1) - 1; - *out++ = (((x >> 3) & 0x1) << 1) - 1; - *out++ = (((x >> 2) & 0x1) << 1) - 1; - *out++ = (((x >> 1) & 0x1) << 1) - 1; - *out++ = (((x >> 0) & 0x1) << 1) - 1; - } - - return noutput_items; -} - - - diff --git a/gr-digital/lib/digital_chunks_to_symbols_XX.cc.t b/gr-digital/lib/digital_chunks_to_symbols_XX.cc.t deleted file mode 100644 index 399a474a62..0000000000 --- a/gr-digital/lib/digital_chunks_to_symbols_XX.cc.t +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2012 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. - */ - -// @WARNING@ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <@NAME@.h> -#include <gr_io_signature.h> -#include <assert.h> -#include <iostream> -#include <string.h> - -@SPTR_NAME@ -digital_make_@BASE_NAME@ (const std::vector<@O_TYPE@> &symbol_table, const int D) -{ - return gnuradio::get_initial_sptr (new @NAME@ (symbol_table,D)); -} - -@NAME@::@NAME@ (const std::vector<@O_TYPE@> &symbol_table, const int D) - : gr_sync_interpolator ("@BASE_NAME@", - gr_make_io_signature (1, -1, sizeof (@I_TYPE@)), - gr_make_io_signature (1, -1, sizeof (@O_TYPE@)), - D), - d_D (D), - d_symbol_table (symbol_table) -{ -} - -int -@NAME@::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - assert (noutput_items % d_D == 0); - assert (input_items.size() == output_items.size()); - int nstreams = input_items.size(); - - for (int m=0;m<nstreams;m++) { - const @I_TYPE@ *in = (@I_TYPE@ *) input_items[m]; - @O_TYPE@ *out = (@O_TYPE@ *) output_items[m]; - - // per stream processing - for (int i = 0; i < noutput_items / d_D; i++){ - assert (((unsigned int)in[i]*d_D+d_D) <= d_symbol_table.size()); - memcpy(out, &d_symbol_table[(unsigned int)in[i]*d_D], d_D*sizeof(@O_TYPE@)); - out+=d_D; - } - // end of per stream processing - - } - return noutput_items; -} diff --git a/gr-digital/lib/digital_clock_recovery_mm_cc.cc b/gr-digital/lib/digital_clock_recovery_mm_cc.cc deleted file mode 100644 index 198eb4b890..0000000000 --- a/gr-digital/lib/digital_clock_recovery_mm_cc.cc +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2006,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <digital_clock_recovery_mm_cc.h> -#include <gri_mmse_fir_interpolator_cc.h> -#include <stdexcept> -#include <cstdio> - - -// Public constructor -static const int FUDGE = 16; - -digital_clock_recovery_mm_cc_sptr -digital_make_clock_recovery_mm_cc(float omega, float gain_omega, - float mu, float gain_mu, - float omega_relative_limit) -{ - return gnuradio::get_initial_sptr(new digital_clock_recovery_mm_cc (omega, - gain_omega, - mu, - gain_mu, - omega_relative_limit)); -} - -digital_clock_recovery_mm_cc::digital_clock_recovery_mm_cc (float omega, float gain_omega, - float mu, float gain_mu, - float omega_relative_limit) - : gr_block ("clock_recovery_mm_cc", - gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))), - d_mu (mu), d_omega(omega), d_gain_omega(gain_omega), - d_omega_relative_limit(omega_relative_limit), - d_gain_mu(gain_mu), d_last_sample(0), d_interp(new gri_mmse_fir_interpolator_cc()), - d_verbose(gr_prefs::singleton()->get_bool("clock_recovery_mm_cc", "verbose", false)), - d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0) -{ - if (omega <= 0.0) - throw std::out_of_range ("clock rate must be > 0"); - if (gain_mu < 0 || gain_omega < 0) - throw std::out_of_range ("Gains must be non-negative"); - - set_omega(omega); // also sets min and max omega - set_relative_rate (1.0 / omega); - set_history(3); // ensure 2 extra input sample is available -} - -digital_clock_recovery_mm_cc::~digital_clock_recovery_mm_cc () -{ - delete d_interp; -} - -void -digital_clock_recovery_mm_cc::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] = - (int) ceil((noutput_items * d_omega) + d_interp->ntaps()) + FUDGE; -} - -gr_complex -digital_clock_recovery_mm_cc::slicer_0deg (gr_complex sample) -{ - float real=0, imag=0; - - if(sample.real() > 0) - real = 1; - if(sample.imag() > 0) - imag = 1; - return gr_complex(real,imag); -} - -gr_complex -digital_clock_recovery_mm_cc::slicer_45deg (gr_complex sample) -{ - float real= -1, imag = -1; - if(sample.real() > 0) - real=1; - if(sample.imag() > 0) - imag = 1; - return gr_complex(real,imag); -} - -/* - Modified Mueller and Muller clock recovery circuit - Based: - G. R. Danesfahani, T.G. Jeans, "Optimisation of modified Mueller and Muller - algorithm," Electronics Letters, Vol. 31, no. 13, 22 June 1995, pp. 1032 - 1033. -*/ - -int -digital_clock_recovery_mm_cc::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]; - float *foptr = (float *) output_items[1]; - - bool write_foptr = output_items.size() >= 2; - - int ii = 0; // input index - int oo = 0; // output index - int ni = ninput_items[0] - d_interp->ntaps() - FUDGE; // don't use more input than this - - assert(d_mu >= 0.0); - assert(d_mu <= 1.0); - - float mm_val=0; - gr_complex u, x, y; - - // This loop writes the error to the second output, if it exists - if (write_foptr) { - while(oo < noutput_items && ii < ni) { - d_p_2T = d_p_1T; - d_p_1T = d_p_0T; - d_p_0T = d_interp->interpolate (&in[ii], d_mu); - - d_c_2T = d_c_1T; - d_c_1T = d_c_0T; - d_c_0T = slicer_0deg(d_p_0T); - - x = (d_c_0T - d_c_2T) * conj(d_p_1T); - y = (d_p_0T - d_p_2T) * conj(d_c_1T); - u = y - x; - mm_val = u.real(); - out[oo++] = d_p_0T; - - // limit mm_val - mm_val = gr_branchless_clip(mm_val,4.0); - d_omega = d_omega + d_gain_omega * mm_val; - d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away - - d_mu = d_mu + d_omega + d_gain_mu * mm_val; - ii += (int)floor(d_mu); - d_mu -= floor(d_mu); - - // write the error signal to the second output - foptr[oo-1] = mm_val; - - if (ii < 0) // clamp it. This should only happen with bogus input - ii = 0; - } - } - // This loop does not write to the second output (ugly, but faster) - else { - while(oo < noutput_items && ii < ni) { - d_p_2T = d_p_1T; - d_p_1T = d_p_0T; - d_p_0T = d_interp->interpolate (&in[ii], d_mu); - - d_c_2T = d_c_1T; - d_c_1T = d_c_0T; - d_c_0T = slicer_0deg(d_p_0T); - - x = (d_c_0T - d_c_2T) * conj(d_p_1T); - y = (d_p_0T - d_p_2T) * conj(d_c_1T); - u = y - x; - mm_val = u.real(); - out[oo++] = d_p_0T; - - // limit mm_val - mm_val = gr_branchless_clip(mm_val,1.0); - - d_omega = d_omega + d_gain_omega * mm_val; - d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away - - d_mu = d_mu + d_omega + d_gain_mu * mm_val; - ii += (int)floor(d_mu); - d_mu -= floor(d_mu); - - if(d_verbose) { - printf("%f\t%f\n", d_omega, d_mu); - } - - if (ii < 0) // clamp it. This should only happen with bogus input - ii = 0; - } - } - - if (ii > 0){ - if (ii > ninput_items[0]){ - fprintf(stderr, "gr_clock_recovery_mm_cc: ii > ninput_items[0] (%d > %d)\n", - ii, ninput_items[0]); - assert(0); - } - consume_each (ii); - } - - return oo; -} diff --git a/gr-digital/lib/digital_clock_recovery_mm_ff.cc b/gr-digital/lib/digital_clock_recovery_mm_ff.cc deleted file mode 100644 index 04057f0e94..0000000000 --- a/gr-digital/lib/digital_clock_recovery_mm_ff.cc +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_io_signature.h> -#include <digital_clock_recovery_mm_ff.h> -#include <gri_mmse_fir_interpolator.h> -#include <stdexcept> - -#define DEBUG_CR_MM_FF 0 // must be defined as 0 or 1 - -// Public constructor - -digital_clock_recovery_mm_ff_sptr -digital_make_clock_recovery_mm_ff(float omega, float gain_omega, - float mu, float gain_mu, - float omega_relative_limit) -{ - return gnuradio::get_initial_sptr(new digital_clock_recovery_mm_ff (omega, - gain_omega, - mu, - gain_mu, - omega_relative_limit)); -} - -digital_clock_recovery_mm_ff::digital_clock_recovery_mm_ff (float omega, float gain_omega, - float mu, float gain_mu, - float omega_relative_limit) - : gr_block ("clock_recovery_mm_ff", - gr_make_io_signature (1, 1, sizeof (float)), - gr_make_io_signature (1, 1, sizeof (float))), - d_mu (mu), d_gain_omega(gain_omega), d_gain_mu(gain_mu), - d_last_sample(0), d_interp(new gri_mmse_fir_interpolator()), - d_logfile(0), d_omega_relative_limit(omega_relative_limit) -{ - if (omega < 1) - throw std::out_of_range ("clock rate must be > 0"); - if (gain_mu < 0 || gain_omega < 0) - throw std::out_of_range ("Gains must be non-negative"); - - set_omega(omega); // also sets min and max omega - set_relative_rate (1.0 / omega); - - if (DEBUG_CR_MM_FF) - d_logfile = fopen("cr_mm_ff.dat", "wb"); -} - -digital_clock_recovery_mm_ff::~digital_clock_recovery_mm_ff () -{ - delete d_interp; - - if (DEBUG_CR_MM_FF && d_logfile){ - fclose(d_logfile); - d_logfile = 0; - } -} - -void -digital_clock_recovery_mm_ff::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] = - (int) ceil((noutput_items * d_omega) + d_interp->ntaps()); -} - -static inline float -slice(float x) -{ - return x < 0 ? -1.0F : 1.0F; -} - -/* - * This implements the Mueller and Müller (M&M) discrete-time error-tracking synchronizer. - * - * See "Digital Communication Receivers: Synchronization, Channel - * Estimation and Signal Processing" by Heinrich Meyr, Marc Moeneclaey, & Stefan Fechtel. - * ISBN 0-471-50275-8. - */ -int -digital_clock_recovery_mm_ff::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const float *in = (const float *) input_items[0]; - float *out = (float *) output_items[0]; - - int ii = 0; // input index - int oo = 0; // output index - int ni = ninput_items[0] - d_interp->ntaps(); // don't use more input than this - float mm_val; - - while (oo < noutput_items && ii < ni ){ - - // produce output sample - out[oo] = d_interp->interpolate (&in[ii], d_mu); - mm_val = slice(d_last_sample) * out[oo] - slice(out[oo]) * d_last_sample; - d_last_sample = out[oo]; - - d_omega = d_omega + d_gain_omega * mm_val; - d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_relative_limit); // make sure we don't walk away - d_mu = d_mu + d_omega + d_gain_mu * mm_val; - - ii += (int) floor(d_mu); - d_mu = d_mu - floor(d_mu); - oo++; - - if (DEBUG_CR_MM_FF && d_logfile){ - fwrite(&d_omega, sizeof(d_omega), 1, d_logfile); - } - } - - consume_each (ii); - - return oo; -} diff --git a/gr-digital/lib/digital_constellation.cc b/gr-digital/lib/digital_constellation.cc deleted file mode 100644 index 0d4b88b047..0000000000 --- a/gr-digital/lib/digital_constellation.cc +++ /dev/null @@ -1,596 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2010, 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_io_signature.h> -#include <digital_constellation.h> -#include <digital_metric_type.h> -#include <gr_math.h> -#include <gr_complex.h> -#include <math.h> -#include <iostream> -#include <stdlib.h> -#include <float.h> -#include <stdexcept> - -#define M_TWOPI (2*M_PI) -#define SQRT_TWO 0.707107 - -// Base Constellation Class - -digital_constellation::digital_constellation (std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int dimensionality) : - d_constellation(constellation), - d_pre_diff_code(pre_diff_code), - d_rotational_symmetry(rotational_symmetry), - d_dimensionality(dimensionality) -{ - // Scale constellation points so that average magnitude is 1. - float summed_mag = 0; - unsigned int constsize = d_constellation.size(); - for (unsigned int i=0; i<constsize; i++) { - gr_complex c = d_constellation[i]; - summed_mag += sqrt(c.real()*c.real() + c.imag()*c.imag()); - } - d_scalefactor = constsize/summed_mag; - for (unsigned int i=0; i<constsize; i++) { - d_constellation[i] = d_constellation[i]*d_scalefactor; - } - if (pre_diff_code.size() == 0) - d_apply_pre_diff_code = false; - else if (pre_diff_code.size() != constellation.size()) - throw std::runtime_error ("The constellation and pre-diff code must be of the same length."); - else - d_apply_pre_diff_code = true; - calc_arity(); -} - -digital_constellation::digital_constellation () : - d_apply_pre_diff_code(false), - d_rotational_symmetry(0), - d_dimensionality(1) -{ - calc_arity(); -} - -//! Returns the constellation points for a symbol value -void -digital_constellation::map_to_points(unsigned int value, gr_complex *points) -{ - for (unsigned int i=0; i<d_dimensionality; i++) - points[i] = d_constellation[value*d_dimensionality + i]; -} - -std::vector<gr_complex> -digital_constellation::map_to_points_v(unsigned int value) -{ - std::vector<gr_complex> points_v; - points_v.resize(d_dimensionality); - map_to_points(value, &(points_v[0])); - return points_v; -} - -float -digital_constellation::get_distance(unsigned int index, const gr_complex *sample) -{ - float dist = 0; - for (unsigned int i=0; i<d_dimensionality; i++) { - dist += norm(sample[i] - d_constellation[index*d_dimensionality + i]); - } - return dist; -} - -unsigned int -digital_constellation::get_closest_point(const gr_complex *sample) -{ - unsigned int min_index = 0; - float min_euclid_dist; - float euclid_dist; - - min_euclid_dist = get_distance(0, sample); - min_index = 0; - for (unsigned int j = 1; j < d_arity; j++){ - euclid_dist = get_distance(j, sample); - if (euclid_dist < min_euclid_dist){ - min_euclid_dist = euclid_dist; - min_index = j; - } - } - return min_index; -} - -unsigned int -digital_constellation::decision_maker_pe(const gr_complex *sample, float *phase_error) -{ - unsigned int index = decision_maker(sample); - *phase_error = 0; - for (unsigned int d=0; d<d_dimensionality; d++) - *phase_error += -arg(sample[d]*conj(d_constellation[index+d])); - return index; -} - -/* -unsigned int digital_constellation::decision_maker_e(const gr_complex *sample, float *error) -{ - unsigned int index = decision_maker(sample); - *error = 0; - for (unsigned int d=0; d<d_dimensionality; d++) - *error += sample[d]*conj(d_constellation[index+d]); - return index; -} -*/ - -std::vector<gr_complex> digital_constellation::s_points () { - if (d_dimensionality != 1) - throw std::runtime_error ("s_points only works for dimensionality 1 constellations."); - else - return d_constellation; -} - -std::vector<std::vector<gr_complex> > -digital_constellation::v_points () -{ - std::vector<std::vector<gr_complex> > vv_const; - vv_const.resize(d_arity); - for (unsigned int p=0; p<d_arity; p++) { - std::vector<gr_complex> v_const; - v_const.resize(d_dimensionality); - for (unsigned int d=0; d<d_dimensionality; d++) { - v_const[d] = d_constellation[p*d_dimensionality+d]; - } - vv_const[p] = v_const; - } - return vv_const; -} - -void -digital_constellation::calc_metric(const gr_complex *sample, float *metric, - trellis_metric_type_t type) -{ - switch (type){ - case TRELLIS_EUCLIDEAN: - calc_euclidean_metric(sample, metric); - break; - case TRELLIS_HARD_SYMBOL: - calc_hard_symbol_metric(sample, metric); - break; - case TRELLIS_HARD_BIT: - throw std::runtime_error ("Invalid metric type (not yet implemented)."); - break; - default: - throw std::runtime_error ("Invalid metric type."); - } -} - -void -digital_constellation::calc_euclidean_metric(const gr_complex *sample, float *metric) -{ - for (unsigned int o=0; o<d_arity; o++) { - metric[o] = get_distance(o, sample); - } -} - -void -digital_constellation::calc_hard_symbol_metric(const gr_complex *sample, float *metric) -{ - float minm = FLT_MAX; - unsigned int minmi = 0; - for (unsigned int o=0; o<d_arity; o++) { - float dist = get_distance(o, sample); - if (dist < minm) { - minm = dist; - minmi = o; - } - } - for(unsigned int o=0; o<d_arity; o++) { - metric[o] = (o==minmi?0.0:1.0); - } -} - -void -digital_constellation::calc_arity () -{ - if (d_constellation.size() % d_dimensionality != 0) - throw std::runtime_error ("Constellation vector size must be a multiple of the dimensionality."); - d_arity = d_constellation.size()/d_dimensionality; -} - -unsigned int -digital_constellation::decision_maker_v (std::vector<gr_complex> sample) -{ - assert(sample.size() == d_dimensionality); - return decision_maker (&(sample[0])); -} - -digital_constellation_calcdist_sptr -digital_make_constellation_calcdist(std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int dimensionality) -{ - return digital_constellation_calcdist_sptr(new digital_constellation_calcdist - (constellation, pre_diff_code, - rotational_symmetry, dimensionality)); -} - -digital_constellation_calcdist::digital_constellation_calcdist(std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int dimensionality) : - digital_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality) -{} - -// Chooses points base on shortest distance. -// Inefficient. -unsigned int -digital_constellation_calcdist::decision_maker(const gr_complex *sample) -{ - return get_closest_point(sample); -} - -digital_constellation_sector::digital_constellation_sector (std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int dimensionality, - unsigned int n_sectors) : - digital_constellation(constellation, pre_diff_code, rotational_symmetry, dimensionality), - n_sectors(n_sectors) -{ -} - -unsigned int -digital_constellation_sector::decision_maker (const gr_complex *sample) -{ - unsigned int sector; - sector = get_sector(sample); - return sector_values[sector]; -} - -void -digital_constellation_sector::find_sector_values () -{ - unsigned int i; - sector_values.clear(); - for (i=0; i<n_sectors; i++) { - sector_values.push_back(calc_sector_value(i)); - } -} - -digital_constellation_rect_sptr -digital_make_constellation_rect(std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, unsigned int imag_sectors, - float width_real_sectors, float width_imag_sectors) -{ - return digital_constellation_rect_sptr(new digital_constellation_rect - (constellation, pre_diff_code, - rotational_symmetry, - real_sectors, imag_sectors, - width_real_sectors, - width_imag_sectors)); - } - -digital_constellation_rect::digital_constellation_rect (std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, unsigned int imag_sectors, - float width_real_sectors, float width_imag_sectors) : - digital_constellation_sector(constellation, pre_diff_code, rotational_symmetry, 1, real_sectors * imag_sectors), - n_real_sectors(real_sectors), n_imag_sectors(imag_sectors), - d_width_real_sectors(width_real_sectors), d_width_imag_sectors(width_imag_sectors) -{ - d_width_real_sectors *= d_scalefactor; - d_width_imag_sectors *= d_scalefactor; - find_sector_values(); -} - -unsigned int -digital_constellation_rect::get_sector (const gr_complex *sample) -{ - int real_sector, imag_sector; - unsigned int sector; - - real_sector = int(real(*sample)/d_width_real_sectors + n_real_sectors/2.0); - if(real_sector < 0) - real_sector = 0; - if(real_sector >= (int)n_real_sectors) - real_sector = n_real_sectors-1; - - imag_sector = int(imag(*sample)/d_width_imag_sectors + n_imag_sectors/2.0); - if(imag_sector < 0) - imag_sector = 0; - if(imag_sector >= (int)n_imag_sectors) - imag_sector = n_imag_sectors-1; - - sector = real_sector * n_imag_sectors + imag_sector; - return sector; -} - -unsigned int -digital_constellation_rect::calc_sector_value (unsigned int sector) -{ - unsigned int real_sector, imag_sector; - gr_complex sector_center; - unsigned int closest_point; - real_sector = float(sector)/n_imag_sectors; - imag_sector = sector - real_sector * n_imag_sectors; - sector_center = gr_complex((real_sector + 0.5 - n_real_sectors/2.0) * d_width_real_sectors, - (imag_sector + 0.5 - n_imag_sectors/2.0) * d_width_imag_sectors); - closest_point = get_closest_point(§or_center); - return closest_point; -} - -digital_constellation_expl_rect_sptr -digital_make_constellation_expl_rect( - std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, - unsigned int imag_sectors, - float width_real_sectors, - float width_imag_sectors, - std::vector<unsigned int> sector_values -) -{ - return digital_constellation_expl_rect_sptr( - new digital_constellation_expl_rect( - constellation, pre_diff_code, rotational_symmetry, real_sectors, imag_sectors, - width_real_sectors, width_imag_sectors, sector_values)); -} - -digital_constellation_expl_rect::digital_constellation_expl_rect ( - std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int rotational_symmetry, - unsigned int real_sectors, - unsigned int imag_sectors, - float width_real_sectors, - float width_imag_sectors, - std::vector<unsigned int> sector_values - ) : digital_constellation_rect( - constellation, pre_diff_code, rotational_symmetry, real_sectors, imag_sectors, - width_real_sectors, width_imag_sectors), - d_sector_values(sector_values) {}; - -digital_constellation_psk_sptr -digital_make_constellation_psk(std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int n_sectors) -{ - return digital_constellation_psk_sptr(new digital_constellation_psk - (constellation, pre_diff_code, - n_sectors)); -} - -digital_constellation_psk::digital_constellation_psk (std::vector<gr_complex> constellation, - std::vector<unsigned int> pre_diff_code, - unsigned int n_sectors) : - digital_constellation_sector(constellation, pre_diff_code, constellation.size(), 1, n_sectors) -{ - find_sector_values(); -} - -unsigned int -digital_constellation_psk::get_sector (const gr_complex *sample) -{ - float phase = arg(*sample); - float width = M_TWOPI / n_sectors; - int sector = floor(phase/width + 0.5); - if (sector < 0) - sector += n_sectors; - return sector; -} - -unsigned int -digital_constellation_psk::calc_sector_value (unsigned int sector) -{ - float phase = sector * M_TWOPI / n_sectors; - gr_complex sector_center = gr_complex(cos(phase), sin(phase)); - unsigned int closest_point = get_closest_point(§or_center); - return closest_point; -} - - -digital_constellation_bpsk_sptr -digital_make_constellation_bpsk() -{ - return digital_constellation_bpsk_sptr(new digital_constellation_bpsk ()); -} - -digital_constellation_bpsk::digital_constellation_bpsk () -{ - d_constellation.resize(2); - d_constellation[0] = gr_complex(-1, 0); - d_constellation[1] = gr_complex(1, 0); - d_rotational_symmetry = 2; - d_dimensionality = 1; - calc_arity(); -} - -unsigned int -digital_constellation_bpsk::decision_maker(const gr_complex *sample) -{ - return (real(*sample) > 0); -} - - -digital_constellation_qpsk_sptr -digital_make_constellation_qpsk() -{ - return digital_constellation_qpsk_sptr(new digital_constellation_qpsk ()); -} - -digital_constellation_qpsk::digital_constellation_qpsk () -{ - d_constellation.resize(4); - // Gray-coded - d_constellation[0] = gr_complex(-SQRT_TWO, -SQRT_TWO); - d_constellation[1] = gr_complex(SQRT_TWO, -SQRT_TWO); - d_constellation[2] = gr_complex(-SQRT_TWO, SQRT_TWO); - d_constellation[3] = gr_complex(SQRT_TWO, SQRT_TWO); - - /* - d_constellation[0] = gr_complex(SQRT_TWO, SQRT_TWO); - d_constellation[1] = gr_complex(-SQRT_TWO, SQRT_TWO); - d_constellation[2] = gr_complex(SQRT_TWO, -SQRT_TWO); - d_constellation[3] = gr_complex(SQRT_TWO, -SQRT_TWO); - */ - - d_pre_diff_code.resize(4); - d_pre_diff_code[0] = 0x0; - d_pre_diff_code[1] = 0x2; - d_pre_diff_code[2] = 0x3; - d_pre_diff_code[3] = 0x1; - - d_rotational_symmetry = 4; - d_dimensionality = 1; - calc_arity(); -} - -unsigned int -digital_constellation_qpsk::decision_maker(const gr_complex *sample) -{ - // Real component determines small bit. - // Imag component determines big bit. - return 2*(imag(*sample)>0) + (real(*sample)>0); - - /* - bool a = real(*sample) > 0; - bool b = imag(*sample) > 0; - if(a) { - if(b) - return 0x0; - else - return 0x1; - } - else { - if(b) - return 0x2; - else - return 0x3; - } - */ -} - - -/********************************************************************/ - - -digital_constellation_dqpsk_sptr -digital_make_constellation_dqpsk() -{ - return digital_constellation_dqpsk_sptr(new digital_constellation_dqpsk ()); -} - -digital_constellation_dqpsk::digital_constellation_dqpsk () -{ - // This constellation is not gray coded, which allows - // us to use differential encodings (through gr_diff_encode and - // gr_diff_decode) on the symbols. - d_constellation.resize(4); - d_constellation[0] = gr_complex(+SQRT_TWO, +SQRT_TWO); - d_constellation[1] = gr_complex(-SQRT_TWO, +SQRT_TWO); - d_constellation[2] = gr_complex(-SQRT_TWO, -SQRT_TWO); - d_constellation[3] = gr_complex(+SQRT_TWO, -SQRT_TWO); - - // Use this mapping to convert to gray code before diff enc. - d_pre_diff_code.resize(4); - d_pre_diff_code[0] = 0x0; - d_pre_diff_code[1] = 0x1; - d_pre_diff_code[2] = 0x3; - d_pre_diff_code[3] = 0x2; - d_apply_pre_diff_code = true; - - d_rotational_symmetry = 4; - d_dimensionality = 1; - calc_arity(); -} - -unsigned int -digital_constellation_dqpsk::decision_maker(const gr_complex *sample) -{ - // Slower deicison maker as we can't slice along one axis. - // Maybe there's a better way to do this, still. - - bool a = real(*sample) > 0; - bool b = imag(*sample) > 0; - if(a) { - if(b) - return 0x0; - else - return 0x3; - } - else { - if(b) - return 0x1; - else - return 0x2; - } -} - -digital_constellation_8psk_sptr -digital_make_constellation_8psk() -{ - return digital_constellation_8psk_sptr(new digital_constellation_8psk ()); -} - -digital_constellation_8psk::digital_constellation_8psk () -{ - float angle = M_PI/8.0; - d_constellation.resize(8); - // Gray-coded - d_constellation[0] = gr_complex(cos( 1*angle), sin( 1*angle)); - d_constellation[1] = gr_complex(cos( 7*angle), sin( 7*angle)); - d_constellation[2] = gr_complex(cos(15*angle), sin(15*angle)); - d_constellation[3] = gr_complex(cos( 9*angle), sin( 9*angle)); - d_constellation[4] = gr_complex(cos( 3*angle), sin( 3*angle)); - d_constellation[5] = gr_complex(cos( 5*angle), sin( 5*angle)); - d_constellation[6] = gr_complex(cos(13*angle), sin(13*angle)); - d_constellation[7] = gr_complex(cos(11*angle), sin(11*angle)); - d_rotational_symmetry = 8; - d_dimensionality = 1; - calc_arity(); -} - -unsigned int -digital_constellation_8psk::decision_maker(const gr_complex *sample) -{ - unsigned int ret = 0; - - float re = sample->real(); - float im = sample->imag(); - - if(fabsf(re) <= fabsf(im)) - ret = 4; - if(re <= 0) - ret |= 1; - if(im <= 0) - ret |= 2; - - return ret; -} diff --git a/gr-digital/lib/digital_constellation_decoder_cb.cc b/gr-digital/lib/digital_constellation_decoder_cb.cc deleted file mode 100644 index 4638790f61..0000000000 --- a/gr-digital/lib/digital_constellation_decoder_cb.cc +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_constellation_decoder_cb.h> -#include <digital_constellation.h> -#include <gr_io_signature.h> -#include <iostream> - -digital_constellation_decoder_cb_sptr -digital_make_constellation_decoder_cb (digital_constellation_sptr constellation) -{ - return gnuradio::get_initial_sptr - (new digital_constellation_decoder_cb(constellation)); -} - -digital_constellation_decoder_cb:: -digital_constellation_decoder_cb (digital_constellation_sptr constellation) - : gr_block ("constellation_decoder_cb", - gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_constellation(constellation), - d_dim(constellation->dimensionality()) -{ - set_relative_rate (1.0 / ((double) d_dim)); -} - -void -digital_constellation_decoder_cb::forecast (int noutput_items, - gr_vector_int &ninput_items_required) -{ - unsigned int input_required = noutput_items * d_dim; - - unsigned ninputs = ninput_items_required.size(); - for (unsigned int i = 0; i < ninputs; i++) - ninput_items_required[i] = input_required; -} - - -int -digital_constellation_decoder_cb::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - gr_complex const *in = (const gr_complex *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - for(int i = 0; i < noutput_items; i++){ - out[i] = d_constellation->decision_maker(&(in[i*d_dim])); - } - - consume_each (noutput_items * d_dim); - return noutput_items; -} diff --git a/gr-digital/lib/digital_constellation_receiver_cb.cc b/gr-digital/lib/digital_constellation_receiver_cb.cc deleted file mode 100644 index faaa760fd0..0000000000 --- a/gr-digital/lib/digital_constellation_receiver_cb.cc +++ /dev/null @@ -1,126 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <digital_constellation_receiver_cb.h> -#include <stdexcept> -#include <gr_math.h> -#include <gr_expj.h> - - -#define M_TWOPI (2*M_PI) -#define VERBOSE_MM 0 // Used for debugging symbol timing loop -#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking - -// Public constructor - -digital_constellation_receiver_cb_sptr -digital_make_constellation_receiver_cb(digital_constellation_sptr constell, - float loop_bw, float fmin, float fmax) -{ - return gnuradio::get_initial_sptr(new digital_constellation_receiver_cb (constell, - loop_bw, - fmin, fmax)); -} - -static int ios[] = {sizeof(char), sizeof(float), sizeof(float), sizeof(float), sizeof(gr_complex)}; -static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); -digital_constellation_receiver_cb::digital_constellation_receiver_cb (digital_constellation_sptr constellation, - float loop_bw, float fmin, float fmax) - : gr_block ("constellation_receiver_cb", - gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signaturev (1, 5, iosig)), - gri_control_loop(loop_bw, fmax, fmin), - d_constellation(constellation), - d_current_const_point(0) -{ - if (d_constellation->dimensionality() != 1) - throw std::runtime_error ("This receiver only works with constellations of dimension 1."); -} - -void -digital_constellation_receiver_cb::phase_error_tracking(float phase_error) -{ - advance_loop(phase_error); - phase_wrap(); - frequency_limit(); - -#if VERBOSE_COSTAS - printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n", - phase_error, d_phase, d_freq, sample.real(), sample.imag(), - d_constellation->points()[d_current_const_point].real(), - d_constellation->points()[d_current_const_point].imag()); -#endif -} - -int -digital_constellation_receiver_cb::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]; - - int i=0; - - float phase_error; - unsigned int sym_value; - gr_complex sample, nco; - - float *out_err = 0, *out_phase = 0, *out_freq = 0; - gr_complex *out_symbol; - if(output_items.size() == 5) { - out_err = (float *) output_items[1]; - out_phase = (float *) output_items[2]; - out_freq = (float *) output_items[3]; - out_symbol = (gr_complex*)output_items[4]; - } - - while((i < noutput_items) && (i < ninput_items[0])) { - sample = in[i]; - nco = gr_expj(d_phase); // get the NCO value for derotating the current sample - sample = nco*sample; // get the downconverted symbol - - sym_value = d_constellation->decision_maker_pe(&sample, &phase_error); - phase_error_tracking(phase_error); // corrects phase and frequency offsets - - out[i] = sym_value; - - if(output_items.size() == 5) { - out_err[i] = phase_error; - out_phase[i] = d_phase; - out_freq[i] = d_freq; - out_symbol[i] = sample; - } - i++; - } - - consume_each(i); - return i; -} - diff --git a/gr-digital/lib/digital_correlate_access_code_bb.cc b/gr-digital/lib/digital_correlate_access_code_bb.cc deleted file mode 100644 index f21b57d92c..0000000000 --- a/gr-digital/lib/digital_correlate_access_code_bb.cc +++ /dev/null @@ -1,134 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2006,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_correlate_access_code_bb.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <gr_count_bits.h> -#include <cstdio> - - -#define VERBOSE 0 - - -digital_correlate_access_code_bb_sptr -digital_make_correlate_access_code_bb (const std::string &access_code, int threshold) -{ - return gnuradio::get_initial_sptr(new digital_correlate_access_code_bb - (access_code, threshold)); -} - - -digital_correlate_access_code_bb::digital_correlate_access_code_bb ( - const std::string &access_code, int threshold) - : gr_sync_block ("correlate_access_code_bb", - gr_make_io_signature (1, 1, sizeof(char)), - gr_make_io_signature (1, 1, sizeof(char))), - d_data_reg(0), d_flag_reg(0), d_flag_bit(0), d_mask(0), - d_threshold(threshold) - -{ - if (!set_access_code(access_code)){ - fprintf(stderr, "digital_correlate_access_code_bb: access_code is > 64 bits\n"); - throw std::out_of_range ("access_code is > 64 bits"); - } -} - -digital_correlate_access_code_bb::~digital_correlate_access_code_bb () -{ -} - -bool -digital_correlate_access_code_bb::set_access_code( - const std::string &access_code) -{ - unsigned len = access_code.length(); // # of bytes in string - if (len > 64) - return false; - - // set len top bits to 1. - d_mask = ((~0ULL) >> (64 - len)) << (64 - len); - - d_flag_bit = 1LL << (64 - len); // Where we or-in new flag values. - // new data always goes in 0x0000000000000001 - d_access_code = 0; - for (unsigned i=0; i < 64; i++){ - d_access_code <<= 1; - if (i < len) - d_access_code |= access_code[i] & 1; // look at LSB only - } - - return true; -} - -int -digital_correlate_access_code_bb::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - for (int i = 0; i < noutput_items; i++){ - - // compute output value - unsigned int t = 0; - - t |= ((d_data_reg >> 63) & 0x1) << 0; - t |= ((d_flag_reg >> 63) & 0x1) << 1; // flag bit - out[i] = t; - - // compute hamming distance between desired access code and current data - unsigned long long wrong_bits = 0; - unsigned int nwrong = d_threshold+1; - int new_flag = 0; - - wrong_bits = (d_data_reg ^ d_access_code) & d_mask; - nwrong = gr_count_bits64(wrong_bits); - - // test for access code with up to threshold errors - new_flag = (nwrong <= d_threshold); - -#if VERBOSE - if(new_flag) { - fprintf(stderr, "access code found: %llx\n", d_access_code); - } - else { - fprintf(stderr, "%llx ==> %llx\n", d_access_code, d_data_reg); - } -#endif - - // shift in new data and new flag - d_data_reg = (d_data_reg << 1) | (in[i] & 0x1); - d_flag_reg = (d_flag_reg << 1); - if (new_flag) { - d_flag_reg |= d_flag_bit; - } - } - - return noutput_items; -} - diff --git a/gr-digital/lib/digital_correlate_access_code_tag_bb.cc b/gr-digital/lib/digital_correlate_access_code_tag_bb.cc deleted file mode 100644 index 95f06534e3..0000000000 --- a/gr-digital/lib/digital_correlate_access_code_tag_bb.cc +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2006,2010-2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_correlate_access_code_tag_bb.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <gr_count_bits.h> -#include <cstdio> -#include <iostream> - -#define VERBOSE 0 - - -digital_correlate_access_code_tag_bb_sptr -digital_make_correlate_access_code_tag_bb (const std::string &access_code, - int threshold, - const std::string &tag_name) -{ - return gnuradio::get_initial_sptr(new digital_correlate_access_code_tag_bb - (access_code, threshold, tag_name)); -} - - -digital_correlate_access_code_tag_bb::digital_correlate_access_code_tag_bb ( - const std::string &access_code, int threshold, const std::string &tag_name) - : gr_sync_block ("correlate_access_code_tag_bb", - gr_make_io_signature (1, 1, sizeof(char)), - gr_make_io_signature (1, 1, sizeof(char))), - d_data_reg(0), d_mask(0), - d_threshold(threshold), d_len(0) -{ - if (!set_access_code(access_code)) { - fprintf(stderr, "digital_correlate_access_code_tag_bb: access_code is > 64 bits\n"); - throw std::out_of_range ("access_code is > 64 bits"); - } - - std::stringstream str; - str << name() << unique_id(); - d_me = pmt::pmt_string_to_symbol(str.str()); - d_key = pmt::pmt_string_to_symbol(tag_name); -} - -digital_correlate_access_code_tag_bb::~digital_correlate_access_code_tag_bb () -{ -} - -bool -digital_correlate_access_code_tag_bb::set_access_code( - const std::string &access_code) -{ - d_len = access_code.length(); // # of bytes in string - if (d_len > 64) - return false; - - // set len top bits to 1. - d_mask = ((~0ULL) >> (64 - d_len)) << (64 - d_len); - - d_access_code = 0; - for (unsigned i=0; i < 64; i++){ - d_access_code <<= 1; - if (i < d_len) - d_access_code |= access_code[i] & 1; // look at LSB only - } - - return true; -} - -int -digital_correlate_access_code_tag_bb::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - uint64_t abs_out_sample_cnt = nitems_written(0); - - for (int i = 0; i < noutput_items; i++){ - - out[i] = in[i]; - - // compute hamming distance between desired access code and current data - unsigned long long wrong_bits = 0; - unsigned int nwrong = d_threshold+1; - int new_flag = 0; - - wrong_bits = (d_data_reg ^ d_access_code) & d_mask; - nwrong = gr_count_bits64(wrong_bits); - - // test for access code with up to threshold errors - new_flag = (nwrong <= d_threshold); - - // shift in new data and new flag - d_data_reg = (d_data_reg << 1) | (in[i] & 0x1); - if (new_flag) { - if(VERBOSE) std::cout << "writing tag at sample " << abs_out_sample_cnt + i << std::endl; - add_item_tag(0, //stream ID - abs_out_sample_cnt + i - 64 + d_len, //sample - d_key, //frame info - pmt::pmt_t(), //data (unused) - d_me //block src id - ); - } - } - - return noutput_items; -} - diff --git a/gr-digital/lib/digital_costas_loop_cc.cc b/gr-digital/lib/digital_costas_loop_cc.cc deleted file mode 100644 index 370dc7e5c1..0000000000 --- a/gr-digital/lib/digital_costas_loop_cc.cc +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_costas_loop_cc.h> -#include <gr_io_signature.h> -#include <gr_expj.h> -#include <gr_sincos.h> -#include <gr_math.h> - -digital_costas_loop_cc_sptr -digital_make_costas_loop_cc (float loop_bw, int order - ) throw (std::invalid_argument) -{ - return gnuradio::get_initial_sptr(new digital_costas_loop_cc - (loop_bw, order)); -} - -digital_costas_loop_cc::digital_costas_loop_cc (float loop_bw, int order - ) throw (std::invalid_argument) - : gr_sync_block ("costas_loop_cc", - gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature2 (1, 2, sizeof (gr_complex), sizeof(float))), - gri_control_loop(loop_bw, 1.0, -1.0), - d_order(order), d_phase_detector(NULL) -{ - // Set up the phase detector to use based on the constellation order - switch(d_order) { - case 2: - d_phase_detector = &digital_costas_loop_cc::phase_detector_2; - break; - - case 4: - d_phase_detector = &digital_costas_loop_cc::phase_detector_4; - break; - - case 8: - d_phase_detector = &digital_costas_loop_cc::phase_detector_8; - break; - - default: - throw std::invalid_argument("order must be 2, 4, or 8"); - break; - } -} - -float -digital_costas_loop_cc::phase_detector_8(gr_complex sample) const -{ - /* This technique splits the 8PSK constellation into 2 squashed - QPSK constellations, one when I is larger than Q and one where - Q is larger than I. The error is then calculated proportionally - to these squashed constellations by the const K = sqrt(2)-1. - - The signal magnitude must be > 1 or K will incorrectly bias - the error value. - - Ref: Z. Huang, Z. Yi, M. Zhang, K. Wang, "8PSK demodulation for - new generation DVB-S2", IEEE Proc. Int. Conf. Communications, - Circuits and Systems, Vol. 2, pp. 1447 - 1450, 2004. - */ - - float K = (sqrt(2.0) - 1); - if(fabsf(sample.real()) >= fabsf(sample.imag())) { - return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() - - (sample.imag()>0 ? 1.0 : -1.0) * sample.real() * K); - } - else { - return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() * K - - (sample.imag()>0 ? 1.0 : -1.0) * sample.real()); - } -} - -float -digital_costas_loop_cc::phase_detector_4(gr_complex sample) const -{ - - return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() - - (sample.imag()>0 ? 1.0 : -1.0) * sample.real()); -} - -float -digital_costas_loop_cc::phase_detector_2(gr_complex sample) const -{ - return (sample.real()*sample.imag()); -} - -int -digital_costas_loop_cc::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const gr_complex *iptr = (gr_complex *) input_items[0]; - gr_complex *optr = (gr_complex *) output_items[0]; - float *foptr = (float *) output_items[1]; - - bool write_foptr = output_items.size() >= 2; - - float error; - gr_complex nco_out; - - if (write_foptr) { - - for (int i = 0; i < noutput_items; i++){ - nco_out = gr_expj(-d_phase); - optr[i] = iptr[i] * nco_out; - - error = (*this.*d_phase_detector)(optr[i]); - error = gr_branchless_clip(error, 1.0); - - advance_loop(error); - phase_wrap(); - frequency_limit(); - - foptr[i] = d_freq; - } - } else { - for (int i = 0; i < noutput_items; i++){ - nco_out = gr_expj(-d_phase); - optr[i] = iptr[i] * nco_out; - - error = (*this.*d_phase_detector)(optr[i]); - error = gr_branchless_clip(error, 1.0); - - advance_loop(error); - phase_wrap(); - frequency_limit(); - } - } - return noutput_items; -} diff --git a/gr-digital/lib/digital_cpmmod_bc.cc b/gr-digital/lib/digital_cpmmod_bc.cc deleted file mode 100644 index a95b604d14..0000000000 --- a/gr-digital/lib/digital_cpmmod_bc.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2010 Free Software Foundation, Inc. - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_cpmmod_bc.h> -#include <gr_io_signature.h> - - -// Shared pointer constructor -digital_cpmmod_bc_sptr -digital_make_cpmmod_bc(int type, float h, - unsigned samples_per_sym, - unsigned L, double beta) -{ - return gnuradio::get_initial_sptr(new digital_cpmmod_bc((gr_cpm::cpm_type)type, - h, samples_per_sym, - L, beta)); -} - - -digital_cpmmod_bc::digital_cpmmod_bc(gr_cpm::cpm_type type, float h, - unsigned samples_per_sym, - unsigned L, double beta) - : gr_hier_block2("digital_cpmmod_bc", - gr_make_io_signature(1, 1, sizeof(char)), - gr_make_io_signature2(1, 1, sizeof(gr_complex), sizeof(float))), - d_taps(gr_cpm::phase_response(type, samples_per_sym, L, beta)), - d_char_to_float(gr_make_char_to_float()), - d_pulse_shaper(gr_make_interp_fir_filter_fff(samples_per_sym, d_taps)), - d_fm(gr_make_frequency_modulator_fc(M_PI * h)) -{ - switch (type) { - case gr_cpm::LRC: - case gr_cpm::LSRC: - case gr_cpm::LREC: - case gr_cpm::TFM: - case gr_cpm::GAUSSIAN: - break; - - default: - throw std::invalid_argument("invalid CPM type"); - } - - connect(self(), 0, d_char_to_float, 0); - connect(d_char_to_float, 0, d_pulse_shaper, 0); - connect(d_pulse_shaper, 0, d_fm, 0); - connect(d_fm, 0, self(), 0); -} - diff --git a/gr-digital/lib/digital_crc32.cc b/gr-digital/lib/digital_crc32.cc deleted file mode 100644 index 8806d6e9c7..0000000000 --- a/gr-digital/lib/digital_crc32.cc +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2011 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. - */ - -/* - * See also ISO 3309 [ISO-3309] or ITU-T V.42 [ITU-V42] for a formal specification. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <digital_crc32.h> - - -// Automatically generated CRC function -// polynomial: 0x104C11DB7 -unsigned int -digital_update_crc32(unsigned int crc, const unsigned char *data, size_t len) -{ - static const unsigned int table[256] = { - 0x00000000U,0x04C11DB7U,0x09823B6EU,0x0D4326D9U, - 0x130476DCU,0x17C56B6BU,0x1A864DB2U,0x1E475005U, - 0x2608EDB8U,0x22C9F00FU,0x2F8AD6D6U,0x2B4BCB61U, - 0x350C9B64U,0x31CD86D3U,0x3C8EA00AU,0x384FBDBDU, - 0x4C11DB70U,0x48D0C6C7U,0x4593E01EU,0x4152FDA9U, - 0x5F15ADACU,0x5BD4B01BU,0x569796C2U,0x52568B75U, - 0x6A1936C8U,0x6ED82B7FU,0x639B0DA6U,0x675A1011U, - 0x791D4014U,0x7DDC5DA3U,0x709F7B7AU,0x745E66CDU, - 0x9823B6E0U,0x9CE2AB57U,0x91A18D8EU,0x95609039U, - 0x8B27C03CU,0x8FE6DD8BU,0x82A5FB52U,0x8664E6E5U, - 0xBE2B5B58U,0xBAEA46EFU,0xB7A96036U,0xB3687D81U, - 0xAD2F2D84U,0xA9EE3033U,0xA4AD16EAU,0xA06C0B5DU, - 0xD4326D90U,0xD0F37027U,0xDDB056FEU,0xD9714B49U, - 0xC7361B4CU,0xC3F706FBU,0xCEB42022U,0xCA753D95U, - 0xF23A8028U,0xF6FB9D9FU,0xFBB8BB46U,0xFF79A6F1U, - 0xE13EF6F4U,0xE5FFEB43U,0xE8BCCD9AU,0xEC7DD02DU, - 0x34867077U,0x30476DC0U,0x3D044B19U,0x39C556AEU, - 0x278206ABU,0x23431B1CU,0x2E003DC5U,0x2AC12072U, - 0x128E9DCFU,0x164F8078U,0x1B0CA6A1U,0x1FCDBB16U, - 0x018AEB13U,0x054BF6A4U,0x0808D07DU,0x0CC9CDCAU, - 0x7897AB07U,0x7C56B6B0U,0x71159069U,0x75D48DDEU, - 0x6B93DDDBU,0x6F52C06CU,0x6211E6B5U,0x66D0FB02U, - 0x5E9F46BFU,0x5A5E5B08U,0x571D7DD1U,0x53DC6066U, - 0x4D9B3063U,0x495A2DD4U,0x44190B0DU,0x40D816BAU, - 0xACA5C697U,0xA864DB20U,0xA527FDF9U,0xA1E6E04EU, - 0xBFA1B04BU,0xBB60ADFCU,0xB6238B25U,0xB2E29692U, - 0x8AAD2B2FU,0x8E6C3698U,0x832F1041U,0x87EE0DF6U, - 0x99A95DF3U,0x9D684044U,0x902B669DU,0x94EA7B2AU, - 0xE0B41DE7U,0xE4750050U,0xE9362689U,0xEDF73B3EU, - 0xF3B06B3BU,0xF771768CU,0xFA325055U,0xFEF34DE2U, - 0xC6BCF05FU,0xC27DEDE8U,0xCF3ECB31U,0xCBFFD686U, - 0xD5B88683U,0xD1799B34U,0xDC3ABDEDU,0xD8FBA05AU, - 0x690CE0EEU,0x6DCDFD59U,0x608EDB80U,0x644FC637U, - 0x7A089632U,0x7EC98B85U,0x738AAD5CU,0x774BB0EBU, - 0x4F040D56U,0x4BC510E1U,0x46863638U,0x42472B8FU, - 0x5C007B8AU,0x58C1663DU,0x558240E4U,0x51435D53U, - 0x251D3B9EU,0x21DC2629U,0x2C9F00F0U,0x285E1D47U, - 0x36194D42U,0x32D850F5U,0x3F9B762CU,0x3B5A6B9BU, - 0x0315D626U,0x07D4CB91U,0x0A97ED48U,0x0E56F0FFU, - 0x1011A0FAU,0x14D0BD4DU,0x19939B94U,0x1D528623U, - 0xF12F560EU,0xF5EE4BB9U,0xF8AD6D60U,0xFC6C70D7U, - 0xE22B20D2U,0xE6EA3D65U,0xEBA91BBCU,0xEF68060BU, - 0xD727BBB6U,0xD3E6A601U,0xDEA580D8U,0xDA649D6FU, - 0xC423CD6AU,0xC0E2D0DDU,0xCDA1F604U,0xC960EBB3U, - 0xBD3E8D7EU,0xB9FF90C9U,0xB4BCB610U,0xB07DABA7U, - 0xAE3AFBA2U,0xAAFBE615U,0xA7B8C0CCU,0xA379DD7BU, - 0x9B3660C6U,0x9FF77D71U,0x92B45BA8U,0x9675461FU, - 0x8832161AU,0x8CF30BADU,0x81B02D74U,0x857130C3U, - 0x5D8A9099U,0x594B8D2EU,0x5408ABF7U,0x50C9B640U, - 0x4E8EE645U,0x4A4FFBF2U,0x470CDD2BU,0x43CDC09CU, - 0x7B827D21U,0x7F436096U,0x7200464FU,0x76C15BF8U, - 0x68860BFDU,0x6C47164AU,0x61043093U,0x65C52D24U, - 0x119B4BE9U,0x155A565EU,0x18197087U,0x1CD86D30U, - 0x029F3D35U,0x065E2082U,0x0B1D065BU,0x0FDC1BECU, - 0x3793A651U,0x3352BBE6U,0x3E119D3FU,0x3AD08088U, - 0x2497D08DU,0x2056CD3AU,0x2D15EBE3U,0x29D4F654U, - 0xC5A92679U,0xC1683BCEU,0xCC2B1D17U,0xC8EA00A0U, - 0xD6AD50A5U,0xD26C4D12U,0xDF2F6BCBU,0xDBEE767CU, - 0xE3A1CBC1U,0xE760D676U,0xEA23F0AFU,0xEEE2ED18U, - 0xF0A5BD1DU,0xF464A0AAU,0xF9278673U,0xFDE69BC4U, - 0x89B8FD09U,0x8D79E0BEU,0x803AC667U,0x84FBDBD0U, - 0x9ABC8BD5U,0x9E7D9662U,0x933EB0BBU,0x97FFAD0CU, - 0xAFB010B1U,0xAB710D06U,0xA6322BDFU,0xA2F33668U, - 0xBCB4666DU,0xB8757BDAU,0xB5365D03U,0xB1F740B4U, - }; - - while (len > 0) - { - crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8); - data++; - len--; - } - return crc; -} - -unsigned int -digital_update_crc32(unsigned int crc, const std::string s) -{ - return digital_update_crc32(crc, (const unsigned char *) s.data(), s.size()); -} - -unsigned int -digital_crc32(const unsigned char *buf, size_t len) -{ - return digital_update_crc32(0xffffffff, buf, len) ^ 0xffffffff; -} - -unsigned int -digital_crc32(const std::string s) -{ - return digital_crc32((const unsigned char *) s.data(), s.size()); -} diff --git a/gr-digital/lib/digital_descrambler_bb.cc b/gr-digital/lib/digital_descrambler_bb.cc deleted file mode 100644 index 68cba7145e..0000000000 --- a/gr-digital/lib/digital_descrambler_bb.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_descrambler_bb.h> -#include <gr_io_signature.h> - -digital_descrambler_bb_sptr -digital_make_descrambler_bb(int mask, int seed, int len) -{ - return gnuradio::get_initial_sptr(new digital_descrambler_bb(mask, seed, len)); -} - -digital_descrambler_bb::digital_descrambler_bb(int mask, int seed, int len) - : gr_sync_block("descrambler_bb", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_lfsr(mask, seed, len) -{ -} - -int -digital_descrambler_bb::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - for (int i = 0; i < noutput_items; i++) - out[i] = d_lfsr.next_bit_descramble(in[i]); - - return noutput_items; -} diff --git a/gr-digital/lib/digital_diff_decoder_bb.cc b/gr-digital/lib/digital_diff_decoder_bb.cc deleted file mode 100644 index 7b8e8726ac..0000000000 --- a/gr-digital/lib/digital_diff_decoder_bb.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_diff_decoder_bb.h> -#include <gr_io_signature.h> - -digital_diff_decoder_bb_sptr -digital_make_diff_decoder_bb (unsigned int modulus) -{ - return gnuradio::get_initial_sptr(new digital_diff_decoder_bb(modulus)); -} - -digital_diff_decoder_bb::digital_diff_decoder_bb (unsigned int modulus) - : gr_sync_block ("diff_decoder_bb", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_modulus(modulus) -{ - set_history(2); // need to look at two inputs -} - -int -digital_diff_decoder_bb::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - in += 1; // ensure that in[-1] is valid - - unsigned modulus = d_modulus; - - for (int i = 0; i < noutput_items; i++) { - out[i] = (in[i] - in[i-1]) % modulus; - } - - return noutput_items; -} diff --git a/gr-digital/lib/digital_diff_encoder_bb.cc b/gr-digital/lib/digital_diff_encoder_bb.cc deleted file mode 100644 index bfbaba98fb..0000000000 --- a/gr-digital/lib/digital_diff_encoder_bb.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_diff_encoder_bb.h> -#include <gr_io_signature.h> - -digital_diff_encoder_bb_sptr -digital_make_diff_encoder_bb (unsigned int modulus) -{ - return gnuradio::get_initial_sptr(new digital_diff_encoder_bb(modulus)); -} - -digital_diff_encoder_bb::digital_diff_encoder_bb (unsigned int modulus) - : gr_sync_block ("diff_encoder_bb", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_last_out(0), d_modulus(modulus) -{ -} - -int -digital_diff_encoder_bb::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - unsigned last_out = d_last_out; - unsigned modulus = d_modulus; - - for (int i = 0; i < noutput_items; i++) { - out[i] = (in[i] + last_out) % modulus; - last_out = out[i]; - } - - d_last_out = last_out; - return noutput_items; -} diff --git a/gr-digital/lib/digital_fll_band_edge_cc.cc b/gr-digital/lib/digital_fll_band_edge_cc.cc deleted file mode 100644 index f2cfb1020a..0000000000 --- a/gr-digital/lib/digital_fll_band_edge_cc.cc +++ /dev/null @@ -1,271 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009-2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_fll_band_edge_cc.h> -#include <gr_io_signature.h> -#include <gr_expj.h> -#include <cstdio> - -#define M_TWOPI (2*M_PI) - -float sinc(float x) -{ - if(x == 0) - return 1; - else - return sin(M_PI*x)/(M_PI*x); -} - -digital_fll_band_edge_cc_sptr -digital_make_fll_band_edge_cc (float samps_per_sym, float rolloff, - int filter_size, float bandwidth) -{ - return gnuradio::get_initial_sptr(new digital_fll_band_edge_cc (samps_per_sym, rolloff, - filter_size, bandwidth)); -} - - -static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; -static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); -digital_fll_band_edge_cc::digital_fll_band_edge_cc(float samps_per_sym, float rolloff, - int filter_size, float bandwidth) - : gr_sync_block("fll_band_edge_cc", - gr_make_io_signature(1, 1, sizeof(gr_complex)), - gr_make_io_signaturev(1, 4, iosig)), - gri_control_loop(bandwidth, M_TWOPI*(2.0/samps_per_sym), -M_TWOPI*(2.0/samps_per_sym)), - d_updated(false) -{ - // Initialize samples per symbol - if(samps_per_sym <= 0) { - throw std::out_of_range("digital_fll_band_edge_cc: invalid number of sps. Must be > 0."); - } - d_sps = samps_per_sym; - - // Initialize rolloff factor - if(rolloff < 0 || rolloff > 1.0) { - throw std::out_of_range("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1]."); - } - d_rolloff = rolloff; - - // Initialize filter length - if(filter_size <= 0) { - throw std::out_of_range("digital_fll_band_edge_cc: invalid filter size. Must be > 0."); - } - d_filter_size = filter_size; - - // Build the band edge filters - design_filter(d_sps, d_rolloff, d_filter_size); - d_output_hist.resize(filter_size,0); -} - -digital_fll_band_edge_cc::~digital_fll_band_edge_cc() -{ -} - - -/******************************************************************* - SET FUNCTIONS -*******************************************************************/ - -void -digital_fll_band_edge_cc::set_samples_per_symbol(float sps) -{ - if(sps <= 0) { - throw std::out_of_range("digital_fll_band_edge_cc: invalid number of sps. Must be > 0."); - } - d_sps = sps; - design_filter(d_sps, d_rolloff, d_filter_size); -} - -void -digital_fll_band_edge_cc::set_rolloff(float rolloff) -{ - if(rolloff < 0 || rolloff > 1.0) { - throw std::out_of_range("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1]."); - } - d_rolloff = rolloff; - design_filter(d_sps, d_rolloff, d_filter_size); -} - -void -digital_fll_band_edge_cc::set_filter_size(int filter_size) -{ - if(filter_size <= 0) { - throw std::out_of_range("digital_fll_band_edge_cc: invalid filter size. Must be > 0."); - } - d_filter_size = filter_size; - design_filter(d_sps, d_rolloff, d_filter_size); -} - -/******************************************************************* - GET FUNCTIONS -*******************************************************************/ - -float -digital_fll_band_edge_cc::get_samples_per_symbol() const -{ - return d_sps; -} - -float -digital_fll_band_edge_cc::get_rolloff() const -{ - return d_rolloff; -} - -int -digital_fll_band_edge_cc:: get_filter_size() const -{ - return d_filter_size; -} - - -/******************************************************************* -*******************************************************************/ - -void -digital_fll_band_edge_cc::design_filter(float samps_per_sym, - float rolloff, int filter_size) -{ - int M = rint(filter_size / samps_per_sym); - float power = 0; - - // Create the baseband filter by adding two sincs together - std::vector<float> bb_taps; - for(int i = 0; i < filter_size; i++) { - float k = -M + i*2.0/samps_per_sym; - float tap = sinc(rolloff*k - 0.5) + sinc(rolloff*k + 0.5); - power += tap; - - bb_taps.push_back(tap); - } - - d_taps_lower.resize(filter_size); - d_taps_upper.resize(filter_size); - - // Create the band edge filters by spinning the baseband - // filter up and down to the right places in frequency. - // Also, normalize the power in the filters - int N = (bb_taps.size() - 1.0)/2.0; - for(int i = 0; i < filter_size; i++) { - float tap = bb_taps[i] / power; - - float k = (-N + (int)i)/(2.0*samps_per_sym); - - gr_complex t1 = tap * gr_expj(-M_TWOPI*(1+rolloff)*k); - gr_complex t2 = tap * gr_expj(M_TWOPI*(1+rolloff)*k); - - d_taps_lower[filter_size-i-1] = t1; - d_taps_upper[filter_size-i-1] = t2; - } - - d_updated = true; - - // Set the history to ensure enough input items for each filter - set_history(filter_size+1); - d_filter_upper = gr_fir_util::create_gr_fir_ccc(d_taps_upper); - d_filter_lower = gr_fir_util::create_gr_fir_ccc(d_taps_lower); -} - -void -digital_fll_band_edge_cc::print_taps() -{ - unsigned int i; - - printf("Upper Band-edge: ["); - for(i = 0; i < d_taps_upper.size(); i++) { - printf(" %.4e + %.4ej,", d_taps_upper[i].real(), d_taps_upper[i].imag()); - } - printf("]\n\n"); - - printf("Lower Band-edge: ["); - for(i = 0; i < d_taps_lower.size(); i++) { - printf(" %.4e + %.4ej,", d_taps_lower[i].real(), d_taps_lower[i].imag()); - } - printf("]\n\n"); -} - -int -digital_fll_band_edge_cc::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]; - - d_fllbuffer.reserve(d_filter_size+noutput_items); - - float *frq = NULL; - float *phs = NULL; - float *err = NULL; - if(output_items.size() == 4) { - frq = (float*)output_items[1]; - phs = (float*)output_items[2]; - err = (float*)output_items[3]; - } - - if(d_updated) { - d_updated = false; - return 0; // history requirements may have changed. - } - - int i; - float error; - gr_complex nco_out; - gr_complex out_upper, out_lower; - gr_complex out_uppersse, out_lowersse; - copy( d_output_hist.begin(), d_output_hist.end(), d_fllbuffer.begin()); - - for(i = 0; i < noutput_items; i++) { - nco_out = gr_expj(d_phase); - d_fllbuffer[i+d_filter_size] = in[i] * nco_out; - // Perform the dot product of the output with the filters - out_upper = 0; - out_lower = 0; - - out_upper = d_filter_lower->filter(&d_fllbuffer[i]); - out_lower = d_filter_upper->filter(&d_fllbuffer[i]); - - error = norm(out_lower) - norm(out_upper); - - advance_loop(error); - phase_wrap(); - frequency_limit(); - - if(output_items.size() == 4) { - frq[i] = d_freq; - phs[i] = d_phase; - err[i] = error; - } - } - - copy(d_fllbuffer.begin(), d_fllbuffer.begin()+noutput_items, out); - copy(d_fllbuffer.begin()+noutput_items, - d_fllbuffer.begin()+noutput_items+d_filter_size, - d_output_hist.begin()); - - return noutput_items; -} diff --git a/gr-digital/lib/digital_framer_sink_1.cc b/gr-digital/lib/digital_framer_sink_1.cc deleted file mode 100644 index ba1c5bd50e..0000000000 --- a/gr-digital/lib/digital_framer_sink_1.cc +++ /dev/null @@ -1,192 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2006,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_framer_sink_1.h> -#include <gr_io_signature.h> -#include <cstdio> -#include <stdexcept> -#include <string.h> - -#define VERBOSE 0 - -inline void -digital_framer_sink_1::enter_search() -{ - if (VERBOSE) - fprintf(stderr, "@ enter_search\n"); - - d_state = STATE_SYNC_SEARCH; -} - -inline void -digital_framer_sink_1::enter_have_sync() -{ - if (VERBOSE) - fprintf(stderr, "@ enter_have_sync\n"); - - d_state = STATE_HAVE_SYNC; - d_header = 0; - d_headerbitlen_cnt = 0; -} - -inline void -digital_framer_sink_1::enter_have_header(int payload_len, - int whitener_offset) -{ - if (VERBOSE) - fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n", - payload_len, whitener_offset); - - d_state = STATE_HAVE_HEADER; - d_packetlen = payload_len; - d_packet_whitener_offset = whitener_offset; - d_packetlen_cnt = 0; - d_packet_byte = 0; - d_packet_byte_index = 0; -} - -digital_framer_sink_1_sptr -digital_make_framer_sink_1(gr_msg_queue_sptr target_queue) -{ - return gnuradio::get_initial_sptr(new digital_framer_sink_1(target_queue)); -} - - -digital_framer_sink_1::digital_framer_sink_1(gr_msg_queue_sptr target_queue) - : gr_sync_block ("framer_sink_1", - gr_make_io_signature (1, 1, sizeof(unsigned char)), - gr_make_io_signature (0, 0, 0)), - d_target_queue(target_queue) -{ - enter_search(); -} - -digital_framer_sink_1::~digital_framer_sink_1 () -{ -} - -int -digital_framer_sink_1::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - int count=0; - - if (VERBOSE) - fprintf(stderr,">>> Entering state machine\n"); - - while (count < noutput_items){ - switch(d_state) { - - case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt - if (VERBOSE) - fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items); - - while (count < noutput_items) { - if (in[count] & 0x2){ // Found it, set up for header decode - enter_have_sync(); - break; - } - count++; - } - break; - - case STATE_HAVE_SYNC: - if (VERBOSE) - fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n", - d_headerbitlen_cnt, d_header); - - while (count < noutput_items) { // Shift bits one at a time into header - d_header = (d_header << 1) | (in[count++] & 0x1); - if (++d_headerbitlen_cnt == HEADERBITLEN) { - - if (VERBOSE) - fprintf(stderr, "got header: 0x%08x\n", d_header); - - // we have a full header, check to see if it has been received properly - if (header_ok()){ - int payload_len; - int whitener_offset; - header_payload(&payload_len, &whitener_offset); - enter_have_header(payload_len, whitener_offset); - - if (d_packetlen == 0){ // check for zero-length payload - // build a zero-length message - // NOTE: passing header field as arg1 is not scalable - gr_message_sptr msg = - gr_make_message(0, d_packet_whitener_offset, 0, 0); - - d_target_queue->insert_tail(msg); // send it - msg.reset(); // free it up - - enter_search(); - } - } - else - enter_search(); // bad header - break; // we're in a new state - } - } - break; - - case STATE_HAVE_HEADER: - if (VERBOSE) - fprintf(stderr,"Packet Build\n"); - - while (count < noutput_items) { // shift bits into bytes of packet one at a time - d_packet_byte = (d_packet_byte << 1) | (in[count++] & 0x1); - if (d_packet_byte_index++ == 7) { // byte is full so move to next byte - d_packet[d_packetlen_cnt++] = d_packet_byte; - d_packet_byte_index = 0; - - if (d_packetlen_cnt == d_packetlen){ // packet is filled - - // build a message - // NOTE: passing header field as arg1 is not scalable - gr_message_sptr msg = - gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt); - memcpy(msg->msg(), d_packet, d_packetlen_cnt); - - d_target_queue->insert_tail(msg); // send it - msg.reset(); // free it up - - enter_search(); - break; - } - } - } - break; - - default: - assert(0); - - } // switch - - } // while - - return noutput_items; -} diff --git a/gr-digital/lib/digital_glfsr_source_b.cc b/gr-digital/lib/digital_glfsr_source_b.cc deleted file mode 100644 index e557e475a8..0000000000 --- a/gr-digital/lib/digital_glfsr_source_b.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2010,2012 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. - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_glfsr_source_b.h> -#include <gri_glfsr.h> -#include <gr_io_signature.h> -#include <stdexcept> - -digital_glfsr_source_b_sptr -digital_make_glfsr_source_b(int degree, bool repeat, int mask, int seed) -{ - return gnuradio::get_initial_sptr(new digital_glfsr_source_b - (degree, repeat, mask, seed)); -} - -digital_glfsr_source_b::digital_glfsr_source_b(int degree, bool repeat, - int mask, int seed) - : gr_sync_block ("glfsr_source_b", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (1, 1, sizeof(unsigned char))), - d_repeat(repeat), - d_index(0) -{ - if (degree < 1 || degree > 32) - throw std::runtime_error("digital_glfsr_source_b: degree must be between 1 and 32 inclusive"); - d_length = (unsigned int)((1ULL << degree)-1); - - if (mask == 0) - mask = gri_glfsr::glfsr_mask(degree); - d_glfsr = new gri_glfsr(mask, seed); -} - -digital_glfsr_source_b::~digital_glfsr_source_b() -{ - delete d_glfsr; -} - -int -digital_glfsr_source_b::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - char *out = (char *) output_items[0]; - if ((d_index > d_length) && d_repeat == false) - return -1; /* once through the sequence */ - - int i; - for (i = 0; i < noutput_items; i++) { - out[i] = d_glfsr->next_bit(); - d_index++; - if (d_index > d_length && d_repeat == false) - break; - } - - return i; -} - -int -digital_glfsr_source_b::mask() const -{ - return d_glfsr->mask(); -} diff --git a/gr-digital/lib/digital_glfsr_source_f.cc b/gr-digital/lib/digital_glfsr_source_f.cc deleted file mode 100644 index 5a7736ef8d..0000000000 --- a/gr-digital/lib/digital_glfsr_source_f.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2010,2012 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. - */ - - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_glfsr_source_f.h> -#include <gri_glfsr.h> -#include <gr_io_signature.h> -#include <stdexcept> - -digital_glfsr_source_f_sptr -digital_make_glfsr_source_f(int degree, bool repeat, int mask, int seed) -{ - return gnuradio::get_initial_sptr(new digital_glfsr_source_f - (degree, repeat, mask, seed)); -} - -digital_glfsr_source_f::digital_glfsr_source_f(int degree, bool repeat, - int mask, int seed) - : gr_sync_block ("glfsr_source_f", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (1, 1, sizeof(float))), - d_repeat(repeat), - d_index(0) -{ - if (degree < 1 || degree > 32) - throw std::runtime_error("digital_glfsr_source_f: degree must be between 1 and 32 inclusive"); - d_length = (unsigned int)((1ULL << degree)-1); - - if (mask == 0) - mask = gri_glfsr::glfsr_mask(degree); - d_glfsr = new gri_glfsr(mask, seed); -} - -digital_glfsr_source_f::~digital_glfsr_source_f() -{ - delete d_glfsr; -} - -int -digital_glfsr_source_f::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - float *out = (float *) output_items[0]; - if ((d_index > d_length) && d_repeat == false) - return -1; /* once through the sequence */ - - int i; - for (i = 0; i < noutput_items; i++) { - out[i] = (float)d_glfsr->next_bit()*2.0-1.0; - d_index++; - if (d_index > d_length && d_repeat == false) - break; - } - - return i; -} - -int -digital_glfsr_source_f::mask() const -{ - return d_glfsr->mask(); -} diff --git a/gr-digital/lib/digital_impl_glfsr.cc b/gr-digital/lib/digital_impl_glfsr.cc deleted file mode 100644 index 342980e535..0000000000 --- a/gr-digital/lib/digital_impl_glfsr.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2012 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. - */ - -#include <digital_impl_glfsr.h> -#include <stdexcept> - -static int s_polynomial_masks[] = { - 0x00000000, - 0x00000001, // x^1 + 1 - 0x00000003, // x^2 + x^1 + 1 - 0x00000005, // x^3 + x^1 + 1 - 0x00000009, // x^4 + x^1 + 1 - 0x00000012, // x^5 + x^2 + 1 - 0x00000021, // x^6 + x^1 + 1 - 0x00000041, // x^7 + x^1 + 1 - 0x0000008E, // x^8 + x^4 + x^3 + x^2 + 1 - 0x00000108, // x^9 + x^4 + 1 - 0x00000204, // x^10 + x^4 + 1 - 0x00000402, // x^11 + x^2 + 1 - 0x00000829, // x^12 + x^6 + x^4 + x^1 + 1 - 0x0000100D, // x^13 + x^4 + x^3 + x^1 + 1 - 0x00002015, // x^14 + x^5 + x^3 + x^1 + 1 - 0x00004001, // x^15 + x^1 + 1 - 0x00008016, // x^16 + x^5 + x^3 + x^2 + 1 - 0x00010004, // x^17 + x^3 + 1 - 0x00020013, // x^18 + x^5 + x^2 + x^1 + 1 - 0x00040013, // x^19 + x^5 + x^2 + x^1 + 1 - 0x00080004, // x^20 + x^3 + 1 - 0x00100002, // x^21 + x^2 + 1 - 0x00200001, // x^22 + x^1 + 1 - 0x00400010, // x^23 + x^5 + 1 - 0x0080000D, // x^24 + x^4 + x^3 + x^1 + 1 - 0x01000004, // x^25 + x^3 + 1 - 0x02000023, // x^26 + x^6 + x^2 + x^1 + 1 - 0x04000013, // x^27 + x^5 + x^2 + x^1 + 1 - 0x08000004, // x^28 + x^3 + 1 - 0x10000002, // x^29 + x^2 + 1 - 0x20000029, // x^30 + x^4 + x^1 + 1 - 0x40000004, // x^31 + x^3 + 1 - 0x80000057 // x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + 1 -}; - -int digital_impl_glfsr::glfsr_mask(int degree) -{ - if (degree < 1 || degree > 32) - throw std::runtime_error("digital_impl_glfsr::glfsr_mask(): degree must be between 1 and 32 inclusive"); - return s_polynomial_masks[degree]; -} diff --git a/gr-digital/lib/digital_impl_mpsk_snr_est.cc b/gr-digital/lib/digital_impl_mpsk_snr_est.cc deleted file mode 100644 index 38177083fc..0000000000 --- a/gr-digital/lib/digital_impl_mpsk_snr_est.cc +++ /dev/null @@ -1,256 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_impl_mpsk_snr_est.h> -#include <cstdio> - -digital_impl_mpsk_snr_est::digital_impl_mpsk_snr_est(double alpha) -{ - set_alpha(alpha); -} - -digital_impl_mpsk_snr_est::~digital_impl_mpsk_snr_est() -{} - -void -digital_impl_mpsk_snr_est::set_alpha(double alpha) -{ - d_alpha = alpha; - d_beta = 1.0-alpha; -} - -double -digital_impl_mpsk_snr_est::alpha() const -{ - return d_alpha; -} - -int -digital_impl_mpsk_snr_est::update(int noutput_items, - const gr_complex *in) -{ - throw std::runtime_error("digital_impl_mpsk_snr_est: Unimplemented"); -} - -double -digital_impl_mpsk_snr_est::snr() -{ - throw std::runtime_error("digital_impl_mpsk_snr_est: Unimplemented"); -} - - -/********************************************************************/ - - -digital_impl_mpsk_snr_est_simple::digital_impl_mpsk_snr_est_simple( - double alpha) : - digital_impl_mpsk_snr_est(alpha) -{ - d_y1 = 0; - d_y2 = 0; -} - -int -digital_impl_mpsk_snr_est_simple::update( - int noutput_items, - const gr_complex *in) -{ - for (int i = 0; i < noutput_items; i++){ - double y1 = abs(in[i]); - d_y1 = d_alpha*y1 + d_beta*d_y1; - - double y2 = real(in[i]*in[i]); - d_y2 = d_alpha*y2 + d_beta*d_y2; - } - return noutput_items; -} - -double -digital_impl_mpsk_snr_est_simple::snr() -{ - double y1_2 = d_y1*d_y1; - double y3 = y1_2 - d_y2 + 1e-20; - return 10.0*log10(y1_2/y3); -} - - -/********************************************************************/ - - -digital_impl_mpsk_snr_est_skew::digital_impl_mpsk_snr_est_skew( - double alpha) : - digital_impl_mpsk_snr_est(alpha) -{ - d_y1 = 0; - d_y2 = 0; - d_y3 = 0; -} - - -int -digital_impl_mpsk_snr_est_skew::update( - int noutput_items, - const gr_complex *in) -{ - for (int i = 0; i < noutput_items; i++){ - double y1 = abs(in[i]); - d_y1 = d_alpha*y1 + d_beta*d_y1; - - double y2 = real(in[i]*in[i]); - d_y2 = d_alpha*y2 + d_beta*d_y2; - - // online algorithm for calculating skewness - // See: - // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Higher-order_statistics - double d = abs(in[i]) - d_y1; - double d_i = d / (i+1); - double y3 = (d*d_i*i)*d_i*(i-1) - 3.0*d_i*d_y2; - d_y3 = d_alpha*y3 + d_beta*d_y3; - } - return noutput_items; -} - -double -digital_impl_mpsk_snr_est_skew::snr() -{ - double y3 = d_y3*d_y3 / (d_y2*d_y2*d_y2); - double y1_2 = d_y1*d_y1; - double x = y1_2 - d_y2; - return 10.0*log10(y1_2 / (x + y3*y1_2)); -} - - -/********************************************************************/ - - -digital_impl_mpsk_snr_est_m2m4::digital_impl_mpsk_snr_est_m2m4( - double alpha) : - digital_impl_mpsk_snr_est(alpha) -{ - d_y1 = 0; - d_y2 = 0; -} - -int -digital_impl_mpsk_snr_est_m2m4::update( - int noutput_items, - const gr_complex *in) -{ - for (int i = 0; i < noutput_items; i++){ - double y1 = abs(in[i])*abs(in[i]); - d_y1 = d_alpha*y1 + d_beta*d_y1; - - double y2 = abs(in[i])*abs(in[i])*abs(in[i])*abs(in[i]); - d_y2 = d_alpha*y2 + d_beta*d_y2; - } - return noutput_items; -} - -double -digital_impl_mpsk_snr_est_m2m4::snr() -{ - double y1_2 = d_y1*d_y1; - return 10.0*log10(2.0*sqrt(2*y1_2 - d_y2) / - (d_y1 - sqrt(2*y1_2 - d_y2))); -} - - -/********************************************************************/ - - -digital_impl_snr_est_m2m4::digital_impl_snr_est_m2m4( - double alpha, double ka, double kw) : - digital_impl_mpsk_snr_est(alpha) -{ - d_y1 = 0; - d_y2 = 0; - d_ka = ka; - d_kw = kw; -} - -int -digital_impl_snr_est_m2m4::update( - int noutput_items, - const gr_complex *in) -{ - for (int i = 0; i < noutput_items; i++) { - double y1 = abs(in[i])*abs(in[i]); - d_y1 = d_alpha*y1 + d_beta*d_y1; - - double y2 = abs(in[i])*abs(in[i])*abs(in[i])*abs(in[i]); - d_y2 = d_alpha*y2 + d_beta*d_y2; - } - return noutput_items; -} - -double -digital_impl_snr_est_m2m4::snr() -{ - double M2 = d_y1; - double M4 = d_y2; - double s = M2*(d_kw - 2) + - sqrt((4.0-d_ka*d_kw)*M2*M2 + M4*(d_ka+d_kw-4.0)) / - (d_ka + d_kw - 4.0); - double n = M2 - s; - - return 10.0*log10(s / n); -} - - -/********************************************************************/ - - -digital_impl_mpsk_snr_est_svr::digital_impl_mpsk_snr_est_svr( - double alpha) : - digital_impl_mpsk_snr_est(alpha) -{ - d_y1 = 0; - d_y2 = 0; -} - -int -digital_impl_mpsk_snr_est_svr::update( - int noutput_items, - const gr_complex *in) -{ - for (int i = 0; i < noutput_items; i++){ - double x = abs(in[i]); - double x1 = abs(in[i-1]); - double y1 = (x*x)*(x1*x1); - d_y1 = d_alpha*y1 + d_beta*d_y1; - - double y2 = x*x*x*x; - d_y2 = d_alpha*y2 + d_beta*d_y2; - } - return noutput_items; -} - -double -digital_impl_mpsk_snr_est_svr::snr() -{ - double x = d_y1 / (d_y2 - d_y1); - return 10.0*log10(2.*((x-1) + sqrt(x*(x-1)))); -} diff --git a/gr-digital/lib/digital_lms_dd_equalizer_cc.cc b/gr-digital/lib/digital_lms_dd_equalizer_cc.cc deleted file mode 100644 index e2c2f16f28..0000000000 --- a/gr-digital/lib/digital_lms_dd_equalizer_cc.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_lms_dd_equalizer_cc.h> -#include <gr_io_signature.h> -#include <gr_misc.h> -#include <iostream> - -digital_lms_dd_equalizer_cc_sptr -digital_make_lms_dd_equalizer_cc(int num_taps, float mu, int sps, - digital_constellation_sptr cnst) -{ - return gnuradio::get_initial_sptr(new digital_lms_dd_equalizer_cc(num_taps, mu, - sps, cnst)); -} - -digital_lms_dd_equalizer_cc::digital_lms_dd_equalizer_cc(int num_taps, float mu, - int sps, - digital_constellation_sptr cnst) - : gr_adaptive_fir_ccc("lms_dd_equalizer_cc", sps, - std::vector<gr_complex>(num_taps, gr_complex(0,0))), - d_taps(num_taps), d_cnst(cnst) -{ - set_gain(mu); - if (num_taps > 0) - d_taps[num_taps/2] = 1.0; -} - - - - -/* -int -digital_lms_dd_equalizer_cc::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]; - - gr_complex acc, decision, error; - - for(int i = 0; i < noutput_items; i++) { - acc = 0; - - // Compute output - for (size_t j=0; j < d_taps.size(); j++) - acc += in[i+j] * conj(d_taps[j]); - - d_cnst->map_to_points(d_cnst->decision_maker(&acc), &decision); - error = decision - acc; - - // Update taps - for (size_t j=0; j < d_taps.size(); j++) - d_taps[j] += d_mu * conj(error) * in[i+j]; - - out[i] = acc; - } - - return noutput_items; -} -*/ diff --git a/gr-digital/lib/digital_map_bb.cc b/gr-digital/lib/digital_map_bb.cc deleted file mode 100644 index 1d8444a405..0000000000 --- a/gr-digital/lib/digital_map_bb.cc +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_map_bb.h> -#include <gr_io_signature.h> - -digital_map_bb_sptr -digital_make_map_bb (const std::vector<int> &map) -{ - return gnuradio::get_initial_sptr(new digital_map_bb (map)); -} - -digital_map_bb::digital_map_bb (const std::vector<int> &map) - : gr_sync_block ("map_bb", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))) -{ - for (int i = 0; i < 0x100; i++) - d_map[i] = i; - - unsigned int size = std::min((size_t) 0x100, map.size()); - for (unsigned int i = 0; i < size; i++) - d_map[i] = map[i]; -} - -int -digital_map_bb::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - for (int i = 0; i < noutput_items; i++) - out[i] = d_map[in[i]]; - - return noutput_items; -} diff --git a/gr-digital/lib/digital_mpsk_receiver_cc.cc b/gr-digital/lib/digital_mpsk_receiver_cc.cc deleted file mode 100644 index 6d2bab8a4e..0000000000 --- a/gr-digital/lib/digital_mpsk_receiver_cc.cc +++ /dev/null @@ -1,329 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2006,2007,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <digital_mpsk_receiver_cc.h> -#include <stdexcept> -#include <gr_math.h> -#include <gr_expj.h> -#include <gri_mmse_fir_interpolator_cc.h> - - -#define M_TWOPI (2*M_PI) -#define VERBOSE_MM 0 // Used for debugging symbol timing loop -#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking - -// Public constructor - -digital_mpsk_receiver_cc_sptr -digital_make_mpsk_receiver_cc(unsigned int M, float theta, - float loop_bw, - float fmin, float fmax, - float mu, float gain_mu, - float omega, float gain_omega, float omega_rel) -{ - return gnuradio::get_initial_sptr(new digital_mpsk_receiver_cc (M, theta, - loop_bw, - fmin, fmax, - mu, gain_mu, - omega, gain_omega, - omega_rel)); -} - -digital_mpsk_receiver_cc::digital_mpsk_receiver_cc (unsigned int M, float theta, - float loop_bw, - float fmin, float fmax, - float mu, float gain_mu, - float omega, float gain_omega, - float omega_rel) - : gr_block ("mpsk_receiver_cc", - gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (gr_complex))), - gri_control_loop(loop_bw, fmax, fmin), - d_M(M), d_theta(theta), - d_current_const_point(0), - d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega), - d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0), - d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0) -{ - d_interp = new gri_mmse_fir_interpolator_cc(); - d_dl_idx = 0; - - set_omega(omega); - - if (omega <= 0.0) - throw std::out_of_range ("clock rate must be > 0"); - if (gain_mu < 0 || gain_omega < 0) - throw std::out_of_range ("Gains must be non-negative"); - - assert(d_interp->ntaps() <= DLLEN); - - // zero double length delay line. - for (unsigned int i = 0; i < 2 * DLLEN; i++) - d_dl[i] = gr_complex(0.0,0.0); - - set_modulation_order(d_M); -} - -digital_mpsk_receiver_cc::~digital_mpsk_receiver_cc () -{ - delete d_interp; -} - -void -digital_mpsk_receiver_cc::set_modulation_order(unsigned int M) -{ - // build the constellation vector from M - make_constellation(); - - // Select a phase detector and a decision maker for the modulation order - switch(d_M) { - case 2: // optimized algorithms for BPSK - d_phase_error_detector = &digital_mpsk_receiver_cc::phase_error_detector_bpsk; //bpsk; - d_decision = &digital_mpsk_receiver_cc::decision_bpsk; - break; - - case 4: // optimized algorithms for QPSK - d_phase_error_detector = &digital_mpsk_receiver_cc::phase_error_detector_qpsk; //qpsk; - d_decision = &digital_mpsk_receiver_cc::decision_qpsk; - break; - - default: // generic algorithms for any M (power of 2?) but not pretty - d_phase_error_detector = &digital_mpsk_receiver_cc::phase_error_detector_generic; - d_decision = &digital_mpsk_receiver_cc::decision_generic; - break; - } -} - -void -digital_mpsk_receiver_cc::set_gain_omega_rel(float omega_rel) -{ - d_omega_rel = omega_rel; - set_omega(d_omega); -} - -void -digital_mpsk_receiver_cc::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] = (int) ceil((noutput_items * d_omega) + d_interp->ntaps()); -} - -// FIXME add these back in an test difference in performance -float -digital_mpsk_receiver_cc::phase_error_detector_qpsk(gr_complex sample) const -{ - float phase_error = 0; - if(fabsf(sample.real()) > fabsf(sample.imag())) { - if(sample.real() > 0) - phase_error = -sample.imag(); - else - phase_error = sample.imag(); - } - else { - if(sample.imag() > 0) - phase_error = sample.real(); - else - phase_error = -sample.real(); - } - - return phase_error; -} - -float -digital_mpsk_receiver_cc::phase_error_detector_bpsk(gr_complex sample) const -{ - return -(sample.real()*sample.imag()); -} - -float digital_mpsk_receiver_cc::phase_error_detector_generic(gr_complex sample) const -{ - //return gr_fast_atan2f(sample*conj(d_constellation[d_current_const_point])); - return -arg(sample*conj(d_constellation[d_current_const_point])); -} - -unsigned int -digital_mpsk_receiver_cc::decision_bpsk(gr_complex sample) const -{ - return (gr_branchless_binary_slicer(sample.real()) ^ 1); - //return gr_binary_slicer(sample.real()) ^ 1; -} - -unsigned int -digital_mpsk_receiver_cc::decision_qpsk(gr_complex sample) const -{ - unsigned int index; - - //index = gr_branchless_quad_0deg_slicer(sample); - index = gr_quad_0deg_slicer(sample); - return index; -} - -unsigned int -digital_mpsk_receiver_cc::decision_generic(gr_complex sample) const -{ - unsigned int min_m = 0; - float min_s = 65535; - - // Develop all possible constellation points and find the one that minimizes - // the Euclidean distance (error) with the sample - for(unsigned int m=0; m < d_M; m++) { - gr_complex diff = norm(d_constellation[m] - sample); - - if(fabs(diff.real()) < min_s) { - min_s = fabs(diff.real()); - min_m = m; - } - } - // Return the index of the constellation point that minimizes the error - return min_m; -} - - -void -digital_mpsk_receiver_cc::make_constellation() -{ - for(unsigned int m=0; m < d_M; m++) { - d_constellation.push_back(gr_expj((M_TWOPI/d_M)*m)); - } -} - -void -digital_mpsk_receiver_cc::mm_sampler(const gr_complex symbol) -{ - gr_complex sample, nco; - - d_mu--; // skip a number of symbols between sampling - d_phase += d_freq; // increment the phase based on the frequency of the rotation - - // Keep phase clamped and not walk to infinity - while(d_phase > M_TWOPI) - d_phase -= M_TWOPI; - while(d_phase < -M_TWOPI) - d_phase += M_TWOPI; - - nco = gr_expj(d_phase+d_theta); // get the NCO value for derotating the current sample - sample = nco*symbol; // get the downconverted symbol - - // Fill up the delay line for the interpolator - d_dl[d_dl_idx] = sample; - d_dl[(d_dl_idx + DLLEN)] = sample; // put this in the second half of the buffer for overflows - d_dl_idx = (d_dl_idx+1) % DLLEN; // Keep the delay line index in bounds -} - -void -digital_mpsk_receiver_cc::mm_error_tracking(gr_complex sample) -{ - gr_complex u, x, y; - float mm_error = 0; - - // Make sample timing corrections - - // set the delayed samples - d_p_2T = d_p_1T; - d_p_1T = d_p_0T; - d_p_0T = sample; - d_c_2T = d_c_1T; - d_c_1T = d_c_0T; - - d_current_const_point = (*this.*d_decision)(d_p_0T); // make a decision on the sample value - d_c_0T = d_constellation[d_current_const_point]; - - x = (d_c_0T - d_c_2T) * conj(d_p_1T); - y = (d_p_0T - d_p_2T) * conj(d_c_1T); - u = y - x; - mm_error = u.real(); // the error signal is in the real part - mm_error = gr_branchless_clip(mm_error, 1.0); // limit mm_val - - d_omega = d_omega + d_gain_omega * mm_error; // update omega based on loop error - d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_rel); // make sure we don't walk away - - d_mu += d_omega + d_gain_mu * mm_error; // update mu based on loop error - -#if VERBOSE_MM - printf("mm: mu: %f omega: %f mm_error: %f sample: %f+j%f constellation: %f+j%f\n", - d_mu, d_omega, mm_error, sample.real(), sample.imag(), - d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag()); -#endif -} - - -void -digital_mpsk_receiver_cc::phase_error_tracking(gr_complex sample) -{ - float phase_error = 0; - - // Make phase and frequency corrections based on sampled value - phase_error = (*this.*d_phase_error_detector)(sample); - - advance_loop(phase_error); - phase_wrap(); - frequency_limit(); - -#if VERBOSE_COSTAS - printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n", - phase_error, d_phase, d_freq, sample.real(), sample.imag(), - d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag()); -#endif -} - -int -digital_mpsk_receiver_cc::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 i=0, o=0; - - while((o < noutput_items) && (i < ninput_items[0])) { - while((d_mu > 1) && (i < ninput_items[0])) { - mm_sampler(in[i]); // puts symbols into a buffer and adjusts d_mu - i++; - } - - if(i < ninput_items[0]) { - gr_complex interp_sample = d_interp->interpolate(&d_dl[d_dl_idx], d_mu); - - mm_error_tracking(interp_sample); // corrects M&M sample time - phase_error_tracking(interp_sample); // corrects phase and frequency offsets - - out[o++] = interp_sample; - } - } - - #if 0 - printf("ninput_items: %d noutput_items: %d consuming: %d returning: %d\n", - ninput_items[0], noutput_items, i, o); - #endif - - consume_each(i); - return o; -} diff --git a/gr-digital/lib/digital_mpsk_snr_est_cc.cc b/gr-digital/lib/digital_mpsk_snr_est_cc.cc deleted file mode 100644 index b5a60f0d38..0000000000 --- a/gr-digital/lib/digital_mpsk_snr_est_cc.cc +++ /dev/null @@ -1,186 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_mpsk_snr_est_cc.h> -#include <gr_io_signature.h> -#include <cstdio> - -digital_mpsk_snr_est_cc_sptr -digital_make_mpsk_snr_est_cc(snr_est_type_t type, - int tag_nsamples, - double alpha) -{ - return gnuradio::get_initial_sptr(new digital_mpsk_snr_est_cc( - type, tag_nsamples, alpha)); -} - -digital_mpsk_snr_est_cc::digital_mpsk_snr_est_cc(snr_est_type_t type, - int tag_nsamples, - double alpha) - : gr_sync_block ("mpsk_snr_est_cc", - gr_make_io_signature(1, 1, sizeof(gr_complex)), - gr_make_io_signature(1, 1, sizeof(gr_complex))) -{ - d_snr_est = NULL; - - d_type = type; - d_nsamples = tag_nsamples; - d_count = 0; - set_alpha(alpha); - - set_type(type); - - // at least 1 estimator has to look back - set_history(2); - - std::stringstream str; - str << name() << unique_id(); - d_me = pmt::pmt_string_to_symbol(str.str()); - d_key = pmt::pmt_string_to_symbol("snr"); -} - -digital_mpsk_snr_est_cc::~digital_mpsk_snr_est_cc() -{ - if(d_snr_est) - delete d_snr_est; -} - -int -digital_mpsk_snr_est_cc::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - // This is a pass-through block; copy input to output - memcpy(output_items[0], input_items[0], - noutput_items * sizeof(gr_complex)); - - const gr_complex *in = (const gr_complex*)input_items[0]; - - // Update, calculate, and issue an SNR tag every d_nsamples - int index = 0, x = 0; - int64_t nwritten = nitems_written(0); - while(index + (d_nsamples-d_count) <= noutput_items) { - x = d_nsamples - d_count; - nwritten += x; - - // Update the SNR estimate registers from the current input - d_snr_est->update(x, &in[index]); - - // Issue a tag with the SNR data - pmt::pmt_t pmt_snr = pmt::pmt_from_double(d_snr_est->snr()); - add_item_tag(0, // stream ID - nwritten, // tag's sample number - d_key, // snr key - pmt_snr, // SNR - d_me); // block src id - - index += x; - d_count = 0; - } - - // Keep track of remaining items and update estimators - x = noutput_items - index; - d_count += x; - d_snr_est->update(x, &in[index]); - - return noutput_items; -} - -double -digital_mpsk_snr_est_cc::snr() -{ - if(d_snr_est) - return d_snr_est->snr(); - else - throw std::runtime_error("digital_mpsk_snr_est_cc:: No SNR estimator defined.\n"); -} - -snr_est_type_t -digital_mpsk_snr_est_cc::type() const -{ - return d_type; -} - -int -digital_mpsk_snr_est_cc::tag_nsample() const -{ - return d_nsamples; -} - -double -digital_mpsk_snr_est_cc::alpha() const -{ - return d_alpha; -} - -void -digital_mpsk_snr_est_cc::set_type(snr_est_type_t t) -{ - d_type = t; - - if(d_snr_est) - delete d_snr_est; - - switch (d_type) { - case(SNR_EST_SIMPLE): - d_snr_est = new digital_impl_mpsk_snr_est_simple(d_alpha); - break; - case(SNR_EST_SKEW): - d_snr_est = new digital_impl_mpsk_snr_est_skew(d_alpha); - break; - case(SNR_EST_M2M4): - d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); - break; - case(SNR_EST_SVR): - d_snr_est = new digital_impl_mpsk_snr_est_svr(d_alpha); - break; - default: - throw std::invalid_argument("digital_mpsk_snr_est_cc: unknown type specified.\n"); - } -} - -void -digital_mpsk_snr_est_cc::set_tag_nsample(int n) -{ - if(n > 0) { - d_nsamples = n; - d_count = 0; // reset state - } - else - throw std::invalid_argument("digital_mpsk_snr_est_cc: tag_nsamples can't be <= 0\n"); -} - -void -digital_mpsk_snr_est_cc::set_alpha(double alpha) -{ - if((alpha >= 0) && (alpha <= 1.0)) { - d_alpha = alpha; - if(d_snr_est) - d_snr_est->set_alpha(d_alpha); - } - else - throw std::invalid_argument("digital_mpsk_snr_est_cc: alpha must be in [0,1]\n"); -} diff --git a/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc b/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc deleted file mode 100644 index 192af2591d..0000000000 --- a/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2006,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_ofdm_cyclic_prefixer.h> -#include <gr_io_signature.h> - -digital_ofdm_cyclic_prefixer_sptr -digital_make_ofdm_cyclic_prefixer (size_t input_size, size_t output_size) -{ - return gnuradio::get_initial_sptr(new digital_ofdm_cyclic_prefixer (input_size, - output_size)); -} - -digital_ofdm_cyclic_prefixer::digital_ofdm_cyclic_prefixer (size_t input_size, - size_t output_size) - : gr_sync_interpolator ("ofdm_cyclic_prefixer", - gr_make_io_signature (1, 1, input_size*sizeof(gr_complex)), - gr_make_io_signature (1, 1, sizeof(gr_complex)), - output_size), - d_input_size(input_size), - d_output_size(output_size) - -{ -} - -int -digital_ofdm_cyclic_prefixer::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - gr_complex *in = (gr_complex *) input_items[0]; - gr_complex *out = (gr_complex *) output_items[0]; - size_t cp_size = d_output_size - d_input_size; - unsigned int i=0, j=0; - - j = cp_size; - for(i=0; i < d_input_size; i++,j++) { - out[j] = in[i]; - } - - j = d_input_size - cp_size; - for(i=0; i < cp_size; i++, j++) { - out[i] = in[j]; - } - - return d_output_size; -} diff --git a/gr-digital/lib/digital_ofdm_frame_acquisition.cc b/gr-digital/lib/digital_ofdm_frame_acquisition.cc deleted file mode 100644 index 93b58aeca5..0000000000 --- a/gr-digital/lib/digital_ofdm_frame_acquisition.cc +++ /dev/null @@ -1,210 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2008,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_ofdm_frame_acquisition.h> -#include <gr_io_signature.h> -#include <gr_expj.h> -#include <gr_math.h> -#include <cstdio> - -#define VERBOSE 0 -#define M_TWOPI (2*M_PI) -#define MAX_NUM_SYMBOLS 1000 - -digital_ofdm_frame_acquisition_sptr -digital_make_ofdm_frame_acquisition (unsigned int occupied_carriers, - unsigned int fft_length, - unsigned int cplen, - const std::vector<gr_complex> &known_symbol, - unsigned int max_fft_shift_len) -{ - return gnuradio::get_initial_sptr(new digital_ofdm_frame_acquisition (occupied_carriers, fft_length, cplen, - known_symbol, max_fft_shift_len)); -} - -digital_ofdm_frame_acquisition::digital_ofdm_frame_acquisition (unsigned occupied_carriers, - unsigned int fft_length, - unsigned int cplen, - const std::vector<gr_complex> &known_symbol, - unsigned int max_fft_shift_len) - : gr_block ("ofdm_frame_acquisition", - gr_make_io_signature2 (2, 2, sizeof(gr_complex)*fft_length, sizeof(char)*fft_length), - gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char))), - d_occupied_carriers(occupied_carriers), - d_fft_length(fft_length), - d_cplen(cplen), - d_freq_shift_len(max_fft_shift_len), - d_known_symbol(known_symbol), - d_coarse_freq(0), - d_phase_count(0) -{ - d_symbol_phase_diff.resize(d_fft_length); - d_known_phase_diff.resize(d_occupied_carriers); - d_hestimate.resize(d_occupied_carriers); - - unsigned int i = 0, j = 0; - - std::fill(d_known_phase_diff.begin(), d_known_phase_diff.end(), 0); - for(i = 0; i < d_known_symbol.size()-2; i+=2) { - d_known_phase_diff[i] = norm(d_known_symbol[i] - d_known_symbol[i+2]); - } - - d_phase_lut = new gr_complex[(2*d_freq_shift_len+1) * MAX_NUM_SYMBOLS]; - for(i = 0; i <= 2*d_freq_shift_len; i++) { - for(j = 0; j < MAX_NUM_SYMBOLS; j++) { - d_phase_lut[j + i*MAX_NUM_SYMBOLS] = gr_expj(-M_TWOPI*d_cplen/d_fft_length*(i-d_freq_shift_len)*j); - } - } -} - -digital_ofdm_frame_acquisition::~digital_ofdm_frame_acquisition(void) -{ - delete [] d_phase_lut; -} - -void -digital_ofdm_frame_acquisition::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] = 1; -} - -gr_complex -digital_ofdm_frame_acquisition::coarse_freq_comp(int freq_delta, int symbol_count) -{ - // return gr_complex(cos(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count), - // sin(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count)); - - return gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count); - - //return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count]; -} - -void -digital_ofdm_frame_acquisition::correlate(const gr_complex *symbol, int zeros_on_left) -{ - unsigned int i,j; - - std::fill(d_symbol_phase_diff.begin(), d_symbol_phase_diff.end(), 0); - for(i = 0; i < d_fft_length-2; i++) { - d_symbol_phase_diff[i] = norm(symbol[i] - symbol[i+2]); - } - - // sweep through all possible/allowed frequency offsets and select the best - int index = 0; - float max = 0, sum=0; - for(i = zeros_on_left - d_freq_shift_len; i < zeros_on_left + d_freq_shift_len; i++) { - sum = 0; - for(j = 0; j < d_occupied_carriers; j++) { - sum += (d_known_phase_diff[j] * d_symbol_phase_diff[i+j]); - } - if(sum > max) { - max = sum; - index = i; - } - } - - // set the coarse frequency offset relative to the edge of the occupied tones - d_coarse_freq = index - zeros_on_left; -} - -void -digital_ofdm_frame_acquisition::calculate_equalizer(const gr_complex *symbol, int zeros_on_left) -{ - unsigned int i=0; - - // Set first tap of equalizer - d_hestimate[0] = d_known_symbol[0] / - (coarse_freq_comp(d_coarse_freq,1)*symbol[zeros_on_left+d_coarse_freq]); - - // set every even tap based on known symbol - // linearly interpolate between set carriers to set zero-filled carriers - // FIXME: is this the best way to set this? - for(i = 2; i < d_occupied_carriers; i+=2) { - d_hestimate[i] = d_known_symbol[i] / - (coarse_freq_comp(d_coarse_freq,1)*(symbol[i+zeros_on_left+d_coarse_freq])); - d_hestimate[i-1] = (d_hestimate[i] + d_hestimate[i-2]) / gr_complex(2.0, 0.0); - } - - // with even number of carriers; last equalizer tap is wrong - if(!(d_occupied_carriers & 1)) { - d_hestimate[d_occupied_carriers-1] = d_hestimate[d_occupied_carriers-2]; - } - - if(VERBOSE) { - fprintf(stderr, "Equalizer setting:\n"); - for(i = 0; i < d_occupied_carriers; i++) { - gr_complex sym = coarse_freq_comp(d_coarse_freq,1)*symbol[i+zeros_on_left+d_coarse_freq]; - gr_complex output = sym * d_hestimate[i]; - fprintf(stderr, "sym: %+.4f + j%+.4f ks: %+.4f + j%+.4f eq: %+.4f + j%+.4f ==> %+.4f + j%+.4f\n", - sym .real(), sym.imag(), - d_known_symbol[i].real(), d_known_symbol[i].imag(), - d_hestimate[i].real(), d_hestimate[i].imag(), - output.real(), output.imag()); - } - fprintf(stderr, "\n"); - } -} - -int -digital_ofdm_frame_acquisition::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 *symbol = (const gr_complex *)input_items[0]; - const char *signal_in = (const char *)input_items[1]; - - gr_complex *out = (gr_complex *) output_items[0]; - char *signal_out = (char *) output_items[1]; - - int unoccupied_carriers = d_fft_length - d_occupied_carriers; - int zeros_on_left = (int)ceil(unoccupied_carriers/2.0); - - if(signal_in[0]) { - d_phase_count = 1; - correlate(symbol, zeros_on_left); - calculate_equalizer(symbol, zeros_on_left); - signal_out[0] = 1; - } - else { - signal_out[0] = 0; - } - - for(unsigned int i = 0; i < d_occupied_carriers; i++) { - out[i] = d_hestimate[i]*coarse_freq_comp(d_coarse_freq,d_phase_count) - *symbol[i+zeros_on_left+d_coarse_freq]; - } - - d_phase_count++; - if(d_phase_count == MAX_NUM_SYMBOLS) { - d_phase_count = 1; - } - - consume_each(1); - return 1; -} diff --git a/gr-digital/lib/digital_ofdm_frame_sink.cc b/gr-digital/lib/digital_ofdm_frame_sink.cc deleted file mode 100644 index f8fb1bbb1d..0000000000 --- a/gr-digital/lib/digital_ofdm_frame_sink.cc +++ /dev/null @@ -1,405 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2008,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_ofdm_frame_sink.h> -#include <gr_io_signature.h> -#include <gr_expj.h> -#include <gr_math.h> -#include <math.h> -#include <cstdio> -#include <stdexcept> -#include <iostream> -#include <string.h> - -#define VERBOSE 0 - -inline void -digital_ofdm_frame_sink::enter_search() -{ - if (VERBOSE) - fprintf(stderr, "@ enter_search\n"); - - d_state = STATE_SYNC_SEARCH; - -} - -inline void -digital_ofdm_frame_sink::enter_have_sync() -{ - if (VERBOSE) - fprintf(stderr, "@ enter_have_sync\n"); - - d_state = STATE_HAVE_SYNC; - - // clear state of demapper - d_byte_offset = 0; - d_partial_byte = 0; - - d_header = 0; - d_headerbytelen_cnt = 0; - - // Resetting PLL - d_freq = 0.0; - d_phase = 0.0; - fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0)); -} - -inline void -digital_ofdm_frame_sink::enter_have_header() -{ - d_state = STATE_HAVE_HEADER; - - // header consists of two 16-bit shorts in network byte order - // payload length is lower 12 bits - // whitener offset is upper 4 bits - d_packetlen = (d_header >> 16) & 0x0fff; - d_packet_whitener_offset = (d_header >> 28) & 0x000f; - d_packetlen_cnt = 0; - - if (VERBOSE) - fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n", - d_packetlen, d_packet_whitener_offset); -} - - -unsigned char digital_ofdm_frame_sink::slicer(const gr_complex x) -{ - unsigned int table_size = d_sym_value_out.size(); - unsigned int min_index = 0; - float min_euclid_dist = norm(x - d_sym_position[0]); - float euclid_dist = 0; - - for (unsigned int j = 1; j < table_size; j++){ - euclid_dist = norm(x - d_sym_position[j]); - if (euclid_dist < min_euclid_dist){ - min_euclid_dist = euclid_dist; - min_index = j; - } - } - return d_sym_value_out[min_index]; -} - -unsigned int digital_ofdm_frame_sink::demapper(const gr_complex *in, - unsigned char *out) -{ - unsigned int i=0, bytes_produced=0; - gr_complex carrier; - - carrier=gr_expj(d_phase); - - gr_complex accum_error = 0.0; - //while(i < d_occupied_carriers) { - while(i < d_subcarrier_map.size()) { - if(d_nresid > 0) { - d_partial_byte |= d_resid; - d_byte_offset += d_nresid; - d_nresid = 0; - d_resid = 0; - } - - //while((d_byte_offset < 8) && (i < d_occupied_carriers)) { - while((d_byte_offset < 8) && (i < d_subcarrier_map.size())) { - //gr_complex sigrot = in[i]*carrier*d_dfe[i]; - gr_complex sigrot = in[d_subcarrier_map[i]]*carrier*d_dfe[i]; - - if(d_derotated_output != NULL){ - d_derotated_output[i] = sigrot; - } - - unsigned char bits = slicer(sigrot); - - gr_complex closest_sym = d_sym_position[bits]; - - accum_error += sigrot * conj(closest_sym); - - // FIX THE FOLLOWING STATEMENT - if (norm(sigrot)> 0.001) d_dfe[i] += d_eq_gain*(closest_sym/sigrot-d_dfe[i]); - - i++; - - if((8 - d_byte_offset) >= d_nbits) { - d_partial_byte |= bits << (d_byte_offset); - d_byte_offset += d_nbits; - } - else { - d_nresid = d_nbits-(8-d_byte_offset); - int mask = ((1<<(8-d_byte_offset))-1); - d_partial_byte |= (bits & mask) << d_byte_offset; - d_resid = bits >> (8-d_byte_offset); - d_byte_offset += (d_nbits - d_nresid); - } - //printf("demod symbol: %.4f + j%.4f bits: %x partial_byte: %x byte_offset: %d resid: %x nresid: %d\n", - // in[i-1].real(), in[i-1].imag(), bits, d_partial_byte, d_byte_offset, d_resid, d_nresid); - } - - if(d_byte_offset == 8) { - //printf("demod byte: %x \n\n", d_partial_byte); - out[bytes_produced++] = d_partial_byte; - d_byte_offset = 0; - d_partial_byte = 0; - } - } - //std::cerr << "accum_error " << accum_error << std::endl; - - float angle = arg(accum_error); - - d_freq = d_freq - d_freq_gain*angle; - d_phase = d_phase + d_freq - d_phase_gain*angle; - if (d_phase >= 2*M_PI) d_phase -= 2*M_PI; - if (d_phase <0) d_phase += 2*M_PI; - - //if(VERBOSE) - // std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl; - - return bytes_produced; -} - - -digital_ofdm_frame_sink_sptr -digital_make_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, - const std::vector<unsigned char> &sym_value_out, - gr_msg_queue_sptr target_queue, unsigned int occupied_carriers, - float phase_gain, float freq_gain) -{ - return gnuradio::get_initial_sptr(new digital_ofdm_frame_sink(sym_position, sym_value_out, - target_queue, occupied_carriers, - phase_gain, freq_gain)); -} - - -digital_ofdm_frame_sink::digital_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, - const std::vector<unsigned char> &sym_value_out, - gr_msg_queue_sptr target_queue, unsigned int occupied_carriers, - float phase_gain, float freq_gain) - : gr_sync_block ("ofdm_frame_sink", - gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)), - gr_make_io_signature (1, 1, sizeof(gr_complex)*occupied_carriers)), - d_target_queue(target_queue), d_occupied_carriers(occupied_carriers), - d_byte_offset(0), d_partial_byte(0), - d_resid(0), d_nresid(0),d_phase(0),d_freq(0),d_phase_gain(phase_gain),d_freq_gain(freq_gain), - d_eq_gain(0.05) -{ - std::string carriers = "FE7F"; - - // A bit hacky to fill out carriers to occupied_carriers length - int diff = (d_occupied_carriers - 4*carriers.length()); - while(diff > 7) { - carriers.insert(0, "f"); - carriers.insert(carriers.length(), "f"); - diff -= 8; - } - - // if there's extras left to be processed - // divide remaining to put on either side of current map - // all of this is done to stick with the concept of a carrier map string that - // can be later passed by the user, even though it'd be cleaner to just do this - // on the carrier map itself - int diff_left=0; - int diff_right=0; - - // dictionary to convert from integers to ascii hex representation - char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - if(diff > 0) { - char c[2] = {0,0}; - - diff_left = (int)ceil((float)diff/2.0f); // number of carriers to put on the left side - c[0] = abc[(1 << diff_left) - 1]; // convert to bits and move to ASCI integer - carriers.insert(0, c); - - diff_right = diff - diff_left; // number of carriers to put on the right side - c[0] = abc[0xF^((1 << diff_right) - 1)]; // convert to bits and move to ASCI integer - carriers.insert(carriers.length(), c); - } - - // It seemed like such a good idea at the time... - // because we are only dealing with the occupied_carriers - // at this point, the diff_left in the following compensates - // for any offset from the 0th carrier introduced - unsigned int i,j,k; - for(i = 0; i < (d_occupied_carriers/4)+diff_left; i++) { - char c = carriers[i]; - for(j = 0; j < 4; j++) { - k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1; - if(k) { - d_subcarrier_map.push_back(4*i + j - diff_left); - } - } - } - - // make sure we stay in the limit currently imposed by the occupied_carriers - if(d_subcarrier_map.size() > d_occupied_carriers) { - throw std::invalid_argument("digital_ofdm_mapper_bcv: subcarriers allocated exceeds size of occupied carriers"); - } - - d_bytes_out = new unsigned char[d_occupied_carriers]; - d_dfe.resize(occupied_carriers); - fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0)); - - set_sym_value_out(sym_position, sym_value_out); - - enter_search(); -} - -digital_ofdm_frame_sink::~digital_ofdm_frame_sink () -{ - delete [] d_bytes_out; -} - -bool -digital_ofdm_frame_sink::set_sym_value_out(const std::vector<gr_complex> &sym_position, - const std::vector<unsigned char> &sym_value_out) -{ - if (sym_position.size() != sym_value_out.size()) - return false; - - if (sym_position.size()<1) - return false; - - d_sym_position = sym_position; - d_sym_value_out = sym_value_out; - d_nbits = (unsigned long)ceil(log10(float(d_sym_value_out.size())) / log10(2.0)); - - return true; -} - - -int -digital_ofdm_frame_sink::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]; - const char *sig = (const char *) input_items[1]; - unsigned int j = 0; - unsigned int bytes=0; - - // If the output is connected, send it the derotated symbols - if(output_items.size() >= 1) - d_derotated_output = (gr_complex *)output_items[0]; - else - d_derotated_output = NULL; - - if (VERBOSE) - fprintf(stderr,">>> Entering state machine\n"); - - switch(d_state) { - - case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt - if (VERBOSE) - fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items); - - if (sig[0]) { // Found it, set up for header decode - enter_have_sync(); - } - break; - - case STATE_HAVE_SYNC: - // only demod after getting the preamble signal; otherwise, the - // equalizer taps will screw with the PLL performance - bytes = demapper(&in[0], d_bytes_out); - - if (VERBOSE) { - if(sig[0]) - printf("ERROR -- Found SYNC in HAVE_SYNC\n"); - fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n", - d_headerbytelen_cnt, d_header); - } - - j = 0; - while(j < bytes) { - d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF); - j++; - - if (++d_headerbytelen_cnt == HEADERBYTELEN) { - - if (VERBOSE) - fprintf(stderr, "got header: 0x%08x\n", d_header); - - // we have a full header, check to see if it has been received properly - if (header_ok()){ - enter_have_header(); - - if (VERBOSE) - printf("\nPacket Length: %d\n", d_packetlen); - - while((j < bytes) && (d_packetlen_cnt < d_packetlen)) { - d_packet[d_packetlen_cnt++] = d_bytes_out[j++]; - } - - if(d_packetlen_cnt == d_packetlen) { - gr_message_sptr msg = - gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen); - memcpy(msg->msg(), d_packet, d_packetlen_cnt); - d_target_queue->insert_tail(msg); // send it - msg.reset(); // free it up - - enter_search(); - } - } - else { - enter_search(); // bad header - } - } - } - break; - - case STATE_HAVE_HEADER: - bytes = demapper(&in[0], d_bytes_out); - - if (VERBOSE) { - if(sig[0]) - printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen); - fprintf(stderr,"Packet Build\n"); - } - - j = 0; - while(j < bytes) { - d_packet[d_packetlen_cnt++] = d_bytes_out[j++]; - - if (d_packetlen_cnt == d_packetlen){ // packet is filled - // build a message - // NOTE: passing header field as arg1 is not scalable - gr_message_sptr msg = - gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt); - memcpy(msg->msg(), d_packet, d_packetlen_cnt); - - d_target_queue->insert_tail(msg); // send it - msg.reset(); // free it up - - enter_search(); - break; - } - } - break; - - default: - assert(0); - - } // switch - - return 1; -} diff --git a/gr-digital/lib/digital_ofdm_insert_preamble.cc b/gr-digital/lib/digital_ofdm_insert_preamble.cc deleted file mode 100644 index 72b9e82a82..0000000000 --- a/gr-digital/lib/digital_ofdm_insert_preamble.cc +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2010-2012 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_ofdm_insert_preamble.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <iostream> -#include <string.h> - -digital_ofdm_insert_preamble_sptr -digital_make_ofdm_insert_preamble(int fft_length, - const std::vector<std::vector<gr_complex> > &preamble) -{ - return gnuradio::get_initial_sptr(new digital_ofdm_insert_preamble(fft_length, - preamble)); -} - -digital_ofdm_insert_preamble::digital_ofdm_insert_preamble - (int fft_length, - const std::vector<std::vector<gr_complex> > &preamble) - : gr_block("ofdm_insert_preamble", - gr_make_io_signature2(1, 2, - sizeof(gr_complex)*fft_length, - sizeof(char)), - gr_make_io_signature2(1, 2, - sizeof(gr_complex)*fft_length, - sizeof(char))), - d_fft_length(fft_length), - d_preamble(preamble), - d_state(ST_IDLE), - d_nsymbols_output(0), - d_pending_flag(0) -{ - // sanity check preamble symbols - for(size_t i = 0; i < d_preamble.size(); i++) { - if(d_preamble[i].size() != (size_t) d_fft_length) - throw std::invalid_argument("digital_ofdm_insert_preamble: invalid length for preamble symbol"); - } - - enter_idle(); -} - - -digital_ofdm_insert_preamble::~digital_ofdm_insert_preamble() -{ -} - -void digital_ofdm_insert_preamble::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - ninput_items_required[0] = noutput_items; -} - -int -digital_ofdm_insert_preamble::general_work(int noutput_items, - gr_vector_int &ninput_items_v, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - int ninput_items = ninput_items_v.size()==2?std::min(ninput_items_v[0], ninput_items_v[1]):ninput_items_v[0]; - const gr_complex *in_sym = (const gr_complex *) input_items[0]; - const unsigned char *in_flag = 0; - if (input_items.size() == 2) - in_flag = (const unsigned char *) input_items[1]; - - gr_complex *out_sym = (gr_complex *) output_items[0]; - unsigned char *out_flag = 0; - if (output_items.size() == 2) - out_flag = (unsigned char *) output_items[1]; - - - int no = 0; // number items output - int ni = 0; // number items read from input - - -#define write_out_flag() \ - do { if (out_flag) \ - out_flag[no] = d_pending_flag; \ - d_pending_flag = 0; \ - } while(0) - - - while (no < noutput_items && ni < ninput_items){ - switch(d_state){ - case ST_IDLE: - if (in_flag && in_flag[ni] & 0x1) // this is first symbol of new payload - enter_preamble(); - else - ni++; // eat one input symbol - break; - - case ST_PREAMBLE: - assert(!in_flag || in_flag[ni] & 0x1); - if (d_nsymbols_output >= (int) d_preamble.size()){ - // we've output all the preamble - enter_first_payload(); - } - else { - memcpy(&out_sym[no * d_fft_length], - &d_preamble[d_nsymbols_output][0], - d_fft_length*sizeof(gr_complex)); - - write_out_flag(); - no++; - d_nsymbols_output++; - } - break; - - case ST_FIRST_PAYLOAD: - // copy first payload symbol from input to output - memcpy(&out_sym[no * d_fft_length], - &in_sym[ni * d_fft_length], - d_fft_length * sizeof(gr_complex)); - - write_out_flag(); - no++; - ni++; - enter_payload(); - break; - - case ST_PAYLOAD: - if (in_flag && in_flag[ni] & 0x1){ // this is first symbol of a new payload - enter_preamble(); - break; - } - - // copy a symbol from input to output - memcpy(&out_sym[no * d_fft_length], - &in_sym[ni * d_fft_length], - d_fft_length * sizeof(gr_complex)); - - write_out_flag(); - no++; - ni++; - break; - - default: - std::cerr << "digital_ofdm_insert_preamble: (can't happen) invalid state, resetting\n"; - enter_idle(); - } - } - - consume_each(ni); - return no; -} - -void -digital_ofdm_insert_preamble::enter_idle() -{ - d_state = ST_IDLE; - d_nsymbols_output = 0; - d_pending_flag = 0; -} - -void -digital_ofdm_insert_preamble::enter_preamble() -{ - d_state = ST_PREAMBLE; - d_nsymbols_output = 0; - d_pending_flag = 1; -} - -void -digital_ofdm_insert_preamble::enter_first_payload() -{ - d_state = ST_FIRST_PAYLOAD; -} - -void -digital_ofdm_insert_preamble::enter_payload() -{ - d_state = ST_PAYLOAD; -} diff --git a/gr-digital/lib/digital_ofdm_mapper_bcv.cc b/gr-digital/lib/digital_ofdm_mapper_bcv.cc deleted file mode 100644 index cf3d08703a..0000000000 --- a/gr-digital/lib/digital_ofdm_mapper_bcv.cc +++ /dev/null @@ -1,241 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2008,2010,2011 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. - */ - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_ofdm_mapper_bcv.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <string.h> - -digital_ofdm_mapper_bcv_sptr -digital_make_ofdm_mapper_bcv (const std::vector<gr_complex> &constellation, unsigned int msgq_limit, - unsigned int occupied_carriers, unsigned int fft_length) -{ - return gnuradio::get_initial_sptr(new digital_ofdm_mapper_bcv (constellation, msgq_limit, - occupied_carriers, fft_length)); -} - -// Consumes 1 packet and produces as many OFDM symbols of fft_length to hold the full packet -digital_ofdm_mapper_bcv::digital_ofdm_mapper_bcv (const std::vector<gr_complex> &constellation, unsigned int msgq_limit, - unsigned int occupied_carriers, unsigned int fft_length) - : gr_sync_block ("ofdm_mapper_bcv", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature2 (1, 2, sizeof(gr_complex)*fft_length, sizeof(char))), - d_constellation(constellation), - d_msgq(gr_make_msg_queue(msgq_limit)), d_msg_offset(0), d_eof(false), - d_occupied_carriers(occupied_carriers), - d_fft_length(fft_length), - d_bit_offset(0), - d_pending_flag(0), - d_resid(0), - d_nresid(0) -{ - if (!(d_occupied_carriers <= d_fft_length)) - throw std::invalid_argument("digital_ofdm_mapper_bcv: occupied carriers must be <= fft_length"); - - // this is not the final form of this solution since we still use the occupied_tones concept, - // which would get us into trouble if the number of carriers we seek is greater than the occupied carriers. - // Eventually, we will get rid of the occupied_carriers concept. - std::string carriers = "FE7F"; - - // A bit hacky to fill out carriers to occupied_carriers length - int diff = (d_occupied_carriers - 4*carriers.length()); - while(diff > 7) { - carriers.insert(0, "f"); - carriers.insert(carriers.length(), "f"); - diff -= 8; - } - - // if there's extras left to be processed - // divide remaining to put on either side of current map - // all of this is done to stick with the concept of a carrier map string that - // can be later passed by the user, even though it'd be cleaner to just do this - // on the carrier map itself - int diff_left=0; - int diff_right=0; - - // dictionary to convert from integers to ascii hex representation - char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - if(diff > 0) { - char c[2] = {0,0}; - - diff_left = (int)ceil((float)diff/2.0f); // number of carriers to put on the left side - c[0] = abc[(1 << diff_left) - 1]; // convert to bits and move to ASCI integer - carriers.insert(0, c); - - diff_right = diff - diff_left; // number of carriers to put on the right side - c[0] = abc[0xF^((1 << diff_right) - 1)]; // convert to bits and move to ASCI integer - carriers.insert(carriers.length(), c); - } - - // find out how many zeros to pad on the sides; the difference between the fft length and the subcarrier - // mapping size in chunks of four. This is the number to pack on the left and this number plus any - // residual nulls (if odd) will be packed on the right. - diff = (d_fft_length/4 - carriers.length())/2; - - unsigned int i,j,k; - for(i = 0; i < carriers.length(); i++) { - char c = carriers[i]; // get the current hex character from the string - for(j = 0; j < 4; j++) { // walk through all four bits - k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1; // convert to int and extract next bit - if(k) { // if bit is a 1, - d_subcarrier_map.push_back(4*(i+diff) + j); // use this subcarrier - } - } - } - - // make sure we stay in the limit currently imposed by the occupied_carriers - if(d_subcarrier_map.size() > d_occupied_carriers) { - throw std::invalid_argument("digital_ofdm_mapper_bcv: subcarriers allocated exceeds size of occupied carriers"); - } - - d_nbits = (unsigned long)ceil(log10(float(d_constellation.size())) / log10(2.0)); -} - -digital_ofdm_mapper_bcv::~digital_ofdm_mapper_bcv(void) -{ -} - -int digital_ofdm_mapper_bcv::randsym() -{ - return (rand() % d_constellation.size()); -} - -int -digital_ofdm_mapper_bcv::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - gr_complex *out = (gr_complex *)output_items[0]; - - unsigned int i=0; - - //printf("OFDM BPSK Mapper: ninput_items: %d noutput_items: %d\n", ninput_items[0], noutput_items); - - if(d_eof) { - return -1; - } - - if(!d_msg) { - d_msg = d_msgq->delete_head(); // block, waiting for a message - d_msg_offset = 0; - d_bit_offset = 0; - d_pending_flag = 1; // new packet, write start of packet flag - - if((d_msg->length() == 0) && (d_msg->type() == 1)) { - d_msg.reset(); - return -1; // We're done; no more messages coming. - } - } - - char *out_flag = 0; - if(output_items.size() == 2) - out_flag = (char *) output_items[1]; - - - // Build a single symbol: - // Initialize all bins to 0 to set unused carriers - memset(out, 0, d_fft_length*sizeof(gr_complex)); - - i = 0; - unsigned char bits = 0; - //while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { - while((d_msg_offset < d_msg->length()) && (i < d_subcarrier_map.size())) { - - // need new data to process - if(d_bit_offset == 0) { - d_msgbytes = d_msg->msg()[d_msg_offset]; - //printf("mod message byte: %x\n", d_msgbytes); - } - - if(d_nresid > 0) { - // take the residual bits, fill out nbits with info from the new byte, and put them in the symbol - d_resid |= (((1 << d_nresid)-1) & d_msgbytes) << (d_nbits - d_nresid); - bits = d_resid; - - out[d_subcarrier_map[i]] = d_constellation[bits]; - i++; - - d_bit_offset += d_nresid; - d_nresid = 0; - d_resid = 0; - //printf("mod bit(r): %x resid: %x nresid: %d bit_offset: %d\n", - // bits, d_resid, d_nresid, d_bit_offset); - } - else { - if((8 - d_bit_offset) >= d_nbits) { // test to make sure we can fit nbits - // take the nbits number of bits at a time from the byte to add to the symbol - bits = ((1 << d_nbits)-1) & (d_msgbytes >> d_bit_offset); - d_bit_offset += d_nbits; - - out[d_subcarrier_map[i]] = d_constellation[bits]; - i++; - } - else { // if we can't fit nbits, store them for the next - // saves d_nresid bits of this message where d_nresid < d_nbits - unsigned int extra = 8-d_bit_offset; - d_resid = ((1 << extra)-1) & (d_msgbytes >> d_bit_offset); - d_bit_offset += extra; - d_nresid = d_nbits - extra; - } - - } - - if(d_bit_offset == 8) { - d_bit_offset = 0; - d_msg_offset++; - } - } - - // Ran out of data to put in symbol - if (d_msg_offset == d_msg->length()) { - if(d_nresid > 0) { - d_resid |= 0x00; - bits = d_resid; - d_nresid = 0; - d_resid = 0; - } - - //while(i < d_occupied_carriers) { // finish filling out the symbol - while(i < d_subcarrier_map.size()) { // finish filling out the symbol - out[d_subcarrier_map[i]] = d_constellation[randsym()]; - - i++; - } - - if (d_msg->type() == 1) // type == 1 sets EOF - d_eof = true; - d_msg.reset(); // finished packet, free message - assert(d_bit_offset == 0); - } - - if (out_flag) - out_flag[0] = d_pending_flag; - d_pending_flag = 0; - - return 1; // produced symbol -} diff --git a/gr-digital/lib/digital_ofdm_sampler.cc b/gr-digital/lib/digital_ofdm_sampler.cc deleted file mode 100644 index cab8c2ba93..0000000000 --- a/gr-digital/lib/digital_ofdm_sampler.cc +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2008,2010,2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_ofdm_sampler.h> -#include <gr_io_signature.h> -#include <gr_expj.h> -#include <cstdio> - -digital_ofdm_sampler_sptr -digital_make_ofdm_sampler (unsigned int fft_length, - unsigned int symbol_length, - unsigned int timeout) -{ - return gnuradio::get_initial_sptr(new digital_ofdm_sampler (fft_length, symbol_length, timeout)); -} - -digital_ofdm_sampler::digital_ofdm_sampler (unsigned int fft_length, - unsigned int symbol_length, - unsigned int timeout) - : gr_block ("ofdm_sampler", - gr_make_io_signature2 (2, 2, sizeof (gr_complex), sizeof(char)), - gr_make_io_signature2 (2, 2, sizeof (gr_complex)*fft_length, sizeof(char)*fft_length)), - d_state(STATE_NO_SIG), d_timeout_max(timeout), d_fft_length(fft_length), d_symbol_length(symbol_length) -{ - set_relative_rate(1.0/(double) fft_length); // buffer allocator hint -} - -void -digital_ofdm_sampler::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - // FIXME do we need more - //int nreqd = (noutput_items-1) * d_symbol_length + d_fft_length; - int nreqd = d_symbol_length + d_fft_length; - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = nreqd; -} - - -int -digital_ofdm_sampler::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 *iptr = (const gr_complex *) input_items[0]; - const char *trigger = (const char *) input_items[1]; - - gr_complex *optr = (gr_complex *) output_items[0]; - char *outsig = (char *) output_items[1]; - - //FIXME: we only process a single OFDM symbol at a time; after the preamble, we can - // process a few at a time as long as we always look out for the next preamble. - - unsigned int index=d_fft_length; // start one fft length into the input so we can always look back this far - - outsig[0] = 0; // set output to no signal by default - - // Search for a preamble trigger signal during the next symbol length - while((d_state != STATE_PREAMBLE) && (index <= (d_symbol_length+d_fft_length))) { - if(trigger[index]) { - outsig[0] = 1; // tell the next block there is a preamble coming - d_state = STATE_PREAMBLE; - } - else - index++; - } - - unsigned int i, pos, ret; - switch(d_state) { - case(STATE_PREAMBLE): - // When we found a preamble trigger, get it and set the symbol boundary here - for(i = (index - d_fft_length + 1); i <= index; i++) { - *optr++ = iptr[i]; - } - - d_timeout = d_timeout_max; // tell the system to expect at least this many symbols for a frame - d_state = STATE_FRAME; - consume_each(index - d_fft_length + 1); // consume up to one fft_length away to keep the history - ret = 1; - break; - - case(STATE_FRAME): - // use this state when we have processed a preamble and are getting the rest of the frames - //FIXME: we could also have a power squelch system here to enter STATE_NO_SIG if no power is received - - // skip over fft length history and cyclic prefix - pos = d_symbol_length; // keeps track of where we are in the input buffer - while(pos < d_symbol_length + d_fft_length) { - *optr++ = iptr[pos++]; - } - - if(d_timeout-- == 0) { - printf("TIMEOUT\n"); - d_state = STATE_NO_SIG; - } - - consume_each(d_symbol_length); // jump up by 1 fft length and the cyclic prefix length - ret = 1; - break; - - case(STATE_NO_SIG): - default: - consume_each(index-d_fft_length); // consume everything we've gone through so far leaving the fft length history - ret = 0; - break; - } - - return ret; -} diff --git a/gr-digital/lib/digital_packet_sink.cc b/gr-digital/lib/digital_packet_sink.cc deleted file mode 100644 index 92521376fd..0000000000 --- a/gr-digital/lib/digital_packet_sink.cc +++ /dev/null @@ -1,207 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_packet_sink.h> -#include <gr_io_signature.h> -#include <cstdio> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdexcept> -#include <gr_count_bits.h> -#include <string.h> - -#define VERBOSE 0 - -static const int DEFAULT_THRESHOLD = 12; // detect access code with up to DEFAULT_THRESHOLD bits wrong - -inline void -digital_packet_sink::enter_search() -{ - if (VERBOSE) - fprintf(stderr, "@ enter_search\n"); - - d_state = STATE_SYNC_SEARCH; - d_shift_reg = 0; -} - -inline void -digital_packet_sink::enter_have_sync() -{ - if (VERBOSE) - fprintf(stderr, "@ enter_have_sync\n"); - - d_state = STATE_HAVE_SYNC; - d_header = 0; - d_headerbitlen_cnt = 0; -} - -inline void -digital_packet_sink::enter_have_header(int payload_len) -{ - if (VERBOSE) - fprintf(stderr, "@ enter_have_header (payload_len = %d)\n", payload_len); - - d_state = STATE_HAVE_HEADER; - d_packetlen = payload_len; - d_packetlen_cnt = 0; - d_packet_byte = 0; - d_packet_byte_index = 0; -} - -digital_packet_sink_sptr -digital_make_packet_sink (const std::vector<unsigned char>& sync_vector, - gr_msg_queue_sptr target_queue, int threshold) -{ - return gnuradio::get_initial_sptr(new digital_packet_sink (sync_vector, target_queue, threshold)); -} - - -digital_packet_sink::digital_packet_sink (const std::vector<unsigned char>& sync_vector, - gr_msg_queue_sptr target_queue, int threshold) - : gr_sync_block ("packet_sink", - gr_make_io_signature (1, 1, sizeof(float)), - gr_make_io_signature (0, 0, 0)), - d_target_queue(target_queue), d_threshold(threshold == -1 ? DEFAULT_THRESHOLD : threshold) -{ - d_sync_vector = 0; - for(int i=0;i<8;i++){ - d_sync_vector <<= 8; - d_sync_vector |= sync_vector[i]; - } - - enter_search(); -} - -digital_packet_sink::~digital_packet_sink () -{ -} - -int -digital_packet_sink::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - float *inbuf = (float *) input_items[0]; - int count=0; - - if (VERBOSE) - fprintf(stderr,">>> Entering state machine\n"),fflush(stderr); - - while (count<noutput_items) { - switch(d_state) { - - case STATE_SYNC_SEARCH: // Look for sync vector - if (VERBOSE) - fprintf(stderr,"SYNC Search, noutput=%d\n",noutput_items),fflush(stderr); - - while (count < noutput_items) { - if(slice(inbuf[count++])) - d_shift_reg = (d_shift_reg << 1) | 1; - else - d_shift_reg = d_shift_reg << 1; - - // Compute popcnt of putative sync vector - if(gr_count_bits64 (d_shift_reg ^ d_sync_vector) <= d_threshold) { - // Found it, set up for header decode - enter_have_sync(); - break; - } - } - break; - - case STATE_HAVE_SYNC: - if (VERBOSE) - fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n", d_headerbitlen_cnt, d_header), - fflush(stderr); - - while (count < noutput_items) { // Shift bits one at a time into header - if(slice(inbuf[count++])) - d_header = (d_header << 1) | 1; - else - d_header = d_header << 1; - - if (++d_headerbitlen_cnt == HEADERBITLEN) { - - if (VERBOSE) - fprintf(stderr, "got header: 0x%08x\n", d_header); - - // we have a full header, check to see if it has been received properly - if (header_ok()){ - int payload_len = header_payload_len(); - if (payload_len <= MAX_PKT_LEN) // reasonable? - enter_have_header(payload_len); // yes. - else - enter_search(); // no. - } - else - enter_search(); // no. - break; // we're in a new state - } - } - break; - - case STATE_HAVE_HEADER: - if (VERBOSE) - fprintf(stderr,"Packet Build\n"),fflush(stderr); - - while (count < noutput_items) { // shift bits into bytes of packet one at a time - if(slice(inbuf[count++])) - d_packet_byte = (d_packet_byte << 1) | 1; - else - d_packet_byte = d_packet_byte << 1; - - if (d_packet_byte_index++ == 7) { // byte is full so move to next byte - d_packet[d_packetlen_cnt++] = d_packet_byte; - d_packet_byte_index = 0; - - if (d_packetlen_cnt == d_packetlen){ // packet is filled - - // build a message - gr_message_sptr msg = gr_make_message(0, 0, 0, d_packetlen_cnt); - memcpy(msg->msg(), d_packet, d_packetlen_cnt); - - d_target_queue->insert_tail(msg); // send it - msg.reset(); // free it up - - enter_search(); - break; - } - } - } - break; - - default: - assert(0); - - } // switch - - } // while - - return noutput_items; -} - diff --git a/gr-digital/lib/digital_pfb_clock_sync_ccf.cc b/gr-digital/lib/digital_pfb_clock_sync_ccf.cc deleted file mode 100644 index 1a2d5970ba..0000000000 --- a/gr-digital/lib/digital_pfb_clock_sync_ccf.cc +++ /dev/null @@ -1,440 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009-2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <cstdio> -#include <cmath> - -#include <digital_pfb_clock_sync_ccf.h> -#include <gr_fir_ccf.h> -#include <gr_fir_util.h> -#include <gr_io_signature.h> -#include <gr_math.h> - -digital_pfb_clock_sync_ccf_sptr -digital_make_pfb_clock_sync_ccf(double sps, float loop_bw, - const std::vector<float> &taps, - unsigned int filter_size, - float init_phase, - float max_rate_deviation, - int osps) -{ - return gnuradio::get_initial_sptr(new digital_pfb_clock_sync_ccf - (sps, loop_bw, taps, - filter_size, - init_phase, - max_rate_deviation, - osps)); -} - -static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; -static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); -digital_pfb_clock_sync_ccf::digital_pfb_clock_sync_ccf (double sps, float loop_bw, - const std::vector<float> &taps, - unsigned int filter_size, - float init_phase, - float max_rate_deviation, - int osps) - : gr_block ("pfb_clock_sync_ccf", - gr_make_io_signature (1, 1, sizeof(gr_complex)), - gr_make_io_signaturev (1, 4, iosig)), - d_updated (false), d_nfilters(filter_size), - d_max_dev(max_rate_deviation), - d_osps(osps), d_error(0), d_out_idx(0) -{ - d_nfilters = filter_size; - d_sps = floor(sps); - - // Set the damping factor for a critically damped system - d_damping = sqrtf(2.0f)/2.0f; - - // Set the bandwidth, which will then call update_gains() - set_loop_bandwidth(loop_bw); - - // Store the last filter between calls to work - // The accumulator keeps track of overflow to increment the stride correctly. - // set it here to the fractional difference based on the initial phaes - d_k = init_phase; - d_rate = (sps-floor(sps))*(double)d_nfilters; - d_rate_i = (int)floor(d_rate); - d_rate_f = d_rate - (float)d_rate_i; - d_filtnum = (int)floor(d_k); - - d_filters = std::vector<gr_fir_ccf*>(d_nfilters); - d_diff_filters = std::vector<gr_fir_ccf*>(d_nfilters); - - // Create an FIR filter for each channel and zero out the taps - std::vector<float> vtaps(0, d_nfilters); - for(int i = 0; i < d_nfilters; i++) { - d_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); - d_diff_filters[i] = gr_fir_util::create_gr_fir_ccf(vtaps); - } - - // Now, actually set the filters' taps - std::vector<float> dtaps; - create_diff_taps(taps, dtaps); - set_taps(taps, d_taps, d_filters); - set_taps(dtaps, d_dtaps, d_diff_filters); -} - -digital_pfb_clock_sync_ccf::~digital_pfb_clock_sync_ccf () -{ - for(int i = 0; i < d_nfilters; i++) { - delete d_filters[i]; - delete d_diff_filters[i]; - } -} - -bool -digital_pfb_clock_sync_ccf::check_topology(int ninputs, int noutputs) -{ - return noutputs == 1 || noutputs == 4; -} - - - -/******************************************************************* - SET FUNCTIONS -*******************************************************************/ - - -void -digital_pfb_clock_sync_ccf::set_loop_bandwidth(float bw) -{ - if(bw < 0) { - throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid bandwidth. Must be >= 0."); - } - - d_loop_bw = bw; - update_gains(); -} - -void -digital_pfb_clock_sync_ccf::set_damping_factor(float df) -{ - if(df < 0 || df > 1.0) { - throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid damping factor. Must be in [0,1]."); - } - - d_damping = df; - update_gains(); -} - -void -digital_pfb_clock_sync_ccf::set_alpha(float alpha) -{ - if(alpha < 0 || alpha > 1.0) { - throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid alpha. Must be in [0,1]."); - } - d_alpha = alpha; -} - -void -digital_pfb_clock_sync_ccf::set_beta(float beta) -{ - if(beta < 0 || beta > 1.0) { - throw std::out_of_range ("digital_pfb_clock_sync_cc: invalid beta. Must be in [0,1]."); - } - d_beta = beta; -} - -/******************************************************************* - GET FUNCTIONS -*******************************************************************/ - - -float -digital_pfb_clock_sync_ccf::get_loop_bandwidth() const -{ - return d_loop_bw; -} - -float -digital_pfb_clock_sync_ccf::get_damping_factor() const -{ - return d_damping; -} - -float -digital_pfb_clock_sync_ccf::get_alpha() const -{ - return d_alpha; -} - -float -digital_pfb_clock_sync_ccf::get_beta() const -{ - return d_beta; -} - -float -digital_pfb_clock_sync_ccf::get_clock_rate() const -{ - return d_rate_f; -} - -/******************************************************************* -*******************************************************************/ - -void -digital_pfb_clock_sync_ccf::update_gains() -{ - float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); - d_alpha = (4*d_damping*d_loop_bw) / denom; - d_beta = (4*d_loop_bw*d_loop_bw) / denom; -} - - -void -digital_pfb_clock_sync_ccf::set_taps (const std::vector<float> &newtaps, - std::vector< std::vector<float> > &ourtaps, - std::vector<gr_fir_ccf*> &ourfilter) -{ - int i,j; - - unsigned int ntaps = newtaps.size(); - d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters); - - // Create d_numchan vectors to store each channel's taps - ourtaps.resize(d_nfilters); - - // Make a vector of the taps plus fill it out with 0's to fill - // each polyphase filter with exactly d_taps_per_filter - std::vector<float> tmp_taps; - tmp_taps = newtaps; - while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) { - tmp_taps.push_back(0.0); - } - - // Partition the filter - for(i = 0; i < d_nfilters; i++) { - // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out - ourtaps[i] = std::vector<float>(d_taps_per_filter, 0); - for(j = 0; j < d_taps_per_filter; j++) { - ourtaps[i][j] = tmp_taps[i + j*d_nfilters]; - } - - // Build a filter for each channel and add it's taps to it - ourfilter[i]->set_taps(ourtaps[i]); - } - - // Set the history to ensure enough input items for each filter - set_history (d_taps_per_filter + d_sps); - - // Make sure there is enough output space for d_osps outputs/input. - set_output_multiple(d_osps); - - d_updated = true; -} - -void -digital_pfb_clock_sync_ccf::create_diff_taps(const std::vector<float> &newtaps, - std::vector<float> &difftaps) -{ - std::vector<float> diff_filter(3); - diff_filter[0] = -1; - diff_filter[1] = 0; - diff_filter[2] = 1; - - float pwr = 0; - difftaps.push_back(0); - for(unsigned int i = 0; i < newtaps.size()-2; i++) { - float tap = 0; - for(int j = 0; j < 3; j++) { - tap += diff_filter[j]*newtaps[i+j]; - pwr += fabsf(tap); - } - difftaps.push_back(tap); - } - difftaps.push_back(0); - - for(unsigned int i = 0; i < difftaps.size(); i++) { - difftaps[i] *= pwr; - } -} - -std::string -digital_pfb_clock_sync_ccf::get_taps_as_string() -{ - int i, j; - std::stringstream str; - str.precision(4); - str.setf(std::ios::scientific); - - str << "[ "; - for(i = 0; i < d_nfilters; i++) { - str << "[" << d_taps[i][0] << ", "; - for(j = 1; j < d_taps_per_filter-1; j++) { - str << d_taps[i][j] << ", "; - } - str << d_taps[i][j] << "],"; - } - str << " ]" << std::endl; - - return str.str(); -} - -std::string -digital_pfb_clock_sync_ccf::get_diff_taps_as_string() -{ - int i, j; - std::stringstream str; - str.precision(4); - str.setf(std::ios::scientific); - - str << "[ "; - for(i = 0; i < d_nfilters; i++) { - str << "[" << d_dtaps[i][0] << ", "; - for(j = 1; j < d_taps_per_filter-1; j++) { - str << d_dtaps[i][j] << ", "; - } - str << d_dtaps[i][j] << "],"; - } - str << " ]" << std::endl; - - return str.str(); -} - -std::vector< std::vector<float> > -digital_pfb_clock_sync_ccf::get_taps() -{ - return d_taps; -} - -std::vector< std::vector<float> > -digital_pfb_clock_sync_ccf::get_diff_taps() -{ - return d_dtaps; -} - -std::vector<float> -digital_pfb_clock_sync_ccf::get_channel_taps(int channel) -{ - std::vector<float> taps; - for(int i = 0; i < d_taps_per_filter; i++) { - taps.push_back(d_taps[channel][i]); - } - return taps; -} - -std::vector<float> -digital_pfb_clock_sync_ccf::get_diff_channel_taps(int channel) -{ - std::vector<float> taps; - for(int i = 0; i < d_taps_per_filter; i++) { - taps.push_back(d_dtaps[channel][i]); - } - return taps; -} - - -int -digital_pfb_clock_sync_ccf::general_work(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - gr_complex *in = (gr_complex *) input_items[0]; - gr_complex *out = (gr_complex *) output_items[0]; - - float *err = NULL, *outrate = NULL, *outk = NULL; - if(output_items.size() == 4) { - err = (float *) output_items[1]; - outrate = (float*)output_items[2]; - outk = (float*)output_items[3]; - } - - if (d_updated) { - d_updated = false; - return 0; // history requirements may have changed. - } - - // We need this many to process one output - int nrequired = ninput_items[0] - d_taps_per_filter - d_osps; - - int i = 0, count = 0; - float error_r, error_i; - - // produce output as long as we can and there are enough input samples - while((i < noutput_items) && (count < nrequired)) { - while(d_out_idx < d_osps) { - d_filtnum = (int)floor(d_k); - - // Keep the current filter number in [0, d_nfilters] - // If we've run beyond the last filter, wrap around and go to next sample - // If we've go below 0, wrap around and go to previous sample - while(d_filtnum >= d_nfilters) { - d_k -= d_nfilters; - d_filtnum -= d_nfilters; - count += 1; - } - while(d_filtnum < 0) { - d_k += d_nfilters; - d_filtnum += d_nfilters; - count -= 1; - } - - out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); - d_k = d_k + d_rate_i + d_rate_f; // update phase - d_out_idx++; - - if(output_items.size() == 4) { - err[i] = d_error; - outrate[i] = d_rate_f; - outk[i] = d_k; - } - - // We've run out of output items we can create; return now. - if(i+d_out_idx >= noutput_items) { - consume_each(count); - return i; - } - } - - // reset here; if we didn't complete a full osps samples last time, - // the early return would take care of it. - d_out_idx = 0; - - // Update the phase and rate estimates for this symbol - gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]); - error_r = out[i].real() * diff.real(); - error_i = out[i].imag() * diff.imag(); - d_error = (error_i + error_r) / 2.0; // average error from I&Q channel - - // Run the control loop to update the current phase (k) and - // tracking rate estimates based on the error value - d_rate_f = d_rate_f + d_beta*d_error; - d_k = d_k + d_alpha*d_error; - - // Keep our rate within a good range - d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev); - - i+=d_osps; - count += (int)floor(d_sps); - } - - consume_each(count); - return i; -} diff --git a/gr-digital/lib/digital_pfb_clock_sync_fff.cc b/gr-digital/lib/digital_pfb_clock_sync_fff.cc deleted file mode 100644 index 0e7d2a52da..0000000000 --- a/gr-digital/lib/digital_pfb_clock_sync_fff.cc +++ /dev/null @@ -1,434 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2009,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <cstdio> -#include <cmath> - -#include <digital_pfb_clock_sync_fff.h> -#include <gr_fir_fff.h> -#include <gr_fir_util.h> -#include <gr_io_signature.h> -#include <gr_math.h> - -digital_pfb_clock_sync_fff_sptr -digital_make_pfb_clock_sync_fff(double sps, float gain, - const std::vector<float> &taps, - unsigned int filter_size, - float init_phase, - float max_rate_deviation, - int osps) -{ - return gnuradio::get_initial_sptr(new digital_pfb_clock_sync_fff - (sps, gain, taps, - filter_size, - init_phase, - max_rate_deviation, - osps)); -} - -static int ios[] = {sizeof(float), sizeof(float), sizeof(float), sizeof(float)}; -static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); -digital_pfb_clock_sync_fff::digital_pfb_clock_sync_fff (double sps, float loop_bw, - const std::vector<float> &taps, - unsigned int filter_size, - float init_phase, - float max_rate_deviation, - int osps) - : gr_block ("pfb_clock_sync_fff", - gr_make_io_signature (1, 1, sizeof(float)), - gr_make_io_signaturev (1, 4, iosig)), - d_updated (false), d_nfilters(filter_size), - d_max_dev(max_rate_deviation), - d_osps(osps), d_error(0), d_out_idx(0) -{ - d_nfilters = filter_size; - d_sps = floor(sps); - - // Set the damping factor for a critically damped system - d_damping = sqrtf(2.0f)/2.0f; - - // Set the bandwidth, which will then call update_gains() - set_loop_bandwidth(loop_bw); - - // Store the last filter between calls to work - // The accumulator keeps track of overflow to increment the stride correctly. - // set it here to the fractional difference based on the initial phaes - d_k = init_phase; - d_rate = (sps-floor(sps))*(double)d_nfilters; - d_rate_i = (int)floor(d_rate); - d_rate_f = d_rate - (float)d_rate_i; - d_filtnum = (int)floor(d_k); - - d_filters = std::vector<gr_fir_fff*>(d_nfilters); - d_diff_filters = std::vector<gr_fir_fff*>(d_nfilters); - - // Create an FIR filter for each channel and zero out the taps - std::vector<float> vtaps(0, d_nfilters); - for(int i = 0; i < d_nfilters; i++) { - d_filters[i] = gr_fir_util::create_gr_fir_fff(vtaps); - d_diff_filters[i] = gr_fir_util::create_gr_fir_fff(vtaps); - } - - // Now, actually set the filters' taps - std::vector<float> dtaps; - create_diff_taps(taps, dtaps); - set_taps(taps, d_taps, d_filters); - set_taps(dtaps, d_dtaps, d_diff_filters); -} - -digital_pfb_clock_sync_fff::~digital_pfb_clock_sync_fff () -{ - for(int i = 0; i < d_nfilters; i++) { - delete d_filters[i]; - delete d_diff_filters[i]; - } -} - -bool -digital_pfb_clock_sync_fff::check_topology(int ninputs, int noutputs) -{ - return noutputs == 1 || noutputs == 4; -} - -/******************************************************************* - SET FUNCTIONS -*******************************************************************/ - - -void -digital_pfb_clock_sync_fff::set_loop_bandwidth(float bw) -{ - if(bw < 0) { - throw std::out_of_range ("digital_pfb_clock_sync_fff: invalid bandwidth. Must be >= 0."); - } - - d_loop_bw = bw; - update_gains(); -} - -void -digital_pfb_clock_sync_fff::set_damping_factor(float df) -{ - if(df < 0 || df > 1.0) { - throw std::out_of_range ("digital_pfb_clock_sync_fff: invalid damping factor. Must be in [0,1]."); - } - - d_damping = df; - update_gains(); -} - -void -digital_pfb_clock_sync_fff::set_alpha(float alpha) -{ - if(alpha < 0 || alpha > 1.0) { - throw std::out_of_range ("digital_pfb_clock_sync_fff: invalid alpha. Must be in [0,1]."); - } - d_alpha = alpha; -} - -void -digital_pfb_clock_sync_fff::set_beta(float beta) -{ - if(beta < 0 || beta > 1.0) { - throw std::out_of_range ("digital_pfb_clock_sync_fff: invalid beta. Must be in [0,1]."); - } - d_beta = beta; -} - -/******************************************************************* - GET FUNCTIONS -*******************************************************************/ - - -float -digital_pfb_clock_sync_fff::get_loop_bandwidth() const -{ - return d_loop_bw; -} - -float -digital_pfb_clock_sync_fff::get_damping_factor() const -{ - return d_damping; -} - -float -digital_pfb_clock_sync_fff::get_alpha() const -{ - return d_alpha; -} - -float -digital_pfb_clock_sync_fff::get_beta() const -{ - return d_beta; -} - -float -digital_pfb_clock_sync_fff::get_clock_rate() const -{ - return d_rate_f; -} - -/******************************************************************* -*******************************************************************/ - -void -digital_pfb_clock_sync_fff::update_gains() -{ - float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); - d_alpha = (4*d_damping*d_loop_bw) / denom; - d_beta = (4*d_loop_bw*d_loop_bw) / denom; -} - - -void -digital_pfb_clock_sync_fff::set_taps (const std::vector<float> &newtaps, - std::vector< std::vector<float> > &ourtaps, - std::vector<gr_fir_fff*> &ourfilter) -{ - int i,j; - - unsigned int ntaps = newtaps.size(); - d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters); - - // Create d_numchan vectors to store each channel's taps - ourtaps.resize(d_nfilters); - - // Make a vector of the taps plus fill it out with 0's to fill - // each polyphase filter with exactly d_taps_per_filter - std::vector<float> tmp_taps; - tmp_taps = newtaps; - while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) { - tmp_taps.push_back(0.0); - } - - // Partition the filter - for(i = 0; i < d_nfilters; i++) { - // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out - ourtaps[i] = std::vector<float>(d_taps_per_filter, 0); - for(j = 0; j < d_taps_per_filter; j++) { - ourtaps[i][j] = tmp_taps[i + j*d_nfilters]; - } - - // Build a filter for each channel and add it's taps to it - ourfilter[i]->set_taps(ourtaps[i]); - } - - // Set the history to ensure enough input items for each filter - set_history (d_taps_per_filter + d_sps); - - // Make sure there is enough output space for d_osps outputs/input. - set_output_multiple(d_osps); - - d_updated = true; -} - -void -digital_pfb_clock_sync_fff::create_diff_taps(const std::vector<float> &newtaps, - std::vector<float> &difftaps) -{ - std::vector<float> diff_filter(3); - diff_filter[0] = -1; - diff_filter[1] = 0; - diff_filter[2] = 1; - - float pwr = 0; - difftaps.push_back(0); - for(unsigned int i = 0; i < newtaps.size()-2; i++) { - float tap = 0; - for(int j = 0; j < 3; j++) { - tap += diff_filter[j]*newtaps[i+j]; - pwr += fabsf(tap); - } - difftaps.push_back(tap); - } - difftaps.push_back(0); - - for(unsigned int i = 0; i < difftaps.size(); i++) { - difftaps[i] *= pwr; - } -} - -std::string -digital_pfb_clock_sync_fff::get_taps_as_string() -{ - int i, j; - std::stringstream str; - str.precision(4); - str.setf(std::ios::scientific); - - str << "[ "; - for(i = 0; i < d_nfilters; i++) { - str << "[" << d_taps[i][0] << ", "; - for(j = 1; j < d_taps_per_filter-1; j++) { - str << d_taps[i][j] << ", "; - } - str << d_taps[i][j] << "],"; - } - str << " ]" << std::endl; - - return str.str(); -} - -std::string -digital_pfb_clock_sync_fff::get_diff_taps_as_string() -{ - int i, j; - std::stringstream str; - str.precision(4); - str.setf(std::ios::scientific); - - str << "[ "; - for(i = 0; i < d_nfilters; i++) { - str << "[" << d_dtaps[i][0] << ", "; - for(j = 1; j < d_taps_per_filter-1; j++) { - str << d_dtaps[i][j] << ", "; - } - str << d_dtaps[i][j] << "],"; - } - str << " ]" << std::endl; - - return str.str(); -} - -std::vector< std::vector<float> > -digital_pfb_clock_sync_fff::get_taps() -{ - return d_taps; -} - -std::vector< std::vector<float> > -digital_pfb_clock_sync_fff::get_diff_taps() -{ - return d_dtaps; -} - -std::vector<float> -digital_pfb_clock_sync_fff::get_channel_taps(int channel) -{ - std::vector<float> taps; - for(int i = 0; i < d_taps_per_filter; i++) { - taps.push_back(d_taps[channel][i]); - } - return taps; -} - -std::vector<float> -digital_pfb_clock_sync_fff::get_diff_channel_taps(int channel) -{ - std::vector<float> taps; - for(int i = 0; i < d_taps_per_filter; i++) { - taps.push_back(d_dtaps[channel][i]); - } - return taps; -} - -int -digital_pfb_clock_sync_fff::general_work(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - float *in = (float *) input_items[0]; - float *out = (float *) output_items[0]; - - float *err = NULL, *outrate = NULL, *outk = NULL; - if(output_items.size() == 4) { - err = (float *) output_items[1]; - outrate = (float*)output_items[2]; - outk = (float*)output_items[3]; - } - - if (d_updated) { - d_updated = false; - return 0; // history requirements may have changed. - } - - // We need this many to process one output - int nrequired = ninput_items[0] - d_taps_per_filter - d_osps; - - int i = 0, count = 0; - - // produce output as long as we can and there are enough input samples - while((i < noutput_items) && (count < nrequired)) { - while(d_out_idx < d_osps) { - d_filtnum = (int)floor(d_k); - - // Keep the current filter number in [0, d_nfilters] - // If we've run beyond the last filter, wrap around and go to next sample - // If we've go below 0, wrap around and go to previous sample - while(d_filtnum >= d_nfilters) { - d_k -= d_nfilters; - d_filtnum -= d_nfilters; - count += 1; - } - while(d_filtnum < 0) { - d_k += d_nfilters; - d_filtnum += d_nfilters; - count -= 1; - } - - out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); - d_k = d_k + d_rate_i + d_rate_f; // update phase - d_out_idx++; - - if(output_items.size() == 4) { - err[i] = d_error; - outrate[i] = d_rate_f; - outk[i] = d_k; - } - - // We've run out of output items we can create; return now. - if(i+d_out_idx >= noutput_items) { - consume_each(count); - return i; - } - } - - // reset here; if we didn't complete a full osps samples last time, - // the early return would take care of it. - d_out_idx = 0; - - // Update the phase and rate estimates for this symbol - float diff = d_diff_filters[d_filtnum]->filter(&in[count]); - d_error = out[i] * diff; - - // Run the control loop to update the current phase (k) and - // tracking rate estimates based on the error value - d_rate_f = d_rate_f + d_beta*d_error; - d_k = d_k + d_alpha*d_error; - - // Keep our rate within a good range - d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev); - - i+=d_osps; - count += (int)floor(d_sps); - } - - consume_each(count); - return i; -} diff --git a/gr-digital/lib/digital_pn_correlator_cc.cc b/gr-digital/lib/digital_pn_correlator_cc.cc deleted file mode 100644 index 43a3ddbd1f..0000000000 --- a/gr-digital/lib/digital_pn_correlator_cc.cc +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_pn_correlator_cc.h> -#include <gr_io_signature.h> - -digital_pn_correlator_cc_sptr -digital_make_pn_correlator_cc(int degree, int mask, int seed) -{ - return gnuradio::get_initial_sptr(new digital_pn_correlator_cc - (degree, mask, seed)); -} - -digital_pn_correlator_cc::digital_pn_correlator_cc(int degree, - int mask, - int seed) - : gr_sync_decimator ("pn_correlator_cc", - gr_make_io_signature (1, 1, sizeof(gr_complex)), - gr_make_io_signature (1, 1, sizeof(gr_complex)), - (unsigned int)((1ULL << degree)-1)) // PN code length -{ - d_len = (unsigned int)((1ULL << degree)-1); - if (mask == 0) - mask = gri_glfsr::glfsr_mask(degree); - d_reference = new gri_glfsr(mask, seed); - for (int i = 0; i < d_len; i++) // initialize to last value in sequence - d_pn = 2.0*d_reference->next_bit()-1.0; -} - -digital_pn_correlator_cc::~digital_pn_correlator_cc() -{ - delete d_reference; -} - -int -digital_pn_correlator_cc::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]; - gr_complex sum; - - for (int i = 0; i < noutput_items; i++) { - sum = 0.0; - - for (int j = 0; j < d_len; j++) { - if (j != 0) // retard PN generator one sample per period - d_pn = 2.0*d_reference->next_bit()-1.0; // no conditionals - sum += *in++ * d_pn; - } - - *out++ = sum*gr_complex(1.0/d_len, 0.0); - } - - return noutput_items; -} diff --git a/gr-digital/lib/digital_probe_density_b.cc b/gr-digital/lib/digital_probe_density_b.cc deleted file mode 100644 index 6b83d2ddb7..0000000000 --- a/gr-digital/lib/digital_probe_density_b.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2010,2012 Free Software Foundation, Inc. - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_probe_density_b.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <iostream> - -digital_probe_density_b_sptr -digital_make_probe_density_b(double alpha) -{ - return gnuradio::get_initial_sptr(new digital_probe_density_b(alpha)); -} - -digital_probe_density_b::digital_probe_density_b(double alpha) - : gr_sync_block("density_b", - gr_make_io_signature(1, 1, sizeof(char)), - gr_make_io_signature(0, 0, 0)) -{ - set_alpha(alpha); - d_density = 1.0; -} - -digital_probe_density_b::~digital_probe_density_b() -{ -} - -int -digital_probe_density_b::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const char *in = (const char *)input_items[0]; - - for (int i = 0; i < noutput_items; i++) - d_density = d_alpha*(double)in[i] + d_beta*d_density; - - return noutput_items; -} - -void -digital_probe_density_b::set_alpha(double alpha) -{ - d_alpha = alpha; - d_beta = 1.0-d_alpha; -} - diff --git a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc b/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc deleted file mode 100644 index 5cdfea96d1..0000000000 --- a/gr-digital/lib/digital_probe_mpsk_snr_est_c.cc +++ /dev/null @@ -1,152 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2011 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. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <digital_probe_mpsk_snr_est_c.h> -#include <gr_io_signature.h> -#include <cstdio> - -digital_probe_mpsk_snr_est_c_sptr -digital_make_probe_mpsk_snr_est_c(snr_est_type_t type, - int msg_nsamples, - double alpha) -{ - return gnuradio::get_initial_sptr( - new digital_probe_mpsk_snr_est_c(type, msg_nsamples, alpha)); -} - -digital_probe_mpsk_snr_est_c::digital_probe_mpsk_snr_est_c( - snr_est_type_t type, - int msg_nsamples, - double alpha) - : gr_sync_block ("probe_mpsk_snr_est_c", - gr_make_io_signature(1, 1, sizeof(gr_complex)), - gr_make_io_signature(0, 0, 0)) -{ - d_snr_est = NULL; - - d_type = type; - d_nsamples = msg_nsamples; - d_count = 0; - set_alpha(alpha); - - set_type(type); - - // at least 1 estimator has to look back - set_history(2); - - d_key = pmt::pmt_string_to_symbol("snr"); -} - -digital_probe_mpsk_snr_est_c::~digital_probe_mpsk_snr_est_c() -{ - if(d_snr_est) - delete d_snr_est; -} - -int -digital_probe_mpsk_snr_est_c::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]; - return d_snr_est->update(noutput_items, in); -} - -double -digital_probe_mpsk_snr_est_c::snr() -{ - if(d_snr_est) - return d_snr_est->snr(); - else - throw std::runtime_error("digital_probe_mpsk_snr_est_c:: No SNR estimator defined.\n"); -} - -snr_est_type_t -digital_probe_mpsk_snr_est_c::type() const -{ - return d_type; -} - -int -digital_probe_mpsk_snr_est_c::msg_nsample() const -{ - return d_nsamples; -} - -double -digital_probe_mpsk_snr_est_c::alpha() const -{ - return d_alpha; -} - -void -digital_probe_mpsk_snr_est_c::set_type(snr_est_type_t t) -{ - d_type = t; - - if(d_snr_est) - delete d_snr_est; - - switch (d_type) { - case(SNR_EST_SIMPLE): - d_snr_est = new digital_impl_mpsk_snr_est_simple(d_alpha); - break; - case(SNR_EST_SKEW): - d_snr_est = new digital_impl_mpsk_snr_est_skew(d_alpha); - break; - case(SNR_EST_M2M4): - d_snr_est = new digital_impl_mpsk_snr_est_m2m4(d_alpha); - break; - case(SNR_EST_SVR): - d_snr_est = new digital_impl_mpsk_snr_est_svr(d_alpha); - break; - default: - throw std::invalid_argument("digital_probe_mpsk_snr_est_c: unknown type specified.\n"); - } -} - -void -digital_probe_mpsk_snr_est_c::set_msg_nsample(int n) -{ - if(n > 0) { - d_nsamples = n; - d_count = 0; // reset state - } - else - throw std::invalid_argument("digital_probe_mpsk_snr_est_c: msg_nsamples can't be <= 0\n"); -} - -void -digital_probe_mpsk_snr_est_c::set_alpha(double alpha) -{ - if((alpha >= 0) && (alpha <= 1.0)) { - d_alpha = alpha; - if(d_snr_est) - d_snr_est->set_alpha(d_alpha); - } - else - throw std::invalid_argument("digital_probe_mpsk_snr_est_c: alpha must be in [0,1]\n"); -} diff --git a/gr-digital/lib/digital_scrambler_bb.cc b/gr-digital/lib/digital_scrambler_bb.cc deleted file mode 100644 index c81b09d8c3..0000000000 --- a/gr-digital/lib/digital_scrambler_bb.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_scrambler_bb.h> -#include <gr_io_signature.h> - -digital_scrambler_bb_sptr -digital_make_scrambler_bb(int mask, int seed, int len) -{ - return gnuradio::get_initial_sptr(new digital_scrambler_bb - (mask, seed, len)); -} - -digital_scrambler_bb::digital_scrambler_bb(int mask, int seed, int len) - : gr_sync_block("scrambler_bb", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_lfsr(mask, seed, len) -{ -} - -int -digital_scrambler_bb::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - for (int i = 0; i < noutput_items; i++) - out[i] = d_lfsr.next_bit_scramble(in[i]); - - return noutput_items; -} diff --git a/gr-digital/lib/digital_simple_correlator.cc b/gr-digital/lib/digital_simple_correlator.cc deleted file mode 100644 index 37ef2f1e5f..0000000000 --- a/gr-digital/lib/digital_simple_correlator.cc +++ /dev/null @@ -1,231 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_simple_correlator.h> -#include <digital_simple_framer_sync.h> -#include <gr_io_signature.h> -#include <gr_count_bits.h> -#include <assert.h> -#include <stdexcept> -#include <string.h> -#include <cstdio> - -static const int THRESHOLD = 3; - -digital_simple_correlator_sptr -digital_make_simple_correlator(int payload_bytesize) -{ - return gnuradio::get_initial_sptr - (new digital_simple_correlator(payload_bytesize)); -} - -digital_simple_correlator::digital_simple_correlator(int payload_bytesize) - : gr_block("simple_correlator", - gr_make_io_signature(1, 1, sizeof(float)), - gr_make_io_signature(1, 1, sizeof(unsigned char))), - d_payload_bytesize(payload_bytesize), - d_state(ST_LOOKING), d_osi(0), - d_bblen((payload_bytesize + GRSF_PAYLOAD_OVERHEAD) * GRSF_BITS_PER_BYTE), - d_bitbuf(new unsigned char[d_bblen]), - d_pktbuf(new unsigned char[d_bblen/GRSF_BITS_PER_BYTE]), - d_bbi(0) -{ - d_avbi = 0; - d_accum = 0.0; - d_avg = 0.0; - for(int i = 0; i < AVG_PERIOD; i++) - d_avgbuf[i] = 0.0; - -#ifdef DEBUG_SIMPLE_CORRELATOR - d_debug_fp = fopen("corr.log", "w"); -#endif - enter_looking(); -} - -digital_simple_correlator::~digital_simple_correlator() -{ -#ifdef DEBUG_SIMPLE_CORRELATOR - fclose(d_debug_fp); -#endif - delete [] d_bitbuf; - delete [] d_pktbuf; -} - -void -digital_simple_correlator::enter_looking() -{ - fflush(stdout); - // fprintf(stderr, ">>> enter_looking\n"); - d_state = ST_LOOKING; - for(int i = 0; i < OVERSAMPLE; i++) - d_shift_reg[i] = 0; - d_osi = 0; - - d_avbi = 0; - d_avg = d_avg * 0.5; - d_accum = 0; - for(int i = 0; i < AVG_PERIOD; i++) - d_avgbuf[i] = 0.0; -} - -void -digital_simple_correlator::enter_under_threshold() -{ - fflush(stdout); - // fprintf(stderr, ">>> enter_under_threshold\n"); - d_state = ST_UNDER_THRESHOLD; - d_transition_osi = d_osi; -} - -void -digital_simple_correlator::enter_locked() -{ - d_state = ST_LOCKED; - int delta = sub_index(d_osi, d_transition_osi); - d_center_osi = add_index(d_transition_osi, delta/2); - //d_center_osi = add_index(d_center_osi, 3); // FIXME - d_bbi = 0; - fflush(stdout); - // fprintf(stderr, ">>> enter_locked d_center_osi = %d\n", d_center_osi); - - d_avg = std::max(-1.0, std::min(1.0, d_accum * (1.0/AVG_PERIOD))); - // fprintf(stderr, ">>> enter_locked d_avg = %g\n", d_avg); -} - -static void -packit(unsigned char *pktbuf, const unsigned char *bitbuf, int bitcount) -{ - for(int i = 0; i < bitcount; i += 8) { - int t = bitbuf[i+0] & 0x1; - t = (t << 1) | (bitbuf[i+1] & 0x1); - t = (t << 1) | (bitbuf[i+2] & 0x1); - t = (t << 1) | (bitbuf[i+3] & 0x1); - t = (t << 1) | (bitbuf[i+4] & 0x1); - t = (t << 1) | (bitbuf[i+5] & 0x1); - t = (t << 1) | (bitbuf[i+6] & 0x1); - t = (t << 1) | (bitbuf[i+7] & 0x1); - *pktbuf++ = t; - } -} - -void -digital_simple_correlator::update_avg(float x) -{ - d_accum -= d_avgbuf[d_avbi]; - d_avgbuf[d_avbi] = x; - d_accum += x; - d_avbi = (d_avbi + 1) & (AVG_PERIOD-1); -} - -int -digital_simple_correlator::general_work(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const float *in = (const float*)input_items[0]; - unsigned char *out = (unsigned char*)output_items[0]; - - int n = 0; - int nin = ninput_items[0]; - int decision; - int hamming_dist; - -#ifdef DEBUG_SIMPLE_CORRELATOR - struct debug_data { - float raw_data; - float sampled; - float enter_locked; - } debug_data; -#endif - - while(n < nin) { - -#ifdef DEBUG_SIMPLE_CORRELATOR - debug_data.raw_data = in[n]; - debug_data.sampled = 0.0; - debug_data.enter_locked = 0.0; -#endif - - switch(d_state) { - case ST_LOCKED: - if(d_osi == d_center_osi) { - -#ifdef DEBUG_SIMPLE_CORRELATOR - debug_data.sampled = 1.0; -#endif - decision = slice(in[n]); - - d_bitbuf[d_bbi] = decision; - d_bbi++; - if(d_bbi >= d_bblen) { - // printf("got whole packet\n"); - packit(d_pktbuf, d_bitbuf, d_bbi); - //printf("seqno %3d\n", d_pktbuf[0]); - memcpy(out, &d_pktbuf[GRSF_PAYLOAD_OVERHEAD], d_payload_bytesize); - enter_looking(); - consume_each(n + 1); - return d_payload_bytesize; - } - } - break; - - case ST_LOOKING: - case ST_UNDER_THRESHOLD: - update_avg(in[n]); - decision = slice(in[n]); - - d_shift_reg[d_osi] = (d_shift_reg[d_osi] << 1) | decision; - hamming_dist = gr_count_bits64(d_shift_reg[d_osi] ^ GRSF_SYNC); - //fprintf(stderr, "%2d %d\n", hamming_dist, d_osi); - - if(d_state == ST_LOOKING && hamming_dist <= THRESHOLD) { - // We're seeing a good PN code, remember location - enter_under_threshold(); - } - else if(d_state == ST_UNDER_THRESHOLD && hamming_dist > THRESHOLD) { - // no longer seeing good PN code, compute center of goodness - enter_locked(); -#ifdef DEBUG_SIMPLE_CORRELATOR - debug_data.enter_locked = 1.0; -#endif - } - break; - default: - assert(0); - } - -#ifdef DEBUG_SIMPLE_CORRELATOR - fwrite(&debug_data, sizeof(debug_data), 1, d_debug_fp); -#endif - - d_osi = add_index(d_osi, 1); - n++; - } - - consume_each(n); - return 0; -} diff --git a/gr-digital/lib/digital_simple_framer.cc b/gr-digital/lib/digital_simple_framer.cc deleted file mode 100644 index 5c194543ca..0000000000 --- a/gr-digital/lib/digital_simple_framer.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2010,2012 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <digital_simple_framer.h> -#include <digital_simple_framer_sync.h> -#include <gr_io_signature.h> -#include <assert.h> -#include <stdexcept> -#include <string.h> - - -digital_simple_framer_sptr -digital_make_simple_framer (int payload_bytesize) -{ - return gnuradio::get_initial_sptr(new digital_simple_framer - (payload_bytesize)); -} - -digital_simple_framer::digital_simple_framer (int payload_bytesize) - : gr_block ("simple_framer", - gr_make_io_signature (1, 1, sizeof (unsigned char)), - gr_make_io_signature (1, 1, sizeof (unsigned char))), - d_seqno (0), d_payload_bytesize (payload_bytesize), - d_input_block_size (payload_bytesize), - d_output_block_size (payload_bytesize + GRSF_OVERHEAD) -{ - set_output_multiple (d_output_block_size); -} - -void -digital_simple_framer::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - assert (noutput_items % d_output_block_size == 0); - - int nblocks = noutput_items / d_output_block_size; - int input_required = nblocks * d_input_block_size; - - unsigned ninputs = ninput_items_required.size(); - for (unsigned int i = 0; i < ninputs; i++) - ninput_items_required[i] = input_required; -} - -int -digital_simple_framer::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const unsigned char *in = (const unsigned char *) input_items[0]; - unsigned char *out = (unsigned char *) output_items[0]; - - int n = 0; - int nblocks = 0; - - memset (out, 0x55, noutput_items); - - while (n < noutput_items) { - out[0] = (GRSF_SYNC >> 56) & 0xff; - out[1] = (GRSF_SYNC >> 48) & 0xff; - out[2] = (GRSF_SYNC >> 40) & 0xff; - out[3] = (GRSF_SYNC >> 32) & 0xff; - out[4] = (GRSF_SYNC >> 24) & 0xff; - out[5] = (GRSF_SYNC >> 16) & 0xff; - out[6] = (GRSF_SYNC >> 8) & 0xff; - out[7] = (GRSF_SYNC >> 0) & 0xff; - out[8] = d_seqno++; - - memcpy (&out[9], in, d_input_block_size); - in += d_input_block_size; - out += d_output_block_size; - n += d_output_block_size; - nblocks++; - } - - assert (n == noutput_items); - - consume_each (nblocks * d_input_block_size); - return n; -} diff --git a/gr-digital/lib/fll_band_edge_cc_impl.cc b/gr-digital/lib/fll_band_edge_cc_impl.cc new file mode 100644 index 0000000000..980d3ab464 --- /dev/null +++ b/gr-digital/lib/fll_band_edge_cc_impl.cc @@ -0,0 +1,276 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "fll_band_edge_cc_impl.h" +#include <gr_io_signature.h> +#include <gr_expj.h> +#include <cstdio> + +namespace gr { + namespace digital { + +#define M_TWOPI (2*M_PI) + + float sinc(float x) + { + if(x == 0) + return 1; + else + return sin(M_PI*x)/(M_PI*x); + } + + fll_band_edge_cc::sptr + fll_band_edge_cc::make(float samps_per_sym, float rolloff, + int filter_size, float bandwidth) + { + return gnuradio::get_initial_sptr + (new fll_band_edge_cc_impl(samps_per_sym, rolloff, + filter_size, bandwidth)); + } + + static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; + static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); + fll_band_edge_cc_impl::fll_band_edge_cc_impl(float samps_per_sym, float rolloff, + int filter_size, float bandwidth) + : gr_sync_block("fll_band_edge_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signaturev(1, 4, iosig)), + gri_control_loop(bandwidth, M_TWOPI*(2.0/samps_per_sym), + -M_TWOPI*(2.0/samps_per_sym)), + d_updated(false) + { + // Initialize samples per symbol + if(samps_per_sym <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid number of sps. Must be > 0."); + } + d_sps = samps_per_sym; + + // Initialize rolloff factor + if(rolloff < 0 || rolloff > 1.0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1]."); + } + d_rolloff = rolloff; + + // Initialize filter length + if(filter_size <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid filter size. Must be > 0."); + } + d_filter_size = filter_size; + + // Build the band edge filters + design_filter(d_sps, d_rolloff, d_filter_size); + d_output_hist.resize(filter_size,0); + } + + fll_band_edge_cc_impl::~fll_band_edge_cc_impl() + { + } + + /******************************************************************* + SET FUNCTIONS + *******************************************************************/ + + void + fll_band_edge_cc_impl::set_samples_per_symbol(float sps) + { + if(sps <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid number of sps. Must be > 0."); + } + d_sps = sps; + design_filter(d_sps, d_rolloff, d_filter_size); + } + + void + fll_band_edge_cc_impl::set_rolloff(float rolloff) + { + if(rolloff < 0 || rolloff > 1.0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid rolloff factor. Must be in [0,1]."); + } + d_rolloff = rolloff; + design_filter(d_sps, d_rolloff, d_filter_size); + } + + void + fll_band_edge_cc_impl::set_filter_size(int filter_size) + { + if(filter_size <= 0) { + throw std::out_of_range("digital_fll_band_edge_cc: invalid filter size. Must be > 0."); + } + d_filter_size = filter_size; + design_filter(d_sps, d_rolloff, d_filter_size); + } + + /******************************************************************* + GET FUNCTIONS + *******************************************************************/ + + float + fll_band_edge_cc_impl::samples_per_symbol() const + { + return d_sps; + } + + float + fll_band_edge_cc_impl::rolloff() const + { + return d_rolloff; + } + + int + fll_band_edge_cc_impl::filter_size() const + { + return d_filter_size; + } + + /******************************************************************* + *******************************************************************/ + + void + fll_band_edge_cc_impl::design_filter(float samps_per_sym, + float rolloff, int filter_size) + { + int M = rint(filter_size / samps_per_sym); + float power = 0; + + // Create the baseband filter by adding two sincs together + std::vector<float> bb_taps; + for(int i = 0; i < filter_size; i++) { + float k = -M + i*2.0/samps_per_sym; + float tap = sinc(rolloff*k - 0.5) + sinc(rolloff*k + 0.5); + power += tap; + + bb_taps.push_back(tap); + } + + d_taps_lower.resize(filter_size); + d_taps_upper.resize(filter_size); + + // Create the band edge filters by spinning the baseband + // filter up and down to the right places in frequency. + // Also, normalize the power in the filters + int N = (bb_taps.size() - 1.0)/2.0; + for(int i = 0; i < filter_size; i++) { + float tap = bb_taps[i] / power; + + float k = (-N + (int)i)/(2.0*samps_per_sym); + + gr_complex t1 = tap * gr_expj(-M_TWOPI*(1+rolloff)*k); + gr_complex t2 = tap * gr_expj(M_TWOPI*(1+rolloff)*k); + + d_taps_lower[filter_size-i-1] = t1; + d_taps_upper[filter_size-i-1] = t2; + } + + d_updated = true; + + // Set the history to ensure enough input items for each filter + set_history(filter_size+1); + d_filter_upper = new gr::filter::kernel::fir_filter_ccc(1, d_taps_upper); + d_filter_lower = new gr::filter::kernel::fir_filter_ccc(1, d_taps_lower); + } + + void + fll_band_edge_cc_impl::print_taps() + { + unsigned int i; + + printf("Upper Band-edge: ["); + for(i = 0; i < d_taps_upper.size(); i++) { + printf(" %.4e + %.4ej,", d_taps_upper[i].real(), d_taps_upper[i].imag()); + } + printf("]\n\n"); + + printf("Lower Band-edge: ["); + for(i = 0; i < d_taps_lower.size(); i++) { + printf(" %.4e + %.4ej,", d_taps_lower[i].real(), d_taps_lower[i].imag()); + } + printf("]\n\n"); + } + + int + fll_band_edge_cc_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]; + + d_fllbuffer.reserve(d_filter_size+noutput_items); + + float *frq = NULL; + float *phs = NULL; + float *err = NULL; + if(output_items.size() == 4) { + frq = (float*)output_items[1]; + phs = (float*)output_items[2]; + err = (float*)output_items[3]; + } + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + int i; + float error; + gr_complex nco_out; + gr_complex out_upper, out_lower; + gr_complex out_uppersse, out_lowersse; + copy(d_output_hist.begin(), d_output_hist.end(), d_fllbuffer.begin()); + + for(i = 0; i < noutput_items; i++) { + nco_out = gr_expj(d_phase); + d_fllbuffer[i+d_filter_size] = in[i] * nco_out; + // Perform the dot product of the output with the filters + out_upper = 0; + out_lower = 0; + + out_upper = d_filter_lower->filter(&d_fllbuffer[i]); + out_lower = d_filter_upper->filter(&d_fllbuffer[i]); + + error = norm(out_lower) - norm(out_upper); + + advance_loop(error); + phase_wrap(); + frequency_limit(); + + if(output_items.size() == 4) { + frq[i] = d_freq; + phs[i] = d_phase; + err[i] = error; + } + } + + copy(d_fllbuffer.begin(), d_fllbuffer.begin()+noutput_items, out); + copy(d_fllbuffer.begin()+noutput_items, + d_fllbuffer.begin()+noutput_items+d_filter_size, + d_output_hist.begin()); + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/fll_band_edge_cc_impl.h b/gr-digital/lib/fll_band_edge_cc_impl.h new file mode 100644 index 0000000000..55e338b38c --- /dev/null +++ b/gr-digital/lib/fll_band_edge_cc_impl.h @@ -0,0 +1,82 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_IMPL_H +#define INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_IMPL_H + +#include <digital/fll_band_edge_cc.h> +#include <gri_control_loop.h> +#include <filter/fir_filter.h> + +namespace gr { + namespace digital { + + class fll_band_edge_cc_impl : + public fll_band_edge_cc + { + private: + float d_sps; + float d_rolloff; + int d_filter_size; + + std::vector<gr_complex> d_taps_lower; + std::vector<gr_complex> d_taps_upper; + bool d_updated; + std::vector<gr_complex> d_output_hist; + std::vector<gr_complex> d_fllbuffer; + gr::filter::kernel::fir_filter_ccc* d_filter_lower; + gr::filter::kernel::fir_filter_ccc* d_filter_upper; + + /*! + * Design the band-edge filter based on the number of samples + * per symbol, filter rolloff factor, and the filter size + * + * \param samps_per_sym (float) Number of samples per symbol of signal + * \param rolloff (float) Rolloff factor of signal + * \param filter_size (int) Size (in taps) of the filter + */ + void design_filter(float samps_per_sym, float rolloff, int filter_size); + + public: + fll_band_edge_cc_impl(float samps_per_sym, float rolloff, + int filter_size, float bandwidth); + ~fll_band_edge_cc_impl(); + + void set_samples_per_symbol(float sps); + void set_rolloff(float rolloff); + void set_filter_size(int filter_size); + + float samples_per_symbol() const; + float rolloff() const; + int filter_size() const; + + void print_taps(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_FLL_BAND_EDGE_CC_IMPL_H */ diff --git a/gr-digital/lib/framer_sink_1_impl.cc b/gr-digital/lib/framer_sink_1_impl.cc new file mode 100644 index 0000000000..1dda5ca50c --- /dev/null +++ b/gr-digital/lib/framer_sink_1_impl.cc @@ -0,0 +1,195 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "framer_sink_1_impl.h" +#include <gr_io_signature.h> +#include <cstdio> +#include <string> + +namespace gr { + namespace digital { + +#define VERBOSE 0 + + inline void + framer_sink_1_impl::enter_search() + { + if(VERBOSE) + fprintf(stderr, "@ enter_search\n"); + + d_state = STATE_SYNC_SEARCH; + } + + inline void + framer_sink_1_impl::enter_have_sync() + { + if (VERBOSE) + fprintf(stderr, "@ enter_have_sync\n"); + + d_state = STATE_HAVE_SYNC; + d_header = 0; + d_headerbitlen_cnt = 0; + } + + inline void + framer_sink_1_impl::enter_have_header(int payload_len, + int whitener_offset) + { + if(VERBOSE) + fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n", + payload_len, whitener_offset); + + d_state = STATE_HAVE_HEADER; + d_packetlen = payload_len; + d_packet_whitener_offset = whitener_offset; + d_packetlen_cnt = 0; + d_packet_byte = 0; + d_packet_byte_index = 0; + } + + framer_sink_1::sptr + framer_sink_1::make(gr_msg_queue_sptr target_queue) + { + return gnuradio::get_initial_sptr + (new framer_sink_1_impl(target_queue)); + } + + framer_sink_1_impl::framer_sink_1_impl(gr_msg_queue_sptr target_queue) + : gr_sync_block("framer_sink_1", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(0, 0, 0)), + d_target_queue(target_queue) + { + enter_search(); + } + + framer_sink_1_impl::~framer_sink_1_impl() + { + } + + int + framer_sink_1_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + int count=0; + + if(VERBOSE) + fprintf(stderr,">>> Entering state machine\n"); + + while(count < noutput_items){ + switch(d_state) { + + case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt + if(VERBOSE) + fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items); + + while(count < noutput_items) { + if(in[count] & 0x2){ // Found it, set up for header decode + enter_have_sync(); + break; + } + count++; + } + break; + + case STATE_HAVE_SYNC: + if(VERBOSE) + fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n", + d_headerbitlen_cnt, d_header); + + while(count < noutput_items) { // Shift bits one at a time into header + d_header = (d_header << 1) | (in[count++] & 0x1); + if(++d_headerbitlen_cnt == HEADERBITLEN) { + + if(VERBOSE) + fprintf(stderr, "got header: 0x%08x\n", d_header); + + // we have a full header, check to see if it has been received properly + if(header_ok()) { + int payload_len; + int whitener_offset; + header_payload(&payload_len, &whitener_offset); + enter_have_header(payload_len, whitener_offset); + + if(d_packetlen == 0) { // check for zero-length payload + // build a zero-length message + // NOTE: passing header field as arg1 is not scalable + gr_message_sptr msg = + gr_make_message(0, d_packet_whitener_offset, 0, 0); + + d_target_queue->insert_tail(msg); // send it + msg.reset(); // free it up + + enter_search(); + } + } + else + enter_search(); // bad header + break; // we're in a new state + } + } + break; + + case STATE_HAVE_HEADER: + if(VERBOSE) + fprintf(stderr,"Packet Build\n"); + + while(count < noutput_items) { // shift bits into bytes of packet one at a time + d_packet_byte = (d_packet_byte << 1) | (in[count++] & 0x1); + if(d_packet_byte_index++ == 7) { // byte is full so move to next byte + d_packet[d_packetlen_cnt++] = d_packet_byte; + d_packet_byte_index = 0; + + if(d_packetlen_cnt == d_packetlen) { // packet is filled + // build a message + // NOTE: passing header field as arg1 is not scalable + gr_message_sptr msg = + gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt); + memcpy(msg->msg(), d_packet, d_packetlen_cnt); + + d_target_queue->insert_tail(msg); // send it + msg.reset(); // free it up + + enter_search(); + break; + } + } + } + break; + + default: + assert(0); + } // switch + + } // while + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/framer_sink_1_impl.h b/gr-digital/lib/framer_sink_1_impl.h new file mode 100644 index 0000000000..ff2839acbf --- /dev/null +++ b/gr-digital/lib/framer_sink_1_impl.h @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006,2012 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. + */ + +#ifndef INCLUDED_GR_FRAMER_SINK_1_IMPL_H +#define INCLUDED_GR_FRAMER_SINK_1_IMPL_H + +#include <digital/framer_sink_1.h> + +namespace gr { + namespace digital { + + class framer_sink_1_impl : public framer_sink_1 + { + private: + enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER}; + + static const int MAX_PKT_LEN = 4096; + static const int HEADERBITLEN = 32; + + gr_msg_queue_sptr d_target_queue; // where to send the packet when received + state_t d_state; + unsigned int d_header; // header bits + int d_headerbitlen_cnt; // how many so far + + unsigned char d_packet[MAX_PKT_LEN]; // assembled payload + unsigned char d_packet_byte; // byte being assembled + int d_packet_byte_index; // which bit of d_packet_byte we're working on + int d_packetlen; // length of packet + int d_packet_whitener_offset; // offset into whitener string to use + int d_packetlen_cnt; // how many so far + + protected: + void enter_search(); + void enter_have_sync(); + void enter_have_header(int payload_len, int whitener_offset); + + bool header_ok() + { + // confirm that two copies of header info are identical + return ((d_header >> 16) ^ (d_header & 0xffff)) == 0; + } + + void header_payload(int *len, int *offset) + { + // header consists of two 16-bit shorts in network byte order + // payload length is lower 12 bits + // whitener offset is upper 4 bits + *len = (d_header >> 16) & 0x0fff; + *offset = (d_header >> 28) & 0x000f; + } + + public: + framer_sink_1_impl(gr_msg_queue_sptr target_queue); + ~framer_sink_1_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_FRAMER_SINK_1_IMPL_H */ diff --git a/gr-digital/lib/glfsr.cc b/gr-digital/lib/glfsr.cc new file mode 100644 index 0000000000..5c9d22af88 --- /dev/null +++ b/gr-digital/lib/glfsr.cc @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2012 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. + */ + +#include <digital/glfsr.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + static int s_polynomial_masks[] = { + 0x00000000, + 0x00000001, // x^1 + 1 + 0x00000003, // x^2 + x^1 + 1 + 0x00000005, // x^3 + x^1 + 1 + 0x00000009, // x^4 + x^1 + 1 + 0x00000012, // x^5 + x^2 + 1 + 0x00000021, // x^6 + x^1 + 1 + 0x00000041, // x^7 + x^1 + 1 + 0x0000008E, // x^8 + x^4 + x^3 + x^2 + 1 + 0x00000108, // x^9 + x^4 + 1 + 0x00000204, // x^10 + x^4 + 1 + 0x00000402, // x^11 + x^2 + 1 + 0x00000829, // x^12 + x^6 + x^4 + x^1 + 1 + 0x0000100D, // x^13 + x^4 + x^3 + x^1 + 1 + 0x00002015, // x^14 + x^5 + x^3 + x^1 + 1 + 0x00004001, // x^15 + x^1 + 1 + 0x00008016, // x^16 + x^5 + x^3 + x^2 + 1 + 0x00010004, // x^17 + x^3 + 1 + 0x00020013, // x^18 + x^5 + x^2 + x^1 + 1 + 0x00040013, // x^19 + x^5 + x^2 + x^1 + 1 + 0x00080004, // x^20 + x^3 + 1 + 0x00100002, // x^21 + x^2 + 1 + 0x00200001, // x^22 + x^1 + 1 + 0x00400010, // x^23 + x^5 + 1 + 0x0080000D, // x^24 + x^4 + x^3 + x^1 + 1 + 0x01000004, // x^25 + x^3 + 1 + 0x02000023, // x^26 + x^6 + x^2 + x^1 + 1 + 0x04000013, // x^27 + x^5 + x^2 + x^1 + 1 + 0x08000004, // x^28 + x^3 + 1 + 0x10000002, // x^29 + x^2 + 1 + 0x20000029, // x^30 + x^4 + x^1 + 1 + 0x40000004, // x^31 + x^3 + 1 + 0x80000057 // x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + 1 + }; + + glfsr::~glfsr() + { + } + + int glfsr::glfsr_mask(int degree) + { + if(degree < 1 || degree > 32) + throw std::runtime_error("glfsr::glfsr_mask(): degree must be between 1 and 32 inclusive"); + return s_polynomial_masks[degree]; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/glfsr_source_b_impl.cc b/gr-digital/lib/glfsr_source_b_impl.cc new file mode 100644 index 0000000000..e4171d80e7 --- /dev/null +++ b/gr-digital/lib/glfsr_source_b_impl.cc @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "glfsr_source_b_impl.h" +#include <gr_io_signature.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + glfsr_source_b::sptr + glfsr_source_b::make(int degree, bool repeat, int mask, int seed) + { + return gnuradio::get_initial_sptr + (new glfsr_source_b_impl(degree, repeat, mask, seed)); + } + + glfsr_source_b_impl::glfsr_source_b_impl(int degree, bool repeat, + int mask, int seed) + : gr_sync_block("glfsr_source_b", + gr_make_io_signature(0, 0, 0), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_repeat(repeat), d_index(0) + { + if(degree < 1 || degree > 32) + throw std::runtime_error("glfsr_source_b_impl: degree must be between 1 and 32 inclusive"); + d_length = (unsigned int)((1ULL << degree)-1); + + if(mask == 0) + mask = glfsr::glfsr_mask(degree); + d_glfsr = new glfsr(mask, seed); + } + + glfsr_source_b_impl::~glfsr_source_b_impl() + { + delete d_glfsr; + } + + int + glfsr_source_b_impl::mask() const + { + return d_glfsr->mask(); + } + + int + glfsr_source_b_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + char *out = (char*)output_items[0]; + if((d_index > d_length) && d_repeat == false) + return -1; /* once through the sequence */ + + int i; + for(i = 0; i < noutput_items; i++) { + out[i] = d_glfsr->next_bit(); + d_index++; + if(d_index > d_length && d_repeat == false) + break; + } + + return i; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/glfsr_source_b_impl.h b/gr-digital/lib/glfsr_source_b_impl.h new file mode 100644 index 0000000000..f52cfa0f20 --- /dev/null +++ b/gr-digital/lib/glfsr_source_b_impl.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2012 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. + */ + +#ifndef INCLUDED_GR_GLFSR_SOURCE_B_IMPL_H +#define INCLUDED_GR_GLFSR_SOURCE_B_IMPL_H + +#include <digital/glfsr_source_b.h> +#include <digital/glfsr.h> + +namespace gr { + namespace digital { + + class glfsr_source_b_impl : public glfsr_source_b + { + private: + glfsr *d_glfsr; + + bool d_repeat; + unsigned int d_index; + unsigned int d_length; + + public: + glfsr_source_b_impl(int degree, bool repeat=true, + int mask=0, int seed=1); + ~glfsr_source_b_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + unsigned int period() const { return d_length; } + int mask() const; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_GLFSR_SOURCE_B_IMPL_H */ diff --git a/gr-digital/lib/glfsr_source_f_impl.cc b/gr-digital/lib/glfsr_source_f_impl.cc new file mode 100644 index 0000000000..1e0ee2d85e --- /dev/null +++ b/gr-digital/lib/glfsr_source_f_impl.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2010,2012 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. + */ + + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "glfsr_source_f_impl.h" +#include <gr_io_signature.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + glfsr_source_f::sptr + glfsr_source_f::make(int degree, bool repeat, int mask, int seed) + { + return gnuradio::get_initial_sptr + (new glfsr_source_f_impl(degree, repeat, mask, seed)); + } + + glfsr_source_f_impl::glfsr_source_f_impl(int degree, bool repeat, + int mask, int seed) + : gr_sync_block("glfsr_source_f", + gr_make_io_signature(0, 0, 0), + gr_make_io_signature(1, 1, sizeof(float))), + d_repeat(repeat), d_index(0) + { + if(degree < 1 || degree > 32) + throw std::runtime_error("glfsr_source_f_impl: degree must be between 1 and 32 inclusive"); + d_length = (unsigned int)((1ULL << degree)-1); + + if(mask == 0) + mask = glfsr::glfsr_mask(degree); + d_glfsr = new glfsr(mask, seed); + } + + glfsr_source_f_impl::~glfsr_source_f_impl() + { + delete d_glfsr; + } + + int + glfsr_source_f_impl::mask() const + { + return d_glfsr->mask(); + } + + int + glfsr_source_f_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + float *out = (float *) output_items[0]; + if((d_index > d_length) && d_repeat == false) + return -1; /* once through the sequence */ + + int i; + for(i = 0; i < noutput_items; i++) { + out[i] = (float)d_glfsr->next_bit()*2.0-1.0; + d_index++; + if(d_index > d_length && d_repeat == false) + break; + } + + return i; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/glfsr_source_f_impl.h b/gr-digital/lib/glfsr_source_f_impl.h new file mode 100644 index 0000000000..4168016097 --- /dev/null +++ b/gr-digital/lib/glfsr_source_f_impl.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2012 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. + */ + +#ifndef INCLUDED_GR_GLFSR_SOURCE_F_IMPL_H +#define INCLUDED_GR_GLFSR_SOURCE_F_IMPL_H + +#include <digital/glfsr_source_f.h> +#include <digital/glfsr.h> + +namespace gr { + namespace digital { + + class glfsr_source_f_impl : public glfsr_source_f + { + private: + glfsr *d_glfsr; + + bool d_repeat; + unsigned int d_index; + unsigned int d_length; + + public: + glfsr_source_f_impl(int degree, bool repeat=true, + int mask=0, int seed=1); + ~glfsr_source_f_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + unsigned int period() const { return d_length; } + int mask() const; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_GLFSR_SOURCE_F_IMPL_H */ diff --git a/gr-digital/lib/kurtotic_equalizer_cc_impl.cc b/gr-digital/lib/kurtotic_equalizer_cc_impl.cc new file mode 100644 index 0000000000..c3be3b5d06 --- /dev/null +++ b/gr-digital/lib/kurtotic_equalizer_cc_impl.cc @@ -0,0 +1,97 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "kurtotic_equalizer_cc_impl.h" +#include <gr_io_signature.h> +#include <volk/volk.h> + +namespace gr { + namespace digital { + + kurtotic_equalizer_cc::sptr + kurtotic_equalizer_cc::make(int num_taps, float mu) + { + return gnuradio::get_initial_sptr + (new kurtotic_equalizer_cc_impl(num_taps, mu)); + } + + kurtotic_equalizer_cc_impl::kurtotic_equalizer_cc_impl(int num_taps, float mu) + : gr_sync_decimator("kurtotic_equalizer_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + 1), + filter::kernel::fir_filter_ccc(1, std::vector<gr_complex>(num_taps, gr_complex(0,0))) + { + set_gain(mu); + if(num_taps > 0) + d_taps[0] = 1.0; + set_taps(d_taps); + + d_alpha_p = 0.01; + d_alpha_q = 0.01; + d_alpha_m = 0.01; + + d_p = 0.0f; + d_m = 0.0f; + d_q = gr_complex(0,0); + d_u = gr_complex(0,0); + + const int alignment_multiple = + volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1,alignment_multiple)); + set_history(num_taps+1); + } + + kurtotic_equalizer_cc_impl::~kurtotic_equalizer_cc_impl() + { + } + + int + kurtotic_equalizer_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex *)input_items[0]; + gr_complex *out = (gr_complex *)output_items[0]; + + int j = 0, k, l = d_taps.size(); + for(int i = 0; i < noutput_items; i++) { + out[i] = filter(&in[j]); + + // Adjust taps + d_error = error(out[i]); + for(k = 0; k < l; k++) { + update_tap(d_taps[l-k-1], in[j+k]); + } + + j += decimation(); + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/kurtotic_equalizer_cc_impl.h b/gr-digital/lib/kurtotic_equalizer_cc_impl.h new file mode 100644 index 0000000000..0f2ff23808 --- /dev/null +++ b/gr-digital/lib/kurtotic_equalizer_cc_impl.h @@ -0,0 +1,108 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_IMPL_H +#define INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_IMPL_H + +#include <digital/kurtotic_equalizer_cc.h> +#include <filter/fir_filter.h> +#include <gr_math.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + class kurtotic_equalizer_cc_impl + : public kurtotic_equalizer_cc, filter::kernel::fir_filter_ccc + { + private: + std::vector<gr_complex> d_new_taps; + bool d_updated; + gr_complex d_error; + + float d_mu; + float d_p, d_m; + gr_complex d_q, d_u; + float d_alpha_p, d_alpha_q, d_alpha_m; + + gr_complex sign(gr_complex x) + { + float re = (float)(x.real() >= 0.0f); + float im = (float)(x.imag() >= 0.0f); + return gr_complex(re, im); + } + + protected: + virtual gr_complex error(const gr_complex &out) + { + // p = E[|z|^2] + // q = E[z^2] + // m = E[|z|^4] + // u = E[kurtosis(z)] + + float nrm = norm(out); + gr_complex cnj = conj(out); + float epsilon_f = 1e-12; + gr_complex epsilon_c = gr_complex(1e-12, 1e-12); + + d_p = (1-d_alpha_p)*d_p + (d_alpha_p)*nrm + epsilon_f; + d_q = (1-d_alpha_q)*d_q + (d_alpha_q)*out*out + epsilon_c; + d_m = (1-d_alpha_m)*d_m + (d_alpha_m)*nrm*nrm + epsilon_f; + d_u = d_m - 2.0f*(d_p*d_p) - d_q*d_q; + + gr_complex F = (1.0f / (d_p*d_p*d_p)) * + (sign(d_u) * (nrm*cnj - 2.0f*d_p*cnj - conj(d_q)*out) - + abs(d_u)*cnj); + + float re = gr_clip(F.real(), 1.0); + float im = gr_clip(F.imag(), 1.0); + return gr_complex(re, im); + } + + virtual void update_tap(gr_complex &tap, const gr_complex &in) + { + tap += d_mu*in*d_error; + } + + public: + kurtotic_equalizer_cc_impl(int num_taps, float mu); + ~kurtotic_equalizer_cc_impl(); + + float gain() const { return d_mu; } + + void set_gain(float mu) + { + if(mu < 0) + throw std::out_of_range("kurtotic_equalizer_cc_impl::set_gain: Gain value must be >= 0"); + d_mu = mu; + } + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_KURTOTIC_EQUALIZER_CC_IMPL_H */ + diff --git a/gr-digital/lib/lms_dd_equalizer_cc_impl.cc b/gr-digital/lib/lms_dd_equalizer_cc_impl.cc new file mode 100644 index 0000000000..15008ca8e7 --- /dev/null +++ b/gr-digital/lib/lms_dd_equalizer_cc_impl.cc @@ -0,0 +1,137 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "lms_dd_equalizer_cc_impl.h" +#include <gr_io_signature.h> +#include <gr_misc.h> +#include <volk/volk.h> + +namespace gr { + namespace digital { + + using namespace filter::kernel; + + lms_dd_equalizer_cc::sptr + lms_dd_equalizer_cc::make(int num_taps, float mu, int sps, + constellation_sptr cnst) + { + return gnuradio::get_initial_sptr + (new lms_dd_equalizer_cc_impl(num_taps, mu, sps, cnst)); + } + + lms_dd_equalizer_cc_impl::lms_dd_equalizer_cc_impl(int num_taps, float mu, + int sps, + constellation_sptr cnst) + : gr_sync_decimator("lms_dd_equalizer_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + sps), + fir_filter_ccc(sps, std::vector<gr_complex>(num_taps, gr_complex(0,0))), + d_new_taps(num_taps, gr_complex(0,0)), + d_updated(false), d_cnst(cnst) + { + set_gain(mu); + if(num_taps > 0) + d_new_taps[0] = 1.0; + fir_filter_ccc::set_taps(d_new_taps); + + const int alignment_multiple = + volk_get_alignment() / sizeof(gr_complex); + set_alignment(std::max(1,alignment_multiple)); + + set_history(num_taps); + } + + lms_dd_equalizer_cc_impl::~lms_dd_equalizer_cc_impl() + { + } + + void + lms_dd_equalizer_cc_impl::set_taps(const std::vector<gr_complex> &taps) + { + d_new_taps = taps; + d_updated = true; + } + + std::vector<gr_complex> + lms_dd_equalizer_cc_impl::taps() const + { + return d_taps; + } + + gr_complex + lms_dd_equalizer_cc_impl::error(const gr_complex &out) + { + gr_complex decision, error; + d_cnst->map_to_points(d_cnst->decision_maker(&out), &decision); + error = decision - out; + return error; + } + + void + lms_dd_equalizer_cc_impl::update_tap(gr_complex &tap, const gr_complex &in) + { + tap += d_mu*conj(in)*d_error; + } + + int + lms_dd_equalizer_cc_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]; + + if(d_updated) { + d_taps = d_new_taps; + set_history(d_taps.size()); + d_updated = false; + return 0; // history requirements may have changed. + } + + int j = 0; + size_t k, l = d_taps.size(); + for(int i = 0; i < noutput_items; i++) { + out[i] = filter(&in[j]); + + // Adjust taps + d_error = error(out[i]); + for(k = 0; k < l; k++) { + // Update tap locally from error. + update_tap(d_taps[k], in[j+k]); + + // Update aligned taps in filter object. + fir_filter_ccc::update_tap(d_taps[k], k); + } + + j += decimation(); + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/lms_dd_equalizer_cc_impl.h b/gr-digital/lib/lms_dd_equalizer_cc_impl.h new file mode 100644 index 0000000000..ca6ba4d84c --- /dev/null +++ b/gr-digital/lib/lms_dd_equalizer_cc_impl.h @@ -0,0 +1,80 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_IMPL_H +#define INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_IMPL_H + +#include <digital/lms_dd_equalizer_cc.h> +#include <filter/fir_filter.h> +#include <stdexcept> + +namespace gr { + namespace digital { + + class lms_dd_equalizer_cc_impl + : public lms_dd_equalizer_cc, filter::kernel::fir_filter_ccc + { + private: + std::vector<gr_complex> d_new_taps; + bool d_updated; + gr_complex d_error; + + float d_mu; + constellation_sptr d_cnst; + + protected: + gr_complex error(const gr_complex &out); + void update_tap(gr_complex &tap, const gr_complex &in); + + public: + lms_dd_equalizer_cc_impl(int num_taps, + float mu, int sps, + constellation_sptr cnst); + ~lms_dd_equalizer_cc_impl(); + + void set_taps(const std::vector<gr_complex> &taps); + std::vector<gr_complex> taps() const; + + float gain() const + { + return d_mu; + } + + void set_gain(float mu) + { + if(mu < 0.0f || mu > 1.0f) { + throw std::out_of_range("lms_dd_equalizer_impl::set_mu: Gain value must in [0, 1]"); + } + else { + d_mu = mu; + } + } + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_LMS_DD_EQUALIZER_CC_IMPL_H */ diff --git a/gr-digital/lib/map_bb_impl.cc b/gr-digital/lib/map_bb_impl.cc new file mode 100644 index 0000000000..3a06394ec4 --- /dev/null +++ b/gr-digital/lib/map_bb_impl.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "map_bb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + map_bb::sptr + map_bb::make(const std::vector<int> &map) + { + return gnuradio::get_initial_sptr(new map_bb_impl(map)); + } + + map_bb_impl::map_bb_impl(const std::vector<int> &map) + : gr_sync_block("map_bb", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))) + { + set_map(map); + } + + map_bb_impl::~map_bb_impl() + { + } + + void + map_bb_impl::set_map(const std::vector<int> &map) + { + gruel::scoped_lock guard(d_mutex); + + for(int i = 0; i < 0x100; i++) + d_map[i] = i; + + unsigned int size = std::min((size_t)0x100, map.size()); + for(unsigned int i = 0; i < size; i++) + d_map[i] = map[i]; + } + + std::vector<int> + map_bb_impl::map() const + { + std::vector<int> m; + for(unsigned i = 0; i < 0x100; i++) + m[i] = d_map[i]; + return m; + } + + int + map_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gruel::scoped_lock guard(d_mutex); + + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + for(int i = 0; i < noutput_items; i++) + out[i] = d_map[in[i]]; + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/map_bb_impl.h b/gr-digital/lib/map_bb_impl.h new file mode 100644 index 0000000000..bce2b9b1b3 --- /dev/null +++ b/gr-digital/lib/map_bb_impl.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2012 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. + */ + +#ifndef INCLUDED_GR_MAP_BB_IMPL_H +#define INCLUDED_GR_MAP_BB_IMPL_H + +#include <digital/map_bb.h> +#include <gruel/thread.h> + +namespace gr { + namespace digital { + + class map_bb_impl : public map_bb + { + private: + unsigned char d_map[0x100]; + gruel::mutex d_mutex; + + public: + map_bb_impl(const std::vector<int> &map); + ~map_bb_impl(); + + void set_map(const std::vector<int> &map); + std::vector<int> map() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_MAP_BB_IMPL_H */ diff --git a/gr-digital/lib/mpsk_receiver_cc_impl.cc b/gr-digital/lib/mpsk_receiver_cc_impl.cc new file mode 100644 index 0000000000..31355c5653 --- /dev/null +++ b/gr-digital/lib/mpsk_receiver_cc_impl.cc @@ -0,0 +1,331 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005-2007,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mpsk_receiver_cc_impl.h" +#include <gr_io_signature.h> +#include <gr_prefs.h> +#include <gr_math.h> +#include <gr_expj.h> +#include <stdexcept> + +namespace gr { + namespace digital { + +#define M_TWOPI (2*M_PI) +#define VERBOSE_MM 0 // Used for debugging symbol timing loop +#define VERBOSE_COSTAS 0 // Used for debugging phase and frequency tracking + + mpsk_receiver_cc::sptr + mpsk_receiver_cc::make(unsigned int M, float theta, + float loop_bw, + float fmin, float fmax, + float mu, float gain_mu, + float omega, float gain_omega, float omega_rel) + { + return gnuradio::get_initial_sptr + (new mpsk_receiver_cc_impl(M, theta, + loop_bw, + fmin, fmax, + mu, gain_mu, + omega, gain_omega, + omega_rel)); + } + + mpsk_receiver_cc_impl::mpsk_receiver_cc_impl(unsigned int M, float theta, + float loop_bw, + float fmin, float fmax, + float mu, float gain_mu, + float omega, float gain_omega, + float omega_rel) + : gr_block("mpsk_receiver_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + gri_control_loop(loop_bw, fmax, fmin), + d_M(M), d_theta(theta), + d_current_const_point(0), + d_mu(mu), d_gain_mu(gain_mu), d_gain_omega(gain_omega), + d_omega_rel(omega_rel), d_max_omega(0), d_min_omega(0), + d_p_2T(0), d_p_1T(0), d_p_0T(0), d_c_2T(0), d_c_1T(0), d_c_0T(0) + { + d_interp = new gr::filter::mmse_fir_interpolator_cc(); + d_dl_idx = 0; + + set_omega(omega); + + if(omega <= 0.0) + throw std::out_of_range("clock rate must be > 0"); + if(gain_mu < 0 || gain_omega < 0) + throw std::out_of_range("Gains must be non-negative"); + + assert(d_interp->ntaps() <= DLLEN); + + // zero double length delay line. + for(unsigned int i = 0; i < 2 * DLLEN; i++) + d_dl[i] = gr_complex(0.0,0.0); + + set_modulation_order(d_M); + } + + mpsk_receiver_cc_impl::~mpsk_receiver_cc_impl() + { + delete d_interp; + } + + void + mpsk_receiver_cc_impl::set_modulation_order(unsigned int M) + { + // build the constellation vector from M + make_constellation(); + + // Select a phase detector and a decision maker for the modulation order + switch(d_M) { + case 2: // optimized algorithms for BPSK + d_phase_error_detector = &mpsk_receiver_cc_impl::phase_error_detector_bpsk; //bpsk; + d_decision = &mpsk_receiver_cc_impl::decision_bpsk; + break; + + case 4: // optimized algorithms for QPSK + d_phase_error_detector = &mpsk_receiver_cc_impl::phase_error_detector_qpsk; //qpsk; + d_decision = &mpsk_receiver_cc_impl::decision_qpsk; + break; + + default: // generic algorithms for any M (power of 2?) but not pretty + d_phase_error_detector = &mpsk_receiver_cc_impl::phase_error_detector_generic; + d_decision = &mpsk_receiver_cc_impl::decision_generic; + break; + } + } + + void + mpsk_receiver_cc_impl::set_gain_omega_rel(float omega_rel) + { + d_omega_rel = omega_rel; + set_omega(d_omega); + } + + void + mpsk_receiver_cc_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] = (int) ceil((noutput_items * d_omega) + d_interp->ntaps()); + } + + // FIXME add these back in an test difference in performance + float + mpsk_receiver_cc_impl::phase_error_detector_qpsk(gr_complex sample) const + { + float phase_error = 0; + if(fabsf(sample.real()) > fabsf(sample.imag())) { + if(sample.real() > 0) + phase_error = -sample.imag(); + else + phase_error = sample.imag(); + } + else { + if(sample.imag() > 0) + phase_error = sample.real(); + else + phase_error = -sample.real(); + } + + return phase_error; + } + + float + mpsk_receiver_cc_impl::phase_error_detector_bpsk(gr_complex sample) const + { + return -(sample.real()*sample.imag()); + } + + float mpsk_receiver_cc_impl::phase_error_detector_generic(gr_complex sample) const + { + //return gr_fast_atan2f(sample*conj(d_constellation[d_current_const_point])); + return -arg(sample*conj(d_constellation[d_current_const_point])); + } + + unsigned int + mpsk_receiver_cc_impl::decision_bpsk(gr_complex sample) const + { + return (gr_branchless_binary_slicer(sample.real()) ^ 1); + //return gr_binary_slicer(sample.real()) ^ 1; + } + + unsigned int + mpsk_receiver_cc_impl::decision_qpsk(gr_complex sample) const + { + unsigned int index; + + //index = gr_branchless_quad_0deg_slicer(sample); + index = gr_quad_0deg_slicer(sample); + return index; + } + + unsigned int + mpsk_receiver_cc_impl::decision_generic(gr_complex sample) const + { + unsigned int min_m = 0; + float min_s = 65535; + + // Develop all possible constellation points and find the one that minimizes + // the Euclidean distance (error) with the sample + for(unsigned int m = 0; m < d_M; m++) { + gr_complex diff = norm(d_constellation[m] - sample); + + if(fabs(diff.real()) < min_s) { + min_s = fabs(diff.real()); + min_m = m; + } + } + // Return the index of the constellation point that minimizes the error + return min_m; + } + + void + mpsk_receiver_cc_impl::make_constellation() + { + for(unsigned int m = 0; m < d_M; m++) { + d_constellation.push_back(gr_expj((M_TWOPI/d_M)*m)); + } + } + + void + mpsk_receiver_cc_impl::mm_sampler(const gr_complex symbol) + { + gr_complex sample, nco; + + d_mu--; // skip a number of symbols between sampling + d_phase += d_freq; // increment the phase based on the frequency of the rotation + + // Keep phase clamped and not walk to infinity + while(d_phase > M_TWOPI) + d_phase -= M_TWOPI; + while(d_phase < -M_TWOPI) + d_phase += M_TWOPI; + + nco = gr_expj(d_phase+d_theta); // get the NCO value for derotating the current sample + sample = nco*symbol; // get the downconverted symbol + + // Fill up the delay line for the interpolator + d_dl[d_dl_idx] = sample; + d_dl[(d_dl_idx + DLLEN)] = sample; // put this in the second half of the buffer for overflows + d_dl_idx = (d_dl_idx+1) % DLLEN; // Keep the delay line index in bounds + } + + void + mpsk_receiver_cc_impl::mm_error_tracking(gr_complex sample) + { + gr_complex u, x, y; + float mm_error = 0; + + // Make sample timing corrections + + // set the delayed samples + d_p_2T = d_p_1T; + d_p_1T = d_p_0T; + d_p_0T = sample; + d_c_2T = d_c_1T; + d_c_1T = d_c_0T; + + d_current_const_point = (*this.*d_decision)(d_p_0T); // make a decision on the sample value + d_c_0T = d_constellation[d_current_const_point]; + + x = (d_c_0T - d_c_2T) * conj(d_p_1T); + y = (d_p_0T - d_p_2T) * conj(d_c_1T); + u = y - x; + mm_error = u.real(); // the error signal is in the real part + mm_error = gr_branchless_clip(mm_error, 1.0); // limit mm_val + + d_omega = d_omega + d_gain_omega * mm_error; // update omega based on loop error + d_omega = d_omega_mid + gr_branchless_clip(d_omega-d_omega_mid, d_omega_rel); // make sure we don't walk away + + d_mu += d_omega + d_gain_mu * mm_error; // update mu based on loop error + +#if VERBOSE_MM + printf("mm: mu: %f omega: %f mm_error: %f sample: %f+j%f constellation: %f+j%f\n", + d_mu, d_omega, mm_error, sample.real(), sample.imag(), + d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag()); +#endif + } + + + void + mpsk_receiver_cc_impl::phase_error_tracking(gr_complex sample) + { + float phase_error = 0; + + // Make phase and frequency corrections based on sampled value + phase_error = (*this.*d_phase_error_detector)(sample); + + advance_loop(phase_error); + phase_wrap(); + frequency_limit(); + +#if VERBOSE_COSTAS + printf("cl: phase_error: %f phase: %f freq: %f sample: %f+j%f constellation: %f+j%f\n", + phase_error, d_phase, d_freq, sample.real(), sample.imag(), + d_constellation[d_current_const_point].real(), d_constellation[d_current_const_point].imag()); +#endif +} + + int + mpsk_receiver_cc_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 i=0, o=0; + + while((o < noutput_items) && (i < ninput_items[0])) { + while((d_mu > 1) && (i < ninput_items[0])) { + mm_sampler(in[i]); // puts symbols into a buffer and adjusts d_mu + i++; + } + + if(i < ninput_items[0]) { + gr_complex interp_sample = d_interp->interpolate(&d_dl[d_dl_idx], d_mu); + + mm_error_tracking(interp_sample); // corrects M&M sample time + phase_error_tracking(interp_sample); // corrects phase and frequency offsets + + out[o++] = interp_sample; + } + } + +#if 0 + printf("ninput_items: %d noutput_items: %d consuming: %d returning: %d\n", + ninput_items[0], noutput_items, i, o); +#endif + + consume_each(i); + return o; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/mpsk_receiver_cc_impl.h b/gr-digital/lib/mpsk_receiver_cc_impl.h new file mode 100644 index 0000000000..3db6fa8b62 --- /dev/null +++ b/gr-digital/lib/mpsk_receiver_cc_impl.h @@ -0,0 +1,244 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_MPSK_RECEIVER_CC_IMPL_H +#define INCLUDED_DIGITAL_MPSK_RECEIVER_CC_IMPL_H + +#include <digital/mpsk_receiver_cc.h> +#include <gruel/attributes.h> +#include <gri_control_loop.h> +#include <gr_complex.h> +#include <fstream> +#include <filter/mmse_fir_interpolator_cc.h> + +namespace gr { + namespace digital { + + class mpsk_receiver_cc_impl + : public mpsk_receiver_cc, public gri_control_loop + { + public: + mpsk_receiver_cc_impl(unsigned int M, float theta, + float loop_bw, + float fmin, float fmax, + float mu, float gain_mu, + float omega, float gain_omega, float omega_rel); + ~mpsk_receiver_cc_impl(); + + 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); + + //! Returns the modulation order (M) currently set + float modulation_order() const { return d_M; } + + //! Returns current value of theta + float theta() const { return d_theta; } + + //! Returns current value of mu + float mu() const { return d_mu; } + + //! Returns current value of omega + float omega() const { return d_omega; } + + //! Returns mu gain factor + float gain_mu() const { return d_gain_mu; } + + //! Returns omega gain factor + float gain_omega() const { return d_gain_omega; } + + //! Returns the relative omega limit + float gain_omega_rel() const {return d_omega_rel; } + + //! Sets the modulation order (M) currently + void set_modulation_order(unsigned int M); + + //! Sets value of theta + void set_theta(float theta) { d_theta = theta; } + + //! Sets value of mu + void set_mu(float mu) { d_mu = mu; } + + //! Sets value of omega and its min and max values + void set_omega(float omega) { + d_omega = omega; + d_min_omega = omega*(1.0 - d_omega_rel); + d_max_omega = omega*(1.0 + d_omega_rel); + d_omega_mid = 0.5*(d_min_omega+d_max_omega); + } + + //! Sets value for mu gain factor + void set_gain_mu(float gain_mu) { d_gain_mu = gain_mu; } + + //! Sets value for omega gain factor + void set_gain_omega(float gain_omega) { d_gain_omega = gain_omega; } + + //! Sets the relative omega limit and resets omega min/max values + void set_gain_omega_rel(float omega_rel); + + protected: + void make_constellation(); + void mm_sampler(const gr_complex symbol); + void mm_error_tracking(gr_complex sample); + void phase_error_tracking(gr_complex sample); + + /*! + * \brief Phase error detector for MPSK modulations. + * + * \param sample the I&Q sample from which to determine the phase error + * + * This function determines the phase error for any MPSK signal + * by creating a set of PSK constellation points and doing a + * brute-force search to see which point minimizes the Euclidean + * distance. This point is then used to derotate the sample to + * the real-axis and a atan (using the fast approximation + * function) to determine the phase difference between the + * incoming sample and the real constellation point + * + * This should be cleaned up and made more efficient. + * + * \returns the approximated phase error. + */ + float phase_error_detector_generic(gr_complex sample) const; + + /*! + * \brief Phase error detector for BPSK modulation. + * + * \param sample the I&Q sample from which to determine the phase error + * + * This function determines the phase error using a simple BPSK + * phase error detector by multiplying the real and imaginary (the + * error signal) components together. As the imaginary part goes to + * 0, so does this error. + * + * \returns the approximated phase error. + */ + float phase_error_detector_bpsk(gr_complex sample) const; + + /*! + * \brief Phase error detector for QPSK modulation. + * + * \param sample the I&Q sample from which to determine the phase error + * + * This function determines the phase error using the limiter + * approach in a standard 4th order Costas loop + * + * \returns the approximated phase error. + */ + float phase_error_detector_qpsk(gr_complex sample) const; + + /*! + * \brief Decision maker for a generic MPSK constellation. + * + * \param sample the baseband I&Q sample from which to make the decision + * + * This decision maker is a generic implementation that does a + * brute-force search for the constellation point that minimizes + * the error between it and the incoming signal. + * + * \returns the index to d_constellation that minimizes the error/ + */ + unsigned int decision_generic(gr_complex sample) const; + + /*! + * \brief Decision maker for BPSK constellation. + * + * \param sample the baseband I&Q sample from which to make the decision + * + * This decision maker is a simple slicer function that makes a + * decision on the symbol based on its placement on the real + * axis of greater than 0 or less than 0; the quadrature + * component is always 0. + * + * \returns the index to d_constellation that minimizes the error/ + */ + unsigned int decision_bpsk(gr_complex sample) const; + + /*! + * \brief Decision maker for QPSK constellation. + * + * \param sample the baseband I&Q sample from which to make the decision + * + * This decision maker is a simple slicer function that makes a + * decision on the symbol based on its placement versus both + * axes and returns which quadrant the symbol is in. + * + * \returns the index to d_constellation that minimizes the error/ + */ + unsigned int decision_qpsk(gr_complex sample) const; + + private: + unsigned int d_M; + float d_theta; + + /*! + * \brief Decision maker function pointer + * + * \param sample the baseband I&Q sample from which to make the decision + * + * This is a function pointer that is set in the constructor to + * point to the proper decision function for the specified + * constellation order. + * + * \return index into d_constellation point that is the closest to the recieved sample + */ + unsigned int (mpsk_receiver_cc_impl::*d_decision)(gr_complex sample) const; + + std::vector<gr_complex> d_constellation; + unsigned int d_current_const_point; + + // Members related to symbol timing + float d_mu, d_gain_mu; + float d_omega, d_gain_omega, d_omega_rel, d_max_omega, d_min_omega, d_omega_mid; + gr_complex d_p_2T, d_p_1T, d_p_0T; + gr_complex d_c_2T, d_c_1T, d_c_0T; + + /*! + * \brief Phase error detector function pointer + * + * \param sample the I&Q sample from which to determine the phase error + * + * This is a function pointer that is set in the constructor to + * point to the proper phase error detector function for the + * specified constellation order. + */ + float (mpsk_receiver_cc_impl::*d_phase_error_detector)(gr_complex sample) const; + + //! get interpolated value + gr::filter::mmse_fir_interpolator_cc *d_interp; + + //! delay line length. + static const unsigned int DLLEN = 8; + + //! delay line plus some length for overflow protection + __GR_ATTR_ALIGNED(8) gr_complex d_dl[2*DLLEN]; + + //! index to delay line + unsigned int d_dl_idx; + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_MPSK_RECEIVER_CC_IMPL_H */ diff --git a/gr-digital/lib/mpsk_snr_est.cc b/gr-digital/lib/mpsk_snr_est.cc new file mode 100644 index 0000000000..1457a1a918 --- /dev/null +++ b/gr-digital/lib/mpsk_snr_est.cc @@ -0,0 +1,252 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <digital/mpsk_snr_est.h> +#include <stdexcept> +#include <cstdio> + +namespace gr { + namespace digital { + + mpsk_snr_est::mpsk_snr_est(double alpha) + { + set_alpha(alpha); + } + + mpsk_snr_est::~mpsk_snr_est() + {} + + void + mpsk_snr_est::set_alpha(double alpha) + { + d_alpha = alpha; + d_beta = 1.0-alpha; + } + + double + mpsk_snr_est::alpha() const + { + return d_alpha; + } + + int + mpsk_snr_est::update(int noutput_items, + const gr_complex *input) + { + throw std::runtime_error("mpsk_snr_est: Unimplemented"); + } + + double + mpsk_snr_est::snr() + { + throw std::runtime_error("mpsk_snr_est: Unimplemented"); + } + + + /*****************************************************************/ + + + mpsk_snr_est_simple::mpsk_snr_est_simple(double alpha) : + mpsk_snr_est(alpha) + { + d_y1 = 0; + d_y2 = 0; + } + + int + mpsk_snr_est_simple::update(int noutput_items, + const gr_complex *input) + { + for(int i = 0; i < noutput_items; i++) { + double y1 = abs(input[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = real(input[i]*input[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; + } + + double + mpsk_snr_est_simple::snr() + { + double y1_2 = d_y1*d_y1; + double y3 = y1_2 - d_y2 + 1e-20; + return 10.0*log10(y1_2/y3); + } + + + /*****************************************************************/ + + + mpsk_snr_est_skew::mpsk_snr_est_skew(double alpha) : + mpsk_snr_est(alpha) + { + d_y1 = 0; + d_y2 = 0; + d_y3 = 0; + } + + int + mpsk_snr_est_skew::update(int noutput_items, + const gr_complex *input) + { + for(int i = 0; i < noutput_items; i++) { + double y1 = abs(input[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = real(input[i]*input[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + + // online algorithm for calculating skewness + // See: + // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Higher-order_statistics + double d = abs(input[i]) - d_y1; + double d_i = d / (i+1); + double y3 = (d*d_i*i)*d_i*(i-1) - 3.0*d_i*d_y2; + d_y3 = d_alpha*y3 + d_beta*d_y3; + } + return noutput_items; + } + + double + mpsk_snr_est_skew::snr() + { + double y3 = d_y3*d_y3 / (d_y2*d_y2*d_y2); + double y1_2 = d_y1*d_y1; + double x = y1_2 - d_y2; + return 10.0*log10(y1_2 / (x + y3*y1_2)); + } + + + /*****************************************************************/ + + + mpsk_snr_est_m2m4::mpsk_snr_est_m2m4(double alpha) : + mpsk_snr_est(alpha) + { + d_y1 = 0; + d_y2 = 0; + } + + int + mpsk_snr_est_m2m4::update(int noutput_items, + const gr_complex *input) + { + for(int i = 0; i < noutput_items; i++) { + double y1 = abs(input[i])*abs(input[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = abs(input[i])*abs(input[i])*abs(input[i])*abs(input[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; + } + + double + mpsk_snr_est_m2m4::snr() + { + double y1_2 = d_y1*d_y1; + return 10.0*log10(2.0*sqrt(2*y1_2 - d_y2) / + (d_y1 - sqrt(2*y1_2 - d_y2))); + } + + + /*****************************************************************/ + + + snr_est_m2m4::snr_est_m2m4(double alpha, double ka, double kw) : + mpsk_snr_est(alpha) + { + d_y1 = 0; + d_y2 = 0; + d_ka = ka; + d_kw = kw; + } + + int + snr_est_m2m4::update(int noutput_items, + const gr_complex *input) + { + for(int i = 0; i < noutput_items; i++) { + double y1 = abs(input[i])*abs(input[i]); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = abs(input[i])*abs(input[i])*abs(input[i])*abs(input[i]); + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; + } + + double + snr_est_m2m4::snr() + { + double M2 = d_y1; + double M4 = d_y2; + double s = M2*(d_kw - 2) + + sqrt((4.0-d_ka*d_kw)*M2*M2 + M4*(d_ka+d_kw-4.0)) / + (d_ka + d_kw - 4.0); + double n = M2 - s; + + return 10.0*log10(s / n); + } + + + /*****************************************************************/ + + + mpsk_snr_est_svr::mpsk_snr_est_svr(double alpha) : + mpsk_snr_est(alpha) + { + d_y1 = 0; + d_y2 = 0; + } + + int + mpsk_snr_est_svr::update(int noutput_items, + const gr_complex *input) + { + for(int i = 0; i < noutput_items; i++) { + double x = abs(input[i]); + double x1 = abs(input[i-1]); + double y1 = (x*x)*(x1*x1); + d_y1 = d_alpha*y1 + d_beta*d_y1; + + double y2 = x*x*x*x; + d_y2 = d_alpha*y2 + d_beta*d_y2; + } + return noutput_items; + } + + double + mpsk_snr_est_svr::snr() + { + double x = d_y1 / (d_y2 - d_y1); + return 10.0*log10(2.*((x-1) + sqrt(x*(x-1)))); + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/mpsk_snr_est_cc_impl.cc b/gr-digital/lib/mpsk_snr_est_cc_impl.cc new file mode 100644 index 0000000000..621c41b9f0 --- /dev/null +++ b/gr-digital/lib/mpsk_snr_est_cc_impl.cc @@ -0,0 +1,192 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "mpsk_snr_est_cc_impl.h" +#include <gr_io_signature.h> +#include <cstdio> + +namespace gr { + namespace digital { + + mpsk_snr_est_cc::sptr + mpsk_snr_est_cc::make(snr_est_type_t type, + int tag_nsamples, + double alpha) + { + return gnuradio::get_initial_sptr + (new mpsk_snr_est_cc_impl(type, tag_nsamples, alpha)); + } + + mpsk_snr_est_cc_impl::mpsk_snr_est_cc_impl(snr_est_type_t type, + int tag_nsamples, + double alpha) + : gr_sync_block("mpsk_snr_est_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))) + { + d_snr_est = NULL; + + d_type = type; + d_nsamples = tag_nsamples; + d_count = 0; + set_alpha(alpha); + + set_type(type); + + // at least 1 estimator has to look back + set_history(2); + + std::stringstream str; + str << name() << unique_id(); + d_me = pmt::string_to_symbol(str.str()); + d_key = pmt::string_to_symbol("snr"); + } + + mpsk_snr_est_cc_impl::~mpsk_snr_est_cc_impl() + { + if(d_snr_est) + delete d_snr_est; + } + + int + mpsk_snr_est_cc_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + // This is a pass-through block; copy input to output + memcpy(output_items[0], input_items[0], + noutput_items * sizeof(gr_complex)); + + const gr_complex *in = (const gr_complex*)input_items[0]; + + // Update, calculate, and issue an SNR tag every d_nsamples + int index = 0, x = 0; + int64_t nwritten = nitems_written(0); + while(index + (d_nsamples-d_count) <= noutput_items) { + x = d_nsamples - d_count; + nwritten += x; + + // Update the SNR estimate registers from the current input + d_snr_est->update(x, &in[index]); + + // Issue a tag with the SNR data + pmt::pmt_t pmt_snr = pmt::from_double(d_snr_est->snr()); + add_item_tag(0, // stream ID + nwritten, // tag's sample number + d_key, // snr key + pmt_snr, // SNR + d_me); // block src id + + index += x; + d_count = 0; + } + + // Keep track of remaining items and update estimators + x = noutput_items - index; + d_count += x; + d_snr_est->update(x, &in[index]); + + return noutput_items; + } + + double + mpsk_snr_est_cc_impl::snr() + { + if(d_snr_est) + return d_snr_est->snr(); + else + throw std::runtime_error("mpsk_snr_est_cc_impl:: No SNR estimator defined.\n"); + } + + snr_est_type_t + mpsk_snr_est_cc_impl::type() const + { + return d_type; + } + + int + mpsk_snr_est_cc_impl::tag_nsample() const + { + return d_nsamples; + } + + double + mpsk_snr_est_cc_impl::alpha() const + { + return d_alpha; + } + + void + mpsk_snr_est_cc_impl::set_type(snr_est_type_t t) + { + d_type = t; + + if(d_snr_est) + delete d_snr_est; + + switch(d_type) { + case(SNR_EST_SIMPLE): + d_snr_est = new mpsk_snr_est_simple(d_alpha); + break; + case(SNR_EST_SKEW): + d_snr_est = new mpsk_snr_est_skew(d_alpha); + break; + case(SNR_EST_M2M4): + d_snr_est = new mpsk_snr_est_m2m4(d_alpha); + break; + case(SNR_EST_SVR): + d_snr_est = new mpsk_snr_est_svr(d_alpha); + break; + default: + throw std::invalid_argument("mpsk_snr_est_cc_impl: unknown type specified.\n"); + } + } + + void + mpsk_snr_est_cc_impl::set_tag_nsample(int n) + { + if(n > 0) { + d_nsamples = n; + d_count = 0; // reset state + } + else + throw std::invalid_argument("mpsk_snr_est_cc_impl: tag_nsamples can't be <= 0\n"); + } + + void + mpsk_snr_est_cc_impl::set_alpha(double alpha) + { + if((alpha >= 0) && (alpha <= 1.0)) { + d_alpha = alpha; + if(d_snr_est) + d_snr_est->set_alpha(d_alpha); + } + else + throw std::invalid_argument("mpsk_snr_est_cc_impl: alpha must be in [0,1]\n"); + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/mpsk_snr_est_cc_impl.h b/gr-digital/lib/mpsk_snr_est_cc_impl.h new file mode 100644 index 0000000000..530d223aec --- /dev/null +++ b/gr-digital/lib/mpsk_snr_est_cc_impl.h @@ -0,0 +1,79 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_MPSK_SNR_EST_CC_IMPL_H +#define INCLUDED_DIGITAL_MPSK_SNR_EST_CC_IMPL_H + +#include <digital/api.h> +#include <digital/mpsk_snr_est_cc.h> +#include <gr_sync_block.h> + +namespace gr { + namespace digital { + + class mpsk_snr_est_cc_impl : public mpsk_snr_est_cc + { + private: + snr_est_type_t d_type; + int d_nsamples, d_count; + double d_alpha; + mpsk_snr_est *d_snr_est; + + //d_key is the tag name, 'snr', d_me is the block name + unique ID + pmt::pmt_t d_key, d_me; + + public: + mpsk_snr_est_cc_impl(snr_est_type_t type, + int tag_nsamples=10000, + double alpha=0.001); + ~mpsk_snr_est_cc_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //! Return the estimated signal-to-noise ratio in decibels + double snr(); + + //! Return the type of estimator in use + snr_est_type_t type() const; + + //! Return how many samples between SNR tags + int tag_nsample() const; + + //! Get the running-average coefficient + double alpha() const; + + //! Set type of estimator to use + void set_type(snr_est_type_t t); + + //! Set the number of samples between SNR tags + void set_tag_nsample(int n); + + //! Set the running-average coefficient + void set_alpha(double alpha); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_MPSK_SNR_EST_CC_IMPL_H */ diff --git a/gr-digital/lib/ofdm_cyclic_prefixer_impl.cc b/gr-digital/lib/ofdm_cyclic_prefixer_impl.cc new file mode 100644 index 0000000000..67cfba615f --- /dev/null +++ b/gr-digital/lib/ofdm_cyclic_prefixer_impl.cc @@ -0,0 +1,79 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2006,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ofdm_cyclic_prefixer_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + ofdm_cyclic_prefixer::sptr + ofdm_cyclic_prefixer::make(size_t input_size, size_t output_size) + { + return gnuradio::get_initial_sptr + (new ofdm_cyclic_prefixer_impl(input_size, output_size)); + } + + ofdm_cyclic_prefixer_impl::ofdm_cyclic_prefixer_impl(size_t input_size, + size_t output_size) + : gr_sync_interpolator("ofdm_cyclic_prefixer", + gr_make_io_signature(1, 1, input_size*sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + output_size), + d_input_size(input_size), + d_output_size(output_size) + { + } + + ofdm_cyclic_prefixer_impl::~ofdm_cyclic_prefixer_impl() + { + } + + int + ofdm_cyclic_prefixer_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + size_t cp_size = d_output_size - d_input_size; + unsigned int i=0, j=0; + + j = cp_size; + for(i=0; i < d_input_size; i++,j++) { + out[j] = in[i]; + } + + j = d_input_size - cp_size; + for(i=0; i < cp_size; i++, j++) { + out[i] = in[j]; + } + + return d_output_size; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/ofdm_cyclic_prefixer_impl.h b/gr-digital/lib/ofdm_cyclic_prefixer_impl.h new file mode 100644 index 0000000000..20f0489d7c --- /dev/null +++ b/gr-digital/lib/ofdm_cyclic_prefixer_impl.h @@ -0,0 +1,49 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004-2006,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_CYCLIC_PREFIXER_IMPL_H +#define INCLUDED_DIGITAL_OFDM_CYCLIC_PREFIXER_IMPL_H + +#include <digital/ofdm_cyclic_prefixer.h> + +namespace gr { + namespace digital { + + class ofdm_cyclic_prefixer_impl : public ofdm_cyclic_prefixer + { + private: + size_t d_input_size; + size_t d_output_size; + + public: + ofdm_cyclic_prefixer_impl(size_t input_size, size_t output_size); + ~ofdm_cyclic_prefixer_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_OFDM_CYCLIC_PREFIXER_IMPL_H */ diff --git a/gr-digital/lib/ofdm_frame_acquisition_impl.cc b/gr-digital/lib/ofdm_frame_acquisition_impl.cc new file mode 100644 index 0000000000..1f45338d8f --- /dev/null +++ b/gr-digital/lib/ofdm_frame_acquisition_impl.cc @@ -0,0 +1,217 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006-2008,2010,2011 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ofdm_frame_acquisition_impl.h" +#include <gr_io_signature.h> +#include <gr_expj.h> +#include <gr_math.h> +#include <cstdio> + +namespace gr { + namespace digital { + +#define VERBOSE 0 +#define M_TWOPI (2*M_PI) +#define MAX_NUM_SYMBOLS 1000 + + ofdm_frame_acquisition::sptr + ofdm_frame_acquisition::make(unsigned int occupied_carriers, + unsigned int fft_length, + unsigned int cplen, + const std::vector<gr_complex> &known_symbol, + unsigned int max_fft_shift_len) + { + return gnuradio::get_initial_sptr + (new ofdm_frame_acquisition_impl(occupied_carriers, fft_length, cplen, + known_symbol, max_fft_shift_len)); + } + + ofdm_frame_acquisition_impl::ofdm_frame_acquisition_impl(unsigned occupied_carriers, + unsigned int fft_length, + unsigned int cplen, + const std::vector<gr_complex> &known_symbol, + unsigned int max_fft_shift_len) + : gr_block("ofdm_frame_acquisition", + gr_make_io_signature2(2, 2, sizeof(gr_complex)*fft_length, sizeof(char)*fft_length), + gr_make_io_signature2(2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char))), + d_occupied_carriers(occupied_carriers), + d_fft_length(fft_length), + d_cplen(cplen), + d_freq_shift_len(max_fft_shift_len), + d_known_symbol(known_symbol), + d_coarse_freq(0), + d_phase_count(0) + { + d_symbol_phase_diff.resize(d_fft_length); + d_known_phase_diff.resize(d_occupied_carriers); + d_hestimate.resize(d_occupied_carriers); + + unsigned int i = 0, j = 0; + + std::fill(d_known_phase_diff.begin(), d_known_phase_diff.end(), 0); + for(i = 0; i < d_known_symbol.size()-2; i+=2) { + d_known_phase_diff[i] = norm(d_known_symbol[i] - d_known_symbol[i+2]); + } + + d_phase_lut = new gr_complex[(2*d_freq_shift_len+1) * MAX_NUM_SYMBOLS]; + for(i = 0; i <= 2*d_freq_shift_len; i++) { + for(j = 0; j < MAX_NUM_SYMBOLS; j++) { + d_phase_lut[j + i*MAX_NUM_SYMBOLS] = gr_expj(-M_TWOPI*d_cplen/d_fft_length*(i-d_freq_shift_len)*j); + } + } + } + + ofdm_frame_acquisition_impl::~ofdm_frame_acquisition_impl() + { + delete [] d_phase_lut; + } + + void + ofdm_frame_acquisition_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] = 1; + } + + gr_complex + ofdm_frame_acquisition_impl::coarse_freq_comp(int freq_delta, int symbol_count) + { + // return gr_complex(cos(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count), + // sin(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count)); + + return gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count); + + //return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count]; + } + + void + ofdm_frame_acquisition_impl::correlate(const gr_complex *symbol, int zeros_on_left) + { + unsigned int i,j; + + std::fill(d_symbol_phase_diff.begin(), d_symbol_phase_diff.end(), 0); + for(i = 0; i < d_fft_length-2; i++) { + d_symbol_phase_diff[i] = norm(symbol[i] - symbol[i+2]); + } + + // sweep through all possible/allowed frequency offsets and select the best + int index = 0; + float max = 0, sum=0; + for(i = zeros_on_left - d_freq_shift_len; i < zeros_on_left + d_freq_shift_len; i++) { + sum = 0; + for(j = 0; j < d_occupied_carriers; j++) { + sum += (d_known_phase_diff[j] * d_symbol_phase_diff[i+j]); + } + if(sum > max) { + max = sum; + index = i; + } + } + + // set the coarse frequency offset relative to the edge of the occupied tones + d_coarse_freq = index - zeros_on_left; + } + + void + ofdm_frame_acquisition_impl::calculate_equalizer(const gr_complex *symbol, int zeros_on_left) + { + unsigned int i=0; + + // Set first tap of equalizer + d_hestimate[0] = d_known_symbol[0] / + (coarse_freq_comp(d_coarse_freq,1)*symbol[zeros_on_left+d_coarse_freq]); + + // set every even tap based on known symbol + // linearly interpolate between set carriers to set zero-filled carriers + // FIXME: is this the best way to set this? + for(i = 2; i < d_occupied_carriers; i+=2) { + d_hestimate[i] = d_known_symbol[i] / + (coarse_freq_comp(d_coarse_freq,1)*(symbol[i+zeros_on_left+d_coarse_freq])); + d_hestimate[i-1] = (d_hestimate[i] + d_hestimate[i-2]) / gr_complex(2.0, 0.0); + } + + // with even number of carriers; last equalizer tap is wrong + if(!(d_occupied_carriers & 1)) { + d_hestimate[d_occupied_carriers-1] = d_hestimate[d_occupied_carriers-2]; + } + + if(VERBOSE) { + fprintf(stderr, "Equalizer setting:\n"); + for(i = 0; i < d_occupied_carriers; i++) { + gr_complex sym = coarse_freq_comp(d_coarse_freq,1)*symbol[i+zeros_on_left+d_coarse_freq]; + gr_complex output = sym * d_hestimate[i]; + fprintf(stderr, "sym: %+.4f + j%+.4f ks: %+.4f + j%+.4f eq: %+.4f + j%+.4f ==> %+.4f + j%+.4f\n", + sym .real(), sym.imag(), + d_known_symbol[i].real(), d_known_symbol[i].imag(), + d_hestimate[i].real(), d_hestimate[i].imag(), + output.real(), output.imag()); + } + fprintf(stderr, "\n"); + } + } + + int + ofdm_frame_acquisition_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 *symbol = (const gr_complex *)input_items[0]; + const char *signal_in = (const char *)input_items[1]; + + gr_complex *out = (gr_complex *) output_items[0]; + char *signal_out = (char *) output_items[1]; + + int unoccupied_carriers = d_fft_length - d_occupied_carriers; + int zeros_on_left = (int)ceil(unoccupied_carriers/2.0); + + if(signal_in[0]) { + d_phase_count = 1; + correlate(symbol, zeros_on_left); + calculate_equalizer(symbol, zeros_on_left); + signal_out[0] = 1; + } + else { + signal_out[0] = 0; + } + + for(unsigned int i = 0; i < d_occupied_carriers; i++) { + out[i] = d_hestimate[i]*coarse_freq_comp(d_coarse_freq,d_phase_count) + *symbol[i+zeros_on_left+d_coarse_freq]; + } + + d_phase_count++; + if(d_phase_count == MAX_NUM_SYMBOLS) { + d_phase_count = 1; + } + + consume_each(1); + return 1; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/ofdm_frame_acquisition_impl.h b/gr-digital/lib/ofdm_frame_acquisition_impl.h new file mode 100644 index 0000000000..867d86736f --- /dev/null +++ b/gr-digital/lib/ofdm_frame_acquisition_impl.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_FRAME_ACQUISITION_IMPL_H +#define INCLUDED_DIGITAL_OFDM_FRAME_ACQUISITION_IMPL_H + +#include <digital/ofdm_frame_acquisition.h> + +namespace gr { + namespace digital { + + class ofdm_frame_acquisition_impl : public ofdm_frame_acquisition + { + private: + unsigned char slicer(gr_complex x); + void correlate(const gr_complex *symbol, int zeros_on_left); + void calculate_equalizer(const gr_complex *symbol, int zeros_on_left); + gr_complex coarse_freq_comp(int freq_delta, int count); + + unsigned int d_occupied_carriers; // !< \brief number of subcarriers with data + unsigned int d_fft_length; // !< \brief length of FFT vector + unsigned int d_cplen; // !< \brief length of cyclic prefix in samples + unsigned int d_freq_shift_len; // !< \brief number of surrounding bins to look at for correlation + std::vector<gr_complex> d_known_symbol; // !< \brief known symbols at start of frame + std::vector<float> d_known_phase_diff; // !< \brief factor used in correlation from known symbol + std::vector<float> d_symbol_phase_diff; // !< \brief factor used in correlation from received symbol + std::vector<gr_complex> d_hestimate; // !< channel estimate + int d_coarse_freq; // !< \brief search distance in number of bins + unsigned int d_phase_count; // !< \brief accumulator for coarse freq correction + float d_snr_est; // !< an estimation of the signal to noise ratio + + gr_complex *d_phase_lut; // !< look-up table for coarse frequency compensation + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + public: + ofdm_frame_acquisition_impl(unsigned int occupied_carriers, unsigned int fft_length, + unsigned int cplen, + const std::vector<gr_complex> &known_symbol, + unsigned int max_fft_shift_len=4); + ~ofdm_frame_acquisition_impl(); + + /*! + * \brief Return an estimate of the SNR of the channel + */ + float snr() { return d_snr_est; } + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_OFDM_FRAME_ACQUISITION_IMPL_H */ diff --git a/gr-digital/lib/ofdm_frame_sink_impl.cc b/gr-digital/lib/ofdm_frame_sink_impl.cc new file mode 100644 index 0000000000..d2f00d3a45 --- /dev/null +++ b/gr-digital/lib/ofdm_frame_sink_impl.cc @@ -0,0 +1,413 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ofdm_frame_sink_impl.h" +#include <gr_io_signature.h> +#include <gr_expj.h> +#include <gr_math.h> +#include <cmath> +#include <cstdio> +#include <stdexcept> +#include <iostream> +#include <string> + +namespace gr { + namespace digital { + +#define VERBOSE 0 + + inline void + ofdm_frame_sink_impl::enter_search() + { + if(VERBOSE) + fprintf(stderr, "@ enter_search\n"); + + d_state = STATE_SYNC_SEARCH; + } + + inline void + ofdm_frame_sink_impl::enter_have_sync() + { + if(VERBOSE) + fprintf(stderr, "@ enter_have_sync\n"); + + d_state = STATE_HAVE_SYNC; + + // clear state of demapper + d_byte_offset = 0; + d_partial_byte = 0; + + d_header = 0; + d_headerbytelen_cnt = 0; + + // Resetting PLL + d_freq = 0.0; + d_phase = 0.0; + fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0)); + } + + inline void + ofdm_frame_sink_impl::enter_have_header() + { + d_state = STATE_HAVE_HEADER; + + // header consists of two 16-bit shorts in network byte order + // payload length is lower 12 bits + // whitener offset is upper 4 bits + d_packetlen = (d_header >> 16) & 0x0fff; + d_packet_whitener_offset = (d_header >> 28) & 0x000f; + d_packetlen_cnt = 0; + + if(VERBOSE) + fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n", + d_packetlen, d_packet_whitener_offset); + } + + char + ofdm_frame_sink_impl::slicer(const gr_complex x) + { + unsigned int table_size = d_sym_value_out.size(); + unsigned int min_index = 0; + float min_euclid_dist = norm(x - d_sym_position[0]); + float euclid_dist = 0; + + for(unsigned int j = 1; j < table_size; j++){ + euclid_dist = norm(x - d_sym_position[j]); + if(euclid_dist < min_euclid_dist){ + min_euclid_dist = euclid_dist; + min_index = j; + } + } + return d_sym_value_out[min_index]; + } + + unsigned int ofdm_frame_sink_impl::demapper(const gr_complex *in, + char *out) + { + unsigned int i=0, bytes_produced=0; + gr_complex carrier; + + carrier = gr_expj(d_phase); + + gr_complex accum_error = 0.0; + //while(i < d_occupied_carriers) { + while(i < d_subcarrier_map.size()) { + if(d_nresid > 0) { + d_partial_byte |= d_resid; + d_byte_offset += d_nresid; + d_nresid = 0; + d_resid = 0; + } + + //while((d_byte_offset < 8) && (i < d_occupied_carriers)) { + while((d_byte_offset < 8) && (i < d_subcarrier_map.size())) { + //gr_complex sigrot = in[i]*carrier*d_dfe[i]; + gr_complex sigrot = in[d_subcarrier_map[i]]*carrier*d_dfe[i]; + + if(d_derotated_output != NULL){ + d_derotated_output[i] = sigrot; + } + + char bits = slicer(sigrot); + + gr_complex closest_sym = d_sym_position[bits]; + + accum_error += sigrot * conj(closest_sym); + + // FIX THE FOLLOWING STATEMENT + if(norm(sigrot)> 0.001) + d_dfe[i] += d_eq_gain*(closest_sym/sigrot-d_dfe[i]); + + i++; + + if((8 - d_byte_offset) >= d_nbits) { + d_partial_byte |= bits << (d_byte_offset); + d_byte_offset += d_nbits; + } + else { + d_nresid = d_nbits-(8-d_byte_offset); + int mask = ((1<<(8-d_byte_offset))-1); + d_partial_byte |= (bits & mask) << d_byte_offset; + d_resid = bits >> (8-d_byte_offset); + d_byte_offset += (d_nbits - d_nresid); + } + //printf("demod symbol: %.4f + j%.4f bits: %x partial_byte: %x byte_offset: %d resid: %x nresid: %d\n", + // in[i-1].real(), in[i-1].imag(), bits, d_partial_byte, d_byte_offset, d_resid, d_nresid); + } + + if(d_byte_offset == 8) { + //printf("demod byte: %x \n\n", d_partial_byte); + out[bytes_produced++] = d_partial_byte; + d_byte_offset = 0; + d_partial_byte = 0; + } + } + //std::cerr << "accum_error " << accum_error << std::endl; + + float angle = arg(accum_error); + + d_freq = d_freq - d_freq_gain*angle; + d_phase = d_phase + d_freq - d_phase_gain*angle; + if(d_phase >= 2*M_PI) + d_phase -= 2*M_PI; + if(d_phase <0) + d_phase += 2*M_PI; + + //if(VERBOSE) + // std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl; + + return bytes_produced; + } + + + ofdm_frame_sink::sptr + ofdm_frame_sink::make(const std::vector<gr_complex> &sym_position, + const std::vector<char> &sym_value_out, + gr_msg_queue_sptr target_queue, + int occupied_carriers, + float phase_gain, float freq_gain) + { + return gnuradio::get_initial_sptr + (new ofdm_frame_sink_impl(sym_position, sym_value_out, + target_queue, occupied_carriers, + phase_gain, freq_gain)); + } + + ofdm_frame_sink_impl::ofdm_frame_sink_impl(const std::vector<gr_complex> &sym_position, + const std::vector<char> &sym_value_out, + gr_msg_queue_sptr target_queue, + int occupied_carriers, + float phase_gain, float freq_gain) + : gr_sync_block("ofdm_frame_sink", + gr_make_io_signature2(2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)), + gr_make_io_signature(1, 1, sizeof(gr_complex)*occupied_carriers)), + d_target_queue(target_queue), d_occupied_carriers(occupied_carriers), + d_byte_offset(0), d_partial_byte(0), + d_resid(0), d_nresid(0),d_phase(0),d_freq(0), + d_phase_gain(phase_gain),d_freq_gain(freq_gain), + d_eq_gain(0.05) + { + std::string carriers = "FE7F"; + + // A bit hacky to fill out carriers to occupied_carriers length + int diff = (d_occupied_carriers - 4*carriers.length()); + while(diff > 7) { + carriers.insert(0, "f"); + carriers.insert(carriers.length(), "f"); + diff -= 8; + } + + // if there's extras left to be processed + // divide remaining to put on either side of current map + // all of this is done to stick with the concept of a carrier map string that + // can be later passed by the user, even though it'd be cleaner to just do this + // on the carrier map itself + int diff_left=0; + int diff_right=0; + + // dictionary to convert from integers to ascii hex representation + char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + if(diff > 0) { + char c[2] = {0,0}; + + diff_left = (int)ceil((float)diff/2.0f); // number of carriers to put on the left side + c[0] = abc[(1 << diff_left) - 1]; // convert to bits and move to ASCI integer + carriers.insert(0, c); + + diff_right = diff - diff_left; // number of carriers to put on the right side + c[0] = abc[0xF^((1 << diff_right) - 1)]; // convert to bits and move to ASCI integer + carriers.insert(carriers.length(), c); + } + + // It seemed like such a good idea at the time... + // because we are only dealing with the occupied_carriers + // at this point, the diff_left in the following compensates + // for any offset from the 0th carrier introduced + int i; + unsigned int j,k; + for(i = 0; i < (d_occupied_carriers/4)+diff_left; i++) { + char c = carriers[i]; + for(j = 0; j < 4; j++) { + k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1; + if(k) { + d_subcarrier_map.push_back(4*i + j - diff_left); + } + } + } + + // make sure we stay in the limit currently imposed by the occupied_carriers + if(d_subcarrier_map.size() > (size_t)d_occupied_carriers) { + throw std::invalid_argument("ofdm_frame_sink_impl: subcarriers allocated exceeds size of occupied carriers"); + } + + d_bytes_out = new char[d_occupied_carriers]; + d_dfe.resize(occupied_carriers); + fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0)); + + set_sym_value_out(sym_position, sym_value_out); + + enter_search(); + } + + ofdm_frame_sink_impl::~ofdm_frame_sink_impl() + { + delete [] d_bytes_out; + } + + bool + ofdm_frame_sink_impl::set_sym_value_out(const std::vector<gr_complex> &sym_position, + const std::vector<char> &sym_value_out) + { + if(sym_position.size() != sym_value_out.size()) + return false; + + if(sym_position.size()<1) + return false; + + d_sym_position = sym_position; + d_sym_value_out = sym_value_out; + d_nbits = (unsigned long)ceil(log10(float(d_sym_value_out.size())) / log10(2.0)); + + return true; + } + + int + ofdm_frame_sink_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]; + const char *sig = (const char*)input_items[1]; + unsigned int j = 0; + unsigned int bytes=0; + + // If the output is connected, send it the derotated symbols + if(output_items.size() >= 1) + d_derotated_output = (gr_complex *)output_items[0]; + else + d_derotated_output = NULL; + + if(VERBOSE) + fprintf(stderr,">>> Entering state machine\n"); + + switch(d_state) { + case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt + if(VERBOSE) + fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items); + + if(sig[0]) { // Found it, set up for header decode + enter_have_sync(); + } + break; + + case STATE_HAVE_SYNC: + // only demod after getting the preamble signal; otherwise, the + // equalizer taps will screw with the PLL performance + bytes = demapper(&in[0], d_bytes_out); + + if(VERBOSE) { + if(sig[0]) + printf("ERROR -- Found SYNC in HAVE_SYNC\n"); + fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n", + d_headerbytelen_cnt, d_header); + } + + j = 0; + while(j < bytes) { + d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF); + j++; + + if(++d_headerbytelen_cnt == HEADERBYTELEN) { + if(VERBOSE) + fprintf(stderr, "got header: 0x%08x\n", d_header); + + // we have a full header, check to see if it has been received properly + if(header_ok()) { + enter_have_header(); + + if(VERBOSE) + printf("\nPacket Length: %d\n", d_packetlen); + + while((j < bytes) && (d_packetlen_cnt < d_packetlen)) { + d_packet[d_packetlen_cnt++] = d_bytes_out[j++]; + } + + if(d_packetlen_cnt == d_packetlen) { + gr_message_sptr msg = + gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen); + memcpy(msg->msg(), d_packet, d_packetlen_cnt); + d_target_queue->insert_tail(msg); // send it + msg.reset(); // free it up + + enter_search(); + } + } + else { + enter_search(); // bad header + } + } + } + break; + + case STATE_HAVE_HEADER: + bytes = demapper(&in[0], d_bytes_out); + + if(VERBOSE) { + if(sig[0]) + printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen); + fprintf(stderr,"Packet Build\n"); + } + + j = 0; + while(j < bytes) { + d_packet[d_packetlen_cnt++] = d_bytes_out[j++]; + + if (d_packetlen_cnt == d_packetlen){ // packet is filled + // build a message + // NOTE: passing header field as arg1 is not scalable + gr_message_sptr msg = + gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt); + memcpy(msg->msg(), d_packet, d_packetlen_cnt); + + d_target_queue->insert_tail(msg); // send it + msg.reset(); // free it up + + enter_search(); + break; + } + } + break; + + default: + assert(0); + } // switch + + return 1; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/ofdm_frame_sink_impl.h b/gr-digital/lib/ofdm_frame_sink_impl.h new file mode 100644 index 0000000000..49d5d6b5c0 --- /dev/null +++ b/gr-digital/lib/ofdm_frame_sink_impl.h @@ -0,0 +1,106 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_FRAME_SINK_IMPL_H +#define INCLUDED_DIGITAL_OFDM_FRAME_SINK_IMPL_H + +#include <digital/ofdm_frame_sink.h> + +namespace gr { + namespace digital { + + class ofdm_frame_sink_impl : public ofdm_frame_sink + { + private: + enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER}; + + static const int MAX_PKT_LEN = 4096; + static const int HEADERBYTELEN = 4; + + gr_msg_queue_sptr d_target_queue; // where to send the packet when received + state_t d_state; + unsigned int d_header; // header bits + int d_headerbytelen_cnt; // how many so far + + char *d_bytes_out; // hold the current bytes produced by the demapper + + int d_occupied_carriers; + unsigned int d_byte_offset; + unsigned int d_partial_byte; + + char d_packet[MAX_PKT_LEN]; // assembled payload + int d_packetlen; // length of packet + int d_packet_whitener_offset; // offset into whitener string to use + int d_packetlen_cnt; // how many so far + + gr_complex * d_derotated_output; // Pointer to output stream to send deroated symbols out + + std::vector<gr_complex> d_sym_position; + std::vector<char> d_sym_value_out; + std::vector<gr_complex> d_dfe; + unsigned int d_nbits; + + char d_resid; + unsigned int d_nresid; + float d_phase; + float d_freq; + float d_phase_gain; + float d_freq_gain; + float d_eq_gain; + + std::vector<int> d_subcarrier_map; + + protected: + void enter_search(); + void enter_have_sync(); + void enter_have_header(); + + bool header_ok() + { + // confirm that two copies of header info are identical + return ((d_header >> 16) ^ (d_header & 0xffff)) == 0; + } + + char slicer(const gr_complex x); + unsigned int demapper(const gr_complex *in, + char *out); + + bool set_sym_value_out(const std::vector<gr_complex> &sym_position, + const std::vector<char> &sym_value_out); + + public: + ofdm_frame_sink_impl(const std::vector<gr_complex> &sym_position, + const std::vector<char> &sym_value_out, + gr_msg_queue_sptr target_queue, + int occupied_tones, + float phase_gain=0.25, float freq_gain=0.25*0.25/4); + ~ofdm_frame_sink_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_OFDM_FRAME_SINK_IMPL_H */ diff --git a/gr-digital/lib/ofdm_insert_preamble_impl.cc b/gr-digital/lib/ofdm_insert_preamble_impl.cc new file mode 100644 index 0000000000..100e69e22c --- /dev/null +++ b/gr-digital/lib/ofdm_insert_preamble_impl.cc @@ -0,0 +1,201 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2010-2012 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ofdm_insert_preamble_impl.h" +#include <gr_io_signature.h> +#include <stdexcept> +#include <iostream> +#include <string> + +namespace gr { + namespace digital { + + ofdm_insert_preamble::sptr + ofdm_insert_preamble::make(int fft_length, + const std::vector<std::vector<gr_complex> > &preamble) + { + return gnuradio::get_initial_sptr + (new ofdm_insert_preamble_impl(fft_length, preamble)); + } + + ofdm_insert_preamble_impl::ofdm_insert_preamble_impl(int fft_length, + const std::vector<std::vector<gr_complex> > &preamble) + : gr_block("ofdm_insert_preamble", + gr_make_io_signature2(1, 2, + sizeof(gr_complex)*fft_length, + sizeof(char)), + gr_make_io_signature2(1, 2, + sizeof(gr_complex)*fft_length, + sizeof(char))), + d_fft_length(fft_length), + d_state(ST_IDLE), + d_nsymbols_output(0), + d_pending_flag(0), + d_preamble(preamble) + { + // sanity check preamble symbols + for(size_t i = 0; i < d_preamble.size(); i++) { + if(d_preamble[i].size() != (size_t) d_fft_length) + throw std::invalid_argument("ofdm_insert_preamble_impl: invalid length for preamble symbol"); + } + + enter_idle(); + } + + + ofdm_insert_preamble_impl::~ofdm_insert_preamble_impl() + { + } + + void + ofdm_insert_preamble_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = noutput_items; + } + + int + ofdm_insert_preamble_impl::general_work(int noutput_items, + gr_vector_int &ninput_items_v, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + int ninput_items = ninput_items_v.size() == 2 ? + std::min(ninput_items_v[0], ninput_items_v[1]) : ninput_items_v[0]; + + const gr_complex *in_sym = (const gr_complex *)input_items[0]; + const unsigned char *in_flag = 0; + + if(input_items.size() == 2) + in_flag = (const unsigned char*)input_items[1]; + + gr_complex *out_sym = (gr_complex*)output_items[0]; + unsigned char *out_flag = 0; + if(output_items.size() == 2) + out_flag = (unsigned char*)output_items[1]; + + int no = 0; // number items output + int ni = 0; // number items read from input + +#define write_out_flag() \ + do { \ + if(out_flag) \ + out_flag[no] = d_pending_flag; \ + d_pending_flag = 0; \ + } while(0) + + while(no < noutput_items && ni < ninput_items) { + switch(d_state) { + case ST_IDLE: + if(in_flag && in_flag[ni] & 0x1) // this is first symbol of new payload + enter_preamble(); + else + ni++; // eat one input symbol + break; + + case ST_PREAMBLE: + assert(!in_flag || in_flag[ni] & 0x1); + if(d_nsymbols_output >= (int) d_preamble.size()) { + // we've output all the preamble + enter_first_payload(); + } + else { + memcpy(&out_sym[no * d_fft_length], + &d_preamble[d_nsymbols_output][0], + d_fft_length*sizeof(gr_complex)); + + write_out_flag(); + no++; + d_nsymbols_output++; + } + break; + + case ST_FIRST_PAYLOAD: + // copy first payload symbol from input to output + memcpy(&out_sym[no * d_fft_length], + &in_sym[ni * d_fft_length], + d_fft_length * sizeof(gr_complex)); + + write_out_flag(); + no++; + ni++; + enter_payload(); + break; + + case ST_PAYLOAD: + if(in_flag && in_flag[ni] & 0x1) { // this is first symbol of a new payload + enter_preamble(); + break; + } + + // copy a symbol from input to output + memcpy(&out_sym[no * d_fft_length], + &in_sym[ni * d_fft_length], + d_fft_length * sizeof(gr_complex)); + + write_out_flag(); + no++; + ni++; + break; + + default: + std::cerr << "ofdm_insert_preamble_impl: (can't happen) invalid state, resetting\n"; + enter_idle(); + } + } + + consume_each(ni); + return no; + } + + void + ofdm_insert_preamble_impl::enter_idle() + { + d_state = ST_IDLE; + d_nsymbols_output = 0; + d_pending_flag = 0; + } + + void + ofdm_insert_preamble_impl::enter_preamble() + { + d_state = ST_PREAMBLE; + d_nsymbols_output = 0; + d_pending_flag = 1; + } + + void + ofdm_insert_preamble_impl::enter_first_payload() + { + d_state = ST_FIRST_PAYLOAD; + } + + void + ofdm_insert_preamble_impl::enter_payload() + { + d_state = ST_PAYLOAD; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/ofdm_insert_preamble_impl.h b/gr-digital/lib/ofdm_insert_preamble_impl.h new file mode 100644 index 0000000000..cd47810daf --- /dev/null +++ b/gr-digital/lib/ofdm_insert_preamble_impl.h @@ -0,0 +1,67 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2011,2012 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_INSERT_PREAMBLE_IMPL_H +#define INCLUDED_DIGITAL_OFDM_INSERT_PREAMBLE_IMPL_H + +#include <digital/ofdm_insert_preamble.h> + +namespace gr { + namespace digital { + + class ofdm_insert_preamble_impl : public ofdm_insert_preamble + { + private: + enum state_t { + ST_IDLE, + ST_PREAMBLE, + ST_FIRST_PAYLOAD, + ST_PAYLOAD + }; + + int d_fft_length; + state_t d_state; + int d_nsymbols_output; + int d_pending_flag; + const std::vector<std::vector<gr_complex> > d_preamble; + + void enter_idle(); + void enter_first_payload(); + void enter_payload(); + + public: + ofdm_insert_preamble_impl(int fft_length, + const std::vector<std::vector<gr_complex> > &preamble); + ~ofdm_insert_preamble_impl(); + + void enter_preamble(); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_OFDM_INSERT_PREAMBLE_IMPL_H */ diff --git a/gr-digital/lib/ofdm_mapper_bcv_impl.cc b/gr-digital/lib/ofdm_mapper_bcv_impl.cc new file mode 100644 index 0000000000..5b5359d7b9 --- /dev/null +++ b/gr-digital/lib/ofdm_mapper_bcv_impl.cc @@ -0,0 +1,252 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006-2008,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ofdm_mapper_bcv_impl.h" +#include <gr_io_signature.h> +#include <stdexcept> +#include <string> + +namespace gr { + namespace digital { + + ofdm_mapper_bcv::sptr + ofdm_mapper_bcv::make(const std::vector<gr_complex> &constellation, + unsigned int msgq_limit, + unsigned int occupied_carriers, + unsigned int fft_length) + { + return gnuradio::get_initial_sptr + (new ofdm_mapper_bcv_impl(constellation, msgq_limit, + occupied_carriers, fft_length)); + } + + // Consumes 1 packet and produces as many OFDM symbols of + // fft_length to hold the full packet + ofdm_mapper_bcv_impl::ofdm_mapper_bcv_impl(const std::vector<gr_complex> &constellation, + unsigned int msgq_limit, + unsigned int occupied_carriers, + unsigned int fft_length) + : gr_sync_block("ofdm_mapper_bcv", + gr_make_io_signature(0, 0, 0), + gr_make_io_signature2(1, 2, sizeof(gr_complex)*fft_length, sizeof(char))), + d_constellation(constellation), + d_msgq(gr_make_msg_queue(msgq_limit)), d_msg_offset(0), d_eof(false), + d_occupied_carriers(occupied_carriers), + d_fft_length(fft_length), + d_bit_offset(0), + d_pending_flag(0), + d_resid(0), + d_nresid(0) + { + if(!(d_occupied_carriers <= d_fft_length)) + throw std::invalid_argument("ofdm_mapper_bcv_impl: occupied carriers must be <= fft_length"); + + // this is not the final form of this solution since we still + // use the occupied_tones concept, which would get us into + // trouble if the number of carriers we seek is greater than the + // occupied carriers. + // Eventually, we will get rid of the occupied_carriers concept. + std::string carriers = "FE7F"; + + // A bit hacky to fill out carriers to occupied_carriers length + int diff = (d_occupied_carriers - 4*carriers.length()); + while(diff > 7) { + carriers.insert(0, "f"); + carriers.insert(carriers.length(), "f"); + diff -= 8; + } + + // if there's extras left to be processed divide remaining to + // put on either side of current map all of this is done to + // stick with the concept of a carrier map string that can be + // later passed by the user, even though it'd be cleaner to just + // do this on the carrier map itself + int diff_left=0; + int diff_right=0; + + // dictionary to convert from integers to ascii hex representation + char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + if(diff > 0) { + char c[2] = {0,0}; + + diff_left = (int)ceil((float)diff/2.0f); // number of carriers to put on the left side + c[0] = abc[(1 << diff_left) - 1]; // convert to bits and move to ASCI integer + carriers.insert(0, c); + + diff_right = diff - diff_left; // number of carriers to put on the right side + c[0] = abc[0xF^((1 << diff_right) - 1)]; // convert to bits and move to ASCI integer + carriers.insert(carriers.length(), c); + } + + // find out how many zeros to pad on the sides; the difference between the fft length and the subcarrier + // mapping size in chunks of four. This is the number to pack on the left and this number plus any + // residual nulls (if odd) will be packed on the right. + diff = (d_fft_length/4 - carriers.length())/2; + + unsigned int i,j,k; + for(i = 0; i < carriers.length(); i++) { + char c = carriers[i]; // get the current hex character from the string + for(j = 0; j < 4; j++) { // walk through all four bits + k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1; // convert to int and extract next bit + if(k) { // if bit is a 1, + d_subcarrier_map.push_back(4*(i+diff) + j); // use this subcarrier + } + } + } + + // make sure we stay in the limit currently imposed by the occupied_carriers + if(d_subcarrier_map.size() > d_occupied_carriers) { + throw std::invalid_argument("ofdm_mapper_bcv_impl: subcarriers allocated exceeds size of occupied carriers"); + } + + d_nbits = (unsigned long)ceil(log10(float(d_constellation.size())) / log10(2.0)); + } + + ofdm_mapper_bcv_impl::~ofdm_mapper_bcv_impl() + { + } + + int ofdm_mapper_bcv_impl::randsym() + { + return (rand() % d_constellation.size()); + } + + int + ofdm_mapper_bcv_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *out = (gr_complex *)output_items[0]; + + unsigned int i=0; + + //printf("OFDM BPSK Mapper: ninput_items: %d noutput_items: %d\n", ninput_items[0], noutput_items); + + if(d_eof) { + return -1; + } + + if(!d_msg) { + d_msg = d_msgq->delete_head(); // block, waiting for a message + d_msg_offset = 0; + d_bit_offset = 0; + d_pending_flag = 1; // new packet, write start of packet flag + + if((d_msg->length() == 0) && (d_msg->type() == 1)) { + d_msg.reset(); + return -1; // We're done; no more messages coming. + } + } + + char *out_flag = 0; + if(output_items.size() == 2) + out_flag = (char *) output_items[1]; + + + // Build a single symbol: + // Initialize all bins to 0 to set unused carriers + memset(out, 0, d_fft_length*sizeof(gr_complex)); + + i = 0; + unsigned char bits = 0; + //while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { + while((d_msg_offset < d_msg->length()) && (i < d_subcarrier_map.size())) { + + // need new data to process + if(d_bit_offset == 0) { + d_msgbytes = d_msg->msg()[d_msg_offset]; + //printf("mod message byte: %x\n", d_msgbytes); + } + + if(d_nresid > 0) { + // take the residual bits, fill out nbits with info from the new byte, and put them in the symbol + d_resid |= (((1 << d_nresid)-1) & d_msgbytes) << (d_nbits - d_nresid); + bits = d_resid; + + out[d_subcarrier_map[i]] = d_constellation[bits]; + i++; + + d_bit_offset += d_nresid; + d_nresid = 0; + d_resid = 0; + //printf("mod bit(r): %x resid: %x nresid: %d bit_offset: %d\n", + // bits, d_resid, d_nresid, d_bit_offset); + } + else { + if((8 - d_bit_offset) >= d_nbits) { // test to make sure we can fit nbits + // take the nbits number of bits at a time from the byte to add to the symbol + bits = ((1 << d_nbits)-1) & (d_msgbytes >> d_bit_offset); + d_bit_offset += d_nbits; + + out[d_subcarrier_map[i]] = d_constellation[bits]; + i++; + } + else { // if we can't fit nbits, store them for the next + // saves d_nresid bits of this message where d_nresid < d_nbits + unsigned int extra = 8-d_bit_offset; + d_resid = ((1 << extra)-1) & (d_msgbytes >> d_bit_offset); + d_bit_offset += extra; + d_nresid = d_nbits - extra; + } + } + + if(d_bit_offset == 8) { + d_bit_offset = 0; + d_msg_offset++; + } + } + + // Ran out of data to put in symbol + if (d_msg_offset == d_msg->length()) { + if(d_nresid > 0) { + d_resid |= 0x00; + bits = d_resid; + d_nresid = 0; + d_resid = 0; + } + + //while(i < d_occupied_carriers) { // finish filling out the symbol + while(i < d_subcarrier_map.size()) { // finish filling out the symbol + out[d_subcarrier_map[i]] = d_constellation[randsym()]; + i++; + } + + if(d_msg->type() == 1) // type == 1 sets EOF + d_eof = true; + d_msg.reset(); // finished packet, free message + assert(d_bit_offset == 0); + } + + if(out_flag) + out_flag[0] = d_pending_flag; + d_pending_flag = 0; + + return 1; // produced symbol + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/ofdm_mapper_bcv_impl.h b/gr-digital/lib/ofdm_mapper_bcv_impl.h new file mode 100644 index 0000000000..6459ed73d8 --- /dev/null +++ b/gr-digital/lib/ofdm_mapper_bcv_impl.h @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_MAPPER_BCV_IMPL_H +#define INCLUDED_DIGITAL_OFDM_MAPPER_BCV_IMPL_H + +#include <digital/ofdm_mapper_bcv.h> +#include <gr_message.h> +#include <vector> + +namespace gr { + namespace digital { + + class ofdm_mapper_bcv_impl : public ofdm_mapper_bcv + { + private: + std::vector<gr_complex> d_constellation; + gr_msg_queue_sptr d_msgq; + gr_message_sptr d_msg; + unsigned d_msg_offset; + bool d_eof; + + unsigned int d_occupied_carriers; + unsigned int d_fft_length; + unsigned int d_bit_offset; + int d_pending_flag; + + unsigned long d_nbits; + unsigned char d_msgbytes; + + unsigned char d_resid; + unsigned int d_nresid; + + std::vector<int> d_subcarrier_map; + + int randsym(); + + public: + ofdm_mapper_bcv_impl(const std::vector<gr_complex> &constellation, + unsigned msgq_limit, + unsigned occupied_carriers, + unsigned int fft_length); + ~ofdm_mapper_bcv_impl(void); + + gr_msg_queue_sptr msgq() const { return d_msgq; } + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_OFDM_MAPPER_BCV_IMPL_H */ diff --git a/gr-digital/lib/ofdm_sampler_impl.cc b/gr-digital/lib/ofdm_sampler_impl.cc new file mode 100644 index 0000000000..0724b7cf26 --- /dev/null +++ b/gr-digital/lib/ofdm_sampler_impl.cc @@ -0,0 +1,144 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008,2010-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ofdm_sampler_impl.h" +#include <gr_io_signature.h> +#include <gr_expj.h> +#include <cstdio> + +namespace gr { + namespace digital { + + ofdm_sampler::sptr + ofdm_sampler::make(unsigned int fft_length, + unsigned int symbol_length, + unsigned int timeout) + { + return gnuradio::get_initial_sptr + (new ofdm_sampler_impl(fft_length, symbol_length, timeout)); + } + + ofdm_sampler_impl::ofdm_sampler_impl(unsigned int fft_length, + unsigned int symbol_length, + unsigned int timeout) + : gr_block("ofdm_sampler", + gr_make_io_signature2(2, 2, sizeof(gr_complex), sizeof(char)), + gr_make_io_signature2(2, 2, sizeof(gr_complex)*fft_length, sizeof(char)*fft_length)), + d_state(STATE_NO_SIG), d_timeout_max(timeout), + d_fft_length(fft_length), d_symbol_length(symbol_length) + { + set_relative_rate(1.0/(double) fft_length); // buffer allocator hint + } + + ofdm_sampler_impl::~ofdm_sampler_impl() + { + } + + void + ofdm_sampler_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + // FIXME do we need more + //int nreqd = (noutput_items-1) * d_symbol_length + d_fft_length; + int nreqd = d_symbol_length + d_fft_length; + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = nreqd; + } + + int + ofdm_sampler_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 *iptr = (const gr_complex*)input_items[0]; + const char *trigger = (const char*)input_items[1]; + + gr_complex *optr = (gr_complex*)output_items[0]; + char *outsig = (char*)output_items[1]; + + //FIXME: we only process a single OFDM symbol at a time; after the preamble, we can + // process a few at a time as long as we always look out for the next preamble. + + unsigned int index = d_fft_length; // start one fft length into the input so we can always look back this far + + outsig[0] = 0; // set output to no signal by default + + // Search for a preamble trigger signal during the next symbol length + while((d_state != STATE_PREAMBLE) && (index <= (d_symbol_length+d_fft_length))) { + if(trigger[index]) { + outsig[0] = 1; // tell the next block there is a preamble coming + d_state = STATE_PREAMBLE; + } + else + index++; + } + + unsigned int i, pos, ret; + switch(d_state) { + case(STATE_PREAMBLE): + // When we found a preamble trigger, get it and set the symbol boundary here + for(i = (index - d_fft_length + 1); i <= index; i++) { + *optr++ = iptr[i]; + } + + d_timeout = d_timeout_max; // tell the system to expect at least this many symbols for a frame + d_state = STATE_FRAME; + consume_each(index - d_fft_length + 1); // consume up to one fft_length away to keep the history + ret = 1; + break; + + case(STATE_FRAME): + // use this state when we have processed a preamble and are getting the rest of the frames + //FIXME: we could also have a power squelch system here to enter STATE_NO_SIG if no power is received + + // skip over fft length history and cyclic prefix + pos = d_symbol_length; // keeps track of where we are in the input buffer + while(pos < d_symbol_length + d_fft_length) { + *optr++ = iptr[pos++]; + } + + if(d_timeout-- == 0) { + printf("TIMEOUT\n"); + d_state = STATE_NO_SIG; + } + + consume_each(d_symbol_length); // jump up by 1 fft length and the cyclic prefix length + ret = 1; + break; + + case(STATE_NO_SIG): + default: + consume_each(index-d_fft_length); // consume everything we've gone through so far leaving the fft length history + ret = 0; + break; + } + + return ret; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/ofdm_sampler_impl.h b/gr-digital/lib/ofdm_sampler_impl.h new file mode 100644 index 0000000000..369447465f --- /dev/null +++ b/gr-digital/lib/ofdm_sampler_impl.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_SAMPLER_IMPL_H +#define INCLUDED_DIGITAL_OFDM_SAMPLER_IMPL_H + +#include <digital/ofdm_sampler.h> +#include <gr_sync_block.h> + +namespace gr { + namespace digital { + + class ofdm_sampler_impl : public ofdm_sampler + { + private: + enum state_t {STATE_NO_SIG, STATE_PREAMBLE, STATE_FRAME}; + + state_t d_state; + unsigned int d_timeout_max; + unsigned int d_timeout; + unsigned int d_fft_length; + unsigned int d_symbol_length; + + public: + ofdm_sampler_impl(unsigned int fft_length, + unsigned int symbol_length, + unsigned int timeout=1000); + ~ofdm_sampler_impl(); + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_OFDM_SAMPLER_IMPL_H */ diff --git a/gr-digital/lib/packet_sink_impl.cc b/gr-digital/lib/packet_sink_impl.cc new file mode 100644 index 0000000000..1d79b3d717 --- /dev/null +++ b/gr-digital/lib/packet_sink_impl.cc @@ -0,0 +1,209 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "packet_sink_impl.h" +#include <gr_io_signature.h> +#include <cstdio> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdexcept> +#include <blocks/count_bits.h> +#include <string.h> + +namespace gr { + namespace digital { + +#define VERBOSE 0 + +// detect access code with up to DEFAULT_THRESHOLD bits wrong +static const int DEFAULT_THRESHOLD = 12; + + inline void + packet_sink_impl::enter_search() + { + if(VERBOSE) + fprintf(stderr, "@ enter_search\n"); + + d_state = STATE_SYNC_SEARCH; + d_shift_reg = 0; + } + + inline void + packet_sink_impl::enter_have_sync() + { + if(VERBOSE) + fprintf(stderr, "@ enter_have_sync\n"); + + d_state = STATE_HAVE_SYNC; + d_header = 0; + d_headerbitlen_cnt = 0; + } + + inline void + packet_sink_impl::enter_have_header(int payload_len) + { + if(VERBOSE) + fprintf(stderr, "@ enter_have_header (payload_len = %d)\n", payload_len); + + d_state = STATE_HAVE_HEADER; + d_packetlen = payload_len; + d_packetlen_cnt = 0; + d_packet_byte = 0; + d_packet_byte_index = 0; + } + + packet_sink::sptr + packet_sink::make(const std::vector<unsigned char>& sync_vector, + gr_msg_queue_sptr target_queue, int threshold) + { + return gnuradio::get_initial_sptr + (new packet_sink_impl(sync_vector, target_queue, threshold)); + } + + packet_sink_impl::packet_sink_impl(const std::vector<unsigned char>& sync_vector, + gr_msg_queue_sptr target_queue, int threshold) + : gr_sync_block("packet_sink", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(0, 0, 0)), + d_target_queue(target_queue), d_threshold(threshold == -1 ? DEFAULT_THRESHOLD : threshold) + { + d_sync_vector = 0; + for(int i=0;i<8;i++){ + d_sync_vector <<= 8; + d_sync_vector |= sync_vector[i]; + } + + enter_search(); + } + + packet_sink_impl::~packet_sink_impl() + { + } + + int + packet_sink_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + float *inbuf = (float*)input_items[0]; + int count=0; + + if(VERBOSE) + fprintf(stderr, ">>> Entering state machine\n"), fflush(stderr); + + while(count<noutput_items) { + switch(d_state) { + + case STATE_SYNC_SEARCH: // Look for sync vector + if(VERBOSE) + fprintf(stderr, "SYNC Search, noutput=%d\n",noutput_items), fflush(stderr); + + while(count < noutput_items) { + if(slice(inbuf[count++])) + d_shift_reg = (d_shift_reg << 1) | 1; + else + d_shift_reg = d_shift_reg << 1; + + // Compute popcnt of putative sync vector + if(gr::blocks::count_bits64(d_shift_reg ^ d_sync_vector) <= d_threshold) { + // Found it, set up for header decode + enter_have_sync(); + break; + } + } + break; + + case STATE_HAVE_SYNC: + if(VERBOSE) + fprintf(stderr, "Header Search bitcnt=%d, header=0x%08x\n", d_headerbitlen_cnt, d_header), + fflush(stderr); + + while(count < noutput_items) { // Shift bits one at a time into header + if(slice(inbuf[count++])) + d_header = (d_header << 1) | 1; + else + d_header = d_header << 1; + + if(++d_headerbitlen_cnt == HEADERBITLEN) { + if(VERBOSE) + fprintf(stderr, "got header: 0x%08x\n", d_header); + + // we have a full header, check to see if it has been received properly + if(header_ok()) { + int payload_len = header_payload_len(); + if(payload_len <= MAX_PKT_LEN) // reasonable? + enter_have_header(payload_len); // yes. + else + enter_search(); // no. + } + else + enter_search(); // no. + break; // we're in a new state + } + } + break; + + case STATE_HAVE_HEADER: + if(VERBOSE) + fprintf(stderr,"Packet Build\n"),fflush(stderr); + + while(count < noutput_items) { // shift bits into bytes of packet one at a time + if(slice(inbuf[count++])) + d_packet_byte = (d_packet_byte << 1) | 1; + else + d_packet_byte = d_packet_byte << 1; + + if(d_packet_byte_index++ == 7) { // byte is full so move to next byte + d_packet[d_packetlen_cnt++] = d_packet_byte; + d_packet_byte_index = 0; + + if(d_packetlen_cnt == d_packetlen) { // packet is filled + // build a message + gr_message_sptr msg = gr_make_message(0, 0, 0, d_packetlen_cnt); + memcpy(msg->msg(), d_packet, d_packetlen_cnt); + + d_target_queue->insert_tail(msg); // send it + msg.reset(); // free it up + + enter_search(); + break; + } + } + } + break; + + default: + assert(0); + } // switch + } // while + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/packet_sink_impl.h b/gr-digital/lib/packet_sink_impl.h new file mode 100644 index 0000000000..a63db7a142 --- /dev/null +++ b/gr-digital/lib/packet_sink_impl.h @@ -0,0 +1,96 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2012 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. + */ + +#ifndef INCLUDED_GR_PACKET_SINK_IMPL_H +#define INCLUDED_GR_PACKET_SINK_IMPL_H + +#include <digital/packet_sink.h> + +namespace gr { + namespace digital { + + class packet_sink_impl : public packet_sink + { + private: + enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER}; + + static const int MAX_PKT_LEN = 4096; + static const int HEADERBITLEN = 32; + + gr_msg_queue_sptr d_target_queue; // where to send the packet when received + unsigned long long d_sync_vector; // access code to locate start of packet + unsigned int d_threshold; // how many bits may be wrong in sync vector + + state_t d_state; + + unsigned long long d_shift_reg; // used to look for sync_vector + + unsigned int d_header; // header bits + int d_headerbitlen_cnt;// how many so far + + unsigned char d_packet[MAX_PKT_LEN]; // assembled payload + unsigned char d_packet_byte; // byte being assembled + int d_packet_byte_index; // which bit of d_packet_byte we're working on + int d_packetlen; // length of packet + int d_packetlen_cnt; // how many so far + + protected: + void enter_search(); + void enter_have_sync(); + void enter_have_header(int payload_len); + + int slice(float x) { return x > 0 ? 1 : 0; } + + bool header_ok() + { + // confirm that two copies of header info are identical + return ((d_header >> 16) ^ (d_header & 0xffff)) == 0; + } + + int header_payload_len() + { + // header consists of two 16-bit shorts in network byte order + int t = (d_header >> 16) & 0xffff; + return t; + } + + public: + packet_sink_impl(const std::vector<unsigned char>& sync_vector, + gr_msg_queue_sptr target_queue, + int threshold=-1); + ~packet_sink_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //! return true if we detect carrier + bool carrier_sensed() const + { + return d_state != STATE_SYNC_SEARCH; + } + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_PACKET_SINK_IMPL_H */ diff --git a/gr-digital/lib/pfb_clock_sync_ccf_impl.cc b/gr-digital/lib/pfb_clock_sync_ccf_impl.cc new file mode 100644 index 0000000000..3c4a0e8ad4 --- /dev/null +++ b/gr-digital/lib/pfb_clock_sync_ccf_impl.cc @@ -0,0 +1,505 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cstdio> +#include <cmath> + +#include "pfb_clock_sync_ccf_impl.h" +#include <gr_io_signature.h> +#include <gr_math.h> + +namespace gr { + namespace digital { + + pfb_clock_sync_ccf::sptr + pfb_clock_sync_ccf::make(double sps, float loop_bw, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation, + int osps) + { + return gnuradio::get_initial_sptr + (new pfb_clock_sync_ccf_impl(sps, loop_bw, taps, + filter_size, + init_phase, + max_rate_deviation, + osps)); + } + + static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)}; + static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); + pfb_clock_sync_ccf_impl::pfb_clock_sync_ccf_impl(double sps, float loop_bw, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation, + int osps) + : gr_block("pfb_clock_sync_ccf", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signaturev(1, 4, iosig)), + d_updated(false), d_nfilters(filter_size), + d_max_dev(max_rate_deviation), + d_osps(osps), d_error(0), d_out_idx(0) + { + d_nfilters = filter_size; + d_sps = floor(sps); + + // Set the damping factor for a critically damped system + d_damping = sqrtf(2.0f)/2.0f; + + // Set the bandwidth, which will then call update_gains() + set_loop_bandwidth(loop_bw); + + // Store the last filter between calls to work + // The accumulator keeps track of overflow to increment the stride correctly. + // set it here to the fractional difference based on the initial phaes + d_k = init_phase; + d_rate = (sps-floor(sps))*(double)d_nfilters; + d_rate_i = (int)floor(d_rate); + d_rate_f = d_rate - (float)d_rate_i; + d_filtnum = (int)floor(d_k); + + d_filters = std::vector<kernel::fir_filter_ccf*>(d_nfilters); + d_diff_filters = std::vector<kernel::fir_filter_ccf*>(d_nfilters); + + // Create an FIR filter for each channel and zero out the taps + std::vector<float> vtaps(0, d_nfilters); + for(int i = 0; i < d_nfilters; i++) { + d_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + d_diff_filters[i] = new kernel::fir_filter_ccf(1, vtaps); + } + + // Now, actually set the filters' taps + std::vector<float> dtaps; + create_diff_taps(taps, dtaps); + set_taps(taps, d_taps, d_filters); + set_taps(dtaps, d_dtaps, d_diff_filters); + } + + pfb_clock_sync_ccf_impl::~pfb_clock_sync_ccf_impl() + { + for(int i = 0; i < d_nfilters; i++) { + delete d_filters[i]; + delete d_diff_filters[i]; + } + } + + bool + pfb_clock_sync_ccf_impl::check_topology(int ninputs, int noutputs) + { + return noutputs == 1 || noutputs == 4; + } + + + /******************************************************************* + SET FUNCTIONS + *******************************************************************/ + + void + pfb_clock_sync_ccf_impl::set_loop_bandwidth(float bw) + { + if(bw < 0) { + throw std::out_of_range("pfb_clock_sync_ccf: invalid bandwidth. Must be >= 0."); + } + + d_loop_bw = bw; + update_gains(); + } + + void + pfb_clock_sync_ccf_impl::set_damping_factor(float df) + { + if(df < 0 || df > 1.0) { + throw std::out_of_range("pfb_clock_sync_ccf: invalid damping factor. Must be in [0,1]."); + } + + d_damping = df; + update_gains(); + } + + void + pfb_clock_sync_ccf_impl::set_alpha(float alpha) + { + if(alpha < 0 || alpha > 1.0) { + throw std::out_of_range("pfb_clock_sync_ccf: invalid alpha. Must be in [0,1]."); + } + d_alpha = alpha; + } + + void + pfb_clock_sync_ccf_impl::set_beta(float beta) + { + if(beta < 0 || beta > 1.0) { + throw std::out_of_range("pfb_clock_sync_ccf: invalid beta. Must be in [0,1]."); + } + d_beta = beta; + } + + /******************************************************************* + GET FUNCTIONS + *******************************************************************/ + + float + pfb_clock_sync_ccf_impl::loop_bandwidth() const + { + return d_loop_bw; + } + + float + pfb_clock_sync_ccf_impl::damping_factor() const + { + return d_damping; + } + + float + pfb_clock_sync_ccf_impl::alpha() const + { + return d_alpha; + } + + float + pfb_clock_sync_ccf_impl::beta() const + { + return d_beta; + } + + float + pfb_clock_sync_ccf_impl::clock_rate() const + { + return d_rate_f; + } + + float + pfb_clock_sync_ccf_impl::error() const + { + return d_error; + } + + float + pfb_clock_sync_ccf_impl::rate() const + { + return d_rate_f; + } + + float + pfb_clock_sync_ccf_impl::phase() const + { + return d_k; + } + + /******************************************************************* + *******************************************************************/ + + void + pfb_clock_sync_ccf_impl::update_gains() + { + float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); + d_alpha = (4*d_damping*d_loop_bw) / denom; + d_beta = (4*d_loop_bw*d_loop_bw) / denom; + } + + void + pfb_clock_sync_ccf_impl::set_taps(const std::vector<float> &newtaps, + std::vector< std::vector<float> > &ourtaps, + std::vector<kernel::fir_filter_ccf*> &ourfilter) + { + int i,j; + + unsigned int ntaps = newtaps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters); + + // Create d_numchan vectors to store each channel's taps + ourtaps.resize(d_nfilters); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector<float> tmp_taps; + tmp_taps = newtaps; + while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_nfilters; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + ourtaps[i] = std::vector<float>(d_taps_per_filter, 0); + for(j = 0; j < d_taps_per_filter; j++) { + ourtaps[i][j] = tmp_taps[i + j*d_nfilters]; + } + + // Build a filter for each channel and add it's taps to it + ourfilter[i]->set_taps(ourtaps[i]); + } + + // Set the history to ensure enough input items for each filter + set_history(d_taps_per_filter + d_sps); + + // Make sure there is enough output space for d_osps outputs/input. + set_output_multiple(d_osps); + + d_updated = true; + } + + void + pfb_clock_sync_ccf_impl::create_diff_taps(const std::vector<float> &newtaps, + std::vector<float> &difftaps) + { + std::vector<float> diff_filter(3); + diff_filter[0] = -1; + diff_filter[1] = 0; + diff_filter[2] = 1; + + float pwr = 0; + difftaps.push_back(0); + for(unsigned int i = 0; i < newtaps.size()-2; i++) { + float tap = 0; + for(int j = 0; j < 3; j++) { + tap += diff_filter[j]*newtaps[i+j]; + pwr += fabsf(tap); + } + difftaps.push_back(tap); + } + difftaps.push_back(0); + + for(unsigned int i = 0; i < difftaps.size(); i++) { + difftaps[i] *= pwr; + } + } + + std::string + pfb_clock_sync_ccf_impl::taps_as_string() const + { + int i, j; + std::stringstream str; + str.precision(4); + str.setf(std::ios::scientific); + + str << "[ "; + for(i = 0; i < d_nfilters; i++) { + str << "[" << d_taps[i][0] << ", "; + for(j = 1; j < d_taps_per_filter-1; j++) { + str << d_taps[i][j] << ", "; + } + str << d_taps[i][j] << "],"; + } + str << " ]" << std::endl; + + return str.str(); + } + + std::string + pfb_clock_sync_ccf_impl::diff_taps_as_string() const + { + int i, j; + std::stringstream str; + str.precision(4); + str.setf(std::ios::scientific); + + str << "[ "; + for(i = 0; i < d_nfilters; i++) { + str << "[" << d_dtaps[i][0] << ", "; + for(j = 1; j < d_taps_per_filter-1; j++) { + str << d_dtaps[i][j] << ", "; + } + str << d_dtaps[i][j] << "],"; + } + str << " ]" << std::endl; + + return str.str(); + } + + std::vector< std::vector<float> > + pfb_clock_sync_ccf_impl::taps() const + { + return d_taps; + } + + std::vector< std::vector<float> > + pfb_clock_sync_ccf_impl::diff_taps() const + { + return d_dtaps; + } + + std::vector<float> + pfb_clock_sync_ccf_impl::channel_taps(int channel) const + { + std::vector<float> taps; + for(int i = 0; i < d_taps_per_filter; i++) { + taps.push_back(d_taps[channel][i]); + } + return taps; + } + + std::vector<float> + pfb_clock_sync_ccf_impl::diff_channel_taps(int channel) const + { + std::vector<float> taps; + for(int i = 0; i < d_taps_per_filter; i++) { + taps.push_back(d_dtaps[channel][i]); + } + return taps; + } + + int + pfb_clock_sync_ccf_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gr_complex *in = (gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + float *err = NULL, *outrate = NULL, *outk = NULL; + if(output_items.size() == 4) { + err = (float *) output_items[1]; + outrate = (float*)output_items[2]; + outk = (float*)output_items[3]; + } + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + // We need this many to process one output + int nrequired = ninput_items[0] - d_taps_per_filter - d_osps; + + int i = 0, count = 0; + float error_r, error_i; + + // produce output as long as we can and there are enough input samples + while((i < noutput_items) && (count < nrequired)) { + while(d_out_idx < d_osps) { + d_filtnum = (int)floor(d_k); + + // Keep the current filter number in [0, d_nfilters] + // If we've run beyond the last filter, wrap around and go to next sample + // If we've go below 0, wrap around and go to previous sample + while(d_filtnum >= d_nfilters) { + d_k -= d_nfilters; + d_filtnum -= d_nfilters; + count += 1; + } + while(d_filtnum < 0) { + d_k += d_nfilters; + d_filtnum += d_nfilters; + count -= 1; + } + + out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); + d_k = d_k + d_rate_i + d_rate_f; // update phase + d_out_idx++; + + if(output_items.size() == 4) { + err[i] = d_error; + outrate[i] = d_rate_f; + outk[i] = d_k; + } + + // We've run out of output items we can create; return now. + if(i+d_out_idx >= noutput_items) { + consume_each(count); + return i; + } + } + + // reset here; if we didn't complete a full osps samples last time, + // the early return would take care of it. + d_out_idx = 0; + + // Update the phase and rate estimates for this symbol + gr_complex diff = d_diff_filters[d_filtnum]->filter(&in[count]); + error_r = out[i].real() * diff.real(); + error_i = out[i].imag() * diff.imag(); + d_error = (error_i + error_r) / 2.0; // average error from I&Q channel + + // Run the control loop to update the current phase (k) and + // tracking rate estimates based on the error value + d_rate_f = d_rate_f + d_beta*d_error; + d_k = d_k + d_alpha*d_error; + + // Keep our rate within a good range + d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev); + + i+=d_osps; + count += (int)floor(d_sps); + } + + consume_each(count); + return i; + } + + void + pfb_clock_sync_ccf_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + // Getters + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<pfb_clock_sync_ccf, float>( + alias(), "error", + &pfb_clock_sync_ccf::error, + pmt::mp(-2.0f), pmt::mp(2.0f), pmt::mp(0.0f), + "", "Error signal of loop", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<pfb_clock_sync_ccf, float>( + alias(), "rate", + &pfb_clock_sync_ccf::rate, + pmt::mp(-2.0f), pmt::mp(2.0f), pmt::mp(0.0f), + "", "Rate change of phase", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<pfb_clock_sync_ccf, float>( + alias(), "phase", + &pfb_clock_sync_ccf::phase, + pmt::mp(0), pmt::mp((int)d_nfilters), pmt::mp(0), + "", "Current filter phase arm", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<pfb_clock_sync_ccf, float>( + alias(), "loop bw", + &pfb_clock_sync_ccf::loop_bandwidth, + pmt::mp(0.0f), pmt::mp(1.0f), pmt::mp(0.0f), + "", "Loop bandwidth", + RPC_PRIVLVL_MIN, DISPNULL))); + + // Setters + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<pfb_clock_sync_ccf, float>( + alias(), "loop bw", + &pfb_clock_sync_ccf::set_loop_bandwidth, + pmt::mp(0.0f), pmt::mp(1.0f), pmt::mp(0.0f), + "", "Loop bandwidth", + RPC_PRIVLVL_MIN, DISPNULL))); +#endif /* GR_CTRLPORT */ + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/pfb_clock_sync_ccf_impl.h b/gr-digital/lib/pfb_clock_sync_ccf_impl.h new file mode 100644 index 0000000000..c7fdc9183e --- /dev/null +++ b/gr-digital/lib/pfb_clock_sync_ccf_impl.h @@ -0,0 +1,121 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_IMPL_H +#define INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_IMPL_H + +#include <digital/pfb_clock_sync_ccf.h> + +using namespace gr::filter; + +namespace gr { + namespace digital { + + class pfb_clock_sync_ccf_impl : public pfb_clock_sync_ccf + { + private: + bool d_updated; + double d_sps; + double d_sample_num; + float d_loop_bw; + float d_damping; + float d_alpha; + float d_beta; + + int d_nfilters; + int d_taps_per_filter; + std::vector<kernel::fir_filter_ccf*> d_filters; + std::vector<kernel::fir_filter_ccf*> d_diff_filters; + std::vector< std::vector<float> > d_taps; + std::vector< std::vector<float> > d_dtaps; + + float d_k; + float d_rate; + float d_rate_i; + float d_rate_f; + float d_max_dev; + int d_filtnum; + int d_osps; + float d_error; + int d_out_idx; + + void create_diff_taps(const std::vector<float> &newtaps, + std::vector<float> &difftaps); + + public: + pfb_clock_sync_ccf_impl(double sps, float loop_bw, + const std::vector<float> &taps, + unsigned int filter_size=32, + float init_phase=0, + float max_rate_deviation=1.5, + int osps=1); + ~pfb_clock_sync_ccf_impl(); + + void setup_rpc(); + + void update_gains(); + + void set_taps(const std::vector<float> &taps, + std::vector< std::vector<float> > &ourtaps, + std::vector<kernel::fir_filter_ccf*> &ourfilter); + + std::vector< std::vector<float> > taps() const; + std::vector< std::vector<float> > diff_taps() const; + std::vector<float> channel_taps(int channel) const; + std::vector<float> diff_channel_taps(int channel) const; + std::string taps_as_string() const; + std::string diff_taps_as_string() const; + + void set_loop_bandwidth(float bw); + void set_damping_factor(float df); + void set_alpha(float alpha); + void set_beta(float beta); + void set_max_rate_deviation(float m) + { + d_max_dev = m; + } + + float loop_bandwidth() const; + float damping_factor() const; + float alpha() const; + float beta() const; + float clock_rate() const; + + float error() const; + float rate() const; + float phase() const; + + /******************************************************************* + *******************************************************************/ + + bool check_topology(int ninputs, int noutputs); + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_PFB_CLOCK_SYNC_CCF_IMPL_H */ diff --git a/gr-digital/lib/pfb_clock_sync_fff_impl.cc b/gr-digital/lib/pfb_clock_sync_fff_impl.cc new file mode 100644 index 0000000000..fb60192324 --- /dev/null +++ b/gr-digital/lib/pfb_clock_sync_fff_impl.cc @@ -0,0 +1,435 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cstdio> +#include <cmath> + +#include "pfb_clock_sync_fff_impl.h" +#include <gr_io_signature.h> +#include <gr_math.h> + +namespace gr { + namespace digital { + + pfb_clock_sync_fff::sptr + pfb_clock_sync_fff::make(double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation, + int osps) + { + return gnuradio::get_initial_sptr + (new pfb_clock_sync_fff_impl(sps, gain, taps, + filter_size, + init_phase, + max_rate_deviation, + osps)); + } + + static int ios[] = {sizeof(float), sizeof(float), sizeof(float), sizeof(float)}; + static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int)); + pfb_clock_sync_fff_impl::pfb_clock_sync_fff_impl(double sps, float loop_bw, + const std::vector<float> &taps, + unsigned int filter_size, + float init_phase, + float max_rate_deviation, + int osps) + : gr_block("pfb_clock_sync_fff", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signaturev(1, 4, iosig)), + d_updated(false), d_nfilters(filter_size), + d_max_dev(max_rate_deviation), + d_osps(osps), d_error(0), d_out_idx(0) + { + d_nfilters = filter_size; + d_sps = floor(sps); + + // Set the damping factor for a critically damped system + d_damping = sqrtf(2.0f)/2.0f; + + // Set the bandwidth, which will then call update_gains() + set_loop_bandwidth(loop_bw); + + // Store the last filter between calls to work + // The accumulator keeps track of overflow to increment the stride correctly. + // set it here to the fractional difference based on the initial phaes + d_k = init_phase; + d_rate = (sps-floor(sps))*(double)d_nfilters; + d_rate_i = (int)floor(d_rate); + d_rate_f = d_rate - (float)d_rate_i; + d_filtnum = (int)floor(d_k); + + d_filters = std::vector<kernel::fir_filter_fff*>(d_nfilters); + d_diff_filters = std::vector<kernel::fir_filter_fff*>(d_nfilters); + + // Create an FIR filter for each channel and zero out the taps + std::vector<float> vtaps(0, d_nfilters); + for(int i = 0; i < d_nfilters; i++) { + d_filters[i] = new kernel::fir_filter_fff(1, vtaps); + d_diff_filters[i] = new kernel::fir_filter_fff(1, vtaps); + } + + // Now, actually set the filters' taps + std::vector<float> dtaps; + create_diff_taps(taps, dtaps); + set_taps(taps, d_taps, d_filters); + set_taps(dtaps, d_dtaps, d_diff_filters); + } + + pfb_clock_sync_fff_impl::~pfb_clock_sync_fff_impl() + { + for(int i = 0; i < d_nfilters; i++) { + delete d_filters[i]; + delete d_diff_filters[i]; + } + } + + bool + pfb_clock_sync_fff_impl::check_topology(int ninputs, int noutputs) + { + return noutputs == 1 || noutputs == 4; + } + + /******************************************************************* + SET FUNCTIONS + *******************************************************************/ + + void + pfb_clock_sync_fff_impl::set_loop_bandwidth(float bw) + { + if(bw < 0) { + throw std::out_of_range("pfb_clock_sync_fff_impl: invalid bandwidth. Must be >= 0."); + } + + d_loop_bw = bw; + update_gains(); + } + + void + pfb_clock_sync_fff_impl::set_damping_factor(float df) + { + if(df < 0 || df > 1.0) { + throw std::out_of_range("pfb_clock_sync_fff_impl: invalid damping factor. Must be in [0,1]."); + } + + d_damping = df; + update_gains(); + } + + void + pfb_clock_sync_fff_impl::set_alpha(float alpha) + { + if(alpha < 0 || alpha > 1.0) { + throw std::out_of_range("pfb_clock_sync_fff_impl: invalid alpha. Must be in [0,1]."); + } + d_alpha = alpha; + } + + void + pfb_clock_sync_fff_impl::set_beta(float beta) + { + if(beta < 0 || beta > 1.0) { + throw std::out_of_range("pfb_clock_sync_fff_impl: invalid beta. Must be in [0,1]."); + } + d_beta = beta; + } + + /******************************************************************* + GET FUNCTIONS + *******************************************************************/ + + float + pfb_clock_sync_fff_impl::loop_bandwidth() const + { + return d_loop_bw; + } + + float + pfb_clock_sync_fff_impl::damping_factor() const + { + return d_damping; + } + + float + pfb_clock_sync_fff_impl::alpha() const + { + return d_alpha; + } + + float + pfb_clock_sync_fff_impl::beta() const + { + return d_beta; + } + + float + pfb_clock_sync_fff_impl::clock_rate() const + { + return d_rate_f; + } + + /******************************************************************* + *******************************************************************/ + + void + pfb_clock_sync_fff_impl::update_gains() + { + float denom = (1.0 + 2.0*d_damping*d_loop_bw + d_loop_bw*d_loop_bw); + d_alpha = (4*d_damping*d_loop_bw) / denom; + d_beta = (4*d_loop_bw*d_loop_bw) / denom; + } + + void + pfb_clock_sync_fff_impl::set_taps(const std::vector<float> &newtaps, + std::vector< std::vector<float> > &ourtaps, + std::vector<kernel::fir_filter_fff*> &ourfilter) + { + int i,j; + + unsigned int ntaps = newtaps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_nfilters); + + // Create d_numchan vectors to store each channel's taps + ourtaps.resize(d_nfilters); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector<float> tmp_taps; + tmp_taps = newtaps; + while((float)(tmp_taps.size()) < d_nfilters*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_nfilters; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + ourtaps[i] = std::vector<float>(d_taps_per_filter, 0); + for(j = 0; j < d_taps_per_filter; j++) { + ourtaps[i][j] = tmp_taps[i + j*d_nfilters]; + } + + // Build a filter for each channel and add it's taps to it + ourfilter[i]->set_taps(ourtaps[i]); + } + + // Set the history to ensure enough input items for each filter + set_history(d_taps_per_filter + d_sps); + + // Make sure there is enough output space for d_osps outputs/input. + set_output_multiple(d_osps); + + d_updated = true; + } + + void + pfb_clock_sync_fff_impl::create_diff_taps(const std::vector<float> &newtaps, + std::vector<float> &difftaps) + { + std::vector<float> diff_filter(3); + diff_filter[0] = -1; + diff_filter[1] = 0; + diff_filter[2] = 1; + + float pwr = 0; + difftaps.push_back(0); + for(unsigned int i = 0; i < newtaps.size()-2; i++) { + float tap = 0; + for(int j = 0; j < 3; j++) { + tap += diff_filter[j]*newtaps[i+j]; + pwr += fabsf(tap); + } + difftaps.push_back(tap); + } + difftaps.push_back(0); + + for(unsigned int i = 0; i < difftaps.size(); i++) { + difftaps[i] *= pwr; + } + } + + std::string + pfb_clock_sync_fff_impl::taps_as_string() const + { + int i, j; + std::stringstream str; + str.precision(4); + str.setf(std::ios::scientific); + + str << "[ "; + for(i = 0; i < d_nfilters; i++) { + str << "[" << d_taps[i][0] << ", "; + for(j = 1; j < d_taps_per_filter-1; j++) { + str << d_taps[i][j] << ", "; + } + str << d_taps[i][j] << "],"; + } + str << " ]" << std::endl; + + return str.str(); + } + + std::string + pfb_clock_sync_fff_impl::diff_taps_as_string() const + { + int i, j; + std::stringstream str; + str.precision(4); + str.setf(std::ios::scientific); + + str << "[ "; + for(i = 0; i < d_nfilters; i++) { + str << "[" << d_dtaps[i][0] << ", "; + for(j = 1; j < d_taps_per_filter-1; j++) { + str << d_dtaps[i][j] << ", "; + } + str << d_dtaps[i][j] << "],"; + } + str << " ]" << std::endl; + + return str.str(); + } + + std::vector< std::vector<float> > + pfb_clock_sync_fff_impl::taps() const + { + return d_taps; + } + + std::vector< std::vector<float> > + pfb_clock_sync_fff_impl::diff_taps() const + { + return d_dtaps; + } + + std::vector<float> + pfb_clock_sync_fff_impl::channel_taps(int channel) const + { + std::vector<float> taps; + for(int i = 0; i < d_taps_per_filter; i++) { + taps.push_back(d_taps[channel][i]); + } + return taps; + } + + std::vector<float> + pfb_clock_sync_fff_impl::diff_channel_taps(int channel) const + { + std::vector<float> taps; + for(int i = 0; i < d_taps_per_filter; i++) { + taps.push_back(d_dtaps[channel][i]); + } + return taps; + } + + int + pfb_clock_sync_fff_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + float *in = (float *) input_items[0]; + float *out = (float *) output_items[0]; + + float *err = NULL, *outrate = NULL, *outk = NULL; + if(output_items.size() == 4) { + err = (float *) output_items[1]; + outrate = (float*)output_items[2]; + outk = (float*)output_items[3]; + } + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + // We need this many to process one output + int nrequired = ninput_items[0] - d_taps_per_filter - d_osps; + + int i = 0, count = 0; + + // produce output as long as we can and there are enough input samples + while((i < noutput_items) && (count < nrequired)) { + while(d_out_idx < d_osps) { + d_filtnum = (int)floor(d_k); + + // Keep the current filter number in [0, d_nfilters] + // If we've run beyond the last filter, wrap around and go to next sample + // If we've go below 0, wrap around and go to previous sample + while(d_filtnum >= d_nfilters) { + d_k -= d_nfilters; + d_filtnum -= d_nfilters; + count += 1; + } + while(d_filtnum < 0) { + d_k += d_nfilters; + d_filtnum += d_nfilters; + count -= 1; + } + + out[i+d_out_idx] = d_filters[d_filtnum]->filter(&in[count+d_out_idx]); + d_k = d_k + d_rate_i + d_rate_f; // update phase + d_out_idx++; + + if(output_items.size() == 4) { + err[i] = d_error; + outrate[i] = d_rate_f; + outk[i] = d_k; + } + + // We've run out of output items we can create; return now. + if(i+d_out_idx >= noutput_items) { + consume_each(count); + return i; + } + } + + // reset here; if we didn't complete a full osps samples last time, + // the early return would take care of it. + d_out_idx = 0; + + // Update the phase and rate estimates for this symbol + float diff = d_diff_filters[d_filtnum]->filter(&in[count]); + d_error = out[i] * diff; + + // Run the control loop to update the current phase (k) and + // tracking rate estimates based on the error value + d_rate_f = d_rate_f + d_beta*d_error; + d_k = d_k + d_alpha*d_error; + + // Keep our rate within a good range + d_rate_f = gr_branchless_clip(d_rate_f, d_max_dev); + + i+=d_osps; + count += (int)floor(d_sps); + } + + consume_each(count); + return i; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/pfb_clock_sync_fff_impl.h b/gr-digital/lib/pfb_clock_sync_fff_impl.h new file mode 100644 index 0000000000..2ade1e646f --- /dev/null +++ b/gr-digital/lib/pfb_clock_sync_fff_impl.h @@ -0,0 +1,112 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,2010,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_PFB_CLOCK_SYNC_FFF_IMPL_H +#define INCLUDED_DIGITAL_PFB_CLOCK_SYNC_FFF_IMPL_H + +#include <digital/pfb_clock_sync_fff.h> + +using namespace gr::filter; + +namespace gr { + namespace digital { + + class pfb_clock_sync_fff_impl : public pfb_clock_sync_fff + { + private: + bool d_updated; + double d_sps; + double d_sample_num; + float d_loop_bw; + float d_damping; + float d_alpha; + float d_beta; + + int d_nfilters; + int d_taps_per_filter; + std::vector<kernel::fir_filter_fff*> d_filters; + std::vector<kernel::fir_filter_fff*> d_diff_filters; + std::vector< std::vector<float> > d_taps; + std::vector< std::vector<float> > d_dtaps; + + float d_k; + float d_rate; + float d_rate_i; + float d_rate_f; + float d_max_dev; + int d_filtnum; + int d_osps; + float d_error; + int d_out_idx; + + void create_diff_taps(const std::vector<float> &newtaps, + std::vector<float> &difftaps); + + public: + pfb_clock_sync_fff_impl(double sps, float gain, + const std::vector<float> &taps, + unsigned int filter_size=32, + float init_phase=0, + float max_rate_deviation=1.5, + int osps=1); + ~pfb_clock_sync_fff_impl(); + + void update_gains(); + + void set_taps(const std::vector<float> &taps, + std::vector< std::vector<float> > &ourtaps, + std::vector<kernel::fir_filter_fff*> &ourfilter); + + std::vector< std::vector<float> > taps() const; + std::vector< std::vector<float> > diff_taps() const; + std::vector<float> channel_taps(int channel) const; + std::vector<float> diff_channel_taps(int channel) const; + std::string taps_as_string() const; + std::string diff_taps_as_string() const; + + void set_loop_bandwidth(float bw); + void set_damping_factor(float df); + void set_alpha(float alpha); + void set_beta(float beta); + void set_max_rate_deviation(float m) + { + d_max_dev = m; + } + + float loop_bandwidth() const; + float damping_factor() const; + float alpha() const; + float beta() const; + float clock_rate() const; + + bool check_topology(int ninputs, int noutputs); + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_PFB_CLOCK_SYNC_FFF_IMPL_H */ diff --git a/gr-digital/lib/pn_correlator_cc_impl.cc b/gr-digital/lib/pn_correlator_cc_impl.cc new file mode 100644 index 0000000000..da0bdbefe9 --- /dev/null +++ b/gr-digital/lib/pn_correlator_cc_impl.cc @@ -0,0 +1,86 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "pn_correlator_cc_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + pn_correlator_cc::sptr + pn_correlator_cc::make(int degree, int mask, int seed) + { + return gnuradio::get_initial_sptr + (new pn_correlator_cc_impl(degree, mask, seed)); + } + + pn_correlator_cc_impl::pn_correlator_cc_impl(int degree, + int mask, + int seed) + : gr_sync_decimator("pn_correlator_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + (unsigned int)((1ULL << degree)-1)) // PN code length + { + d_len = (unsigned int)((1ULL << degree)-1); + if(mask == 0) + mask = glfsr::glfsr_mask(degree); + d_reference = new glfsr(mask, seed); + for(int i = 0; i < d_len; i++) // initialize to last value in sequence + d_pn = 2.0*d_reference->next_bit()-1.0; + } + + pn_correlator_cc_impl::~pn_correlator_cc_impl() + { + delete d_reference; + } + + int + pn_correlator_cc_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]; + gr_complex sum; + + for(int i = 0; i < noutput_items; i++) { + sum = 0.0; + + for(int j = 0; j < d_len; j++) { + if(j != 0) // retard PN generator one sample per period + d_pn = 2.0*d_reference->next_bit()-1.0; // no conditionals + sum += *in++ * d_pn; + } + + *out++ = sum*gr_complex(1.0/d_len, 0.0); + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/pn_correlator_cc_impl.h b/gr-digital/lib/pn_correlator_cc_impl.h new file mode 100644 index 0000000000..bea9a30505 --- /dev/null +++ b/gr-digital/lib/pn_correlator_cc_impl.h @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2012 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. + */ + +#ifndef INCLUDED_GR_PN_CORRELATOR_CC_IMPL_H +#define INCLUDED_GR_PN_CORRELATOR_CC_IMPL_H + +#include <digital/pn_correlator_cc.h> +#include <digital/glfsr.h> + +namespace gr { + namespace digital { + + class pn_correlator_cc_impl : public pn_correlator_cc + { + private: + int d_len; + float d_pn; + glfsr *d_reference; + + public: + pn_correlator_cc_impl(int degree, int mask=0, int seed=1); + ~pn_correlator_cc_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_PN_CORRELATOR_CC_IMPL_H */ diff --git a/gr-digital/lib/probe_density_b_impl.cc b/gr-digital/lib/probe_density_b_impl.cc new file mode 100644 index 0000000000..532930ad1b --- /dev/null +++ b/gr-digital/lib/probe_density_b_impl.cc @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2010,2012 Free Software Foundation, Inc. + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "probe_density_b_impl.h" +#include <gr_io_signature.h> +#include <iostream> + +namespace gr { + namespace digital { + + probe_density_b::sptr + probe_density_b::make(double alpha) + { + return gnuradio::get_initial_sptr + (new probe_density_b_impl(alpha)); + } + + probe_density_b_impl::probe_density_b_impl(double alpha) + : gr_sync_block("density_b", + gr_make_io_signature(1, 1, sizeof(char)), + gr_make_io_signature(0, 0, 0)) + { + set_alpha(alpha); + d_density = 1.0; + } + + probe_density_b_impl::~probe_density_b_impl() + { + } + + void + probe_density_b_impl::set_alpha(double alpha) + { + d_alpha = alpha; + d_beta = 1.0-d_alpha; + } + + int + probe_density_b_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const char *in = (const char *)input_items[0]; + + for(int i = 0; i < noutput_items; i++) + d_density = d_alpha*(double)in[i] + d_beta*d_density; + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/probe_density_b_impl.h b/gr-digital/lib/probe_density_b_impl.h new file mode 100644 index 0000000000..e792403dc5 --- /dev/null +++ b/gr-digital/lib/probe_density_b_impl.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2012 Free Software Foundation, Inc. + * + * 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. + */ + +#ifndef INCLUDED_GR_PROBE_DENSITY_B_IMPL_H +#define INCLUDED_GR_PROBE_DENSITY_B_IMPL_H + +#include <digital/probe_density_b.h> + +namespace gr { + namespace digital { + + class probe_density_b_impl : public probe_density_b + { + private: + double d_alpha; + double d_beta; + double d_density; + + public: + probe_density_b_impl(double alpha); + ~probe_density_b_impl(); + + /*! + * \brief Returns the current density value + */ + double density() const { return d_density; } + + /*! + * \brief Set the average filter constant + */ + void set_alpha(double alpha); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_PROBE_DENSITY_B_IMPL_H */ diff --git a/gr-digital/lib/probe_mpsk_snr_est_c_impl.cc b/gr-digital/lib/probe_mpsk_snr_est_c_impl.cc new file mode 100644 index 0000000000..fb71bdc110 --- /dev/null +++ b/gr-digital/lib/probe_mpsk_snr_est_c_impl.cc @@ -0,0 +1,157 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "probe_mpsk_snr_est_c_impl.h" +#include <gr_io_signature.h> +#include <cstdio> + +namespace gr { + namespace digital { + + probe_mpsk_snr_est_c::sptr + probe_mpsk_snr_est_c::make(snr_est_type_t type, + int msg_nsamples, + double alpha) + { + return gnuradio::get_initial_sptr + (new probe_mpsk_snr_est_c_impl(type, msg_nsamples, alpha)); + } + + probe_mpsk_snr_est_c_impl::probe_mpsk_snr_est_c_impl(snr_est_type_t type, + int msg_nsamples, + double alpha) + : gr_sync_block("probe_mpsk_snr_est_c", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(0, 0, 0)) + { + d_snr_est = NULL; + + d_type = type; + d_nsamples = msg_nsamples; + d_count = 0; + set_alpha(alpha); + + set_type(type); + + // at least 1 estimator has to look back + set_history(2); + + d_key = pmt::string_to_symbol("snr"); + } + + probe_mpsk_snr_est_c_impl::~probe_mpsk_snr_est_c_impl() + { + if(d_snr_est) + delete d_snr_est; + } + + int + probe_mpsk_snr_est_c_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]; + return d_snr_est->update(noutput_items, in); + } + + double + probe_mpsk_snr_est_c_impl::snr() + { + if(d_snr_est) + return d_snr_est->snr(); + else + throw std::runtime_error("probe_mpsk_snr_est_c_impl:: No SNR estimator defined.\n"); + } + + snr_est_type_t + probe_mpsk_snr_est_c_impl::type() const + { + return d_type; + } + + int + probe_mpsk_snr_est_c_impl::msg_nsample() const + { + return d_nsamples; + } + + double + probe_mpsk_snr_est_c_impl::alpha() const + { + return d_alpha; + } + + void + probe_mpsk_snr_est_c_impl::set_type(snr_est_type_t t) + { + d_type = t; + + if(d_snr_est) + delete d_snr_est; + + switch (d_type) { + case(SNR_EST_SIMPLE): + d_snr_est = new mpsk_snr_est_simple(d_alpha); + break; + case(SNR_EST_SKEW): + d_snr_est = new mpsk_snr_est_skew(d_alpha); + break; + case(SNR_EST_M2M4): + d_snr_est = new mpsk_snr_est_m2m4(d_alpha); + break; + case(SNR_EST_SVR): + d_snr_est = new mpsk_snr_est_svr(d_alpha); + break; + default: + throw std::invalid_argument("probe_mpsk_snr_est_c_impl: unknown type specified.\n"); + } + } + + void + probe_mpsk_snr_est_c_impl::set_msg_nsample(int n) + { + if(n > 0) { + d_nsamples = n; + d_count = 0; // reset state + } + else + throw std::invalid_argument("probe_mpsk_snr_est_c_impl: msg_nsamples can't be <= 0\n"); + } + + void + probe_mpsk_snr_est_c_impl::set_alpha(double alpha) + { + if((alpha >= 0) && (alpha <= 1.0)) { + d_alpha = alpha; + if(d_snr_est) + d_snr_est->set_alpha(d_alpha); + } + else + throw std::invalid_argument("probe_mpsk_snr_est_c_impl: alpha must be in [0,1]\n"); + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/probe_mpsk_snr_est_c_impl.h b/gr-digital/lib/probe_mpsk_snr_est_c_impl.h new file mode 100644 index 0000000000..90da85d21b --- /dev/null +++ b/gr-digital/lib/probe_mpsk_snr_est_c_impl.h @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * Copyright 2011,2012 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. + */ + +#ifndef INCLUDED_DIGITAL_PROBE_MPSK_SNR_EST_C_IMPL_H +#define INCLUDED_DIGITAL_PROBE_MPSK_SNR_EST_C_IMPL_H + +#include <digital/probe_mpsk_snr_est_c.h> + +namespace gr { + namespace digital { + + class probe_mpsk_snr_est_c_impl : public probe_mpsk_snr_est_c + { + private: + snr_est_type_t d_type; + int d_nsamples, d_count; + double d_alpha; + mpsk_snr_est *d_snr_est; + + //d_key is the message name, 'snr' + pmt::pmt_t d_key; + + public: + probe_mpsk_snr_est_c_impl(snr_est_type_t type, + int msg_nsamples=10000, + double alpha=0.001); + + ~probe_mpsk_snr_est_c_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + //! Return the estimated signal-to-noise ratio in decibels + double snr(); + + //! Return the type of estimator in use + snr_est_type_t type() const; + + //! Return how many samples between SNR messages + int msg_nsample() const; + + //! Get the running-average coefficient + double alpha() const; + + //! Set type of estimator to use + void set_type(snr_est_type_t t); + + //! Set the number of samples between SNR messages + void set_msg_nsample(int n); + + //! Set the running-average coefficient + void set_alpha(double alpha); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_DIGITAL_PROBE_MPSK_SNR_EST_C_IMPL_H */ diff --git a/gr-digital/lib/scrambler_bb_impl.cc b/gr-digital/lib/scrambler_bb_impl.cc new file mode 100644 index 0000000000..d656fe2430 --- /dev/null +++ b/gr-digital/lib/scrambler_bb_impl.cc @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "scrambler_bb_impl.h" +#include <gr_io_signature.h> + +namespace gr { + namespace digital { + + scrambler_bb::sptr + scrambler_bb::make(int mask, int seed, int len) + { + return gnuradio::get_initial_sptr + (new scrambler_bb_impl(mask, seed, len)); + } + + scrambler_bb_impl::scrambler_bb_impl(int mask, int seed, int len) + : gr_sync_block("scrambler_bb", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_lfsr(mask, seed, len) + { + } + + scrambler_bb_impl::~scrambler_bb_impl() + { + } + + int + scrambler_bb_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + for(int i = 0; i < noutput_items; i++) { + out[i] = d_lfsr.next_bit_scramble(in[i]); + } + + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/scrambler_bb_impl.h b/gr-digital/lib/scrambler_bb_impl.h new file mode 100644 index 0000000000..8525e7ef5c --- /dev/null +++ b/gr-digital/lib/scrambler_bb_impl.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2012 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. + */ + +#ifndef INCLUDED_GR_SCRAMBLER_BB_IMPL_H +#define INCLUDED_GR_SCRAMBLER_BB_IMPL_H + +#include <digital/scrambler_bb.h> +#include <gr_sync_block.h> +#include <digital/lfsr.h> + +namespace gr { + namespace digital { + + class scrambler_bb_impl : public scrambler_bb + { + private: + digital::lfsr d_lfsr; + + public: + scrambler_bb_impl(int mask, int seed, int len); + ~scrambler_bb_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_SCRAMBLER_BB_IMPL_H */ diff --git a/gr-digital/lib/simple_correlator_impl.cc b/gr-digital/lib/simple_correlator_impl.cc new file mode 100644 index 0000000000..6b35b4cf0d --- /dev/null +++ b/gr-digital/lib/simple_correlator_impl.cc @@ -0,0 +1,237 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "simple_correlator_impl.h" +#include <digital/simple_framer_sync.h> +#include <gr_io_signature.h> +#include <blocks/count_bits.h> +#include <assert.h> +#include <stdexcept> +#include <string.h> +#include <cstdio> + +namespace gr { + namespace digital { + + static const int THRESHOLD = 3; + + simple_correlator::sptr + simple_correlator::make(int payload_bytesize) + { + return gnuradio::get_initial_sptr + (new simple_correlator_impl(payload_bytesize)); + } + + simple_correlator_impl::simple_correlator_impl(int payload_bytesize) + : gr_block("simple_correlator", + gr_make_io_signature(1, 1, sizeof(float)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_payload_bytesize(payload_bytesize), + d_state(ST_LOOKING), d_osi(0), + d_bblen((payload_bytesize + GRSF_PAYLOAD_OVERHEAD) * GRSF_BITS_PER_BYTE), + d_bitbuf(new unsigned char[d_bblen]), + d_pktbuf(new unsigned char[d_bblen/GRSF_BITS_PER_BYTE]), + d_bbi(0) + { + d_avbi = 0; + d_accum = 0.0; + d_avg = 0.0; + for(int i = 0; i < AVG_PERIOD; i++) + d_avgbuf[i] = 0.0; + +#ifdef DEBUG_SIMPLE_CORRELATOR + d_debug_fp = fopen("corr.log", "w"); +#endif + enter_looking(); + } + + simple_correlator_impl::~simple_correlator_impl() + { +#ifdef DEBUG_SIMPLE_CORRELATOR + fclose(d_debug_fp); +#endif + delete [] d_bitbuf; + delete [] d_pktbuf; + } + + void + simple_correlator_impl::enter_looking() + { + fflush(stdout); + // fprintf(stderr, ">>> enter_looking\n"); + d_state = ST_LOOKING; + for(int i = 0; i < OVERSAMPLE; i++) + d_shift_reg[i] = 0; + d_osi = 0; + + d_avbi = 0; + d_avg = d_avg * 0.5; + d_accum = 0; + for(int i = 0; i < AVG_PERIOD; i++) + d_avgbuf[i] = 0.0; + } + + void + simple_correlator_impl::enter_under_threshold() + { + fflush(stdout); + // fprintf(stderr, ">>> enter_under_threshold\n"); + d_state = ST_UNDER_THRESHOLD; + d_transition_osi = d_osi; + } + + void + simple_correlator_impl::enter_locked() + { + d_state = ST_LOCKED; + int delta = sub_index(d_osi, d_transition_osi); + d_center_osi = add_index(d_transition_osi, delta/2); + //d_center_osi = add_index(d_center_osi, 3); // FIXME + d_bbi = 0; + fflush(stdout); + // fprintf(stderr, ">>> enter_locked d_center_osi = %d\n", d_center_osi); + + d_avg = std::max(-1.0, std::min(1.0, d_accum * (1.0/AVG_PERIOD))); + // fprintf(stderr, ">>> enter_locked d_avg = %g\n", d_avg); + } + + static void + packit(unsigned char *pktbuf, const unsigned char *bitbuf, int bitcount) + { + for(int i = 0; i < bitcount; i += 8) { + int t = bitbuf[i+0] & 0x1; + t = (t << 1) | (bitbuf[i+1] & 0x1); + t = (t << 1) | (bitbuf[i+2] & 0x1); + t = (t << 1) | (bitbuf[i+3] & 0x1); + t = (t << 1) | (bitbuf[i+4] & 0x1); + t = (t << 1) | (bitbuf[i+5] & 0x1); + t = (t << 1) | (bitbuf[i+6] & 0x1); + t = (t << 1) | (bitbuf[i+7] & 0x1); + *pktbuf++ = t; + } + } + + void + simple_correlator_impl::update_avg(float x) + { + d_accum -= d_avgbuf[d_avbi]; + d_avgbuf[d_avbi] = x; + d_accum += x; + d_avbi = (d_avbi + 1) & (AVG_PERIOD-1); + } + + int + simple_correlator_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 float *in = (const float*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + int n = 0; + int nin = ninput_items[0]; + int decision; + int hamming_dist; + +#ifdef DEBUG_SIMPLE_CORRELATOR + struct debug_data { + float raw_data; + float sampled; + float enter_locked; + } debug_data; +#endif + + while(n < nin) { + +#ifdef DEBUG_SIMPLE_CORRELATOR + debug_data.raw_data = in[n]; + debug_data.sampled = 0.0; + debug_data.enter_locked = 0.0; +#endif + + switch(d_state) { + case ST_LOCKED: + if(d_osi == d_center_osi) { + +#ifdef DEBUG_SIMPLE_CORRELATOR + debug_data.sampled = 1.0; +#endif + decision = slice(in[n]); + + d_bitbuf[d_bbi] = decision; + d_bbi++; + if(d_bbi >= d_bblen) { + // printf("got whole packet\n"); + packit(d_pktbuf, d_bitbuf, d_bbi); + //printf("seqno %3d\n", d_pktbuf[0]); + memcpy(out, &d_pktbuf[GRSF_PAYLOAD_OVERHEAD], d_payload_bytesize); + enter_looking(); + consume_each(n + 1); + return d_payload_bytesize; + } + } + break; + + case ST_LOOKING: + case ST_UNDER_THRESHOLD: + update_avg(in[n]); + decision = slice(in[n]); + d_shift_reg[d_osi] = (d_shift_reg[d_osi] << 1) | decision; + + hamming_dist = gr::blocks::count_bits64(d_shift_reg[d_osi] ^ GRSF_SYNC); + // printf("%2d %d\n", hamming_dist, d_osi); + + if(d_state == ST_LOOKING && hamming_dist <= THRESHOLD) { + // We're seeing a good PN code, remember location + enter_under_threshold(); + } + else if(d_state == ST_UNDER_THRESHOLD && hamming_dist > THRESHOLD) { + // no longer seeing good PN code, compute center of goodness + enter_locked(); +#ifdef DEBUG_SIMPLE_CORRELATOR + debug_data.enter_locked = 1.0; +#endif + } + break; + default: + assert(0); + } + +#ifdef DEBUG_SIMPLE_CORRELATOR + fwrite(&debug_data, sizeof(debug_data), 1, d_debug_fp); +#endif + + d_osi = add_index(d_osi, 1); + n++; + } + + consume_each(n); + return 0; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/simple_correlator_impl.h b/gr-digital/lib/simple_correlator_impl.h new file mode 100644 index 0000000000..fe324131fd --- /dev/null +++ b/gr-digital/lib/simple_correlator_impl.h @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,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. + */ + +#ifndef INCLUDED_GR_SIMPLE_CORRELATOR_IMPL_H +#define INCLUDED_GR_SIMPLE_CORRELATOR_IMPL_H + +#include <digital/simple_correlator.h> + +//#define DEBUG_SIMPLE_CORRELATOR + +namespace gr { + namespace digital { + + class simple_correlator_impl : public simple_correlator + { + private: + static const int OVERSAMPLE = 8; + enum state_t { ST_LOOKING, ST_UNDER_THRESHOLD, ST_LOCKED }; + + int d_payload_bytesize; + state_t d_state; + unsigned int d_osi; // over sample index [0,OVERSAMPLE-1] + unsigned int d_transition_osi; // first index where Hamming dist < thresh + unsigned int d_center_osi; // center of bit + unsigned long long int d_shift_reg[OVERSAMPLE]; + int d_bblen; // length of bitbuf + unsigned char *d_bitbuf; // demodulated bits + unsigned char *d_pktbuf; // temp packet buf + int d_bbi; // bitbuf index + + static const int AVG_PERIOD = 512; // must be power of 2 (for freq offset correction) + int d_avbi; + float d_avgbuf[AVG_PERIOD]; + float d_avg; + float d_accum; + +#ifdef DEBUG_SIMPLE_CORRELATOR + FILE *d_debug_fp; // binary log file +#endif + + inline int slice (float x) + { + return x >= d_avg ? 1 : 0; + } + + void update_avg(float x); + + void enter_locked (); + void enter_under_threshold (); + void enter_looking (); + + static int add_index (int a, int b) + { + int t = a + b; + if(t >= OVERSAMPLE) + t -= OVERSAMPLE; + assert(t >= 0 && t < OVERSAMPLE); + return t; + } + + static int sub_index (int a, int b) + { + int t = a - b; + if(t < 0) + t += OVERSAMPLE; + assert(t >= 0 && t < OVERSAMPLE); + return t; + } + + public: + simple_correlator_impl(int payload_bytesize); + ~simple_correlator_impl(); + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_SIMPLE_CORRELATOR_IMPL_H */ diff --git a/gr-digital/lib/simple_framer_impl.cc b/gr-digital/lib/simple_framer_impl.cc new file mode 100644 index 0000000000..ff7e3ab614 --- /dev/null +++ b/gr-digital/lib/simple_framer_impl.cc @@ -0,0 +1,110 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2010,2012 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "simple_framer_impl.h" +#include <digital/simple_framer_sync.h> +#include <gr_io_signature.h> +#include <assert.h> +#include <string> + +namespace gr { + namespace digital { + + simple_framer::sptr + simple_framer::make(int payload_bytesize) + { + return gnuradio::get_initial_sptr + (new simple_framer_impl(payload_bytesize)); + } + + simple_framer_impl::simple_framer_impl(int payload_bytesize) + : gr_block("simple_framer", + gr_make_io_signature(1, 1, sizeof(unsigned char)), + gr_make_io_signature(1, 1, sizeof(unsigned char))), + d_seqno (0), d_payload_bytesize (payload_bytesize), + d_input_block_size (payload_bytesize), + d_output_block_size (payload_bytesize + GRSF_OVERHEAD) + { + set_output_multiple(d_output_block_size); + } + + simple_framer_impl::~simple_framer_impl() + { + } + + void + simple_framer_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + assert(noutput_items % d_output_block_size == 0); + + int nblocks = noutput_items / d_output_block_size; + int input_required = nblocks * d_input_block_size; + + unsigned ninputs = ninput_items_required.size(); + for(unsigned int i = 0; i < ninputs; i++) + ninput_items_required[i] = input_required; + } + + int + simple_framer_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 unsigned char *in = (const unsigned char*)input_items[0]; + unsigned char *out = (unsigned char*)output_items[0]; + + int n = 0; + int nblocks = 0; + + memset(out, 0x55, noutput_items); + + while(n < noutput_items) { + out[0] = (GRSF_SYNC >> 56) & 0xff; + out[1] = (GRSF_SYNC >> 48) & 0xff; + out[2] = (GRSF_SYNC >> 40) & 0xff; + out[3] = (GRSF_SYNC >> 32) & 0xff; + out[4] = (GRSF_SYNC >> 24) & 0xff; + out[5] = (GRSF_SYNC >> 16) & 0xff; + out[6] = (GRSF_SYNC >> 8) & 0xff; + out[7] = (GRSF_SYNC >> 0) & 0xff; + out[8] = d_seqno++; + + memcpy(&out[9], in, d_input_block_size); + in += d_input_block_size; + out += d_output_block_size; + n += d_output_block_size; + nblocks++; + } + + assert(n == noutput_items); + + consume_each(nblocks * d_input_block_size); + return n; + } + + } /* namespace digital */ +} /* namespace gr */ diff --git a/gr-digital/lib/simple_framer_impl.h b/gr-digital/lib/simple_framer_impl.h new file mode 100644 index 0000000000..fe967eb26a --- /dev/null +++ b/gr-digital/lib/simple_framer_impl.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2012 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. + */ + +#ifndef INCLUDED_GR_SIMPLE_FRAMER_IMPL_H +#define INCLUDED_GR_SIMPLE_FRAMER_IMPL_H + +#include <digital/simple_framer.h> + +namespace gr { + namespace digital { + + class simple_framer_impl : public simple_framer + { + private: + int d_seqno; + int d_payload_bytesize; + int d_input_block_size; // bytes + int d_output_block_size; // bytes + + public: + simple_framer_impl(int payload_bytesize); + ~simple_framer_impl(); + + 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 digital */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_SIMPLE_FRAMER_IMPL_H */ |