diff options
58 files changed, 2510 insertions, 897 deletions
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_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..70857173b 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 * @@ -119,6 +119,8 @@ public: 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..10eec4f54 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 * @@ -118,7 +118,9 @@ public: { 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/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..178e18f3e 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,8 +45,12 @@ 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 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/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 diff --git a/gnuradio-examples/grc/demod/digital_freq_lock.grc b/gnuradio-examples/grc/demod/digital_freq_lock.grc index 37ee8123e..36037febb 100644 --- a/gnuradio-examples/grc/demod/digital_freq_lock.grc +++ b/gnuradio-examples/grc/demod/digital_freq_lock.grc @@ -1,6 +1,6 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Fri Jan 29 18:10:00 2010</timestamp> + <timestamp>Sat Mar 6 17:17:12 2010</timestamp> <block> <key>options</key> <param> @@ -980,54 +980,50 @@ </param> </block> <block> - <key>variable_slider</key> + <key>root_raised_cosine_filter</key> <param> <key>id</key> - <value>alpha</value> + <value>root_raised_cosine_filter_0</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>label</key> - <value>Freq Alpha</value> - </param> - <param> - <key>value</key> - <value>0</value> + <key>type</key> + <value>interp_fir_filter_ccf</value> </param> <param> - <key>min</key> - <value>0</value> + <key>decim</key> + <value>1</value> </param> <param> - <key>max</key> - <value>0.001</value> + <key>interp</key> + <value>spb_gen</value> </param> <param> - <key>num_steps</key> - <value>1000</value> + <key>gain</key> + <value>2*spb_gen</value> </param> <param> - <key>style</key> - <value>wx.SL_HORIZONTAL</value> + <key>samp_rate</key> + <value>1.0</value> </param> <param> - <key>converver</key> - <value>float_converter</value> + <key>sym_rate</key> + <value>1./spb_gen</value> </param> <param> - <key>grid_pos</key> - <value></value> + <key>alpha</key> + <value>rolloff</value> </param> <param> - <key>notebook</key> - <value></value> + <key>ntaps</key> + <value>44</value> </param> <param> <key>_coordinate</key> - <value>(552, 4)</value> + <value>(978, 157)</value> </param> <param> <key>_rotation</key> @@ -1035,105 +1031,81 @@ </param> </block> <block> - <key>variable_slider</key> + <key>gr_fll_band_edge_cc</key> <param> <key>id</key> - <value>beta</value> + <value>gr_fll_band_edge_cc_0</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>label</key> - <value>Freq Beta</value> - </param> - <param> - <key>value</key> - <value>0</value> - </param> - <param> - <key>min</key> - <value>0.0</value> - </param> - <param> - <key>max</key> - <value>0.0001</value> + <key>type</key> + <value>cc</value> </param> <param> - <key>num_steps</key> - <value>1000</value> + <key>samps_per_sym</key> + <value>spb_gen</value> </param> <param> - <key>style</key> - <value>wx.SL_HORIZONTAL</value> + <key>rolloff</key> + <value>rolloff</value> </param> <param> - <key>converver</key> - <value>float_converter</value> + <key>filter_size</key> + <value>44</value> </param> <param> - <key>grid_pos</key> - <value></value> + <key>alpha</key> + <value>alpha</value> </param> <param> - <key>notebook</key> - <value></value> + <key>beta</key> + <value>beta</value> </param> <param> <key>_coordinate</key> - <value>(668, 5)</value> + <value>(874, 664)</value> </param> <param> <key>_rotation</key> - <value>180</value> + <value>0</value> </param> </block> <block> - <key>root_raised_cosine_filter</key> + <key>gr_channel_model</key> <param> <key>id</key> - <value>root_raised_cosine_filter_0</value> + <value>gr_channel_model_0</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>interp_fir_filter_ccf</value> - </param> - <param> - <key>decim</key> - <value>1</value> - </param> - <param> - <key>interp</key> - <value>spb_gen</value> + <key>noise_voltage</key> + <value>noise_amp</value> </param> <param> - <key>gain</key> - <value>2*spb_gen</value> + <key>freq_offset</key> + <value>freq_offset</value> </param> <param> - <key>samp_rate</key> + <key>epsilon</key> <value>1.0</value> </param> <param> - <key>sym_rate</key> - <value>1./spb_gen</value> - </param> - <param> - <key>alpha</key> - <value>rolloff</value> + <key>taps</key> + <value>1.0</value> </param> <param> - <key>ntaps</key> - <value>44</value> + <key>seed</key> + <value>42</value> </param> <param> <key>_coordinate</key> - <value>(978, 157)</value> + <value>(618, 376)</value> </param> <param> <key>_rotation</key> @@ -1141,81 +1113,109 @@ </param> </block> <block> - <key>gr_fll_band_edge_cc</key> + <key>variable_slider</key> <param> <key>id</key> - <value>gr_fll_band_edge_cc_0</value> + <value>beta</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>type</key> - <value>cc</value> + <key>label</key> + <value>Freq Beta</value> </param> <param> - <key>samps_per_sym</key> - <value>spb_gen</value> + <key>value</key> + <value>0</value> </param> <param> - <key>rolloff</key> - <value>rolloff</value> + <key>min</key> + <value>0.0</value> </param> <param> - <key>filter_size</key> - <value>44</value> + <key>max</key> + <value>0.01</value> </param> <param> - <key>alpha</key> - <value>alpha</value> + <key>num_steps</key> + <value>1000</value> </param> <param> - <key>beta</key> - <value>beta</value> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>notebook</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(874, 664)</value> + <value>(668, 5)</value> </param> <param> <key>_rotation</key> - <value>0</value> + <value>180</value> </param> </block> <block> - <key>gr_channel_model</key> + <key>variable_slider</key> <param> <key>id</key> - <value>gr_channel_model_0</value> + <value>alpha</value> </param> <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>noise_voltage</key> - <value>noise_amp</value> + <key>label</key> + <value>Freq Alpha</value> </param> <param> - <key>freq_offset</key> - <value>freq_offset</value> + <key>value</key> + <value>0</value> </param> <param> - <key>epsilon</key> - <value>1.0</value> + <key>min</key> + <value>0</value> </param> <param> - <key>taps</key> - <value>1.0</value> + <key>max</key> + <value>0.1</value> </param> <param> - <key>seed</key> - <value>42</value> + <key>num_steps</key> + <value>1000</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>notebook</key> + <value></value> </param> <param> <key>_coordinate</key> - <value>(618, 376)</value> + <value>(552, 4)</value> </param> <param> <key>_rotation</key> diff --git a/gnuradio-examples/grc/demod/pam_sync.grc b/gnuradio-examples/grc/demod/pam_sync.grc index 80a7aef0c..8571995a5 100644 --- a/gnuradio-examples/grc/demod/pam_sync.grc +++ b/gnuradio-examples/grc/demod/pam_sync.grc @@ -1,6 +1,6 @@ <?xml version='1.0' encoding='ASCII'?> <flow_graph> - <timestamp>Mon Feb 1 18:58:32 2010</timestamp> + <timestamp>Sat Mar 6 17:17:22 2010</timestamp> <block> <key>options</key> <param> @@ -713,116 +713,6 @@ <key>variable_slider</key> <param> <key>id</key> - <value>freq_beta</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>label</key> - <value>Freq Beta</value> - </param> - <param> - <key>value</key> - <value>0</value> - </param> - <param> - <key>min</key> - <value>0.0</value> - </param> - <param> - <key>max</key> - <value>0.0001</value> - </param> - <param> - <key>num_steps</key> - <value>1000</value> - </param> - <param> - <key>style</key> - <value>wx.SL_HORIZONTAL</value> - </param> - <param> - <key>converver</key> - <value>float_converter</value> - </param> - <param> - <key>grid_pos</key> - <value></value> - </param> - <param> - <key>notebook</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(836, 9)</value> - </param> - <param> - <key>_rotation</key> - <value>180</value> - </param> - </block> - <block> - <key>variable_slider</key> - <param> - <key>id</key> - <value>freq_alpha</value> - </param> - <param> - <key>_enabled</key> - <value>True</value> - </param> - <param> - <key>label</key> - <value>Freq Alpha</value> - </param> - <param> - <key>value</key> - <value>0</value> - </param> - <param> - <key>min</key> - <value>0</value> - </param> - <param> - <key>max</key> - <value>0.001</value> - </param> - <param> - <key>num_steps</key> - <value>1000</value> - </param> - <param> - <key>style</key> - <value>wx.SL_HORIZONTAL</value> - </param> - <param> - <key>converver</key> - <value>float_converter</value> - </param> - <param> - <key>grid_pos</key> - <value></value> - </param> - <param> - <key>notebook</key> - <value></value> - </param> - <param> - <key>_coordinate</key> - <value>(734, 10)</value> - </param> - <param> - <key>_rotation</key> - <value>0</value> - </param> - </block> - <block> - <key>variable_slider</key> - <param> - <key>id</key> <value>phase_alpha</value> </param> <param> @@ -1621,6 +1511,116 @@ <value>0</value> </param> </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>freq_alpha</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Freq Alpha</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>min</key> + <value>0</value> + </param> + <param> + <key>max</key> + <value>0.1</value> + </param> + <param> + <key>num_steps</key> + <value>1000</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(734, 10)</value> + </param> + <param> + <key>_rotation</key> + <value>0</value> + </param> + </block> + <block> + <key>variable_slider</key> + <param> + <key>id</key> + <value>freq_beta</value> + </param> + <param> + <key>_enabled</key> + <value>True</value> + </param> + <param> + <key>label</key> + <value>Freq Beta</value> + </param> + <param> + <key>value</key> + <value>0</value> + </param> + <param> + <key>min</key> + <value>0.0</value> + </param> + <param> + <key>max</key> + <value>0.01</value> + </param> + <param> + <key>num_steps</key> + <value>1000</value> + </param> + <param> + <key>style</key> + <value>wx.SL_HORIZONTAL</value> + </param> + <param> + <key>converver</key> + <value>float_converter</value> + </param> + <param> + <key>grid_pos</key> + <value></value> + </param> + <param> + <key>notebook</key> + <value></value> + </param> + <param> + <key>_coordinate</key> + <value>(836, 9)</value> + </param> + <param> + <key>_rotation</key> + <value>180</value> + </param> + </block> <connection> <source_block_id>random_source_x_0</source_block_id> <sink_block_id>gr_uchar_to_float_0</sink_block_id> diff --git a/gnuradio-examples/python/digital/benchmark_loopback.py b/gnuradio-examples/python/digital/benchmark_loopback.py index 4cc4a7bee..47e4f2028 100755 --- a/gnuradio-examples/python/digital/benchmark_loopback.py +++ b/gnuradio-examples/python/digital/benchmark_loopback.py @@ -44,6 +44,11 @@ class my_top_block(gr.top_block): noise_power = power_in_signal/SNR noise_voltage = math.sqrt(noise_power) + # With new interface, sps does not get set by default, but + # in the loopback, we don't recalculate it; so just force it here + if(options.samples_per_symbol == None): + options.samples_per_symbol = 2 + self.txpath = transmit_path(mod_class, options) self.throttle = gr.throttle(gr.sizeof_gr_complex, options.sample_rate) self.rxpath = receive_path(demod_class, rx_callback, options) diff --git a/gnuradio-examples/python/digital/benchmark_qt_loopback2.py b/gnuradio-examples/python/digital/benchmark_qt_loopback2.py index 1cb95198e..56c6c7f52 100755 --- a/gnuradio-examples/python/digital/benchmark_qt_loopback2.py +++ b/gnuradio-examples/python/digital/benchmark_qt_loopback2.py @@ -1,6 +1,26 @@ #!/usr/bin/env python - -from gnuradio import gr, gru, modulation_utils +# +# 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. +# + +from gnuradio import gr, gru, modulation_utils2 from gnuradio import eng_notation from gnuradio.eng_option import eng_option from optparse import OptionParser @@ -223,6 +243,11 @@ class my_top_block(gr.top_block): self._noise_voltage = self.get_noise_voltage(self._snr_dB) + # With new interface, sps does not get set by default, but + # in the loopback, we don't recalculate it; so just force it here + if(options.samples_per_symbol == None): + options.samples_per_symbol = 2 + self.txpath = transmit_path(mod_class, options) self.throttle = gr.throttle(gr.sizeof_gr_complex, self.sample_rate()) self.rxpath = receive_path(demod_class, rx_callback, options) @@ -269,6 +294,7 @@ class my_top_block(gr.top_block): self.phase_recov = self.rxpath.packet_receiver._demodulator.phase_recov self.time_recov = self.rxpath.packet_receiver._demodulator.time_recov self.freq_recov.set_alpha(self._gain_freq) + self.freq_recov.set_beta(self._gain_freq/10.0) self.phase_recov.set_alpha(self._gain_phase) self.phase_recov.set_beta(0.25*self._gain_phase*self._gain_phase) self.time_recov.set_alpha(self._gain_clock) @@ -367,6 +393,7 @@ class my_top_block(gr.top_block): self._gain_freq = gain_freq #self._gain_freq_beta = .25 * self._gain_freq * self._gain_freq self.rxpath.packet_receiver._demodulator.freq_recov.set_alpha(self._gain_freq) + self.rxpath.packet_receiver._demodulator.freq_recov.set_beta(self._gain_freq/10.0) #self.rxpath.packet_receiver._demodulator.freq_recov.set_beta(self._gain_fre_beta) @@ -431,15 +458,15 @@ def main(): def send_pkt(payload='', eof=False): return tb.txpath.send_pkt(payload, eof) - mods = modulation_utils.type_1_mods() - demods = modulation_utils.type_1_demods() + mods = modulation_utils2.type_1_mods() + demods = modulation_utils2.type_1_demods() parser = OptionParser(option_class=eng_option, conflict_handler="resolve") expert_grp = parser.add_option_group("Expert") channel_grp = parser.add_option_group("Channel") parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), - default='dbpsk', + default='dbpsk2', help="Select modulation from: %s [default=%%default]" % (', '.join(mods.keys()),)) diff --git a/gnuradio-examples/python/digital/benchmark_qt_rx2.py b/gnuradio-examples/python/digital/benchmark_qt_rx2.py index cabbecb6f..0c37f4c6a 100755 --- a/gnuradio-examples/python/digital/benchmark_qt_rx2.py +++ b/gnuradio-examples/python/digital/benchmark_qt_rx2.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2005,2006,2007,2009 Free Software Foundation, Inc. +# Copyright 2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,7 +20,7 @@ # Boston, MA 02110-1301, USA. # -from gnuradio import gr, gru, modulation_utils +from gnuradio import gr, gru, modulation_utils2 from gnuradio import usrp from gnuradio import eng_notation from gnuradio.eng_option import eng_option @@ -33,7 +33,7 @@ import sys # from current dir from receive_path import receive_path -from pick_bitrate import pick_rx_bitrate +from pick_bitrate2 import pick_rx_bitrate try: from gnuradio.qtgui import qtgui @@ -219,7 +219,7 @@ class my_top_block(gr.top_block): # FIXME: do better exposure to lower issues for control self._gain_clock = self.rxpath.packet_receiver._demodulator._timing_alpha - self._gain_phase = self.rxpath.packet_receiver._demodulator._costas_alpha + self._gain_phase = self.rxpath.packet_receiver._demodulator._phase_alpha self._gain_freq = self.rxpath.packet_receiver._demodulator._freq_alpha self.connect(self.u, self.rxpath) @@ -242,8 +242,8 @@ class my_top_block(gr.top_block): # Connect to the QT sinks # FIXME: make better exposure to receiver from rxpath - #self.receiver = self.rxpath.packet_receiver._demodulator.phase_recov - self.receiver = self.rxpath.packet_receiver._demodulator.freq_recov + self.receiver = self.rxpath.packet_receiver._demodulator.phase_recov + #self.receiver = self.rxpath.packet_receiver._demodulator.freq_recov self.connect(self.u, self.snk_rxin) self.connect(self.receiver, self.snk_rx) @@ -267,9 +267,9 @@ class my_top_block(gr.top_block): self.u.set_decim(self._decim) (self._bitrate, self._samples_per_symbol, self._decim) = \ - pick_rx_bitrate(self._bitrate, self._demod_class.bits_per_symbol(), \ - self._samples_per_symbol, self._decim, adc_rate, \ - self.u.get_decim_rates()) + pick_rx_bitrate(options.bitrate, self._demod_class.bits_per_symbol(), \ + options.samples_per_symbol, options.decim, \ + adc_rate, self.u.get_decim_rates()) self.u.set_decim(self._decim) self.set_auto_tr(True) # enable Auto Transmit/Receive switching @@ -353,6 +353,7 @@ class my_top_block(gr.top_block): self._gain_freq = gain_freq #self._gain_freq_beta = .25 * self._gain_freq * self._gain_freq self.rxpath.packet_receiver._demodulator.freq_recov.set_alpha(self._gain_freq) + self.rxpath.packet_receiver._demodulator.freq_recov.set_beta(self._gain_freq/10.0) #self.rxpath.packet_receiver._demodulator.freq_recov.set_beta(self._gain_fre_beta) @@ -423,14 +424,14 @@ def main(): ok, pktno, n_rcvd, n_right) - demods = modulation_utils.type_1_demods() + demods = modulation_utils2.type_1_demods() # Create Options Parser: parser = OptionParser (option_class=eng_option, conflict_handler="resolve") expert_grp = parser.add_option_group("Expert") parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), - default='dbpsk', + default='dbpsk2', help="Select modulation from: %s [default=%%default]" % (', '.join(demods.keys()),)) diff --git a/gnuradio-examples/python/digital/benchmark_rx2.py b/gnuradio-examples/python/digital/benchmark_rx2.py new file mode 100755 index 000000000..fe422be83 --- /dev/null +++ b/gnuradio-examples/python/digital/benchmark_rx2.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# +# 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. +# + +from gnuradio import gr, gru, modulation_utils2 +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import struct +import sys + +# from current dir +import usrp_receive_path2 + +#import os +#print os.getpid() +#raw_input('Attach and press enter: ') + +class my_top_block(gr.top_block): + def __init__(self, demodulator, rx_callback, options): + gr.top_block.__init__(self) + + # Set up receive path + self.rxpath = usrp_receive_path2.usrp_receive_path(demodulator, rx_callback, options) + + self.connect(self.rxpath) + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +global n_rcvd, n_right + +def main(): + global n_rcvd, n_right + + n_rcvd = 0 + n_right = 0 + + def rx_callback(ok, payload): + global n_rcvd, n_right + (pktno,) = struct.unpack('!H', payload[0:2]) + n_rcvd += 1 + if ok: + n_right += 1 + + print "ok = %5s pktno = %4d n_rcvd = %4d n_right = %4d" % ( + ok, pktno, n_rcvd, n_right) + + + demods = modulation_utils2.type_1_demods() + + # Create Options Parser: + parser = OptionParser (option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), + default='dbpsk2', + help="Select modulation from: %s [default=%%default]" + % (', '.join(demods.keys()),)) + + usrp_receive_path2.add_options(parser, expert_grp) + + for mod in demods.values(): + mod.add_options(expert_grp) + + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help(sys.stderr) + sys.exit(1) + + if options.rx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + + # build the graph + tb = my_top_block(demods[options.modulation], rx_callback, options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: Failed to enable realtime scheduling." + + tb.start() # start flow graph + tb.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/benchmark_tx2.py b/gnuradio-examples/python/digital/benchmark_tx2.py new file mode 100755 index 000000000..6093dba61 --- /dev/null +++ b/gnuradio-examples/python/digital/benchmark_tx2.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# 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. +# + +from gnuradio import gr, gru, modulation_utils2 +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random, time, struct, sys + +# from current dir +import usrp_transmit_path2 + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + +class my_top_block(gr.top_block): + def __init__(self, modulator, options): + gr.top_block.__init__(self) + + self.txpath = usrp_transmit_path2.usrp_transmit_path(modulator, options) + + self.connect(self.txpath) + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + def send_pkt(payload='', eof=False): + return tb.txpath.send_pkt(payload, eof) + + def rx_callback(ok, payload): + print "ok = %r, payload = '%s'" % (ok, payload) + + mods = modulation_utils2.type_1_mods() + + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), + default='dbpsk2', + help="Select modulation from: %s [default=%%default]" + % (', '.join(mods.keys()),)) + + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, + help="set megabytes to transmit [default=%default]") + parser.add_option("","--discontinuous", action="store_true", default=False, + help="enable discontinous transmission (bursts of 5 packets)") + parser.add_option("","--from-file", default=None, + help="use file for packet contents") + + usrp_transmit_path2.add_options(parser, expert_grp) + + for mod in mods.values(): + mod.add_options(expert_grp) + + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.tx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + if options.from_file is not None: + source_file = open(options.from_file, 'r') + + # build the graph + tb = my_top_block(mods[options.modulation], options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: failed to enable realtime scheduling" + + tb.start() # start flow graph + + # generate and send packets + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + pkt_size = int(options.size) + + while n < nbytes: + if options.from_file is None: + data = (pkt_size - 2) * chr(pktno & 0xff) + else: + data = source_file.read(pkt_size - 2) + if data == '': + break; + + payload = struct.pack('!H', pktno & 0xffff) + data + send_pkt(payload) + n += len(payload) + sys.stderr.write('.') + if options.discontinuous and pktno % 5 == 4: + time.sleep(1) + pktno += 1 + + send_pkt(eof=True) + + tb.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/pick_bitrate2.py b/gnuradio-examples/python/digital/pick_bitrate2.py new file mode 100644 index 000000000..92539560c --- /dev/null +++ b/gnuradio-examples/python/digital/pick_bitrate2.py @@ -0,0 +1,154 @@ +# +# 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. +# + +from gnuradio import eng_notation + +_default_bitrate = 500e3 +_sps_min = 2 +_sps_max = 100 + +def _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + xrate, converter_rate, xrates): + """ + @returns tuple (bitrate, samples_per_symbol, interp_rate_or_decim_rate) + """ + + if not isinstance(bits_per_symbol, int) or bits_per_symbol < 1: + raise ValueError, "bits_per_symbol must be an int >= 1" + + converter_rate = float(converter_rate) + bits_per_symbol = float(bits_per_symbol) + + # completely determined; if bitrate is specified, this overwrites it + if (samples_per_symbol is not None) and (xrate is not None): + bitrate = converter_rate / bits_per_symbol / xrate / samples_per_symbol + + # If only SPS is given + if (bitrate is None) and (samples_per_symbol is not None) and (xrate is None): + xrate = max(xrates) + bitrate = converter_rate / bits_per_symbol / xrate / samples_per_symbol + + # If only xrate is given, just set SPS to 2 and calculate bitrate + if (bitrate is None) and (samples_per_symbol is None) and (xrate is not None): + samples_per_symbol = 2.0 + bitrate = converter_rate / bits_per_symbol / xrate / samples_per_symbol + + # If no parameters are give, use the default bit rate + if (bitrate is None) and (samples_per_symbol is None) and (xrate is None): + bitrate = _default_bitrate + + # If only bitrate is specified, return max xrate and appropriate + # samples per symbol (minimum of 2.0) to reach bit rate + if (samples_per_symbol is None) and (xrate is None): + xrates.sort() + for i in xrange(len(xrates)): + if((converter_rate / bits_per_symbol / xrates[i]) >= 2*bitrate): + rate = xrates[i] + else: + break + + try: + xrate = rate + except UnboundLocalError: + raise ValueError("Requested bitrate out of bounds") + + samples_per_symbol = converter_rate / bits_per_symbol / rate / bitrate + bitrate = converter_rate / bits_per_symbol / xrate / samples_per_symbol + + # If bitrate and xrate are specified + if(samples_per_symbol is None): + samples_per_symbol = converter_rate / xrate / bits_per_symbol / bitrate + + # If bitrate and SPS are specified + if(xrate is None): + xrate = converter_rate / samples_per_symbol / bits_per_symbol / bitrate + if((xrate in xrates) == False): + # Find the closest avaiable rate larger than the calculated one + xrates.sort() + for x in xrates: + if(x > xrate): + xrate = x + break + if(xrate > max(xrates)): + xrate = max(xrates) + + bitrate = converter_rate / bits_per_symbol / xrate / samples_per_symbol + print "Could not find suitable rate for specified SPS and Bitrate" + print "Using rate = %d for bitrate of %sbps" % \ + (xrate, (eng_notation.num_to_str(bitrate))) + + if((xrate in xrates) == False): + raise ValueError(("Invalid rate (rate = %d)" % xrate)) + if((samples_per_symbol < _sps_min) or (samples_per_symbol > _sps_max)): + raise ValueError(("Invalid samples per symbol (sps = %.2f). Must be in [%.0f, %.0f]." \ + % (samples_per_symbol, _sps_min, _sps_max))) + + return (bitrate, samples_per_symbol, int(xrate)) + + +def pick_tx_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + interp_rate, converter_rate, possible_interps): + """ + Given the 4 input parameters, return at configuration that matches + + @param bitrate: desired bitrate or None + @type bitrate: number or None + @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3 + @type bits_per_symbol: integer >= 1 + @param samples_per_symbol: samples/baud (aka samples/symbol) + @type samples_per_symbol: number or None + @param interp_rate: USRP interpolation factor + @type interp_rate: integer or None + @param converter_rate: converter sample rate in Hz + @type converter_rate: number + @param possible_interps: a list of possible rates + @type possible_interps: a list of integers + + @returns tuple (bitrate, samples_per_symbol, interp_rate) + """ + + return _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + interp_rate, converter_rate, possible_interps) + + +def pick_rx_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + decim_rate, converter_rate, possible_decims): + """ + Given the 4 input parameters, return at configuration that matches + + @param bitrate: desired bitrate or None + @type bitrate: number or None + @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3 + @type bits_per_symbol: integer >= 1 + @param samples_per_symbol: samples/baud (aka samples/symbol) + @type samples_per_symbol: number or None + @param decim_rate: USRP decimation factor + @type decim_rate: integer or None + @param converter_rate: converter sample rate in Hz + @type converter_rate: number + @param possible_decims: a list of possible rates + @type possible_decims: a list of integers + + @returns tuple (bitrate, samples_per_symbol, decim_rate) + """ + + return _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + decim_rate, converter_rate, possible_decims) diff --git a/gnuradio-examples/python/digital/receive_path.py b/gnuradio-examples/python/digital/receive_path.py index c229aa9e4..0024d6941 100644 --- a/gnuradio-examples/python/digital/receive_path.py +++ b/gnuradio-examples/python/digital/receive_path.py @@ -119,7 +119,7 @@ class receive_path(gr.hier_block2): normal.add_option("-r", "--bitrate", type="eng_float", default=100e3, help="specify bitrate [default=%default].") normal.add_option("-v", "--verbose", action="store_true", default=False) - expert.add_option("-S", "--samples-per-symbol", type="int", default=2, + expert.add_option("-S", "--samples-per-symbol", type="float", default=None, help="set samples/symbol [default=%default]") expert.add_option("", "--log", action="store_true", default=False, help="Log all parts of flow graph to files (CAUTION: lots of data)") @@ -135,4 +135,4 @@ class receive_path(gr.hier_block2): print "\nReceive Path:" print "modulation: %s" % (self._demod_class.__name__) print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate)) - print "samples/symbol: %3d" % (self._samples_per_symbol) + print "samples/symbol: %.4f" % (self._samples_per_symbol) diff --git a/gnuradio-examples/python/digital/transmit_path.py b/gnuradio-examples/python/digital/transmit_path.py index 9badcdc08..86ebf75c3 100644 --- a/gnuradio-examples/python/digital/transmit_path.py +++ b/gnuradio-examples/python/digital/transmit_path.py @@ -99,7 +99,7 @@ class transmit_path(gr.hier_block2): help="set transmitter digital amplitude: 0 <= AMPL < 1 [default=%default]") normal.add_option("-v", "--verbose", action="store_true", default=False) - expert.add_option("-S", "--samples-per-symbol", type="int", default=2, + expert.add_option("-S", "--samples-per-symbol", type="float", default=None, help="set samples/symbol [default=%default]") expert.add_option("", "--log", action="store_true", default=False, help="Log all parts of flow graph to file (CAUTION: lots of data)") @@ -114,5 +114,5 @@ class transmit_path(gr.hier_block2): print "Tx amplitude %s" % (self._tx_amplitude) print "modulation: %s" % (self._modulator_class.__name__) print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate)) - print "samples/symbol: %3d" % (self._samples_per_symbol) + print "samples/symbol: %.4f" % (self._samples_per_symbol) diff --git a/gnuradio-examples/python/digital/usrp_receive_path.py b/gnuradio-examples/python/digital/usrp_receive_path.py index 517825cc1..a8f16e28a 100644 --- a/gnuradio-examples/python/digital/usrp_receive_path.py +++ b/gnuradio-examples/python/digital/usrp_receive_path.py @@ -59,37 +59,35 @@ class usrp_receive_path(gr.hier_block2): if options.rx_freq is None: sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n") raise SystemExit - rx_path = receive_path.receive_path(demod_class, rx_callback, options) - for attr in dir(rx_path): #forward the methods - if not attr.startswith('_') and not hasattr(self, attr): - setattr(self, attr, getattr(rx_path, attr)) #setup usrp self._demod_class = demod_class self._setup_usrp_source(options) - # Set up resampler based on rate determined by _setup_usrp_source - rs_taps = gr.firdes.low_pass_2(32, 32, 0.45, 0.1, 60) - self.resampler = gr.pfb_arb_resampler_ccf(self.rs_rate, rs_taps) + rx_path = receive_path.receive_path(demod_class, rx_callback, options) + for attr in dir(rx_path): #forward the methods + if not attr.startswith('_') and not hasattr(self, attr): + setattr(self, attr, getattr(rx_path, attr)) #connect - self.connect(self.u, self.resampler, rx_path) + self.connect(self.u, rx_path) def _setup_usrp_source(self, options): self.u = usrp_options.create_usrp_source(options) adc_rate = self.u.adc_rate() self.rs_rate = options.bitrate - if options.verbose: - print 'USRP Source:', self.u + (self._bitrate, self._samples_per_symbol, self._decim) = \ pick_rx_bitrate(options.bitrate, self._demod_class.bits_per_symbol(), \ - options.samples_per_symbol, options.decim, adc_rate, \ - self.u.get_decim_rates()) + options.samples_per_symbol, options.decim, + adc_rate, self.u.get_decim_rates()) - # Calculate resampler rate based on requested and actual rates - self.rs_rate = 1.0 /(self._bitrate / self.rs_rate) - - print "Resampling by %f to get bitrate of %ssps" % ( self.rs_rate, eng_notation.num_to_str(self._bitrate/self.rs_rate)) + if options.verbose: + print 'USRP Source:', self.u + print 'Decimation: ', self._decim + + options.samples_per_symbol = self._samples_per_symbol + options.decim = self._decim self.u.set_decim(self._decim) diff --git a/gnuradio-examples/python/digital/usrp_receive_path2.py b/gnuradio-examples/python/digital/usrp_receive_path2.py new file mode 100644 index 000000000..d20017204 --- /dev/null +++ b/gnuradio-examples/python/digital/usrp_receive_path2.py @@ -0,0 +1,96 @@ +# +# 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. +# + +from gnuradio import gr +from gnuradio import usrp_options +import receive_path +from pick_bitrate2 import pick_rx_bitrate +from gnuradio import eng_notation + +def add_freq_option(parser): + """ + Hackery that has the -f / --freq option set both tx_freq and rx_freq + """ + def freq_callback(option, opt_str, value, parser): + parser.values.rx_freq = value + parser.values.tx_freq = value + + if not parser.has_option('--freq'): + parser.add_option('-f', '--freq', type="eng_float", + action="callback", callback=freq_callback, + help="set Tx and/or Rx frequency to FREQ [default=%default]", + metavar="FREQ") + +def add_options(parser, expert): + add_freq_option(parser) + usrp_options.add_rx_options(parser) + receive_path.receive_path.add_options(parser, expert) + expert.add_option("", "--rx-freq", type="eng_float", default=None, + help="set Rx frequency to FREQ [default=%default]", metavar="FREQ") + parser.add_option("-v", "--verbose", action="store_true", default=False) + +class usrp_receive_path(gr.hier_block2): + + def __init__(self, demod_class, rx_callback, options): + ''' + See below for what options should hold + ''' + gr.hier_block2.__init__(self, "usrp_receive_path", + gr.io_signature(0, 0, 0), # Input signature + gr.io_signature(0, 0, 0)) # Output signature + if options.rx_freq is None: + sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n") + raise SystemExit + + #setup usrp + self._demod_class = demod_class + self._setup_usrp_source(options) + + rx_path = receive_path.receive_path(demod_class, rx_callback, options) + for attr in dir(rx_path): #forward the methods + if not attr.startswith('_') and not hasattr(self, attr): + setattr(self, attr, getattr(rx_path, attr)) + + #connect + self.connect(self.u, rx_path) + + def _setup_usrp_source(self, options): + self.u = usrp_options.create_usrp_source(options) + adc_rate = self.u.adc_rate() + self.rs_rate = options.bitrate + + (self._bitrate, self._samples_per_symbol, self._decim) = \ + pick_rx_bitrate(options.bitrate, self._demod_class.bits_per_symbol(), \ + options.samples_per_symbol, options.decim, + adc_rate, self.u.get_decim_rates()) + + if options.verbose: + print 'USRP Source:', self.u + print 'Decimation: ', self._decim + + options.samples_per_symbol = self._samples_per_symbol + options.decim = self._decim + + self.u.set_decim(self._decim) + + if not self.u.set_center_freq(options.rx_freq): + print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.rx_freq)) + raise ValueError, eng_notation.num_to_str(options.rx_freq) diff --git a/gnuradio-examples/python/digital/usrp_transmit_path.py b/gnuradio-examples/python/digital/usrp_transmit_path.py index ee63dcd2b..f0f467599 100644 --- a/gnuradio-examples/python/digital/usrp_transmit_path.py +++ b/gnuradio-examples/python/digital/usrp_transmit_path.py @@ -58,21 +58,18 @@ class usrp_transmit_path(gr.hier_block2): if options.tx_freq is None: sys.stderr.write("-f FREQ or --freq FREQ or --tx-freq FREQ must be specified\n") raise SystemExit - tx_path = transmit_path.transmit_path(modulator_class, options) - for attr in dir(tx_path): #forward the methods - if not attr.startswith('_') and not hasattr(self, attr): - setattr(self, attr, getattr(tx_path, attr)) #setup usrp self._modulator_class = modulator_class self._setup_usrp_sink(options) - # Set up resampler based on rate determined by _setup_usrp_sink - rs_taps = gr.firdes.low_pass_2(32, 32, 0.45, 0.1, 60) - self.resampler = gr.pfb_arb_resampler_ccf(self.rs_rate, rs_taps) + tx_path = transmit_path.transmit_path(modulator_class, options) + for attr in dir(tx_path): #forward the methods + if not attr.startswith('_') and not hasattr(self, attr): + setattr(self, attr, getattr(tx_path, attr)) #connect - self.connect(tx_path, self.resampler, self.u) + self.connect(tx_path, self.u) def _setup_usrp_sink(self, options): """ @@ -82,17 +79,20 @@ class usrp_transmit_path(gr.hier_block2): self.u = usrp_options.create_usrp_sink(options) dac_rate = self.u.dac_rate() self.rs_rate = options.bitrate # Store requested bit rate - if options.verbose: - print 'USRP Sink:', self.u + (self._bitrate, self._samples_per_symbol, self._interp) = \ - pick_tx_bitrate(options.bitrate, self._modulator_class.bits_per_symbol(), \ - options.samples_per_symbol, options.interp, dac_rate, \ - self.u.get_interp_rates()) + pick_tx_bitrate(options.bitrate, self._modulator_class.bits_per_symbol(), + options.samples_per_symbol, options.interp, + dac_rate, self.u.get_interp_rates()) - # Calculate resampler rate based on requested and actual rates - self.rs_rate = self._bitrate / self.rs_rate - print "Resampling by %f to get bitrate of %ssps" % (self.rs_rate, eng_notation.num_to_str(self._bitrate/self.rs_rate)) + options.interp = self._interp + options.samples_per_symbol = self._samples_per_symbol + options.bitrate = self._bitrate + if options.verbose: + print 'USRP Sink:', self.u + print "Interpolation Rate: ", self._interp + self.u.set_interp(self._interp) self.u.set_auto_tr(True) diff --git a/gnuradio-examples/python/digital/usrp_transmit_path2.py b/gnuradio-examples/python/digital/usrp_transmit_path2.py new file mode 100644 index 000000000..54930e5a0 --- /dev/null +++ b/gnuradio-examples/python/digital/usrp_transmit_path2.py @@ -0,0 +1,101 @@ +# +# 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. +# + +from gnuradio import gr +from gnuradio import usrp_options +import transmit_path +from pick_bitrate2 import pick_tx_bitrate +from gnuradio import eng_notation + +def add_freq_option(parser): + """ + Hackery that has the -f / --freq option set both tx_freq and rx_freq + """ + def freq_callback(option, opt_str, value, parser): + parser.values.rx_freq = value + parser.values.tx_freq = value + + if not parser.has_option('--freq'): + parser.add_option('-f', '--freq', type="eng_float", + action="callback", callback=freq_callback, + help="set Tx and/or Rx frequency to FREQ [default=%default]", + metavar="FREQ") + +def add_options(parser, expert): + add_freq_option(parser) + usrp_options.add_tx_options(parser) + transmit_path.transmit_path.add_options(parser, expert) + expert.add_option("", "--tx-freq", type="eng_float", default=None, + help="set transmit frequency to FREQ [default=%default]", metavar="FREQ") + parser.add_option("-v", "--verbose", action="store_true", default=False) + +class usrp_transmit_path(gr.hier_block2): + def __init__(self, modulator_class, options): + ''' + See below for what options should hold + ''' + gr.hier_block2.__init__(self, "usrp_transmit_path", + gr.io_signature(0, 0, 0), # Input signature + gr.io_signature(0, 0, 0)) # Output signature + if options.tx_freq is None: + sys.stderr.write("-f FREQ or --freq FREQ or --tx-freq FREQ must be specified\n") + raise SystemExit + + #setup usrp + self._modulator_class = modulator_class + self._setup_usrp_sink(options) + + tx_path = transmit_path.transmit_path(modulator_class, options) + for attr in dir(tx_path): #forward the methods + if not attr.startswith('_') and not hasattr(self, attr): + setattr(self, attr, getattr(tx_path, attr)) + + #connect + self.connect(tx_path, self.u) + + def _setup_usrp_sink(self, options): + """ + Creates a USRP sink, determines the settings for best bitrate, + and attaches to the transmitter's subdevice. + """ + self.u = usrp_options.create_usrp_sink(options) + dac_rate = self.u.dac_rate() + self.rs_rate = options.bitrate # Store requested bit rate + + (self._bitrate, self._samples_per_symbol, self._interp) = \ + pick_tx_bitrate(options.bitrate, self._modulator_class.bits_per_symbol(), + options.samples_per_symbol, options.interp, + dac_rate, self.u.get_interp_rates()) + + options.interp = self._interp + options.samples_per_symbol = self._samples_per_symbol + options.bitrate = self._bitrate + + if options.verbose: + print 'USRP Sink:', self.u + print "Interpolation Rate: ", self._interp + + self.u.set_interp(self._interp) + self.u.set_auto_tr(True) + + if not self.u.set_center_freq(options.tx_freq): + print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.tx_freq)) + raise ValueError, eng_notation.num_to_str(options.tx_freq) diff --git a/gr-gpio/src/python/gpio.py b/gr-gpio/src/python/gpio.py index 2ef495589..a315e166b 100644 --- a/gr-gpio/src/python/gpio.py +++ b/gr-gpio/src/python/gpio.py @@ -1,3 +1 @@ -from gpio_swig import * - fpga_filename = 'std_2rxint_2tx_dig.rbf' diff --git a/gr-howto-write-a-block/Makefile.common b/gr-howto-write-a-block/Makefile.common index c81bc780d..e628d6b16 100644 --- a/gr-howto-write-a-block/Makefile.common +++ b/gr-howto-write-a-block/Makefile.common @@ -1,6 +1,6 @@ # -*- Makefile -*- # -# Copyright 2004,2006,2009 Free Software Foundation, Inc. +# Copyright 2004,2006,2009,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -20,6 +20,9 @@ # Boston, MA 02110-1301, USA. # +# The name of this "out-of-tree" module +modname = howto + # these flags are used when compiling non-SWIG-wrapper files # when going in to non-SWIG libraries AM_CXXFLAGS = @autoconf_default_CXXFLAGS@ @@ -34,21 +37,22 @@ AM_CPPFLAGS = \ # these are used by both SWIG and CXX STD_DEFINES_AND_INCLUDES = \ $(DEFINES) \ + -I$(abs_top_srcdir)/include \ -I$(GNURADIO_CORE_INCLUDEDIR) \ -I$(GNURADIO_CORE_INCLUDEDIR)/swig # includes -grincludedir = $(includedir)/gnuradio +modincludedir = $(includedir)/$(modname) # swig includes -swigincludedir = $(grincludedir)/swig +swigincludedir = $(modincludedir)/swig # Install this stuff in the appropriate subdirectory # This usually ends up at: -# ${prefix}/lib/python${python_version}/site-packages/gnuradio +# ${prefix}/lib/python${python_version}/site-packages/$(modname) -grpythondir = $(pythondir)/gnuradio -grpyexecdir = $(pyexecdir)/gnuradio +modpythondir = $(pythondir)/$(modname) +modpyexecdir = $(pyexecdir)/$(modname) # Data directory for grc block wrappers grc_blocksdir = $(prefix)/share/gnuradio/grc/blocks diff --git a/gr-howto-write-a-block/Makefile.swig.gen.t b/gr-howto-write-a-block/Makefile.swig.gen.t index c15a81721..686117f83 100644 --- a/gr-howto-write-a-block/Makefile.swig.gen.t +++ b/gr-howto-write-a-block/Makefile.swig.gen.t @@ -25,18 +25,16 @@ ## Default install locations for these files: ## ## Default location for the Python directory is: -## ${prefix}/lib/python${python_version}/site-packages/[category]/@NAME@ +## ${prefix}/lib/python${python_version}/site-packages/@NAME@ ## Default location for the Python exec directory is: -## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/@NAME@ +## ${exec_prefix}/lib/python${python_version}/site-packages/@NAME@ ## ## The following can be overloaded to change the install location, but ## this has to be done in the including Makefile.am -before- ## Makefile.swig is included. -@NAME@_pythondir_category ?= gnuradio/@NAME@ -@NAME@_pylibdir_category ?= $(@NAME@_pythondir_category) -@NAME@_pythondir = $(pythondir)/$(@NAME@_pythondir_category) -@NAME@_pylibdir = $(pyexecdir)/$(@NAME@_pylibdir_category) +@NAME@_pythondir = $(pythondir)/@NAME@ +@NAME@_pylibdir = $(pyexecdir)/@NAME@ ## SWIG headers are always installed into the same directory. @@ -72,7 +70,7 @@ MOSTLYCLEANFILES += $(DEPDIR)/*.S* ## .h file is sometimes built, but not always ... so that one has to ## be added manually by the including Makefile.am . -swig_built_sources += @NAME@.py @NAME@.cc +swig_built_sources += @NAME@_swig.py @NAME@_swig.cc ## Various SWIG variables. These can be overloaded in the including ## Makefile.am by setting the variable value there, then including @@ -83,31 +81,31 @@ swig_built_sources += @NAME@.py @NAME@.cc $(@NAME@_swiginclude_headers) @NAME@_pylib_LTLIBRARIES = \ - _@NAME@.la + _@NAME@_swig.la -_@NAME@_la_SOURCES = \ - @NAME@.cc \ +_@NAME@_swig_la_SOURCES = \ + @NAME@_swig.cc \ $(@NAME@_la_swig_sources) -_@NAME@_la_LIBADD = \ +_@NAME@_swig_la_LIBADD = \ $(STD_SWIG_LA_LIB_ADD) \ $(@NAME@_la_swig_libadd) -_@NAME@_la_LDFLAGS = \ +_@NAME@_swig_la_LDFLAGS = \ $(STD_SWIG_LA_LD_FLAGS) \ $(@NAME@_la_swig_ldflags) -_@NAME@_la_CXXFLAGS = \ +_@NAME@_swig_la_CXXFLAGS = \ $(STD_SWIG_CXX_FLAGS) \ $(@NAME@_la_swig_cxxflags) @NAME@_python_PYTHON = \ - @NAME@.py \ + @NAME@_swig.py \ $(@NAME@_python) ## Entry rule for running SWIG -@NAME@.h @NAME@.py @NAME@.cc: @NAME@.i +@NAME@.h @NAME@_swig.py @NAME@_swig.cc: @NAME@.i ## This rule will get called only when MAKE decides that one of the ## targets needs to be created or re-created, because: ## @@ -202,7 +200,7 @@ $(DEPDIR)/@NAME@-generate-stamp: ## if $(SWIG) $(STD_SWIG_PYTHON_ARGS) $(@NAME@_swig_args) \ -MD -MF $(DEPDIR)/@NAME@.Std \ - -module @NAME@ -o @NAME@.cc $(WHAT); then \ + -module @NAME@_swig -o @NAME@_swig.cc $(WHAT); then \ if test $(host_os) = mingw32; then \ $(RM) $(DEPDIR)/@NAME@.Sd; \ $(SED) 's,\\\\,/,g' < $(DEPDIR)/@NAME@.Std \ diff --git a/gr-howto-write-a-block/apps/howto_square.py b/gr-howto-write-a-block/apps/howto_square.py index 8d3d870d8..f14e28325 100755 --- a/gr-howto-write-a-block/apps/howto_square.py +++ b/gr-howto-write-a-block/apps/howto_square.py @@ -5,9 +5,9 @@ # Generated: Thu Nov 12 11:26:07 2009 ################################################## +import howto from gnuradio import eng_notation from gnuradio import gr -from gnuradio import howto from gnuradio.eng_option import eng_option from gnuradio.gr import firdes from gnuradio.wxgui import scopesink2 diff --git a/gr-howto-write-a-block/grc/howto_square2_ff.xml b/gr-howto-write-a-block/grc/howto_square2_ff.xml index 2b46106e8..c58ef0047 100644 --- a/gr-howto-write-a-block/grc/howto_square2_ff.xml +++ b/gr-howto-write-a-block/grc/howto_square2_ff.xml @@ -3,7 +3,7 @@ <name>Square2</name> <key>howto_square2_ff</key> <category>HOWTO</category> - <import>from gnuradio import howto</import> + <import>import howto</import> <make>howto.square2_ff()</make> <sink> diff --git a/gr-howto-write-a-block/grc/howto_square_ff.xml b/gr-howto-write-a-block/grc/howto_square_ff.xml index ed318bfc6..34a0b0a3f 100644 --- a/gr-howto-write-a-block/grc/howto_square_ff.xml +++ b/gr-howto-write-a-block/grc/howto_square_ff.xml @@ -3,7 +3,7 @@ <name>Square</name> <key>howto_square_ff</key> <category>HOWTO</category> - <import>from gnuradio import howto</import> + <import>import howto</import> <make>howto.square_ff()</make> <sink> diff --git a/gr-howto-write-a-block/lib/Makefile.am b/gr-howto-write-a-block/lib/Makefile.am index 336cb8a20..2e76ee453 100644 --- a/gr-howto-write-a-block/lib/Makefile.am +++ b/gr-howto-write-a-block/lib/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2004,2005,2006,2008,2009 Free Software Foundation, Inc. +# Copyright 2004,2005,2006,2008,2009,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -28,21 +28,21 @@ TESTS = test_all # howto C++ library: libgnuradio-howto.so # ---------------------------------------------------------------- -# C/C++ headers get installed in ${prefix}/include/gnuradio -grinclude_HEADERS = \ - howto_square_ff.h \ +# C/C++ headers get installed in ${prefix}/include/$(modname) +modinclude_HEADERS = \ + howto_square_ff.h \ howto_square2_ff.h lib_LTLIBRARIES = libgnuradio-howto.la -libgnuradio_howto_la_SOURCES = \ - howto_square_ff.cc \ +libgnuradio_howto_la_SOURCES = \ + howto_square_ff.cc \ howto_square2_ff.cc -libgnuradio_howto_la_LIBADD = \ +libgnuradio_howto_la_LIBADD = \ $(GNURADIO_CORE_LA) -libgnuradio_howto_la_LDFLAGS = \ +libgnuradio_howto_la_LDFLAGS = \ $(NO_UNDEFINED) # ---------------------------------------------------------------- @@ -51,23 +51,23 @@ libgnuradio_howto_la_LDFLAGS = \ noinst_LTLIBRARIES = libgnuradio-howto-qa.la -libgnuradio_howto_qa_la_SOURCES = \ - qa_howto.cc \ - qa_howto_square_ff.cc \ +libgnuradio_howto_qa_la_SOURCES = \ + qa_howto.cc \ + qa_howto_square_ff.cc \ qa_howto_square2_ff.cc libgnuradio_howto_qa_la_LDFLAGS = $(NO_UNDEFINED) -version-info 0:0:0 -libgnuradio_howto_qa_la_LIBADD = \ - libgnuradio-howto.la \ +libgnuradio_howto_qa_la_LIBADD = \ + libgnuradio-howto.la \ $(CPPUNIT_LIBS) # ---------------------------------------------------------------- # headers that don't get installed # ---------------------------------------------------------------- -noinst_HEADERS = \ - qa_howto.h \ - qa_howto_square_ff.h \ +noinst_HEADERS = \ + qa_howto.h \ + qa_howto_square_ff.h \ qa_howto_square2_ff.h # ---------------------------------------------------------------- diff --git a/gr-howto-write-a-block/python/Makefile.am b/gr-howto-write-a-block/python/Makefile.am index 4ef5fc964..ae36ea665 100644 --- a/gr-howto-write-a-block/python/Makefile.am +++ b/gr-howto-write-a-block/python/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2004 Free Software Foundation, Inc. +# Copyright 2004,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -21,12 +21,10 @@ include $(top_srcdir)/Makefile.common -ourpythondir = $(grpythondir)/howto - EXTRA_DIST = run_tests.in TESTS = run_tests -ourpython_PYTHON = \ +modpython_PYTHON = \ __init__.py noinst_PYTHON = \ diff --git a/gr-howto-write-a-block/swig/Makefile.am b/gr-howto-write-a-block/swig/Makefile.am index fc40109d0..4737ad619 100644 --- a/gr-howto-write-a-block/swig/Makefile.am +++ b/gr-howto-write-a-block/swig/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2004,2005,2006,2008,2009 Free Software Foundation, Inc. +# Copyright 2004,2005,2006,2008,2009,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -27,14 +27,13 @@ if PYTHON ################################### # SWIG Python interface and library -TOP_SWIG_IFILES = \ +TOP_SWIG_IFILES = \ howto.i # Install so that they end up available as: -# import gnuradio.howto +# import howto # This ends up at: -# ${prefix}/lib/python${python_version}/site-packages/gnuradio -howto_pythondir_category = gnuradio/howto +# ${prefix}/lib/python${python_version}/site-packages/$(modname) howto_la_swig_libadd = \ $(top_builddir)/lib/libgnuradio-howto.la @@ -48,7 +47,7 @@ BUILT_SOURCES = $(swig_built_sources) no_dist_files = $(swig_built_sources) # additional SWIG files to be installed -howto_swiginclude_headers = \ +howto_swiginclude_headers = \ howto_square_ff.i \ howto_square2_ff.i diff --git a/gr-howto-write-a-block/swig/Makefile.swig.gen b/gr-howto-write-a-block/swig/Makefile.swig.gen index c62e5aa3e..6c6e66290 100644 --- a/gr-howto-write-a-block/swig/Makefile.swig.gen +++ b/gr-howto-write-a-block/swig/Makefile.swig.gen @@ -25,18 +25,16 @@ ## Default install locations for these files: ## ## Default location for the Python directory is: -## ${prefix}/lib/python${python_version}/site-packages/[category]/howto +## ${prefix}/lib/python${python_version}/site-packages/howto ## Default location for the Python exec directory is: -## ${exec_prefix}/lib/python${python_version}/site-packages/[category]/howto +## ${exec_prefix}/lib/python${python_version}/site-packages/howto ## ## The following can be overloaded to change the install location, but ## this has to be done in the including Makefile.am -before- ## Makefile.swig is included. -howto_pythondir_category ?= gnuradio/howto -howto_pylibdir_category ?= $(howto_pythondir_category) -howto_pythondir = $(pythondir)/$(howto_pythondir_category) -howto_pylibdir = $(pyexecdir)/$(howto_pylibdir_category) +howto_pythondir = $(pythondir)/howto +howto_pylibdir = $(pyexecdir)/howto ## SWIG headers are always installed into the same directory. @@ -79,7 +77,7 @@ swig_built_sources += howto_swig.py howto_swig.cc ## Makefile.swig . howto_swiginclude_HEADERS = \ - howto.i \ + howto.i \ $(howto_swiginclude_headers) howto_pylib_LTLIBRARIES = \ @@ -89,7 +87,7 @@ _howto_swig_la_SOURCES = \ howto_swig.cc \ $(howto_la_swig_sources) -_howto_swig_la_LIBADD = \ +_howto_swig_la_LIBADD = \ $(STD_SWIG_LA_LIB_ADD) \ $(howto_la_swig_libadd) diff --git a/gr-utils/src/python/Makefile.am b/gr-utils/src/python/Makefile.am index fb21e4f44..9c4e222c8 100644 --- a/gr-utils/src/python/Makefile.am +++ b/gr-utils/src/python/Makefile.am @@ -35,6 +35,7 @@ ourpython_PYTHON = \ pyqt_filter.py bin_SCRIPTS = \ + create-gnuradio-out-of-tree-project \ gr_plot_char.py \ gr_plot_const.py \ gr_plot_fft.py \ diff --git a/gr-utils/src/python/create-gnuradio-out-of-tree-project b/gr-utils/src/python/create-gnuradio-out-of-tree-project new file mode 100755 index 000000000..1f512b219 --- /dev/null +++ b/gr-utils/src/python/create-gnuradio-out-of-tree-project @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +from optparse import OptionParser +import os +import re +import sys +import subprocess + +tarball_url="http://gnuradio.org/releases/gnuradio/gr-howto-write-a-block-3.3git-651-g642252d8.tar.gz" + +def open_tarball(tarball_name=None): + """Return a readable fileobject that references the tarball. + If tarball_name is None, download from the net + """ + if tarball_name: + return open(tarball_name, 'r') + p = subprocess.Popen(["wget", "-O", "-", tarball_url], + close_fds=True, stdout=subprocess.PIPE) + return p.stdout + +def extract_and_rename_files(tarball, module_name): + # Requires GNU tar. + tar_cmd = 'tar xz --strip-components=1 --transform="s/howto/%s/g"' % (module_name,) + p = subprocess.Popen(tar_cmd, shell=True, stdin=tarball, close_fds=True) + sts = os.waitpid(p.pid, 0) + return sts == 0 + +def main(): + usage = "%prog: [options] new_module_name" + description="Create a prototype 'out of tree' GNU Radio project" + parser = OptionParser(usage=usage, description=description) + parser.add_option("-T", "--tarball", type="string", default=None, + help="path to gr-howto-build-a-block gzipped tarball [default=<get from web>]") + (options, args) = parser.parse_args() + if len(args) != 1: + parser.print_help() + raise SystemExit,2 + module_name = args[0] + if not re.match(r'[_a-z][_a-z0-9]*$', module_name): + sys.stderr.write("module_name '%s' may only contain [a-z0-9_]\n" % (module_name)) + raise SystemExit, 1 + + # Ensure there's no file or directory called <module_name> + if os.path.exists(module_name): + sys.stderr.write("A file or directory named '%s' already exists\n" % (module_name,)) + raise SystemExit, 1 + + os.mkdir(module_name) + os.chdir(module_name) + + ok = extract_and_rename_files(open_tarball(options.tarball), module_name) + + # rename file contents + upper_module_name = module_name.upper() + sed_cmd = 'sed -i -e "s/howto/%s/g" -e "s/HOWTO/%s/g"' % (module_name, + upper_module_name) + os.system('find . -type f -print0 | xargs -0 ' + sed_cmd) + + sys.stdout.write(""" +Project '%s' is now ready to build. + + $ ./bootstrap + $ ./configure --prefix=/home/[user]/install + $ (make && make check && make install) 2>&1 | tee make.log + +""" % (module_name,)) + +if __name__ == '__main__': + main() diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index b70468ed0..790df7c3f 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -82,19 +82,21 @@ class DrawingArea(gtk.DrawingArea): Forward button click information to the flow graph. """ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK - self._flow_graph.handle_mouse_button_press( - left_click=(event.button == 1), + if event.button == 1: self._flow_graph.handle_mouse_selector_press( double_click=(event.type == gtk.gdk._2BUTTON_PRESS), coordinate=(event.x, event.y), ) + if event.button == 3: self._flow_graph.handle_mouse_context_press( + coordinate=(event.x, event.y), + event=event, + ) def _handle_mouse_button_release(self, widget, event): """ Forward button release information to the flow graph. """ self.ctrl_mask = event.state & gtk.gdk.CONTROL_MASK - self._flow_graph.handle_mouse_button_release( - left_click=(event.button == 1), + if event.button == 1: self._flow_graph.handle_mouse_selector_release( coordinate=(event.x, event.y), ) diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 5adecccc1..897145a1d 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -51,6 +51,19 @@ class FlowGraph(Element): #selected ports self._old_selected_port = None self._new_selected_port = None + #context menu + self._context_menu = gtk.Menu() + for action in [ + Actions.BLOCK_CUT, + Actions.BLOCK_COPY, + Actions.BLOCK_PASTE, + Actions.ELEMENT_DELETE, + Actions.BLOCK_ROTATE_CCW, + Actions.BLOCK_ROTATE_CW, + Actions.BLOCK_ENABLE, + Actions.BLOCK_DISABLE, + Actions.BLOCK_PARAM_MODIFY, + ]: self._context_menu.append(action.create_menu_item()) ########################################################################### # Access Drawing Area @@ -425,14 +438,27 @@ class FlowGraph(Element): ########################################################################## ## Event Handlers ########################################################################## - def handle_mouse_button_press(self, left_click, double_click, coordinate): + def handle_mouse_context_press(self, coordinate, event): """ - A mouse button is pressed, only respond to left clicks. + The context mouse button was pressed: + If no elements were selected, perform re-selection at this coordinate. + Then, show the context menu at the mouse click location. + """ + selections = self.what_is_selected(coordinate) + if not set(selections).intersection(self.get_selected_elements()): + self.set_coordinate(coordinate) + self.mouse_pressed = True + self.update_selected_elements() + self.mouse_pressed = False + self._context_menu.popup(None, None, None, event.button, event.time) + + def handle_mouse_selector_press(self, double_click, coordinate): + """ + The selector mouse button was pressed: Find the selected element. Attempt a new connection if possible. Open the block params window on a double click. Update the selection state of the flow graph. """ - if not left_click: return self.press_coor = coordinate self.set_coordinate(coordinate) self.time = 0 @@ -444,11 +470,12 @@ class FlowGraph(Element): self.mouse_pressed = False Actions.BLOCK_PARAM_MODIFY() - def handle_mouse_button_release(self, left_click, coordinate): + def handle_mouse_selector_release(self, coordinate): """ - A mouse button is released, record the state. + The selector mouse button was released: + Update the state, handle motion (dragging). + And update the selected flowgraph elements. """ - if not left_click: return self.set_coordinate(coordinate) self.time = 0 self.mouse_pressed = False diff --git a/gruel/src/include/gruel/pmt.h b/gruel/src/include/gruel/pmt.h index 3188aad1d..c371b023b 100644 --- a/gruel/src/include/gruel/pmt.h +++ b/gruel/src/include/gruel/pmt.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2009 Free Software Foundation, Inc. + * Copyright 2006,2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -465,23 +465,30 @@ std::complex<double> *pmt_c64vector_writable_elements(pmt_t v, size_t &len); //< /* * ------------------------------------------------------------------------ * Dictionary (a.k.a associative array, hash, map) + * + * This is a functional data structure that is persistent. Updating a + * functional data structure does not destroy the existing version, but + * rather creates a new version that coexists with the old. * ------------------------------------------------------------------------ */ //! Return true if \p obj is a dictionary -bool pmt_is_dict(pmt_t obj); +bool pmt_is_dict(const pmt_t &obj); -//! make an empty dictionary +//! Make an empty dictionary pmt_t pmt_make_dict(); -//! dict[key] = value -void pmt_dict_set(pmt_t dict, pmt_t key, pmt_t value); +//! Return a new dictionary with \p key associated with \p value. +pmt_t pmt_dict_add(const pmt_t &dict, const pmt_t &key, const pmt_t &value); + +//! Return a new dictionary with \p key removed. +pmt_t pmt_dict_delete(const pmt_t &dict, const pmt_t &key); //! Return true if \p key exists in \p dict -bool pmt_dict_has_key(pmt_t dict, pmt_t key); +bool pmt_dict_has_key(const pmt_t &dict, const pmt_t &key); //! If \p key exists in \p dict, return associated value; otherwise return \p not_found. -pmt_t pmt_dict_ref(pmt_t dict, pmt_t key, pmt_t not_found); +pmt_t pmt_dict_ref(const pmt_t &dict, const pmt_t &key, const pmt_t ¬_found); //! Return list of (key . value) pairs pmt_t pmt_dict_items(pmt_t dict); diff --git a/gruel/src/lib/pmt/pmt.cc b/gruel/src/lib/pmt/pmt.cc index e50e21838..aa1688d24 100644 --- a/gruel/src/lib/pmt/pmt.cc +++ b/gruel/src/lib/pmt/pmt.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2009 Free Software Foundation, Inc. + * Copyright 2006,2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -141,12 +141,6 @@ _uniform_vector(pmt_t x) return dynamic_cast<pmt_uniform_vector*>(x.get()); } -static pmt_dict * -_dict(pmt_t x) -{ - return dynamic_cast<pmt_dict*>(x.get()); -} - static pmt_any * _any(pmt_t x) { @@ -728,124 +722,91 @@ pmt_uniform_vector_writable_elements(pmt_t vector, size_t &len) // Dictionaries //////////////////////////////////////////////////////////////////////////// -pmt_dict::pmt_dict() - : d_alist(PMT_NIL) -{ -} - -void -pmt_dict::set(pmt_t key, pmt_t value) -{ - pmt_t p = pmt_assv(key, d_alist); // look for (key . value) pair - if (pmt_is_pair(p)){ // found existing pair... - pmt_set_cdr(p, value); // overrwrite cdr with new value - } - else { // not in the dict - d_alist = pmt_cons(pmt_cons(key, value), d_alist); // add new (key . value) pair - } -} - -pmt_t -pmt_dict::ref(pmt_t key, pmt_t not_found) const -{ - pmt_t p = pmt_assv(key, d_alist); // look for (key . value) pair - if (pmt_is_pair(p)) - return pmt_cdr(p); - else - return not_found; -} +/* + * This is an a-list implementation. + * + * When we need better performance for large dictionaries, consider implementing + * persistent Red-Black trees as described in "Purely Functional Data Structures", + * Chris Okasaki, 1998, section 3.3. + */ bool -pmt_dict::has_key(pmt_t key) const +pmt_is_dict(const pmt_t &obj) { - return pmt_is_pair(pmt_assv(key, d_alist)); + return pmt_is_null(obj) || pmt_is_pair(obj); } pmt_t -pmt_dict::items() const +pmt_make_dict() { - return d_alist; + return PMT_NIL; } pmt_t -pmt_dict::keys() const +pmt_dict_add(const pmt_t &dict, const pmt_t &key, const pmt_t &value) { - return pmt_map(pmt_car, d_alist); -} + if (pmt_is_null(dict)) + return pmt_acons(key, value, PMT_NIL); -pmt_t -pmt_dict::values() const -{ - return pmt_map(pmt_cdr, d_alist); -} + if (pmt_dict_has_key(dict, key)) + return pmt_acons(key, value, pmt_dict_delete(dict, key)); -bool -pmt_is_dict(pmt_t obj) -{ - return obj->is_dict(); + return pmt_acons(key, value, dict); } pmt_t -pmt_make_dict() +pmt_dict_delete(const pmt_t &dict, const pmt_t &key) { - return pmt_t(new pmt_dict()); + if (pmt_is_null(dict)) + return dict; + + if (pmt_eqv(pmt_caar(dict), key)) + return pmt_cdr(dict); + + return pmt_cons(pmt_car(dict), pmt_dict_delete(pmt_cdr(dict), key)); } -void -pmt_dict_set(pmt_t dict, pmt_t key, pmt_t value) +pmt_t +pmt_dict_ref(const pmt_t &dict, const pmt_t &key, const pmt_t ¬_found) { - pmt_dict* d = _dict(dict); - if (!d) - throw pmt_wrong_type("pmt_dict_set", dict); - - d->set(key, value); + pmt_t p = pmt_assv(key, dict); // look for (key . value) pair + if (pmt_is_pair(p)) + return pmt_cdr(p); + else + return not_found; } bool -pmt_dict_has_key(pmt_t dict, pmt_t key) +pmt_dict_has_key(const pmt_t &dict, const pmt_t &key) { - pmt_dict* d = _dict(dict); - if (!d) - throw pmt_wrong_type("pmt_dict_has_key", dict); - - return d->has_key(key); -} - -pmt_t -pmt_dict_ref(pmt_t dict, pmt_t key, pmt_t not_found) -{ - pmt_dict* d = _dict(dict); - if (!d) - throw pmt_wrong_type("pmt_dict_ref", dict); - - return d->ref(key, not_found); + return pmt_is_pair(pmt_assv(key, dict)); } pmt_t pmt_dict_items(pmt_t dict) { - if (!dict->is_dict()) - throw pmt_wrong_type("pmt_dict_items", dict); + if (!pmt_is_dict(dict)) + throw pmt_wrong_type("pmt_dict_values", dict); - return _dict(dict)->items(); + return dict; // equivalent to dict in the a-list case } pmt_t pmt_dict_keys(pmt_t dict) { - if (!dict->is_dict()) + if (!pmt_is_dict(dict)) throw pmt_wrong_type("pmt_dict_keys", dict); - return _dict(dict)->keys(); + return pmt_map(pmt_car, dict); } pmt_t pmt_dict_values(pmt_t dict) { - if (!dict->is_dict()) - throw pmt_wrong_type("pmt_dict_values", dict); + if (!pmt_is_dict(dict)) + throw pmt_wrong_type("pmt_dict_keys", dict); - return _dict(dict)->values(); + return pmt_map(pmt_cdr, dict); } //////////////////////////////////////////////////////////////////////////// @@ -978,6 +939,24 @@ pmt_eqv(const pmt_t& x, const pmt_t& y) } bool +pmt_eqv_raw(pmt_base *x, pmt_base *y) +{ + if (x == y) + return true; + + if (x->is_integer() && y->is_integer()) + return _integer(x)->value() == _integer(y)->value(); + + if (x->is_real() && y->is_real()) + return _real(x)->value() == _real(y)->value(); + + if (x->is_complex() && y->is_complex()) + return _complex(x)->value() == _complex(y)->value(); + + return false; +} + +bool pmt_equal(const pmt_t& x, const pmt_t& y) { if (pmt_eqv(x, y)) @@ -1082,6 +1061,35 @@ pmt_assq(pmt_t obj, pmt_t alist) return PMT_F; } +/* + * This avoids a bunch of shared_pointer reference count manipulation. + */ +pmt_t +pmt_assv_raw(pmt_base *obj, pmt_base *alist) +{ + while (alist->is_pair()){ + pmt_base *p = ((pmt_pair *)alist)->d_car.get(); + if (!p->is_pair()) // malformed alist + return PMT_F; + + if (pmt_eqv_raw(obj, ((pmt_pair *)p)->d_car.get())) + return ((pmt_pair *)alist)->d_car; + + alist = (((pmt_pair *)alist)->d_cdr).get(); + } + return PMT_F; +} + +#if 1 + +pmt_t +pmt_assv(pmt_t obj, pmt_t alist) +{ + return pmt_assv_raw(obj.get(), alist.get()); +} + +#else + pmt_t pmt_assv(pmt_t obj, pmt_t alist) { @@ -1098,6 +1106,9 @@ pmt_assv(pmt_t obj, pmt_t alist) return PMT_F; } +#endif + + pmt_t pmt_assoc(pmt_t obj, pmt_t alist) { @@ -1322,7 +1333,6 @@ pmt_dump_sizeof() printf("sizeof(pmt_null) = %3zd\n", sizeof(pmt_null)); printf("sizeof(pmt_pair) = %3zd\n", sizeof(pmt_pair)); printf("sizeof(pmt_vector) = %3zd\n", sizeof(pmt_vector)); - printf("sizeof(pmt_dict) = %3zd\n", sizeof(pmt_dict)); printf("sizeof(pmt_uniform_vector) = %3zd\n", sizeof(pmt_uniform_vector)); } diff --git a/gruel/src/lib/pmt/pmt_int.h b/gruel/src/lib/pmt/pmt_int.h index 7581845f8..50683ffb5 100644 --- a/gruel/src/lib/pmt/pmt_int.h +++ b/gruel/src/lib/pmt/pmt_int.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2009 Free Software Foundation, Inc. + * Copyright 2006,2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -107,9 +107,9 @@ public: class pmt_integer : public pmt_base { +public: long d_value; -public: pmt_integer(long value); //~pmt_integer(){} @@ -120,9 +120,9 @@ public: class pmt_real : public pmt_base { +public: double d_value; -public: pmt_real(double value); //~pmt_real(){} @@ -133,9 +133,9 @@ public: class pmt_complex : public pmt_base { +public: std::complex<double> d_value; -public: pmt_complex(std::complex<double> value); //~pmt_complex(){} @@ -155,10 +155,10 @@ public: class pmt_pair : public pmt_base { +public: pmt_t d_car; pmt_t d_cdr; -public: pmt_pair(const pmt_t& car, const pmt_t& cdr); //~pmt_pair(){}; @@ -203,23 +203,6 @@ public: void _set(size_t k, pmt_t v) { d_v[k] = v; } }; -class pmt_dict : public pmt_base -{ - pmt_t d_alist; // list of (key . value) pairs - -public: - pmt_dict(); - //~pmt_dict(); - - bool is_dict() const { return true; } - void set(pmt_t key, pmt_t value); - pmt_t ref(pmt_t key, pmt_t default_value) const; - bool has_key(pmt_t key) const; - pmt_t items() const; - pmt_t keys() const; - pmt_t values() const; -}; - class pmt_any : public pmt_base { boost::any d_any; diff --git a/gruel/src/lib/pmt/qa_pmt_prims.cc b/gruel/src/lib/pmt/qa_pmt_prims.cc index 59d9e14d3..f2414c72c 100644 --- a/gruel/src/lib/pmt/qa_pmt_prims.cc +++ b/gruel/src/lib/pmt/qa_pmt_prims.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2009 Free Software Foundation, Inc. + * Copyright 2006,2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -36,14 +36,14 @@ qa_pmt_prims::test_symbols() CPPUNIT_ASSERT(!pmt_is_symbol(PMT_F)); CPPUNIT_ASSERT_THROW(pmt_symbol_to_string(PMT_F), pmt_wrong_type); - pmt_t sym1 = pmt_string_to_symbol("test"); + pmt_t sym1 = mp("test"); CPPUNIT_ASSERT(pmt_is_symbol(sym1)); CPPUNIT_ASSERT_EQUAL(std::string("test"), pmt_symbol_to_string(sym1)); CPPUNIT_ASSERT(pmt_is_true(sym1)); CPPUNIT_ASSERT(!pmt_is_false(sym1)); - pmt_t sym2 = pmt_string_to_symbol("foo"); - pmt_t sym3 = pmt_string_to_symbol("test"); + pmt_t sym2 = mp("foo"); + pmt_t sym3 = mp("test"); CPPUNIT_ASSERT_EQUAL(sym1, sym3); CPPUNIT_ASSERT(sym1 != sym2); CPPUNIT_ASSERT(sym1 == sym3); @@ -56,7 +56,7 @@ qa_pmt_prims::test_symbols() for (int i = 0; i < N; i++){ char buf[100]; snprintf(buf, sizeof(buf), "test-%d", i); - v1[i] = pmt_string_to_symbol(buf); + v1[i] = mp(buf); } // confirm that they are all unique @@ -68,7 +68,7 @@ qa_pmt_prims::test_symbols() for (int i = 0; i < N; i++){ char buf[100]; snprintf(buf, sizeof(buf), "test-%d", i); - v2[i] = pmt_string_to_symbol(buf); + v2[i] = mp(buf); } // confirm that we get the same ones back @@ -79,7 +79,7 @@ qa_pmt_prims::test_symbols() void qa_pmt_prims::test_booleans() { - pmt_t sym = pmt_string_to_symbol("test"); + pmt_t sym = mp("test"); CPPUNIT_ASSERT(pmt_is_bool(PMT_T)); CPPUNIT_ASSERT(pmt_is_bool(PMT_F)); CPPUNIT_ASSERT(!pmt_is_bool(sym)); @@ -137,9 +137,9 @@ qa_pmt_prims::test_pairs() { CPPUNIT_ASSERT(pmt_is_null(PMT_NIL)); CPPUNIT_ASSERT(!pmt_is_pair(PMT_NIL)); - pmt_t s1 = pmt_string_to_symbol("s1"); - pmt_t s2 = pmt_string_to_symbol("s2"); - pmt_t s3 = pmt_string_to_symbol("s3"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t s3 = mp("s3"); CPPUNIT_ASSERT_EQUAL((size_t)0, pmt_length(PMT_NIL)); @@ -174,9 +174,9 @@ qa_pmt_prims::test_vectors() static const size_t N = 3; pmt_t v1 = pmt_make_vector(N, PMT_NIL); CPPUNIT_ASSERT_EQUAL(N, pmt_length(v1)); - pmt_t s0 = pmt_string_to_symbol("s0"); - pmt_t s1 = pmt_string_to_symbol("s1"); - pmt_t s2 = pmt_string_to_symbol("s2"); + pmt_t s0 = mp("s0"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); pmt_vector_set(v1, 0, s0); pmt_vector_set(v1, 1, s1); @@ -213,7 +213,7 @@ qa_pmt_prims::test_tuples() for (size_t i = 0; i < 10; i++){ std::ostringstream os; os << "s" << i; - s[i] = pmt_string_to_symbol(os.str()); + s[i] = mp(os.str()); pmt_vector_set(v, i, s[i]); } @@ -282,9 +282,9 @@ qa_pmt_prims::test_tuples() void qa_pmt_prims::test_equivalence() { - pmt_t s0 = pmt_string_to_symbol("s0"); - pmt_t s1 = pmt_string_to_symbol("s1"); - pmt_t s2 = pmt_string_to_symbol("s2"); + pmt_t s0 = mp("s0"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); pmt_t list0 = pmt_cons(s0, pmt_cons(s1, pmt_cons(s2, PMT_NIL))); pmt_t list1 = pmt_cons(s0, pmt_cons(s1, pmt_cons(s2, PMT_NIL))); pmt_t i0 = pmt_from_long(42); @@ -324,13 +324,13 @@ qa_pmt_prims::test_equivalence() void qa_pmt_prims::test_misc() { - pmt_t k0 = pmt_string_to_symbol("k0"); - pmt_t k1 = pmt_string_to_symbol("k1"); - pmt_t k2 = pmt_string_to_symbol("k2"); - pmt_t k3 = pmt_string_to_symbol("k3"); - pmt_t v0 = pmt_string_to_symbol("v0"); - pmt_t v1 = pmt_string_to_symbol("v1"); - pmt_t v2 = pmt_string_to_symbol("v2"); + pmt_t k0 = mp("k0"); + pmt_t k1 = mp("k1"); + pmt_t k2 = mp("k2"); + pmt_t k3 = mp("k3"); + pmt_t v0 = mp("v0"); + pmt_t v1 = mp("v1"); + pmt_t v2 = mp("v2"); pmt_t p0 = pmt_cons(k0, v0); pmt_t p1 = pmt_cons(k1, v1); pmt_t p2 = pmt_cons(k2, v2); @@ -351,29 +351,31 @@ qa_pmt_prims::test_dict() pmt_t dict = pmt_make_dict(); CPPUNIT_ASSERT(pmt_is_dict(dict)); - pmt_t k0 = pmt_string_to_symbol("k0"); - pmt_t k1 = pmt_string_to_symbol("k1"); - pmt_t k2 = pmt_string_to_symbol("k2"); - pmt_t k3 = pmt_string_to_symbol("k3"); - pmt_t v0 = pmt_string_to_symbol("v0"); - pmt_t v1 = pmt_string_to_symbol("v1"); - pmt_t v2 = pmt_string_to_symbol("v2"); - pmt_t v3 = pmt_string_to_symbol("v3"); + pmt_t k0 = mp("k0"); + pmt_t k1 = mp("k1"); + pmt_t k2 = mp("k2"); + pmt_t k3 = mp("k3"); + pmt_t v0 = mp("v0"); + pmt_t v1 = mp("v1"); + pmt_t v2 = mp("v2"); + pmt_t v3 = mp("v3"); pmt_t not_found = pmt_cons(PMT_NIL, PMT_NIL); CPPUNIT_ASSERT(!pmt_dict_has_key(dict, k0)); - pmt_dict_set(dict, k0, v0); + dict = pmt_dict_add(dict, k0, v0); CPPUNIT_ASSERT(pmt_dict_has_key(dict, k0)); CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k0, not_found), v0)); CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k1, not_found), not_found)); - pmt_dict_set(dict, k1, v1); - pmt_dict_set(dict, k2, v2); + dict = pmt_dict_add(dict, k1, v1); + dict = pmt_dict_add(dict, k2, v2); CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k1, not_found), v1)); - pmt_dict_set(dict, k1, v3); + dict = pmt_dict_add(dict, k1, v3); CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k1, not_found), v3)); - pmt_t keys = pmt_cons(k2, pmt_cons(k1, pmt_cons(k0, PMT_NIL))); - pmt_t vals = pmt_cons(v2, pmt_cons(v3, pmt_cons(v0, PMT_NIL))); + pmt_t keys = pmt_list3(k1, k2, k0); + pmt_t vals = pmt_list3(v3, v2, v0); + //std::cout << "pmt_dict_keys: " << pmt_dict_keys(dict) << std::endl; + //std::cout << "pmt_dict_values: " << pmt_dict_values(dict) << std::endl; CPPUNIT_ASSERT(pmt_equal(keys, pmt_dict_keys(dict))); CPPUNIT_ASSERT(pmt_equal(vals, pmt_dict_values(dict))); } @@ -381,10 +383,10 @@ qa_pmt_prims::test_dict() void qa_pmt_prims::test_io() { - pmt_t k0 = pmt_string_to_symbol("k0"); - pmt_t k1 = pmt_string_to_symbol("k1"); - pmt_t k2 = pmt_string_to_symbol("k2"); - pmt_t k3 = pmt_string_to_symbol("k3"); + pmt_t k0 = mp("k0"); + pmt_t k1 = mp("k1"); + pmt_t k2 = mp("k2"); + pmt_t k3 = mp("k3"); CPPUNIT_ASSERT_EQUAL(std::string("k0"), pmt_write_string(k0)); } @@ -392,10 +394,10 @@ qa_pmt_prims::test_io() void qa_pmt_prims::test_lists() { - pmt_t s0 = pmt_intern("s0"); - pmt_t s1 = pmt_intern("s1"); - pmt_t s2 = pmt_intern("s2"); - pmt_t s3 = pmt_intern("s3"); + pmt_t s0 = mp("s0"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t s3 = mp("s3"); pmt_t l1 = pmt_list4(s0, s1, s2, s3); pmt_t l2 = pmt_list3(s0, s1, s2); @@ -466,7 +468,7 @@ qa_pmt_msg_accepter_nop::~qa_pmt_msg_accepter_nop(){} void qa_pmt_prims::test_msg_accepter() { - pmt_t sym = pmt_intern("my-symbol"); + pmt_t sym = mp("my-symbol"); boost::any a0; a0 = std::string("Hello!"); @@ -493,16 +495,16 @@ void qa_pmt_prims::test_serialize() { std::stringbuf sb; // fake channel - pmt_t a = pmt_intern("a"); - pmt_t b = pmt_intern("b"); - pmt_t c = pmt_intern("c"); + pmt_t a = mp("a"); + pmt_t b = mp("b"); + pmt_t c = mp("c"); sb.str(""); // reset channel to empty // write stuff to channel pmt_serialize(PMT_NIL, sb); - pmt_serialize(pmt_intern("foobarvia"), sb); + pmt_serialize(mp("foobarvia"), sb); pmt_serialize(pmt_from_long(123456789), sb); pmt_serialize(pmt_from_long(-123456789), sb); pmt_serialize(pmt_cons(PMT_NIL, PMT_NIL), sb); @@ -517,7 +519,7 @@ qa_pmt_prims::test_serialize() // read it back CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_NIL)); - CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_intern("foobarvia"))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), mp("foobarvia"))); CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_from_long(123456789))); CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_from_long(-123456789))); CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_cons(PMT_NIL, PMT_NIL))); @@ -540,9 +542,9 @@ qa_pmt_prims::test_serialize() void qa_pmt_prims::test_sets() { - pmt_t s1 = pmt_intern("s1"); - pmt_t s2 = pmt_intern("s2"); - pmt_t s3 = pmt_intern("s3"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t s3 = mp("s3"); pmt_t l1 = pmt_list1(s1); pmt_t l2 = pmt_list2(s2,s3); |