summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am9
-rw-r--r--gnuradio-core/src/lib/general/general.i6
-rw-r--r--gnuradio-core/src/lib/general/gr_math.h13
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_correlator.cc231
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.cc223
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.h (renamed from gnuradio-core/src/lib/general/gr_ofdm_correlator.h)57
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.i (renamed from gnuradio-core/src/lib/general/gr_ofdm_correlator.i)28
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc79
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h17
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i6
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc4
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_sampler.cc18
-rw-r--r--gnuradio-core/src/lib/general/gr_peak_detector2_fb.cc106
-rw-r--r--gnuradio-core/src/lib/general/gr_peak_detector2_fb.h108
-rw-r--r--gnuradio-core/src/lib/general/gr_peak_detector2_fb.i45
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am6
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py)96
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py112
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py49
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py)83
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py (renamed from gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py)95
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py131
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am6
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py64
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py41
-rw-r--r--gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py126
-rw-r--r--gnuradio-core/src/utils/README40
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_char.py165
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_const.py203
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_fft_c.py221
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_fft_f.py223
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_float.py158
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_int.py165
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_iq.py160
-rwxr-xr-xgnuradio-core/src/utils/gr_plot_short.py165
-rw-r--r--gnuradio-core/src/utils/gr_read_binary.py61
-rwxr-xr-xgnuradio-examples/python/ofdm/benchmark_ofdm.py44
-rwxr-xr-xgnuradio-examples/python/ofdm/benchmark_ofdm_rx.py24
-rwxr-xr-xgnuradio-examples/python/ofdm/benchmark_ofdm_tx.py28
-rwxr-xr-xgnuradio-examples/python/ofdm/gr_plot_ofdm.py268
-rwxr-xr-xgnuradio-examples/python/ofdm/plot_ofdm.m67
-rw-r--r--gnuradio-examples/python/ofdm/receive_path.py19
-rw-r--r--gnuradio-examples/python/ofdm/transmit_path.py17
44 files changed, 2840 insertions, 948 deletions
diff --git a/AUTHORS b/AUTHORS
index e0bd7a7d1..e030f7b7c 100644
--- 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
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index b466ad44b..cde6a7549 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -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 \
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index e9780ea13..0eab24f1a 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -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>
@@ -128,6 +128,7 @@
#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"
@@ -201,7 +202,7 @@
%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"
@@ -236,3 +237,4 @@
%include "gr_bin_statistics_f.i"
%include "gr_glfsr_source_b.i"
%include "gr_glfsr_source_f.i"
+%include "gr_peak_detector2_fb.i"
diff --git a/gnuradio-core/src/lib/general/gr_math.h b/gnuradio-core/src/lib/general/gr_math.h
index 439e5f4b9..2cd5b8eb7 100644
--- a/gnuradio-core/src/lib/general/gr_math.h
+++ b/gnuradio-core/src/lib/general/gr_math.h
@@ -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
index e396eeb8e..000000000
--- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc
+++ /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_frame_acquisition.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.cc
new file mode 100644
index 000000000..0fa6a3d3e
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.cc
@@ -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_correlator.h b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.h
index 55ee4e190..af63f3e4c 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.h
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.h
@@ -20,22 +20,21 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef INCLUDED_GR_OFDM_CORRELATOR_H
-#define INCLUDED_GR_OFDM_CORRELATOR_H
+#ifndef INCLUDED_GR_OFDM_FRAME_ACQUISITION_H
+#define INCLUDED_GR_OFDM_FRAME_ACQUISITION_H
#include <gr_block.h>
#include <vector>
-class gr_ofdm_correlator;
-typedef boost::shared_ptr<gr_ofdm_correlator> gr_ofdm_correlator_sptr;
+class gr_ofdm_frame_acquisition;
+typedef boost::shared_ptr<gr_ofdm_frame_acquisition> gr_ofdm_frame_acquisition_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);
+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
@@ -54,7 +53,7 @@ gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length
* distortion caused by the channel.
*/
-class gr_ofdm_correlator : public gr_block
+class gr_ofdm_frame_acquisition : public gr_block
{
/*!
* \brief Build an OFDM correlator and equalizer.
@@ -68,35 +67,33 @@ class gr_ofdm_correlator : public gr_block
* 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);
+ 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_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_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 *previous, const gr_complex *current, int zeros_on_left);
- void calculate_equalizer(const gr_complex *previous,
- const gr_complex *current, int zeros_on_left);
+ 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_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_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
- signed int d_coarse_freq; // !< \brief search distance in number of bins
+ 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
@@ -110,7 +107,7 @@ class gr_ofdm_correlator : public gr_block
*/
float snr() { return d_snr_est; }
- ~gr_ofdm_correlator(void);
+ ~gr_ofdm_frame_acquisition(void);
int general_work(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.i b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.i
index 2e39e2150..0fd0bc58b 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.i
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_acquisition.i
@@ -22,25 +22,23 @@
#include <vector>
-GR_SWIG_BLOCK_MAGIC(gr,ofdm_correlator);
+GR_SWIG_BLOCK_MAGIC(gr,ofdm_frame_acquisition);
-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);
+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_correlator : public gr_sync_decimator
+class gr_ofdm_frame_acquisition : 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);
+ 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; }
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc
index d75b693a2..a1ac66ff7 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc
@@ -26,8 +26,12 @@
#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;
}
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h
index f1c9b76fe..904373bba 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h
@@ -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();
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i
index 296eb6591..38ab50e97 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i
+++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i
@@ -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();
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc
index 4ff55b5d8..f916977df 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc
+++ b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc
@@ -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)
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
index 56b5d50a4..6216df791 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
+++ b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
@@ -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
index 000000000..a84cf189f
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_peak_detector2_fb.cc
@@ -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
index 000000000..e20c6c022
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_peak_detector2_fb.h
@@ -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
index 000000000..4b01435c8
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_peak_detector2_fb.i
@@ -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; }
+};
+
+
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
index e3d83aeee..934326d8f 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
@@ -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/blksimpl/ofdm.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
index b040d8c7f..491ef1a19 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm.py
@@ -1,4 +1,4 @@
-
+#!/usr/bin/env python
#
# Copyright 2006,2007 Free Software Foundation, Inc.
#
@@ -21,40 +21,41 @@
#
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
+from gnuradio.blks2impl.ofdm_receiver import ofdm_receiver
# /////////////////////////////////////////////////////////////////////////////
# mod/demod with packets as i/o
# /////////////////////////////////////////////////////////////////////////////
-class ofdm_mod(gr.hier_block):
+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, fg, options, msgq_limit=2, pad_for_usrp=True):
+ 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 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
"""
+ 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
@@ -71,10 +72,10 @@ class ofdm_mod(gr.hier_block):
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])
-
+ 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,]
@@ -96,25 +97,29 @@ class ofdm_mod(gr.hier_block):
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)
+ 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)
+ 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:
- 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)
+ 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):
"""
@@ -138,7 +143,7 @@ class ofdm_mod(gr.hier_block):
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]")
+ 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,
@@ -159,7 +164,7 @@ class ofdm_mod(gr.hier_block):
print "CP length: %3d" % (self._cp_length)
-class ofdm_demod(gr.hier_block):
+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
@@ -169,19 +174,22 @@ class ofdm_demod(gr.hier_block):
app via the callback.
"""
- def __init__(self, fg, options, callback=None):
+ 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 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
"""
+ 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
@@ -190,30 +198,19 @@ class ofdm_demod(gr.hier_block):
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])
+ 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(fg, 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)
@@ -231,18 +228,27 @@ class ofdm_demod(gr.hier_block):
#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))
+ 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()
- 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
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
index 000000000..9592755b1
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_receiver.py
@@ -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
index 000000000..74acc8fde
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_fixed.py
@@ -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/blksimpl/ofdm_sync_ml.py b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py
index d58f56cff..a93852623 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_ml.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_ml.py
@@ -23,19 +23,22 @@
import math
from gnuradio import gr
-class ofdm_sync_ml(gr.hier_block):
- def __init__(self, fg, fft_length, cp_length, snr, logging):
+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.
'''
- self.fg = fg
-
- # FIXME: when converting to hier_block2's, the output signature
+ # 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)
@@ -47,9 +50,11 @@ class ofdm_sync_ml(gr.hier_block):
# 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.fg.connect(self.input, self.delay)
+ self.connect(self.input, self.delay)
# magnitude squared blocks
self.magsqrd1 = gr.complex_to_mag_squared()
@@ -59,11 +64,11 @@ class ofdm_sync_ml(gr.hier_block):
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)
+ 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
@@ -76,60 +81,62 @@ class ofdm_sync_ml(gr.hier_block):
# 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)
+ 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.fg.connect(self.c2mag,(self.diff,0))
- self.fg.connect(self.moving_sum_filter,(self.diff,1))
+ 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.fg.connect(self.input, (self.sigmix,0))
- self.fg.connect(self.nco, (self.sigmix,1))
- self.fg.connect(self.sigmix, (self.sampler,0))
+ 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.fg.connect(self.diff, self.pk_detect)
+ self.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))
+ 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.fg.connect(self.pk_detect, (self.sampler,1))
- self.fg.connect(self.pk_detect, (self.sample_and_hold,1))
+ self.connect(self.pk_detect, (self.sampler,1))
+ self.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)
+ 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.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"))
+ 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.fg.connect(self.dpll, gr.file_sink(gr.sizeof_char, "ofdm_sync_ml-dpll_b.dat"))
+ self.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"))
+ 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"))
- 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/blks2impl/ofdm_sync_pn.py
index 56425868f..e3e0ad9d2 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pn.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pn.py
@@ -24,15 +24,18 @@ 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:
+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.
- '''
+ """
- self.fg = fg
+ 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
@@ -84,52 +87,60 @@ class ofdm_sync_pn(gr.hier_block):
#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.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.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))
+ 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.fg.connect(self.normalize, self.matched_filter)
+ self.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))
+ 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.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)
+ 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
index 000000000..5c16a5703
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/ofdm_sync_pnac.py
@@ -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"))
diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am
index b75fade58..74fa098d4 100644
--- a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am
@@ -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_receiver.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py
deleted file mode 100644
index d16d2e294..000000000
--- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_receiver.py
+++ /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
index b56f65660..000000000
--- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_fixed.py
+++ /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_pnac.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py
deleted file mode 100644
index e3774e341..000000000
--- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm_sync_pnac.py
+++ /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
index 000000000..0c4657ba9
--- /dev/null
+++ b/gnuradio-core/src/utils/README
@@ -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
index 000000000..6f799cdd2
--- /dev/null
+++ b/gnuradio-core/src/utils/gr_plot_char.py
@@ -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
+
diff --git a/gnuradio-core/src/utils/gr_plot_const.py b/gnuradio-core/src/utils/gr_plot_const.py
index effda3e0c..bbcbb85cc 100755
--- a/gnuradio-core/src/utils/gr_plot_const.py
+++ b/gnuradio-core/src/utils/gr_plot_const.py
@@ -20,88 +20,171 @@
# 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
index 000000000..924566968
--- /dev/null
+++ b/gnuradio-core/src/utils/gr_plot_fft_c.py
@@ -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
index 000000000..717efdfb5
--- /dev/null
+++ b/gnuradio-core/src/utils/gr_plot_fft_f.py
@@ -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
+
+
+
diff --git a/gnuradio-core/src/utils/gr_plot_float.py b/gnuradio-core/src/utils/gr_plot_float.py
index e4043a640..473326012 100755
--- a/gnuradio-core/src/utils/gr_plot_float.py
+++ b/gnuradio-core/src/utils/gr_plot_float.py
@@ -20,50 +20,142 @@
# 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
index 000000000..ef2c7170a
--- /dev/null
+++ b/gnuradio-core/src/utils/gr_plot_int.py
@@ -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
+
diff --git a/gnuradio-core/src/utils/gr_plot_iq.py b/gnuradio-core/src/utils/gr_plot_iq.py
index db5d99a11..1bb24517e 100755
--- a/gnuradio-core/src/utils/gr_plot_iq.py
+++ b/gnuradio-core/src/utils/gr_plot_iq.py
@@ -20,52 +20,144 @@
# 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
index 000000000..0bb091def
--- /dev/null
+++ b/gnuradio-core/src/utils/gr_plot_short.py
@@ -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
index ae91b4480..000000000
--- a/gnuradio-core/src/utils/gr_read_binary.py
+++ /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)
-
-
diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm.py b/gnuradio-examples/python/ofdm/benchmark_ofdm.py
index 690c57d60..5861da16c 100755
--- a/gnuradio-examples/python/ofdm/benchmark_ofdm.py
+++ b/gnuradio-examples/python/ofdm/benchmark_ofdm.py
@@ -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__':
diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py
index a8c20d390..cb9649a6c 100755
--- a/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py
+++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py
@@ -20,21 +20,21 @@
# 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:
diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py
index a9d1e00e6..fb41ab129 100755
--- a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py
+++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py
@@ -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
index 000000000..0bca41037
--- /dev/null
+++ b/gnuradio-examples/python/ofdm/gr_plot_ofdm.py
@@ -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
+
+
+
diff --git a/gnuradio-examples/python/ofdm/plot_ofdm.m b/gnuradio-examples/python/ofdm/plot_ofdm.m
index 87eae3a11..2a649b5f5 100755
--- a/gnuradio-examples/python/ofdm/plot_ofdm.m
+++ b/gnuradio-examples/python/ofdm/plot_ofdm.m
@@ -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
diff --git a/gnuradio-examples/python/ofdm/receive_path.py b/gnuradio-examples/python/ofdm/receive_path.py
index 2ebaad883..b758bc4d0 100644
--- a/gnuradio-examples/python/ofdm/receive_path.py
+++ b/gnuradio-examples/python/ofdm/receive_path.py
@@ -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.
diff --git a/gnuradio-examples/python/ofdm/transmit_path.py b/gnuradio-examples/python/ofdm/transmit_path.py
index f15845b00..44c7331b0 100644
--- a/gnuradio-examples/python/ofdm/transmit_path.py
+++ b/gnuradio-examples/python/ofdm/transmit_path.py
@@ -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):
"""