summaryrefslogtreecommitdiff
path: root/gnuradio-core/src
diff options
context:
space:
mode:
Diffstat (limited to 'gnuradio-core/src')
-rw-r--r--gnuradio-core/src/gen_interpolator_taps/Makefile.am18
-rw-r--r--gnuradio-core/src/lib/filter/Makefile.am4
-rw-r--r--gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc143
-rw-r--r--gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h21
-rw-r--r--gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc157
-rw-r--r--gnuradio-core/src/lib/filter/gr_fft_filter_fff.h22
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc12
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h25
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc91
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h58
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i10
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc15
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h99
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc15
-rw-r--r--gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h101
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.cc167
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.h82
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.cc186
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.h82
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.cc158
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.h80
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.cc184
-rw-r--r--gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.h81
-rw-r--r--gnuradio-core/src/lib/general/Makefile.am6
-rw-r--r--gnuradio-core/src/lib/general/general.i4
-rw-r--r--gnuradio-core/src/lib/general/gr_additive_scrambler_bb.cc65
-rw-r--r--gnuradio-core/src/lib/general/gr_additive_scrambler_bb.h67
-rw-r--r--gnuradio-core/src/lib/general/gr_additive_scrambler_bb.i (renamed from gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i)15
-rw-r--r--gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc196
-rw-r--r--gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h93
-rw-r--r--gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc27
-rw-r--r--gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h16
-rw-r--r--gnuradio-core/src/lib/general/gr_ofdm_sampler.cc3
-rw-r--r--gnuradio-core/src/lib/general/gri_lfsr.h12
-rw-r--r--gnuradio-core/src/lib/io/Makefile.am2
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_sink.cc314
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_sink.h98
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_sink.i22
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_source.cc273
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_source.h90
-rw-r--r--gnuradio-core/src/lib/io/gr_udp_source.i15
-rw-r--r--gnuradio-core/src/lib/io/gri_logger.cc178
-rw-r--r--gnuradio-core/src/lib/io/gri_logger.h59
-rw-r--r--gnuradio-core/src/python/gnuradio/Makefile.am1
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am2
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py10
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py66
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py60
-rw-r--r--gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py8
-rw-r--r--gnuradio-core/src/python/gnuradio/gr/Makefile.am3
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gr/qa_scrambler.py20
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py99
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/hexint.py12
-rw-r--r--gnuradio-core/src/python/gnuradio/modulation_utils2.py81
-rw-r--r--gnuradio-core/src/python/gnuradio/packet_utils.py2
55 files changed, 2422 insertions, 1308 deletions
diff --git a/gnuradio-core/src/gen_interpolator_taps/Makefile.am b/gnuradio-core/src/gen_interpolator_taps/Makefile.am
index 5f3a6cb25..d244e7f54 100644
--- a/gnuradio-core/src/gen_interpolator_taps/Makefile.am
+++ b/gnuradio-core/src/gen_interpolator_taps/Makefile.am
@@ -21,13 +21,13 @@
include $(top_srcdir)/Makefile.common
-EXTRA_DIST = praxis.txt simpson.h
+EXTRA_DIST = praxis.txt simpson.h objective_fct.c gen_interpolator_taps.c simpson.c praxis.f
-if ENABLE_FORTRAN
-noinst_PROGRAMS = gen_interpolator_taps
-noinst_HEADERS = simpson.h
-
-gen_interpolator_taps_SOURCES = gen_interpolator_taps.c objective_fct.c simpson.c praxis.f
-gen_interpolator_taps_LDADD = $(FLIBS) -lm
-
-endif
+# if ENABLE_FORTRAN
+# noinst_PROGRAMS = gen_interpolator_taps
+# noinst_HEADERS = simpson.h
+#
+# gen_interpolator_taps_SOURCES = gen_interpolator_taps.c objective_fct.c simpson.c praxis.f
+# gen_interpolator_taps_LDADD = $(FLIBS) -lm
+#
+# endif
diff --git a/gnuradio-core/src/lib/filter/Makefile.am b/gnuradio-core/src/lib/filter/Makefile.am
index 9cd6e9f38..23c1dadc3 100644
--- a/gnuradio-core/src/lib/filter/Makefile.am
+++ b/gnuradio-core/src/lib/filter/Makefile.am
@@ -184,6 +184,8 @@ libfilter_la_common_SOURCES = \
$(GENERATED_CC) \
gr_adaptive_fir_ccf.cc \
gr_cma_equalizer_cc.cc \
+ gri_fft_filter_fff_generic.cc \
+ gri_fft_filter_ccc_generic.cc \
gr_fft_filter_ccc.cc \
gr_fft_filter_fff.cc \
gr_goertzel_fc.cc \
@@ -259,6 +261,8 @@ grinclude_HEADERS = \
gr_altivec.h \
gr_cma_equalizer_cc.h \
gr_cpu.h \
+ gri_fft_filter_fff_generic.h \
+ gri_fft_filter_ccc_generic.h \
gr_fft_filter_ccc.h \
gr_fft_filter_fff.h \
gr_filter_delay_fc.h \
diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc
index 3dd40d56d..4540c6e4a 100644
--- a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc
+++ b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.cc
@@ -30,6 +30,8 @@
#endif
#include <gr_fft_filter_ccc.h>
+//#include <gri_fft_filter_ccc_sse.h>
+#include <gri_fft_filter_ccc_generic.h>
#include <gr_io_signature.h>
#include <gri_fft.h>
#include <math.h>
@@ -52,32 +54,23 @@ gr_fft_filter_ccc::gr_fft_filter_ccc (int decimation, const std::vector<gr_compl
gr_make_io_signature (1, 1, sizeof (gr_complex)),
gr_make_io_signature (1, 1, sizeof (gr_complex)),
decimation),
- d_fftsize(-1), d_fwdfft(0), d_invfft(0), d_updated(false)
+ d_updated(false)
{
- // if (decimation != 1)
- // throw std::invalid_argument("gr_fft_filter_ccc: decimation must be 1");
-
set_history(1);
- actual_set_taps(taps);
+#if 1 // don't enable the sse version until handling it is worked out
+ d_filter = new gri_fft_filter_ccc_generic(decimation, taps);
+#else
+ d_filter = new gri_fft_filter_ccc_sse(decimation, taps);
+#endif
+ d_nsamples = d_filter->set_taps(taps);
+ set_output_multiple(d_nsamples);
}
gr_fft_filter_ccc::~gr_fft_filter_ccc ()
{
- delete d_fwdfft;
- delete d_invfft;
+ delete d_filter;
}
-#if 0
-static void
-print_vector_complex(const std::string label, const std::vector<gr_complex> &x)
-{
- std::cout << label;
- for (unsigned i = 0; i < x.size(); i++)
- std::cout << x[i] << " ";
- std::cout << "\n";
-}
-#endif
-
void
gr_fft_filter_ccc::set_taps (const std::vector<gr_complex> &taps)
{
@@ -85,130 +78,26 @@ gr_fft_filter_ccc::set_taps (const std::vector<gr_complex> &taps)
d_updated = true;
}
-/*
- * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
- */
-void
-gr_fft_filter_ccc::actual_set_taps (const std::vector<gr_complex> &taps)
-{
- int i = 0;
- compute_sizes(taps.size());
-
- d_tail.resize(tailsize());
- for (i = 0; i < tailsize(); i++)
- d_tail[i] = 0;
-
- gr_complex *in = d_fwdfft->get_inbuf();
- gr_complex *out = d_fwdfft->get_outbuf();
-
- float scale = 1.0 / d_fftsize;
-
- // Compute forward xform of taps.
- // Copy taps into first ntaps slots, then pad with zeros
- for (i = 0; i < d_ntaps; i++)
- in[i] = taps[i] * scale;
-
- for (; i < d_fftsize; i++)
- in[i] = 0;
-
- d_fwdfft->execute(); // do the xform
-
- // now copy output to d_xformed_taps
- for (i = 0; i < d_fftsize; i++)
- d_xformed_taps[i] = out[i];
-
- //print_vector_complex("transformed taps:", d_xformed_taps);
-}
-
-// determine and set d_ntaps, d_nsamples, d_fftsize
-
-void
-gr_fft_filter_ccc::compute_sizes(int ntaps)
-{
- int old_fftsize = d_fftsize;
- d_ntaps = ntaps;
- d_fftsize = (int) (2 * pow(2.0, ceil(log(ntaps) / log(2))));
- d_nsamples = d_fftsize - d_ntaps + 1;
-
- if (0)
- fprintf(stderr, "gr_fft_filter: ntaps = %d, fftsize = %d, nsamples = %d\n",
- d_ntaps, d_fftsize, d_nsamples);
-
- assert(d_fftsize == d_ntaps + d_nsamples -1 );
-
- if (d_fftsize != old_fftsize){ // compute new plans
- delete d_fwdfft;
- delete d_invfft;
- d_fwdfft = new gri_fft_complex(d_fftsize, true);
- d_invfft = new gri_fft_complex(d_fftsize, false);
- d_xformed_taps.resize(d_fftsize);
- }
-
- set_output_multiple(d_nsamples);
-}
-
int
gr_fft_filter_ccc::work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
{
- gr_complex *in = (gr_complex *) input_items[0];
+ const gr_complex *in = (const gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
if (d_updated){
- actual_set_taps(d_new_taps);
+ d_nsamples = d_filter->set_taps(d_new_taps);
d_updated = false;
+ set_output_multiple(d_nsamples);
return 0; // output multiple may have changed
}
assert(noutput_items % d_nsamples == 0);
- int dec_ctr = 0;
- int j = 0;
- int ninput_items = noutput_items * decimation();
-
- for (int i = 0; i < ninput_items; i += d_nsamples){
-
- memcpy(d_fwdfft->get_inbuf(), &in[i], d_nsamples * sizeof(gr_complex));
-
- for (j = d_nsamples; j < d_fftsize; j++)
- d_fwdfft->get_inbuf()[j] = 0;
-
- d_fwdfft->execute(); // compute fwd xform
-
- gr_complex *a = d_fwdfft->get_outbuf();
- gr_complex *b = &d_xformed_taps[0];
- gr_complex *c = d_invfft->get_inbuf();
-
- for (j = 0; j < d_fftsize; j++) // filter in the freq domain
- c[j] = a[j] * b[j];
-
- d_invfft->execute(); // compute inv xform
-
- // add in the overlapping tail
-
- for (j = 0; j < tailsize(); j++)
- d_invfft->get_outbuf()[j] += d_tail[j];
-
- // copy nsamples to output
-
- //memcpy(out, d_invfft->get_outbuf(), d_nsamples * sizeof(gr_complex));
- //out += d_nsamples;
-
- j = dec_ctr;
- while (j < d_nsamples) {
- *out++ = d_invfft->get_outbuf()[j];
- j += decimation();
- }
- dec_ctr = (j - d_nsamples);
-
- // stash the tail
- memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
- tailsize() * sizeof(gr_complex));
- }
+ d_filter->filter(noutput_items, in, out);
- assert((out - (gr_complex *) output_items[0]) == noutput_items);
- assert(dec_ctr == 0);
+ //assert((out - (gr_complex *) output_items[0]) == noutput_items);
return noutput_items;
}
diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h
index c5363dcbb..68b19e775 100644
--- a/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h
+++ b/gnuradio-core/src/lib/filter/gr_fft_filter_ccc.h
@@ -28,8 +28,8 @@ class gr_fft_filter_ccc;
typedef boost::shared_ptr<gr_fft_filter_ccc> gr_fft_filter_ccc_sptr;
gr_fft_filter_ccc_sptr gr_make_fft_filter_ccc (int decimation, const std::vector<gr_complex> &taps);
-class gr_fir_ccc;
-class gri_fft_complex;
+//class gri_fft_filter_ccc_sse;
+class gri_fft_filter_ccc_generic;
/*!
* \brief Fast FFT filter with gr_complex input, gr_complex output and gr_complex taps
@@ -40,15 +40,14 @@ class gr_fft_filter_ccc : public gr_sync_decimator
private:
friend gr_fft_filter_ccc_sptr gr_make_fft_filter_ccc (int decimation, const std::vector<gr_complex> &taps);
- int d_ntaps;
int d_nsamples;
- int d_fftsize; // fftsize = ntaps + nsamples - 1
- gri_fft_complex *d_fwdfft; // forward "plan"
- gri_fft_complex *d_invfft; // inverse "plan"
- std::vector<gr_complex> d_tail; // state carried between blocks for overlap-add
- std::vector<gr_complex> d_xformed_taps; // Fourier xformed taps
- std::vector<gr_complex> d_new_taps;
bool d_updated;
+#if 1 // don't enable the sse version until handling it is worked out
+ gri_fft_filter_ccc_generic *d_filter;
+#else
+ gri_fft_filter_ccc_sse *d_filter;
+#endif
+ std::vector<gr_complex> d_new_taps;
/*!
* Construct a FFT filter with the given taps
@@ -58,10 +57,6 @@ class gr_fft_filter_ccc : public gr_sync_decimator
*/
gr_fft_filter_ccc (int decimation, const std::vector<gr_complex> &taps);
- void compute_sizes(int ntaps);
- int tailsize() const { return d_ntaps - 1; }
- void actual_set_taps (const std::vector<gr_complex> &taps);
-
public:
~gr_fft_filter_ccc ();
diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc
index 57232f3fb..e8857fe8c 100644
--- a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc
+++ b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2005 Free Software Foundation, Inc.
+ * Copyright 2005,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -25,13 +25,11 @@
#endif
#include <gr_fft_filter_fff.h>
+#include <gri_fft_filter_fff_generic.h>
+//#include <gri_fft_filter_fff_sse.h>
#include <gr_io_signature.h>
-#include <gri_fft.h>
-#include <math.h>
#include <assert.h>
#include <stdexcept>
-#include <gr_firdes.h>
-
#include <cstdio>
#include <iostream>
@@ -48,37 +46,24 @@ gr_fft_filter_fff::gr_fft_filter_fff (int decimation, const std::vector<float> &
gr_make_io_signature (1, 1, sizeof (float)),
gr_make_io_signature (1, 1, sizeof (float)),
decimation),
- d_fftsize(-1), d_fwdfft(0), d_invfft(0), d_updated(false)
+ d_updated(false)
{
set_history(1);
- actual_set_taps(taps);
-}
-
-gr_fft_filter_fff::~gr_fft_filter_fff ()
-{
- delete d_fwdfft;
- delete d_invfft;
-}
+
+#if 1 // don't enable the sse version until handling it is worked out
+ d_filter = new gri_fft_filter_fff_generic(decimation, taps);
+#else
+ d_filter = new gri_fft_filter_fff_sse(decimation, taps);
+#endif
-#if 0
-static void
-print_vector_complex(const std::string label, const std::vector<gr_complex> &x)
-{
- std::cout << label;
- for (unsigned i = 0; i < x.size(); i++)
- std::cout << x[i] << " ";
- std::cout << "\n";
+ d_nsamples = d_filter->set_taps(taps);
+ set_output_multiple(d_nsamples);
}
-static void
-print_vector_float(const std::string label, const std::vector<float> &x)
+gr_fft_filter_fff::~gr_fft_filter_fff ()
{
- std::cout << label;
- for (unsigned i = 0; i < x.size(); i++)
- std::cout << x[i] << " ";
- std::cout << "\n";
+ delete d_filter;
}
-#endif
void
gr_fft_filter_fff::set_taps (const std::vector<float> &taps)
@@ -87,68 +72,6 @@ gr_fft_filter_fff::set_taps (const std::vector<float> &taps)
d_updated = true;
}
-/*
- * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
- */
-void
-gr_fft_filter_fff::actual_set_taps (const std::vector<float> &taps)
-{
- int i = 0;
- compute_sizes(taps.size());
-
- d_tail.resize(tailsize());
- for (i = 0; i < tailsize(); i++)
- d_tail[i] = 0;
-
- float *in = d_fwdfft->get_inbuf();
- gr_complex *out = d_fwdfft->get_outbuf();
-
- float scale = 1.0 / d_fftsize;
-
- // Compute forward xform of taps.
- // Copy taps into first ntaps slots, then pad with zeros
- for (i = 0; i < d_ntaps; i++)
- in[i] = taps[i] * scale;
-
- for (; i < d_fftsize; i++)
- in[i] = 0;
-
- d_fwdfft->execute(); // do the xform
-
- // now copy output to d_xformed_taps
- for (i = 0; i < d_fftsize/2+1; i++)
- d_xformed_taps[i] = out[i];
-
- //print_vector_complex("transformed taps:", d_xformed_taps);
-}
-
-// determine and set d_ntaps, d_nsamples, d_fftsize
-
-void
-gr_fft_filter_fff::compute_sizes(int ntaps)
-{
- int old_fftsize = d_fftsize;
- d_ntaps = ntaps;
- d_fftsize = (int) (2 * pow(2.0, ceil(log(ntaps) / log(2))));
- d_nsamples = d_fftsize - d_ntaps + 1;
-
- if (0)
- fprintf(stderr, "gr_fft_filter: ntaps = %d, fftsize = %d, nsamples = %d\n",
- d_ntaps, d_fftsize, d_nsamples);
-
- assert(d_fftsize == d_ntaps + d_nsamples -1 );
-
- if (d_fftsize != old_fftsize){ // compute new plans
- delete d_fwdfft;
- delete d_invfft;
- d_fwdfft = new gri_fft_real_fwd(d_fftsize);
- d_invfft = new gri_fft_real_rev(d_fftsize);
- d_xformed_taps.resize(d_fftsize/2+1);
- }
-
- set_output_multiple(d_nsamples);
-}
-
int
gr_fft_filter_fff::work (int noutput_items,
gr_vector_const_void_star &input_items,
@@ -158,59 +81,17 @@ gr_fft_filter_fff::work (int noutput_items,
float *out = (float *) output_items[0];
if (d_updated){
- actual_set_taps(d_new_taps);
+ d_nsamples = d_filter->set_taps(d_new_taps);
d_updated = false;
+ set_output_multiple(d_nsamples);
return 0; // output multiple may have changed
}
assert(noutput_items % d_nsamples == 0);
+
+ d_filter->filter(noutput_items, in, out);
- int dec_ctr = 0;
- int j = 0;
- int ninput_items = noutput_items * decimation();
-
- for (int i = 0; i < ninput_items; i += d_nsamples){
-
- memcpy(d_fwdfft->get_inbuf(), &in[i], d_nsamples * sizeof(float));
-
- for (j = d_nsamples; j < d_fftsize; j++)
- d_fwdfft->get_inbuf()[j] = 0;
-
- d_fwdfft->execute(); // compute fwd xform
-
- gr_complex *a = d_fwdfft->get_outbuf();
- gr_complex *b = &d_xformed_taps[0];
- gr_complex *c = d_invfft->get_inbuf();
-
- for (j = 0; j < d_fftsize/2+1; j++) // filter in the freq domain
- c[j] = a[j] * b[j];
-
- d_invfft->execute(); // compute inv xform
-
- // add in the overlapping tail
-
- for (j = 0; j < tailsize(); j++)
- d_invfft->get_outbuf()[j] += d_tail[j];
-
- // copy nsamples to output
-
- //memcpy(out, d_invfft->get_outbuf(), d_nsamples * sizeof(float));
- //out += d_nsamples;
-
- j = dec_ctr;
- while (j < d_nsamples) {
- *out++ = d_invfft->get_outbuf()[j];
- j += decimation();
- }
- dec_ctr = (j - d_nsamples);
-
- // stash the tail
- memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
- tailsize() * sizeof(float));
- }
-
- assert((out - (float *) output_items[0]) == noutput_items);
- assert(dec_ctr == 0);
+ //assert((out - (float *) output_items[0]) == noutput_items);
return noutput_items;
}
diff --git a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h
index b26361107..6eaa21500 100644
--- a/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h
+++ b/gnuradio-core/src/lib/filter/gr_fft_filter_fff.h
@@ -28,9 +28,8 @@ class gr_fft_filter_fff;
typedef boost::shared_ptr<gr_fft_filter_fff> gr_fft_filter_fff_sptr;
gr_fft_filter_fff_sptr gr_make_fft_filter_fff (int decimation, const std::vector<float> &taps);
-class gr_fir_fff;
-class gri_fft_real_fwd;
-class gri_fft_real_rev;
+class gri_fft_filter_fff_generic;
+//class gri_fft_filter_fff_sse;
/*!
* \brief Fast FFT filter with float input, float output and float taps
@@ -41,15 +40,14 @@ class gr_fft_filter_fff : public gr_sync_decimator
private:
friend gr_fft_filter_fff_sptr gr_make_fft_filter_fff (int decimation, const std::vector<float> &taps);
- int d_ntaps;
int d_nsamples;
- int d_fftsize; // fftsize = ntaps + nsamples - 1
- gri_fft_real_fwd *d_fwdfft; // forward "plan"
- gri_fft_real_rev *d_invfft; // inverse "plan"
- std::vector<float> d_tail; // state carried between blocks for overlap-add
- std::vector<gr_complex> d_xformed_taps; // Fourier xformed taps
- std::vector<float> d_new_taps;
bool d_updated;
+#if 1 // don't enable the sse version until handling it is worked out
+ gri_fft_filter_fff_generic *d_filter;
+#else
+ gri_fft_filter_fff_sse *d_filter;
+#endif
+ std::vector<float> d_new_taps;
/*!
* Construct a FFT filter with the given taps
@@ -58,10 +56,6 @@ class gr_fft_filter_fff : public gr_sync_decimator
* \param taps float filter taps
*/
gr_fft_filter_fff (int decimation, const std::vector<float> &taps);
-
- void compute_sizes(int ntaps);
- int tailsize() const { return d_ntaps - 1; }
- void actual_set_taps (const std::vector<float> &taps);
public:
~gr_fft_filter_fff ();
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc
index 48eb849ab..5a6e753ab 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -79,8 +79,8 @@ gr_pfb_arb_resampler_ccf::gr_pfb_arb_resampler_ccf (float rate,
// Now, actually set the filters' taps
std::vector<float> dtaps;
create_diff_taps(taps, dtaps);
- set_taps(taps, d_taps, d_filters);
- set_taps(dtaps, d_dtaps, d_diff_filters);
+ create_taps(taps, d_taps, d_filters);
+ create_taps(dtaps, d_dtaps, d_diff_filters);
}
gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf ()
@@ -91,9 +91,9 @@ gr_pfb_arb_resampler_ccf::~gr_pfb_arb_resampler_ccf ()
}
void
-gr_pfb_arb_resampler_ccf::set_taps (const std::vector<float> &newtaps,
- std::vector< std::vector<float> > &ourtaps,
- std::vector<gr_fir_ccf*> &ourfilter)
+gr_pfb_arb_resampler_ccf::create_taps (const std::vector<float> &newtaps,
+ std::vector< std::vector<float> > &ourtaps,
+ std::vector<gr_fir_ccf*> &ourfilter)
{
int i,j;
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
index b99ad286b..cf5a79d4e 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_arb_resampler_ccf.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -139,18 +139,23 @@ class gr_pfb_arb_resampler_ccf : public gr_block
void create_diff_taps(const std::vector<float> &newtaps,
std::vector<float> &difftaps);
-
-public:
- ~gr_pfb_arb_resampler_ccf ();
-
+
/*!
* Resets the filterbank's filter taps with the new prototype filter
- * \param taps (vector/list of floats) The prototype filter to populate the filterbank. The taps
- * should be generated at the interpolated sampling rate.
+ * \param newtaps (vector of floats) The prototype filter to populate the filterbank.
+ * The taps should be generated at the interpolated sampling rate.
+ * \param ourtaps (vector of floats) Reference to our internal member of holding the taps.
+ * \param ourfilter (vector of filters) Reference to our internal filter to set the taps for.
*/
- void set_taps (const std::vector<float> &newtaps,
- std::vector< std::vector<float> > &ourtaps,
- std::vector<gr_fir_ccf*> &ourfilter);
+ void create_taps (const std::vector<float> &newtaps,
+ std::vector< std::vector<float> > &ourtaps,
+ std::vector<gr_fir_ccf*> &ourfilter);
+
+
+public:
+ ~gr_pfb_arb_resampler_ccf ();
+
+ // FIXME: See about a set_taps function during runtime.
/*!
* Print all of the filterbank taps to screen.
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
index 7e34551c8..5fda47880 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -33,20 +33,33 @@
#include <cstring>
gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps)
+ const std::vector<float> &taps,
+ float oversample_rate)
{
- return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps));
+ return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps,
+ oversample_rate));
}
gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps)
- : gr_sync_block ("pfb_channelizer_ccf",
- gr_make_io_signature (numchans, numchans, sizeof(gr_complex)),
- gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))),
- d_updated (false)
+ const std::vector<float> &taps,
+ float oversample_rate)
+ : gr_block ("pfb_channelizer_ccf",
+ gr_make_io_signature (numchans, numchans, sizeof(gr_complex)),
+ gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))),
+ d_updated (false), d_numchans(numchans), d_oversample_rate(oversample_rate)
{
- d_numchans = numchans;
+ // The over sampling rate must be rationally related to the number of channels
+ // in that it must be N/i for i in [1,N], which gives an outputsample rate
+ // of [fs/N, fs] where fs is the input sample rate.
+ // This tests the specified input sample rate to see if it conforms to this
+ // requirement within a few significant figures.
+ double intp = 0;
+ double x = (10000.0*rint(numchans / oversample_rate)) / 10000.0;
+ double fltp = modf(numchans / oversample_rate, &intp);
+ if(fltp != 0.0)
+ throw std::invalid_argument("gr_pfb_channelizer: oversample rate must be N/i for i in [1, N]");
+
d_filters = std::vector<gr_fir_ccf*>(d_numchans);
// Create an FIR filter for each channel and zero out the taps
@@ -60,10 +73,28 @@ gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans,
// Create the FFT to handle the output de-spinning of the channels
d_fft = new gri_fft_complex (d_numchans, false);
+
+ // Although the filters change, we use this look up table
+ // to set the index of the FFT input buffer, which equivalently
+ // performs the FFT shift operation on every other turn.
+ d_rate_ratio = (int)rintf(d_numchans / d_oversample_rate);
+ d_idxlut = new int[d_numchans];
+ for(unsigned int i = 0; i < d_numchans; i++) {
+ d_idxlut[i] = d_numchans - ((i + d_rate_ratio) % d_numchans) - 1;
+ }
+
+ // Calculate the number of filtering rounds to do to evenly
+ // align the input vectors with the output channels
+ d_output_multiple = 1;
+ while((d_output_multiple * d_rate_ratio) % d_numchans != 0)
+ d_output_multiple++;
+ set_output_multiple(d_output_multiple);
}
gr_pfb_channelizer_ccf::~gr_pfb_channelizer_ccf ()
{
+ delete [] d_idxlut;
+
for(unsigned int i = 0; i < d_numchans; i++) {
delete d_filters[i];
}
@@ -101,7 +132,7 @@ gr_pfb_channelizer_ccf::set_taps (const std::vector<float> &taps)
}
// Set the history to ensure enough input items for each filter
- set_history (d_taps_per_filter);
+ set_history (d_taps_per_filter+1);
d_updated = true;
}
@@ -121,9 +152,10 @@ gr_pfb_channelizer_ccf::print_taps()
int
-gr_pfb_channelizer_ccf::work (int noutput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
+gr_pfb_channelizer_ccf::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
{
gr_complex *in = (gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
@@ -133,20 +165,35 @@ gr_pfb_channelizer_ccf::work (int noutput_items,
return 0; // history requirements may have changed.
}
- for(int i = 0; i < noutput_items; i++) {
- // Move through filters from bottom to top
- for(int j = d_numchans-1; j >= 0; j--) {
- // Take in the items from the first input stream to d_numchans
- in = (gr_complex*)input_items[d_numchans - 1 - j];
+ int n=1, i=-1, j=0, last;
+ int toconsume = (int)rintf(noutput_items/d_oversample_rate);
+ while(n <= toconsume) {
+ j = 0;
+ i = (i + d_rate_ratio) % d_numchans;
+ last = i;
+ while(i >= 0) {
+ in = (gr_complex*)input_items[j];
+ d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n]);
+ j++;
+ i--;
+ }
- // Filter current input stream from bottom filter to top
- d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]);
+ i = d_numchans-1;
+ while(i > last) {
+ in = (gr_complex*)input_items[j];
+ d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n-1]);
+ j++;
+ i--;
}
+ n += (i+d_rate_ratio) >= (int)d_numchans;
+
// despin through FFT
d_fft->execute();
- memcpy(&out[d_numchans*i], d_fft->get_outbuf(), d_numchans*sizeof(gr_complex));
+ memcpy(out, d_fft->get_outbuf(), d_numchans*sizeof(gr_complex));
+ out += d_numchans;
}
-
+
+ consume_each(toconsume);
return noutput_items;
}
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
index b2e67e817..751673bc7 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -24,12 +24,13 @@
#ifndef INCLUDED_GR_PFB_CHANNELIZER_CCF_H
#define INCLUDED_GR_PFB_CHANNELIZER_CCF_H
-#include <gr_sync_block.h>
+#include <gr_block.h>
class gr_pfb_channelizer_ccf;
typedef boost::shared_ptr<gr_pfb_channelizer_ccf> gr_pfb_channelizer_ccf_sptr;
gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps);
+ const std::vector<float> &taps,
+ float oversample_rate=1);
class gr_fir_ccf;
class gri_fft_complex;
@@ -88,6 +89,19 @@ class gri_fft_complex;
* <B><EM>self._taps = gr.firdes.low_pass_2(1, fs, BW, TB,
* attenuation_dB=ATT, window=gr.firdes.WIN_BLACKMAN_hARRIS)</EM></B>
*
+ * The filter output can also be overs ampled. The over sampling rate
+ * is the ratio of the the actual output sampling rate to the normal
+ * output sampling rate. It must be rationally related to the number
+ * of channels as N/i for i in [1,N], which gives an outputsample rate
+ * of [fs/N, fs] where fs is the input sample rate and N is the number
+ * of channels.
+ *
+ * For example, for 6 channels with fs = 6000 Hz, the normal rate is
+ * 6000/6 = 1000 Hz. Allowable oversampling rates are 6/6, 6/5, 6/4,
+ * 6/3, 6/2, and 6/1 where the output sample rate of a 6/1 oversample
+ * ratio is 6000 Hz, or 6 times the normal 1000 Hz. A rate of 6/5 = 1.2,
+ * so the output rate would be 1200 Hz.
+ *
* The theory behind this block can be found in Chapter 6 of
* the following book.
*
@@ -96,31 +110,50 @@ class gri_fft_complex;
*
*/
-class gr_pfb_channelizer_ccf : public gr_sync_block
+class gr_pfb_channelizer_ccf : public gr_block
{
private:
/*!
* Build the polyphase filterbank decimator.
* \param numchans (unsigned integer) Specifies the number of channels <EM>M</EM>
* \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ * \param oversample_rate (float) The over sampling rate is the ratio of the the actual
+ * output sampling rate to the normal output sampling rate.
+ * It must be rationally related to the number of channels
+ * as N/i for i in [1,N], which gives an outputsample rate
+ * of [fs/N, fs] where fs is the input sample rate and N is
+ * the number of channels.
+ *
+ * For example, for 6 channels with fs = 6000 Hz, the normal
+ * rate is 6000/6 = 1000 Hz. Allowable oversampling rates
+ * are 6/6, 6/5, 6/4, 6/3, 6/2, and 6/1 where the output
+ * sample rate of a 6/1 oversample ratio is 6000 Hz, or
+ * 6 times the normal 1000 Hz.
*/
friend gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps);
+ const std::vector<float> &taps,
+ float oversample_rate);
+ bool d_updated;
+ unsigned int d_numchans;
+ float d_oversample_rate;
std::vector<gr_fir_ccf*> d_filters;
std::vector< std::vector<float> > d_taps;
- gri_fft_complex *d_fft;
- unsigned int d_numchans;
unsigned int d_taps_per_filter;
- bool d_updated;
+ gri_fft_complex *d_fft;
+ int *d_idxlut;
+ int d_rate_ratio;
+ int d_output_multiple;
/*!
* Build the polyphase filterbank decimator.
* \param numchans (unsigned integer) Specifies the number of channels <EM>M</EM>
* \param taps (vector/list of floats) The prototype filter to populate the filterbank.
+ * \param oversample_rate (float) The output over sampling rate.
*/
gr_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps);
+ const std::vector<float> &taps,
+ float oversample_rate);
public:
~gr_pfb_channelizer_ccf ();
@@ -136,9 +169,10 @@ public:
*/
void print_taps();
- int work (int noutput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
};
#endif
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i
index 4bef90e22..63e3e0fe6 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i
+++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -23,13 +23,15 @@
GR_SWIG_BLOCK_MAGIC(gr,pfb_channelizer_ccf);
gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps);
+ const std::vector<float> &taps,
+ float oversample_rate=1);
-class gr_pfb_channelizer_ccf : public gr_sync_block
+class gr_pfb_channelizer_ccf : public gr_block
{
private:
gr_pfb_channelizer_ccf (unsigned int numchans,
- const std::vector<float> &taps);
+ const std::vector<float> &taps,
+ float oversample_rate);
public:
~gr_pfb_channelizer_ccf ();
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
index 59454afe5..ff4fb70a3 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -93,9 +93,16 @@ gr_pfb_clock_sync_ccf::~gr_pfb_clock_sync_ccf ()
{
for(int i = 0; i < d_nfilters; i++) {
delete d_filters[i];
+ delete d_diff_filters[i];
}
}
+bool
+gr_pfb_clock_sync_ccf::check_topology(int ninputs, int noutputs)
+{
+ return noutputs == 1 || noutputs == 4;
+}
+
void
gr_pfb_clock_sync_ccf::set_taps (const std::vector<float> &newtaps,
std::vector< std::vector<float> > &ourtaps,
@@ -219,8 +226,8 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items,
gr_complex *in = (gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
- float *err, *outrate, *outk;
- if(output_items.size() > 2) {
+ float *err = 0, *outrate = 0, *outk = 0;
+ if(output_items.size() == 4) {
err = (float *) output_items[1];
outrate = (float*)output_items[2];
outk = (float*)output_items[3];
@@ -271,7 +278,7 @@ gr_pfb_clock_sync_ccf::general_work (int noutput_items,
i++;
count += (int)floor(d_sps);
- if(output_items.size() > 2) {
+ if(output_items.size() == 4) {
err[i] = error;
outrate[i] = d_rate_f;
outk[i] = d_k;
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
index a07192a7f..4e6ef5fc4 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_ccf.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -43,6 +43,71 @@ class gr_fir_ccf;
*
* \ingroup filter_blk
*
+ * This block performs timing synchronization for PAM signals by minimizing the
+ * derivative of the filtered signal, which in turn maximizes the SNR and
+ * minimizes ISI.
+ *
+ * This approach works by setting up two filterbanks; one filterbanke contains the
+ * signal's pulse shaping matched filter (such as a root raised cosine filter),
+ * where each branch of the filterbank contains a different phase of the filter.
+ * The second filterbank contains the derivatives of the filters in the first
+ * filterbank. Thinking of this in the time domain, the first filterbank contains
+ * filters that have a sinc shape to them. We want to align the output signal to
+ * be sampled at exactly the peak of the sinc shape. The derivative of the sinc
+ * contains a zero at the maximum point of the sinc (sinc(0) = 1, sinc(0)' = 0).
+ * Furthermore, the region around the zero point is relatively linear. We make
+ * use of this fact to generate the error signal.
+ *
+ * If the signal out of the derivative filters is d_i[n] for the ith filter, and
+ * the output of the matched filter is x_i[n], we calculate the error as:
+ * e[n] = (Re{x_i[n]} * Re{d_i[n]} + Im{x_i[n]} * Im{d_i[n]}) / 2.0
+ * This equation averages the error in the real and imaginary parts. There are two
+ * reasons we multiply by the signal itself. First, if the symbol could be positive
+ * or negative going, but we want the error term to always tell us to go in the
+ * same direction depending on which side of the zero point we are on. The sign of
+ * x_i[n] adjusts the error term to do this. Second, the magnitude of x_i[n] scales
+ * the error term depending on the symbol's amplitude, so larger signals give us
+ * a stronger error term because we have more confidence in that symbol's value.
+ * Using the magnitude of x_i[n] instead of just the sign is especially good for
+ * signals with low SNR.
+ *
+ * The error signal, e[n], gives us a value proportional to how far away from the zero
+ * point we are in the derivative signal. We want to drive this value to zero, so we
+ * set up a second order loop. We have two variables for this loop; d_k is the filter
+ * number in the filterbank we are on and d_rate is the rate which we travel through
+ * the filters in the steady state. That is, due to the natural clock differences between
+ * the transmitter and receiver, d_rate represents that difference and would traverse
+ * the filter phase paths to keep the receiver locked. Thinking of this as a second-order
+ * PLL, the d_rate is the frequency and d_k is the phase. So we update d_rate and d_k
+ * using the standard loop equations based on two error signals, d_alpha and d_beta.
+ * We have these two values set based on each other for a critically damped system, so in
+ * the block constructor, we just ask for "gain," which is d_alpha while d_beta is
+ * equal to (gain^2)/4.
+ *
+ * The clock sync block needs to know the number of samples per second (sps), because it
+ * only returns a single point representing the sample. The sps can be any positive real
+ * number and does not need to be an integer. The filter taps must also be specified. The
+ * taps are generated by first conceiving of the prototype filter that would be the signal's
+ * matched filter. Then interpolate this by the number of filters in the filterbank. These
+ * are then distributed among all of the filters. So if the prototype filter was to have
+ * 45 taps in it, then each path of the filterbank will also have 45 taps. This is easily
+ * done by building the filter with the sample rate multiplied by the number of filters
+ * to use.
+ *
+ * The number of filters can also be set and defaults to 32. With 32 filters, you get a
+ * good enough resolution in the phase to produce very small, almost unnoticeable, ISI.
+ * Going to 64 filters can reduce this more, but after that there is very little gained
+ * for the extra complexity.
+ *
+ * The initial phase is another settable parameter and refers to the filter path the
+ * algorithm initially looks at (i.e., d_k starts at init_phase). This value defaults
+ * to zero, but it might be useful to start at a different phase offset, such as the mid-
+ * point of the filters.
+ *
+ * The final parameter is the max_rate_devitation, which defaults to 1.5. This is how far
+ * we allow d_rate to swing, positive or negative, from 0. Constraining the rate can help
+ * keep the algorithm from walking too far away to lock during times when there is no signal.
+ *
*/
class gr_pfb_clock_sync_ccf : public gr_block
@@ -50,6 +115,14 @@ class gr_pfb_clock_sync_ccf : public gr_block
private:
/*!
* Build the polyphase filterbank timing synchronizer.
+ * \param sps (double) The number of samples per second in the incoming signal
+ * \param gain (float) The alpha gain of the control loop; beta = (gain^2)/4 by default.
+ * \param taps (vector<int>) The filter taps.
+ * \param filter_size (uint) The number of filters in the filterbank (default = 32).
+ * \param init_phase (float) The initial phase to look at, or which filter to start
+ * with (default = 0).
+ * \param max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5).
+ *
*/
friend gr_pfb_clock_sync_ccf_sptr gr_make_pfb_clock_sync_ccf (double sps, float gain,
const std::vector<float> &taps,
@@ -96,29 +169,53 @@ public:
void set_taps (const std::vector<float> &taps,
std::vector< std::vector<float> > &ourtaps,
std::vector<gr_fir_ccf*> &ourfilter);
+
+ /*!
+ * Returns the taps of the matched filter
+ */
std::vector<float> channel_taps(int channel);
+
+ /*!
+ * Returns the taps in the derivative filter
+ */
std::vector<float> diff_channel_taps(int channel);
/*!
* Print all of the filterbank taps to screen.
*/
void print_taps();
+
+ /*!
+ * Print all of the filterbank taps of the derivative filter to screen.
+ */
void print_diff_taps();
+ /*!
+ * Set the gain value alpha for the control loop
+ */
void set_alpha(float alpha)
{
d_alpha = alpha;
}
+
+ /*!
+ * Set the gain value beta for the control loop
+ */
void set_beta(float beta)
{
d_beta = beta;
}
+ /*!
+ * Set the maximum deviation from 0 d_rate can have
+ */
void set_max_rate_deviation(float m)
{
d_max_dev = m;
}
+ bool check_topology(int ninputs, int noutputs);
+
int general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc
index d1d2f05db..86de3b5a1 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -93,9 +93,16 @@ gr_pfb_clock_sync_fff::~gr_pfb_clock_sync_fff ()
{
for(int i = 0; i < d_nfilters; i++) {
delete d_filters[i];
+ delete d_diff_filters[i];
}
}
+bool
+gr_pfb_clock_sync_fff::check_topology(int ninputs, int noutputs)
+{
+ return noutputs == 1 || noutputs == 4;
+}
+
void
gr_pfb_clock_sync_fff::set_taps (const std::vector<float> &newtaps,
std::vector< std::vector<float> > &ourtaps,
@@ -219,8 +226,8 @@ gr_pfb_clock_sync_fff::general_work (int noutput_items,
float *in = (float *) input_items[0];
float *out = (float *) output_items[0];
- float *err, *outrate, *outk;
- if(output_items.size() > 2) {
+ float *err = 0, *outrate = 0, *outk = 0;
+ if(output_items.size() == 4) {
err = (float *) output_items[1];
outrate = (float*)output_items[2];
outk = (float*)output_items[3];
@@ -269,7 +276,7 @@ gr_pfb_clock_sync_fff::general_work (int noutput_items,
i++;
count += (int)floor(d_sps);
- if(output_items.size() > 2) {
+ if(output_items.size() == 4) {
err[i] = error;
outrate[i] = d_rate_f;
outk[i] = d_k;
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h
index 913f798fe..fa1279a7c 100644
--- a/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h
+++ b/gnuradio-core/src/lib/filter/gr_pfb_clock_sync_fff.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2009 Free Software Foundation, Inc.
+ * Copyright 2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -43,6 +43,71 @@ class gr_fir_fff;
*
* \ingroup filter_blk
*
+ * This block performs timing synchronization for PAM signals by minimizing the
+ * derivative of the filtered signal, which in turn maximizes the SNR and
+ * minimizes ISI.
+ *
+ * This approach works by setting up two filterbanks; one filterbanke contains the
+ * signal's pulse shaping matched filter (such as a root raised cosine filter),
+ * where each branch of the filterbank contains a different phase of the filter.
+ * The second filterbank contains the derivatives of the filters in the first
+ * filterbank. Thinking of this in the time domain, the first filterbank contains
+ * filters that have a sinc shape to them. We want to align the output signal to
+ * be sampled at exactly the peak of the sinc shape. The derivative of the sinc
+ * contains a zero at the maximum point of the sinc (sinc(0) = 1, sinc(0)' = 0).
+ * Furthermore, the region around the zero point is relatively linear. We make
+ * use of this fact to generate the error signal.
+ *
+ * If the signal out of the derivative filters is d_i[n] for the ith filter, and
+ * the output of the matched filter is x_i[n], we calculate the error as:
+ * e[n] = (Re{x_i[n]} * Re{d_i[n]} + Im{x_i[n]} * Im{d_i[n]}) / 2.0
+ * This equation averages the error in the real and imaginary parts. There are two
+ * reasons we multiply by the signal itself. First, if the symbol could be positive
+ * or negative going, but we want the error term to always tell us to go in the
+ * same direction depending on which side of the zero point we are on. The sign of
+ * x_i[n] adjusts the error term to do this. Second, the magnitude of x_i[n] scales
+ * the error term depending on the symbol's amplitude, so larger signals give us
+ * a stronger error term because we have more confidence in that symbol's value.
+ * Using the magnitude of x_i[n] instead of just the sign is especially good for
+ * signals with low SNR.
+ *
+ * The error signal, e[n], gives us a value proportional to how far away from the zero
+ * point we are in the derivative signal. We want to drive this value to zero, so we
+ * set up a second order loop. We have two variables for this loop; d_k is the filter
+ * number in the filterbank we are on and d_rate is the rate which we travel through
+ * the filters in the steady state. That is, due to the natural clock differences between
+ * the transmitter and receiver, d_rate represents that difference and would traverse
+ * the filter phase paths to keep the receiver locked. Thinking of this as a second-order
+ * PLL, the d_rate is the frequency and d_k is the phase. So we update d_rate and d_k
+ * using the standard loop equations based on two error signals, d_alpha and d_beta.
+ * We have these two values set based on each other for a critically damped system, so in
+ * the block constructor, we just ask for "gain," which is d_alpha while d_beta is
+ * equal to (gain^2)/4.
+ *
+ * The clock sync block needs to know the number of samples per second (sps), because it
+ * only returns a single point representing the sample. The sps can be any positive real
+ * number and does not need to be an integer. The filter taps must also be specified. The
+ * taps are generated by first conceiving of the prototype filter that would be the signal's
+ * matched filter. Then interpolate this by the number of filters in the filterbank. These
+ * are then distributed among all of the filters. So if the prototype filter was to have
+ * 45 taps in it, then each path of the filterbank will also have 45 taps. This is easily
+ * done by building the filter with the sample rate multiplied by the number of filters
+ * to use.
+ *
+ * The number of filters can also be set and defaults to 32. With 32 filters, you get a
+ * good enough resolution in the phase to produce very small, almost unnoticeable, ISI.
+ * Going to 64 filters can reduce this more, but after that there is very little gained
+ * for the extra complexity.
+ *
+ * The initial phase is another settable parameter and refers to the filter path the
+ * algorithm initially looks at (i.e., d_k starts at init_phase). This value defaults
+ * to zero, but it might be useful to start at a different phase offset, such as the mid-
+ * point of the filters.
+ *
+ * The final parameter is the max_rate_devitation, which defaults to 1.5. This is how far
+ * we allow d_rate to swing, positive or negative, from 0. Constraining the rate can help
+ * keep the algorithm from walking too far away to lock during times when there is no signal.
+ *
*/
class gr_pfb_clock_sync_fff : public gr_block
@@ -50,6 +115,14 @@ class gr_pfb_clock_sync_fff : public gr_block
private:
/*!
* Build the polyphase filterbank timing synchronizer.
+ * \param sps (double) The number of samples per second in the incoming signal
+ * \param gain (float) The alpha gain of the control loop; beta = (gain^2)/4 by default.
+ * \param taps (vector<int>) The filter taps.
+ * \param filter_size (uint) The number of filters in the filterbank (default = 32).
+ * \param init_phase (float) The initial phase to look at, or which filter to start
+ * with (default = 0).
+ * \param max_rate_deviation (float) Distance from 0 d_rate can get (default = 1.5).
+ *
*/
friend gr_pfb_clock_sync_fff_sptr gr_make_pfb_clock_sync_fff (double sps, float gain,
const std::vector<float> &taps,
@@ -96,29 +169,53 @@ public:
void set_taps (const std::vector<float> &taps,
std::vector< std::vector<float> > &ourtaps,
std::vector<gr_fir_fff*> &ourfilter);
+
+ /*!
+ * Returns the taps of the matched filter
+ */
std::vector<float> channel_taps(int channel);
+
+ /*!
+ * Returns the taps in the derivative filter
+ */
std::vector<float> diff_channel_taps(int channel);
/*!
* Print all of the filterbank taps to screen.
*/
void print_taps();
+
+ /*!
+ * Print all of the filterbank taps of the derivative filter to screen.
+ */
void print_diff_taps();
+ /*!
+ * Set the gain value alpha for the control loop
+ */
void set_alpha(float alpha)
{
d_alpha = alpha;
}
+
+ /*!
+ * Set the gain value beta for the control loop
+ */
void set_beta(float beta)
{
d_beta = beta;
}
+ /*!
+ * Set the maximum deviation from 0 d_rate can have
+ */
void set_max_rate_deviation(float m)
{
d_max_dev = m;
}
-
+
+ bool check_topology(int ninputs, int noutputs);
+
int general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.cc b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.cc
new file mode 100644
index 000000000..1bf4a6f4b
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.cc
@@ -0,0 +1,167 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gri_fft_filter_ccc_generic.h>
+#include <gri_fft.h>
+#include <assert.h>
+#include <stdexcept>
+#include <cstdio>
+#include <cstring>
+#include <fftw3.h>
+
+gri_fft_filter_ccc_generic::gri_fft_filter_ccc_generic (int decimation,
+ const std::vector<gr_complex> &taps)
+ : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0), d_invfft(0)
+{
+ set_taps(taps);
+}
+
+gri_fft_filter_ccc_generic::~gri_fft_filter_ccc_generic ()
+{
+ delete d_fwdfft;
+ delete d_invfft;
+}
+
+#if 0
+static void
+print_vector_complex(const std::string label, const std::vector<gr_complex> &x)
+{
+ std::cout << label;
+ for (unsigned i = 0; i < x.size(); i++)
+ std::cout << x[i] << " ";
+ std::cout << "\n";
+}
+#endif
+
+
+/*
+ * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
+ */
+int
+gri_fft_filter_ccc_generic::set_taps (const std::vector<gr_complex> &taps)
+{
+ int i = 0;
+ compute_sizes(taps.size());
+
+ d_tail.resize(tailsize());
+ for (i = 0; i < tailsize(); i++)
+ d_tail[i] = 0;
+
+ gr_complex *in = d_fwdfft->get_inbuf();
+ gr_complex *out = d_fwdfft->get_outbuf();
+
+ float scale = 1.0 / d_fftsize;
+
+ // Compute forward xform of taps.
+ // Copy taps into first ntaps slots, then pad with zeros
+ for (i = 0; i < d_ntaps; i++)
+ in[i] = taps[i] * scale;
+
+ for (; i < d_fftsize; i++)
+ in[i] = 0;
+
+ d_fwdfft->execute(); // do the xform
+
+ // now copy output to d_xformed_taps
+ for (i = 0; i < d_fftsize; i++)
+ d_xformed_taps[i] = out[i];
+
+ return d_nsamples;
+}
+
+// determine and set d_ntaps, d_nsamples, d_fftsize
+
+void
+gri_fft_filter_ccc_generic::compute_sizes(int ntaps)
+{
+ int old_fftsize = d_fftsize;
+ d_ntaps = ntaps;
+ d_fftsize = (int) (2 * pow(2.0, ceil(log(ntaps) / log(2))));
+ d_nsamples = d_fftsize - d_ntaps + 1;
+
+ if (0)
+ fprintf(stderr, "gri_fft_filter_ccc_generic: ntaps = %d, fftsize = %d, nsamples = %d\n",
+ d_ntaps, d_fftsize, d_nsamples);
+
+ assert(d_fftsize == d_ntaps + d_nsamples -1 );
+
+ if (d_fftsize != old_fftsize){ // compute new plans
+ delete d_fwdfft;
+ delete d_invfft;
+ d_fwdfft = new gri_fft_complex(d_fftsize, true);
+ d_invfft = new gri_fft_complex(d_fftsize, false);
+ d_xformed_taps.resize(d_fftsize);
+ }
+}
+
+int
+gri_fft_filter_ccc_generic::filter (int nitems, const gr_complex *input, gr_complex *output)
+{
+ int dec_ctr = 0;
+ int j = 0;
+ int ninput_items = nitems * d_decimation;
+
+ for (int i = 0; i < ninput_items; i += d_nsamples){
+
+ memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(gr_complex));
+
+ for (j = d_nsamples; j < d_fftsize; j++)
+ d_fwdfft->get_inbuf()[j] = 0;
+
+ d_fwdfft->execute(); // compute fwd xform
+
+ gr_complex *a = d_fwdfft->get_outbuf();
+ gr_complex *b = &d_xformed_taps[0];
+ gr_complex *c = d_invfft->get_inbuf();
+
+ for (j = 0; j < d_fftsize; j+=1) { // filter in the freq domain
+ c[j] = a[j] * b[j];
+ }
+
+ d_invfft->execute(); // compute inv xform
+
+ // add in the overlapping tail
+
+ for (j = 0; j < tailsize(); j++)
+ d_invfft->get_outbuf()[j] += d_tail[j];
+
+ // copy nsamples to output
+ j = dec_ctr;
+ while (j < d_nsamples) {
+ *output++ = d_invfft->get_outbuf()[j];
+ j += d_decimation;
+ }
+ dec_ctr = (j - d_nsamples);
+
+ // stash the tail
+ memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
+ tailsize() * sizeof(gr_complex));
+ }
+
+ assert(dec_ctr == 0);
+
+ return nitems;
+}
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.h b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.h
new file mode 100644
index 000000000..3cd9105c7
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_generic.h
@@ -0,0 +1,82 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_GRI_FFT_FILTER_CCC_GENERIC_H
+#define INCLUDED_GRI_FFT_FILTER_CCC_GENERIC_H
+
+#include <gr_complex.h>
+#include <vector>
+
+class gri_fft_complex;
+
+/*!
+ * \brief Fast FFT filter with gr_complex input, gr_complex output and gr_complex taps
+ * \ingroup filter_blk
+ */
+class gri_fft_filter_ccc_generic
+{
+ private:
+ int d_ntaps;
+ int d_nsamples;
+ int d_fftsize; // fftsize = ntaps + nsamples - 1
+ int d_decimation;
+ gri_fft_complex *d_fwdfft; // forward "plan"
+ gri_fft_complex *d_invfft; // inverse "plan"
+ std::vector<gr_complex> d_tail; // state carried between blocks for overlap-add
+ std::vector<gr_complex> d_xformed_taps; // Fourier xformed taps
+ std::vector<gr_complex> d_new_taps;
+
+ void compute_sizes(int ntaps);
+ int tailsize() const { return d_ntaps - 1; }
+
+ public:
+ /*!
+ * \brief Construct an FFT filter for complex vectors with the given taps and decimation rate.
+ *
+ * This is the basic implementation for performing FFT filter for fast convolution
+ * in other blocks for complex vectors (such as gr_fft_filter_ccc).
+ * \param decimation The decimation rate of the filter (int)
+ * \param taps The filter taps (complex)
+ */
+ gri_fft_filter_ccc_generic (int decimation, const std::vector<gr_complex> &taps);
+ ~gri_fft_filter_ccc_generic ();
+
+ /*!
+ * \brief Set new taps for the filter.
+ *
+ * Sets new taps and resets the class properties to handle different sizes
+ * \param taps The filter taps (complex)
+ */
+ int set_taps (const std::vector<gr_complex> &taps);
+
+ /*!
+ * \brief Perform the filter operation
+ *
+ * \param nitems The number of items to produce
+ * \param input The input vector to be filtered
+ * \param output The result of the filter operation
+ */
+ int filter (int nitems, const gr_complex *input, gr_complex *output);
+
+};
+
+#endif /* INCLUDED_GRI_FFT_FILTER_CCC_GENERIC_H */
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.cc b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.cc
new file mode 100644
index 000000000..b7d925ff3
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.cc
@@ -0,0 +1,186 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gri_fft_filter_ccc_sse.h>
+#include <gri_fft.h>
+#include <assert.h>
+#include <stdexcept>
+#include <cstdio>
+#include <xmmintrin.h>
+#include <fftw3.h>
+
+gri_fft_filter_ccc_sse::gri_fft_filter_ccc_sse (int decimation,
+ const std::vector<gr_complex> &taps)
+ : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0), d_invfft(0)
+{
+ d_xformed_taps = (gr_complex*)fftwf_malloc(1*sizeof(gr_complex));
+ set_taps(taps);
+}
+
+gri_fft_filter_ccc_sse::~gri_fft_filter_ccc_sse ()
+{
+ fftwf_free(d_xformed_taps);
+ delete d_fwdfft;
+ delete d_invfft;
+}
+
+#if 0
+static void
+print_vector_complex(const std::string label, const std::vector<gr_complex> &x)
+{
+ std::cout << label;
+ for (unsigned i = 0; i < x.size(); i++)
+ std::cout << x[i] << " ";
+ std::cout << "\n";
+}
+#endif
+
+
+/*
+ * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
+ */
+int
+gri_fft_filter_ccc_sse::set_taps (const std::vector<gr_complex> &taps)
+{
+ int i = 0;
+ compute_sizes(taps.size());
+
+ d_tail.resize(tailsize());
+ for (i = 0; i < tailsize(); i++)
+ d_tail[i] = 0;
+
+ gr_complex *in = d_fwdfft->get_inbuf();
+ gr_complex *out = d_fwdfft->get_outbuf();
+
+ float scale = 1.0 / d_fftsize;
+
+ // Compute forward xform of taps.
+ // Copy taps into first ntaps slots, then pad with zeros
+ for (i = 0; i < d_ntaps; i++)
+ in[i] = taps[i] * scale;
+
+ for (; i < d_fftsize; i++)
+ in[i] = 0;
+
+ d_fwdfft->execute(); // do the xform
+
+ // now copy output to d_xformed_taps
+ for (i = 0; i < d_fftsize; i++)
+ d_xformed_taps[i] = out[i];
+
+ return d_nsamples;
+}
+
+// determine and set d_ntaps, d_nsamples, d_fftsize
+
+void
+gri_fft_filter_ccc_sse::compute_sizes(int ntaps)
+{
+ int old_fftsize = d_fftsize;
+ d_ntaps = ntaps;
+ d_fftsize = (int) (2 * pow(2.0, ceil(log(ntaps) / log(2))));
+ d_nsamples = d_fftsize - d_ntaps + 1;
+
+ if (0)
+ fprintf(stderr, "gri_fft_filter_ccc_sse: ntaps = %d, fftsize = %d, nsamples = %d\n",
+ d_ntaps, d_fftsize, d_nsamples);
+
+ assert(d_fftsize == d_ntaps + d_nsamples -1 );
+
+ if (d_fftsize != old_fftsize){ // compute new plans
+ delete d_fwdfft;
+ delete d_invfft;
+ d_fwdfft = new gri_fft_complex(d_fftsize, true);
+ d_invfft = new gri_fft_complex(d_fftsize, false);
+
+ fftwf_free(d_xformed_taps);
+ d_xformed_taps = (gr_complex*)fftwf_malloc((d_fftsize)*sizeof(gr_complex));
+ }
+}
+
+int
+gri_fft_filter_ccc_sse::filter (int nitems, const gr_complex *input, gr_complex *output)
+{
+ int dec_ctr = 0;
+ int j = 0;
+ int ninput_items = nitems * d_decimation;
+
+ for (int i = 0; i < ninput_items; i += d_nsamples){
+
+ memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(gr_complex));
+
+ for (j = d_nsamples; j < d_fftsize; j++)
+ d_fwdfft->get_inbuf()[j] = 0;
+
+ d_fwdfft->execute(); // compute fwd xform
+
+ float *a = (float*)(d_fwdfft->get_outbuf());
+ float *b = (float*)(&d_xformed_taps[0]);
+ float *c = (float*)(d_invfft->get_inbuf());
+
+ __m128 x0, x1, x2, t0, t1, m;
+ m = _mm_set_ps(-1, 1, -1, 1);
+ for (j = 0; j < 2*d_fftsize; j+=4) { // filter in the freq domain
+ x0 = _mm_load_ps(&a[j]);
+ t0 = _mm_load_ps(&b[j]);
+
+ t1 = _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(3, 3, 1, 1));
+ t0 = _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(2, 2, 0, 0));
+ t1 = _mm_mul_ps(t1, m);
+
+ x1 = _mm_mul_ps(x0, t0);
+ x2 = _mm_mul_ps(x0, t1);
+
+ x2 = _mm_shuffle_ps(x2, x2, _MM_SHUFFLE(2, 3, 0, 1));
+ x2 = _mm_add_ps(x1, x2);
+
+ _mm_store_ps(&c[j], x2);
+ }
+
+ d_invfft->execute(); // compute inv xform
+
+ // add in the overlapping tail
+
+ for (j = 0; j < tailsize(); j++)
+ d_invfft->get_outbuf()[j] += d_tail[j];
+
+ // copy nsamples to output
+ j = dec_ctr;
+ while (j < d_nsamples) {
+ *output++ = d_invfft->get_outbuf()[j];
+ j += d_decimation;
+ }
+ dec_ctr = (j - d_nsamples);
+
+ // stash the tail
+ memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
+ tailsize() * sizeof(gr_complex));
+ }
+
+ assert(dec_ctr == 0);
+
+ return nitems;
+}
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.h b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.h
new file mode 100644
index 000000000..d1c54f01f
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_ccc_sse.h
@@ -0,0 +1,82 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_GRI_FFT_FILTER_CCC_SSE_H
+#define INCLUDED_GRI_FFT_FILTER_CCC_SSE_H
+
+#include <gr_complex.h>
+#include <vector>
+
+class gri_fft_complex;
+
+/*!
+ * \brief Fast FFT filter with gr_complex input, gr_complex output and gr_complex taps
+ * \ingroup filter_blk
+ */
+class gri_fft_filter_ccc_sse
+{
+ private:
+ int d_ntaps;
+ int d_nsamples;
+ int d_fftsize; // fftsize = ntaps + nsamples - 1
+ int d_decimation;
+ gri_fft_complex *d_fwdfft; // forward "plan"
+ gri_fft_complex *d_invfft; // inverse "plan"
+ std::vector<gr_complex> d_tail; // state carried between blocks for overlap-add
+ gr_complex *d_xformed_taps;
+ std::vector<gr_complex> d_new_taps;
+
+ void compute_sizes(int ntaps);
+ int tailsize() const { return d_ntaps - 1; }
+
+ public:
+ /*!
+ * \brief Construct an FFT filter for complex vectors with the given taps and decimation rate.
+ *
+ * This is the basic implementation for performing FFT filter for fast convolution
+ * in other blocks for complex vectors (such as gr_fft_filter_ccc).
+ * \param decimation The decimation rate of the filter (int)
+ * \param taps The filter taps (complex)
+ */
+ gri_fft_filter_ccc_sse (int decimation, const std::vector<gr_complex> &taps);
+ ~gri_fft_filter_ccc_sse ();
+
+ /*!
+ * \brief Set new taps for the filter.
+ *
+ * Sets new taps and resets the class properties to handle different sizes
+ * \param taps The filter taps (complex)
+ */
+ int set_taps (const std::vector<gr_complex> &taps);
+
+ /*!
+ * \brief Perform the filter operation
+ *
+ * \param nitems The number of items to produce
+ * \param input The input vector to be filtered
+ * \param output The result of the filter operation
+ */
+ int filter (int nitems, const gr_complex *input, gr_complex *output);
+
+};
+
+#endif /* INCLUDED_GRI_FFT_FILTER_CCC_SSE_H */
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.cc b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.cc
new file mode 100644
index 000000000..74058fa93
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.cc
@@ -0,0 +1,158 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gri_fft_filter_fff_generic.h>
+#include <gri_fft.h>
+#include <assert.h>
+#include <stdexcept>
+#include <cstdio>
+#include <cstring>
+
+gri_fft_filter_fff_generic::gri_fft_filter_fff_generic (int decimation,
+ const std::vector<float> &taps)
+ : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0), d_invfft(0)
+{
+ set_taps(taps);
+}
+
+gri_fft_filter_fff_generic::~gri_fft_filter_fff_generic ()
+{
+ delete d_fwdfft;
+ delete d_invfft;
+}
+
+/*
+ * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
+ */
+int
+gri_fft_filter_fff_generic::set_taps (const std::vector<float> &taps)
+{
+ int i = 0;
+ compute_sizes(taps.size());
+
+ d_tail.resize(tailsize());
+ for (i = 0; i < tailsize(); i++)
+ d_tail[i] = 0;
+
+ float *in = d_fwdfft->get_inbuf();
+ gr_complex *out = d_fwdfft->get_outbuf();
+
+ float scale = 1.0 / d_fftsize;
+
+ // Compute forward xform of taps.
+ // Copy taps into first ntaps slots, then pad with zeros
+ for (i = 0; i < d_ntaps; i++)
+ in[i] = taps[i] * scale;
+
+ for (; i < d_fftsize; i++)
+ in[i] = 0;
+
+ d_fwdfft->execute(); // do the xform
+
+ // now copy output to d_xformed_taps
+ for (i = 0; i < d_fftsize/2+1; i++)
+ d_xformed_taps[i] = out[i];
+
+ return d_nsamples;
+}
+
+// determine and set d_ntaps, d_nsamples, d_fftsize
+
+void
+gri_fft_filter_fff_generic::compute_sizes(int ntaps)
+{
+ int old_fftsize = d_fftsize;
+ d_ntaps = ntaps;
+ d_fftsize = (int) (2 * pow(2.0, ceil(log(ntaps) / log(2))));
+ d_nsamples = d_fftsize - d_ntaps + 1;
+
+ if (0)
+ fprintf(stderr, "gri_fft_filter_fff_generic: ntaps = %d, fftsize = %d, nsamples = %d\n",
+ d_ntaps, d_fftsize, d_nsamples);
+
+ assert(d_fftsize == d_ntaps + d_nsamples -1 );
+
+ if (d_fftsize != old_fftsize){ // compute new plans
+ delete d_fwdfft;
+ delete d_invfft;
+ d_fwdfft = new gri_fft_real_fwd(d_fftsize);
+ d_invfft = new gri_fft_real_rev(d_fftsize);
+ d_xformed_taps.resize(d_fftsize/2+1);
+ }
+}
+
+int
+gri_fft_filter_fff_generic::filter (int nitems, const float *input, float *output)
+{
+ int dec_ctr = 0;
+ int j = 0;
+ int ninput_items = nitems * d_decimation;
+
+ for (int i = 0; i < ninput_items; i += d_nsamples){
+
+ memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(float));
+
+ for (j = d_nsamples; j < d_fftsize; j++)
+ d_fwdfft->get_inbuf()[j] = 0;
+
+ d_fwdfft->execute(); // compute fwd xform
+
+ gr_complex *a = d_fwdfft->get_outbuf();
+ gr_complex *b = &d_xformed_taps[0];
+ gr_complex *c = d_invfft->get_inbuf();
+
+ for (j = 0; j < d_fftsize/2+1; j++) { // filter in the freq domain
+ c[j] = a[j] * b[j];
+ }
+
+ d_invfft->execute(); // compute inv xform
+
+ // add in the overlapping tail
+
+ for (j = 0; j < tailsize(); j++)
+ d_invfft->get_outbuf()[j] += d_tail[j];
+
+ // copy nsamples to output
+
+ //memcpy(out, d_invfft->get_outbuf(), d_nsamples * sizeof(float));
+ //out += d_nsamples;
+
+ j = dec_ctr;
+ while (j < d_nsamples) {
+ *output++ = d_invfft->get_outbuf()[j];
+ j += d_decimation;
+ }
+ dec_ctr = (j - d_nsamples);
+
+ // stash the tail
+ memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
+ tailsize() * sizeof(float));
+ }
+
+ assert(dec_ctr == 0);
+
+ return nitems;
+}
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.h b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.h
new file mode 100644
index 000000000..6c31632d5
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_generic.h
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_GRI_FFT_FILTER_FFF_GENERIC_H
+#define INCLUDED_GRI_FFT_FILTER_FFF_GENERIC_H
+
+#include <gr_complex.h>
+#include <vector>
+
+class gri_fft_real_fwd;
+class gri_fft_real_rev;
+
+class gri_fft_filter_fff_generic
+{
+ private:
+ int d_ntaps;
+ int d_nsamples;
+ int d_fftsize; // fftsize = ntaps + nsamples - 1
+ int d_decimation;
+ gri_fft_real_fwd *d_fwdfft; // forward "plan"
+ gri_fft_real_rev *d_invfft; // inverse "plan"
+ std::vector<float> d_tail; // state carried between blocks for overlap-add
+ std::vector<gr_complex> d_xformed_taps; // Fourier xformed taps
+ std::vector<float> d_new_taps;
+
+
+ void compute_sizes(int ntaps);
+ int tailsize() const { return d_ntaps - 1; }
+
+ public:
+ /*!
+ * \brief Construct a FFT filter for float vectors with the given taps and decimation rate.
+ *
+ * This is the basic implementation for performing FFT filter for fast convolution
+ * in other blocks for floating point vectors (such as gr_fft_filter_fff).
+ * \param decimation The decimation rate of the filter (int)
+ * \param taps The filter taps (float)
+ */
+ gri_fft_filter_fff_generic (int decimation, const std::vector<float> &taps);
+ ~gri_fft_filter_fff_generic ();
+
+ /*!
+ * \brief Set new taps for the filter.
+ *
+ * Sets new taps and resets the class properties to handle different sizes
+ * \param taps The filter taps (float)
+ */
+ int set_taps (const std::vector<float> &taps);
+
+ /*!
+ * \brief Perform the filter operation
+ *
+ * \param nitems The number of items to produce
+ * \param input The input vector to be filtered
+ * \param output The result of the filter operation
+ */
+ int filter (int nitems, const float *input, float *output);
+
+};
+
+#endif /* INCLUDED_GRI_FFT_FILTER_FFF_GENERIC_H */
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.cc b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.cc
new file mode 100644
index 000000000..2680e6594
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.cc
@@ -0,0 +1,184 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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 <gri_fft_filter_fff_sse.h>
+#include <gri_fft.h>
+#include <assert.h>
+#include <stdexcept>
+#include <cstdio>
+#include <xmmintrin.h>
+#include <fftw3.h>
+
+gri_fft_filter_fff_sse::gri_fft_filter_fff_sse (int decimation,
+ const std::vector<float> &taps)
+ : d_fftsize(-1), d_decimation(decimation), d_fwdfft(0), d_invfft(0)
+{
+ d_xformed_taps = (gr_complex*)fftwf_malloc(1*sizeof(gr_complex));
+ set_taps(taps);
+}
+
+gri_fft_filter_fff_sse::~gri_fft_filter_fff_sse ()
+{
+ fftwf_free(d_xformed_taps);
+ delete d_fwdfft;
+ delete d_invfft;
+}
+
+/*
+ * determines d_ntaps, d_nsamples, d_fftsize, d_xformed_taps
+ */
+int
+gri_fft_filter_fff_sse::set_taps (const std::vector<float> &taps)
+{
+ int i = 0;
+ compute_sizes(taps.size());
+
+ d_tail.resize(tailsize());
+ for (i = 0; i < tailsize(); i++)
+ d_tail[i] = 0;
+
+ float *in = d_fwdfft->get_inbuf();
+ gr_complex *out = d_fwdfft->get_outbuf();
+
+ float scale = 1.0 / d_fftsize;
+
+ // Compute forward xform of taps.
+ // Copy taps into first ntaps slots, then pad with zeros
+ for (i = 0; i < d_ntaps; i++)
+ in[i] = taps[i] * scale;
+
+ for (; i < d_fftsize; i++)
+ in[i] = 0;
+
+ d_fwdfft->execute(); // do the xform
+
+ // now copy output to d_xformed_taps
+ for (i = 0; i < d_fftsize/2+1; i++)
+ d_xformed_taps[i] = out[i];
+
+ return d_nsamples;
+}
+
+// determine and set d_ntaps, d_nsamples, d_fftsize
+
+void
+gri_fft_filter_fff_sse::compute_sizes(int ntaps)
+{
+ int old_fftsize = d_fftsize;
+ d_ntaps = ntaps;
+ d_fftsize = (int) (2 * pow(2.0, ceil(log(ntaps) / log(2))));
+ d_nsamples = d_fftsize - d_ntaps + 1;
+
+ if (0)
+ fprintf(stderr, "gri_fft_filter_fff_sse: ntaps = %d, fftsize = %d, nsamples = %d\n",
+ d_ntaps, d_fftsize, d_nsamples);
+
+ assert(d_fftsize == d_ntaps + d_nsamples -1 );
+
+ if (d_fftsize != old_fftsize){ // compute new plans
+ delete d_fwdfft;
+ delete d_invfft;
+ d_fwdfft = new gri_fft_real_fwd(d_fftsize);
+ d_invfft = new gri_fft_real_rev(d_fftsize);
+ //d_xformed_taps.resize(d_fftsize/2+1);
+
+ fftwf_free(d_xformed_taps);
+ d_xformed_taps = (gr_complex*)fftwf_malloc((d_fftsize/2+1)*sizeof(gr_complex));
+ }
+}
+
+int
+gri_fft_filter_fff_sse::filter (int nitems, const float *input, float *output)
+{
+ int dec_ctr = 0;
+ int j = 0;
+ int ninput_items = nitems * d_decimation;
+
+ for (int i = 0; i < ninput_items; i += d_nsamples){
+
+ memcpy(d_fwdfft->get_inbuf(), &input[i], d_nsamples * sizeof(float));
+
+ for (j = d_nsamples; j < d_fftsize; j++)
+ d_fwdfft->get_inbuf()[j] = 0;
+
+ d_fwdfft->execute(); // compute fwd xform
+
+ float *a = (float*)(d_fwdfft->get_outbuf());
+ float *b = (float*)(&d_xformed_taps[0]);
+ float *c = (float*)(d_invfft->get_inbuf());
+
+ __m128 x0, x1, x2, t0, t1, m;
+ m = _mm_set_ps(-1, 1, -1, 1);
+ for (j = 0; j < d_fftsize; j+=4) { // filter in the freq domain
+ x0 = _mm_load_ps(&a[j]);
+ t0 = _mm_load_ps(&b[j]);
+
+ t1 = _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(3, 3, 1, 1));
+ t0 = _mm_shuffle_ps(t0, t0, _MM_SHUFFLE(2, 2, 0, 0));
+ t1 = _mm_mul_ps(t1, m);
+
+ x1 = _mm_mul_ps(x0, t0);
+ x2 = _mm_mul_ps(x0, t1);
+
+ x2 = _mm_shuffle_ps(x2, x2, _MM_SHUFFLE(2, 3, 0, 1));
+ x2 = _mm_add_ps(x1, x2);
+
+ _mm_store_ps(&c[j], x2);
+ }
+
+ // Finish off the last one; do the complex multiply as floats
+ j = d_fftsize/2;
+ c[j] = (a[j] * b[j]) - (a[j+1] * b[j+1]);
+ c[j+1] = (a[j] * b[j+1]) + (a[j+1] * b[j]);
+
+ d_invfft->execute(); // compute inv xform
+
+ // add in the overlapping tail
+
+ for (j = 0; j < tailsize(); j++)
+ d_invfft->get_outbuf()[j] += d_tail[j];
+
+ // copy nsamples to output
+
+ //memcpy(out, d_invfft->get_outbuf(), d_nsamples * sizeof(float));
+ //out += d_nsamples;
+
+ j = dec_ctr;
+ while (j < d_nsamples) {
+ *output++ = d_invfft->get_outbuf()[j];
+ j += d_decimation;
+ }
+ dec_ctr = (j - d_nsamples);
+
+ // stash the tail
+ memcpy(&d_tail[0], d_invfft->get_outbuf() + d_nsamples,
+ tailsize() * sizeof(float));
+ }
+
+ assert(dec_ctr == 0);
+
+ return nitems;
+}
diff --git a/gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.h b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.h
new file mode 100644
index 000000000..8258bb824
--- /dev/null
+++ b/gnuradio-core/src/lib/filter/gri_fft_filter_fff_sse.h
@@ -0,0 +1,81 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2010 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_GRI_FFT_FILTER_FFF_SSE_H
+#define INCLUDED_GRI_FFT_FILTER_FFF_SSE_H
+
+#include <gr_complex.h>
+#include <vector>
+
+class gri_fft_real_fwd;
+class gri_fft_real_rev;
+
+class gri_fft_filter_fff_sse
+{
+ private:
+ int d_ntaps;
+ int d_nsamples;
+ int d_fftsize; // fftsize = ntaps + nsamples - 1
+ int d_decimation;
+ gri_fft_real_fwd *d_fwdfft; // forward "plan"
+ gri_fft_real_rev *d_invfft; // inverse "plan"
+ std::vector<float> d_tail; // state carried between blocks for overlap-add
+ //std::vector<gr_complex> d_xformed_taps; // Fourier xformed taps
+ gr_complex *d_xformed_taps;
+ std::vector<float> d_new_taps;
+
+
+ void compute_sizes(int ntaps);
+ int tailsize() const { return d_ntaps - 1; }
+
+ public:
+ /*!
+ * \brief Construct a FFT filter for float vectors with the given taps and decimation rate.
+ *
+ * This is the basic implementation for performing FFT filter for fast convolution
+ * in other blocks for floating point vectors (such as gr_fft_filter_fff).
+ * \param decimation The decimation rate of the filter (int)
+ * \param taps The filter taps (float)
+ */
+ gri_fft_filter_fff_sse (int decimation, const std::vector<float> &taps);
+ ~gri_fft_filter_fff_sse ();
+
+ /*!
+ * \brief Set new taps for the filter.
+ *
+ * Sets new taps and resets the class properties to handle different sizes
+ * \param taps The filter taps (float)
+ */
+ int set_taps (const std::vector<float> &taps);
+
+ /*!
+ * \brief Perform the filter operation
+ *
+ * \param nitems The number of items to produce
+ * \param input The input vector to be filtered
+ * \param output The result of the filter operation
+ */
+ int filter (int nitems, const float *input, float *output);
+
+};
+
+#endif /* INCLUDED_GRI_FFT_FILTER_FFF_SSE_H */
diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am
index ecef7d6e3..3d8a42805 100644
--- a/gnuradio-core/src/lib/general/Makefile.am
+++ b/gnuradio-core/src/lib/general/Makefile.am
@@ -34,6 +34,7 @@ EXTRA_DIST = \
gr_constants.cc.in
libgeneral_la_SOURCES = \
+ gr_additive_scrambler_bb.cc \
gr_agc_cc.cc \
gr_agc_ff.cc \
gr_agc2_cc.cc \
@@ -59,7 +60,6 @@ libgeneral_la_SOURCES = \
gr_cpfsk_bc.cc \
gr_crc32.cc \
gr_ctcss_squelch_ff.cc \
- gr_dd_mpsk_sync_cc.cc \
gr_decode_ccsds_27_fb.cc \
gr_deinterleave.cc \
gr_delay.cc \
@@ -188,6 +188,7 @@ libgeneral_qa_la_SOURCES = \
qa_gri_lfsr.cc
grinclude_HEADERS = \
+ gr_additive_scrambler_bb.h \
gr_agc_cc.h \
gr_agc_ff.h \
gr_agc2_cc.h \
@@ -213,7 +214,6 @@ grinclude_HEADERS = \
gr_cpfsk_bc.h \
gr_crc32.h \
gr_ctcss_squelch_ff.h \
- gr_dd_mpsk_sync_cc.h \
gr_decode_ccsds_27_fb.h \
gr_diff_decoder_bb.h \
gr_diff_encoder_bb.h \
@@ -360,6 +360,7 @@ noinst_HEADERS = \
if PYTHON
swiginclude_HEADERS = \
general.i \
+ gr_additive_scrambler_bb.i \
gr_agc_cc.i \
gr_agc_ff.i \
gr_agc2_cc.i \
@@ -383,7 +384,6 @@ swiginclude_HEADERS = \
gr_cpfsk_bc.i \
gr_crc32.i \
gr_ctcss_squelch_ff.i \
- gr_dd_mpsk_sync_cc.i \
gr_decode_ccsds_27_fb.i \
gr_diff_decoder_bb.i \
gr_diff_encoder_bb.i \
diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i
index 2c26b59cd..68cafce2e 100644
--- a/gnuradio-core/src/lib/general/general.i
+++ b/gnuradio-core/src/lib/general/general.i
@@ -80,7 +80,6 @@
#include <gr_threshold_ff.h>
#include <gr_clock_recovery_mm_ff.h>
#include <gr_clock_recovery_mm_cc.h>
-#include <gr_dd_mpsk_sync_cc.h>
#include <gr_packet_sink.h>
#include <gr_lms_dfe_cc.h>
#include <gr_lms_dfe_ff.h>
@@ -141,6 +140,7 @@
#include <gr_wvps_ff.h>
#include <gr_copy.h>
#include <gr_fll_band_edge_cc.h>
+#include <gr_additive_scrambler_bb.h>
%}
%include "gr_nop.i"
@@ -201,7 +201,6 @@
%include "gr_threshold_ff.i"
%include "gr_clock_recovery_mm_ff.i"
%include "gr_clock_recovery_mm_cc.i"
-%include "gr_dd_mpsk_sync_cc.i"
%include "gr_packet_sink.i"
%include "gr_lms_dfe_cc.i"
%include "gr_lms_dfe_ff.i"
@@ -262,3 +261,4 @@
%include "gr_wvps_ff.i"
%include "gr_copy.i"
%include "gr_fll_band_edge_cc.i"
+%include "gr_additive_scrambler_bb.i"
diff --git a/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.cc b/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.cc
new file mode 100644
index 000000000..91e02c2d3
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.cc
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008,2010 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_additive_scrambler_bb.h>
+#include <gr_io_signature.h>
+
+gr_additive_scrambler_bb_sptr
+gr_make_additive_scrambler_bb(int mask, int seed, int len, int count)
+{
+ return gr_additive_scrambler_bb_sptr(new gr_additive_scrambler_bb(mask, seed, len, count));
+}
+
+gr_additive_scrambler_bb::gr_additive_scrambler_bb(int mask, int seed, int len, int count)
+ : gr_sync_block("additive_scrambler_bb",
+ gr_make_io_signature (1, 1, sizeof (unsigned char)),
+ gr_make_io_signature (1, 1, sizeof (unsigned char))),
+ d_lfsr(mask, seed, len),
+ d_count(count),
+ d_bits(0)
+{
+}
+
+int
+gr_additive_scrambler_bb::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const unsigned char *in = (const unsigned char *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+
+ for (int i = 0; i < noutput_items; i++) {
+ out[i] = in[i]^d_lfsr.next_bit();
+ if (d_count > 0) {
+ if (++d_bits == d_count) {
+ d_lfsr.reset();
+ d_bits = 0;
+ }
+ }
+ }
+
+ return noutput_items;
+}
diff --git a/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.h b/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.h
new file mode 100644
index 000000000..6c9493050
--- /dev/null
+++ b/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.h
@@ -0,0 +1,67 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2008,2010 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_ADDITIVE_SCRAMBLER_BB_H
+#define INCLUDED_GR_ADDITIVE_SCRAMBLER_BB_H
+
+#include <gr_sync_block.h>
+#include "gri_lfsr.h"
+
+class gr_additive_scrambler_bb;
+typedef boost::shared_ptr<gr_additive_scrambler_bb> gr_additive_scrambler_bb_sptr;
+
+gr_additive_scrambler_bb_sptr gr_make_additive_scrambler_bb(int mask, int seed, int len, int count=0);
+
+/*!
+ * Scramble an input stream using an LFSR. This block works on the LSB only
+ * of the input data stream, i.e., on an "unpacked binary" stream, and
+ * produces the same format on its output.
+ *
+ * \param mask Polynomial mask for LFSR
+ * \param seed Initial shift register contents
+ * \param len Shift register length
+ * \param count Number of bits after which shift register is reset, 0=never
+ *
+ * The scrambler works by XORing the incoming bit stream by the output of
+ * the LFSR. Optionally, after 'count' bits have been processed, the shift
+ * register is reset to the seed value. This allows processing fixed length
+ * vectors of samples.
+ *
+ * \ingroup coding_blk
+ */
+
+class gr_additive_scrambler_bb : public gr_sync_block
+{
+ friend gr_additive_scrambler_bb_sptr gr_make_additive_scrambler_bb(int mask, int seed, int len, int count);
+
+ gri_lfsr d_lfsr;
+ int d_count;
+ int d_bits;
+
+ gr_additive_scrambler_bb(int mask, int seed, int len, int count);
+
+public:
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_GR_ADDITIVE_SCRAMBLER_BB_H */
diff --git a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i b/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.i
index 17739248e..0ca9c1cd7 100644
--- a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.i
+++ b/gnuradio-core/src/lib/general/gr_additive_scrambler_bb.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2005 Free Software Foundation, Inc.
+ * Copyright 2008,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -20,15 +20,12 @@
* Boston, MA 02110-1301, USA.
*/
-GR_SWIG_BLOCK_MAGIC(gr,dd_mpsk_sync_cc)
+GR_SWIG_BLOCK_MAGIC(gr,additive_scrambler_bb);
- gr_dd_mpsk_sync_cc_sptr gr_make_dd_mpsk_sync_cc (float alpha, float beta,
- float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
+gr_additive_scrambler_bb_sptr gr_make_additive_scrambler_bb(int mask, int seed, int len, int count=0);
-class gr_dd_mpsk_sync_cc : public gr_block
+class gr_additive_scrambler_bb : public gr_sync_block
{
- private:
- gr_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
+private:
+ gr_additive_scrambler_bb(int mask, int seed, int len, int count);
};
diff --git a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc b/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc
deleted file mode 100644
index d4141efc7..000000000
--- a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.cc
+++ /dev/null
@@ -1,196 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2004 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_dd_mpsk_sync_cc.h>
-#include <gr_io_signature.h>
-#include <gr_sincos.h>
-#include <gri_mmse_fir_interpolator_cc.h>
-#include <math.h>
-#include <stdexcept>
-#include <cstdio>
-
-#include <gr_complex.h>
-
-#define M_TWOPI (2*M_PI)
-
-gr_dd_mpsk_sync_cc_sptr
-gr_make_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu)
-{
- return gr_dd_mpsk_sync_cc_sptr (new gr_dd_mpsk_sync_cc (alpha, beta, max_freq, min_freq,ref_phase,
- omega,gain_omega,mu,gain_mu));
-}
-
-gr_dd_mpsk_sync_cc::gr_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq,
- float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu)
- : gr_block ("dd_mpsk_sync_cc",
- gr_make_io_signature (1, 1, sizeof (gr_complex)),
- gr_make_io_signature (1, 1, sizeof (gr_complex))),
- d_alpha(alpha), d_beta(beta),
- d_max_freq(max_freq), d_min_freq(min_freq),
- d_ref_phase(ref_phase),d_omega(omega), d_gain_omega(gain_omega),
- d_mu(mu), d_gain_mu(gain_mu),
- d_phase(0), d_freq((max_freq+min_freq)/2), d_last_sample(0),
- d_interp(new gri_mmse_fir_interpolator_cc()),
- d_dl_idx(0)
-{
- if (omega <= 0.0)
- throw std::out_of_range ("clock rate must be > 0");
- if (gain_mu < 0 || gain_omega < 0)
- throw std::out_of_range ("Gains must be non-negative");
-
- assert(d_interp->ntaps() <= DLLEN);
-
- // zero double length delay line.
- for (unsigned int i = 0; i < 2 * DLLEN; i++)
- d_dl[i] = gr_complex(0.0,0.0);
-}
-
-gr_dd_mpsk_sync_cc::~gr_dd_mpsk_sync_cc()
-{
- delete d_interp;
-}
-
-float
-gr_dd_mpsk_sync_cc::phase_detector(gr_complex sample,float ref_phase)
-{
- return ((sample.real()>0 ? 1.0 : -1.0) * sample.imag() -
- (sample.imag()>0 ? 1.0 : -1.0) * sample.real());
-}
-
-void
-gr_dd_mpsk_sync_cc::forecast(int noutput_items, gr_vector_int &ninput_items_required)
-{
- unsigned ninputs = ninput_items_required.size();
- for (unsigned i=0; i < ninputs; i++)
- ninput_items_required[i] =
- (int) ceil((noutput_items * d_omega) + d_interp->ntaps());
-}
-gr_complex
-gr_dd_mpsk_sync_cc::slicer_45deg (gr_complex sample)
-{
- float real,imag;
- if(sample.real() > 0)
- real=1;
- else
- real=-1;
- if(sample.imag() > 0)
- imag = 1;
- else
- imag = -1;
- return gr_complex(real,imag);
-}
-
-gr_complex
-gr_dd_mpsk_sync_cc::slicer_0deg (gr_complex sample)
-{
- gr_complex out;
- if( fabs(sample.real()) > fabs(sample.imag()) ) {
- if(sample.real() > 0)
- return gr_complex(1.0,0.0);
- else
- return gr_complex(-1.0,0.0);
- }
- else {
- if(sample.imag() > 0)
- return gr_complex(0.0, 1.0);
- else
- return gr_complex(0.0, -1.0);
- }
-}
-
-int
-gr_dd_mpsk_sync_cc::general_work (int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
-{
- const gr_complex *in = (gr_complex *) input_items[0];
- gr_complex *out = (gr_complex *) output_items[0];
-
- int ii, oo;
- ii = 0; oo = 0;
-
- float error;
- float t_imag, t_real;
- gr_complex nco_out;
- float mm_val;
-
- while (oo < noutput_items) {
- //
- // generate an output sample by interpolating between the carrier
- // tracked samples in the delay line. d_mu, the fractional
- // interpolation amount (in [0.0, 1.0]) is controlled by the
- // symbol timing loop below.
- //
- out[oo] = d_interp->interpolate (&d_dl[d_dl_idx], d_mu);
-
- error = phase_detector(out[oo], d_ref_phase);
-
- d_freq = d_freq + d_beta * error;
- d_phase = d_phase + d_alpha * error;
- while(d_phase>M_TWOPI)
- d_phase -= M_TWOPI;
- while(d_phase<-M_TWOPI)
- d_phase += M_TWOPI;
-
- if (d_freq > d_max_freq)
- d_freq = d_max_freq;
- else if (d_freq < d_min_freq)
- d_freq = d_min_freq;
-
- mm_val = real(d_last_sample * slicer_0deg(out[oo]) - out[oo] * slicer_0deg(d_last_sample));
- d_last_sample = out[oo];
-
- d_omega = d_omega + d_gain_omega * mm_val;
- d_mu = d_mu + d_omega + d_gain_mu * mm_val;
-
- while(d_mu >= 1.0) {
- //
- // Generate more carrier tracked samples for the delay line
- //
- d_mu -= 1.0;
- gr_sincosf(d_phase, &t_imag, &t_real);
- nco_out = gr_complex(t_real, -t_imag);
- gr_complex new_sample = in[ii] * nco_out;
-
- d_dl[d_dl_idx] = new_sample; // overwrite oldest sample
- d_dl[(d_dl_idx + DLLEN)] = new_sample; // and second copy
- d_dl_idx = (d_dl_idx+1) % DLLEN; // point to the new oldest sample
- d_phase = d_phase + d_freq;
- ii++;
- }
- oo++;
- printf("%f\t%f\t%f\t%f\t%f\n",d_mu,d_omega,mm_val,d_freq,d_phase);
- //printf("%f\t%f\t%f\t%f\t%f\t%f\t%f\n",mple).real(),slicer_0deg(d_last_sample).imag(),mm_val,d_omega,d_mu);
- }
-
- assert(ii <= ninput_items[0]);
-
- consume_each (ii);
- return noutput_items;
-}
diff --git a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h b/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h
deleted file mode 100644
index 4ffcd3771..000000000
--- a/gnuradio-core/src/lib/general/gr_dd_mpsk_sync_cc.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2004,2006 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_DD_MPSK_SYNC_CC_H
-#define INCLUDED_GR_DD_MPSK_SYNC_CC_H
-
-#include <gr_sync_block.h>
-
-class gri_mmse_fir_interpolator_cc;
-
-class gr_dd_mpsk_sync_cc;
-typedef boost::shared_ptr<gr_dd_mpsk_sync_cc> gr_dd_mpsk_sync_cc_sptr;
-
-gr_dd_mpsk_sync_cc_sptr
-gr_make_dd_mpsk_sync_cc (float alpha, float beta,
- float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-
-/*!
- * \brief Decision directed M-PSK synchronous demod
- * \ingroup sync_blk
- * This block performs joint carrier tracking and symbol timing recovery.
- *
- * input: complex baseband; output: properly timed complex samples ready for slicing.
- *
- * N.B, at this point, it handles only QPSK.
- */
-
-class gr_dd_mpsk_sync_cc : public gr_block
-{
- friend gr_dd_mpsk_sync_cc_sptr gr_make_dd_mpsk_sync_cc (float alpha, float beta,
- float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-public:
- ~gr_dd_mpsk_sync_cc ();
- void forecast(int noutput_items, gr_vector_int &ninput_items_required);
- float mu() const { return d_mu;}
- float omega() const { return d_omega;}
- float gain_mu() const { return d_gain_mu;}
- float gain_omega() const { return d_gain_omega;}
-
- void set_gain_mu (float gain_mu) { d_gain_mu = gain_mu; }
- void set_gain_omega (float gain_omega) { d_gain_omega = gain_omega; }
- void set_mu (float mu) { d_mu = mu; }
- void set_omega (float omega) { d_omega = omega; }
-
-protected:
- gr_dd_mpsk_sync_cc (float alpha, float beta, float max_freq, float min_freq, float ref_phase,
- float omega, float gain_omega, float mu, float gain_mu);
-
- int general_work (int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
-
-private:
- static const unsigned int DLLEN = 8; // delay line length.
-
- float d_alpha,d_beta,d_max_freq,d_min_freq,d_ref_phase;
- float d_omega, d_gain_omega, d_mu, d_gain_mu;
- float d_phase, d_freq;
- gr_complex slicer_45deg (gr_complex sample);
- gr_complex slicer_0deg (gr_complex sample);
- gr_complex d_last_sample;
- gri_mmse_fir_interpolator_cc *d_interp;
-
- gr_complex d_dl[2 * DLLEN]; // Holds post carrier tracking samples.
- // double length delay line to avoid wraps.
- unsigned int d_dl_idx; // indexes oldest sample in delay line.
-
- float phase_detector(gr_complex sample,float ref_phase);
-};
-
-#endif
diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc
index 030e45ddf..7f2c468b7 100644
--- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc
+++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.cc
@@ -53,7 +53,7 @@ gr_fll_band_edge_cc_sptr gr_make_fll_band_edge_cc (float samps_per_sym, float ro
}
-static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(float)};
+static int ios[] = {sizeof(gr_complex), sizeof(float), sizeof(float), sizeof(gr_complex)};
static std::vector<int> iosig(ios, ios+sizeof(ios)/sizeof(int));
gr_fll_band_edge_cc::gr_fll_band_edge_cc (float samps_per_sym, float rolloff,
int filter_size, float alpha, float beta)
@@ -83,10 +83,11 @@ gr_fll_band_edge_cc::~gr_fll_band_edge_cc ()
void
gr_fll_band_edge_cc::set_alpha(float alpha)
{
- float eta = sqrt(2.0)/2.0;
- float theta = alpha;
- d_alpha = (4*eta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
- d_beta = (4*theta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
+ //float eta = sqrt(2.0)/2.0;
+ //float theta = alpha;
+ //d_alpha = (4*eta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
+ //d_beta = (4*theta*theta) / (1.0 + 2.0*eta*theta + theta*theta);
+ d_alpha = alpha;
}
void
@@ -160,11 +161,12 @@ gr_fll_band_edge_cc::work (int noutput_items,
const gr_complex *in = (const gr_complex *) input_items[0];
gr_complex *out = (gr_complex *) output_items[0];
- float *frq, *phs, *err;
+ float *frq, *phs;
+ gr_complex *err;
if(output_items.size() > 2) {
frq = (float *) output_items[1];
phs = (float *) output_items[2];
- err = (float *) output_items[3];
+ err = (gr_complex *) output_items[3];
}
if (d_updated) {
@@ -174,16 +176,17 @@ gr_fll_band_edge_cc::work (int noutput_items,
int i;
gr_complex nco_out;
- float out_upper, out_lower;
+ gr_complex out_upper, out_lower;
float error;
+ float avg_k = 0.1;
for(i = 0; i < noutput_items; i++) {
nco_out = gr_expj(d_phase);
out[i] = in[i] * nco_out;
- out_upper = norm(d_filter_upper->filter(&out[i]));
- out_lower = norm(d_filter_lower->filter(&out[i]));
- error = out_lower - out_upper;
- d_error = 0.01*error + 0.99*d_error; // average error
+ out_upper = (d_filter_upper->filter(&out[i]));
+ out_lower = (d_filter_lower->filter(&out[i]));
+ error = -real((out_upper + out_lower) * conj(out_upper - out_lower));
+ d_error = avg_k*error + avg_k*d_error; // average error
d_freq = d_freq + d_beta * d_error;
d_phase = d_phase + d_freq + d_alpha * d_error;
diff --git a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h
index 09baf7fde..db060793e 100644
--- a/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h
+++ b/gnuradio-core/src/lib/general/gr_fll_band_edge_cc.h
@@ -45,11 +45,15 @@ class gri_fft_complex;
* (e.g., rolloff factor) of the modulated signal. The placement in frequency of the band-edges
* is determined by the oversampling ratio (number of samples per symbol) and the excess bandwidth.
* The size of the filters should be fairly large so as to average over a number of symbols.
- * The FLL works by calculating the power in both the upper and lower bands and comparing them. The
- * difference in power between the filters is proportional to the frequency offset.
+ *
+ * The FLL works by filtering the upper and lower band edges into x_u(t) and x_l(t), respectively.
+ * These are combined to form cc(t) = x_u(t) + x_l(t) and ss(t) = x_u(t) - x_l(t). Combining
+ * these to form the signal e(t) = Re{cc(t) \\times ss(t)^*} (where ^* is the complex conjugate)
+ * provides an error signal at the DC term that is directly proportional to the carrier frequency.
+ * We then make a second-order loop using the error signal that is the running average of e(t).
*
* In theory, the band-edge filter is the derivative of the matched filter in frequency,
- * (H_be(f) = \frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point
+ * (H_be(f) = \\frac{H(f)}{df}. In practice, this comes down to a quarter sine wave at the point
* of the matched filter's rolloff (if it's a raised-cosine, the derivative of a cosine is a sine).
* Extend this sine by another quarter wave to make a half wave around the band-edges is equivalent
* in time to the sum of two sinc functions. The baseband filter fot the band edges is therefore
@@ -89,7 +93,11 @@ class gr_fll_band_edge_cc : public gr_sync_block
/*!
* Build the FLL
- * \param taps (vector/list of gr_complex) The taps of the band-edge filter
+ * \param samps_per_sym (float) number of samples per symbol
+ * \param rolloff (float) Rolloff (excess bandwidth) of signal filter
+ * \param filter_size (int) number of filter taps to generate
+ * \param alpha (float) Alpha gain in the control loop
+ * \param beta (float) Beta gain in the control loop
*/
gr_fll_band_edge_cc(float samps_per_sym, float rolloff,
int filter_size, float alpha, float beta);
diff --git a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
index 74bd65a50..7f6b2b01c 100644
--- a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
+++ b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -45,6 +45,7 @@ gr_ofdm_sampler::gr_ofdm_sampler (unsigned int fft_length,
gr_make_io_signature2 (2, 2, sizeof (gr_complex)*fft_length, sizeof(char)*fft_length)),
d_state(STATE_NO_SIG), d_timeout_max(timeout), d_fft_length(fft_length), d_symbol_length(symbol_length)
{
+ set_relative_rate(1.0/(double) fft_length); // buffer allocator hint
}
void
diff --git a/gnuradio-core/src/lib/general/gri_lfsr.h b/gnuradio-core/src/lib/general/gri_lfsr.h
index 715da78a9..f691e36ec 100644
--- a/gnuradio-core/src/lib/general/gri_lfsr.h
+++ b/gnuradio-core/src/lib/general/gri_lfsr.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2008 Free Software Foundation, Inc.
+ * Copyright 2008,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -86,6 +86,7 @@ class gri_lfsr
private:
uint32_t d_shift_register;
uint32_t d_mask;
+ uint32_t d_seed;
uint32_t d_shift_register_length; // less than 32
static uint32_t
@@ -99,7 +100,10 @@ class gri_lfsr
public:
gri_lfsr(uint32_t mask, uint32_t seed, uint32_t reg_len)
- : d_shift_register(seed), d_mask(mask), d_shift_register_length(reg_len)
+ : d_shift_register(seed),
+ d_mask(mask),
+ d_seed(seed),
+ d_shift_register_length(reg_len)
{
if (reg_len > 31)
throw std::invalid_argument("reg_len must be <= 31");
@@ -126,6 +130,10 @@ class gri_lfsr
return output;
}
+ /*!
+ * Reset shift register to initial seed value
+ */
+ void reset() { d_shift_register = d_seed; }
/*!
* Rotate the register through x number of bits
diff --git a/gnuradio-core/src/lib/io/Makefile.am b/gnuradio-core/src/lib/io/Makefile.am
index 9eacd137d..c52554645 100644
--- a/gnuradio-core/src/lib/io/Makefile.am
+++ b/gnuradio-core/src/lib/io/Makefile.am
@@ -39,7 +39,6 @@ libio_la_SOURCES = \
gr_oscope_guts.cc \
gr_oscope_sink_f.cc \
gr_oscope_sink_x.cc \
- gri_logger.cc \
i2c.cc \
i2c_bitbang.cc \
i2c_bbio.cc \
@@ -72,7 +71,6 @@ grinclude_HEADERS = \
gr_oscope_sink_f.h \
gr_oscope_sink_x.h \
gr_trigger_mode.h \
- gri_logger.h \
i2c.h \
i2c_bitbang.h \
i2c_bbio.h \
diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.cc b/gnuradio-core/src/lib/io/gr_udp_sink.cc
index d37adfb8a..3084a848b 100644
--- a/gnuradio-core/src/lib/io/gr_udp_sink.cc
+++ b/gnuradio-core/src/lib/io/gr_udp_sink.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -26,13 +26,24 @@
#include <gr_udp_sink.h>
#include <gr_io_signature.h>
#include <stdexcept>
-#if defined(HAVE_SOCKET)
-#include <netdb.h>
+#include <errno.h>
#include <stdio.h>
+#include <string.h>
+#if defined(HAVE_NETDB_H)
+#include <netdb.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> //usually included by <netdb.h>?
+#endif
typedef void* optval_t;
-#else
+#elif defined(HAVE_WINDOWS_H)
+// if not posix, assume winsock
+#define USING_WINSOCK
+#include <winsock2.h>
+#include <ws2tcpip.h>
#define SHUT_RDWR 2
-#define inet_aton(N,A) ( (A)->s_addr = inet_addr(N), ( (A)->s_addr != INADDR_NONE ) )
typedef char* optval_t;
#endif
@@ -40,91 +51,67 @@ typedef char* optval_t;
#define SNK_VERBOSE 0
-gr_udp_sink::gr_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size)
- : gr_sync_block ("udp_sink",
- gr_make_io_signature (1, 1, itemsize),
- gr_make_io_signature (0, 0, 0)),
- d_itemsize (itemsize), d_updated(false), d_payload_size(payload_size)
+static int is_error( int perr )
{
- int ret = 0;
-
- // Set up the address stucture for the source address and port numbers
- // Get the source IP address from the host name
- struct hostent *hsrc = gethostbyname(src);
- if(hsrc) { // if the source was provided as a host namex
- d_ip_src = *(struct in_addr*)hsrc->h_addr_list[0];
+ // Compare error to posix error code; return nonzero if match.
+#if defined(USING_WINSOCK)
+#define ENOPROTOOPT 109
+#define ECONNREFUSED 111
+ // All codes to be checked for must be defined below
+ int werr = WSAGetLastError();
+ switch( werr ) {
+ case WSAETIMEDOUT:
+ return( perr == EAGAIN );
+ case WSAENOPROTOOPT:
+ return( perr == ENOPROTOOPT );
+ case WSAECONNREFUSED:
+ return( perr == ECONNREFUSED );
+ default:
+ fprintf(stderr,"gr_udp_source/is_error: unknown error %d\n", perr );
+ throw std::runtime_error("internal error");
}
- else { // assume it was specified as an IP address
- if((ret=inet_aton(src, &d_ip_src)) == 0) { // format IP address
- perror("Not a valid source IP address or host name");
- throw std::runtime_error("can't initialize source socket");
- }
- }
-
- // Get the destination IP address from the host name
- struct hostent *hdst = gethostbyname(dst);
- if(hdst) { // if the source was provided as a host namex
- d_ip_dst = *(struct in_addr*)hdst->h_addr_list[0];
- }
- else { // assume it was specified as an IP address
- if((ret=inet_aton(dst, &d_ip_dst)) == 0) { // format IP address
- perror("Not a valid destination IP address or host name");
- throw std::runtime_error("can't initialize destination socket");
- }
- }
-
- d_port_src = htons(port_src); // format port number
- d_port_dst = htons(port_dst); // format port number
-
- d_sockaddr_src.sin_family = AF_INET;
- d_sockaddr_src.sin_addr = d_ip_src;
- d_sockaddr_src.sin_port = d_port_src;
-
- d_sockaddr_dst.sin_family = AF_INET;
- d_sockaddr_dst.sin_addr = d_ip_dst;
- d_sockaddr_dst.sin_port = d_port_dst;
-
- open();
-}
-
-// public constructor that returns a shared_ptr
-
-gr_udp_sink_sptr
-gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size)
-{
- return gr_udp_sink_sptr (new gr_udp_sink (itemsize,
- src, port_src,
- dst, port_dst,
- payload_size));
+ return 0;
+#else
+ return( perr == errno );
+#endif
}
-gr_udp_sink::~gr_udp_sink ()
+static void report_error( const char *msg1, const char *msg2 )
{
- close();
+ // Deal with errors, both posix and winsock
+#if defined(USING_WINSOCK)
+ int werr = WSAGetLastError();
+ fprintf(stderr, "%s: winsock error %d\n", msg1, werr );
+#else
+ perror(msg1);
+#endif
+ if( msg2 != NULL )
+ throw std::runtime_error(msg2);
+ return;
}
-bool
-gr_udp_sink::open()
+gr_udp_sink::gr_udp_sink (size_t itemsize,
+ const char *host, unsigned short port,
+ int payload_size, bool eof)
+ : gr_sync_block ("udp_sink",
+ gr_make_io_signature (1, 1, itemsize),
+ gr_make_io_signature (0, 0, 0)),
+ d_itemsize (itemsize), d_payload_size(payload_size), d_eof(eof),
+ d_socket(-1), d_connected(false)
{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
-
- // create socket
- if((d_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
- perror("socket open");
- throw std::runtime_error("can't open socket");
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // initialize winsock DLL
+ WSADATA wsaData;
+ int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
+ if( iResult != NO_ERROR ) {
+ report_error( "gr_udp_source WSAStartup", "can't open socket" );
}
+#endif
- // Turn on reuse address
- int opt_val = true;
- if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (optval_t)&opt_val, sizeof(int)) == -1) {
- perror("SO_REUSEADDR");
- throw std::runtime_error("can't set socket option SO_REUSEADDR");
+ // create socket
+ d_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if(d_socket == -1) {
+ report_error("socket open","can't open socket");
}
// Don't wait when shutting down
@@ -132,36 +119,46 @@ gr_udp_sink::open()
lngr.l_onoff = 1;
lngr.l_linger = 0;
if(setsockopt(d_socket, SOL_SOCKET, SO_LINGER, (optval_t)&lngr, sizeof(linger)) == -1) {
- perror("SO_LINGER");
- throw std::runtime_error("can't set socket option SO_LINGER");
+ if( !is_error(ENOPROTOOPT) ) { // no SO_LINGER for SOCK_DGRAM on Windows
+ report_error("SO_LINGER","can't set socket option SO_LINGER");
+ }
}
- // bind socket to an address and port number to listen on
- if(bind (d_socket, (sockaddr*)&d_sockaddr_src, sizeof(struct sockaddr)) == -1) {
- perror("socket bind");
- throw std::runtime_error("can't bind socket");
- }
+ // Get the destination address
+ connect(host, port);
+}
- // Not sure if we should throw here or allow retries
- if(connect(d_socket, (sockaddr*)&d_sockaddr_dst, sizeof(struct sockaddr)) == -1) {
- perror("socket connect");
- throw std::runtime_error("can't connect to socket");
- }
+// public constructor that returns a shared_ptr
- d_updated = true;
- return d_socket != 0;
+gr_udp_sink_sptr
+gr_make_udp_sink (size_t itemsize,
+ const char *host, unsigned short port,
+ int payload_size, bool eof)
+{
+ return gr_udp_sink_sptr (new gr_udp_sink (itemsize,
+ host, port,
+ payload_size, eof));
}
-void
-gr_udp_sink::close()
+gr_udp_sink::~gr_udp_sink ()
{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+ if (d_connected)
+ disconnect();
- if (d_socket){
+ if (d_socket != -1){
shutdown(d_socket, SHUT_RDWR);
- d_socket = 0;
+#if defined(USING_WINSOCK)
+ closesocket(d_socket);
+#else
+ ::close(d_socket);
+#endif
+ d_socket = -1;
}
- d_updated = true;
+
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // free winsock resources
+ WSACleanup();
+#endif
}
int
@@ -174,21 +171,31 @@ gr_udp_sink::work (int noutput_items,
ssize_t total_size = noutput_items*d_itemsize;
#if SNK_VERBOSE
- printf("Entered upd_sink\n");
+ printf("Entered udp_sink\n");
#endif
+ gruel::scoped_lock guard(d_mutex); // protect d_socket
+
while(bytes_sent < total_size) {
bytes_to_send = std::min((ssize_t)d_payload_size, (total_size-bytes_sent));
- r = send(d_socket, (in+bytes_sent), bytes_to_send, 0);
- if(r == -1) { // error on send command
- perror("udp_sink"); // there should be no error case where this function
- return -1; // should not exit immediately
+ if(d_connected) {
+ r = send(d_socket, (in+bytes_sent), bytes_to_send, 0);
+ if(r == -1) { // error on send command
+ if( is_error(ECONNREFUSED) )
+ r = bytes_to_send; // discard data until receiver is started
+ else {
+ report_error("udp_sink",NULL); // there should be no error case where
+ return -1; // this function should not exit immediately
+ }
+ }
}
+ else
+ r = bytes_to_send; // discarded for lack of connection
bytes_sent += r;
#if SNK_VERBOSE
- printf("\tbyte sent: %d bytes\n", bytes);
+ printf("\tbyte sent: %d bytes\n", r);
#endif
}
@@ -198,3 +205,98 @@ gr_udp_sink::work (int noutput_items,
return noutput_items;
}
+
+void gr_udp_sink::connect( const char *host, unsigned short port )
+{
+ if(d_connected)
+ disconnect();
+
+ if(host != NULL ) {
+ // Get the destination address
+ struct addrinfo *ip_dst;
+ struct addrinfo hints;
+ memset( (void*)&hints, 0, sizeof(hints) );
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ char port_str[12];
+ sprintf( port_str, "%d", port );
+
+ // FIXME leaks if report_error throws below
+ int ret = getaddrinfo( host, port_str, &hints, &ip_dst );
+ if( ret != 0 )
+ report_error("gr_udp_source/getaddrinfo",
+ "can't initialize destination socket" );
+
+ // don't need d_mutex lock when !d_connected
+ if(::connect(d_socket, ip_dst->ai_addr, ip_dst->ai_addrlen) == -1) {
+ report_error("socket connect","can't connect to socket");
+ }
+ d_connected = true;
+
+ freeaddrinfo(ip_dst);
+ }
+
+ return;
+}
+
+void gr_udp_sink::disconnect()
+{
+ if(!d_connected)
+ return;
+
+ #if SNK_VERBOSE
+ printf("gr_udp_sink disconnecting\n");
+ #endif
+
+ gruel::scoped_lock guard(d_mutex); // protect d_socket from work()
+
+ // Send a few zero-length packets to signal receiver we are done
+ if(d_eof) {
+ int i;
+ for( i = 0; i < 3; i++ )
+ (void) send( d_socket, NULL, 0, 0 ); // ignore errors
+ }
+
+ // Sending EOF can produce ERRCONNREFUSED errors that won't show up
+ // until the next send or recv, which might confuse us if it happens
+ // on a new connection. The following does a nonblocking recv to
+ // clear any such errors.
+ timeval timeout;
+ timeout.tv_sec = 0; // zero time for immediate return
+ timeout.tv_usec = 0;
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(d_socket, &readfds);
+ int r = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
+ if(r < 0) {
+ #if SNK_VERBOSE
+ report_error("udp_sink/select",NULL);
+ #endif
+ }
+ else if(r > 0) { // call recv() to get error return
+ r = recv(d_socket, (char*)&readfds, sizeof(readfds), 0);
+ if(r < 0) {
+ #if SNK_VERBOSE
+ report_error("udp_sink/recv",NULL);
+ #endif
+ }
+ }
+
+ // Since I can't find any way to disconnect a datagram socket in Cygwin,
+ // we just leave it connected but disable sending.
+#if 0
+ // zeroed address structure should reset connection
+ struct sockaddr addr;
+ memset( (void*)&addr, 0, sizeof(addr) );
+ // addr.sa_family = AF_UNSPEC; // doesn't work on Cygwin
+ // addr.sa_family = AF_INET; // doesn't work on Cygwin
+
+ if(::connect(d_socket, &addr, sizeof(addr)) == -1)
+ report_error("socket connect","can't connect to socket");
+#endif
+
+ d_connected = false;
+
+ return;
+}
diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.h b/gnuradio-core/src/lib/io/gr_udp_sink.h
index f22b92dd0..421d514a4 100644
--- a/gnuradio-core/src/lib/io/gr_udp_sink.h
+++ b/gnuradio-core/src/lib/io/gr_udp_sink.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -24,18 +24,6 @@
#define INCLUDED_GR_UDP_SINK_H
#include <gr_sync_block.h>
-#include <boost/thread.hpp>
-#if defined(HAVE_SOCKET)
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#elif defined(HAVE_WINDOWS_H)
-#include <winsock2.h>
-#include <windows.h>
-#endif
-#if defined(HAVE_NETINET_IN_H)
-#include <netinet/in.h>
-#endif
-
#include <gruel/thread.h>
class gr_udp_sink;
@@ -43,85 +31,75 @@ typedef boost::shared_ptr<gr_udp_sink> gr_udp_sink_sptr;
gr_udp_sink_sptr
gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size=1472);
+ const char *host, unsigned short port,
+ int payload_size=1472, bool eof=true);
/*!
* \brief Write stream to an UDP socket.
* \ingroup sink_blk
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src Destination port to bind to (0 allows socket to choose an appropriate port)
- * \param dst The destination address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_dst Destination port to connect to
- * \param payload_size UDP payload size by default set to
- * 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param host The name or IP address of the receiving host; use
+ * NULL or None for no connection
+ * \param port Destination port to connect to on receiving host
+ * \param payload_size UDP payload size by default set to 1472 =
+ * (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Send zero-length packet on disconnect
*/
class gr_udp_sink : public gr_sync_block
{
friend gr_udp_sink_sptr gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size);
+ const char *host,
+ unsigned short port,
+ int payload_size, bool eof);
private:
size_t d_itemsize;
- bool d_updated;
- gruel::mutex d_mutex;
- int d_payload_size; // maximum transmission unit (packet length)
- int d_socket; // handle to socket
- int d_socket_rcv; // handle to socket retuned in the accept call
- struct in_addr d_ip_src; // store the source ip info
- struct in_addr d_ip_dst; // store the destination ip info
- unsigned short d_port_src; // the port number to open for connections to this service
- unsigned short d_port_dst; // port number of the remove system
- struct sockaddr_in d_sockaddr_src; // store the source sockaddr data (formatted IP address and port number)
- struct sockaddr_in d_sockaddr_dst; // store the destination sockaddr data (formatted IP address and port number)
+ int d_payload_size; // maximum transmission unit (packet length)
+ bool d_eof; // send zero-length packet on disconnect
+ int d_socket; // handle to socket
+ bool d_connected; // are we connected?
+ gruel::mutex d_mutex; // protects d_socket and d_connected
protected:
/*!
* \brief UDP Sink Constructor
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src Destination port to bind to (0 allows socket to choose an appropriate port)
- * \param dst The destination address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_dst Destination port to connect to
+ * \param host The name or IP address of the receiving host; use
+ * NULL or None for no connection
+ * \param port Destination port to connect to on receiving host
* \param payload_size UDP payload size by default set to
* 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Send zero-length packet on disconnect
*/
gr_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size);
+ const char *host, unsigned short port,
+ int payload_size, bool eof);
public:
~gr_udp_sink ();
- /*!
- * \brief open a socket specified by the port and ip address info
- *
- * Opens a socket, binds to the address, and makes connectionless association
- * over UDP. If any of these fail, the fuction retuns the error and exits.
- */
- bool open();
+ /*! \brief return the PAYLOAD_SIZE of the socket */
+ int payload_size() { return d_payload_size; }
- /*!
- * \brief Close current socket.
+ /*! \brief Change the connection to a new destination
+ *
+ * \param host The name or IP address of the receiving host; use
+ * NULL or None to break the connection without closing
+ * \param port Destination port to connect to on receiving host
*
- * Shuts down read/write on the socket
+ * Calls disconnect() to terminate any current connection first.
*/
- void close();
+ void connect( const char *host, unsigned short port );
- /*! \brief return the PAYLOAD_SIZE of the socket */
- int payload_size() { return d_payload_size; }
+ /*! \brief Send zero-length packet (if eof is requested) then stop sending
+ *
+ * Zero-byte packets can be interpreted as EOF by gr_udp_source. Note that
+ * disconnect occurs automatically when the sink is destroyed, but not when
+ * its top_block stops.*/
+ void disconnect();
// should we export anything else?
diff --git a/gnuradio-core/src/lib/io/gr_udp_sink.i b/gnuradio-core/src/lib/io/gr_udp_sink.i
index 0f37b477b..a71006ae0 100644
--- a/gnuradio-core/src/lib/io/gr_udp_sink.i
+++ b/gnuradio-core/src/lib/io/gr_udp_sink.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright 2007,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -25,22 +25,22 @@ GR_SWIG_BLOCK_MAGIC(gr,udp_sink)
gr_udp_sink_sptr
gr_make_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size=1472);
+ const char *host, unsigned short port,
+ int payload_size=1472, bool eof=true) throw (std::runtime_error);
class gr_udp_sink : public gr_sync_block
{
protected:
gr_udp_sink (size_t itemsize,
- const char *src, unsigned short port_src,
- const char *dst, unsigned short port_dst,
- int payload_size);
-
- bool open();
- void close();
- int payload_size() { return d_payload_size; }
+ const char *host, unsigned short port,
+ int payload_size, bool eof)
+ throw (std::runtime_error);
public:
~gr_udp_sink ();
+
+ int payload_size() { return d_payload_size; }
+ void connect( const char *host, unsigned short port );
+ void disconnect();
+
};
diff --git a/gnuradio-core/src/lib/io/gr_udp_source.cc b/gnuradio-core/src/lib/io/gr_udp_source.cc
index d76d0ee32..fea9a26ba 100644
--- a/gnuradio-core/src/lib/io/gr_udp_source.cc
+++ b/gnuradio-core/src/lib/io/gr_udp_source.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -29,80 +29,126 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
-#if defined(HAVE_SOCKET)
+
+#if defined(HAVE_NETDB_H)
#include <netdb.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
typedef void* optval_t;
-#else
+
+// ntohs() on FreeBSD may require both netinet/in.h and arpa/inet.h, in order
+#if defined(HAVE_NETINET_IN_H)
+#include <netinet/in.h>
+#endif
+#if defined(HAVE_ARPA_INET_H)
+#include <arpa/inet.h>
+#endif
+
+#elif defined(HAVE_WINDOWS_H)
+// if not posix, assume winsock
+#define USING_WINSOCK
+#include <winsock2.h>
+#include <ws2tcpip.h>
#define SHUT_RDWR 2
-#define inet_aton(N,A) ( (A)->s_addr = inet_addr(N), ( (A)->s_addr != INADDR_NONE ) )
typedef char* optval_t;
#endif
+#define USE_SELECT 1 // non-blocking receive on all platforms
+#define USE_RCV_TIMEO 0 // non-blocking receive on all but Cygwin
#define SRC_VERBOSE 0
-gr_udp_source::gr_udp_source(size_t itemsize, const char *src,
- unsigned short port_src, int payload_size)
+static int is_error( int perr )
+{
+ // Compare error to posix error code; return nonzero if match.
+#if defined(USING_WINSOCK)
+#define ENOPROTOOPT 109
+ // All codes to be checked for must be defined below
+ int werr = WSAGetLastError();
+ switch( werr ) {
+ case WSAETIMEDOUT:
+ return( perr == EAGAIN );
+ case WSAENOPROTOOPT:
+ return( perr == ENOPROTOOPT );
+ default:
+ fprintf(stderr,"gr_udp_source/is_error: unknown error %d\n", perr );
+ throw std::runtime_error("internal error");
+ }
+ return 0;
+#else
+ return( perr == errno );
+#endif
+}
+
+static void report_error( const char *msg1, const char *msg2 )
+{
+ // Deal with errors, both posix and winsock
+#if defined(USING_WINSOCK)
+ int werr = WSAGetLastError();
+ fprintf(stderr, "%s: winsock error %d\n", msg1, werr );
+#else
+ perror(msg1);
+#endif
+ if( msg2 != NULL )
+ throw std::runtime_error(msg2);
+ return;
+}
+
+gr_udp_source::gr_udp_source(size_t itemsize, const char *host,
+ unsigned short port, int payload_size,
+ bool eof, bool wait)
: gr_sync_block ("udp_source",
gr_make_io_signature(0, 0, 0),
gr_make_io_signature(1, 1, itemsize)),
- d_itemsize(itemsize), d_updated(false), d_payload_size(payload_size), d_residual(0), d_temp_offset(0)
+ d_itemsize(itemsize), d_payload_size(payload_size),
+ d_eof(eof), d_wait(wait), d_socket(-1), d_residual(0), d_temp_offset(0)
{
int ret = 0;
+
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // initialize winsock DLL
+ WSADATA wsaData;
+ int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
+ if( iResult != NO_ERROR ) {
+ report_error( "gr_udp_source WSAStartup", "can't open socket" );
+ }
+#endif
// Set up the address stucture for the source address and port numbers
// Get the source IP address from the host name
- struct hostent *hsrc = gethostbyname(src);
- if(hsrc) { // if the source was provided as a host namex
- d_ip_src = *(struct in_addr*)hsrc->h_addr_list[0];
- }
- else { // assume it was specified as an IP address
- if((ret=inet_aton(src, &d_ip_src)) == 0) { // format IP address
- perror("Not a valid source IP address or host name");
- throw std::runtime_error("can't initialize source socket");
- }
- }
+ struct addrinfo *ip_src; // store the source IP address to use
+ struct addrinfo hints;
+ memset( (void*)&hints, 0, sizeof(hints) );
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_PASSIVE;
+ char port_str[12];
+ sprintf( port_str, "%d", port );
- d_port_src = htons(port_src); // format port number
-
- d_sockaddr_src.sin_family = AF_INET;
- d_sockaddr_src.sin_addr = d_ip_src;
- d_sockaddr_src.sin_port = d_port_src;
+ // FIXME leaks if report_error throws below
+ ret = getaddrinfo( host, port_str, &hints, &ip_src );
+ if( ret != 0 )
+ report_error("gr_udp_source/getaddrinfo",
+ "can't initialize source socket" );
+ // FIXME leaks if report_error throws below
d_temp_buff = new char[d_payload_size]; // allow it to hold up to payload_size bytes
-
- open();
-}
-gr_udp_source_sptr
-gr_make_udp_source (size_t itemsize, const char *ipaddr,
- unsigned short port, int payload_size)
-{
- return gr_udp_source_sptr (new gr_udp_source (itemsize, ipaddr,
- port, payload_size));
-}
-
-gr_udp_source::~gr_udp_source ()
-{
- delete [] d_temp_buff;
- close();
-}
-
-bool
-gr_udp_source::open()
-{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
// create socket
- d_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ d_socket = socket(ip_src->ai_family, ip_src->ai_socktype,
+ ip_src->ai_protocol);
if(d_socket == -1) {
- perror("socket open");
- throw std::runtime_error("can't open socket");
+ report_error("socket open","can't open socket");
}
// Turn on reuse address
int opt_val = 1;
if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (optval_t)&opt_val, sizeof(int)) == -1) {
- perror("SO_REUSEADDR");
- throw std::runtime_error("can't set socket option SO_REUSEADDR");
+ report_error("SO_REUSEADDR","can't set socket option SO_REUSEADDR");
}
// Don't wait when shutting down
@@ -110,40 +156,61 @@ gr_udp_source::open()
lngr.l_onoff = 1;
lngr.l_linger = 0;
if(setsockopt(d_socket, SOL_SOCKET, SO_LINGER, (optval_t)&lngr, sizeof(linger)) == -1) {
- perror("SO_LINGER");
- throw std::runtime_error("can't set socket option SO_LINGER");
+ if( !is_error(ENOPROTOOPT) ) { // no SO_LINGER for SOCK_DGRAM on Windows
+ report_error("SO_LINGER","can't set socket option SO_LINGER");
+ }
}
+#if USE_RCV_TIMEO
// Set a timeout on the receive function to not block indefinitely
// This value can (and probably should) be changed
+ // Ignored on Cygwin
+#if defined(USING_WINSOCK)
+ DWORD timeout = 1000; // milliseconds
+#else
timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
+#endif
if(setsockopt(d_socket, SOL_SOCKET, SO_RCVTIMEO, (optval_t)&timeout, sizeof(timeout)) == -1) {
- perror("SO_RCVTIMEO");
- throw std::runtime_error("can't set socket option SO_RCVTIMEO");
+ report_error("SO_RCVTIMEO","can't set socket option SO_RCVTIMEO");
}
+#endif // USE_RCV_TIMEO
// bind socket to an address and port number to listen on
- if(bind (d_socket, (sockaddr*)&d_sockaddr_src, sizeof(struct sockaddr)) == -1) {
- perror("socket bind");
- throw std::runtime_error("can't bind socket");
+ if(bind (d_socket, ip_src->ai_addr, ip_src->ai_addrlen) == -1) {
+ report_error("socket bind","can't bind socket");
}
-
- d_updated = true;
- return d_socket != 0;
+ freeaddrinfo(ip_src);
+
}
-void
-gr_udp_source::close()
+gr_udp_source_sptr
+gr_make_udp_source (size_t itemsize, const char *ipaddr,
+ unsigned short port, int payload_size, bool eof, bool wait)
{
- gruel::scoped_lock guard(d_mutex); // hold mutex for duration of this function
+ return gr_udp_source_sptr (new gr_udp_source (itemsize, ipaddr,
+ port, payload_size, eof, wait));
+}
+
+gr_udp_source::~gr_udp_source ()
+{
+ delete [] d_temp_buff;
- if (d_socket){
+ if (d_socket != -1){
shutdown(d_socket, SHUT_RDWR);
- d_socket = 0;
+#if defined(USING_WINSOCK)
+ closesocket(d_socket);
+#else
+ ::close(d_socket);
+#endif
+ d_socket = -1;
}
- d_updated = true;
+
+#if defined(USING_WINSOCK) // for Windows (with MinGW)
+ // free winsock resources
+ WSACleanup();
+#endif
}
int
@@ -175,29 +242,85 @@ gr_udp_source::work (int noutput_items,
// Update indexing of amount of bytes left in the buffer
d_residual -= nbytes;
- d_temp_offset = d_temp_offset+d_residual;
+ d_temp_offset += nbytes;
+
+ // Return now with what we've got.
+ assert(nbytes % d_itemsize == 0);
+ return nbytes/d_itemsize;
}
while(1) {
// get the data into our output buffer and record the number of bytes
+
+#if USE_SELECT
+ // RCV_TIMEO doesn't work on all systems (e.g., Cygwin)
+ // use select() instead of, or in addition to RCV_TIMEO
+ fd_set readfds;
+ timeval timeout;
+ timeout.tv_sec = 1; // Init timeout each iteration. Select can modify it.
+ timeout.tv_usec = 0;
+ FD_ZERO(&readfds);
+ FD_SET(d_socket, &readfds);
+ r = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
+ if(r < 0) {
+ report_error("udp_source/select",NULL);
+ return -1;
+ }
+ else if(r == 0 ) { // timed out
+ if( d_wait ) {
+ // Allow boost thread interrupt, then try again
+ boost::this_thread::interruption_point();
+ continue;
+ }
+ else
+ return -1;
+ }
+#endif // USE_SELECT
+
// This is a non-blocking call with a timeout set in the constructor
r = recv(d_socket, d_temp_buff, d_payload_size, 0); // get the entire payload or the what's available
+ // If r > 0, round it down to a multiple of d_itemsize
+ // (If sender is broken, don't propagate problem)
+ if (r > 0)
+ r = (r/d_itemsize) * d_itemsize;
+
// Check if there was a problem; forget it if the operation just timed out
if(r == -1) {
- if(errno == EAGAIN) { // handle non-blocking call timeout
+ if( is_error(EAGAIN) ) { // handle non-blocking call timeout
#if SRC_VERBOSE
printf("UDP receive timed out\n");
#endif
- // Break here to allow the rest of the flow graph time to run and so ctrl-C breaks
- break;
+ if( d_wait ) {
+ // Allow boost thread interrupt, then try again
+ boost::this_thread::interruption_point();
+ continue;
+ }
+ else
+ return -1;
}
else {
- perror("udp_source");
+ report_error("udp_source/recv",NULL);
return -1;
}
}
+ else if(r==0) {
+ if(d_eof) {
+ // zero-length packet interpreted as EOF
+
+ #if SNK_VERBOSE
+ printf("\tzero-length packet received; returning EOF\n");
+ #endif
+
+ return -1;
+ }
+ else{
+ // do we need to allow boost thread interrupt?
+ boost::this_thread::interruption_point();
+ continue;
+ }
+ }
else {
// Calculate the number of bytes we can take from the buffer in this call
nbytes = std::min(r, total_bytes-bytes_received);
@@ -235,3 +358,15 @@ gr_udp_source::work (int noutput_items,
return bytes_received/d_itemsize;
}
+// Return port number of d_socket
+int gr_udp_source::get_port(void)
+{
+ sockaddr_in name;
+ socklen_t len = sizeof(name);
+ int ret = getsockname( d_socket, (sockaddr*)&name, &len );
+ if( ret ) {
+ report_error("gr_udp_source/getsockname",NULL);
+ return -1;
+ }
+ return ntohs(name.sin_port);
+}
diff --git a/gnuradio-core/src/lib/io/gr_udp_source.h b/gnuradio-core/src/lib/io/gr_udp_source.h
index 61d719e4d..e23231aa7 100644
--- a/gnuradio-core/src/lib/io/gr_udp_source.h
+++ b/gnuradio-core/src/lib/io/gr_udp_source.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright 2007,2008,2009,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -24,54 +24,48 @@
#define INCLUDED_GR_UDP_SOURCE_H
#include <gr_sync_block.h>
-#if defined(HAVE_SOCKET)
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#elif defined(HAVE_WINDOWS_H)
-#include <winsock2.h>
-#include <windows.h>
-#endif
-#if defined(HAVE_NETINET_IN_H)
-#include <netinet/in.h>
-#endif
-
#include <gruel/thread.h>
class gr_udp_source;
typedef boost::shared_ptr<gr_udp_source> gr_udp_source_sptr;
-gr_udp_source_sptr gr_make_udp_source(size_t itemsize, const char *src,
- unsigned short port_src, int payload_size=1472);
+gr_udp_source_sptr gr_make_udp_source(size_t itemsize, const char *host,
+ unsigned short port,
+ int payload_size=1472,
+ bool eof=true, bool wait=true);
/*!
* \brief Read stream from an UDP socket.
* \ingroup source_blk
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src The port number on which the socket listens for data
- * \param payload_size UDP payload size by default set to
- * 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param host The name or IP address of the receiving host; can be
+ * NULL, None, or "0.0.0.0" to allow reading from any
+ * interface on the host
+ * \param port The port number on which to receive data; use 0 to
+ * have the system assign an unused port number
+ * \param payload_size UDP payload size by default set to 1472 =
+ * (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Interpret zero-length packet as EOF (default: true)
+ * \param wait Wait for data if not immediately available
+ * (default: true)
*
*/
class gr_udp_source : public gr_sync_block
{
- friend gr_udp_source_sptr gr_make_udp_source(size_t itemsize, const char *src,
- unsigned short port_src, int payload_size);
+ friend gr_udp_source_sptr gr_make_udp_source(size_t itemsize,
+ const char *host,
+ unsigned short port,
+ int payload_size,
+ bool eof, bool wait);
private:
size_t d_itemsize;
- bool d_updated;
- gruel::mutex d_mutex;
-
- int d_payload_size; // maximum transmission unit (packet length)
- int d_socket; // handle to socket
- int d_socket_rcv; // handle to socket retuned in the accept call
- struct in_addr d_ip_src; // store the source IP address to use
- unsigned short d_port_src; // the port number to open for connections to this service
- struct sockaddr_in d_sockaddr_src; // store the source sockaddr data (formatted IP address and port number)
+ int d_payload_size; // maximum transmission unit (packet length)
+ bool d_eof; // zero-length packet is EOF
+ bool d_wait; // wait if data if not immediately available
+ int d_socket; // handle to socket
char *d_temp_buff; // hold buffer between calls
ssize_t d_residual; // hold information about number of bytes stored in the temp buffer
size_t d_temp_offset; // point to temp buffer location offset
@@ -81,35 +75,29 @@ class gr_udp_source : public gr_sync_block
* \brief UDP Source Constructor
*
* \param itemsize The size (in bytes) of the item datatype
- * \param src The source address as either the host name or the 'numbers-and-dots'
- * IP address
- * \param port_src The port number on which the socket listens for data
- * \param payload_size UDP payload size by default set to
- * 1472 = (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param host The name or IP address of the receiving host; can be
+ * NULL, None, or "0.0.0.0" to allow reading from any
+ * interface on the host
+ * \param port The port number on which to receive data; use 0 to
+ * have the system assign an unused port number
+ * \param payload_size UDP payload size by default set to 1472 =
+ * (1500 MTU - (8 byte UDP header) - (20 byte IP header))
+ * \param eof Interpret zero-length packet as EOF (default: true)
+ * \param wait Wait for data if not immediately available
+ * (default: true)
*/
- gr_udp_source(size_t itemsize, const char *src, unsigned short port_src, int payload_size);
+ gr_udp_source(size_t itemsize, const char *host, unsigned short port,
+ int payload_size, bool eof, bool wait);
public:
~gr_udp_source();
- /*!
- * \brief open a socket specified by the port and ip address info
- *
- * Opens a socket, binds to the address, and waits for a connection
- * over UDP. If any of these fail, the fuction retuns the error and exits.
- */
- bool open();
-
- /*!
- * \brief Close current socket.
- *
- * Shuts down read/write on the socket
- */
- void close();
-
/*! \brief return the PAYLOAD_SIZE of the socket */
int payload_size() { return d_payload_size; }
+ /*! \breif return the port number of the socket */
+ int get_port();
+
// should we export anything else?
int work(int noutput_items,
diff --git a/gnuradio-core/src/lib/io/gr_udp_source.i b/gnuradio-core/src/lib/io/gr_udp_source.i
index fb39dad68..2001f33e9 100644
--- a/gnuradio-core/src/lib/io/gr_udp_source.i
+++ b/gnuradio-core/src/lib/io/gr_udp_source.i
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2007 Free Software Foundation, Inc.
+ * Copyright 2007,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -23,20 +23,19 @@
GR_SWIG_BLOCK_MAGIC(gr,udp_source)
gr_udp_source_sptr
-gr_make_udp_source (size_t itemsize, const char *src,
- unsigned short port_src, int payload_size=1472);
+gr_make_udp_source (size_t itemsize, const char *host,
+ unsigned short port, int payload_size=1472,
+ bool eof=true, bool wait=true) throw (std::runtime_error);
class gr_udp_source : public gr_sync_block
{
protected:
- gr_udp_source (size_t itemsize, const char *src,
- unsigned short port_src, int payload_size);
+ gr_udp_source (size_t itemsize, const char *host,
+ unsigned short port, int payload_size, bool eof, bool wait) throw (std::runtime_error);
public:
~gr_udp_source ();
- bool open();
- void close();
int payload_size() { return d_payload_size; }
-
+ int get_port();
};
diff --git a/gnuradio-core/src/lib/io/gri_logger.cc b/gnuradio-core/src/lib/io/gri_logger.cc
deleted file mode 100644
index 473a7c5ed..000000000
--- a/gnuradio-core/src/lib/io/gri_logger.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006,2009 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
-
-#if 0 // This needs reimplementation with boost threads and synchronization
-
-#include <gri_logger.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdexcept>
-#include <boost/weak_ptr.hpp>
-#include <string.h>
-
-
-/*
- * This class creates the thread that reads from the ringbuffer and
- * and writes to the file. This is opaque to the user.
- */
-class gri_log_poster : public omni_thread
-{
- FILE *d_fp;
- gr_buffer_sptr d_writer;
- gr_buffer_reader_sptr d_reader;
- omni_semaphore d_ringbuffer_ready;
- volatile bool d_time_to_die;
- volatile bool d_writer_overrun;
-
- virtual void* run_undetached(void * arg);
-
-public:
- gri_log_poster(const char *filename);
- ~gri_log_poster();
-
- void kill() { d_time_to_die = true; post(); }
- gr_buffer_sptr writer() const { return d_writer; }
- void post() { d_ringbuffer_ready.post(); }
- void note_writer_overrun() { d_writer_overrun = true; }
-};
-
-gri_log_poster::gri_log_poster(const char *filename)
- : omni_thread(),
- d_ringbuffer_ready(1, 1), // binary semaphore
- d_time_to_die(false),
- d_writer_overrun(false)
-{
- if ((d_fp = fopen(filename, "w")) == 0){
- perror (filename);
- throw std::runtime_error("can't open file");
- }
-
- // Create a 1MB buffer.
- d_writer = gr_make_buffer(1 * 1024 * 1024, sizeof(unsigned char));
- d_reader = gr_buffer_add_reader(d_writer, 0);
-
- start_undetached(); // start the thread
-}
-
-gri_log_poster::~gri_log_poster()
-{
- if (d_fp != 0){
- fclose(d_fp);
- d_fp = 0;
- }
-}
-
-/*
- * This is the body of the logging thread.
- */
-void *
-gri_log_poster::run_undetached(void *arg)
-{
- int nbytes;
-
- //fprintf(stderr, "Enter: run_undetached!\n");
-
- while (!d_time_to_die){
- while ((nbytes = d_reader->items_available()) > 0){
- fwrite(d_reader->read_pointer(), 1, nbytes, d_fp);
- d_reader->update_read_pointer(nbytes);
- }
- fflush(d_fp);
- d_ringbuffer_ready.wait();
-
- if (d_writer_overrun){
- fputs(">>>>> gri_logger: writer overrun. Info lost <<<<<\n", d_fp);
- d_writer_overrun = false;
- }
- }
-
- // fprintf(stderr, "Exit: run_undetached!\n");
- return 0;
-}
-
-// ------------------------------------------------------------------------
-
-static boost::weak_ptr<gri_logger> s_singleton; // weak pointer IQ test ;-)
-static omni_mutex s_singleton_mutex;
-
-gri_logger_sptr
-gri_logger::singleton()
-{
- omni_mutex_lock l(s_singleton_mutex);
- gri_logger_sptr r;
-
- if (r = s_singleton.lock())
- return r;
-
- r = gri_logger_sptr(new gri_logger("gri_logger.log"));
- s_singleton = r;
- return r;
-}
-
-
-gri_logger::gri_logger(const char *filename)
-{
- d_poster = new gri_log_poster(filename);
-}
-
-gri_logger::~gri_logger()
-{
- d_poster->kill();
- d_poster->join(NULL);
-}
-
-void
-gri_logger::write(const void *buf, size_t count)
-{
- omni_mutex_lock l(d_write_mutex);
- gr_buffer_sptr writer = d_poster->writer();
-
- // either write it all, or drop it on the ground
- if (count <= (size_t) writer->space_available()){
- memcpy(writer->write_pointer(), buf, count);
- writer->update_write_pointer(count);
- d_poster->post();
- }
- else {
- d_poster->note_writer_overrun();
- }
-}
-
-void
-gri_logger::printf(const char *format, ...)
-{
- va_list ap;
- char buf[4096];
- int n;
-
- va_start(ap, format);
- n = vsnprintf(buf, sizeof(buf), format, ap);
- va_end(ap);
- if (n > -1 && n < (ssize_t) sizeof(buf))
- write(buf, n);
-}
-
-#endif
diff --git a/gnuradio-core/src/lib/io/gri_logger.h b/gnuradio-core/src/lib/io/gri_logger.h
deleted file mode 100644
index 0a1414540..000000000
--- a/gnuradio-core/src/lib/io/gri_logger.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006,2009 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_GRI_LOGGER_H
-#define INCLUDED_GRI_LOGGER_H
-
-#if 0 // This needs reimplementation with boost threads and synchronization
-
-#include <stddef.h>
-#include <gnuradio/omnithread.h>
-#include <gr_buffer.h>
-
-class gri_log_poster;
-class gri_logger;
-typedef boost::shared_ptr<gri_logger> gri_logger_sptr;
-
-
-/*!
- * \brief non-blocking logging to a file.
- *
- * In reality, this may block, but only for a bounded time.
- * Trust me, it's safe to use from portaudio and JACK callbacks.
- */
-class gri_logger
-{
- gri_log_poster *d_poster;
- omni_mutex d_write_mutex;
-
-public:
- static gri_logger_sptr singleton();
-
- gri_logger(const char *filename);
- ~gri_logger();
-
- void write(const void *buf, size_t count);
- void printf(const char *format, ...);
-};
-
-#endif
-
-#endif /* INCLUDED_GRI_LOGGER_H */
diff --git a/gnuradio-core/src/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am
index dcc0017b3..f0516f2fd 100644
--- a/gnuradio-core/src/python/gnuradio/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/Makefile.am
@@ -30,6 +30,7 @@ grpython_PYTHON = \
eng_notation.py \
eng_option.py \
modulation_utils.py \
+ modulation_utils2.py \
ofdm_packet_utils.py \
packet_utils.py \
gr_unittest.py \
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
index 68d683623..7b24fb69d 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2005,2007,2009 Free Software Foundation, Inc.
+# Copyright 2005,2007,2009,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py
index 860015c3f..55e4890f3 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk.py
@@ -233,10 +233,10 @@ class dbpsk_demod(gr.hier_block2):
arity = pow(2,self.bits_per_symbol())
# Automatic gain control
- scale = (1.0/16384.0)
- self.pre_scaler = gr.multiply_const_cc(scale) # scale the signal from full-range to +-1
- #self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
- self.agc = gr.feedforward_agc_cc(16, 2.0)
+ #scale = (1.0/16384.0)
+ #self.pre_scaler = gr.multiply_const_cc(scale) # scale the signal from full-range to +-1
+ self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100)
+ #self.agc = gr.feedforward_agc_cc(16, 2.0)
# RRC data filter
ntaps = 11 * samples_per_symbol
@@ -288,7 +288,7 @@ class dbpsk_demod(gr.hier_block2):
self._setup_logging()
# Connect and Initialize base class
- self.connect(self, self.pre_scaler, self.agc, self.rrc_filter, self.receiver,
+ self.connect(self, self.agc, self.rrc_filter, self.receiver,
self.diffdec, self.slicer, self.symbol_mapper, self.unpack, self)
def samples_per_symbol(self):
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py
index e9fb3df89..d7bcf5390 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/dbpsk2.py
@@ -1,5 +1,5 @@
#
-# Copyright 2005,2006,2007 Free Software Foundation, Inc.
+# Copyright 2009,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -25,7 +25,7 @@
differential BPSK modulation and demodulation.
"""
-from gnuradio import gr, gru, modulation_utils
+from gnuradio import gr, gru, modulation_utils2
from math import pi, sqrt, ceil
import psk
import cmath
@@ -38,8 +38,8 @@ _def_gray_code = True
_def_verbose = False
_def_log = False
-_def_freq_alpha = 4e-3
-_def_costas_alpha = 0.1
+_def_freq_alpha = 0.010
+_def_phase_alpha = 0.1
_def_timing_alpha = 0.100
_def_timing_beta = 0.010
_def_timing_max_dev = 1.5
@@ -83,7 +83,7 @@ class dbpsk2_mod(gr.hier_block2):
self._excess_bw = excess_bw
self._gray_code = gray_code
- if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2:
+ if self._samples_per_symbol < 2:
raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol)
arity = pow(2,self.bits_per_symbol())
@@ -103,7 +103,7 @@ class dbpsk2_mod(gr.hier_block2):
# pulse shaping filter
nfilts = 32
- ntaps = nfilts * 11 * self._samples_per_symbol # make nfilts filters of ntaps each
+ ntaps = nfilts * 11 * int(self._samples_per_symbol) # make nfilts filters of ntaps each
self.rrc_taps = gr.firdes.root_raised_cosine(
nfilts, # gain
nfilts, # sampling rate based on 32 filters in resampler
@@ -145,7 +145,7 @@ class dbpsk2_mod(gr.hier_block2):
"""
Given command line options, create dictionary suitable for passing to __init__
"""
- return modulation_utils.extract_kwargs_from_options(dbpsk2_mod.__init__,
+ return modulation_utils2.extract_kwargs_from_options(dbpsk2_mod.__init__,
('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -182,7 +182,7 @@ class dbpsk2_demod(gr.hier_block2):
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
freq_alpha=_def_freq_alpha,
- costas_alpha=_def_costas_alpha,
+ phase_alpha=_def_phase_alpha,
timing_alpha=_def_timing_alpha,
timing_max_dev=_def_timing_max_dev,
gray_code=_def_gray_code,
@@ -201,8 +201,8 @@ class dbpsk2_demod(gr.hier_block2):
@type excess_bw: float
@param freq_alpha: loop filter gain for frequency recovery
@type freq_alpha: float
- @param costas_alpha: loop filter gain for phase/fine frequency recovery
- @type costas_alpha: float
+ @param phase_alpha: loop filter gain for phase/fine frequency recovery
+ @type phase_alpha: float
@param timing_alpha: loop alpha gain for timing recovery
@type timing_alpha: float
@param timing_max: timing loop maximum rate deviations
@@ -226,8 +226,8 @@ class dbpsk2_demod(gr.hier_block2):
self._samples_per_symbol = samples_per_symbol
self._excess_bw = excess_bw
self._freq_alpha = freq_alpha
- self._freq_beta = 0.25*self._freq_alpha**2
- self._costas_alpha = costas_alpha
+ self._freq_beta = 0.10*self._freq_alpha
+ self._phase_alpha = phase_alpha
self._timing_alpha = timing_alpha
self._timing_beta = _def_timing_beta
self._timing_max_dev=timing_max_dev
@@ -259,13 +259,13 @@ class dbpsk2_demod(gr.hier_block2):
self.time_recov.set_beta(self._timing_beta)
# Perform phase / fine frequency correction
- self._costas_beta = 0.25 * self._costas_alpha * self._costas_alpha
+ self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
# Allow a frequency swing of +/- half of the sample rate
fmin = -0.5
fmax = 0.5
- self.phase_recov = gr.costas_loop_cc(self._costas_alpha,
- self._costas_beta,
+ self.phase_recov = gr.costas_loop_cc(self._phase_alpha,
+ self._phase_beta,
fmax, fmin, arity)
# Do differential decoding based on phase change of symbols
@@ -308,29 +308,27 @@ class dbpsk2_demod(gr.hier_block2):
print "bits per symbol: %d" % self.bits_per_symbol()
print "Gray code: %s" % self._gray_code
print "RRC roll-off factor: %.2f" % self._excess_bw
- print "FLL gain: %.2f" % self._freq_alpha
- print "Costas Loop alpha: %.2f" % self._costas_alpha
- print "Costas Loop beta: %.2f" % self._costas_beta
- print "Timing alpha gain: %.2f" % self._timing_alpha
- print "Timing beta gain: %.2f" % self._timing_beta
+ print "FLL gain: %.2e" % self._freq_alpha
+ print "Timing alpha gain: %.2e" % self._timing_alpha
+ print "Timing beta gain: %.2e" % self._timing_beta
print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
def _setup_logging(self):
print "Modulation logging turned on."
- self.connect(self.pre_scaler,
- gr.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat"))
self.connect(self.agc,
gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat"))
- self.connect(self.clock_recov,
- gr.file_sink(gr.sizeof_gr_complex, "rx_clock_recov.dat"))
+ self.connect(self.freq_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
self.connect(self.time_recov,
gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect(self.phase_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat"))
self.connect(self.diffdec,
gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
self.connect(self.slicer,
- gr.file_sink(gr.sizeof_char, "rx_slicer.dat"))
+ gr.file_sink(gr.sizeof_char, "rx_slicer.dat"))
self.connect(self.symbol_mapper,
gr.file_sink(gr.sizeof_char, "rx_symbol_mapper.dat"))
self.connect(self.unpack,
@@ -347,11 +345,11 @@ class dbpsk2_demod(gr.hier_block2):
help="disable gray coding on modulated bits (PSK)")
parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
help="set frequency lock loop alpha gain value [default=%default] (PSK)")
- parser.add_option("", "--costas-alpha", type="float", default=None,
- help="set Costas loop alpha value [default=%default] (PSK)")
- parser.add_option("", "--gain-alpha", type="float", default=_def_timing_alpha,
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default] (PSK)")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)")
- parser.add_option("", "--gain-beta", type="float", default=_def_timing_beta,
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)")
parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)")
@@ -361,11 +359,11 @@ class dbpsk2_demod(gr.hier_block2):
"""
Given command line options, create dictionary suitable for passing to __init__
"""
- return modulation_utils.extract_kwargs_from_options(
+ return modulation_utils2.extract_kwargs_from_options(
dbpsk2_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
#
# Add these to the mod/demod registry
#
-modulation_utils.add_type_1_mod('dbpsk2', dbpsk2_mod)
-modulation_utils.add_type_1_demod('dbpsk2', dbpsk2_demod)
+modulation_utils2.add_type_1_mod('dbpsk2', dbpsk2_mod)
+modulation_utils2.add_type_1_demod('dbpsk2', dbpsk2_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py
index 9fae6acca..e1e627707 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/dqpsk2.py
@@ -1,5 +1,5 @@
#
-# Copyright 2005,2006,2007,2009 Free Software Foundation, Inc.
+# Copyright 2009,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -25,7 +25,7 @@
differential QPSK modulation and demodulation.
"""
-from gnuradio import gr, gru, modulation_utils
+from gnuradio import gr, gru, modulation_utils2
from math import pi, sqrt
import psk
import cmath
@@ -38,8 +38,8 @@ _def_gray_code = True
_def_verbose = False
_def_log = False
-_def_freq_alpha = 4e-3
-_def_costas_alpha = 0.01
+_def_freq_alpha = 0.010
+_def_phase_alpha = 0.01
_def_timing_alpha = 0.100
_def_timing_beta = 0.010
_def_timing_max_dev = 1.5
@@ -83,8 +83,8 @@ class dqpsk2_mod(gr.hier_block2):
self._excess_bw = excess_bw
self._gray_code = gray_code
- if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2:
- raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol)
+ if samples_per_symbol < 2:
+ raise TypeError, ("sbp must be >= 2, is %f" % samples_per_symbol)
ntaps = 11 * samples_per_symbol
@@ -107,7 +107,7 @@ class dqpsk2_mod(gr.hier_block2):
# pulse shaping filter
nfilts = 32
- ntaps = nfilts * 11 * self._samples_per_symbol # make nfilts filters of ntaps each
+ ntaps = 11 * int(nfilts * self._samples_per_symbol) # make nfilts filters of ntaps each
self.rrc_taps = gr.firdes.root_raised_cosine(
nfilts, # gain
nfilts, # sampling rate based on 32 filters in resampler
@@ -168,7 +168,7 @@ class dqpsk2_mod(gr.hier_block2):
"""
Given command line options, create dictionary suitable for passing to __init__
"""
- return modulation_utils.extract_kwargs_from_options(dqpsk2_mod.__init__,
+ return modulation_utils2.extract_kwargs_from_options(dqpsk2_mod.__init__,
('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -185,7 +185,7 @@ class dqpsk2_demod(gr.hier_block2):
samples_per_symbol=_def_samples_per_symbol,
excess_bw=_def_excess_bw,
freq_alpha=_def_freq_alpha,
- costas_alpha=_def_costas_alpha,
+ phase_alpha=_def_phase_alpha,
timing_alpha=_def_timing_alpha,
timing_max_dev=_def_timing_max_dev,
gray_code=_def_gray_code,
@@ -204,8 +204,8 @@ class dqpsk2_demod(gr.hier_block2):
@type excess_bw: float
@param freq_alpha: loop filter gain for frequency recovery
@type freq_alpha: float
- @param costas_alpha: loop filter gain
- @type costas_alphas: float
+ @param phase_alpha: loop filter gain
+ @type phase_alphas: float
@param timing_alpha: timing loop alpha gain
@type timing_alpha: float
@param timing_max: timing loop maximum rate deviations
@@ -230,7 +230,7 @@ class dqpsk2_demod(gr.hier_block2):
self._excess_bw = excess_bw
self._freq_alpha = freq_alpha
self._freq_beta = 0.25*self._freq_alpha**2
- self._costas_alpha = costas_alpha
+ self._phase_alpha = phase_alpha
self._timing_alpha = timing_alpha
self._timing_beta = _def_timing_beta
self._timing_max_dev=timing_max_dev
@@ -264,13 +264,13 @@ class dqpsk2_demod(gr.hier_block2):
# Perform phase / fine frequency correction
- self._costas_beta = 0.25 * self._costas_alpha * self._costas_alpha
+ self._phase_beta = 0.25 * self._phase_alpha * self._phase_alpha
# Allow a frequency swing of +/- half of the sample rate
fmin = -0.5
fmax = 0.5
- self.phase_recov = gr.costas_loop_cc(self._costas_alpha,
- self._costas_beta,
+ self.phase_recov = gr.costas_loop_cc(self._phase_alpha,
+ self._phase_beta,
fmax, fmin, arity)
@@ -315,24 +315,22 @@ class dqpsk2_demod(gr.hier_block2):
print "Gray code: %s" % self._gray_code
print "RRC roll-off factor: %.2f" % self._excess_bw
print "FLL gain: %.2f" % self._freq_alpha
- print "Costas Loop alpha: %.2e" % self._costas_alpha
- print "Costas Loop beta: %.2e" % self._costas_beta
print "Timing alpha gain: %.2f" % self._timing_alpha
print "Timing beta gain: %.2f" % self._timing_beta
print "Timing max dev: %.2f" % self._timing_max_dev
+ print "Phase track alpha: %.2e" % self._phase_alpha
+ print "Phase track beta: %.2e" % self._phase_beta
def _setup_logging(self):
print "Modulation logging turned on."
- self.connect(self.pre_scaler,
- gr.file_sink(gr.sizeof_gr_complex, "rx_prescaler.dat"))
self.connect(self.agc,
gr.file_sink(gr.sizeof_gr_complex, "rx_agc.dat"))
- self.connect(self.rrc_filter,
- gr.file_sink(gr.sizeof_gr_complex, "rx_rrc_filter.dat"))
- self.connect(self.clock_recov,
- gr.file_sink(gr.sizeof_gr_complex, "rx_clock_recov.dat"))
+ self.connect(self.freq_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_freq_recov.dat"))
self.connect(self.time_recov,
gr.file_sink(gr.sizeof_gr_complex, "rx_time_recov.dat"))
+ self.connect(self.phase_recov,
+ gr.file_sink(gr.sizeof_gr_complex, "rx_phase_recov.dat"))
self.connect(self.diffdec,
gr.file_sink(gr.sizeof_gr_complex, "rx_diffdec.dat"))
self.connect(self.slicer,
@@ -344,7 +342,7 @@ class dqpsk2_demod(gr.hier_block2):
def add_options(parser):
"""
- Adds modulation-specific options to the standard parser
+ Adds DQPSK demodulation-specific options to the standard parser
"""
parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw,
help="set RRC excess bandwith factor [default=%default] (PSK)")
@@ -353,11 +351,11 @@ class dqpsk2_demod(gr.hier_block2):
help="disable gray coding on modulated bits (PSK)")
parser.add_option("", "--freq-alpha", type="float", default=_def_freq_alpha,
help="set frequency lock loop alpha gain value [default=%default] (PSK)")
- parser.add_option("", "--costas-alpha", type="float", default=_def_costas_alpha,
- help="set Costas loop alpha value [default=%default] (PSK)")
- parser.add_option("", "--gain-alpha", type="float", default=_def_timing_alpha,
+ parser.add_option("", "--phase-alpha", type="float", default=_def_phase_alpha,
+ help="set phase tracking loop alpha value [default=%default] (PSK)")
+ parser.add_option("", "--timing-alpha", type="float", default=_def_timing_alpha,
help="set timing symbol sync loop gain alpha value [default=%default] (GMSK/PSK)")
- parser.add_option("", "--gain-beta", type="float", default=_def_timing_beta,
+ parser.add_option("", "--timing-beta", type="float", default=_def_timing_beta,
help="set timing symbol sync loop gain beta value [default=%default] (GMSK/PSK)")
parser.add_option("", "--timing-max-dev", type="float", default=_def_timing_max_dev,
help="set timing symbol sync loop maximum deviation [default=%default] (GMSK/PSK)")
@@ -367,7 +365,7 @@ class dqpsk2_demod(gr.hier_block2):
"""
Given command line options, create dictionary suitable for passing to __init__
"""
- return modulation_utils.extract_kwargs_from_options(
+ return modulation_utils2.extract_kwargs_from_options(
dqpsk2_demod.__init__, ('self',), options)
extract_kwargs_from_options=staticmethod(extract_kwargs_from_options)
@@ -375,5 +373,5 @@ class dqpsk2_demod(gr.hier_block2):
#
# Add these to the mod/demod registry
#
-modulation_utils.add_type_1_mod('dqpsk2', dqpsk2_mod)
-modulation_utils.add_type_1_demod('dqpsk2', dqpsk2_demod)
+modulation_utils2.add_type_1_mod('dqpsk2', dqpsk2_mod)
+modulation_utils2.add_type_1_demod('dqpsk2', dqpsk2_demod)
diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py b/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py
index c45ae4d1a..a479ed48e 100644
--- a/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py
+++ b/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
#
-# Copyright 2009 Free Software Foundation, Inc.
+# Copyright 2009,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -29,16 +29,18 @@ class pfb_channelizer_ccf(gr.hier_block2):
This simplifies the interface by allowing a single input stream to connect to this block.
It will then output a stream for each channel.
'''
- def __init__(self, numchans, taps):
+ def __init__(self, numchans, taps, oversample_rate=1):
gr.hier_block2.__init__(self, "pfb_channelizer_ccf",
gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature
gr.io_signature(numchans, numchans, gr.sizeof_gr_complex)) # Output signature
self._numchans = numchans
self._taps = taps
+ self._oversample_rate = oversample_rate
self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._numchans)
- self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps)
+ self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps,
+ self._oversample_rate)
self.v2s = gr.vector_to_streams(gr.sizeof_gr_complex, self._numchans)
self.connect(self, self.s2ss)
diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
index 3aff89ee7..341f58812 100644
--- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
@@ -1,5 +1,5 @@
#
-# Copyright 2004,2005,2006,2008 Free Software Foundation, Inc.
+# Copyright 2004,2005,2006,2008,2010 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
@@ -97,4 +97,5 @@ noinst_PYTHON = \
qa_unpack_k_bits.py \
qa_repeat.py \
qa_scrambler.py \
+ qa_udp_sink_source.py \
qa_vector_sink_source.py
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_scrambler.py b/gnuradio-core/src/python/gnuradio/gr/qa_scrambler.py
index 76b0e62fa..aecf49293 100755
--- a/gnuradio-core/src/python/gnuradio/gr/qa_scrambler.py
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_scrambler.py
@@ -40,5 +40,25 @@ class test_scrambler(gr_unittest.TestCase):
self.tb.run()
self.assertEqual(tuple(src_data[:-8]), dst.data()[8:]) # skip garbage during synchronization
+ def test_additive_scrambler(self):
+ src_data = (1,)*1000
+ src = gr.vector_source_b(src_data, False)
+ scrambler = gr.additive_scrambler_bb(0x8a, 0x7f, 7)
+ descrambler = gr.additive_scrambler_bb(0x8a, 0x7f, 7)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.run()
+ self.assertEqual(src_data, dst.data())
+
+ def test_additive_scrambler_reset(self):
+ src_data = (1,)*1000
+ src = gr.vector_source_b(src_data, False)
+ scrambler = gr.additive_scrambler_bb(0x8a, 0x7f, 7, 100)
+ descrambler = gr.additive_scrambler_bb(0x8a, 0x7f, 7, 100)
+ dst = gr.vector_sink_b()
+ self.tb.connect(src, scrambler, descrambler, dst)
+ self.tb.run()
+ self.assertEqual(src_data, dst.data())
+
if __name__ == '__main__':
gr_unittest.main ()
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py b/gnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py
new file mode 100755
index 000000000..b00b26bbe
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_udp_sink_source.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+#
+# Copyright 2008,2010 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.
+#
+
+from gnuradio import gr, gr_unittest
+from threading import Timer
+
+class test_sink_source(gr_unittest.TestCase):
+
+ def setUp(self):
+ self.tb_snd = gr.top_block()
+ self.tb_rcv = gr.top_block()
+
+ def tearDown(self):
+ self.tb_rcv = None
+ self.tb_snd = None
+
+ def test_001(self):
+ port = 65500
+
+ n_data = 16
+ src_data = [float(x) for x in range(n_data)]
+ expected_result = tuple(src_data)
+ src = gr.vector_source_f(src_data)
+ udp_snd = gr.udp_sink( gr.sizeof_float, 'localhost', port )
+ self.tb_snd.connect( src, udp_snd )
+
+ udp_rcv = gr.udp_source( gr.sizeof_float, 'localhost', port )
+ dst = gr.vector_sink_f()
+ self.tb_rcv.connect( udp_rcv, dst )
+
+ self.tb_rcv.start()
+ self.tb_snd.run()
+ udp_snd.disconnect()
+ self.timeout = False
+ q = Timer(3.0,self.stop_rcv)
+ q.start()
+ self.tb_rcv.wait()
+ q.cancel()
+
+ result_data = dst.data()
+ self.assertEqual(expected_result, result_data)
+ self.assert_(not self.timeout)
+
+ def test_002(self):
+ udp_rcv = gr.udp_source( gr.sizeof_float, '0.0.0.0', 0, eof=False )
+ rcv_port = udp_rcv.get_port()
+
+ udp_snd = gr.udp_sink( gr.sizeof_float, '127.0.0.1', 65500 )
+ udp_snd.connect( 'localhost', rcv_port )
+
+ n_data = 16
+ src_data = [float(x) for x in range(n_data)]
+ expected_result = tuple(src_data)
+ src = gr.vector_source_f(src_data)
+ dst = gr.vector_sink_f()
+
+ self.tb_snd.connect( src, udp_snd )
+ self.tb_rcv.connect( udp_rcv, dst )
+
+ self.tb_rcv.start()
+ self.tb_snd.run()
+ udp_snd.disconnect()
+ self.timeout = False
+ q = Timer(3.0,self.stop_rcv)
+ q.start()
+ self.tb_rcv.wait()
+ q.cancel()
+
+ result_data = dst.data()
+ self.assertEqual(expected_result, result_data)
+ self.assert_(self.timeout) # source ignores EOF?
+
+ def stop_rcv(self):
+ self.timeout = True
+ self.tb_rcv.stop()
+ #print "tb_rcv stopped by Timer"
+
+if __name__ == '__main__':
+ gr_unittest.main ()
+
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py b/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py
index 8d46e8192..f2808c448 100644
--- a/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py
@@ -30,3 +30,15 @@ def hexint(mask):
if mask >= 2**31:
return int(mask-2**32)
return mask
+
+def hexshort(mask):
+ """
+ Convert unsigned masks into signed shorts.
+
+ This allows us to use hex constants like 0x8000 when talking to
+ our hardware and not get screwed by them getting treated as python
+ longs.
+ """
+ if mask >= 2**15:
+ return int(mask-2**16)
+ return mask
diff --git a/gnuradio-core/src/python/gnuradio/modulation_utils2.py b/gnuradio-core/src/python/gnuradio/modulation_utils2.py
new file mode 100644
index 000000000..c5dba3e79
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/modulation_utils2.py
@@ -0,0 +1,81 @@
+#
+# Copyright 2010 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+
+"""
+Miscellaneous utilities for managing mods and demods, as well as other items
+useful in dealing with generalized handling of different modulations and demods.
+"""
+
+import inspect
+
+
+# Type 1 modulators accept a stream of bytes on their input and produce complex baseband output
+_type_1_modulators = {}
+
+def type_1_mods():
+ return _type_1_modulators
+
+def add_type_1_mod(name, mod_class):
+ _type_1_modulators[name] = mod_class
+
+
+# Type 1 demodulators accept complex baseband input and produce a stream of bits, packed
+# 1 bit / byte as their output. Their output is completely unambiguous. There is no need
+# to resolve phase or polarity ambiguities.
+_type_1_demodulators = {}
+
+def type_1_demods():
+ return _type_1_demodulators
+
+def add_type_1_demod(name, demod_class):
+ _type_1_demodulators[name] = demod_class
+
+
+def extract_kwargs_from_options(function, excluded_args, options):
+ """
+ Given a function, a list of excluded arguments and the result of
+ parsing command line options, create a dictionary of key word
+ arguments suitable for passing to the function. The dictionary
+ will be populated with key/value pairs where the keys are those
+ that are common to the function's argument list (minus the
+ excluded_args) and the attributes in options. The values are the
+ corresponding values from options unless that value is None.
+ In that case, the corresponding dictionary entry is not populated.
+
+ (This allows different modulations that have the same parameter
+ names, but different default values to coexist. The downside is
+ that --help in the option parser will list the default as None,
+ but in that case the default provided in the __init__ argument
+ list will be used since there is no kwargs entry.)
+
+ @param function: the function whose parameter list will be examined
+ @param excluded_args: function arguments that are NOT to be added to the dictionary
+ @type excluded_args: sequence of strings
+ @param options: result of command argument parsing
+ @type options: optparse.Values
+ """
+ # Try this in C++ ;)
+ args, varargs, varkw, defaults = inspect.getargspec(function)
+ d = {}
+ for kw in [a for a in args if a not in excluded_args]:
+ if hasattr(options, kw):
+ if getattr(options, kw) is not None:
+ d[kw] = getattr(options, kw)
+ return d
diff --git a/gnuradio-core/src/python/gnuradio/packet_utils.py b/gnuradio-core/src/python/gnuradio/packet_utils.py
index 1417c17fa..e36b05413 100644
--- a/gnuradio-core/src/python/gnuradio/packet_utils.py
+++ b/gnuradio-core/src/python/gnuradio/packet_utils.py
@@ -143,7 +143,7 @@ def make_packet(payload, samples_per_symbol, bits_per_symbol,
(payload_with_crc), '\x55'))
if pad_for_usrp:
- pkt = pkt + (_npadding_bytes(len(pkt), samples_per_symbol, bits_per_symbol) * '\x55')
+ pkt = pkt + (_npadding_bytes(len(pkt), int(samples_per_symbol), bits_per_symbol) * '\x55')
#print "make_packet: len(pkt) =", len(pkt)
return pkt