From a663f5b481679d8a352c668825cee92f548f3fcc Mon Sep 17 00:00:00 2001 From: trondeau Date: Sun, 10 Jun 2007 18:16:11 +0000 Subject: [PATCH] Merging OFDM features branch r5661:5759 into trunk. OFDM works over the air with BPSK and QPSK modulations on subcarriers. Passes make distcheck. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@5761 221aa14e-8319-0410-a670-987f0aec2ac5 --- gnuradio-core/src/lib/general/Makefile.am | 12 + gnuradio-core/src/lib/general/general.i | 8 + gnuradio-core/src/lib/general/gr_delay.cc | 2 +- .../src/lib/general/gr_ofdm_bpsk_mapper.cc | 73 ++--- .../src/lib/general/gr_ofdm_bpsk_mapper.h | 31 +-- .../src/lib/general/gr_ofdm_bpsk_mapper.i | 13 +- .../src/lib/general/gr_ofdm_correlator.cc | 38 ++- .../src/lib/general/gr_ofdm_correlator.h | 12 +- .../src/lib/general/gr_ofdm_correlator.i | 6 +- .../src/lib/general/gr_ofdm_frame_sink.cc | 80 ++++-- .../src/lib/general/gr_ofdm_frame_sink.h | 40 +-- .../src/lib/general/gr_ofdm_frame_sink.i | 8 +- .../lib/general/gr_ofdm_insert_preamble.cc | 186 +++++++++++++ .../src/lib/general/gr_ofdm_insert_preamble.h | 102 +++++++ .../src/lib/general/gr_ofdm_insert_preamble.i | 35 +++ .../src/lib/general/gr_ofdm_qam_mapper.cc | 249 ++++++++++++++++++ .../src/lib/general/gr_ofdm_qam_mapper.h | 84 ++++++ .../src/lib/general/gr_ofdm_qam_mapper.i | 46 ++++ .../src/lib/general/gr_ofdm_qpsk_mapper.cc | 141 ++++++++++ .../src/lib/general/gr_ofdm_qpsk_mapper.h | 76 ++++++ .../src/lib/general/gr_ofdm_qpsk_mapper.i | 44 ++++ .../src/lib/general/gr_ofdm_sampler.cc | 4 +- .../src/lib/general/gr_regenerate_bb.cc | 74 ++++++ .../src/lib/general/gr_regenerate_bb.h | 59 +++++ .../src/lib/general/gr_regenerate_bb.i | 31 +++ gnuradio-core/src/lib/swig/gnuradio.i | 10 +- .../src/python/gnuradio/blksimpl/Makefile.am | 7 +- .../blksimpl/{ofdm_pkt.py => ofdm.py} | 151 +++++++---- .../python/gnuradio/blksimpl/ofdm_receiver.py | 19 +- .../gnuradio/blksimpl/ofdm_sync_fixed.py | 41 +++ .../{ofdm_sync.py => ofdm_sync_ml.py} | 76 +++--- .../python/gnuradio/blksimpl/ofdm_sync_pn.py | 135 ++++++++++ .../gnuradio/blksimpl/ofdm_sync_pnac.py | 126 +++++++++ .../src/python/gnuradio/gr/Makefile.am | 1 + .../gnuradio/gr/qa_ofdm_insert_preamble.py | 179 +++++++++++++ .../src/python/gnuradio/ofdm_packet_utils.py | 19 +- .../src/python/gnuradio/packet_utils.py | 4 +- .../python/ofdm/benchmark_ofdm.py | 16 +- .../python/ofdm/benchmark_ofdm_rx.py | 32 ++- .../python/ofdm/benchmark_ofdm_tx.py | 30 +-- gnuradio-examples/python/ofdm/ofdm_sync_pn.m | 21 ++ gnuradio-examples/python/ofdm/plot_ofdm.m | 65 +++++ gnuradio-examples/python/ofdm/receive_path.py | 14 +- .../python/ofdm/transmit_path.py | 17 +- 44 files changed, 2111 insertions(+), 306 deletions(-) create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.cc create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.h create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.i create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.cc create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.h create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.i create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.h create mode 100644 gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.i create mode 100644 gnuradio-core/src/lib/general/gr_regenerate_bb.cc create mode 100644 gnuradio-core/src/lib/general/gr_regenerate_bb.h create mode 100644 gnuradio-core/src/lib/general/gr_regenerate_bb.i rename gnuradio-core/src/python/gnuradio/blksimpl/{ofdm_pkt.py => ofdm.py} (65%) create mode 100644 gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py rename gnuradio-core/src/python/gnuradio/blksimpl/{ofdm_sync.py => ofdm_sync_ml.py} (71%) create mode 100644 gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py create mode 100644 gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py create mode 100755 gnuradio-core/src/python/gnuradio/gr/qa_ofdm_insert_preamble.py create mode 100644 gnuradio-examples/python/ofdm/ofdm_sync_pn.m create mode 100755 gnuradio-examples/python/ofdm/plot_ofdm.m diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index d774baa1..35aac0a2 100644 --- a/gnuradio-core/src/lib/general/Makefile.am +++ b/gnuradio-core/src/lib/general/Makefile.am @@ -102,7 +102,10 @@ libgeneral_la_SOURCES = \ gr_ofdm_mapper_bcv.cc \ gr_ofdm_bpsk_demapper.cc \ gr_ofdm_bpsk_mapper.cc \ + gr_ofdm_qpsk_mapper.cc \ + gr_ofdm_qam_mapper.cc \ gr_ofdm_frame_sink.cc \ + gr_ofdm_insert_preamble.cc \ gr_ofdm_sampler.cc \ gr_pa_2x2_phase_combiner.cc \ gr_packet_sink.cc \ @@ -121,6 +124,7 @@ libgeneral_la_SOURCES = \ gr_pwr_squelch_ff.cc \ gr_quadrature_demod_cf.cc \ gr_random.cc \ + gr_regenerate_bb.cc \ gr_remez.cc \ gr_reverse.cc \ gr_rms_cf.cc \ @@ -240,8 +244,11 @@ grinclude_HEADERS = \ gr_ofdm_demapper_vcb.h \ gr_ofdm_mapper_bcv.h \ gr_ofdm_bpsk_mapper.h \ + gr_ofdm_qpsk_mapper.h \ + gr_ofdm_qam_mapper.h \ gr_ofdm_bpsk_demapper.h \ gr_ofdm_frame_sink.h \ + gr_ofdm_insert_preamble.h \ gr_ofdm_sampler.h \ gr_pa_2x2_phase_combiner.h \ gr_packet_sink.h \ @@ -260,6 +267,7 @@ grinclude_HEADERS = \ gr_pwr_squelch_ff.h \ gr_quadrature_demod_cf.h \ gr_random.h \ + gr_regenerate_bb.h \ gr_remez.h \ gr_reverse.h \ gr_rms_cf.h \ @@ -381,7 +389,10 @@ swiginclude_HEADERS = \ gr_ofdm_mapper_bcv.i \ gr_ofdm_bpsk_demapper.i \ gr_ofdm_bpsk_mapper.i \ + gr_ofdm_qpsk_mapper.i \ + gr_ofdm_qam_mapper.i \ gr_ofdm_frame_sink.i \ + gr_ofdm_insert_preamble.i \ gr_ofdm_sampler.i \ gr_pa_2x2_phase_combiner.i \ gr_packet_sink.i \ @@ -399,6 +410,7 @@ swiginclude_HEADERS = \ gr_pwr_squelch_cc.i \ gr_pwr_squelch_ff.i \ gr_quadrature_demod_cf.i \ + gr_regenerate_bb.i \ gr_remez.i \ gr_rms_cf.i \ gr_rms_ff.i \ diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index 1fdb4239..b362d24d 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -97,8 +97,12 @@ #include #include #include +#include +#include #include +#include #include +#include #include #include #include @@ -200,8 +204,12 @@ %include "gr_ofdm_cyclic_prefixer.i" %include "gr_ofdm_bpsk_demapper.i" %include "gr_ofdm_bpsk_mapper.i" +%include "gr_ofdm_qpsk_mapper.i" +%include "gr_ofdm_qam_mapper.i" %include "gr_ofdm_frame_sink.i" +%include "gr_ofdm_insert_preamble.i" %include "gr_ofdm_sampler.i" +%include "gr_regenerate_bb.i" %include "gr_costas_loop_cc.i" %include "gr_pa_2x2_phase_combiner.i" %include "gr_kludge_copy.i" diff --git a/gnuradio-core/src/lib/general/gr_delay.cc b/gnuradio-core/src/lib/general/gr_delay.cc index 89ab3ce0..73b61a9a 100644 --- a/gnuradio-core/src/lib/general/gr_delay.cc +++ b/gnuradio-core/src/lib/general/gr_delay.cc @@ -52,7 +52,7 @@ gr_delay::work (int noutput_items, const char *iptr; char *optr; - for(int i = 0; i < input_items.size(); i++) { + for(size_t i = 0; i < input_items.size(); i++) { iptr = (const char *) input_items[i]; optr = (char *) output_items[i]; diff --git a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc index f0b52c32..5b463122 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc @@ -26,23 +26,18 @@ #include #include -#include +#include gr_ofdm_bpsk_mapper_sptr gr_make_ofdm_bpsk_mapper (unsigned int msgq_limit, - unsigned int occupied_carriers, unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2) + unsigned int occupied_carriers, unsigned int fft_length) { - return gr_ofdm_bpsk_mapper_sptr (new gr_ofdm_bpsk_mapper (msgq_limit, occupied_carriers, fft_length, - known_symbol1, known_symbol2)); + return gr_ofdm_bpsk_mapper_sptr (new gr_ofdm_bpsk_mapper (msgq_limit, occupied_carriers, fft_length)); } // Consumes 1 packet and produces as many OFDM symbols of fft_length to hold the full packet gr_ofdm_bpsk_mapper::gr_ofdm_bpsk_mapper (unsigned int msgq_limit, - unsigned int occupied_carriers, unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2) + unsigned int occupied_carriers, unsigned int fft_length) : gr_sync_block ("ofdm_bpsk_mapper", gr_make_io_signature (0, 0, 0), gr_make_io_signature2 (1, 2, sizeof(gr_complex)*fft_length, sizeof(char))), @@ -50,20 +45,18 @@ gr_ofdm_bpsk_mapper::gr_ofdm_bpsk_mapper (unsigned int msgq_limit, d_occupied_carriers(occupied_carriers), d_fft_length(fft_length), d_bit_offset(0), - d_header_sent(0), - d_known_symbol1(known_symbol1), - d_known_symbol2(known_symbol2) + d_pending_flag(0) { - assert(d_occupied_carriers <= d_fft_length); - assert(d_occupied_carriers == d_known_symbol1.size()); - assert(d_occupied_carriers == d_known_symbol2.size()); + if (!(d_occupied_carriers <= d_fft_length)) + throw std::invalid_argument("gr_ofdm_bpsk_mapper: occupied carriers must be <= fft_length"); } gr_ofdm_bpsk_mapper::~gr_ofdm_bpsk_mapper(void) { } -float randombit() +static float +randombit() { int r = rand()&1; return (float)(-1 + 2*r); @@ -90,47 +83,25 @@ gr_ofdm_bpsk_mapper::work(int noutput_items, d_msg = d_msgq->delete_head(); // block, waiting for a message d_msg_offset = 0; d_bit_offset = 0; - d_header_sent = 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; + return -1; // We're done; no more messages coming. } } - if(output_items.size() == 2) { - char *sig = (char *)output_items[1]; - if(d_header_sent == 1) { - sig[0] = 1; - } - else { - sig[0] = 0; - } - } + 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)); - if(d_header_sent == 0) { - for(i=0; i < d_occupied_carriers; i++) { - out[i+zeros_on_left] = d_known_symbol1[i]; - } - d_header_sent++; - - return 1; - } - - if(d_header_sent == 1) { - for(i=0; i < d_occupied_carriers; i++) { - out[i+zeros_on_left] = d_known_symbol2[i]; - } - d_header_sent++; - - return 1; - } - i = 0; while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { unsigned char bit = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; @@ -150,14 +121,16 @@ gr_ofdm_bpsk_mapper::work(int noutput_items, i++; } - if (d_msg->type() == 1) // type == 1 sets EOF + if (d_msg->type() == 1) // type == 1 sets EOF d_eof = true; - d_msg.reset(); // finished packet, free message - + d_msg.reset(); // finished packet, free message assert(d_bit_offset == 0); - return 1; // produced one symbol } - + + if (out_flag) + out_flag[0] = d_pending_flag; + d_pending_flag = 0; + return 1; // produced symbol } diff --git a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.h b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.h index 41b2f5be..da78ca47 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.h +++ b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006 Free Software Foundation, Inc. + * Copyright 2006,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,19 +27,16 @@ #include #include #include -#include class gr_ofdm_bpsk_mapper; typedef boost::shared_ptr gr_ofdm_bpsk_mapper_sptr; gr_ofdm_bpsk_mapper_sptr gr_make_ofdm_bpsk_mapper (unsigned msgq_limit, - unsigned occupied_carriers, unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2); + unsigned occupied_carriers, unsigned int fft_length); /*! - * \brief take a stream of bytes in and map to a vector of complex + * \brief take a message in and map to a vector of complex * constellation points suitable for IFFT input to be used in an ofdm * modulator. Simple BPSK version. */ @@ -47,28 +44,22 @@ gr_make_ofdm_bpsk_mapper (unsigned msgq_limit, class gr_ofdm_bpsk_mapper : public gr_sync_block { friend gr_ofdm_bpsk_mapper_sptr - gr_make_ofdm_bpsk_mapper (unsigned msgq_limit, - unsigned occupied_carriers, unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2); - + gr_make_ofdm_bpsk_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); protected: gr_ofdm_bpsk_mapper (unsigned msgq_limit, - unsigned occupied_carriers, unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2); - + unsigned occupied_carriers, unsigned int fft_length); + private: 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; - unsigned int d_header_sent; - std::vector d_known_symbol1, d_known_symbol2; + unsigned int d_occupied_carriers; + unsigned int d_fft_length; + unsigned int d_bit_offset; + int d_pending_flag; public: ~gr_ofdm_bpsk_mapper(void); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.i b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.i index d0094062..2af37d64 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.i +++ b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2006,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,25 +20,20 @@ * Boston, MA 02110-1301, USA. */ -#include - GR_SWIG_BLOCK_MAGIC(gr,ofdm_bpsk_mapper); gr_ofdm_bpsk_mapper_sptr gr_make_ofdm_bpsk_mapper (unsigned int msgq_limit, unsigned int bits_per_symbol, - unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2); + unsigned int fft_length); + class gr_ofdm_bpsk_mapper : public gr_sync_block { protected: gr_ofdm_bpsk_mapper (unsigned int msgq_limit, unsigned int bits_per_symbol, - unsigned int fft_length, - const std::vector &known_symbol1, - const std::vector &known_symbol2); + unsigned int fft_length); public: gr_msg_queue_sptr msgq(); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc b/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc index 3973b837..4eb6626a 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc @@ -30,28 +30,32 @@ #define VERBOSE 0 #define M_TWOPI (2*M_PI) +#define MAX_NUM_SYMBOLS 1000 gr_ofdm_correlator_sptr gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2) + const std::vector &known_symbol2, + unsigned int max_fft_shift_len) { return gr_ofdm_correlator_sptr (new gr_ofdm_correlator (occupied_carriers, fft_length, cplen, - known_symbol1, known_symbol2)); + known_symbol1, known_symbol2, + max_fft_shift_len)); } gr_ofdm_correlator::gr_ofdm_correlator (unsigned occupied_carriers, unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2) + const std::vector &known_symbol2, + unsigned int max_fft_shift_len) : gr_block ("ofdm_correlator", gr_make_io_signature (1, 1, sizeof(gr_complex)*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(5), + d_freq_shift_len(max_fft_shift_len), d_known_symbol1(known_symbol1), d_known_symbol2(known_symbol2), d_coarse_freq(0), @@ -62,16 +66,24 @@ gr_ofdm_correlator::gr_ofdm_correlator (unsigned occupied_carriers, unsigned int std::vector::iterator i1, i2; - int i = 0; + unsigned int i = 0, j = 0; gr_complex one(1.0, 0.0); for(i1 = d_known_symbol1.begin(), i2 = d_known_symbol2.begin(); i1 != d_known_symbol1.end(); i1++, i2++) { d_diff_corr_factor[i] = one / ((*i1) * conj(*i2)); i++; } + + 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); + } + } } gr_ofdm_correlator::~gr_ofdm_correlator(void) { + delete [] d_phase_lut; } void @@ -87,7 +99,12 @@ gr_ofdm_correlator::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 gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count); + + assert(d_freq_shift_len + freq_delta >= 0); + assert(symbol_count <= MAX_NUM_SYMBOLS); + + return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count]; } bool @@ -132,14 +149,17 @@ gr_ofdm_correlator::correlate(const gr_complex *previous, const gr_complex *curr d_snr_est = 10*log10(fabs(h_sqrd.real()/h_sqrd.imag())); } +#if VERBOSE printf("CORR: Found, bin %d\tSNR Est %f dB\tcorr power fraction %f\n", search_delta, d_snr_est, h_sqrd.real()/power); +#endif + // search_delta,10*log10(h_sqrd.real()/fabs(h_sqrd.imag())),h_sqrd.real()/power); break; } else { if(search_delta <= 0) - search_delta = (-search_delta) + 1; + search_delta = (-search_delta) + 2; else search_delta = -search_delta; } @@ -161,10 +181,6 @@ gr_ofdm_correlator::calculate_equalizer(const gr_complex *previous, const gr_com d_hestimate[i] = 0.5F * (d_known_symbol1[i] / previous[i+zeros_on_left+d_coarse_freq] + d_known_symbol2[i] / (coarse_freq_comp(d_coarse_freq,1)* current[i+zeros_on_left+d_coarse_freq])); - -#if VERBOSE - fprintf(stderr, "%f %f ", d_hestimate[i].real(), d_hestimate[i].imag()); -#endif } #if VERBOSE fprintf(stderr, "\n"); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.h b/gnuradio-core/src/lib/general/gr_ofdm_correlator.h index 44a6847a..36aa1f0b 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.h +++ b/gnuradio-core/src/lib/general/gr_ofdm_correlator.h @@ -34,7 +34,8 @@ gr_ofdm_correlator_sptr gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2); + const std::vector &known_symbol2, + unsigned int max_fft_shift_len=4); /*! * \brief take a vector of complex constellation points in from an FFT @@ -65,18 +66,21 @@ class gr_ofdm_correlator : public gr_block * start of a frame after known_symbol1 (usually a BPSK PN sequence). * Both of these start symbols are differentially correlated to compensate * for phase changes between symbols. + * \param max_fft_shift_len Set's the maximum distance you can look between bins for correlation */ friend gr_ofdm_correlator_sptr gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2); + const std::vector &known_symbol2, + unsigned int max_fft_shift_len); protected: gr_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2); + const std::vector &known_symbol2, + unsigned int max_fft_shift_len); private: unsigned char slicer(gr_complex x); @@ -96,6 +100,8 @@ class gr_ofdm_correlator : public gr_block 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: diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.i b/gnuradio-core/src/lib/general/gr_ofdm_correlator.i index 40f9f83f..700faaa0 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.i +++ b/gnuradio-core/src/lib/general/gr_ofdm_correlator.i @@ -29,7 +29,8 @@ gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2); + const std::vector &known_symbol2, + unsigned int max_fft_shift_len=4); class gr_ofdm_correlator : public gr_sync_decimator { @@ -38,7 +39,8 @@ class gr_ofdm_correlator : public gr_sync_decimator unsigned int fft_length, unsigned int cplen, const std::vector &known_symbol1, - const std::vector &known_symbol2); + const std::vector &known_symbol2, + unsigned int max_fft_shift_len); public: float snr() { return d_snr_est; } diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc index acaf1258..c04aca3d 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc @@ -79,6 +79,14 @@ unsigned char gr_ofdm_frame_sink::bpsk_slicer(gr_complex x) return (unsigned char)(x.real() > 0 ? 1 : 0); } +unsigned char gr_ofdm_frame_sink::qpsk_slicer(gr_complex x) +{ + unsigned char i = (x.real() > 0 ? 1 : 0); + unsigned char q = (x.imag() > 0 ? 1 : 0); + + return (q << 1) | i; +} + unsigned int gr_ofdm_frame_sink::bpsk_demapper(const gr_complex *in, unsigned char *out) { @@ -101,23 +109,56 @@ unsigned int gr_ofdm_frame_sink::bpsk_demapper(const gr_complex *in, return bytes_produced; } +unsigned int gr_ofdm_frame_sink::qpsk_demapper(const gr_complex *in, + unsigned char *out) +{ + unsigned int i=0, bytes_produced=0; + while(i < d_occupied_carriers) { + + while((d_byte_offset < 8) && (i < d_occupied_carriers)) { + //fprintf(stderr, "%f+j%f\n", in[i].real(), in[i].imag()); + d_partial_byte |= qpsk_slicer(in[i++]) << (d_byte_offset); + d_byte_offset += 2; + } + + if(d_byte_offset == 8) { + out[bytes_produced++] = d_partial_byte; + d_byte_offset = 0; + d_partial_byte = 0; + } + } + + return bytes_produced; +} gr_ofdm_frame_sink_sptr -gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers) +gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers, + const std::string &mod) { - return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(target_queue, occupied_carriers)); + return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(target_queue, occupied_carriers, mod)); } -gr_ofdm_frame_sink::gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers) +gr_ofdm_frame_sink::gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers, + const std::string &mod) : gr_sync_block ("ofdm_frame_sink", gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)), gr_make_io_signature (0, 0, 0)), d_target_queue(target_queue), d_occupied_carriers(occupied_carriers), d_byte_offset(0), d_partial_byte(0) { - d_bytes_out = new unsigned char[(int)ceil(d_occupied_carriers/8.0)]; + d_bytes_out = new unsigned char[(int)ceil(d_occupied_carriers/4.0)]; + + if(mod == "qpsk") { + d_demapper = &gr_ofdm_frame_sink::qpsk_demapper; + } + else if(mod == "bpsk") { + d_demapper = &gr_ofdm_frame_sink::bpsk_demapper; + } + else { + throw std::invalid_argument("Modulation type must be BPSK or QPSK."); + } enter_search(); } @@ -134,15 +175,15 @@ gr_ofdm_frame_sink::work (int noutput_items, { const gr_complex *in = (const gr_complex *) input_items[0]; const char *sig = (const char *) input_items[1]; - int count_tones=0, count_items=0; unsigned int j = 0; unsigned int bytes=0; if (VERBOSE) fprintf(stderr,">>> Entering state machine\n"); - bytes = bpsk_demapper(&in[0], d_bytes_out); - + //bytes = bpsk_demapper(&in[0], d_bytes_out); + bytes = (this->*d_demapper)(&in[0], d_bytes_out); + switch(d_state) { case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt @@ -155,12 +196,13 @@ gr_ofdm_frame_sink::work (int noutput_items, break; case STATE_HAVE_SYNC: - if(sig[0]) - printf("ERROR -- Found SYNC in HAVE_SYNC\n"); - if (VERBOSE) + 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); @@ -174,10 +216,9 @@ gr_ofdm_frame_sink::work (int noutput_items, // we have a full header, check to see if it has been received properly if (header_ok()){ enter_have_header(); - printf("\nPacket Length: %d\n", d_packetlen); - //for(int k=0; k < d_packetlen; k++) - // printf("%02x", d_packet[k]); - //printf("\n"); + + 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++]; @@ -201,10 +242,11 @@ gr_ofdm_frame_sink::work (int noutput_items, break; case STATE_HAVE_HEADER: - if(sig[0]) - printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen); - if (VERBOSE) - fprintf(stderr,"Packet Build\n"); + 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) { diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h index d77c7674..8f38abb0 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005,2006 Free Software Foundation, Inc. + * Copyright 2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -30,30 +30,22 @@ class gr_ofdm_frame_sink; typedef boost::shared_ptr gr_ofdm_frame_sink_sptr; gr_ofdm_frame_sink_sptr -gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_tones); +gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_tones, + const std::string &mod); /*! - * \brief Given a stream of bits and access_code flags, assemble packets. - * \ingroup sink - * - * input: stream of bytes from gr_correlate_access_code_bb - * output: none. Pushes assembled packet into target queue - * - * The framer expects a fixed length header of 2 16-bit shorts - * containing the payload length, followed by the payload. If the - * 2 16-bit shorts are not identical, this packet is ignored. Better - * algs are welcome. - * - * The input data consists of bytes that have two bits used. - * Bit 0, the LSB, contains the data bit. - * Bit 1 if set, indicates that the corresponding bit is the - * the first bit of the packet. That is, this bit is the first - * one after the access code. + * \brief Takes an OFDM symbol in, demaps it into bits of 0's and 1's, packs + * them into packets, and sends to to a message queue sink. + + * NOTE: The mod input parameter simply chooses a pre-defined demapper/slicer. Eventually, + * we want to be able to pass in a reference to an object to do the demapping and slicing + * for a given modulation type. */ class gr_ofdm_frame_sink : public gr_sync_block { friend gr_ofdm_frame_sink_sptr - gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_tones); + gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_tones, + const std::string &mod); private: enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER}; @@ -78,7 +70,8 @@ class gr_ofdm_frame_sink : public gr_sync_block int d_packetlen_cnt; // how many so far protected: - gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones); + gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones, + const std::string &mod); void enter_search(); void enter_have_sync(); @@ -94,6 +87,13 @@ class gr_ofdm_frame_sink : public gr_sync_block unsigned int bpsk_demapper(const gr_complex *in, unsigned char *out); + unsigned char qpsk_slicer(gr_complex x); + unsigned int qpsk_demapper(const gr_complex *in, + unsigned char *out); + + // pointer to mod-specific demapper + unsigned int (gr_ofdm_frame_sink::*d_demapper)(const gr_complex *in, unsigned char *out); + public: ~gr_ofdm_frame_sink(); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i index b05c8b79..32a0ec9f 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,12 +23,14 @@ GR_SWIG_BLOCK_MAGIC(gr,ofdm_frame_sink); gr_ofdm_frame_sink_sptr -gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones); +gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones, + const std::string &mod); class gr_ofdm_frame_sink : public gr_sync_block { protected: - gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones); + gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones, + const std::string &mod); public: ~gr_ofdm_frame_sink(); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.cc b/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.cc new file mode 100644 index 00000000..41b23fcd --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.cc @@ -0,0 +1,186 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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 +#endif + +#include +#include +#include +#include + +gr_ofdm_insert_preamble_sptr +gr_make_ofdm_insert_preamble(int fft_length, + const std::vector > &preamble) +{ + return gr_ofdm_insert_preamble_sptr(new gr_ofdm_insert_preamble(fft_length, + preamble)); +} + +gr_ofdm_insert_preamble::gr_ofdm_insert_preamble + (int fft_length, + const std::vector > &preamble) + : gr_block("ofdm_insert_preamble", + gr_make_io_signature2(2, 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("gr_ofdm_insert_preamble: invalid length for preamble symbol"); + } + + enter_idle(); +} + + +gr_ofdm_insert_preamble::~gr_ofdm_insert_preamble() +{ +} + +int +gr_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 = std::min(ninput_items_v[0], ninput_items_v[1]); + const gr_complex *in_sym = (const gr_complex *) input_items[0]; + const unsigned char *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[ni] & 0x1) // this is first symbol of new payload + enter_preamble(); + else + ni++; // eat one input symbol + break; + + case ST_PREAMBLE: + assert(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[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 << "gr_ofdm_insert_preamble: (can't happen) invalid state, resetting\n"; + enter_idle(); + } + } + + consume_each(ni); + return no; +} + +void +gr_ofdm_insert_preamble::enter_idle() +{ + d_state = ST_IDLE; + d_nsymbols_output = 0; + d_pending_flag = 0; +} + +void +gr_ofdm_insert_preamble::enter_preamble() +{ + d_state = ST_PREAMBLE; + d_nsymbols_output = 0; + d_pending_flag = 1; +} + +void +gr_ofdm_insert_preamble::enter_first_payload() +{ + d_state = ST_FIRST_PAYLOAD; +} + +void +gr_ofdm_insert_preamble::enter_payload() +{ + d_state = ST_PAYLOAD; +} diff --git a/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.h b/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.h new file mode 100644 index 00000000..48622b06 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.h @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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_GR_OFDM_INSERT_PREAMBLE_H +#define INCLUDED_GR_OFDM_INSERT_PREAMBLE_H + +#include +#include + +class gr_ofdm_insert_preamble; +typedef boost::shared_ptr gr_ofdm_insert_preamble_sptr; + +gr_ofdm_insert_preamble_sptr +gr_make_ofdm_insert_preamble(int fft_length, + const std::vector > &preamble); + +/*! + * \brief insert "pre-modulated" preamble symbols before each payload. + * + *
+ * input 1: stream of vectors of gr_complex [fft_length]
+ *          These are the modulated symbols of the payload.
+ *
+ * input 2: stream of char.  The LSB indicates whether the corresponding
+ *          symbol on input 1 is the first symbol of the payload or not.
+ *          It's a 1 if the corresponding symbol is the first symbol,
+ *          otherwise 0.
+ *
+ * N.B., this implies that there must be at least 1 symbol in the payload.
+ *
+ *
+ * output 1: stream of vectors of gr_complex [fft_length]
+ *           These include the preamble symbols and the payload symbols.
+ *
+ * output 2: stream of char.  The LSB indicates whether the corresponding
+ *           symbol on input 1 is the first symbol of a packet (i.e., the
+ *           first symbol of the preamble.)   It's a 1 if the corresponding
+ *           symbol is the first symbol, otherwise 0.
+ * 
+ * + * \param fft_length length of each symbol in samples. + * \param preamble vector of symbols that represent the pre-modulated preamble. + */ + +class gr_ofdm_insert_preamble : public gr_block +{ + friend gr_ofdm_insert_preamble_sptr + gr_make_ofdm_insert_preamble(int fft_length, + const std::vector > &preamble); + +protected: + gr_ofdm_insert_preamble(int fft_length, + const std::vector > &preamble); + +private: + enum state_t { + ST_IDLE, + ST_PREAMBLE, + ST_FIRST_PAYLOAD, + ST_PAYLOAD + }; + + int d_fft_length; + const std::vector > d_preamble; + state_t d_state; + int d_nsymbols_output; + int d_pending_flag; + + void enter_idle(); + void enter_preamble(); + void enter_first_payload(); + void enter_payload(); + + +public: + ~gr_ofdm_insert_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); +}; + +#endif /* INCLUDED_GR_OFDM_INSERT_PREAMBLE_H */ diff --git a/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.i b/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.i new file mode 100644 index 00000000..183e91b0 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_insert_preamble.i @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,ofdm_insert_preamble); + +gr_ofdm_insert_preamble_sptr +gr_make_ofdm_insert_preamble(int fft_length, + const std::vector > &preamble); + + +class gr_ofdm_insert_preamble : public gr_block +{ + protected: + gr_ofdm_insert_preamble(int fft_length, + const std::vector > &preamble); +}; diff --git a/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.cc b/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.cc new file mode 100644 index 00000000..8e774fe7 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.cc @@ -0,0 +1,249 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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 +#include +#include + +gr_ofdm_qam_mapper_sptr +gr_make_ofdm_qam_mapper (unsigned int msgq_limit, + unsigned int occupied_carriers, unsigned int fft_length, + int m) +{ + return gr_ofdm_qam_mapper_sptr (new gr_ofdm_qam_mapper (msgq_limit, occupied_carriers, fft_length, m)); +} + +// Consumes 1 packet and produces as many OFDM symbols of fft_length to hold the full packet +gr_ofdm_qam_mapper::gr_ofdm_qam_mapper (unsigned int msgq_limit, + unsigned int occupied_carriers, unsigned int fft_length, + int m) + : gr_sync_block ("ofdm_qam_mapper", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature2 (1, 2, sizeof(gr_complex)*fft_length, sizeof(char))), + 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_mod_order(m) +{ + if (!(d_occupied_carriers <= d_fft_length)) + throw std::invalid_argument("gr_ofdm_qam_mapper: occupied carriers must be <= fft_length"); + + bool ok = false; + if(m == 2) { + ok = true; + } + if(m == 4) { + ok = true; + } + if(m == 16) { + ok = true; + } + if(m == 64) { + ok = true; + } + if(m == 256) { + ok = true; + } + + if(!ok) + throw std::invalid_argument("Order M must be [2, 4, 16, 64, 256]"); + + make_constellation(); +} + +gr_ofdm_qam_mapper::~gr_ofdm_qam_mapper(void) +{ +} + +void gr_ofdm_qam_mapper::make_constellation() +{ + int i = 0, j = 0, ii = 0, jj = 0; + // number of bits/symbol (log2(M)) + int k = (int)(log10(d_mod_order) / log10(2.0)); + + int a, b; + float re, im; + float coeff = 1; + std::vector bits_i, bits_q; + + int rr = 0; + int ss = 0; + int ll = bits_i.size(); + + for(i=0; i < d_mod_order; i++) { + a = (i & (0x01 << (k-1))) >> (k-1); + b = (i & (0x01 << (k-2))) >> (k-2); + for(j=2; j < k; j+=2) { + bits_i.push_back( (i & (0x01 << (k-j-1))) >> (k-j-1)); + bits_q.push_back( (i & (0x01 << (k-(j+1)-1))) >> (k-(j+1)-1)); + } + + ss = 0; + ll = bits_i.size(); + for(ii = 0; ii < ll; ii++) { + rr = 0; + for(jj = 0; jj < (ll-ii); jj++) { + rr = abs(bits_i[jj] - rr); + } + ss += rr * pow(2.0, ii+1.0); + } + re = (2.0*a-1.0)*(ss+1.0); + + ss = 0; + ll = bits_q.size(); + for(ii = 0; ii < ll; ii++) { + rr = 0; + for(jj = 0; jj < (ll-ii); jj++) { + rr = abs(bits_q[jj] - rr); + } + ss += rr*pow(2.0, ii+1.0); + } + im = (2.0*b-1.0)*(ss+1.0); + + a = std::max(re, im); + if(a > coeff) { + coeff = a; + } + d_constellation_map.push_back(gr_complex(re, im)); + } + + d_constellation_map[0] = gr_complex(-3, -3); + d_constellation_map[1] = gr_complex(-3, -1); + d_constellation_map[2] = gr_complex(-3, 1); + d_constellation_map[3] = gr_complex(-3, 3); + d_constellation_map[4] = gr_complex(-1, -3); + d_constellation_map[5] = gr_complex(-1, -1); + d_constellation_map[6] = gr_complex(-1, 1); + d_constellation_map[7] = gr_complex(-1, 3); + d_constellation_map[8] = gr_complex(1, -3); + d_constellation_map[9] = gr_complex(1, -1); + d_constellation_map[10] = gr_complex(1, 1); + d_constellation_map[11] = gr_complex(1, 3); + d_constellation_map[12] = gr_complex(3, -3); + d_constellation_map[13] = gr_complex(3, -1); + d_constellation_map[14] = gr_complex(3, 1); + d_constellation_map[15] = gr_complex(3, 3); + + coeff = sqrt(31.0)/2.0; + for(i = 0; i < d_constellation_map.size(); i++) { + d_constellation_map[i] /= coeff; + printf("const[%d]: %f + j%f\n", i, d_constellation_map[i].real(), d_constellation_map[i].imag()); + } +} + +static float +randombit() +{ + int r = rand()&1; + return (float)(-1 + 2*r); +} + +int +gr_ofdm_qam_mapper::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; + unsigned int unoccupied_carriers = d_fft_length - d_occupied_carriers; + unsigned int zeros_on_left = (unsigned)ceil(unoccupied_carriers/2.0); + + //printf("OFDM QAM 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; + while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { + unsigned char bit0 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; + d_bit_offset++; + + unsigned char bit1 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; + d_bit_offset++; + + unsigned char bit2 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; + d_bit_offset++; + + unsigned char bit3 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; + d_bit_offset++; + + unsigned char bit = (bit0 << 3) | (bit1 << 2) | (bit2 << 1) | (bit3 << 0); + + out[i + zeros_on_left] = d_constellation_map[bit]; + i++; + 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()) { + while(i < d_occupied_carriers) { // finish filling out the symbol + out[i + zeros_on_left] = d_constellation_map[rand() & 0x0F]; + 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/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.h b/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.h new file mode 100644 index 00000000..2b2a8e39 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.h @@ -0,0 +1,84 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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_OFDM_QAM_MAPPER_H +#define INCLUDED_GR_OFDM_QAM_MAPPER_H + + +#include +#include +#include + +class gr_ofdm_qam_mapper; +typedef boost::shared_ptr gr_ofdm_qam_mapper_sptr; + +gr_ofdm_qam_mapper_sptr +gr_make_ofdm_qam_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length, + int m=4); + +/*! + * \brief take a message in and map to a vector of complex + * constellation points suitable for IFFT input to be used in an ofdm + * modulator. Simple QAM version. + */ + +class gr_ofdm_qam_mapper : public gr_sync_block +{ + friend gr_ofdm_qam_mapper_sptr + gr_make_ofdm_qam_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length, + int m); + protected: + gr_ofdm_qam_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length, + int m); + + private: + 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; + + int d_mod_order; + std::vector d_constellation_map; + + void make_constellation(); + + public: + ~gr_ofdm_qam_mapper(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); + +}; + + +#endif diff --git a/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.i b/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.i new file mode 100644 index 00000000..84fd0851 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_qam_mapper.i @@ -0,0 +1,46 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,ofdm_qam_mapper); + +gr_ofdm_qam_mapper_sptr +gr_make_ofdm_qam_mapper (unsigned int msgq_limit, + unsigned int bits_per_symbol, + unsigned int fft_length, + int m=16); + + +class gr_ofdm_qam_mapper : public gr_sync_block +{ + protected: + gr_ofdm_qam_mapper (unsigned int msgq_limit, + unsigned int bits_per_symbol, + unsigned int fft_length, + int m); + + public: + gr_msg_queue_sptr msgq(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; diff --git a/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc new file mode 100644 index 00000000..cad14c70 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc @@ -0,0 +1,141 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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 +#include +#include + +gr_ofdm_qpsk_mapper_sptr +gr_make_ofdm_qpsk_mapper (unsigned int msgq_limit, + unsigned int occupied_carriers, unsigned int fft_length) +{ + return gr_ofdm_qpsk_mapper_sptr (new gr_ofdm_qpsk_mapper (msgq_limit, occupied_carriers, fft_length)); +} + +// Consumes 1 packet and produces as many OFDM symbols of fft_length to hold the full packet +gr_ofdm_qpsk_mapper::gr_ofdm_qpsk_mapper (unsigned int msgq_limit, + unsigned int occupied_carriers, unsigned int fft_length) + : gr_sync_block ("ofdm_qpsk_mapper", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature2 (1, 2, sizeof(gr_complex)*fft_length, sizeof(char))), + 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) +{ + if (!(d_occupied_carriers <= d_fft_length)) + throw std::invalid_argument("gr_ofdm_qpsk_mapper: occupied carriers must be <= fft_length"); +} + +gr_ofdm_qpsk_mapper::~gr_ofdm_qpsk_mapper(void) +{ +} + +static gr_complex +randombit() +{ + int r1 = rand()&1; + int r2 = rand()&1; + return gr_complex((0.707)*(-1 + 2*r1),(0.707)*(-1 + 2*r2)); +} + +int +gr_ofdm_qpsk_mapper::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; + unsigned int unoccupied_carriers = d_fft_length - d_occupied_carriers; + unsigned int zeros_on_left = (unsigned)ceil(unoccupied_carriers/2.0); + + //printf("OFDM QPSK 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; + while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { + unsigned char bit0 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; + d_bit_offset++; + + unsigned char bit1 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; + d_bit_offset++; + + out[i + zeros_on_left] = gr_complex((0.707)*(-1+2*(bit0)), (0.707)*(-1+2*(bit1)) ); + i++; + 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()) { + while(i < d_occupied_carriers) { // finish filling out the symbol + out[i + zeros_on_left] = randombit(); + 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/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.h b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.h new file mode 100644 index 00000000..93bd8f98 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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_OFDM_QPSK_MAPPER_H +#define INCLUDED_GR_OFDM_QPSK_MAPPER_H + + +#include +#include +#include + +class gr_ofdm_qpsk_mapper; +typedef boost::shared_ptr gr_ofdm_qpsk_mapper_sptr; + +gr_ofdm_qpsk_mapper_sptr +gr_make_ofdm_qpsk_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); + +/*! + * \brief take a message in and map to a vector of complex + * constellation points suitable for IFFT input to be used in an ofdm + * modulator. Simple QPSK version. + */ + +class gr_ofdm_qpsk_mapper : public gr_sync_block +{ + friend gr_ofdm_qpsk_mapper_sptr + gr_make_ofdm_qpsk_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); + protected: + gr_ofdm_qpsk_mapper (unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); + + private: + 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; + + public: + ~gr_ofdm_qpsk_mapper(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); + +}; + + +#endif diff --git a/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.i b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.i new file mode 100644 index 00000000..5f19f08f --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.i @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,ofdm_qpsk_mapper); + +gr_ofdm_qpsk_mapper_sptr +gr_make_ofdm_qpsk_mapper (unsigned int msgq_limit, + unsigned int bits_per_symbol, + unsigned int fft_length); + + +class gr_ofdm_qpsk_mapper : public gr_sync_block +{ + protected: + gr_ofdm_qpsk_mapper (unsigned int msgq_limit, + unsigned int bits_per_symbol, + unsigned int fft_length); + + public: + gr_msg_queue_sptr msgq(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; diff --git a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc index 5f5a91fd..1ca738a2 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc @@ -67,7 +67,7 @@ gr_ofdm_sampler::general_work (int noutput_items, int found=0; - unsigned int i=d_fft_length-1; + int i=d_fft_length-1; while(!found && i= 0); - for(unsigned int j=i-d_fft_length+1;j<=i;j++) + for(int j=i-d_fft_length+1;j<=i;j++) *optr++ = iptr[j]; consume_each(i-d_fft_length+2); //printf("OFDM Sampler found: ninput_items: %d/%d noutput_items: %d consumed: %d found: %d\n", diff --git a/gnuradio-core/src/lib/general/gr_regenerate_bb.cc b/gnuradio-core/src/lib/general/gr_regenerate_bb.cc new file mode 100644 index 00000000..6b0535e1 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_regenerate_bb.cc @@ -0,0 +1,74 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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 +#include + +gr_regenerate_bb_sptr +gr_make_regenerate_bb (int period, unsigned int max_regen) +{ + return gr_regenerate_bb_sptr (new gr_regenerate_bb (period, max_regen)); +} + +gr_regenerate_bb::gr_regenerate_bb (int period, unsigned int max_regen) + : gr_sync_block ("regenerate_bb", + gr_make_io_signature (1, 1, sizeof (char)), + gr_make_io_signature (1, 1, sizeof (char))), + d_period(period), + d_max_regen(max_regen), + d_regen_count(0) +{ +} + +int +gr_regenerate_bb::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const char *iptr = (const char *) input_items[0]; + char *optr = (char *) output_items[0]; + + for (int i = 0; i < noutput_items; i++){ + optr[i] = 0; + + if(iptr[i] == 1) { + d_countdown = d_period; + optr[i] = 1; + d_regen_count = 0; + } + + if(d_regen_count <= d_max_regen) { + d_countdown--; + + if(d_countdown == 0) { + optr[i] = 1; + d_countdown = d_period; + d_regen_count++; + } + } + } + return noutput_items; +} diff --git a/gnuradio-core/src/lib/general/gr_regenerate_bb.h b/gnuradio-core/src/lib/general/gr_regenerate_bb.h new file mode 100644 index 00000000..446e658a --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_regenerate_bb.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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_REGENERATE_BB_H +#define INCLUDED_GR_REGENERATE_BB_H + +#include + +class gr_regenerate_bb; +typedef boost::shared_ptr gr_regenerate_bb_sptr; + +gr_regenerate_bb_sptr gr_make_regenerate_bb (int period, unsigned int max_regen=500); + +/*! + * \brief Detect the peak of a signal + * \ingroup block + * + * If a peak is detected, this block outputs a 1 repeated every period samples + * until reset by detection of another 1 on the input + */ +class gr_regenerate_bb : public gr_sync_block +{ + friend gr_regenerate_bb_sptr gr_make_regenerate_bb (int period, unsigned int max_regen); + + gr_regenerate_bb (int period, unsigned int max_regen); + + private: + int d_period; + int d_countdown; + unsigned int d_max_regen; + unsigned int d_regen_count; + + public: + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif diff --git a/gnuradio-core/src/lib/general/gr_regenerate_bb.i b/gnuradio-core/src/lib/general/gr_regenerate_bb.i new file mode 100644 index 00000000..6afd84d8 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_regenerate_bb.i @@ -0,0 +1,31 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,regenerate_bb) + +gr_regenerate_bb_sptr gr_make_regenerate_bb (int period, unsigned int max_regen=500); + +class gr_regenerate_bb : public gr_sync_block +{ + private: + gr_regenerate_bb (int period, unsigned int max_regen); +}; diff --git a/gnuradio-core/src/lib/swig/gnuradio.i b/gnuradio-core/src/lib/swig/gnuradio.i index 706ba8a6..a3e04223 100644 --- a/gnuradio-core/src/lib/swig/gnuradio.i +++ b/gnuradio-core/src/lib/swig/gnuradio.i @@ -59,7 +59,15 @@ namespace std { %template() vector; %template() vector; %template() vector; - %template() vector >; + + %template() vector< std::complex >; + %template() vector< std::vector< unsigned char > >; + %template() vector< std::vector< char > >; + %template() vector< std::vector< short > >; + %template() vector< std::vector< int > >; + %template() vector< std::vector< float > >; + %template() vector< std::vector< double > >; + %template() vector< std::vector< std::complex > >; }; //////////////////////////////////////////////////////////////////////// diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am index b8c80011..71598354 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am @@ -40,9 +40,12 @@ grblkspython_PYTHON = \ cpm.py \ nbfm_rx.py \ nbfm_tx.py \ - ofdm_pkt.py \ + ofdm.py \ ofdm_receiver.py \ - ofdm_sync.py \ + ofdm_sync_fixed.py \ + ofdm_sync_ml.py \ + ofdm_sync_pnac.py \ + ofdm_sync_pn.py \ pkt.py \ psk.py \ qam.py \ diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_pkt.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py similarity index 65% rename from gnuradio-core/src/python/gnuradio/blksimpl/ofdm_pkt.py rename to gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py index 9a98b374..74a674cb 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_pkt.py +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py @@ -1,6 +1,6 @@ # -# Copyright 2005,2006,2007 Free Software Foundation, Inc. +# Copyright 2006,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -21,7 +21,7 @@ # import math -from math import pi +from numpy import fft from gnuradio import gr, ofdm_packet_utils import gnuradio.gr.gr_threading as _threading @@ -32,10 +32,11 @@ from gnuradio.blksimpl.ofdm_receiver import ofdm_receiver # mod/demod with packets as i/o # ///////////////////////////////////////////////////////////////////////////// -class mod_ofdm_pkts(gr.hier_block): +class ofdm_mod(gr.hier_block): """ - Wrap an arbitrary digital modulator in our packet handling framework. - + Modulates an OFDM stream. Based on the options fft_length, occupied_tones, and + cp_length, this block creates OFDM symbols using a specified modulation option. + Send packets by calling send_pkt """ def __init__(self, fg, options, msgq_limit=2, pad_for_usrp=True): @@ -47,35 +48,62 @@ class mod_ofdm_pkts(gr.hier_block): @param fg: flow graph @type fg: flow graph + @param options: pass modulation options from higher layers (fft length, occupied tones, etc.) @param msgq_limit: maximum number of messages in message queue @type msgq_limit: int @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples - - See modulators for remaining parameters """ + self._pad_for_usrp = pad_for_usrp + self._modulation = options.modulation + self._fft_length = options.fft_length + self._occupied_tones = options.occupied_tones + self._cp_length = options.cp_length win = [] #[1 for i in range(self._fft_length)] - # hard-coded known symbol - ks1 = known_symbols_4512_1[0:options.occupied_tones] - #ks1 = known_symbols_4512_impulse[0:options.occupied_tones] - ks2 = known_symbols_4512_2[0:options.occupied_tones] - + # Use freq domain to get doubled-up known symbol for correlation in time domain + zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0)) + ksfreq = known_symbols_4512_3[0:self._occupied_tones] + for i in range(len(ksfreq)): + if((zeros_on_left + i) & 1): + ksfreq[i] = 0 + + # hard-coded known symbols + preambles = (ksfreq, + known_symbols_4512_1[0:self._occupied_tones], + known_symbols_4512_2[0:self._occupied_tones]) + + padded_preambles = list() + for pre in preambles: + padded = self._fft_length*[0,] + padded[zeros_on_left : zeros_on_left + self._occupied_tones] = pre + padded_preambles.append(padded) + symbol_length = options.fft_length + options.cp_length - # accepts messages from the outside world - self._pkt_input = gr.ofdm_bpsk_mapper(msgq_limit, options.occupied_tones, options.fft_length, ks1, ks2) - self.ifft = gr.fft_vcc(options.fft_length, False, win, True) - self.cp_adder = gr.ofdm_cyclic_prefixer(options.fft_length, symbol_length) - self.scale = gr.multiply_const_cc(1.0 / math.sqrt(options.fft_length)) - - fg.connect(self._pkt_input, self.ifft, self.cp_adder, self.scale) - + # The next step will all us to pass a constellation into a generic mapper function instead + # of using these hard-coded versions + if self._modulation == "bpsk": + self._pkt_input = gr.ofdm_bpsk_mapper(msgq_limit, options.occupied_tones, options.fft_length) + elif self._modulation == "qpsk": + self._pkt_input = gr.ofdm_qpsk_mapper(msgq_limit, options.occupied_tones, options.fft_length) + else: + print "Modulation type not supported (must be \"bpsk\" or \"qpsk\"" + + self.preambles = gr.ofdm_insert_preamble(self._fft_length, padded_preambles) + self.ifft = gr.fft_vcc(self._fft_length, False, win, True) + self.cp_adder = gr.ofdm_cyclic_prefixer(self._fft_length, symbol_length) + self.scale = gr.multiply_const_cc(1.0 / math.sqrt(self._fft_length)) + + fg.connect((self._pkt_input, 0), (self.preambles, 0)) + fg.connect((self._pkt_input, 1), (self.preambles, 1)) + fg.connect(self.preambles, self.ifft, self.cp_adder, self.scale) + if options.verbose: self._print_verbage() - if 1: + if options.log: fg.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length, "ofdm_mapper_c.dat")) gr.hier_block.__init__(self, fg, None, self.scale) @@ -91,25 +119,18 @@ class mod_ofdm_pkts(gr.hier_block): msg = gr.message(1) # tell self._pkt_input we're not sending any more packets else: # print "original_payload =", string_to_hex_list(payload) - pkt = ofdm_packet_utils.make_packet(payload, - self.samples_per_symbol(), - self.bits_per_symbol(), - self._pad_for_usrp) + pkt = ofdm_packet_utils.make_packet(payload, 1, 1, self._pad_for_usrp) + #print "pkt =", string_to_hex_list(pkt) msg = gr.message_from_string(pkt) self._pkt_input.msgq().insert_tail(msg) - def samples_per_symbol(self): - return 2 - - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - def add_options(normal, expert): """ Adds OFDM-specific options to the Options Parser """ + normal.add_option("-m", "--modulation", type="string", default="bpsk", + help="set modulation type (bpsk or qpsk) [default=%default]") expert.add_option("", "--fft-length", type="intx", default=512, help="set the number of FFT bins [default=%default]") expert.add_option("", "--occupied-tones", type="intx", default=200, @@ -124,14 +145,17 @@ class mod_ofdm_pkts(gr.hier_block): Prints information about the OFDM modulator """ print "\nOFDM Modulator:" + print "Modulation Type: %s" % (self._modulation) print "FFT length: %3d" % (self._fft_length) print "Occupied Tones: %3d" % (self._occupied_tones) print "CP length: %3d" % (self._cp_length) -class demod_ofdm_pkts(gr.hier_block): +class ofdm_demod(gr.hier_block): """ - Wrap an arbitrary digital demodulator in our packet handling framework. + Demodulates a received OFDM stream. Based on the options fft_length, occupied_tones, and + cp_length, this block performs synchronization, FFT, and demodulation of incoming OFDM + symbols and passes packets up the a higher layer. The input is complex baseband. When packets are demodulated, they are passed to the app via the callback. @@ -146,38 +170,64 @@ class demod_ofdm_pkts(gr.hier_block): @param fg: flow graph @type fg: flow graph - @param demodulator: instance of demodulator class (gr_block or hier_block) - @type demodulator: complex baseband in + @param options: pass modulation options from higher layers (fft length, occupied tones, etc.) @param callback: function of two args: ok, payload @type callback: ok: bool; payload: string """ self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY - ks1 = known_symbols_4512_1[0:options.occupied_tones] - #ks1 = known_symbols_4512_impulse[0:options.occupied_tones] - ks2 = known_symbols_4512_2[0:options.occupied_tones] + self._modulation = options.modulation + self._fft_length = options.fft_length + self._occupied_tones = options.occupied_tones + self._cp_length = options.cp_length + self._snr = options.snr + + + # Use freq domain to get doubled-up known symbol for correlation in time domain + ksfreq = known_symbols_4512_3[0:self._occupied_tones] + for i in range(len(ksfreq)): + if(i&1): + ksfreq[i] = 0 + + zeros_on_left = int(math.ceil((self._fft_length - self._occupied_tones)/2.0)) + zeros_on_right = self._fft_length - self._occupied_tones - zeros_on_left + ks0 = zeros_on_left*[0.0,] + ks0.extend(ksfreq) + ks0.extend(zeros_on_right*[0.0,]) - symbol_length = options.fft_length + options.cp_length - self.ofdm_recv = ofdm_receiver(fg, options.fft_length, options.cp_length, - options.occupied_tones, options.snr, ks1, ks2) + ks0time = fft.ifft(ks0) + # ADD SCALING FACTOR + ks0time = ks0time.tolist() + + # hard-coded known symbols + preambles = (ks0time, + known_symbols_4512_1[0:self._occupied_tones], + known_symbols_4512_2[0:self._occupied_tones]) + + symbol_length = self._fft_length + self._cp_length + self.ofdm_recv = ofdm_receiver(fg, self._fft_length, self._cp_length, + self._occupied_tones, self._snr, preambles, + options.log) self.ofdm_demod = gr.ofdm_frame_sink(self._rcvd_pktq, - options.occupied_tones) + self._occupied_tones, + self._modulation) fg.connect((self.ofdm_recv, 0), (self.ofdm_demod, 0)) fg.connect((self.ofdm_recv, 1), (self.ofdm_demod, 1)) + if options.verbose: + self._print_verbage() + gr.hier_block.__init__(self, fg, self.ofdm_recv, None) self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback) - def bits_per_symbol(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM - def add_options(normal, expert): """ Adds OFDM-specific options to the Options Parser """ + normal.add_option("-m", "--modulation", type="string", default="bpsk", + help="set modulation type (bpsk or qpsk) [default=%default]") expert.add_option("", "--fft-length", type="intx", default=512, help="set the number of FFT bins [default=%default]") expert.add_option("", "--occupied-tones", type="intx", default=200, @@ -192,6 +242,7 @@ class demod_ofdm_pkts(gr.hier_block): Prints information about the OFDM demodulator """ print "\nOFDM Demodulator:" + print "Modulation Type: %s" % (self._modulation) print "FFT length: %3d" % (self._fft_length) print "Occupied Tones: %3d" % (self._occupied_tones) print "CP length: %3d" % (self._cp_length) @@ -215,15 +266,19 @@ class _queue_watcher_thread(_threading.Thread): if self.callback: self.callback(ok, payload) +# Generating known symbols with: +# i = [2*random.randint(0,1)-1 for i in range(4512)] + known_symbols_200_1 = [1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0] known_symbols_200_2 = [-1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, 1.0] - known_symbols_4512_1 = [-1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1] known_symbols_4512_2 = [1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1] known_symbols_4512_impulse = 4512*[1,] + +known_symbols_4512_3 = [-1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, 1, -1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, -1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, -1, -1, -1, 1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, 1, -1, 1, -1, -1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, 1, 1, -1, -1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, 1, 1, -1, 1, -1] diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py index e2f59328..22ec41f1 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py @@ -22,10 +22,12 @@ import math from gnuradio import gr -from gnuradio.blksimpl.ofdm_sync import ofdm_sync +from gnuradio.blksimpl.ofdm_sync_ml import ofdm_sync_ml +from gnuradio.blksimpl.ofdm_sync_pn import ofdm_sync_pn +from gnuradio.blksimpl.ofdm_sync_pnac import ofdm_sync_pnac class ofdm_receiver(gr.hier_block): - def __init__(self, fg, fft_length, cp_length, occupied_tones, snr, ks1, ks2): + def __init__(self, fg, fft_length, cp_length, occupied_tones, snr, ks, logging=False): self.fg = fg bw = (float(occupied_tones) / float(fft_length)) / 2.0 @@ -39,14 +41,21 @@ class ofdm_receiver(gr.hier_block): win = [1 for i in range(fft_length)] - self.ofdm_sync = ofdm_sync(fg, fft_length, cp_length, snr) + SYNC = "pn" + if SYNC == "ml": + self.ofdm_sync = ofdm_sync_ml(fg, fft_length, cp_length, snr, logging) + elif SYNC == "pn": + self.ofdm_sync = ofdm_sync_pn(fg, fft_length, cp_length, logging) + elif SYNC == "pnac": + self.ofdm_sync = ofdm_sync_pnac(fg, fft_length, cp_length, ks[0]) + self.fft_demod = gr.fft_vcc(fft_length, True, win, True) self.ofdm_corr = gr.ofdm_correlator(occupied_tones, fft_length, - cp_length, ks1, ks2) + cp_length, ks[1], ks[2]) self.fg.connect(self.chan_filt, self.ofdm_sync, self.fft_demod, self.ofdm_corr) - if 1: + if logging: self.fg.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "chan_filt_c.dat")) self.fg.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "fft_out_c.dat")) self.fg.connect(self.ofdm_corr, gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_corr_out_c.dat")) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py new file mode 100644 index 00000000..bd5f4b87 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# +# Copyright 2007 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 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import math +from gnuradio import gr + +class ofdm_sync_fixed(gr.hier_block): + def __init__(self, fg, fft_length, cp_length, snr): + self.fg = fg + + # Use a fixed trigger point instead of sync block + data = (fft_length+cp_len)*[0,] + data[(fft_length+cp_len)-1] = 1 + peak_trigger = gr.vector_source_b(data, True) + + self.fg.connect(peak_trigger, (self.sampler,1)) + + if 1: + self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, + "ofdm_sync_fixed-sampler_c.dat")) + + gr.hier_block.__init__(self, fg, (self.sampler,0), self.sampler) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py similarity index 71% rename from gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync.py rename to gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py index 271be93d..6944cb81 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync.py +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py @@ -23,10 +23,20 @@ import math from gnuradio import gr -class ofdm_sync(gr.hier_block): - def __init__(self, fg, fft_length, cp_length, snr): +class ofdm_sync_ml(gr.hier_block): + def __init__(self, fg, fft_length, cp_length, snr, logging): + ''' Maximum Likelihood OFDM synchronizer: + J. van de Beek, M. Sandell, and P. O. Borjesson, "ML Estimation + of Time and Frequency Offset in OFDM Systems," IEEE Trans. + Signal Processing, vol. 45, no. 7, pp. 1800-1805, 1997. + ''' + self.fg = fg + # FIXME: when converting to hier_block2's, the output signature + # should be the output of the divider (the normalized peaks) and + # the angle value out of the sample and hold block + self.input = gr.add_const_cc(0) SNR = 10.0**(snr/10.0) @@ -77,13 +87,12 @@ class ofdm_sync(gr.hier_block): self.fg.connect(self.moving_sum_filter,(self.diff,1)) #ML measurements input to sampler block and detect - nco_sensitivity = 1.0/fft_length + nco_sensitivity = -1.0/fft_length self.f2c = gr.float_to_complex() self.sampler = gr.ofdm_sampler(fft_length,symbol_length) self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005) self.sample_and_hold = gr.sample_and_hold_ff() self.nco = gr.frequency_modulator_fc(nco_sensitivity) - self.inv = gr.multiply_const_ff(-1) self.sigmix = gr.multiply_cc() # Mix the signal with an NCO controlled by the sync loop @@ -96,46 +105,31 @@ class ofdm_sync(gr.hier_block): # self.angle = epsilon self.fg.connect(self.diff, self.pk_detect) - use_dpll = 1 - fixed_timing = 0 - if fixed_timing: - # Use a fixed trigger point instead of sync block - peak_null = gr.null_sink(gr.sizeof_char) - data = 640*[0,] - data[639] = 1 - peak_trigger = gr.vector_source_b(data, True) - - self.fg.connect(self.pk_detect, peak_null) - self.fg.connect(peak_trigger, (self.sampler,1)) - self.fg.connect(peak_trigger, (self.sample_and_hold,1)) - else: + use_dpll = 1 + if use_dpll: self.dpll = gr.dpll_bb(float(symbol_length),0.01) - if use_dpll: - self.fg.connect(self.pk_detect, self.dpll) - self.fg.connect(self.dpll, (self.sampler,1)) - self.fg.connect(self.dpll, (self.sample_and_hold,1)) - else: - self.fg.connect(self.pk_detect, (self.sampler,1)) - self.fg.connect(self.pk_detect, (self.sample_and_hold,1)) + self.fg.connect(self.pk_detect, self.dpll) + self.fg.connect(self.dpll, (self.sampler,1)) + self.fg.connect(self.dpll, (self.sample_and_hold,1)) + else: + self.fg.connect(self.pk_detect, (self.sampler,1)) + self.fg.connect(self.pk_detect, (self.sample_and_hold,1)) self.fg.connect(self.angle, (self.sample_and_hold,0)) - self.fg.connect(self.sample_and_hold, self.inv, self.nco) - - if 1: - self.fg.connect(self.diff, gr.file_sink(gr.sizeof_float, "theta_f.dat")) - self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float, "epsilon_f.dat")) - if fixed_timing: - self.fg.connect(peak_trigger, gr.file_sink(gr.sizeof_char, "peaks_b.dat")) - else: - self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "peaks_b.dat")) - if use_dpll: - self.fg.connect(self.dpll, gr.file_sink(gr.sizeof_char, "dpll_b.dat")) - - self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "sigmix_c.dat")) - self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "sampler_c.dat")) - self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "sample_and_hold_f.dat")) - self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "nco_c.dat")) - self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "input_c.dat")) + self.fg.connect(self.sample_and_hold, self.nco) + + if logging: + self.fg.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat")) + self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat")) + self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat")) + if use_dpll: + self.fg.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat")) + + self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-sigmix_c.dat")) + self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_sync_ml-sampler_c.dat")) + self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat")) + self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-nco_c.dat")) + self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat")) gr.hier_block.__init__(self, fg, self.input, self.sampler) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py new file mode 100644 index 00000000..a49ff84f --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# Copyright 2007 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 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import math +from numpy import fft +from gnuradio import gr + +class ofdm_sync_pn(gr.hier_block): + def __init__(self, fg, fft_length, cp_length, logging=False): + ''' OFDM synchronization using PN Correlation: + T. M. Schmidl and D. C. Cox, "Robust Frequency and Timing + Synchonization for OFDM," IEEE Trans. Communications, vol. 45, + no. 12, 1997. + ''' + + self.fg = fg + + # FIXME: when converting to hier_block2's, the output signature + # should be the output of the divider (the normalized peaks) and + # the angle value out of the sample and hold block + + self.input = gr.add_const_cc(0) + + symbol_length = fft_length + cp_length + + # PN Sync + + # Create a delay line + self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2) + + # Correlation from ML Sync + self.conjg = gr.conjugate_cc(); + self.corr = gr.multiply_cc(); + + # Create a moving sum filter for the corr output + if 1: + moving_sum_taps = [1.0 for i in range(fft_length//2)] + self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps) + else: + moving_sum_taps = [complex(1.0,0.0) for i in range(fft_length//2)] + self.moving_sum_filter = gr.fft_filter_ccc(1,moving_sum_taps) + + # Create a moving sum filter for the input + self.inputmag2 = gr.complex_to_mag_squared() + movingsum2_taps = [1.0 for i in range(fft_length//2)] + + if 1: + self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps) + else: + self.inputmovingsum = gr.fft_filter_fff(1,movingsum2_taps) + + self.square = gr.multiply_ff() + self.normalize = gr.divide_ff() + + # Get magnitude (peaks) and angle (phase/freq error) + self.c2mag = gr.complex_to_mag_squared() + self.angle = gr.complex_to_arg() + + self.sample_and_hold = gr.sample_and_hold_ff() + + # Mix the signal with an NCO controlled by the sync loop + nco_sensitivity = -2.0/fft_length + self.nco = gr.frequency_modulator_fc(nco_sensitivity) + self.sigmix = gr.multiply_cc() + + #ML measurements input to sampler block and detect + self.sub1 = gr.add_const_ff(-1) + self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005) + self.regen = gr.regenerate_bb(symbol_length) + + self.sampler = gr.ofdm_sampler(fft_length,symbol_length) + + self.fg.connect(self.input, self.delay) + self.fg.connect(self.input, (self.corr,0)) + self.fg.connect(self.delay, self.conjg) + self.fg.connect(self.conjg, (self.corr,1)) + self.fg.connect(self.corr, self.moving_sum_filter) + self.fg.connect(self.moving_sum_filter, self.c2mag) + self.fg.connect(self.moving_sum_filter, self.angle) + self.fg.connect(self.angle, (self.sample_and_hold,0)) + self.fg.connect(self.sample_and_hold, self.nco) + + self.fg.connect(self.input, (self.sigmix,0)) + self.fg.connect(self.nco, (self.sigmix,1)) + self.fg.connect(self.sigmix, (self.sampler,0)) + + self.fg.connect(self.input, self.inputmag2, self.inputmovingsum) + self.fg.connect(self.inputmovingsum, (self.square,0)) + self.fg.connect(self.inputmovingsum, (self.square,1)) + self.fg.connect(self.square, (self.normalize,1)) + self.fg.connect(self.c2mag, (self.normalize,0)) + + # Create a moving sum filter for the corr output + matched_filter_taps = [1.0/cp_length for i in range(cp_length)] + self.matched_filter = gr.fir_filter_fff(1,matched_filter_taps) + self.fg.connect(self.normalize, self.matched_filter) + + self.fg.connect(self.matched_filter, self.sub1, self.pk_detect) + self.fg.connect(self.pk_detect, self.regen) + self.fg.connect(self.regen, (self.sampler,1)) + self.fg.connect(self.pk_detect, (self.sample_and_hold,1)) + + + if logging: + self.fg.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat")) + self.fg.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat")) + self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat")) + self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat")) + self.fg.connect(self.regen, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-regen_b.dat")) + self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-sigmix_c.dat")) + self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_sync_pn-sampler_c.dat")) + self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat")) + self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-nco_c.dat")) + self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat")) + + gr.hier_block.__init__(self, fg, self.input, self.sampler) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py new file mode 100644 index 00000000..833cee57 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +# +# Copyright 2007 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 2, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +import math +from numpy import fft +from gnuradio import gr + +class ofdm_sync_pnac(gr.hier_block): + def __init__(self, fg, fft_length, cp_length, ks): + self.fg = fg + + # FIXME: when converting to hier_block2's, the output signature + # should be the output of the divider (the normalized peaks) and + # the angle value out of the sample and hold block + + self.input = gr.add_const_cc(0) + + symbol_length = fft_length + cp_length + + # PN Sync + + # autocorrelate with the known symbol + ks = ks[0:fft_length//2] + ks.reverse() + self.crosscorr_filter = gr.fir_filter_ccc(1, ks) + self.fg.connect(self.crosscorr_filter, gr.file_sink(gr.sizeof_gr_complex, "crosscorr.dat")) + + # Create a delay line + self.delay = gr.delay(gr.sizeof_gr_complex, fft_length/2) + + # Correlation from ML Sync + self.conjg = gr.conjugate_cc(); + self.corr = gr.multiply_cc(); + + # Create a moving sum filter for the corr output + moving_sum_taps = [1.0 for i in range(fft_length//2)] + self.moving_sum_filter = gr.fir_filter_ccf(1,moving_sum_taps) + + # Create a moving sum filter for the input + self.inputmag2 = gr.complex_to_mag_squared() + movingsum2_taps = [1.0 for i in range(fft_length/2)] + self.inputmovingsum = gr.fir_filter_fff(1,movingsum2_taps) + self.square = gr.multiply_ff() + self.normalize = gr.divide_ff() + + # Get magnitude (peaks) and angle (phase/freq error) + self.c2mag = gr.complex_to_mag_squared() + self.angle = gr.complex_to_arg() + + self.sample_and_hold = gr.sample_and_hold_ff() + + # Mix the signal with an NCO controlled by the sync loop + nco_sensitivity = -1.0/fft_length + self.nco = gr.frequency_modulator_fc(nco_sensitivity) + self.sigmix = gr.multiply_cc() + + #ML measurements input to sampler block and detect + self.sub1 = gr.add_const_ff(-1) + self.pk_detect = gr.peak_detector_fb(0.2, 0.25, 30, 0.0005) + + self.sampler = gr.ofdm_sampler(fft_length,symbol_length) + + self.fg.connect(self.input, self.crosscorr_filter) + self.fg.connect(self.crosscorr_filter, self.delay) + self.fg.connect(self.crosscorr_filter, (self.corr,0)) + self.fg.connect(self.delay, self.conjg) + self.fg.connect(self.conjg, (self.corr,1)) + self.fg.connect(self.corr, self.moving_sum_filter) + self.fg.connect(self.moving_sum_filter, self.c2mag) + self.fg.connect(self.moving_sum_filter, self.angle) + self.fg.connect(self.angle, (self.sample_and_hold,0)) + self.fg.connect(self.sample_and_hold, self.nco) + + self.fg.connect(self.input, (self.sigmix,0)) + self.fg.connect(self.nco, (self.sigmix,1)) + self.fg.connect(self.sigmix, (self.sampler,0)) + + self.fg.connect(self.input, self.inputmag2, self.inputmovingsum) + self.fg.connect(self.inputmovingsum, (self.square,0)) + self.fg.connect(self.inputmovingsum, (self.square,1)) + self.fg.connect(self.square, (self.normalize,1)) + self.fg.connect(self.c2mag, (self.normalize,0)) + self.fg.connect(self.normalize, self.sub1, self.pk_detect) + + self.fg.connect(self.pk_detect, (self.sampler,1)) + self.fg.connect(self.pk_detect, (self.sample_and_hold,1)) + + + if 1: + self.fg.connect(self.normalize, gr.file_sink(gr.sizeof_float, + "ofdm_sync_pnac-theta_f.dat")) + self.fg.connect(self.angle, gr.file_sink(gr.sizeof_float, + "ofdm_sync_pnac-epsilon_f.dat")) + self.fg.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, + "ofdm_sync_pnac-peaks_b.dat")) + self.fg.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, + "ofdm_sync_pnac-sigmix_c.dat")) + self.fg.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, + "ofdm_sync_pnac-sampler_c.dat")) + self.fg.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, + "ofdm_sync_pnac-sample_and_hold_f.dat")) + self.fg.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, + "ofdm_sync_pnac-nco_c.dat")) + self.fg.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, + "ofdm_sync_pnac-input_c.dat")) + + gr.hier_block.__init__(self, fg, self.input, self.sampler) diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am index dc0e4a8a..92b3b666 100644 --- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am @@ -80,6 +80,7 @@ noinst_PYTHON = \ qa_mute.py \ qa_nlog10.py \ qa_noise.py \ + qa_ofdm_insert_preamble.py \ qa_packed_to_unpacked.py \ qa_pipe_fittings.py \ qa_pll_carriertracking.py \ diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_ofdm_insert_preamble.py b/gnuradio-core/src/python/gnuradio/gr/qa_ofdm_insert_preamble.py new file mode 100755 index 00000000..58edb829 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/qa_ofdm_insert_preamble.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python +# +# Copyright 2007 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 2, 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. +# + +from gnuradio import gr, gr_unittest +from pprint import pprint + +class testing (gr_unittest.TestCase): + + def setUp (self): + self.fg = gr.flow_graph () + + def tearDown (self): + self.fg = None + + def helper(self, v0, v1, fft_length, preamble): + fg = self.fg + src0 = gr.vector_source_c(v0) + src1 = gr.vector_source_b(v1) + + s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_length) + + # print "len(v) = %d" % (len(v)) + + op = gr.ofdm_insert_preamble(fft_length, preamble) + + v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_length) + dst0 = gr.vector_sink_c() + dst1 = gr.vector_sink_b() + + fg.connect(src0, s2v, (op, 0)) + fg.connect(src1, (op, 1)) + fg.connect((op, 0), v2s, dst0) + fg.connect((op, 1), dst1) + + fg.run() + r0 = dst0.data() + r0v = [] + for i in range(len(r0)//fft_length): + r0v.append(r0[i*fft_length:(i+1)*fft_length]) + + r1 = dst1.data() + self.assertEqual(len(r0v), len(r1)) + return (r1, r0v) + + def check_match(self, actual, expected_list): + lst = [] + map(lambda x: lst.append(x), expected_list) + self.assertEqual(actual, lst) + + + # ---------------------------------------------------------------- + + def test_000(self): + # no preamble, 1 symbol payloads + + preamble = () + fft_length = 8 + npayloads = 8 + v = [] + p = [] + for i in range(npayloads): + t = fft_length*[(i + i*1j)] + p.append(tuple(t)) + v += t + + p = tuple(p) + + r = self.helper(v, npayloads*[1], fft_length, preamble) + # pprint(r) + + self.assertEqual(r[0], tuple(npayloads*[1])) + self.check_match(r[1], (p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7])) + + + def test_001(self): + # 1 symbol preamble, 1 symbol payloads + preamble = ((100, 101, 102, 103, 104, 105, 106, 107),) + p0 = preamble[0] + fft_length = 8 + npayloads = 8 + v = [] + p = [] + for i in range(npayloads): + t = fft_length*[(i + i*1j)] + p.append(tuple(t)) + v += t + + + r = self.helper(v, npayloads*[1], fft_length, preamble) + + self.assertEqual(r[0], tuple(npayloads*[1, 0])) + self.check_match(r[1], (p0, p[0], + p0, p[1], + p0, p[2], + p0, p[3], + p0, p[4], + p0, p[5], + p0, p[6], + p0, p[7])) + + def test_002(self): + # 2 symbol preamble, 1 symbol payloads + preamble = ((100, 101, 102, 103, 104, 105, 106, 107), + (200, 201, 202, 203, 204, 205, 206, 207)) + p0 = preamble[0] + p1 = preamble[1] + + fft_length = 8 + npayloads = 8 + v = [] + p = [] + for i in range(npayloads): + t = fft_length*[(i + i*1j)] + p.append(tuple(t)) + v += t + + r = self.helper(v, npayloads*[1], fft_length, preamble) + + self.assertEqual(r[0], tuple(npayloads*[1, 0, 0])) + self.check_match(r[1], (p0, p1, p[0], + p0, p1, p[1], + p0, p1, p[2], + p0, p1, p[3], + p0, p1, p[4], + p0, p1, p[5], + p0, p1, p[6], + p0, p1, p[7])) + + + def xtest_003_preamble(self): + # 2 symbol preamble, 2 symbol payloads + preamble = ((100, 101, 102, 103, 104, 105, 106, 107), + (200, 201, 202, 203, 204, 205, 206, 207)) + p0 = preamble[0] + p1 = preamble[1] + + fft_length = 8 + npayloads = 8 + v = [] + p = [] + for i in range(npayloads * 2): + t = fft_length*[(i + i*1j)] + p.append(tuple(t)) + v += t + + r = self.helper(v, npayloads*[1, 0], fft_length, preamble) + + self.assertEqual(r[0], tuple(npayloads*[1, 0, 0, 0])) + self.check_match(r[1], (p0, p1, p[0], p[1], + p0, p1, p[2], p[3], + p0, p1, p[4], p[5], + p0, p1, p[6], p[7], + p0, p1, p[8], p[9], + p0, p1, p[10], p[11], + p0, p1, p[12], p[13], + p0, p1, p[14], p[15])) + + +if __name__ == '__main__': + gr_unittest.main () diff --git a/gnuradio-core/src/python/gnuradio/ofdm_packet_utils.py b/gnuradio-core/src/python/gnuradio/ofdm_packet_utils.py index 006ca6de..463284d6 100644 --- a/gnuradio-core/src/python/gnuradio/ofdm_packet_utils.py +++ b/gnuradio-core/src/python/gnuradio/ofdm_packet_utils.py @@ -96,7 +96,7 @@ def make_header(payload_len, whitener_offset=0): return struct.pack('!HH', val, val) def make_packet(payload, samples_per_symbol, bits_per_symbol, - pad_for_usrp=True, whitener_offset=0, dowhiten=1): + pad_for_usrp=True, whitener_offset=0, whitening=True): """ Build a packet, given access code, payload, and whitener offset @@ -106,10 +106,13 @@ def make_packet(payload, samples_per_symbol, bits_per_symbol, @param bits_per_symbol: (needed for padding calculation) @type bits_per_symbol: int @param whitener_offset offset into whitener string to use [0-16) + @param whitening: Turn whitener on or off + @type whitening: bool Packet will have access code at the beginning, followed by length, payload and finally CRC-32. """ + if not whitener_offset >=0 and whitener_offset < 16: raise ValueError, "whitener_offset must be between 0 and 15, inclusive (%i)" % (whitener_offset,) @@ -129,7 +132,7 @@ def make_packet(payload, samples_per_symbol, bits_per_symbol, usrp_packing = _npadding_bytes(packet_length, samples_per_symbol, bits_per_symbol) * '\x55' pkt_dt = pkt_dt + usrp_packing - if(dowhiten): + if(whitening): pkt = pkt_hd + whiten(pkt_dt, whitener_offset) else: pkt = pkt_hd + pkt_dt @@ -147,8 +150,10 @@ def _npadding_bytes(pkt_byte_len, samples_per_symbol, bits_per_symbol): is a multiple of 128 samples. @param ptk_byte_len: len in bytes of packet, not including padding. - @param samples_per_symbol: samples per bit (1 bit / symbolwith GMSK) + @param samples_per_symbol: samples per bit (1 bit / symbolwidth GMSK) @type samples_per_symbol: int + @param bits_per_symbol: bits per symbol (log2(modulation order)) + @type bits_per_symbol: int @returns number of bytes of padding to append. """ @@ -160,13 +165,17 @@ def _npadding_bytes(pkt_byte_len, samples_per_symbol, bits_per_symbol): return byte_modulus - r -def unmake_packet(whitened_payload_with_crc, whitener_offset=0, dodewhiten=1): +def unmake_packet(whitened_payload_with_crc, whitener_offset=0, dewhitening=1): """ Return (ok, payload) @param whitened_payload_with_crc: string + @param whitener_offset offset into whitener string to use [0-16) + @param dewhitening: Turn whitener on or off + @type dewhitening: bool """ - if dodewhiten: + + if dewhitening: payload_with_crc = dewhiten(whitened_payload_with_crc, whitener_offset) else: payload_with_crc = whitened_payload_with_crc diff --git a/gnuradio-core/src/python/gnuradio/packet_utils.py b/gnuradio-core/src/python/gnuradio/packet_utils.py index e4de6213..dad050c8 100644 --- a/gnuradio-core/src/python/gnuradio/packet_utils.py +++ b/gnuradio-core/src/python/gnuradio/packet_utils.py @@ -157,8 +157,10 @@ def _npadding_bytes(pkt_byte_len, samples_per_symbol, bits_per_symbol): is a multiple of 128 samples. @param ptk_byte_len: len in bytes of packet, not including padding. - @param samples_per_symbol: samples per bit (1 bit / symbolwith GMSK) + @param samples_per_symbol: samples per bit (1 bit / symbolwidth GMSK) @type samples_per_symbol: int + @param bits_per_symbol: bits per symbol (log2(modulation order)) + @type bits_per_symbol: int @returns number of bytes of padding to append. """ diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm.py b/gnuradio-examples/python/ofdm/benchmark_ofdm.py index 53f4bd0b..3c4f172c 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm.py @@ -24,7 +24,6 @@ from gnuradio import gr, blks from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser -from gnuradio.blksimpl import ofdm_pkt import random, time, struct, sys, math, os @@ -77,10 +76,11 @@ class my_graph(gr.flow_graph): self.connect(self.zeros, (self.mux,0)) self.connect(self.txpath, (self.mux,1)) self.connect(self.mux, self.throttle, self.channel, self.rxpath) - - self.connect(self.txpath, gr.file_sink(gr.sizeof_gr_complex, "txpath.dat")) - self.connect(self.mux, gr.file_sink(gr.sizeof_gr_complex, "mux.dat")) - self.connect(self.channel, gr.file_sink(gr.sizeof_gr_complex, "channel.dat")) + + if options.log: + self.connect(self.txpath, gr.file_sink(gr.sizeof_gr_complex, "txpath.dat")) + self.connect(self.mux, gr.file_sink(gr.sizeof_gr_complex, "mux.dat")) + self.connect(self.channel, gr.file_sink(gr.sizeof_gr_complex, "channel.dat")) # ///////////////////////////////////////////////////////////////////////////// # main @@ -121,7 +121,7 @@ def main(): parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, help="set megabytes to transmit [default=%default]") parser.add_option("-r", "--sample-rate", type="eng_float", default=1e5, - help="set sample rate to RATE (%default)") + help="limit sample rate to RATE in throttle (%default)") parser.add_option("", "--snr", type="eng_float", default=30, help="set the SNR of the channel in dB [default=%default]") parser.add_option("", "--frequency-offset", type="eng_float", default=0, @@ -137,8 +137,8 @@ def main(): transmit_path.add_options(parser, expert_grp) receive_path.add_options(parser, expert_grp) - ofdm_pkt.mod_ofdm_pkts.add_options(parser, expert_grp) - ofdm_pkt.demod_ofdm_pkts.add_options(parser, expert_grp) + blks.ofdm_mod.add_options(parser, expert_grp) + blks.ofdm_demod.add_options(parser, expert_grp) (options, args) = parser.parse_args () diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py index f8ebb820..6ab8e157 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2005, 2006 Free Software Foundation, Inc. +# Copyright 2006, 2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,17 +20,17 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru, modulation_utils +from gnuradio import gr, blks from gnuradio import usrp from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser -import random, time, struct, sys, math +import random, time, struct, sys # from current dir from receive_path import receive_path -import ofdm, fusb_options +import fusb_options class usrp_graph(gr.flow_graph): def __init__(self, callback, options): @@ -118,9 +118,6 @@ class usrp_graph(gr.flow_graph): Adds usrp-specific options to the Options Parser """ add_freq_option(normal) - if not normal.has_option("--bitrate"): - normal.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. samples-per-symbol and interp/decim will be derived.") normal.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, help="select USRP Rx side A or B") normal.add_option("", "--rx-gain", type="eng_float", default=None, metavar="GAIN", @@ -129,8 +126,6 @@ class usrp_graph(gr.flow_graph): help="print min and max Rx gain available on selected daughterboard") normal.add_option("-v", "--verbose", action="store_true", default=False) - expert.add_option("-S", "--samples-per-symbol", type="int", default=None, - help="set samples/symbol [default=%default]") expert.add_option("", "--rx-freq", type="eng_float", default=None, help="set Rx frequency to FREQ [default=%default]", metavar="FREQ") expert.add_option("-d", "--decim", type="intx", default=32, @@ -175,14 +170,27 @@ def main(): n_right += 1 print "ok: %r \t pktno: %d \t n_rcvd: %d \t n_right: %d" % (ok, pktno, n_rcvd, n_right) + if 0: + printlst = list() + for x in payload[2:]: + t = hex(ord(x)).replace('0x', '') + if(len(t) == 1): + t = '0' + t + printlst.append(t) + printable = ''.join(printlst) + + print printable + print "\n" + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") expert_grp = parser.add_option_group("Expert") - parser.add_option("-r", "--sample-rate", type="eng_float", default=1e5, - help="set sample rate to RATE (%default)") + parser.add_option("","--discontinuous", action="store_true", default=False, + help="enable discontinuous") usrp_graph.add_options(parser, expert_grp) receive_path.add_options(parser, expert_grp) - ofdm.ofdm_mod.add_options(parser, expert_grp) + blks.ofdm_mod.add_options(parser, expert_grp) + blks.ofdm_demod.add_options(parser, expert_grp) fusb_options.add_options(expert_grp) (options, args) = parser.parse_args () diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py index bda63805..9bdd5ecb 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py @@ -20,18 +20,18 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru, modulation_utils +from gnuradio import gr, blks from gnuradio import usrp from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser -import random, time, struct, sys, math +import time, struct, sys # from current dir from transmit_path import transmit_path from pick_bitrate import pick_tx_bitrate -import ofdm, fusb_options +import fusb_options class usrp_graph(gr.flow_graph): def __init__(self, options): @@ -39,7 +39,6 @@ class usrp_graph(gr.flow_graph): self._tx_freq = options.tx_freq # tranmitter's center frequency self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use - self._bitrate = options.bitrate # desired bit rate self._interp = options.interp # interpolating rate for the USRP (prelim) self._fusb_block_size = options.fusb_block_size # usb info for USRP self._fusb_nblocks = options.fusb_nblocks # usb info for USRP @@ -82,7 +81,7 @@ class usrp_graph(gr.flow_graph): # Set the USRP for maximum transmit gain # (Note that on the RFX cards this is a nop.) - self.set_gain(self.subdev.gain_range()[0]) + self.set_gain(self.subdev.gain_range()[1]) # enable Auto Transmit/Receive switching self.set_auto_tr(True) @@ -126,15 +125,10 @@ class usrp_graph(gr.flow_graph): Adds usrp-specific options to the Options Parser """ add_freq_option(normal) - if not normal.has_option('--bitrate'): - normal.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. samples-per-symbol and interp/decim will be derived.") normal.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, help="select USRP Tx side A or B") normal.add_option("-v", "--verbose", action="store_true", default=False) - expert.add_option("-S", "--samples-per-symbol", type="int", default=None, - help="set samples/symbol [default=%default]") expert.add_option("", "--tx-freq", type="eng_float", default=None, help="set transmit frequency to FREQ [default=%default]", metavar="FREQ") expert.add_option("-i", "--interp", type="intx", default=64, @@ -181,21 +175,17 @@ def main(): help="set packet size [default=%default]") parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, help="set megabytes to transmit [default=%default]") - parser.add_option("-r", "--sample-rate", type="eng_float", default=1e5, - help="set sample rate to RATE (%default)") + parser.add_option("","--discontinuous", action="store_true", default=False, + help="enable discontinuous mode") usrp_graph.add_options(parser, expert_grp) transmit_path.add_options(parser, expert_grp) - ofdm.ofdm_mod.add_options(parser, expert_grp) + blks.ofdm_mod.add_options(parser, expert_grp) + blks.ofdm_demod.add_options(parser, expert_grp) fusb_options.add_options(expert_grp) (options, args) = parser.parse_args () - if(options.mtu < options.size): - sys.stderr.write("MTU (%.0f) must be larger than the packet size (%.0f)\n" - % (options.mtu, options.size)) - sys.exit(1) - # build the graph fg = usrp_graph(options) @@ -215,8 +205,8 @@ def main(): send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) n += pkt_size sys.stderr.write('.') - #if options.discontinuous and pktno % 5 == 4: - # time.sleep(1) + if options.discontinuous and pktno % 5 == 1: + time.sleep(1) pktno += 1 send_pkt(eof=True) diff --git a/gnuradio-examples/python/ofdm/ofdm_sync_pn.m b/gnuradio-examples/python/ofdm/ofdm_sync_pn.m new file mode 100644 index 00000000..d93c0ca9 --- /dev/null +++ b/gnuradio-examples/python/ofdm/ofdm_sync_pn.m @@ -0,0 +1,21 @@ +mf = read_float_binary('ofdm_sync_pn-mf_f.dat'); +theta_pn = read_float_binary('ofdm_sync_pn-theta_f.dat'); +peaks_pn = read_char_binary('ofdm_sync_pn-peaks_b.dat'); +regen_pn = read_char_binary('ofdm_sync_pn-regen_b.dat'); +angle_pn = read_float_binary('ofdm_sync_pn-epsilon_f.dat'); + +plot(mf, 'k') +hold +plot(theta_pn, 'g'); +plot(peaks_pn, 'r'); +plot(regen_pn, 'b'); +xlim([100, 50000]); +ylim([0, 1]) +i = find(peaks_pn); +i(100:200) +hold off + +ipeaks = find(peaks_pn); +dpeaks = diff(ipeaks); +hist(dpeaks, 30) +set(gca, 'FontSize', 30, 'FontWeight', 'Bold'); diff --git a/gnuradio-examples/python/ofdm/plot_ofdm.m b/gnuradio-examples/python/ofdm/plot_ofdm.m new file mode 100755 index 00000000..87eae3a1 --- /dev/null +++ b/gnuradio-examples/python/ofdm/plot_ofdm.m @@ -0,0 +1,65 @@ +function plot_ofdm(fft_size, occ_tones) + +ofdm = read_complex_binary('ofdm_corr_out_c.dat'); +ofdm_split = split_vect(ofdm, occ_tones); + +fftc = read_complex_binary('fft_out_c.dat'); +fftc_split = split_vect(fftc, fft_size); + +figure(1) +set(gcf, 'Position', [50 50 1000 600]); + +a = size(ofdm_split); +if nargin == 3 + maxcount = count; + if maxcount > a(1) + error('plot_ofdm:tolong', 'Requested count size exceeds size of vectors'); + end +else + maxcount = a(1); +end + +for i = 1:20000 + x = ofdm_split(i,:); + y = fftc_split(i+1,:); + + subplot(2,2,1) + plot(real(x), imag(x), 'bo') + set(gca, 'FontSize', 30, 'FontWeight', 'Bold'); + axis([-1.5, 1.5, -1.5, 1.5]) + title('I&Q Constellation', 'FontSize', 36); + xlabel('Inphase', 'FontSize', 32); + ylabel('Quadrature', 'FontSize', 32); + + subplot(2,2,3) + plot(angle(x*j), 'bo') + set(gca, 'FontSize', 30, 'FontWeight', 'Bold'); + axis([0, occ_tones, -3.5, 3.5]) + title('Equalized Symbol Angle', 'FontSize', 36); + xlabel('Bin Number (Occ. Tones)', 'FontSize', 32); + ylabel('Symbol Angle', 'FontSize', 32); + + subplot(2,2,2) + plot(angle(y*j), 'bo') + set(gca, 'FontSize', 30, 'FontWeight', 'Bold'); + axis([0, fft_size, -3.5, 3.5]) + title('Unequalized Symbol Angle', 'FontSize', 36); + xlabel('Bin Number (FFT Size)', 'FontSize', 32); + ylabel('Symbol Angle', 'FontSize', 32); + + Y = 20*log10(abs(y) ./ max(abs(y))); + subplot(2,2,4) + plot(Y, 'b-') + set(gca, 'FontSize', 30, 'FontWeight', 'Bold'); + axis([0, fft_size, -50, 1]); + title('Frequency Domain of Unequalized Rx', 'FontSize', 36); + xlabel('Bin Number (FFT Size)', 'FontSize', 32); + ylabel('Power (dB)', 'FontSize', 32); + + % N = 20*log10(var(abs(x)-1)) + + disp(sprintf('Symbol Number: %d\n', i)) +% disp(sprintf('\tFreq Error: %f\n', anglesh_pn(1+(i-1)*fft_size))) + pause + +end diff --git a/gnuradio-examples/python/ofdm/receive_path.py b/gnuradio-examples/python/ofdm/receive_path.py index 0e44ffde..67a71204 100644 --- a/gnuradio-examples/python/ofdm/receive_path.py +++ b/gnuradio-examples/python/ofdm/receive_path.py @@ -43,9 +43,8 @@ class receive_path(gr.hier_block): self._rx_callback = rx_callback # this callback is fired when there's a packet available # receiver - self.ofdm_receiver = \ - blks.demod_ofdm_pkts(fg, options, - callback=self._rx_callback) + self.ofdm_rx = \ + blks.ofdm_demod(fg, options, callback=self._rx_callback) # Carrier Sensing Blocks #alpha = 0.001 @@ -57,7 +56,7 @@ class receive_path(gr.hier_block): if self._verbose: self._print_verbage() - gr.hier_block.__init__(self, fg, self.ofdm_receiver, None) + gr.hier_block.__init__(self, fg, self.ofdm_rx, None) def carrier_sensed(self): """ @@ -98,9 +97,4 @@ class receive_path(gr.hier_block): """ Prints information about the receive path """ - print "Using RX d'board %s" % (self.subdev.side_and_name(),) - print "Rx gain: %g" % (self.gain,) - print "modulation: %s" % (self._demod_class.__name__) - print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate)) - print "samples/symbol: %3d" % (self._samples_per_symbol) - print "decim: %3d" % (self._decim) + pass diff --git a/gnuradio-examples/python/ofdm/transmit_path.py b/gnuradio-examples/python/ofdm/transmit_path.py index e684c442..2576c2f4 100644 --- a/gnuradio-examples/python/ofdm/transmit_path.py +++ b/gnuradio-examples/python/ofdm/transmit_path.py @@ -41,11 +41,8 @@ class transmit_path(gr.hier_block): self._verbose = options.verbose self._tx_amplitude = options.tx_amplitude # digital amplitude sent to USRP - self.ofdm_transmitter = \ - blks.mod_ofdm_pkts(fg, - options, - msgq_limit=4, - pad_for_usrp=False) + self.ofdm_tx = \ + blks.ofdm_mod(fg, options, msgq_limit=4, pad_for_usrp=False) self.amp = gr.multiply_const_cc(1) self.set_tx_amplitude(self._tx_amplitude) @@ -55,7 +52,7 @@ class transmit_path(gr.hier_block): self._print_verbage() # Create and setup transmit path flow graph - fg.connect(self.ofdm_transmitter, self.amp) + fg.connect(self.ofdm_tx, self.amp) gr.hier_block.__init__(self, fg, None, self.amp) def set_tx_amplitude(self, ampl): @@ -70,14 +67,8 @@ class transmit_path(gr.hier_block): """ Calls the transmitter method to send a packet """ - return self.ofdm_transmitter.send_pkt(payload, eof) + return self.ofdm_tx.send_pkt(payload, eof) - def bitrate(self): - return self._bitrate - - def samples_per_symbol(self): - return self._samples_per_symbol - def add_options(normal, expert): """ Adds transmitter-specific options to the Options Parser -- 2.30.2