Merging ofdm2 branch -r7047:7321 into trunk. This updates the OFDM code to hier_block...
authortrondeau <trondeau@221aa14e-8319-0410-a670-987f0aec2ac5>
Wed, 2 Jan 2008 17:35:35 +0000 (17:35 +0000)
committertrondeau <trondeau@221aa14e-8319-0410-a670-987f0aec2ac5>
Wed, 2 Jan 2008 17:35:35 +0000 (17:35 +0000)
implements a decision feedback sync loop to lock the phase/freq, removes two unnecessary premables and performs frame sync and equalization off
single preamble symbol. Also adds/updates Python plotting tools and a branchless clip algorithm in gr_math.h.

git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@7324 221aa14e-8319-0410-a670-987f0aec2ac5

49 files changed:
AUTHORS
gnuradio-core/src/lib/general/Makefile.am
gnuradio-core/src/lib/general/general.i
gnuradio-core/src/lib/general/gr_math.h
gnuradio-core/src/lib/general/gr_ofdm_correlator.cc [deleted file]
gnuradio-core/src/lib/general/gr_ofdm_correlator.h [deleted file]
gnuradio-core/src/lib/general/gr_ofdm_correlator.i [deleted file]
gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.cc [new file with mode: 0644]
gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.h [new file with mode: 0644]
gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.i [new file with mode: 0644]
gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc
gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h
gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i
gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc
gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
gnuradio-core/src/lib/general/gr_peak_detector2_fb.cc [new file with mode: 0644]
gnuradio-core/src/lib/general/gr_peak_detector2_fb.h [new file with mode: 0644]
gnuradio-core/src/lib/general/gr_peak_detector2_fb.i [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py [new file with mode: 0644]
gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am
gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py [deleted file]
gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py [deleted file]
gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py [deleted file]
gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py [deleted file]
gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py [deleted file]
gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py [deleted file]
gnuradio-core/src/utils/README [new file with mode: 0644]
gnuradio-core/src/utils/gr_plot_char.py [new file with mode: 0755]
gnuradio-core/src/utils/gr_plot_const.py
gnuradio-core/src/utils/gr_plot_fft_c.py [new file with mode: 0755]
gnuradio-core/src/utils/gr_plot_fft_f.py [new file with mode: 0755]
gnuradio-core/src/utils/gr_plot_float.py
gnuradio-core/src/utils/gr_plot_int.py [new file with mode: 0755]
gnuradio-core/src/utils/gr_plot_iq.py
gnuradio-core/src/utils/gr_plot_short.py [new file with mode: 0755]
gnuradio-core/src/utils/gr_read_binary.py [deleted file]
gnuradio-examples/python/ofdm/benchmark_ofdm.py
gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py
gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py
gnuradio-examples/python/ofdm/gr_plot_ofdm.py [new file with mode: 0755]
gnuradio-examples/python/ofdm/plot_ofdm.m
gnuradio-examples/python/ofdm/receive_path.py
gnuradio-examples/python/ofdm/transmit_path.py

diff --git a/AUTHORS b/AUTHORS
index e0bd7a7d1263bcf5aa25a2714eb208fb6b28e1fb..e030f7b7c1102a7dea3bc638f36e4787119b5875 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -11,3 +11,4 @@ Andrew Thomas Beck <Andrew.Beck@postgrads.unisa.edu.au> bugfixes
 Joshua Lackey <jl@noether.uoregon.edu> Original GMSK implementation.
 Johnathan Corgan <jcorgan@corganenterprises.com>  Build system, ongoing stuff, release manager
 Bdale Garbee <bdale@gag.com>           Debian release packages
+Tom Rondeau <trondeau@vt.edu>          Mostly digital waveforms and a little bit of trouble
index b466ad44b6911e478e73b97f3625ad85ef352a92..cde6a754967a36e016dec087f3c7b7dbaaa891f8 100644 (file)
@@ -96,7 +96,7 @@ libgeneral_la_SOURCES =               \
        gr_nop.cc                       \
        gr_null_sink.cc                 \
        gr_null_source.cc               \
-       gr_ofdm_correlator.cc           \
+       gr_ofdm_frame_acquisition.cc    \
         gr_ofdm_cyclic_prefixer.cc      \
         gr_ofdm_demapper_vcb.cc         \
         gr_ofdm_mapper_bcv.cc           \
@@ -109,6 +109,7 @@ libgeneral_la_SOURCES =             \
         gr_ofdm_sampler.cc              \
        gr_pa_2x2_phase_combiner.cc     \
        gr_packet_sink.cc               \
+       gr_peak_detector2_fb.cc         \
        gr_phase_modulator_fc.cc        \
        gr_pll_carriertracking_cc.cc    \
        gr_pll_freqdet_cf.cc            \
@@ -239,7 +240,7 @@ grinclude_HEADERS =                         \
        gr_nop.h                        \
        gr_null_sink.h                  \
        gr_null_source.h                \
-       gr_ofdm_correlator.h            \
+       gr_ofdm_frame_acquisition.h     \
         gr_ofdm_cyclic_prefixer.h       \
         gr_ofdm_demapper_vcb.h          \
         gr_ofdm_mapper_bcv.h            \
@@ -252,6 +253,7 @@ grinclude_HEADERS =                         \
        gr_ofdm_sampler.h               \
        gr_pa_2x2_phase_combiner.h      \
        gr_packet_sink.h                \
+       gr_peak_detector2_fb.h          \
        gr_phase_modulator_fc.h         \
        gr_pll_carriertracking_cc.h     \
        gr_pll_freqdet_cf.h             \
@@ -383,7 +385,7 @@ swiginclude_HEADERS =                       \
        gr_nop.i                        \
        gr_null_sink.i                  \
        gr_null_source.i                \
-       gr_ofdm_correlator.i            \
+       gr_ofdm_frame_acquisition.i     \
         gr_ofdm_cyclic_prefixer.i       \
         gr_ofdm_demapper_vcb.i          \
         gr_ofdm_mapper_bcv.i            \
@@ -396,6 +398,7 @@ swiginclude_HEADERS =                       \
        gr_ofdm_sampler.i               \
        gr_pa_2x2_phase_combiner.i      \
        gr_packet_sink.i                \
+       gr_peak_detector2_fb.i          \
        gr_phase_modulator_fc.i         \
        gr_pll_carriertracking_cc.i     \
        gr_pll_freqdet_cf.i             \
index e9780ea133a68e02f8ec2cd1776fac2b3112fde7..0eab24f1ad653bd0d62367713c70186657f71627 100644 (file)
@@ -93,7 +93,7 @@
 #include <gr_probe_avg_mag_sqrd_cf.h>
 #include <gr_probe_avg_mag_sqrd_f.h>
 #include <gr_probe_signal_f.h>
-#include <gr_ofdm_correlator.h>
+#include <gr_ofdm_frame_acquisition.h>
 #include <gr_ofdm_cyclic_prefixer.h>
 #include <gr_ofdm_bpsk_demapper.h>
 #include <gr_ofdm_mapper_bcv.h>
 #include <gr_bin_statistics_f.h>
 #include <gr_glfsr_source_b.h>
 #include <gr_glfsr_source_f.h>
+#include <gr_peak_detector2_fb.h>
 %}
 
 %include "gr_nop.i"
 %include "gr_probe_avg_mag_sqrd_cf.i"
 %include "gr_probe_avg_mag_sqrd_f.i"
 %include "gr_probe_signal_f.i"
-%include "gr_ofdm_correlator.i"
+%include "gr_ofdm_frame_acquisition.i"
 %include "gr_ofdm_cyclic_prefixer.i"
 %include "gr_ofdm_bpsk_demapper.i"
 %include "gr_ofdm_mapper_bcv.i"
 %include "gr_bin_statistics_f.i"
 %include "gr_glfsr_source_b.i"
 %include "gr_glfsr_source_f.i"
+%include "gr_peak_detector2_fb.i"
index 439e5f4b94dfc0c45cb4e4843ec38041bcb8a2ba..2cd5b8eb7beeea245ceb634bf052082e7618f34b 100644 (file)
@@ -64,4 +64,17 @@ static inline float gr_fast_atan2f(gr_complex z)
   return gr_fast_atan2f(z.imag(), z.real()); 
 }
 
+
+/* This bounds x by +/- clip without a branch */
+
+static inline float gr_branchless_clip(float x, float clip)
+{
+  float x1 = fabsf(x+clip);
+  float x2 = fabsf(x-clip);
+  x1 -= x2;
+  return 0.5*x1;
+}
+
+
+
 #endif /* _GR_MATH_H_ */
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc b/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc
deleted file mode 100644 (file)
index e396eeb..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006, 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 3, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_ofdm_correlator.h>
-#include <gr_io_signature.h>
-#include <gr_expj.h>
-
-#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<gr_complex> &known_symbol1, 
-                        const std::vector<gr_complex> &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,
-                                                         max_fft_shift_len));
-}
-
-gr_ofdm_correlator::gr_ofdm_correlator (unsigned occupied_carriers, unsigned int fft_length, 
-                                       unsigned int cplen,
-                                       const std::vector<gr_complex> &known_symbol1, 
-                                       const std::vector<gr_complex> &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(max_fft_shift_len),
-    d_known_symbol1(known_symbol1),
-    d_known_symbol2(known_symbol2),
-    d_coarse_freq(0),
-    d_phase_count(0)
-{
-  d_diff_corr_factor.resize(d_occupied_carriers);
-  d_hestimate.resize(d_occupied_carriers);
-
-  std::vector<gr_complex>::iterator i1, i2;
-
-  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
-gr_ofdm_correlator::forecast (int noutput_items, gr_vector_int &ninput_items_required)
-{
-  unsigned ninputs = ninput_items_required.size ();
-  for (unsigned i = 0; i < ninputs; i++)
-    ninput_items_required[i] = 2;
-}
-
-gr_complex
-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);
-
-  //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
-gr_ofdm_correlator::correlate(const gr_complex *previous, const gr_complex *current, 
-                             int zeros_on_left)
-{
-  unsigned int i = 0;
-  int search_delta = 0;
-  bool found = false;
-
-  gr_complex h_sqrd = gr_complex(0.0,0.0);
-  float power = 0.0F;
-
-  while(!found && ((unsigned)abs(search_delta) <= d_freq_shift_len)) {
-    h_sqrd = gr_complex(0.0,0.0);
-    power = 0.0F;
-
-    for(i = 0; i < d_occupied_carriers; i++) {
-      h_sqrd = h_sqrd + previous[i+zeros_on_left+search_delta] * 
-       conj(coarse_freq_comp(search_delta,1)*current[i+zeros_on_left+search_delta]) * 
-       d_diff_corr_factor[i];
-      
-      power = power + norm(current[i+zeros_on_left+search_delta]); // No need to do coarse freq here
-    }
-    
-#if VERBOSE
-    printf("bin %d\th_sqrd = ( %f, %f )\t power = %f\t real(h)/p = %f\t angle = %f\n", 
-          search_delta, h_sqrd.real(), h_sqrd.imag(), power, h_sqrd.real()/power, arg(h_sqrd)); 
-#endif      
-    // FIXME: Look at h_sqrd.read() > power
-    if((h_sqrd.real() > 0.82*power) && (h_sqrd.real() < 1.1 * power)) {
-      found = true;
-      //printf("search delta: %d\n", search_delta);
-      d_coarse_freq = search_delta;
-      d_phase_count = 1;
-      //d_snr_est = 10*log10(power/(power-h_sqrd.real()));
-
-      // check for low noise power; sets maximum SNR at 100 dB
-      if(fabs(h_sqrd.imag()) <= 1e-12) {
-       d_snr_est = 100.0;
-      }
-      else {
-       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) + 2;
-      else
-       search_delta = -search_delta;
-    }
-  }
-  return found;
-}
-
-void
-gr_ofdm_correlator::calculate_equalizer(const gr_complex *previous, const gr_complex *current, 
-                                       int zeros_on_left)
-{
-  unsigned int i=0;
-
-  for(i = 0; i < d_occupied_carriers; i++) {
-    // FIXME possibly add small epsilon in divisor to protect from div 0
-    //d_hestimate[i] = 0.5F * (d_known_symbol1[i] / previous[i+zeros_on_left] +
-    //                     d_known_symbol2[i] / (coarse_freq_comp(d_coarse_freq,1)*
-    //                                           current[i+zeros_on_left+d_coarse_freq]));
-    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, "\n");
-#endif
-}
-
-int
-gr_ofdm_correlator::general_work(int noutput_items,
-                                gr_vector_int &ninput_items,
-                                gr_vector_const_void_star &input_items,
-                                gr_vector_void_star &output_items)
-{
-  const gr_complex *in = (const gr_complex *)input_items[0];
-  const gr_complex *previous = &in[0];
-  const gr_complex *current = &in[d_fft_length];
-
-  gr_complex *out = (gr_complex *) output_items[0];
-  char *sig = (char *) output_items[1];
-  
-  unsigned int i=0;
-
-  int unoccupied_carriers = d_fft_length - d_occupied_carriers;
-  int zeros_on_left = (int)ceil(unoccupied_carriers/2.0);
-
-  bool corr = correlate(previous, current, zeros_on_left);
-  if(corr) {
-    calculate_equalizer(previous, current, zeros_on_left);
-    sig[0] = 1;
-  }
-  else {
-    sig[0] = 0;
-  }
-
-  for(i = 0; i < d_occupied_carriers; i++) {
-    out[i] = d_hestimate[i]*coarse_freq_comp(d_coarse_freq,d_phase_count)*current[i+zeros_on_left+d_coarse_freq];
-  }
-  
-
-  d_phase_count++;
-  if(d_phase_count == MAX_NUM_SYMBOLS) {
-    d_phase_count = 1;
-  }
-
-  consume_each(1);
-  return 1;
-}
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.h b/gnuradio-core/src/lib/general/gr_ofdm_correlator.h
deleted file mode 100644 (file)
index 55ee4e1..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006, 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 3, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifndef INCLUDED_GR_OFDM_CORRELATOR_H
-#define INCLUDED_GR_OFDM_CORRELATOR_H
-
-
-#include <gr_block.h>
-#include <vector>
-
-class gr_ofdm_correlator;
-typedef boost::shared_ptr<gr_ofdm_correlator> gr_ofdm_correlator_sptr;
-
-gr_ofdm_correlator_sptr 
-gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length,
-                        unsigned int cplen,
-                        const std::vector<gr_complex> &known_symbol1, 
-                        const std::vector<gr_complex> &known_symbol2,
-                        unsigned int max_fft_shift_len=10);
-
-/*!
- * \brief take a vector of complex constellation points in from an FFT
- * and performs a correlation and equalization.
- * \inblock blocks
- *
- * This block takes the output of an FFT of a received OFDM symbol and finds the 
- * start of a frame based on two known symbols. It also looks at the surrounding
- * bins in the FFT output for the correlation in case there is a large frequency
- * shift in the data. This block assumes that the fine frequency shift has already
- * been corrected and that the samples fall in the middle of one FFT bin.
- *
- * It then uses one of those known
- * symbols to estimate the channel response over all subcarriers and does a simple 
- * 1-tap equalization on all subcarriers. This corrects for the phase and amplitude
- * distortion caused by the channel.
- */
-
-class gr_ofdm_correlator : public gr_block
-{
-  /*! 
-   * \brief Build an OFDM correlator and equalizer.
-   * \param occupied_carriers   The number of subcarriers with data in the received symbol
-   * \param fft_length          The size of the FFT vector (occupied_carriers + unused carriers)
-   * \param known_symbol1       A vector of complex numbers representing a known symbol at the
-   *                            start of a frame (usually a BPSK PN sequence)
-   * \param known_symbol2       A vector of complex numbers representing a known symbol at the
-   *                            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<gr_complex> &known_symbol1, 
-                          const std::vector<gr_complex> &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<gr_complex> &known_symbol1, 
-                     const std::vector<gr_complex> &known_symbol2,
-                     unsigned int max_fft_shift_len);
-  
- private:
-  unsigned char slicer(gr_complex x);
-  bool correlate(const gr_complex *previous, const gr_complex *current, int zeros_on_left);
-  void calculate_equalizer(const gr_complex *previous, 
-                          const gr_complex *current, int zeros_on_left);
-  gr_complex coarse_freq_comp(int freq_delta, int count);
-  
-  unsigned int d_occupied_carriers;  // !< \brief number of subcarriers with data
-  unsigned int d_fft_length;         // !< \brief length of FFT vector
-  unsigned int d_cplen;              // !< \brief length of cyclic prefix in samples
-  unsigned int d_freq_shift_len;     // !< \brief number of surrounding bins to look at for correlation
-  std::vector<gr_complex> d_known_symbol1, d_known_symbol2; // !< \brief known symbols at start of frame
-  std::vector<gr_complex> d_diff_corr_factor; // !< \brief factor used in correlation
-  std::vector<gr_complex> d_hestimate;  // !< channel estimate
-  signed int d_coarse_freq;             // !< \brief search distance in number of bins
-  unsigned int d_phase_count;           // !< \brief accumulator for coarse freq correction
-  float d_snr_est;                      // !< an estimation of the signal to noise ratio
-
-  gr_complex *d_phase_lut;  // !< look-up table for coarse frequency compensation
-
-  void forecast(int noutput_items, gr_vector_int &ninput_items_required);
-
- public:
-  /*!
-   * \brief Return an estimate of the SNR of the channel
-   */
-  float snr() { return d_snr_est; }
-
-  ~gr_ofdm_correlator(void);
-  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
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.i b/gnuradio-core/src/lib/general/gr_ofdm_correlator.i
deleted file mode 100644 (file)
index 2e39e21..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006, 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 3, or (at your option)
- * any later version.
- * 
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <vector>
-
-GR_SWIG_BLOCK_MAGIC(gr,ofdm_correlator);
-
-gr_ofdm_correlator_sptr 
-gr_make_ofdm_correlator (unsigned int occupied_carriers, 
-                        unsigned int fft_length,
-                        unsigned int cplen,
-                        const std::vector<gr_complex> &known_symbol1, 
-                        const std::vector<gr_complex> &known_symbol2,
-                        unsigned int max_fft_shift_len=4);
-
-class gr_ofdm_correlator : public gr_sync_decimator
-{
- protected:
-  gr_ofdm_correlator (unsigned int occupied_carriers,
-                     unsigned int fft_length,
-                     unsigned int cplen,
-                     const std::vector<gr_complex> &known_symbol1, 
-                     const std::vector<gr_complex> &known_symbol2,
-                     unsigned int max_fft_shift_len);
-
- public:
-  float snr() { return d_snr_est; }
-  int general_work(int noutput_items,
-                  gr_vector_int &ninput_items,
-                  gr_vector_const_void_star &input_items,
-                  gr_vector_void_star &output_items);
-};
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.cc
new file mode 100644 (file)
index 0000000..0fa6a3d
--- /dev/null
@@ -0,0 +1,223 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_ofdm_frame_acquisition.h>
+#include <gr_io_signature.h>
+#include <gr_expj.h>
+#include <gr_math.h>
+
+#define VERBOSE 0
+#define M_TWOPI (2*M_PI)
+#define MAX_NUM_SYMBOLS 1000
+
+gr_ofdm_frame_acquisition_sptr
+gr_make_ofdm_frame_acquisition (unsigned int occupied_carriers, unsigned int fft_length, 
+                               unsigned int cplen,
+                               const std::vector<gr_complex> &known_symbol,
+                               unsigned int max_fft_shift_len)
+{
+  return gr_ofdm_frame_acquisition_sptr (new gr_ofdm_frame_acquisition (occupied_carriers, fft_length, cplen,
+                                                                       known_symbol, max_fft_shift_len));
+}
+
+gr_ofdm_frame_acquisition::gr_ofdm_frame_acquisition (unsigned occupied_carriers, unsigned int fft_length, 
+                                                     unsigned int cplen,
+                                                     const std::vector<gr_complex> &known_symbol,
+                                                     unsigned int max_fft_shift_len)
+  : gr_block ("ofdm_frame_acquisition",
+             gr_make_io_signature2 (2, 2, sizeof(gr_complex)*fft_length, sizeof(char)),
+             gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char))),
+    d_occupied_carriers(occupied_carriers),
+    d_fft_length(fft_length),
+    d_cplen(cplen),
+    d_freq_shift_len(max_fft_shift_len),
+    d_known_symbol(known_symbol),
+    d_coarse_freq(0),
+    d_phase_count(0)
+{
+  d_symbol_phase_diff.resize(d_fft_length);
+  d_known_phase_diff.resize(d_occupied_carriers);
+  d_hestimate.resize(d_occupied_carriers);
+
+  unsigned int i = 0, j = 0;
+
+  std::fill(d_known_phase_diff.begin(), d_known_phase_diff.end(), 0);
+  for(i = 0; i < d_known_symbol.size()-2; i+=2) {
+    d_known_phase_diff[i] = fabs(gr_fast_atan2f(d_known_symbol[i]) - gr_fast_atan2f(d_known_symbol[i+2]));
+  }
+  
+  d_phase_lut = new gr_complex[(2*d_freq_shift_len+1) * MAX_NUM_SYMBOLS];
+  for(i = 0; i <= 2*d_freq_shift_len; i++) {
+    for(j = 0; j < MAX_NUM_SYMBOLS; j++) {
+      d_phase_lut[j + i*MAX_NUM_SYMBOLS] =  gr_expj(-M_TWOPI*d_cplen/d_fft_length*(i-d_freq_shift_len)*j);
+    }
+  }
+}
+
+gr_ofdm_frame_acquisition::~gr_ofdm_frame_acquisition(void)
+{
+  delete [] d_phase_lut;
+}
+
+void
+gr_ofdm_frame_acquisition::forecast (int noutput_items, gr_vector_int &ninput_items_required)
+{
+  unsigned ninputs = ninput_items_required.size ();
+  for (unsigned i = 0; i < ninputs; i++)
+    ninput_items_required[i] = 1;
+}
+
+gr_complex
+gr_ofdm_frame_acquisition::coarse_freq_comp(int freq_delta, int symbol_count)
+{
+  //  return gr_complex(cos(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count),
+  //       sin(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count));
+
+  return gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count);
+
+  //return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count];
+}
+
+
+
+bool
+gr_ofdm_frame_acquisition::correlate(const gr_complex *symbol, int zeros_on_left)
+{
+  unsigned int i = 0, j = 0;
+
+  std::fill(d_symbol_phase_diff.begin(), d_symbol_phase_diff.end(), 0);
+  for(i = 0; i < d_fft_length-2; i++) {
+    d_symbol_phase_diff[i] = fabs(gr_fast_atan2f(symbol[i]) - gr_fast_atan2f(symbol[i+2]));
+  }
+
+  int index = 0;
+  float max = 0, sum=0;
+  for(i =  zeros_on_left - d_freq_shift_len; i < zeros_on_left + d_freq_shift_len; i+=2) {
+    sum = 0;
+    for(j = 0; j < d_occupied_carriers; j++) {
+      sum += (d_known_phase_diff[j] * d_symbol_phase_diff[i+j]);
+    }
+    if(fabs(sum) > max) {
+      max = sum;
+      index = i;
+    }
+  }
+
+  d_coarse_freq = index - zeros_on_left;
+
+  if(VERBOSE) {
+    fprintf(stderr, "Coarse Freq Offset: %d\n", d_coarse_freq);
+    for(i = 0; i < 40; i++) {
+      fprintf(stderr, "%+.4f   %+.4f\n", d_known_phase_diff[i], 
+             d_symbol_phase_diff[zeros_on_left+d_coarse_freq+i]);
+    }
+  }
+
+  return true;  //FIXME: don't need ot return anything now
+}
+
+void
+gr_ofdm_frame_acquisition::calculate_equalizer(const gr_complex *symbol, int zeros_on_left)
+{
+  unsigned int i=0;
+
+  // Set first tap of equalizer
+  d_hestimate[0] = d_known_symbol[0] / 
+    (coarse_freq_comp(d_coarse_freq,1)*symbol[zeros_on_left+d_coarse_freq]);
+
+  // set every even tap based on known symbol
+  // linearly interpolate between set carriers to set zero-filled carriers
+  // FIXME: is this the best way to set this?
+  for(i = 2; i < d_occupied_carriers; i+=2) {
+    d_hestimate[i] = d_known_symbol[i] / 
+      (coarse_freq_comp(d_coarse_freq,1)*(symbol[i+zeros_on_left+d_coarse_freq]));
+    d_hestimate[i-1] = (d_hestimate[i] + d_hestimate[i-2]) / gr_complex(2.0, 0.0);    
+  }
+
+  // with even number of carriers; last equalizer tap is wrong
+  if(!(d_occupied_carriers & 1)) {
+    d_hestimate[d_occupied_carriers-1] = d_hestimate[d_occupied_carriers-2];
+  }
+
+  if(VERBOSE) {
+    fprintf(stderr, "Equalizer setting:\n");
+    for(i = 0; i < d_occupied_carriers; i++) {
+      gr_complex sym = coarse_freq_comp(d_coarse_freq,1)*symbol[i+zeros_on_left+d_coarse_freq];
+      gr_complex output = sym * d_hestimate[i];
+      fprintf(stderr, "sym: %+.4f + j%+.4f  ks: %+.4f + j%+.4f  eq: %+.4f + j%+.4f  ==>  %+.4f + j%+.4f\n", 
+             sym .real(), sym.imag(),
+             d_known_symbol[i].real(), d_known_symbol[i].imag(),
+             d_hestimate[i].real(), d_hestimate[i].imag(),
+             output.real(), output.imag());
+    }
+    fprintf(stderr, "\n");
+  }
+}
+
+int
+gr_ofdm_frame_acquisition::general_work(int noutput_items,
+                                       gr_vector_int &ninput_items,
+                                       gr_vector_const_void_star &input_items,
+                                       gr_vector_void_star &output_items)
+{
+  const gr_complex *symbol = (const gr_complex *)input_items[0];
+  const char *trigger = (const char *)input_items[1];
+
+  gr_complex *out = (gr_complex *) output_items[0];
+  char *sig = (char *) output_items[1];
+  
+  int unoccupied_carriers = d_fft_length - d_occupied_carriers;
+  int zeros_on_left = (int)ceil(unoccupied_carriers/2.0);
+
+  int found = 0;
+  for(int i = 0; i < ninput_items[1]; i++) {
+    found += trigger[i];
+  }
+
+  if(found) {
+    d_phase_count = 1;
+    correlate(symbol, zeros_on_left);
+    calculate_equalizer(symbol, zeros_on_left);
+    sig[0] = 1;
+  }
+  else {
+    sig[0] = 0;
+  }
+
+  for(unsigned int i = 0; i < d_occupied_carriers; i++) {
+    out[i] = d_hestimate[i]*coarse_freq_comp(d_coarse_freq,d_phase_count)
+      *symbol[i+zeros_on_left+d_coarse_freq];
+  }
+  
+  d_phase_count++;
+  if(d_phase_count == MAX_NUM_SYMBOLS) {
+    d_phase_count = 1;
+  }
+
+  consume(0,1);
+  consume(1,ninput_items[1]);
+  return 1;
+}
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.h b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.h
new file mode 100644 (file)
index 0000000..af63f3e
--- /dev/null
@@ -0,0 +1,118 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_OFDM_FRAME_ACQUISITION_H
+#define INCLUDED_GR_OFDM_FRAME_ACQUISITION_H
+
+
+#include <gr_block.h>
+#include <vector>
+
+class gr_ofdm_frame_acquisition;
+typedef boost::shared_ptr<gr_ofdm_frame_acquisition> gr_ofdm_frame_acquisition_sptr;
+
+gr_ofdm_frame_acquisition_sptr 
+gr_make_ofdm_frame_acquisition (unsigned int occupied_carriers, unsigned int fft_length,
+                               unsigned int cplen,
+                               const std::vector<gr_complex> &known_symbol, 
+                               unsigned int max_fft_shift_len=10);
+
+/*!
+ * \brief take a vector of complex constellation points in from an FFT
+ * and performs a correlation and equalization.
+ * \inblock blocks
+ *
+ * This block takes the output of an FFT of a received OFDM symbol and finds the 
+ * start of a frame based on two known symbols. It also looks at the surrounding
+ * bins in the FFT output for the correlation in case there is a large frequency
+ * shift in the data. This block assumes that the fine frequency shift has already
+ * been corrected and that the samples fall in the middle of one FFT bin.
+ *
+ * It then uses one of those known
+ * symbols to estimate the channel response over all subcarriers and does a simple 
+ * 1-tap equalization on all subcarriers. This corrects for the phase and amplitude
+ * distortion caused by the channel.
+ */
+
+class gr_ofdm_frame_acquisition : public gr_block
+{
+  /*! 
+   * \brief Build an OFDM correlator and equalizer.
+   * \param occupied_carriers   The number of subcarriers with data in the received symbol
+   * \param fft_length          The size of the FFT vector (occupied_carriers + unused carriers)
+   * \param known_symbol1       A vector of complex numbers representing a known symbol at the
+   *                            start of a frame (usually a BPSK PN sequence)
+   * \param known_symbol2       A vector of complex numbers representing a known symbol at the
+   *                            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_frame_acquisition_sptr
+  gr_make_ofdm_frame_acquisition (unsigned int occupied_carriers, unsigned int fft_length,
+                                 unsigned int cplen,
+                                 const std::vector<gr_complex> &known_symbol, 
+                                 unsigned int max_fft_shift_len);
+  
+protected:
+  gr_ofdm_frame_acquisition (unsigned int occupied_carriers, unsigned int fft_length,
+                            unsigned int cplen,
+                            const std::vector<gr_complex> &known_symbol, 
+                            unsigned int max_fft_shift_len);
+  
+ private:
+  unsigned char slicer(gr_complex x);
+  bool correlate(const gr_complex *symbol, int zeros_on_left);
+  void calculate_equalizer(const gr_complex *symbol, int zeros_on_left);
+  gr_complex coarse_freq_comp(int freq_delta, int count);
+  
+  unsigned int d_occupied_carriers;  // !< \brief number of subcarriers with data
+  unsigned int d_fft_length;         // !< \brief length of FFT vector
+  unsigned int d_cplen;              // !< \brief length of cyclic prefix in samples
+  unsigned int d_freq_shift_len;     // !< \brief number of surrounding bins to look at for correlation
+  std::vector<gr_complex> d_known_symbol; // !< \brief known symbols at start of frame
+  std::vector<float> d_known_phase_diff; // !< \brief factor used in correlation from known symbol
+  std::vector<float> d_symbol_phase_diff; // !< \brief factor used in correlation from received symbol
+  std::vector<gr_complex> d_hestimate;  // !< channel estimate
+  int d_coarse_freq;             // !< \brief search distance in number of bins
+  unsigned int d_phase_count;           // !< \brief accumulator for coarse freq correction
+  float d_snr_est;                      // !< an estimation of the signal to noise ratio
+
+  gr_complex *d_phase_lut;  // !< look-up table for coarse frequency compensation
+
+  void forecast(int noutput_items, gr_vector_int &ninput_items_required);
+
+ public:
+  /*!
+   * \brief Return an estimate of the SNR of the channel
+   */
+  float snr() { return d_snr_est; }
+
+  ~gr_ofdm_frame_acquisition(void);
+  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
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.i b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.i
new file mode 100644 (file)
index 0000000..0fd0bc5
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006, 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <vector>
+
+GR_SWIG_BLOCK_MAGIC(gr,ofdm_frame_acquisition);
+
+gr_ofdm_frame_acquisition_sptr 
+gr_make_ofdm_frame_acquisition (unsigned int occupied_carriers, 
+                               unsigned int fft_length,
+                               unsigned int cplen,
+                               const std::vector<gr_complex> &known_symbol, 
+                               unsigned int max_fft_shift_len=4);
+
+class gr_ofdm_frame_acquisition : public gr_sync_decimator
+{
+ protected:
+  gr_ofdm_frame_acquisition (unsigned int occupied_carriers,
+                            unsigned int fft_length,
+                            unsigned int cplen,
+                            const std::vector<gr_complex> &known_symbol, 
+                            unsigned int max_fft_shift_len);
+
+ public:
+  float snr() { return d_snr_est; }
+  int general_work(int noutput_items,
+                  gr_vector_int &ninput_items,
+                  gr_vector_const_void_star &input_items,
+                  gr_vector_void_star &output_items);
+};
index d75b693a2b119b88f397056e58b328418ffa40d7..a1ac66ff7f858aacb48362c31878a4272dc9c920 100644 (file)
 
 #include <gr_ofdm_frame_sink.h>
 #include <gr_io_signature.h>
+#include <gr_expj.h>
+#include <gr_math.h>
+#include <math.h>
 #include <cstdio>
 #include <stdexcept>
+#include <iostream>
 
 #define VERBOSE 0
 
@@ -55,6 +59,11 @@ gr_ofdm_frame_sink::enter_have_sync()
 
   d_header = 0;
   d_headerbytelen_cnt = 0;
+
+  // Resetting PLL
+  d_freq = 0.0;
+  d_phase = 0.0;
+  fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
 }
 
 inline void
@@ -96,7 +105,11 @@ unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
                                          unsigned char *out)
 {
   unsigned int i=0, bytes_produced=0;
+  gr_complex carrier;
+
+  carrier=gr_expj(d_phase);
 
+  gr_complex accum_error = 0.0;
   while(i < d_occupied_carriers) {
     if(d_nresid > 0) {
       d_partial_byte |= d_resid;
@@ -106,8 +119,23 @@ unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
     }
 
     while((d_byte_offset < 8) && (i < d_occupied_carriers)) {
-      //fprintf(stderr, "%f+j%f  = %d\n", in[i].real(), in[i].imag(), slicer(in[i])); 
-      unsigned char bits = slicer(in[i++]);
+      gr_complex sigrot = in[i]*carrier*d_dfe[i];
+      
+      if(d_derotated_output != NULL){
+       d_derotated_output[i] = sigrot;
+      }
+      
+      unsigned char bits = slicer(sigrot);
+
+      gr_complex closest_sym = d_sym_position[bits];
+      
+      accum_error += sigrot * conj(closest_sym);
+
+      // FIX THE FOLLOWING STATEMENT
+      if (norm(sigrot)> 0.001) d_dfe[i] +=  d_eq_gain*(closest_sym/sigrot-d_dfe[i]);
+      
+      i++;
+
       if((8 - d_byte_offset) >= d_nbits) {
        d_partial_byte |= bits << (d_byte_offset);
        d_byte_offset += d_nbits;
@@ -130,7 +158,18 @@ unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
       d_partial_byte = 0;
     }
   }
+  //std::cerr << "accum_error " << accum_error << std::endl;
+
+  float angle = arg(accum_error);
 
+  d_freq = d_freq - d_freq_gain*angle;
+  d_phase = d_phase + d_freq - d_phase_gain*angle;
+  if (d_phase >= 2*M_PI) d_phase -= 2*M_PI;
+  if (d_phase <0) d_phase += 2*M_PI;
+    
+  //if(VERBOSE)
+  //  std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl;
+  
   return bytes_produced;
 }
 
@@ -138,24 +177,30 @@ unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
 gr_ofdm_frame_sink_sptr
 gr_make_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, 
                        const std::vector<unsigned char> &sym_value_out,
-                       gr_msg_queue_sptr target_queue, unsigned int occupied_carriers)
+                       gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
+                       float phase_gain, float freq_gain)
 {
   return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(sym_position, sym_value_out,
-                                                       target_queue, occupied_carriers));
+                                                       target_queue, occupied_carriers,
+                                                       phase_gain, freq_gain));
 }
 
 
 gr_ofdm_frame_sink::gr_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, 
                                       const std::vector<unsigned char> &sym_value_out,
-                                      gr_msg_queue_sptr target_queue, unsigned int occupied_carriers)
+                                      gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
+                                      float phase_gain, float freq_gain)
   : gr_sync_block ("ofdm_frame_sink",
                   gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)),
-                  gr_make_io_signature (0, 0, 0)),
+                  gr_make_io_signature (1, 1, sizeof(gr_complex)*occupied_carriers)),
     d_target_queue(target_queue), d_occupied_carriers(occupied_carriers), 
     d_byte_offset(0), d_partial_byte(0),
-    d_resid(0), d_nresid(0)
+    d_resid(0), d_nresid(0),d_phase(0),d_freq(0),d_phase_gain(phase_gain),d_freq_gain(freq_gain),
+    d_eq_gain(0.05)
 {
   d_bytes_out = new unsigned char[d_occupied_carriers];
+  d_dfe.resize(occupied_carriers);
+  fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
 
   set_sym_value_out(sym_position, sym_value_out);
   
@@ -179,7 +224,7 @@ gr_ofdm_frame_sink::set_sym_value_out(const std::vector<gr_complex> &sym_positio
 
   d_sym_position  = sym_position;
   d_sym_value_out = sym_value_out;
-  d_nbits = (unsigned long)(log10(d_sym_value_out.size()) / log10(2));
+  d_nbits = (unsigned long)ceil(log10(d_sym_value_out.size()) / log10(2.0));
 
   return true;
 }
@@ -194,12 +239,16 @@ gr_ofdm_frame_sink::work (int noutput_items,
   const char *sig = (const char *) input_items[1];
   unsigned int j = 0;
   unsigned int bytes=0;
+
+  // If the output is connected, send it the derotated symbols
+  if(output_items.size() >= 1)
+    d_derotated_output = (gr_complex *)output_items[0];
+  else
+    d_derotated_output = NULL;
   
   if (VERBOSE)
     fprintf(stderr,">>> Entering state machine\n");
-  
-  bytes = demapper(&in[0], d_bytes_out);
-  
+
   switch(d_state) {
       
   case STATE_SYNC_SEARCH:    // Look for flag indicating beginning of pkt
@@ -212,6 +261,10 @@ gr_ofdm_frame_sink::work (int noutput_items,
     break;
 
   case STATE_HAVE_SYNC:
+    // only demod after getting the preamble signal; otherwise, the 
+    // equalizer taps will screw with the PLL performance
+    bytes = demapper(&in[0], d_bytes_out);
+    
     if (VERBOSE) {
       if(sig[0])
        printf("ERROR -- Found SYNC in HAVE_SYNC\n");
@@ -258,6 +311,8 @@ gr_ofdm_frame_sink::work (int noutput_items,
     break;
       
   case STATE_HAVE_HEADER:
+    bytes = demapper(&in[0], d_bytes_out);
+
     if (VERBOSE) {
       if(sig[0])
        printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen);
@@ -288,6 +343,6 @@ gr_ofdm_frame_sink::work (int noutput_items,
     assert(0);
     
   } // switch
-  
+
   return 1;
 }
index f1c9b76feae50e727fbaf1fba17f8baabeb59313..904373bba897e39d9710ecc24984f007ed010f12 100644 (file)
@@ -32,7 +32,8 @@ typedef boost::shared_ptr<gr_ofdm_frame_sink> gr_ofdm_frame_sink_sptr;
 gr_ofdm_frame_sink_sptr 
 gr_make_ofdm_frame_sink (const std::vector<gr_complex> &sym_position, 
                         const std::vector<unsigned char> &sym_value_out,
-                        gr_msg_queue_sptr target_queue, unsigned int occupied_tones);
+                        gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+                        float phase_gain=0.25, float freq_gain=0.25*0.25/4.0);
 
 /*!
  * \brief Takes an OFDM symbol in, demaps it into bits of 0's and 1's, packs
@@ -47,7 +48,8 @@ class gr_ofdm_frame_sink : public gr_sync_block
   friend gr_ofdm_frame_sink_sptr 
   gr_make_ofdm_frame_sink (const std::vector<gr_complex> &sym_position, 
                           const std::vector<unsigned char> &sym_value_out,
-                          gr_msg_queue_sptr target_queue, unsigned int occupied_tones);
+                          gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+                          float phase_gain, float freq_gain);
 
  private:
   enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER};
@@ -71,17 +73,26 @@ class gr_ofdm_frame_sink : public gr_sync_block
   int                d_packet_whitener_offset;  // offset into whitener string to use
   int               d_packetlen_cnt;           // how many so far
 
+  gr_complex * d_derotated_output;  // Pointer to output stream to send deroated symbols out
+
   std::vector<gr_complex>    d_sym_position;
   std::vector<unsigned char> d_sym_value_out;
+  std::vector<gr_complex>    d_dfe;
   unsigned int d_nbits;
 
   unsigned char d_resid;
   unsigned int d_nresid;
+  float d_phase;
+  float d_freq;
+  float d_phase_gain;
+  float d_freq_gain;
+  float d_eq_gain;
 
  protected:
   gr_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, 
                     const std::vector<unsigned char> &sym_value_out,
-                    gr_msg_queue_sptr target_queue, unsigned int occupied_tones);
+                    gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+                    float phase_gain, float freq_gain);
 
   void enter_search();
   void enter_have_sync();
index 296eb65912199edcc73a0edcf77b776a8a591264..38ab50e973a7e4855c0618bd9db30a7dbda2dbe2 100644 (file)
@@ -25,14 +25,16 @@ GR_SWIG_BLOCK_MAGIC(gr,ofdm_frame_sink);
 gr_ofdm_frame_sink_sptr 
 gr_make_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, 
                        const std::vector<unsigned char> &sym_value_out,
-                       gr_msg_queue_sptr target_queue, unsigned int occupied_tones);
+                       gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+                       float phase_gain=0.25, float freq_gain=0.25*0.25/4);
 
 class gr_ofdm_frame_sink : public gr_sync_block
 {
  protected:
   gr_ofdm_frame_sink(const std::vector<gr_complex> &sym_position, 
                     const std::vector<unsigned char> &sym_value_out,
-                    gr_msg_queue_sptr target_queue, unsigned int occupied_tones);
+                    gr_msg_queue_sptr target_queue, unsigned int occupied_tones,
+                    float phase_gain, float freq_gain);
 
  public:
   ~gr_ofdm_frame_sink();
index 4ff55b5d8096af4a13e9eaf8877841127cead7da..f916977df3ccce1ec11a312856d8c18c9915d99e 100644 (file)
@@ -54,8 +54,8 @@ gr_ofdm_mapper_bcv::gr_ofdm_mapper_bcv (const std::vector<gr_complex> &constella
 {
   if (!(d_occupied_carriers <= d_fft_length))
     throw std::invalid_argument("gr_ofdm_mapper_bcv: occupied carriers must be <= fft_length");
-
-  d_nbits = (unsigned long)(log10(d_constellation.size()) / log10(2));
+  
+  d_nbits = (unsigned long)ceil(log10(d_constellation.size()) / log10(2.0));
 }
 
 gr_ofdm_mapper_bcv::~gr_ofdm_mapper_bcv(void)
index 56b5d50a4e761ed87d61cef6ab7f9cf328709948..6216df791cfc7e7bd03c35cc1711682f525a4bab 100644 (file)
@@ -65,22 +65,26 @@ gr_ofdm_sampler::general_work (int noutput_items,
 
   gr_complex *optr = (gr_complex *) output_items[0];
 
-  int found=0;
+  int found=0, index=0;
 
   int i=d_fft_length-1;
 
-  while(!found && i<std::min(ninput_items[0],ninput_items[1]) ) {
-    if(trigger[i])
+  // FIXME: This is where we miss if the regeneration happens too soon.
+  //while(!found && i<std::min(ninput_items[0],ninput_items[1]) ) {
+  while(i<std::min(ninput_items[0],ninput_items[1]) ) {
+    if(trigger[i]) {
       found = 1;
+      index = i++;
+    }
     else
       i++;
   }
-
+  
   if(found) {
-    assert(i-d_fft_length+1 >= 0);
-    for(int j=i-d_fft_length+1;j<=i;j++)
+    assert(index-d_fft_length+1 >= 0);
+    for(int j=index - d_fft_length + 1; j <= index; j++)
       *optr++ = iptr[j];
-    consume_each(i-d_fft_length+2);
+    consume_each(index - d_fft_length + 2);
     //printf("OFDM Sampler found:  ninput_items: %d/%d   noutput_items: %d  consumed: %d   found: %d\n", 
     //   ninput_items[0], ninput_items[1], noutput_items, (i-d_fft_length+2), found);
   }
diff --git a/gnuradio-core/src/lib/general/gr_peak_detector2_fb.cc b/gnuradio-core/src/lib/general/gr_peak_detector2_fb.cc
new file mode 100644 (file)
index 0000000..a84cf18
--- /dev/null
@@ -0,0 +1,106 @@
+/* -*- 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_peak_detector2_fb.h>
+#include <gr_io_signature.h>
+
+gr_peak_detector2_fb_sptr
+gr_make_peak_detector2_fb (float threshold_factor_rise,
+                          int look_ahead, float alpha)
+{
+  return gr_peak_detector2_fb_sptr (new gr_peak_detector2_fb (threshold_factor_rise, 
+                                 look_ahead, alpha));
+}
+
+gr_peak_detector2_fb::gr_peak_detector2_fb (float threshold_factor_rise, 
+                                           int look_ahead, float alpha)
+  : gr_sync_block ("peak_detector2_fb",
+                  gr_make_io_signature (1, 1, sizeof(float)),
+                  gr_make_io_signature2 (1, 2, sizeof(char), sizeof(float))),
+    d_threshold_factor_rise(threshold_factor_rise), 
+    d_look_ahead(look_ahead), d_alpha(alpha), d_avg(0.0f), d_found(false)
+{
+}
+
+int
+gr_peak_detector2_fb::work (int noutput_items,
+                           gr_vector_const_void_star &input_items,
+                           gr_vector_void_star &output_items) {
+  float *iptr = (float *) input_items[0];
+  char *optr = (char *) output_items[0];
+  
+  assert(noutput_items >= 2);
+
+  memset(optr, 0, noutput_items*sizeof(char));
+
+  for (int i = 0; i < noutput_items; i++) {
+
+    if (!d_found) {
+      // Have not yet detected presence of peak
+      if (iptr[i] > d_avg * (1.0f + d_threshold_factor_rise)) {
+       d_found = true;
+       d_look_ahead_remaining = d_look_ahead;
+        d_peak_val = -(float)INFINITY;
+      } 
+      else {
+       d_avg = d_alpha*iptr[i] + (1.0f - d_alpha)*d_avg;
+      }
+    } 
+    else {
+      // Detected presence of peak
+      if (iptr[i] > d_peak_val) {
+        d_peak_val = iptr[i];
+        d_peak_ind = i;
+      } 
+      else if (d_look_ahead_remaining <= 0) {
+        optr[d_peak_ind] = 1;
+        d_found = false;
+        d_avg = iptr[i];
+      }
+      
+      // Have not yet located peak, loop and keep searching.
+      d_look_ahead_remaining--;
+    }
+    
+    // Every iteration of the loop, write debugging signal out if
+    // connected:
+    if (output_items.size() == 2) {
+      float *sigout = (float *) output_items[1];
+      sigout[i] = d_avg;
+    }
+  } // loop
+  
+  if (!d_found) 
+    return noutput_items;
+  
+  // else if detected presence, keep searching during the next call to work.
+  int tmp = d_peak_ind;
+  d_peak_ind = 1;
+  
+  return tmp - 1; 
+}
+
+
diff --git a/gnuradio-core/src/lib/general/gr_peak_detector2_fb.h b/gnuradio-core/src/lib/general/gr_peak_detector2_fb.h
new file mode 100644 (file)
index 0000000..e20c6c0
--- /dev/null
@@ -0,0 +1,108 @@
+/* -*- 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_gr_peak_detector2_FB_H
+#define INCLUDED_gr_peak_detector2_FB_H
+
+#include <gr_sync_block.h>
+
+class gr_peak_detector2_fb;
+typedef boost::shared_ptr<gr_peak_detector2_fb> gr_peak_detector2_fb_sptr;
+
+gr_peak_detector2_fb_sptr gr_make_peak_detector2_fb (float threshold_factor_rise = 7,
+                                                    int look_ahead = 1000,
+                                                    float alpha = 0.001);
+
+/*!
+ * \brief Detect the peak of a signal
+ * \ingroup block
+ *
+ * If a peak is detected, this block outputs a 1, 
+ * or it outputs 0's.  A separate debug output may be connected, to
+ * view the internal EWMA described below.
+ *
+ * \param threshold_factor_rise The threshold factor determins when a peak
+ *        is present. An EWMA average of the signal is calculated and when the 
+ *        value of the signal goes over threshold_factor_rise*average, we
+ *        call the peak.
+ * \param look_ahead The look-ahead value is used when the threshold is
+ *        found to locate the peak within this range.
+ * \param alpha The gain value of a single-pole moving average filter
+ */
+
+class gr_peak_detector2_fb : public gr_sync_block
+{
+  friend gr_peak_detector2_fb_sptr 
+  gr_make_peak_detector2_fb (float threshold_factor_rise, int look_ahead, float alpha);
+  
+  gr_peak_detector2_fb (float threshold_factor_rise, int look_ahead, float alpha);
+  
+private:
+  float d_threshold_factor_rise;
+  int d_look_ahead;
+  int d_look_ahead_remaining;
+  int d_peak_ind;
+  float d_peak_val;
+  float d_alpha;
+  float d_avg;
+  bool d_found;
+  
+public:
+  
+  /*! \brief Set the threshold factor value for the rise time
+   *  \param thr new threshold factor
+   */
+  void set_threshold_factor_rise(float thr) { d_threshold_factor_rise = thr; }
+  
+  /*! \brief Set the look-ahead factor
+   *  \param look new look-ahead factor
+   */
+  void set_look_ahead(int look) { d_look_ahead = look; }
+  
+  /*! \brief Set the running average alpha
+   *  \param alpha new alpha for running average
+   */
+  void set_alpha(int alpha) { d_alpha = alpha; }
+  
+  /*! \brief Get the threshold factor value for the rise time
+   *  \return threshold factor
+   */
+  float threshold_factor_rise() { return d_threshold_factor_rise; }
+  
+  /*! \brief Get the look-ahead factor value
+   *  \return look-ahead factor
+   */
+  int look_ahead() { return d_look_ahead; }
+  
+  /*! \brief Get the alpha value of the running average
+   *  \return alpha
+   */
+  float alpha() { return d_alpha; }
+  
+  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_peak_detector2_fb.i b/gnuradio-core/src/lib/general/gr_peak_detector2_fb.i
new file mode 100644 (file)
index 0000000..4b01435
--- /dev/null
@@ -0,0 +1,45 @@
+/* -*- 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 3, or (at your option)
+ * any later version.
+ * 
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+GR_SWIG_BLOCK_MAGIC(gr,peak_detector2_fb)
+  
+  gr_peak_detector2_fb_sptr gr_make_peak_detector2_fb (float threshold_factor_rise = 7,
+                                                      int look_ahead = 1000,
+                                                      float alpha=0.001);
+
+class gr_peak_detector2_fb : public gr_sync_block
+{
+private:
+  gr_peak_detector2_fb (float threshold_factor_rise, int look_ahead, float alpha);
+  
+public:
+  void set_threshold_factor_rise(float thr) { d_threshold_factor_rise = thr; }
+  void set_look_ahead(int look) { d_look_ahead = look; }
+  void set_alpha(int alpha) { d_avg_alpha = alpha; }
+  
+  float threshold_factor_rise() { return d_threshold_factor_rise; } 
+  int look_ahead() { return d_look_ahead; }
+  float alpha() { return d_avg_alpha; }
+};
+
+
index e3d83aeee97d719bc051ae32c453c78e44571da5..934326d8f36af2a5ed5e9d73bd62e68291a899f5 100644 (file)
@@ -40,6 +40,12 @@ grblkspython_PYTHON =                \
        cpm.py                  \
        nbfm_rx.py              \
        nbfm_tx.py              \
+       ofdm.py                 \
+       ofdm_receiver.py        \
+       ofdm_sync_fixed.py      \
+       ofdm_sync_pn.py         \
+       ofdm_sync_pnac.py       \
+       ofdm_sync_ml.py         \
        pkt.py                  \
        psk.py                  \
        qam.py                  \
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
new file mode 100644 (file)
index 0000000..491ef1a
--- /dev/null
@@ -0,0 +1,311 @@
+#!/usr/bin/env python
+#
+# Copyright 2006,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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import math
+from gnuradio import gr, ofdm_packet_utils
+import gnuradio.gr.gr_threading as _threading
+import psk, qam
+
+from gnuradio.blks2impl.ofdm_receiver import ofdm_receiver
+
+
+# /////////////////////////////////////////////////////////////////////////////
+#                   mod/demod with packets as i/o
+# /////////////////////////////////////////////////////////////////////////////
+
+class ofdm_mod(gr.hier_block2):
+    """
+    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, options, msgq_limit=2, pad_for_usrp=True):
+        """
+       Hierarchical block for sending packets
+
+        Packets to be sent are enqueued by calling send_pkt.
+        The output is the complex modulated signal at baseband.
+
+        @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
+        """
+
+       gr.hier_block2.__init__(self, "ofdm_mod",
+                               gr.io_signature(0, 0, 0),       # Input signature
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+        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)]
+
+        # 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
+        
+        mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
+        arity = mods[self._modulation]
+        
+        rot = 1
+        if self._modulation == "qpsk":
+            rot = (0.707+0.707j)
+            
+        if(self._modulation.find("psk") >= 0):
+            rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
+        elif(self._modulation.find("qam") >= 0):
+            rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+        #print rotated_const
+        self._pkt_input = gr.ofdm_mapper_bcv(rotated_const, msgq_limit,
+                                             options.occupied_tones, options.fft_length)
+        
+        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))
+        
+        self.connect((self._pkt_input, 0), (self.preambles, 0))
+        self.connect((self._pkt_input, 1), (self.preambles, 1))
+        self.connect(self.preambles, self.ifft, self.cp_adder, self.scale, self)
+        
+        if options.verbose:
+            self._print_verbage()
+
+        if options.log:
+            self.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+                                                       "ofdm_mapper_c.dat"))
+            self.connect(self.preambles, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+                                                      "ofdm_preambles.dat"))
+            self.connect(self.ifft, gr.file_sink(gr.sizeof_gr_complex*options.fft_length,
+                                                 "ofdm_ifft_c.dat"))
+            self.connect(self.cp_adder, gr.file_sink(gr.sizeof_gr_complex,
+                                                     "ofdm_cp_adder_c.dat"))
+
+    def send_pkt(self, payload='', eof=False):
+        """
+        Send the payload.
+
+        @param payload: data to send
+        @type payload: string
+        """
+        if eof:
+            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, 1, 1, self._pad_for_usrp, whitening=True)
+            
+            #print "pkt =", string_to_hex_list(pkt)
+            msg = gr.message_from_string(pkt)
+        self._pkt_input.msgq().insert_tail(msg)
+
+    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, qpsk, 8psk, qam{16,64}) [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,
+                          help="set the number of occupied FFT bins [default=%default]")
+        expert.add_option("", "--cp-length", type="intx", default=128,
+                          help="set the number of bits in the cyclic prefix [default=%default]")
+    # Make a static method to call before instantiation
+    add_options = staticmethod(add_options)
+
+    def _print_verbage(self):
+        """
+        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 ofdm_demod(gr.hier_block2):
+    """
+    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.
+    """
+
+    def __init__(self, options, callback=None):
+        """
+       Hierarchical block for demodulating and deframing packets.
+
+       The input is the complex modulated signal at baseband.
+        Demodulated packets are sent to the handler.
+
+        @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
+       """
+       gr.hier_block2.__init__(self, "ofdm_demod",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
+
+        self._rcvd_pktq = gr.msg_queue()          # holds packets from the PHY
+
+        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        
+
+        # hard-coded known symbols
+        preambles = (ksfreq,)
+                     #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(self._fft_length, self._cp_length,
+                                       self._occupied_tones, self._snr, preambles,
+                                       options.log)
+
+        mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
+        arity = mods[self._modulation]
+        
+        rot = 1
+        if self._modulation == "qpsk":
+            rot = (0.707+0.707j)
+
+        if(self._modulation.find("psk") >= 0):
+            rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
+        elif(self._modulation.find("qam") >= 0):
+            rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
+        #print rotated_const
+        self.ofdm_demod = gr.ofdm_frame_sink(rotated_const, range(arity),
+                                             self._rcvd_pktq,
+                                             self._occupied_tones,
+                                             0.25, 0.25*.25/4.0)
+
+        self.connect(self, self.ofdm_recv)
+        self.connect((self.ofdm_recv, 0), (self.ofdm_demod, 0))
+        self.connect((self.ofdm_recv, 1), (self.ofdm_demod, 1))
+
+        # added output signature to work around bug, though it might not be a bad
+        # thing to export, anyway
+        self.connect(self.ofdm_recv.chan_filt, self)
+
+        if options.log:
+            self.connect(self.ofdm_demod, gr.file_sink(gr.sizeof_gr_complex*self._occupied_tones, "ofdm_frame_sink_c.dat"))
+        else:
+            self.connect(self.ofdm_demod, gr.null_sink(gr.sizeof_gr_complex*self._occupied_tones))
+
+        if options.verbose:
+            self._print_verbage()
+            
+        self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
+
+    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,
+                          help="set the number of occupied FFT bins [default=%default]")
+        expert.add_option("", "--cp-length", type="intx", default=128,
+                          help="set the number of bits in the cyclic prefix [default=%default]")
+    # Make a static method to call before instantiation
+    add_options = staticmethod(add_options)
+
+    def _print_verbage(self):
+        """
+        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)
+
+
+
+class _queue_watcher_thread(_threading.Thread):
+    def __init__(self, rcvd_pktq, callback):
+        _threading.Thread.__init__(self)
+        self.setDaemon(1)
+        self.rcvd_pktq = rcvd_pktq
+        self.callback = callback
+        self.keep_running = True
+        self.start()
+
+
+    def run(self):
+        while self.keep_running:
+            msg = self.rcvd_pktq.delete_head()
+            ok, payload = ofdm_packet_utils.unmake_packet(msg.to_string())
+            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/blks2impl/ofdm_receiver.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py
new file mode 100644 (file)
index 0000000..9592755
--- /dev/null
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+#
+# Copyright 2006, 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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import math
+from numpy import fft
+from gnuradio import gr
+from gnuradio.blks2impl.ofdm_sync_ml import ofdm_sync_ml
+from gnuradio.blks2impl.ofdm_sync_pn import ofdm_sync_pn
+from gnuradio.blks2impl.ofdm_sync_pnac import ofdm_sync_pnac
+from gnuradio.blks2impl.ofdm_sync_fixed import ofdm_sync_fixed
+
+class ofdm_receiver(gr.hier_block2):
+    """
+    Performs receiver synchronization on OFDM symbols.
+
+    The receiver performs channel filtering as well as symbol, frequency, and phase synchronization.
+    The synchronization routines are available in three flavors: preamble correlator (Schmidl and Cox),
+    modifid preamble correlator with autocorrelation (not yet working), and cyclic prefix correlator
+    (Van de Beeks).
+    """
+
+    def __init__(self, fft_length, cp_length, occupied_tones, snr, ks, logging=False):
+        """
+       Hierarchical block for receiving OFDM symbols.
+
+       The input is the complex modulated signal at baseband.
+        Synchronized packets are sent back to the demodulator.
+
+        @param fft_length: total number of subcarriers
+        @type  fft_length: int
+        @param cp_length: length of cyclic prefix as specified in subcarriers (<= fft_length)
+        @type  cp_length: int
+        @param occupied_tones: number of subcarriers used for data
+        @type  occupied_tones: int
+        @param snr: estimated signal to noise ratio used to guide cyclic prefix synchronizer
+        @type  snr: float
+        @param ks: known symbols used as preambles to each packet
+        @type  ks: list of lists
+        @param logging: turn file logging on or off
+        @type  logging: bool
+       """
+
+       gr.hier_block2.__init__(self, "ofdm_receiver",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                                gr.io_signature2(2, 2, gr.sizeof_gr_complex*occupied_tones, gr.sizeof_char)) # Output signature
+
+        bw = (float(occupied_tones) / float(fft_length)) / 2.0
+        tb = bw*0.08
+        chan_coeffs = gr.firdes.low_pass (1.0,                     # gain
+                                          1.0,                     # sampling rate
+                                          bw+tb,                   # midpoint of trans. band
+                                          tb,                      # width of trans. band
+                                          gr.firdes.WIN_HAMMING)   # filter type
+        self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs)
+        
+        win = [1 for i in range(fft_length)]
+
+        zeros_on_left = int(math.ceil((fft_length - occupied_tones)/2.0))
+        zeros_on_right = fft_length - occupied_tones - zeros_on_left
+        ks0 = zeros_on_left*[0.0,]
+        ks0.extend(ks[0])
+        ks0.extend(zeros_on_right*[0.0,])
+        
+        ks0time = fft.ifft(ks0)
+        # ADD SCALING FACTOR
+        ks0time = ks0time.tolist()
+        
+        SYNC = "pn"
+        if SYNC == "ml":
+            self.ofdm_sync = ofdm_sync_ml(fft_length, cp_length, snr, logging)
+        elif SYNC == "pn":
+            self.ofdm_sync = ofdm_sync_pn(fft_length, cp_length, logging)
+        elif SYNC == "pnac":
+            self.ofdm_sync = ofdm_sync_pnac(fft_length, cp_length, ks0time)
+        elif SYNC == "fixed":
+            self.ofdm_sync = ofdm_sync_fixed(fft_length, cp_length, logging)
+                        
+        self.fft_demod = gr.fft_vcc(fft_length, True, win, True)
+        self.ofdm_frame_acq = gr.ofdm_frame_acquisition(occupied_tones, fft_length,
+                                                        cp_length, ks[0])
+
+        self.connect(self, self.chan_filt)
+        self.connect(self.chan_filt, self.ofdm_sync, self.fft_demod, (self.ofdm_frame_acq,0))
+        self.connect((self.ofdm_sync,1), (self.ofdm_frame_acq,1))
+        self.connect((self.ofdm_frame_acq,0), (self,0))
+        self.connect((self.ofdm_frame_acq,1), (self,1))
+
+        if logging:
+            self.connect(self.chan_filt, gr.file_sink(gr.sizeof_gr_complex, "chan_filt_c.dat"))
+            self.connect(self.fft_demod, gr.file_sink(gr.sizeof_gr_complex*fft_length, "fft_out_c.dat"))
+            self.connect(self.ofdm_frame_acq,
+                         gr.file_sink(gr.sizeof_gr_complex*occupied_tones, "ofdm_frame_acq_c.dat"))
+            self.connect((self.ofdm_frame_acq,1), gr.file_sink(1, "found_corr_b.dat"))
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py
new file mode 100644 (file)
index 0000000..74acc8f
--- /dev/null
@@ -0,0 +1,49 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import math
+from gnuradio import gr
+
+class ofdm_sync_fixed(gr.hier_block2):
+    def __init__(self, fft_length, cp_length, logging=False):
+
+        gr.hier_block2.__init__(self, "ofdm_sync_fixed",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                               gr.io_signature2(2, 2, gr.sizeof_gr_complex*fft_length, gr.sizeof_char)) # Output signature
+
+        # Use a fixed trigger point instead of sync block
+        symbol_length = fft_length + cp_length
+        data = (symbol_length)*[0,]
+        data[(symbol_length)-1] = 1
+        self.peak_trigger = gr.vector_source_b(data, True)
+        self.sampler = gr.ofdm_sampler(fft_length, symbol_length)
+
+        self.connect(self, (self.sampler,0))
+        self.connect(self.peak_trigger, (self.sampler,1))
+        self.connect(self.sampler, (self,0))
+        self.connect(self.peak_trigger, (self,1))
+
+        if logging:
+            self.connect(self.peak_trigger, gr.file_sink(gr.sizeof_char, "ofdm_sync_fixed-peaks_b.dat"))
+            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length,
+                                                    "ofdm_sync_fixed-sampler_c.dat"))
+
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py
new file mode 100644 (file)
index 0000000..a938526
--- /dev/null
@@ -0,0 +1,142 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import math
+from gnuradio import gr
+
+class ofdm_sync_ml(gr.hier_block2):
+    def __init__(self, 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.
+        '''
+
+        # FIXME: change the output signature
+        # should be the output of the divider (the normalized peaks) and
+        # the angle value out of the sample and hold block
+        # move sampler out of this block
+
+       gr.hier_block2.__init__(self, "ofdm_sync_ml",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex*fft_length)) # Output signature
+
+        self.input = gr.add_const_cc(0)
+
+        SNR = 10.0**(snr/10.0)
+        rho = SNR / (SNR + 1.0)
+        symbol_length = fft_length + cp_length
+
+        # ML Sync
+
+        # Energy Detection from ML Sync
+
+        self.connect(self, self.input)
+
+        # Create a delay line
+        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
+        self.connect(self.input, self.delay)
+
+        # magnitude squared blocks
+        self.magsqrd1 = gr.complex_to_mag_squared()
+        self.magsqrd2 = gr.complex_to_mag_squared()
+        self.adder = gr.add_ff()
+
+        moving_sum_taps = [rho/2 for i in range(cp_length)]
+        self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
+        
+        self.connect(self.input,self.magsqrd1)
+        self.connect(self.delay,self.magsqrd2)
+        self.connect(self.magsqrd1,(self.adder,0))
+        self.connect(self.magsqrd2,(self.adder,1))
+        self.connect(self.adder,self.moving_sum_filter)
+        
+
+        # Correlation from ML Sync
+        self.conjg = gr.conjugate_cc();
+        self.mixer = gr.multiply_cc();
+
+        movingsum2_taps = [1.0 for i in range(cp_length)]
+        self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
+        
+        # Correlator data handler
+        self.c2mag = gr.complex_to_mag()
+        self.angle = gr.complex_to_arg()
+        self.connect(self.input,(self.mixer,1))
+        self.connect(self.delay,self.conjg,(self.mixer,0))
+        self.connect(self.mixer,self.movingsum2,self.c2mag)
+        self.connect(self.movingsum2,self.angle)
+
+        # ML Sync output arg, need to find maximum point of this
+        self.diff = gr.sub_ff()
+        self.connect(self.c2mag,(self.diff,0))
+        self.connect(self.moving_sum_filter,(self.diff,1))
+
+        #ML measurements input to sampler block and detect
+        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.pk_detect = gr.peak_detector2_fb()
+        self.sample_and_hold = gr.sample_and_hold_ff()
+        self.nco = gr.frequency_modulator_fc(nco_sensitivity)
+        self.sigmix = gr.multiply_cc()
+
+        # Mix the signal with an NCO controlled by the sync loop
+        self.connect(self.input, (self.sigmix,0))
+        self.connect(self.nco, (self.sigmix,1))
+        self.connect(self.sigmix, (self.sampler,0))
+
+        # use the sync loop values to set the sampler and the NCO
+        #     self.diff = theta
+        #     self.angle = epsilon
+                          
+        self.connect(self.diff, self.pk_detect)
+
+        use_dpll = 1
+        if use_dpll:
+            self.dpll = gr.dpll_bb(float(symbol_length),0.01)
+            self.connect(self.pk_detect, self.dpll)
+            self.connect(self.dpll, (self.sampler,1))
+            self.connect(self.dpll, (self.sample_and_hold,1))
+        else:
+            self.connect(self.pk_detect, (self.sampler,1))
+            self.connect(self.pk_detect, (self.sample_and_hold,1))
+            
+        self.connect(self.angle, (self.sample_and_hold,0))
+        self.connect(self.sample_and_hold, self.nco)
+
+        self.connect(self.sampler, self)
+
+        if logging:
+            self.connect(self.diff, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-theta_f.dat"))
+            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-epsilon_f.dat"))
+            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-peaks_b.dat"))
+            if use_dpll:
+                self.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))
+
+            self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-sigmix_c.dat"))
+            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_sync_ml-sampler_c.dat"))
+            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_ml-sample_and_hold_f.dat"))
+            self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-nco_c.dat"))
+            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_ml-input_c.dat"))
+
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py
new file mode 100644 (file)
index 0000000..e3e0ad9
--- /dev/null
@@ -0,0 +1,146 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import math
+from numpy import fft
+from gnuradio import gr
+
+class ofdm_sync_pn(gr.hier_block2):
+    def __init__(self, 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.
+        """
+        
+       gr.hier_block2.__init__(self, "ofdm_sync_pn",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                               gr.io_signature2(2, 2, gr.sizeof_gr_complex*fft_length, gr.sizeof_char)) # Output signature
+
+        # 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.20, 0.20, 30, 0.001)
+        #self.pk_detect = gr.peak_detector2_fb()
+        #self.pk_detect = gr.threshold_detector_fb(0.5)
+        self.regen = gr.regenerate_bb(symbol_length)
+
+        # FIXME: If sampler doesn't get proper input, it can completely
+        # stall the flowgraph.
+        self.sampler = gr.ofdm_sampler(fft_length,symbol_length)
+
+        self.connect(self, self.input)
+        
+        self.connect(self.input, self.delay)
+        self.connect(self.input, (self.corr,0))
+        self.connect(self.delay, self.conjg)
+        self.connect(self.conjg, (self.corr,1))
+        self.connect(self.corr, self.moving_sum_filter)
+        self.connect(self.moving_sum_filter, self.c2mag)
+        self.connect(self.moving_sum_filter, self.angle)
+        self.connect(self.angle, (self.sample_and_hold,0))
+        self.connect(self.sample_and_hold, self.nco)
+
+        self.connect(self.input, (self.sigmix,0))
+        self.connect(self.nco, (self.sigmix,1))
+        self.connect(self.sigmix, (self.sampler,0))
+
+        self.connect(self.input, self.inputmag2, self.inputmovingsum)
+        self.connect(self.inputmovingsum, (self.square,0))
+        self.connect(self.inputmovingsum, (self.square,1))
+        self.connect(self.square, (self.normalize,1))
+        self.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.connect(self.normalize, self.matched_filter)
+        
+        self.connect(self.matched_filter, self.sub1, self.pk_detect)
+        self.connect(self.pk_detect, self.regen)
+        self.connect(self.regen, (self.sampler,1))
+        self.connect(self.pk_detect, (self.sample_and_hold,1))
+
+        # Set output from sampler
+        self.connect(self.sampler, (self,0))
+        self.connect(self.pk_detect, (self,1))
+
+        if logging:
+            self.connect(self.matched_filter, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-mf_f.dat"))
+            self.connect(self.normalize, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-theta_f.dat"))
+            self.connect(self.angle, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-epsilon_f.dat"))
+            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-peaks_b.dat"))
+            self.connect(self.regen, gr.file_sink(gr.sizeof_char, "ofdm_sync_pn-regen_b.dat"))
+            self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-sigmix_c.dat"))
+            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length, "ofdm_sync_pn-sampler_c.dat"))
+            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float, "ofdm_sync_pn-sample_and_hold_f.dat"))
+            self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-nco_c.dat"))
+            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex, "ofdm_sync_pn-input_c.dat"))
+
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py
new file mode 100644 (file)
index 0000000..5c16a57
--- /dev/null
@@ -0,0 +1,131 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import math
+from numpy import fft
+from gnuradio import gr
+
+class ofdm_sync_pnac(gr.hier_block2):
+    def __init__(self, fft_length, cp_length, ks):
+        
+        # FIXME: change the output signature
+        # should be the output of the divider (the normalized peaks) and
+        # the angle value out of the sample and hold block
+        # move sampler out of this block
+
+       gr.hier_block2.__init__(self, "ofdm_sync_pnac",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex*fft_length)) # Output signature
+
+            
+        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.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.connect(self, self.input)
+        self.connect(self.input, self.crosscorr_filter)
+        self.connect(self.crosscorr_filter, self.delay)
+        self.connect(self.crosscorr_filter, (self.corr,0))
+        self.connect(self.delay, self.conjg)
+        self.connect(self.conjg, (self.corr,1))
+        self.connect(self.corr, self.moving_sum_filter)
+        self.connect(self.moving_sum_filter, self.c2mag)
+        self.connect(self.moving_sum_filter, self.angle)
+        self.connect(self.angle, (self.sample_and_hold,0))
+        self.connect(self.sample_and_hold, self.nco)
+
+        self.connect(self.input, (self.sigmix,0))
+        self.connect(self.nco, (self.sigmix,1))
+        self.connect(self.sigmix, (self.sampler,0))
+
+        self.connect(self.input, self.inputmag2, self.inputmovingsum)
+        self.connect(self.inputmovingsum, (self.square,0))
+        self.connect(self.inputmovingsum, (self.square,1))
+        self.connect(self.square, (self.normalize,1))
+        self.connect(self.c2mag, (self.normalize,0))
+        self.connect(self.normalize, self.sub1, self.pk_detect)
+
+        self.connect(self.pk_detect, (self.sampler,1))
+        self.connect(self.pk_detect, (self.sample_and_hold,1))
+            
+        self.connect(self.sampler, self)
+
+        if 1:
+            self.connect(self.normalize, gr.file_sink(gr.sizeof_float,
+                                                      "ofdm_sync_pnac-theta_f.dat"))
+            self.connect(self.angle, gr.file_sink(gr.sizeof_float,
+                                                  "ofdm_sync_pnac-epsilon_f.dat"))
+            self.connect(self.pk_detect, gr.file_sink(gr.sizeof_char,
+                                                      "ofdm_sync_pnac-peaks_b.dat"))
+            self.connect(self.sigmix, gr.file_sink(gr.sizeof_gr_complex,
+                                                   "ofdm_sync_pnac-sigmix_c.dat"))
+            self.connect(self.sampler, gr.file_sink(gr.sizeof_gr_complex*fft_length,
+                                                    "ofdm_sync_pnac-sampler_c.dat"))
+            self.connect(self.sample_and_hold, gr.file_sink(gr.sizeof_float,
+                                                            "ofdm_sync_pnac-sample_and_hold_f.dat"))
+            self.connect(self.nco, gr.file_sink(gr.sizeof_gr_complex,
+                                                "ofdm_sync_pnac-nco_c.dat"))
+            self.connect(self.input, gr.file_sink(gr.sizeof_gr_complex,
+                                                  "ofdm_sync_pnac-input_c.dat"))
index b75fade58dca1bef63a06593d6934255a84deda4..74fa098d46c23d98a4ec5272818058985f0b02fa 100644 (file)
@@ -40,12 +40,6 @@ grblkspython_PYTHON =                \
        cpm.py                  \
        nbfm_rx.py              \
        nbfm_tx.py              \
-       ofdm.py                 \
-       ofdm_receiver.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.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py
deleted file mode 100644 (file)
index b040d8c..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-
-#
-# Copyright 2006,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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import math
-from numpy import fft
-from gnuradio import gr, ofdm_packet_utils
-import gnuradio.gr.gr_threading as _threading
-import psk, qam
-
-from gnuradio.blksimpl.ofdm_receiver import ofdm_receiver
-
-
-# /////////////////////////////////////////////////////////////////////////////
-#                   mod/demod with packets as i/o
-# /////////////////////////////////////////////////////////////////////////////
-
-class ofdm_mod(gr.hier_block):
-    """
-    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):
-        """
-       Hierarchical block for sending packets
-
-        Packets to be sent are enqueued by calling send_pkt.
-        The output is the complex modulated signal at baseband.
-
-       @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
-        """
-
-        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)]
-
-        # 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
-        
-        mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
-        arity = mods[self._modulation]
-        
-        rot = 1
-        if self._modulation == "qpsk":
-            rot = (0.707+0.707j)
-            
-        if(self._modulation.find("psk") >= 0):
-            rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
-        elif(self._modulation.find("qam") >= 0):
-            rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
-        #print rotated_const
-        self._pkt_input = gr.ofdm_mapper_bcv(rotated_const, msgq_limit,
-                                                 options.occupied_tones, options.fft_length)
-        
-        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 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)
-
-    def send_pkt(self, payload='', eof=False):
-        """
-        Send the payload.
-
-        @param payload: data to send
-        @type payload: string
-        """
-        if eof:
-            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, 1, 1, self._pad_for_usrp, whitening=True)
-            
-            #print "pkt =", string_to_hex_list(pkt)
-            msg = gr.message_from_string(pkt)
-        self._pkt_input.msgq().insert_tail(msg)
-
-    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,
-                          help="set the number of occupied FFT bins [default=%default]")
-        expert.add_option("", "--cp-length", type="intx", default=128,
-                          help="set the number of bits in the cyclic prefix [default=%default]")
-    # Make a static method to call before instantiation
-    add_options = staticmethod(add_options)
-
-    def _print_verbage(self):
-        """
-        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 ofdm_demod(gr.hier_block):
-    """
-    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.
-    """
-
-    def __init__(self, fg, options, callback=None):
-        """
-       Hierarchical block for demodulating and deframing packets.
-
-       The input is the complex modulated signal at baseband.
-        Demodulated packets are sent to the handler.
-
-       @param fg: flow graph
-       @type fg: flow graph
-        @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
-
-        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,])
-        
-        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)
-
-        mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256}
-        arity = mods[self._modulation]
-        
-        rot = 1
-        if self._modulation == "qpsk":
-            rot = (0.707+0.707j)
-
-        if(self._modulation.find("psk") >= 0):
-            rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity])
-        elif(self._modulation.find("qam") >= 0):
-            rotated_const = map(lambda pt: pt * rot, qam.constellation[arity])
-        #print rotated_const
-        self.ofdm_demod = gr.ofdm_frame_sink(rotated_const, range(arity),
-                                             self._rcvd_pktq,
-                                             self._occupied_tones)
-        
-        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 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,
-                          help="set the number of occupied FFT bins [default=%default]")
-        expert.add_option("", "--cp-length", type="intx", default=128,
-                          help="set the number of bits in the cyclic prefix [default=%default]")
-    # Make a static method to call before instantiation
-    add_options = staticmethod(add_options)
-
-    def _print_verbage(self):
-        """
-        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)
-
-
-
-class _queue_watcher_thread(_threading.Thread):
-    def __init__(self, rcvd_pktq, callback):
-        _threading.Thread.__init__(self)
-        self.setDaemon(1)
-        self.rcvd_pktq = rcvd_pktq
-        self.callback = callback
-        self.keep_running = True
-        self.start()
-
-
-    def run(self):
-        while self.keep_running:
-            msg = self.rcvd_pktq.delete_head()
-            ok, payload = ofdm_packet_utils.unmake_packet(msg.to_string())
-            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
deleted file mode 100644 (file)
index d16d2e2..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2006, 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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import math
-from gnuradio import gr
-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, ks, logging=False):
-        self.fg = fg
-
-        bw = (float(occupied_tones) / float(fft_length)) / 2.0
-        tb = bw*0.08
-        chan_coeffs = gr.firdes.low_pass (1.0,                     # gain
-                                          1.0,                     # sampling rate
-                                          bw+tb,                   # midpoint of trans. band
-                                          tb,                      # width of trans. band
-                                          gr.firdes.WIN_HAMMING)   # filter type
-        self.chan_filt = gr.fft_filter_ccc(1, chan_coeffs)
-        
-        win = [1 for i in range(fft_length)]
-
-        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, ks[1], ks[2])
-
-        self.fg.connect(self.chan_filt, self.ofdm_sync, self.fft_demod, self.ofdm_corr)
-        
-        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"))
-            self.fg.connect((self.ofdm_corr,1), gr.file_sink(1, "found_corr_b.dat"))
-
-        gr.hier_block.__init__(self, fg, self.chan_filt, self.ofdm_corr)
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py
deleted file mode 100644 (file)
index b56f656..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import 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_ml.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py
deleted file mode 100644 (file)
index d58f56c..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import math
-from gnuradio import gr
-
-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)
-        rho = SNR / (SNR + 1.0)
-        symbol_length = fft_length + cp_length
-
-        # ML Sync
-
-        # Energy Detection from ML Sync
-
-        # Create a delay line
-        self.delay = gr.delay(gr.sizeof_gr_complex, fft_length)
-        self.fg.connect(self.input, self.delay)
-
-        # magnitude squared blocks
-        self.magsqrd1 = gr.complex_to_mag_squared()
-        self.magsqrd2 = gr.complex_to_mag_squared()
-        self.adder = gr.add_ff()
-
-        moving_sum_taps = [rho/2 for i in range(cp_length)]
-        self.moving_sum_filter = gr.fir_filter_fff(1,moving_sum_taps)
-        
-        self.fg.connect(self.input,self.magsqrd1)
-        self.fg.connect(self.delay,self.magsqrd2)
-        self.fg.connect(self.magsqrd1,(self.adder,0))
-        self.fg.connect(self.magsqrd2,(self.adder,1))
-        self.fg.connect(self.adder,self.moving_sum_filter)
-        
-
-        # Correlation from ML Sync
-        self.conjg = gr.conjugate_cc();
-        self.mixer = gr.multiply_cc();
-
-        movingsum2_taps = [1.0 for i in range(cp_length)]
-        self.movingsum2 = gr.fir_filter_ccf(1,movingsum2_taps)
-        
-        # Correlator data handler
-        self.c2mag = gr.complex_to_mag()
-        self.angle = gr.complex_to_arg()
-        self.fg.connect(self.input,(self.mixer,1))
-        self.fg.connect(self.delay,self.conjg,(self.mixer,0))
-        self.fg.connect(self.mixer,self.movingsum2,self.c2mag)
-        self.fg.connect(self.movingsum2,self.angle)
-
-        # ML Sync output arg, need to find maximum point of this
-        self.diff = gr.sub_ff()
-        self.fg.connect(self.c2mag,(self.diff,0))
-        self.fg.connect(self.moving_sum_filter,(self.diff,1))
-
-        #ML measurements input to sampler block and detect
-        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.sigmix = gr.multiply_cc()
-
-        # Mix the signal with an NCO controlled by the sync loop
-        self.fg.connect(self.input, (self.sigmix,0))
-        self.fg.connect(self.nco, (self.sigmix,1))
-        self.fg.connect(self.sigmix, (self.sampler,0))
-
-        # use the sync loop values to set the sampler and the NCO
-        #     self.diff = theta
-        #     self.angle = epsilon
-                          
-        self.fg.connect(self.diff, self.pk_detect)
-
-        use_dpll = 1
-        if use_dpll:
-            self.dpll = gr.dpll_bb(float(symbol_length),0.01)
-            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.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
deleted file mode 100644 (file)
index 5642586..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import 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
deleted file mode 100644 (file)
index e3774e3..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import 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/utils/README b/gnuradio-core/src/utils/README
new file mode 100644 (file)
index 0000000..0c4657b
--- /dev/null
@@ -0,0 +1,40 @@
+* gr_plot_*.py:
+These are a collection of Python scripts to enable viewing and analysis of files produced by GNU Radio flow graphs. Most of them work off complex data produced by digital waveforms.
+
+
+** gr_plot_float.py:
+Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file.
+
+By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples.
+
+
+
+** gr_plot_iq.py:
+Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file.
+
+By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples.
+
+
+
+** gr_plot_const.py:
+Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file.
+
+By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples.
+
+
+
+** gr_plot_fft_c.py:
+Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally).
+
+The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file).
+
+By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples.
+
+
+
+** gr_plot_fft_f.py:
+Takes a GNU Radio floating point binary file and displays the samples versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally).
+
+The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file).
+
+By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples.
diff --git a/gnuradio-core/src/utils/gr_plot_char.py b/gnuradio-core/src/utils/gr_plot_char.py
new file mode 100755 (executable)
index 0000000..6f799cd
--- /dev/null
@@ -0,0 +1,165 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import scipy
+from pylab import *
+from optparse import OptionParser
+
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft_c:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_f.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('key_press_event', self.click)
+        show()
+        
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()))
+        f = scipy.fromfile(self.hfile, dtype=scipy.int8, count=self.block_length)
+        #print "Read in %d items" % len(self.f)
+        if(len(f) == 0):
+            print "End of File"
+        else:
+            self.f = f
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.f))]
+        
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(8*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6])
+        self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_f = plot(self.time, self.f, 'bo-')
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+
+        draw()
+
+    def update_plots(self):
+        self.plot_f[0].set_data([self.time, self.f])
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+        draw()
+        
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 2*self.block_length ):
+            self.hfile.seek(-2*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
+def main():
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
+    (options, args) = parser.parse_args ()
+    if len(args) != 1:
+        parser.print_help()
+        raise SystemExit, 1
+    filename = args[0]
+
+    dc = draw_fft_c(filename, options)
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+    
index effda3e0cd851c6375e56b14246ce47fe568cc3b..bbcbb85cc26ff8263985a1560053548ac010fffe 100755 (executable)
 # Boston, MA 02110-1301, USA.
 # 
 
-import pylab, math
+import scipy
 from pylab import *
-import struct, sys
+from matplotlib.font_manager import fontManager, FontProperties
 from optparse import OptionParser
 
-import gr_read_binary
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
 
-class zoom:
-    def __init__(self, xdata, reals, imags, sp_iq, sp_const, plot_const, manager):
-        self.sp_iq = sp_iq
-        self.sp_const = sp_const
-        self.xaxis = xdata
-        self.reals = reals
-        self.imags = imags
-        self.plot_const = plot_const
-        self.manager = manager
+class draw_constellation:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.95, ("File: %s" % filename), weight="heavy", size=16)
+        self.text_file_pos = figtext(0.10, 0.90, "File Position: ", weight="heavy", size=16)
+        self.text_block    = figtext(0.40, 0.90, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=16)        
+        self.text_sr       = figtext(0.60, 0.90, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=16)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
 
         self.xlim = self.sp_iq.get_xlim()
-           
-    def __call__(self, event):
-        newxlim = self.sp_iq.get_xlim()
 
+        self.manager = get_current_fig_manager()
+        connect('draw_event', self.zoom)
+        connect('key_press_event', self.click)
+        show()
+
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//8))
+        iq = scipy.fromfile(self.hfile, dtype=scipy.complex64, count=self.block_length)
+        #print "Read in %d items" % len(iq)
+        if(len(iq) == 0):
+            print "End of File"
+        else:
+            self.reals = [r.real for r in iq]
+            self.imags = [i.imag for i in iq]
+
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))]
+            
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(16*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6])
+        self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-')
+        self.sp_iq.axis([min(self.time), max(self.time),
+                         1.5*min([min(self.reals), min(self.imags)]),
+                         1.5*max([max(self.reals), max(self.imags)])])
+
+        # Subplot for constellation plot
+        self.sp_const = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6])
+        self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_const = plot(self.reals, self.imags, 'bo')
+        self.sp_const.axis([-2, 2, -2, 2])
+
+        draw()
+
+    def update_plots(self):
+        self.plot_iq[0].set_data([self.time, self.reals])
+        self.plot_iq[1].set_data([self.time, self.imags])
+        self.sp_iq.axis([min(self.time), max(self.time),
+                         1.5*min([min(self.reals), min(self.imags)]),
+                         1.5*max([max(self.reals), max(self.imags)])])
+
+        self.plot_const[0].set_data([self.reals, self.imags])
+        self.sp_const.axis([-2, 2, -2, 2])
+        draw()
+        
+    def zoom(self, event):
+        newxlim = self.sp_iq.get_xlim()
         if(newxlim != self.xlim):
             self.xlim = newxlim
-            r = self.reals[int(self.xlim[0]) : int(self.xlim[1])]
-            i = self.imags[int(self.xlim[0]) : int(self.xlim[1])]
+            r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))]
+            i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))]
 
             self.plot_const[0].set_data(r, i)
             self.sp_const.axis([-2, 2, -2, 2])
             self.manager.canvas.draw()
+            draw()
+
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 16*self.block_length ):
+            self.hfile.seek(-16*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
             
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
 def main():
-    usage="%prog: [options] output_filename"
-    parser = OptionParser(conflict_handler="resolve", usage=usage)
-    parser.add_option("-s", "--size", type="int", default=None,
-                      help="Specify the number of points to plot [default=%default]")
-    parser.add_option("", "--skip", type="int", default=None,
-                      help="Specify the number of points to skip [default=%default]")
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time and the constellation plot (I vs. Q). You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
 
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
     (options, args) = parser.parse_args ()
     if len(args) != 1:
         parser.print_help()
         raise SystemExit, 1
     filename = args[0]
 
-    iq = gr_read_binary.read_complex_binary(filename)
-
-    if(options.skip is None):
-        options.skip = 0
-    
-    if((options.size is None) or ((options.skip+options.size) > len(iq[0]))):
-        options.size = len(iq[0]) - options.skip
-
-    reals = iq[0][options.skip : options.skip + options.size]
-    imags = iq[1][options.skip : options.skip + options.size]
-    x = range(options.skip, options.skip + options.size)
-    
-    # PLOT
-    f = figure(1, figsize=(16, 12), facecolor='w')
-    rcParams['xtick.labelsize'] = 16
-    rcParams['ytick.labelsize'] = 16
-
-    # Subplot for real and imaginary parts of signal
-    sp1 = f.add_subplot(2,1,1)
-    sp1.set_title(("I&Q"), fontsize=26, fontweight="bold")
-    sp1.set_xlabel("Time (s)", fontsize=20, fontweight="bold")
-    sp1.set_ylabel("Amplitude (V)", fontsize=20, fontweight="bold")
-    plot(x, reals, 'bo-', x, imags, 'ro-')
-
-    # Subplot for constellation plot
-    sp2 = f.add_subplot(2,1,2)
-    sp2.set_title(("Constellation"), fontsize=26, fontweight="bold")
-    sp2.set_xlabel("Inphase", fontsize=20, fontweight="bold")
-    sp2.set_ylabel("Qaudrature", fontsize=20, fontweight="bold")
-    p2 = plot(reals, imags, 'bo')
-    sp2.axis([-2, 2, -2, 2])
-    
-    manager = get_current_fig_manager()
-    zm = zoom(x, reals, imags, sp1, sp2, p2, manager)
-    connect('draw_event', zm)
-    
-    show()
+    dc = draw_constellation(filename, options)
 
 if __name__ == "__main__":
     try:
diff --git a/gnuradio-core/src/utils/gr_plot_fft_c.py b/gnuradio-core/src/utils/gr_plot_fft_c.py
new file mode 100755 (executable)
index 0000000..9245669
--- /dev/null
@@ -0,0 +1,221 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import scipy
+from pylab import *
+from optparse import OptionParser
+from scipy import fftpack
+from math import log10
+
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft_c:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_iq.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('draw_event', self.zoom)
+        connect('key_press_event', self.click)
+        show()
+        
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//8))
+        self.iq = scipy.fromfile(self.hfile, dtype=scipy.complex64, count=self.block_length)
+        #print "Read in %d items" % len(self.iq)
+        if(len(self.iq) == 0):
+            print "End of File"
+        else:
+            self.reals = [r.real for r in self.iq]
+            self.imags = [i.imag for i in self.iq]
+
+            self.iq_fft = self.dofft(self.iq)
+
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))]
+            self.freq = self.calc_freq(self.time, self.sample_rate)
+
+            
+    def dofft(self, iq):
+        N = len(iq)
+        iq_fft = fftpack.fftshift(scipy.fft(iq))       # fft and shift axis
+        iq_fft = [20*log10(abs(i/N)) for i in iq_fft]  # convert to decibels, adjust power
+        return iq_fft
+
+    def calc_freq(self, time, sample_rate):
+        N = len(time)
+        Fs = 1.0 / (max(time) - min(time))
+        Fn = 0.5 * sample_rate
+        freq = [-Fn + i*Fs for i in range(N)]
+        return freq
+        
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(16*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6])
+        self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-')
+        self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]),
+                             1.5*max([max(self.reals), max(self.imags)])])
+
+        # Subplot for constellation plot
+        self.sp_fft = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6])
+        self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_fft = plot(self.freq, self.iq_fft, '-bo')
+        self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10])
+        
+        draw()
+
+    def update_plots(self):
+        self.plot_iq[0].set_data([self.time, self.reals])
+        self.plot_iq[1].set_data([self.time, self.imags])
+        self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]),
+                             1.5*max([max(self.reals), max(self.imags)])])
+
+        self.plot_fft[0].set_data([self.freq, self.iq_fft])
+        self.sp_fft.set_ylim([min(self.iq_fft)-10, max(self.iq_fft)+10])
+
+        draw()
+        
+    def zoom(self, event):
+        newxlim = self.sp_iq.get_xlim()
+        if(newxlim != self.xlim):
+            self.xlim = newxlim
+            xmin = max(0, int(ceil(self.sample_rate*self.xlim[0])))
+            xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.iq))
+
+            iq = self.iq[xmin : xmax]
+            time = self.time[xmin : xmax]
+            
+            iq_fft = self.dofft(iq)
+            freq = self.calc_freq(time, self.sample_rate)
+            
+            self.plot_fft[0].set_data(freq, iq_fft)
+            self.sp_fft.axis([min(freq), max(freq),
+                              min(iq_fft)-10, max(iq_fft)+10])
+
+            draw()
+
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 16*self.block_length ):
+            self.hfile.seek(-16*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
+def main():
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
+    (options, args) = parser.parse_args ()
+    if len(args) != 1:
+        parser.print_help()
+        raise SystemExit, 1
+    filename = args[0]
+
+    dc = draw_fft_c(filename, options)
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+    
+
+
diff --git a/gnuradio-core/src/utils/gr_plot_fft_f.py b/gnuradio-core/src/utils/gr_plot_fft_f.py
new file mode 100755 (executable)
index 0000000..717efdf
--- /dev/null
@@ -0,0 +1,223 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import scipy
+from pylab import *
+from optparse import OptionParser
+from scipy import fftpack
+from math import log10
+
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft_f:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_f.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('draw_event', self.zoom)
+        connect('key_press_event', self.click)
+        show()
+        
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//4))
+        self.floats = scipy.fromfile(self.hfile, dtype=scipy.float32, count=self.block_length)
+        #print "Read in %d items" % len(self.floats)
+        if(len(self.floats) == 0):
+            print "End of File"
+        else:
+            self.f_fft = self.dofft(self.floats)
+
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.floats))]
+            self.freq = self.calc_freq(self.time, self.sample_rate)
+            
+    def dofft(self, f):
+        N = len(f)
+        f_fft = fftpack.fftshift(scipy.fft(f))       # fft and shift axis
+        f_dB = list()
+        for f in f_fft:
+            try:
+                f_dB.append(20*log10(abs(f/N)))  # convert to decibels, adjust power
+            except OverflowError:                # protect against taking log(0)
+                f = 1e-14                        # not sure if this is the best way to do this
+                f_dB.append(20*log10(abs(f/N)))
+                
+        return f_dB
+
+    def calc_freq(self, time, sample_rate):
+        N = len(time)
+        Fs = 1.0 / (max(time) - min(time))
+        Fn = 0.5 * sample_rate
+        freq = [-Fn + i*Fs for i in range(N)]
+        return freq
+        
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(16*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.4, 0.6])
+        self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_f = plot(self.time, self.floats, 'bo-')
+        self.sp_f.set_ylim([1.5*min(self.floats),
+                            1.5*max(self.floats)])
+
+        # Subplot for constellation plot
+        self.sp_fft = self.fig.add_subplot(2,2,1, position=[0.575, 0.2, 0.4, 0.6])
+        self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_fft.set_xlabel("Frequency (Hz)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_fft = plot(self.freq, self.f_fft, '-bo')
+        self.sp_fft.set_ylim([min(self.f_fft)-10, max(self.f_fft)+10])
+        
+        draw()
+
+    def update_plots(self):
+        self.plot_f[0].set_data([self.time, self.floats])
+        self.sp_f.set_ylim([1.5*min(self.floats),
+                            1.5*max(self.floats)])
+
+        self.plot_fft[0].set_data([self.freq, self.f_fft])
+        self.sp_fft.set_ylim([min(self.f_fft)-10, max(self.f_fft)+10])
+
+        draw()
+        
+    def zoom(self, event):
+        newxlim = self.sp_f.get_xlim()
+        if(newxlim != self.xlim):
+            self.xlim = newxlim
+            xmin = max(0, int(ceil(self.sample_rate*self.xlim[0])))
+            xmax = min(int(ceil(self.sample_rate*self.xlim[1])), len(self.floats))
+
+            f = self.floats[xmin : xmax]
+            time = self.time[xmin : xmax]
+            
+            f_fft = self.dofft(f)
+            freq = self.calc_freq(time, self.sample_rate)
+                        
+            self.plot_fft[0].set_data(freq, f_fft)
+            self.sp_fft.axis([min(freq), max(freq),
+                              min(f_fft)-10, max(f_fft)+10])
+
+            draw()
+
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 8*self.block_length ):
+            self.hfile.seek(-8*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
+def main():
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio floating point binary file and displays the sample data versus time as well as the frequency domain (FFT) plot. The y-axis values are plotted assuming volts as the amplitude of the I&Q streams and converted into dBm in the frequency domain (the 1/N power adjustment out of the FFT is performed internally). The script plots a certain block of data at a time, specified on the command line as -B or --block. This value defaults to 1000. The start position in the file can be set by specifying -s or --start and defaults to 0 (the start of the file). By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time and frequency axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
+    (options, args) = parser.parse_args ()
+    if len(args) != 1:
+        parser.print_help()
+        raise SystemExit, 1
+    filename = args[0]
+
+    dc = draw_fft_f(filename, options)
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+    
+
+
index e4043a64086d3837a7dbfa20fb0f1e8a3587f3e3..473326012dbb6a54ebba8b9917cd66e91159340f 100755 (executable)
 # Boston, MA 02110-1301, USA.
 # 
 
-import pylab, math
+import scipy
 from pylab import *
-import struct, sys
 from optparse import OptionParser
 
-import gr_read_binary
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft_c:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_f.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('key_press_event', self.click)
+        show()
+        
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//4))
+        f = scipy.fromfile(self.hfile, dtype=scipy.float32, count=self.block_length)
+        #print "Read in %d items" % len(self.f)
+        if(len(f) == 0):
+            print "End of File"
+        else:
+            self.f = f
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.f))]
+        
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(8*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6])
+        self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_f = plot(self.time, self.f, 'bo-')
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+
+        draw()
+
+    def update_plots(self):
+        self.plot_f[0].set_data([self.time, self.f])
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+        draw()
+        
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 8*self.block_length ):
+            self.hfile.seek(-8*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
 
 def main():
-    usage="%prog: [options] output_filename"
-    parser = OptionParser(conflict_handler="resolve", usage=usage)
-    parser.add_option("-s", "--size", type="int", default=None,
-                      help="Specify the number of points to plot [default=%default]")
-    parser.add_option("", "--skip", type="int", default=None,
-                      help="Specify the number of points to skip [default=%default]")
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
 
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
     (options, args) = parser.parse_args ()
     if len(args) != 1:
         parser.print_help()
         raise SystemExit, 1
     filename = args[0]
 
-    fl = gr_read_binary.read_float_binary(filename)
-
-    if(options.skip is None):
-        options.skip = 0
-    
-    if((options.size is None) or ((options.skip+options.size) > len(iq[0]))):
-        options.size = len(fl) - options.skip
-
-    x = range(options.skip, options.skip + options.size)
-    
-    # PLOT REAL AND IMAGINARY PARTS
-    
-    f = figure(1, figsize=(16, 12), facecolor='w')
-    rcParams['xtick.labelsize'] = 16
-    rcParams['ytick.labelsize'] = 16
-
-    sp1 = f.add_subplot(1,1,1)
-    sp1.set_title(("GNU Radio Float"), fontsize=26, fontweight="bold")
-    sp1.set_xlabel("Time (s)", fontsize=20, fontweight="bold")
-    sp1.set_ylabel("Amplitude (V)", fontsize=20, fontweight="bold")
-    plot(x, fl, 'bo-')
-
-    show()
+    dc = draw_fft_c(filename, options)
 
 if __name__ == "__main__":
     try:
@@ -71,5 +163,3 @@ if __name__ == "__main__":
     except KeyboardInterrupt:
         pass
     
-
-
diff --git a/gnuradio-core/src/utils/gr_plot_int.py b/gnuradio-core/src/utils/gr_plot_int.py
new file mode 100755 (executable)
index 0000000..ef2c717
--- /dev/null
@@ -0,0 +1,165 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import scipy
+from pylab import *
+from optparse import OptionParser
+
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft_c:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_f.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('key_press_event', self.click)
+        show()
+        
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//4))
+        f = scipy.fromfile(self.hfile, dtype=scipy.int32, count=self.block_length)
+        #print "Read in %d items" % len(self.f)
+        if(len(f) == 0):
+            print "End of File"
+        else:
+            self.f = f
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.f))]
+        
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(8*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6])
+        self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_f = plot(self.time, self.f, 'bo-')
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+
+        draw()
+
+    def update_plots(self):
+        self.plot_f[0].set_data([self.time, self.f])
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+        draw()
+        
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 8*self.block_length ):
+            self.hfile.seek(-8*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
+def main():
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
+    (options, args) = parser.parse_args ()
+    if len(args) != 1:
+        parser.print_help()
+        raise SystemExit, 1
+    filename = args[0]
+
+    dc = draw_fft_c(filename, options)
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+    
index db5d99a114bd7246e387d3ec13d051e0f2b56668..1bb24517eccaeb8093a1e9faae279066916979ff 100755 (executable)
 # Boston, MA 02110-1301, USA.
 # 
 
-import pylab, math
+import scipy
 from pylab import *
-import struct, sys
 from optparse import OptionParser
 
-import gr_read_binary
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_iq.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('key_press_event', self.click)
+        show()
+
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//8))
+        self.iq = scipy.fromfile(self.hfile, dtype=scipy.complex64, count=self.block_length)
+        #print "Read in %d items" % len(self.iq)
+        if(len(self.iq) == 0):
+            print "End of File"
+        else:
+            self.reals = [r.real for r in self.iq]
+            self.imags = [i.imag for i in self.iq]
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.reals))]
+            
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(16*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_iq = self.fig.add_subplot(2,1,1, position=[0.075, 0.14, 0.85, 0.67])
+        self.sp_iq.set_title(("I&Q"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_iq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_iq.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_iq = plot(self.time, self.reals, 'bo-', self.time, self.imags, 'ro-')
+        self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]),
+                             1.5*max([max(self.reals), max(self.imags)])])
+        
+        draw()
+
+    def update_plots(self):
+        self.plot_iq[0].set_data([self.time, self.reals])
+        self.plot_iq[1].set_data([self.time, self.imags])
+        self.sp_iq.set_ylim([1.5*min([min(self.reals), min(self.imags)]),
+                             1.5*max([max(self.reals), max(self.imags)])])
+        draw()
+        
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 16*self.block_length ):
+            self.hfile.seek(-16*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
 
 def main():
-    usage="%prog: [options] output_filename"
-    parser = OptionParser(conflict_handler="resolve", usage=usage)
-    parser.add_option("-s", "--size", type="int", default=None,
-                      help="Specify the number of points to plot [default=%default]")
-    parser.add_option("", "--skip", type="int", default=None,
-                      help="Specify the number of points to skip [default=%default]")
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio complex binary file and displays the I&Q data versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
 
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
     (options, args) = parser.parse_args ()
     if len(args) != 1:
         parser.print_help()
         raise SystemExit, 1
     filename = args[0]
 
-    iq = gr_read_binary.read_complex_binary(filename)
-
-    if(options.skip is None):
-        options.skip = 0
-    
-    if((options.size is None) or ((options.skip+options.size) > len(iq[0]))):
-        options.size = len(iq[0]) - options.skip
-
-    reals = iq[0][options.skip : options.skip + options.size]
-    imags = iq[1][options.skip : options.skip + options.size]
-    x = range(options.skip, options.skip + options.size)
-    
-    # PLOT REAL AND IMAGINARY PARTS
-    
-    f = figure(1, figsize=(16, 12), facecolor='w')
-    rcParams['xtick.labelsize'] = 16
-    rcParams['ytick.labelsize'] = 16
-
-    sp1 = f.add_subplot(1,1,1)
-    sp1.set_title(("I&Q"), fontsize=26, fontweight="bold")
-    sp1.set_xlabel("Time (s)", fontsize=20, fontweight="bold")
-    sp1.set_ylabel("Amplitude (V)", fontsize=20, fontweight="bold")
-    plot(x, reals, 'bo-', x, imags, 'ro-')
-
-    show()
+    dc = draw_fft(filename, options)
 
 if __name__ == "__main__":
     try:
diff --git a/gnuradio-core/src/utils/gr_plot_short.py b/gnuradio-core/src/utils/gr_plot_short.py
new file mode 100755 (executable)
index 0000000..0bb091d
--- /dev/null
@@ -0,0 +1,165 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import scipy
+from pylab import *
+from optparse import OptionParser
+
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_fft_c:
+    def __init__(self, filename, options):
+        self.hfile = open(filename, "r")
+        self.block_length = options.block
+        self.start = options.start
+        self.sample_rate = options.sample_rate
+
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+
+        # Setup PLOT
+        self.fig = figure(1, figsize=(16, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+        
+        self.text_file     = figtext(0.10, 0.94, ("File: %s" % filename), weight="heavy", size=self.text_size)
+        self.text_file_pos = figtext(0.10, 0.88, "File Position: ", weight="heavy", size=self.text_size)
+        self.text_block    = figtext(0.40, 0.88, ("Block Size: %d" % self.block_length),
+                                     weight="heavy", size=self.text_size)
+        self.text_sr       = figtext(0.60, 0.88, ("Sample Rate: %.2f" % self.sample_rate),
+                                     weight="heavy", size=self.text_size)
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_f.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        connect('key_press_event', self.click)
+        show()
+        
+    def get_data(self):
+        self.text_file_pos.set_text("File Position: %d" % (self.hfile.tell()//2))
+        f = scipy.fromfile(self.hfile, dtype=scipy.int16, count=self.block_length)
+        #print "Read in %d items" % len(self.f)
+        if(len(f) == 0):
+            print "End of File"
+        else:
+            self.f = f
+            self.time = [i*(1/self.sample_rate) for i in range(len(self.f))]
+        
+    def make_plots(self):
+        # if specified on the command-line, set file pointer
+        self.hfile.seek(8*self.start, 1)
+
+        self.get_data()
+        
+        # Subplot for real and imaginary parts of signal
+        self.sp_f = self.fig.add_subplot(2,1,1, position=[0.075, 0.2, 0.875, 0.6])
+        self.sp_f.set_title(("Amplitude"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_f.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_f.set_ylabel("Amplitude (V)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_f = plot(self.time, self.f, 'bo-')
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+
+        draw()
+
+    def update_plots(self):
+        self.plot_f[0].set_data([self.time, self.f])
+        self.sp_f.set_ylim([1.5*min(self.f),
+                            1.5*max(self.f)])
+        draw()
+        
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        if(self.hfile.tell() >= 4*self.block_length ):
+            self.hfile.seek(-4*self.block_length, 1)
+        else:
+            self.hfile.seek(-self.hfile.tell(),1)
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
+def main():
+    usage="%prog: [options] input_filename"
+    description = "Takes a GNU Radio floating point binary file and displays the samples versus time. You can set the block size to specify how many points to read in at a time and the start position in the file. By default, the system assumes a sample rate of 1, so in time, each sample is plotted versus the sample number. To set a true time axis, set the sample rate (-R or --sample-rate) to the sample rate used when capturing the samples."
+
+    parser = OptionParser(conflict_handler="resolve", usage=usage, description=description)
+    parser.add_option("-B", "--block", type="int", default=1000,
+                      help="Specify the block size [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify where to start in the file [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
+    (options, args) = parser.parse_args ()
+    if len(args) != 1:
+        parser.print_help()
+        raise SystemExit, 1
+    filename = args[0]
+
+    dc = draw_fft_c(filename, options)
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+    
diff --git a/gnuradio-core/src/utils/gr_read_binary.py b/gnuradio-core/src/utils/gr_read_binary.py
deleted file mode 100644 (file)
index ae91b44..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/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 3, or (at your option)
-# any later version.
-# 
-# GNU Radio is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-# 
-# You should have received a copy of the GNU General Public License
-# along with GNU Radio; see the file COPYING.  If not, write to
-# the Free Software Foundation, Inc., 51 Franklin Street,
-# Boston, MA 02110-1301, USA.
-# 
-
-import struct
-
-def read_binary(filename, type):
-    n = struct.calcsize(type)
-    f = open(filename, 'rb')
-    out = list()
-    lin = f.read(n)
-    while(len(lin) == n):
-        cp = struct.unpack(type, lin)
-        out.append(cp)
-        lin = f.read(n)
-    return out
-
-def read_char_binary(filename):
-    return read_binary(filename, 'c')
-
-def read_float_binary(filename):
-    return read_binary(filename, 'f')
-
-def read_int_binary(filename):
-    return read_binary(filename, 'i')
-
-def read_short_binary(filename):
-    return read_binary(filename, 'h')
-
-def read_complex_binary(filename):
-    n = struct.calcsize('ff')
-    f = open(filename, 'rb')
-    re = list()
-    im = list()
-    lin = f.read(n)
-    while(len(lin) == n):
-        cp = struct.unpack('ff', lin)
-        re.append(cp[0])
-        im.append(cp[1])
-        lin = f.read(n)
-    return (re, im)
-
-
index 690c57d600938b6fe2496402074712d027d0d4bf..5861da16c7a089370423921ebda44b5cd4cd1da5 100755 (executable)
@@ -20,7 +20,7 @@
 # Boston, MA 02110-1301, USA.
 # 
 
-from gnuradio import gr, blks
+from gnuradio import gr, blks2
 from gnuradio import eng_notation
 from gnuradio.eng_option import eng_option
 from optparse import OptionParser
@@ -32,9 +32,9 @@ from transmit_path import transmit_path
 from receive_path import receive_path
 
 
-class my_graph(gr.flow_graph):
+class my_top_block(gr.top_block):
     def __init__(self, callback, options):
-        gr.flow_graph.__init__(self)
+        gr.top_block.__init__(self)
 
         if not options.channel_off:
             SNR = 10.0**(options.snr/10.0)
@@ -67,22 +67,24 @@ class my_graph(gr.flow_graph):
 
         z = [0,]
         self.zeros = gr.vector_source_c(z, True)
-        self.txpath = transmit_path(self, options)
+        self.txpath = transmit_path(options)
 
-        self.mux = gr.stream_mux(gr.sizeof_gr_complex, stream_size)
+        #self.mux = gr.stream_mux(gr.sizeof_gr_complex, stream_size)
         self.throttle = gr.throttle(gr.sizeof_gr_complex, options.sample_rate)
-        self.channel = blks.channel_model(self, noise_voltage, frequency_offset,
-                                          options.clockrate_ratio, taps)
-        self.rxpath = receive_path(self, callback, options)
+        self.channel = blks2.channel_model(noise_voltage, frequency_offset,
+                                           options.clockrate_ratio, taps)
+        self.rxpath = receive_path(callback, options)
                 
-        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.zeros, (self.mux,0))
+        #self.connect(self.txpath, (self.mux,1))
+        #self.connect(self.mux, self.throttle, self.channel, self.rxpath)
+        #self.connect(self.mux, self.throttle, self.rxpath)
+        self.connect(self.txpath, self.throttle, self.channel, self.rxpath)
+        
         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"))
+            #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
@@ -95,7 +97,7 @@ def main():
     n_right = 0
         
     def send_pkt(payload='', eof=False):
-        return fg.txpath.send_pkt(payload, eof)
+        return tb.txpath.send_pkt(payload, eof)
         
     def rx_callback(ok, payload):
         global n_rcvd, n_right
@@ -139,19 +141,19 @@ def main():
 
     transmit_path.add_options(parser, expert_grp)
     receive_path.add_options(parser, expert_grp)
-    blks.ofdm_mod.add_options(parser, expert_grp)
-    blks.ofdm_demod.add_options(parser, expert_grp)
+    blks2.ofdm_mod.add_options(parser, expert_grp)
+    blks2.ofdm_demod.add_options(parser, expert_grp)
     
     (options, args) = parser.parse_args ()
        
     # build the graph
-    fg = my_graph(rx_callback, options)
+    tb = my_top_block(rx_callback, options)
     
     r = gr.enable_realtime_scheduling()
     #    if r != gr.RT_OK:
     #        print "Warning: failed to enable realtime scheduling"
-        
-    fg.start()                       # start flow graph
+    
+    tb.start()                       # start flow graph
     
     # generate and send packets
     nbytes = int(1e6 * options.megabytes)
@@ -173,7 +175,7 @@ def main():
         pktno += 1
         
     send_pkt(eof=True)
-    fg.wait()                       # wait for it to finish
+    tb.wait()                       # wait for it to finish
 
 
 if __name__ == '__main__':
index a8c20d39064f76ca283816072a9cb2f9fd8221d6..cb9649a6c8cc10847e47912a43b9ece286757c26 100755 (executable)
 # Boston, MA 02110-1301, USA.
 # 
 
-from gnuradio import gr, blks
+from gnuradio import gr, blks2
 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
+import struct, sys
 
 # from current dir
 from receive_path import receive_path
 import fusb_options
 
-class usrp_graph(gr.flow_graph):
+class my_top_block(gr.top_block):
     def __init__(self, callback, options):
-        gr.flow_graph.__init__(self)
+        gr.top_block.__init__(self)
 
         self._rx_freq            = options.rx_freq         # receiver's center frequency
         self._rx_gain            = options.rx_gain         # receiver's gain
@@ -61,10 +61,10 @@ class usrp_graph(gr.flow_graph):
         self.set_auto_tr(True)                 # enable Auto Transmit/Receive switching
 
         # Set up receive path
-        self.rxpath = receive_path(self, callback, options)
+        self.rxpath = receive_path(callback, options)
 
         self.connect(self.u, self.rxpath)
-
+        
     def _setup_usrp_source(self):
         self.u = usrp.source_c (fusb_block_size=self._fusb_block_size,
                                 fusb_nblocks=self._fusb_nblocks)
@@ -187,23 +187,23 @@ def main():
     parser.add_option("","--discontinuous", action="store_true", default=False,
                       help="enable discontinuous")
 
-    usrp_graph.add_options(parser, expert_grp)
+    my_top_block.add_options(parser, expert_grp)
     receive_path.add_options(parser, expert_grp)
-    blks.ofdm_mod.add_options(parser, expert_grp)
-    blks.ofdm_demod.add_options(parser, expert_grp)
+    blks2.ofdm_mod.add_options(parser, expert_grp)
+    blks2.ofdm_demod.add_options(parser, expert_grp)
     fusb_options.add_options(expert_grp)
 
     (options, args) = parser.parse_args ()
 
     # build the graph
-    fg = usrp_graph(rx_callback, options)
+    tb = my_top_block(rx_callback, options)
 
     r = gr.enable_realtime_scheduling()
     if r != gr.RT_OK:
         print "Warning: failed to enable realtime scheduling"
 
-    fg.start()                      # start flow graph
-    fg.wait()                       # wait for it to finish
+    tb.start()                      # start flow graph
+    tb.wait()                       # wait for it to finish
 
 if __name__ == '__main__':
     try:
index a9d1e00e6ce8da4ceb966772188e8ce4b95cb350..fb41ab12936c448319c7fd4524933f457468656b 100755 (executable)
@@ -20,7 +20,7 @@
 # Boston, MA 02110-1301, USA.
 # 
 
-from gnuradio import gr, blks
+from gnuradio import gr, blks2
 from gnuradio import usrp
 from gnuradio import eng_notation
 from gnuradio.eng_option import eng_option
@@ -33,9 +33,9 @@ from transmit_path import transmit_path
 from pick_bitrate import pick_tx_bitrate
 import fusb_options
 
-class usrp_graph(gr.flow_graph):
+class my_top_block(gr.top_block):
     def __init__(self, options):
-        gr.flow_graph.__init__(self)
+        gr.top_block.__init__(self)
 
         self._tx_freq            = options.tx_freq         # tranmitter's center frequency
         self._tx_subdev_spec     = options.tx_subdev_spec  # daughterboard to use
@@ -53,10 +53,10 @@ class usrp_graph(gr.flow_graph):
         # copy the final answers back into options for use by modulator
         #options.bitrate = self._bitrate
 
-        self.txpath = transmit_path(self, options)
+        self.txpath = transmit_path(options)
 
         self.connect(self.txpath, self.u)
-
+        
     def _setup_usrp_sink(self):
         """
         Creates a USRP sink, determines the settings for best bitrate,
@@ -167,7 +167,7 @@ def add_freq_option(parser):
 def main():
 
     def send_pkt(payload='', eof=False):
-        return fg.txpath.send_pkt(payload, eof)
+        return tb.txpath.send_pkt(payload, eof)
 
     parser = OptionParser(option_class=eng_option, conflict_handler="resolve")
     expert_grp = parser.add_option_group("Expert")
@@ -178,23 +178,23 @@ def main():
     parser.add_option("","--discontinuous", action="store_true", default=False,
                       help="enable discontinuous mode")
 
-    usrp_graph.add_options(parser, expert_grp)
+    my_top_block.add_options(parser, expert_grp)
     transmit_path.add_options(parser, expert_grp)
-    blks.ofdm_mod.add_options(parser, expert_grp)
-    blks.ofdm_demod.add_options(parser, expert_grp)
+    blks2.ofdm_mod.add_options(parser, expert_grp)
+    blks2.ofdm_demod.add_options(parser, expert_grp)
     fusb_options.add_options(expert_grp)
 
     (options, args) = parser.parse_args ()
 
     # build the graph
-    fg = usrp_graph(options)
-
+    tb = my_top_block(options)
+    
     r = gr.enable_realtime_scheduling()
     if r != gr.RT_OK:
         print "Warning: failed to enable realtime scheduling"
 
-    fg.start()                       # start flow graph
-
+    tb.start()                       # start flow graph
+    
     # generate and send packets
     nbytes = int(1e6 * options.megabytes)
     n = 0
@@ -210,7 +210,7 @@ def main():
         pktno += 1
         
     send_pkt(eof=True)
-    fg.wait()                       # wait for it to finish
+    tb.wait()                       # wait for it to finish
 
 if __name__ == '__main__':
     try:
diff --git a/gnuradio-examples/python/ofdm/gr_plot_ofdm.py b/gnuradio-examples/python/ofdm/gr_plot_ofdm.py
new file mode 100755 (executable)
index 0000000..0bca410
--- /dev/null
@@ -0,0 +1,268 @@
+#!/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 3, or (at your option)
+# any later version.
+# 
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+import scipy, pylab, math
+import struct, sys
+from pylab import *
+from matplotlib.font_manager import fontManager, FontProperties
+from optparse import OptionParser
+from scipy import fftpack
+from math import log10
+
+matplotlib.interactive(True)
+matplotlib.use('TkAgg')
+
+class draw_constellation:
+    def __init__(self, options):
+        derot_file = "ofdm_frame_sink_c.dat"
+        acq_file = "ofdm_frame_acq_c.dat"
+        fft_file = "fft_out_c.dat"
+
+        self.h_derot_file = open(derot_file, "r")
+        self.h_acq_file = open(acq_file, "r")
+        self.h_fft_file = open(fft_file, "r")
+
+        self.occ_tones = options.occ_tones
+        self.fft_size  = options.fft_size
+        self.symbol = options.start
+        self.sample_rate = options.sample_rate
+        
+        self.axis_font_size = 16
+        self.label_font_size = 18
+        self.title_font_size = 20
+        self.text_size = 22
+        
+        # Setup PLOT
+        self.fig = figure(1, figsize=(14, 9), facecolor='w')
+        rcParams['xtick.labelsize'] = self.axis_font_size
+        rcParams['ytick.labelsize'] = self.axis_font_size
+
+        self.text_sym = figtext(0.05, 0.95, ("Symbol: %s" % self.symbol), weight="heavy", size=self.text_size)
+
+        self.make_plots()
+
+        self.button_left_axes = self.fig.add_axes([0.45, 0.01, 0.05, 0.05], frameon=True)
+        self.button_left = Button(self.button_left_axes, "<")
+        self.button_left_callback = self.button_left.on_clicked(self.button_left_click)
+
+        self.button_right_axes = self.fig.add_axes([0.50, 0.01, 0.05, 0.05], frameon=True)
+        self.button_right = Button(self.button_right_axes, ">")
+        self.button_right_callback = self.button_right.on_clicked(self.button_right_click)
+
+        self.xlim = self.sp_eq.get_xlim()
+
+        self.manager = get_current_fig_manager()
+        #connect('draw_event', self.zoom)
+        connect('key_press_event', self.click)
+        show()
+
+    def get_data(self):
+        self.text_sym.set_text("Symbol: %d" % (self.symbol))
+
+        derot_data = scipy.fromfile(self.h_derot_file, dtype=scipy.complex64, count=self.occ_tones)
+        acq_data = scipy.fromfile(self.h_acq_file, dtype=scipy.complex64, count=self.occ_tones)
+        fft_data = scipy.fromfile(self.h_fft_file, dtype=scipy.complex64, count=self.fft_size)
+        if(len(acq_data) == 0):
+            print "End of File"
+        else:
+            self.acq_data_reals = [r.real for r in acq_data]
+            self.acq_data_imags = [i.imag for i in acq_data]
+            self.derot_data_reals = [r.real for r in derot_data]
+            self.derot_data_imags = [i.imag for i in derot_data]
+
+            self.unequalized_angle = [math.atan2(x.imag, x.real) for x in fft_data]
+            self.equalized_angle = [math.atan2(x.imag, x.real) for x in acq_data]
+            self.derot_equalized_angle = [math.atan2(x.imag, x.real) for x in derot_data]
+
+            self.time = [i*(1/self.sample_rate) for i in range(len(acq_data))]
+            ffttime = [i*(1/self.sample_rate) for i in range(len(fft_data))]
+
+            self.freq = self.get_freq(ffttime, self.sample_rate)
+
+            for i in range(len(fft_data)):
+                if(abs(fft_data[i]) == 0.0):
+                    fft_data[i] = complex(1e-6,1e-6)
+            self.fft_data = [20*log10(abs(f)) for f in fft_data]
+              
+    def get_freq(self, time, sample_rate, T=1):
+        N = len(time)
+        Fs = 1.0 / (max(time) - min(time))
+        Fn = 0.5 * sample_rate
+        freq = [-Fn + i*Fs for i in range(N)]
+        return freq
+
+    def make_plots(self):
+        self.h_acq_file.seek(8*self.symbol*self.occ_tones, 0)
+        self.h_fft_file.seek(8*self.symbol*self.fft_size, 0)
+        self.h_derot_file.seek(8*self.symbol*self.occ_tones, 0)
+
+        self.get_data()
+        
+        # Subplot:  constellation of rotated symbols
+        self.sp_const = self.fig.add_subplot(4,1,1, position=[0.15, 0.55, 0.3, 0.35])
+        self.sp_const.set_title(("Constellation"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_const.set_xlabel("Inphase", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_const.set_ylabel("Qaudrature", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_const = plot(self.acq_data_reals, self.acq_data_imags, 'bo')
+        self.plot_const += plot(self.derot_data_reals, self.derot_data_imags, 'ro')
+        self.sp_const.axis([-2, 2, -2, 2])
+
+        # Subplot: unequalized angle
+        self.sp_uneq = self.fig.add_subplot(4,2,1, position=[0.575, 0.55, 0.3, 0.35])
+        self.sp_uneq.set_title(("Unequalized Angle"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_uneq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_uneq.set_ylabel("Angle", fontsize=self.label_font_size, fontweight="bold")
+        uneqscale = range(len(self.unequalized_angle))
+        self.plot_uneq = plot(uneqscale, self.unequalized_angle, 'bo')
+
+        # Subplot: equalized angle
+        self.sp_eq = self.fig.add_subplot(4,1,2, position=[0.15, 0.1, 0.3, 0.35])
+        self.sp_eq.set_title(("Equalized Angle"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_eq.set_xlabel("Time (s)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_eq.set_ylabel("Angle", fontsize=self.label_font_size, fontweight="bold")
+        eqscale = range(len(self.equalized_angle))
+        self.plot_eq = plot(eqscale, self.equalized_angle, 'bo')
+        self.plot_eq += plot(eqscale, self.derot_equalized_angle, 'ro', markersize=4)
+
+        # Subplot: FFT
+        self.sp_fft = self.fig.add_subplot(4,2,2, position=[0.575, 0.1, 0.3, 0.35])
+        self.sp_fft.set_title(("FFT"), fontsize=self.title_font_size, fontweight="bold")
+        self.sp_fft.set_xlabel("Frequency (MHz)", fontsize=self.label_font_size, fontweight="bold")
+        self.sp_fft.set_ylabel("Power (dBm)", fontsize=self.label_font_size, fontweight="bold")
+        self.plot_fft = plot(self.freq, self.fft_data, '-bo')
+
+        draw()
+
+    def update_plots(self):
+        eqscale = range(len(self.equalized_angle))
+        uneqscale = range(len(self.unequalized_angle))
+        self.plot_eq[0].set_data([eqscale, self.equalized_angle])
+        self.plot_eq[1].set_data([eqscale, self.derot_equalized_angle])
+        self.plot_uneq[0].set_data([uneqscale, self.unequalized_angle])
+        self.sp_eq.set_ylim([-4, 4])
+        self.sp_uneq.set_ylim([-4, 4])
+
+        #self.sp_iq.axis([min(self.time), max(self.time),
+        #                 1.5*min([min(self.acq_data_reals), min(self.acq_data_imags)]),
+        #                 1.5*max([max(self.acq_data_reals), max(self.acq_data_imags)])])
+
+        self.plot_const[0].set_data([self.acq_data_reals, self.acq_data_imags])
+        self.plot_const[1].set_data([self.derot_data_reals, self.derot_data_imags])
+        self.sp_const.axis([-2, 2, -2, 2])
+
+        self.plot_fft[0].set_data([self.freq, self.fft_data])
+
+        draw()
+        
+    def zoom(self, event):
+        newxlim = self.sp_eq.get_xlim()
+        if(newxlim != self.xlim):
+            self.xlim = newxlim
+            r = self.reals[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))]
+            i = self.imags[int(ceil(self.xlim[0])) : int(ceil(self.xlim[1]))]
+
+            self.plot_const[0].set_data(r, i)
+            self.sp_const.axis([-2, 2, -2, 2])
+            self.manager.canvas.draw()
+            draw()
+
+    def click(self, event):
+        forward_valid_keys = [" ", "down", "right"]
+        backward_valid_keys = ["up", "left"]
+
+        if(find(event.key, forward_valid_keys)):
+            self.step_forward()
+            
+        elif(find(event.key, backward_valid_keys)):
+            self.step_backward()
+
+    def button_left_click(self, event):
+        self.step_backward()
+
+    def button_right_click(self, event):
+        self.step_forward()
+
+    def step_forward(self):
+        self.symbol += 1
+        self.get_data()
+        self.update_plots()
+
+    def step_backward(self):
+        # Step back in file position
+        self.symbol -= 1
+        if(self.h_acq_file.tell() >= 16*self.occ_tones):
+            self.h_acq_file.seek(-16*self.occ_tones, 1)
+        else:
+            self.symbol = 0
+            self.h_acq_file.seek(-self.h_acq_file.tell(),1)
+
+
+        if(self.h_derot_file.tell() >= 16*self.occ_tones):
+            self.h_derot_file.seek(-16*self.occ_tones, 1)
+        else:
+            self.symbol = 0
+            self.h_derot_file.seek(-self.h_derot_file.tell(),1)
+
+
+        if(self.h_fft_file.tell() >= 16*self.fft_size):
+            self.h_fft_file.seek(-16*self.fft_size, 1)
+        else:
+            self.symbol = 0
+            self.h_fft_file.seek(-self.h_fft_file.tell(),1)
+
+        self.get_data()
+        self.update_plots()
+        
+            
+
+#FIXME: there must be a way to do this with a Python builtin
+def find(item_in, list_search):
+    for l in list_search:
+        if item_in == l:
+            return True
+    return False
+
+def main():
+    usage="%prog: [options]"
+
+    parser = OptionParser(conflict_handler="resolve", usage=usage)
+    parser.add_option("", "--fft-size", type="int", default=512,
+                      help="Specify the size of the FFT [default=%default]")
+    parser.add_option("", "--occ-tones", type="int", default=200,
+                      help="Specify the number of occupied tones [default=%default]")
+    parser.add_option("-s", "--start", type="int", default=0,
+                      help="Specify the starting symbol to plot [default=%default]")
+    parser.add_option("-R", "--sample-rate", type="float", default=1.0,
+                      help="Set the sampler rate of the data [default=%default]")
+    
+    (options, args) = parser.parse_args ()
+
+    dc = draw_constellation(options)
+
+if __name__ == "__main__":
+    try:
+        main()
+    except KeyboardInterrupt:
+        pass
+    
+
+
index 87eae3a116e0f1ae411e3299c0150143702b46e4..2a649b5f5557e2e5f809fa6fcdafcad7be10d89e 100755 (executable)
@@ -1,13 +1,22 @@
 function plot_ofdm(fft_size, occ_tones)
 
-ofdm = read_complex_binary('ofdm_corr_out_c.dat');
+ofdm = read_complex_binary('ofdm_frame_acq_c.dat');
 ofdm_split = split_vect(ofdm, occ_tones);
 
+ofdm_derot = read_complex_binary('ofdm_frame_sink_c.dat');
+ofdm_derot_split = split_vect(ofdm_derot, occ_tones);
+
 fftc = read_complex_binary('fft_out_c.dat');
 fftc_split = split_vect(fftc, fft_size);
 
+size(ofdm_split)
+size(ofdm_derot_split)
+disp "DEROTATED SPLIT"
+ofdm_derot(1:100)
+
+
 figure(1)
-set(gcf, 'Position', [50 50 1000 600]);
+#set(gcf, 'Position', [50 50 1000 600]);
 
 a = size(ofdm_split);
 if nargin == 3
@@ -19,47 +28,47 @@ else
     maxcount = a(1);
 end
 
-for i = 1:20000
+for i = 1:size(ofdm_split)[0]
     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');
+    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);
+    #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');
+    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);
+    #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');
+    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);
+    #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');
+    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);
+    #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))
+    #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)))
+    #disp(sprintf('\tFreq Error: %f\n', anglesh_pn(1+(i-1)*fft_size)))
     pause
 
 end
index 2ebaad883873394c8edd3e086e585730a0531ef9..b758bc4d0c6a4424d8e5b7bde400889e452fe1d4 100644 (file)
@@ -20,7 +20,7 @@
 # Boston, MA 02110-1301, USA.
 # 
 
-from gnuradio import gr, gru, blks
+from gnuradio import gr, gru, blks2
 from gnuradio import usrp
 from gnuradio import eng_notation
 import copy
@@ -33,8 +33,13 @@ from pick_bitrate import pick_rx_bitrate
 #                              receive path
 # /////////////////////////////////////////////////////////////////////////////
 
-class receive_path(gr.hier_block):
-    def __init__(self, fg, rx_callback, options):
+class receive_path(gr.hier_block2):
+    def __init__(self, rx_callback, options):
+
+       gr.hier_block2.__init__(self, "receive_path",
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
+                               gr.io_signature(0, 0, 0)) # Output signature
+
 
         options = copy.copy(options)    # make a copy so we can destructively modify
 
@@ -44,20 +49,20 @@ class receive_path(gr.hier_block):
 
         # receiver
         self.ofdm_rx = \
-                     blks.ofdm_demod(fg, options, callback=self._rx_callback)
+                     blks2.ofdm_demod(options, callback=self._rx_callback)
 
         # Carrier Sensing Blocks
         alpha = 0.001
         thresh = 30   # in dB, will have to adjust
         self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha)
-        fg.connect(self.ofdm_rx.ofdm_recv.chan_filt, self.probe)
+
+        self.connect(self, self.ofdm_rx)
+        self.connect(self.ofdm_rx, self.probe)
 
         # Display some information about the setup
         if self._verbose:
             self._print_verbage()
         
-        gr.hier_block.__init__(self, fg, self.ofdm_rx, None)
-
     def carrier_sensed(self):
         """
         Return True if we think carrier is present.
index f15845b007e248691b5801a59e07e0040daf9751..44c7331b05b28269a551fb39a804af9a416491fb 100644 (file)
@@ -19,7 +19,7 @@
 # Boston, MA 02110-1301, USA.
 # 
 
-from gnuradio import gr, gru, blks
+from gnuradio import gr, gru, blks2
 from gnuradio import usrp
 from gnuradio import eng_notation
 
@@ -30,19 +30,23 @@ import sys
 #                              transmit path
 # /////////////////////////////////////////////////////////////////////////////
 
-class transmit_path(gr.hier_block): 
-    def __init__(self, fg, options):
+class transmit_path(gr.hier_block2): 
+    def __init__(self, options):
         '''
         See below for what options should hold
         '''
 
+       gr.hier_block2.__init__(self, "transmit_path",
+                               gr.io_signature(0, 0, 0), # Input signature
+                               gr.io_signature(1, 1, gr.sizeof_gr_complex)) # Output signature
+
         options = copy.copy(options)    # make a copy so we can destructively modify
 
-        self._verbose      = options.verbose
+        self._verbose      = options.verbose         # turn verbose mode on/off
         self._tx_amplitude = options.tx_amplitude    # digital amplitude sent to USRP
 
         self.ofdm_tx = \
-                     blks.ofdm_mod(fg, options, msgq_limit=4, pad_for_usrp=False)
+                     blks2.ofdm_mod(options, msgq_limit=4, pad_for_usrp=False)
 
         self.amp = gr.multiply_const_cc(1)
         self.set_tx_amplitude(self._tx_amplitude)
@@ -52,8 +56,7 @@ class transmit_path(gr.hier_block):
             self._print_verbage()
 
         # Create and setup transmit path flow graph
-        fg.connect(self.ofdm_tx, self.amp)
-        gr.hier_block.__init__(self, fg, None, self.amp)
+        self.connect(self.ofdm_tx, self.amp, self)
 
     def set_tx_amplitude(self, ampl):
         """