diff options
33 files changed, 1426 insertions, 172 deletions
diff --git a/config/Makefile.am b/config/Makefile.am index 46c84da76..4e87bc458 100644 --- a/config/Makefile.am +++ b/config/Makefile.am @@ -42,6 +42,7 @@ m4macros = \ grc_gr_audio_portaudio.m4 \ grc_gr_audio_windows.m4 \ grc_gr_comedi.m4 \ + grc_gr_gcell.m4 \ grc_gr_gpio.m4 \ grc_gr_gsm_fr_vocoder.m4 \ grc_gr_radar_mono.m4 \ diff --git a/config/grc_gcell.m4 b/config/grc_gcell.m4 index a229211aa..188437f04 100644 --- a/config/grc_gcell.m4 +++ b/config/grc_gcell.m4 @@ -65,6 +65,11 @@ AC_DEFUN([GRC_GCELL],[ gcell_spu_LA="\${abs_top_builddir}/gcell/src/lib/spu/libgcell_spu.a" AC_SUBST(gcell_spu_INCLUDES) AC_SUBST(gcell_spu_LA) + + dnl kludge up initial swig dependency files + AC_CONFIG_COMMANDS([swig_gcell_deps], [ + touch gr-gcell/src/gcell.d + ]) fi AC_CONFIG_FILES([ \ diff --git a/config/grc_gr_gcell.m4 b/config/grc_gr_gcell.m4 new file mode 100644 index 000000000..d425337ef --- /dev/null +++ b/config/grc_gr_gcell.m4 @@ -0,0 +1,38 @@ +dnl Copyright 2001,2002,2003,2004,2005,2006,2008 Free Software Foundation, Inc. +dnl +dnl This file is part of GNU Radio +dnl +dnl GNU Radio is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3, or (at your option) +dnl any later version. +dnl +dnl GNU Radio is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Radio; see the file COPYING. If not, write to +dnl the Free Software Foundation, Inc., 51 Franklin Street, +dnl Boston, MA 02110-1301, USA. + +AC_DEFUN([GRC_GR_GCELL],[ + GRC_ENABLE(gr-gcell) + + dnl Don't do gr-gcell if gcell or gnuradio-core skipped + GRC_CHECK_DEPENDENCY(gr-gcell, gcell) + GRC_CHECK_DEPENDENCY(gr-gcell, gnuradio-core) + + AC_CONFIG_FILES([ \ + gr-gcell/Makefile \ + gr-gcell/src/Makefile \ + gr-gcell/src/examples/Makefile \ + gr-gcell/src/run_tests \ + ]) + + GRC_BUILD_CONDITIONAL(gr-gcell,[ + dnl run_tests is created from run_tests.in. Make it executable. + AC_CONFIG_COMMANDS([run_tests_gcell], [chmod +x gr-gcell/src/run_tests]) + ]) +]) diff --git a/configure.ac b/configure.ac index 9917d1ff4..05c2cc050 100644 --- a/configure.ac +++ b/configure.ac @@ -245,6 +245,7 @@ GRC_GCELL GRC_GNURADIO_CORE GRC_USRP GRC_GR_USRP dnl this must come after GRC_USRP +GRC_GR_GCELL dnl this must come after GRC_GCELL and GRC_GNURADIO_CORE GRC_GR_MSDD6000 GRC_GR_AUDIO_ALSA GRC_GR_AUDIO_JACK diff --git a/gcell/src/lib/runtime/Makefile.am b/gcell/src/lib/runtime/Makefile.am index a68d2bcd0..89d6f1bb9 100644 --- a/gcell/src/lib/runtime/Makefile.am +++ b/gcell/src/lib/runtime/Makefile.am @@ -32,6 +32,7 @@ dist_bin_SCRIPTS = gcell-embedspu-libtool noinst_LTLIBRARIES = libruntime.la libruntime-qa.la libruntime_la_SOURCES = \ + gc_aligned_alloc.cc \ gc_job_manager.cc \ gc_job_manager_impl.cc \ gc_jd_queue.c \ @@ -46,6 +47,7 @@ libruntime_qa_la_SOURCES = \ gcellinclude_HEADERS = \ + gc_aligned_alloc.h \ gc_job_manager.h noinst_HEADERS = \ diff --git a/gcell/src/lib/runtime/gc_aligned_alloc.cc b/gcell/src/lib/runtime/gc_aligned_alloc.cc new file mode 100644 index 000000000..fa20a6443 --- /dev/null +++ b/gcell/src/lib/runtime/gc_aligned_alloc.cc @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gc_aligned_alloc.h> +#include <stdlib.h> +#include <stdexcept> + +// custom deleter of anything that can be freed with "free" +class free_deleter { +public: + void operator()(void *p) { + free(p); + } +}; + +void * +gc_aligned_alloc(size_t size, size_t alignment) +{ + void *p = 0; + if (posix_memalign(&p, alignment, size) != 0){ + perror("posix_memalign"); + throw std::runtime_error("memory"); + } + memset(p, 0, size); // zero the memory + return p; +} + +boost::shared_ptr<void> +gc_aligned_alloc_sptr(size_t size, size_t alignment) +{ + return boost::shared_ptr<void>(gc_aligned_alloc(size, alignment), + free_deleter()); +} diff --git a/gcell/src/lib/runtime/gc_aligned_alloc.h b/gcell/src/lib/runtime/gc_aligned_alloc.h new file mode 100644 index 000000000..bdc21c278 --- /dev/null +++ b/gcell/src/lib/runtime/gc_aligned_alloc.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ +#ifndef INCLUDED_GC_ALIGNED_ALLOC_H +#define INCLUDED_GC_ALIGNED_ALLOC_H + +#include <boost/shared_ptr.hpp> + +/*! + * \brief Return pointer to chunk of storage of size size bytes. + * The allocation will be aligned to an \p alignment boundary. + * + * \param size is the number of bytes to allocate + * \param alignment is the minimum storage alignment in bytes; must be a power of 2. + * + * Throws if can't allocate memory. The storage should be freed + * with "free" when done. The memory is initialized to zero. + */ +void * +gc_aligned_alloc(size_t size, size_t alignment = 128); + +/*! + * \brief Return boost::shared_ptr to chunk of storage of size size bytes. + * The allocation will be aligned to an \p alignment boundary. + * + * \param size is the number of bytes to allocate + * \param alignment is the minimum storage alignment in bytes; must be a power of 2. + * + * Throws if can't allocate memory. The storage should be freed + * with "free" when done. The memory is initialized to zero. + */ +boost::shared_ptr<void> +gc_aligned_alloc_sptr(size_t size, size_t alignment = 128); + +#endif /* INCLUDED_GC_ALIGNED_ALLOC_H */ diff --git a/gcell/src/lib/runtime/gc_job_manager.cc b/gcell/src/lib/runtime/gc_job_manager.cc index 9ede5e156..ac2e989a4 100644 --- a/gcell/src/lib/runtime/gc_job_manager.cc +++ b/gcell/src/lib/runtime/gc_job_manager.cc @@ -31,6 +31,19 @@ static boost::weak_ptr<gc_job_manager> s_singleton; +// custom deleter of gc_job_desc allocated via alloc_job_desc_sptr +class job_desc_deleter { + gc_job_manager_sptr d_mgr; +public: + job_desc_deleter(gc_job_manager_sptr mgr) : d_mgr(mgr) {} + + void operator()(gc_job_desc *jd) { + d_mgr->free_job_desc(jd); + } +}; + + + gc_job_manager_sptr gc_make_job_manager(const gc_jm_options *options) { @@ -71,6 +84,19 @@ gc_job_manager::singleton() return gc_job_manager_sptr(s_singleton); } +gc_job_desc_sptr +gc_job_manager::make_jd_sptr(gc_job_manager_sptr mgr, gc_job_desc *jd) +{ + return gc_job_desc_sptr(jd, job_desc_deleter(mgr)); +} + +gc_job_desc_sptr +gc_job_manager::alloc_job_desc(gc_job_manager_sptr mgr) +{ + return make_jd_sptr(mgr, mgr->alloc_job_desc()); +} + + // ------------------------------------------------------------------------ diff --git a/gcell/src/lib/runtime/gc_job_manager.h b/gcell/src/lib/runtime/gc_job_manager.h index aa30dc24b..67abce7ed 100644 --- a/gcell/src/lib/runtime/gc_job_manager.h +++ b/gcell/src/lib/runtime/gc_job_manager.h @@ -33,6 +33,7 @@ class gc_job_manager; typedef boost::shared_ptr<gc_job_manager> gc_job_manager_sptr; typedef boost::shared_ptr<spe_program_handle_t> spe_program_handle_sptr; +typedef boost::shared_ptr<gc_job_desc> gc_job_desc_sptr; /*! * \brief Return a boost::shared_ptr to an spe_program_handle_t @@ -86,10 +87,19 @@ struct gc_jm_options { gc_jm_options() : max_jobs(0), max_client_threads(0), nspes(0), - gang_schedule(true), use_affinity(false), + gang_schedule(false), use_affinity(false), enable_logging(false), log2_nlog_entries(12) { } + + gc_jm_options(spe_program_handle_sptr program_handle_, + unsigned int nspes_ = 0) : + max_jobs(0), max_client_threads(0), nspes(nspes_), + gang_schedule(false), use_affinity(false), + enable_logging(false), log2_nlog_entries(12), + program_handle(program_handle_) + { + } }; enum gc_wait_mode { @@ -236,6 +246,11 @@ public: */ virtual std::vector<std::string> proc_names() = 0; + virtual void set_debug(int debug); + virtual int debug(); + + /* ----- static methods ----- */ + /*! * \brief Set the singleton gc_job_manager instance. * \param mgr is the job manager instance. @@ -256,9 +271,15 @@ public: */ static gc_job_manager_sptr singleton(); + /*! + * \brief return a boost::shared_ptr to a job descriptor. + */ + static gc_job_desc_sptr make_jd_sptr(gc_job_manager_sptr mgr, gc_job_desc *jd); - virtual void set_debug(int debug); - virtual int debug(); + /*! + * \brief allocate a job descriptor and return a boost::shared_ptr to it. + */ + static gc_job_desc_sptr alloc_job_desc(gc_job_manager_sptr mgr); }; diff --git a/gcell/src/lib/runtime/gc_job_manager_impl.cc b/gcell/src/lib/runtime/gc_job_manager_impl.cc index 59deb4ae5..9c859511b 100644 --- a/gcell/src/lib/runtime/gc_job_manager_impl.cc +++ b/gcell/src/lib/runtime/gc_job_manager_impl.cc @@ -25,7 +25,7 @@ #include <gc_job_manager_impl.h> #include <gc_mbox.h> #include <gc_proc_def_utils.h> - +#include <gc_aligned_alloc.h> #include <stdio.h> #include <stdexcept> #include <stdlib.h> @@ -85,23 +85,6 @@ client_key_destructor(void *p) ((gc_client_thread_info *) p)->d_free = 1; } -/* - * Return pointer to cache-aligned chunk of storage of size size bytes. - * Throw if can't allocate memory. The storage should be freed - * with "free" when done. The memory is initialized to zero. - */ -static void * -aligned_alloc(size_t size, size_t alignment = CACHE_LINE_SIZE) -{ - void *p = 0; - if (posix_memalign(&p, alignment, size) != 0){ - perror("posix_memalign"); - throw std::runtime_error("memory"); - } - memset(p, 0, size); // zero the memory - return p; -} - static bool is_power_of_2(uint32_t x) { @@ -196,7 +179,7 @@ gc_job_manager_impl::gc_job_manager_impl(const gc_jm_options *options) // ---------------------------------------------------------------- // initalize the job queue - d_queue = (gc_jd_queue_t *) aligned_alloc(sizeof(gc_jd_queue_t)); + d_queue = (gc_jd_queue_t *) gc_aligned_alloc(sizeof(gc_jd_queue_t), CACHE_LINE_SIZE); _d_queue_boost = boost::shared_ptr<void>((void *) d_queue, free_deleter()); gc_jd_queue_init(d_queue); @@ -208,15 +191,15 @@ gc_job_manager_impl::gc_job_manager_impl(const gc_jm_options *options) // 1 spu_arg struct for each SPE assert(sizeof(gc_spu_args_t) % 16 == 0); d_spu_args = - (gc_spu_args_t *) aligned_alloc(MAX_SPES * sizeof(gc_spu_args_t), 16); + (gc_spu_args_t *) gc_aligned_alloc(MAX_SPES * sizeof(gc_spu_args_t), 16); _d_spu_args_boost = boost::shared_ptr<void>((void *) d_spu_args, free_deleter()); // 2 completion info structs for each SPE (we double buffer them) assert(sizeof(gc_comp_info_t) % CACHE_LINE_SIZE == 0); d_comp_info = - (gc_comp_info_t *) aligned_alloc(2 * MAX_SPES * sizeof(gc_comp_info_t), - CACHE_LINE_SIZE); + (gc_comp_info_t *) gc_aligned_alloc(2 * MAX_SPES * sizeof(gc_comp_info_t), + CACHE_LINE_SIZE); _d_comp_info_boost = boost::shared_ptr<void>((void *) d_comp_info, free_deleter()); @@ -269,7 +252,7 @@ gc_job_manager_impl::gc_job_manager_impl(const gc_jm_options *options) // ---------------------------------------------------------------- // initalize the free list of job descriptors - d_free_list = (gc_jd_stack_t *) aligned_alloc(sizeof(gc_jd_stack_t)); + d_free_list = (gc_jd_stack_t *) gc_aligned_alloc(sizeof(gc_jd_stack_t), CACHE_LINE_SIZE); // This ensures that the memory associated with d_free_list is // automatically freed in the destructor or if an exception occurs // here in the constructor. @@ -283,7 +266,7 @@ gc_job_manager_impl::gc_job_manager_impl(const gc_jm_options *options) } // Initialize the array of job descriptors. - d_jd = (gc_job_desc_t *) aligned_alloc(sizeof(d_jd[0]) * d_options.max_jobs); + d_jd = (gc_job_desc_t *) gc_aligned_alloc(sizeof(d_jd[0]) * d_options.max_jobs, CACHE_LINE_SIZE); _d_jd_boost = boost::shared_ptr<void>((void *) d_jd, free_deleter()); @@ -317,7 +300,7 @@ gc_job_manager_impl::gc_job_manager_impl(const gc_jm_options *options) // allocate all bitvectors in a single cache-aligned chunk size_t nlongs = d_bvlen * d_options.max_client_threads; - void *p = aligned_alloc(nlongs * sizeof(unsigned long)); + void *p = gc_aligned_alloc(nlongs * sizeof(unsigned long), CACHE_LINE_SIZE); _d_all_bitvectors = boost::shared_ptr<void>(p, free_deleter()); // Now point the gc_client_thread_info bitvectors into this storage diff --git a/gcell/src/lib/wrapper/gcp_fft_1d_r2.cc b/gcell/src/lib/wrapper/gcp_fft_1d_r2.cc index f92ee42c8..07267e303 100644 --- a/gcell/src/lib/wrapper/gcp_fft_1d_r2.cc +++ b/gcell/src/lib/wrapper/gcp_fft_1d_r2.cc @@ -30,18 +30,19 @@ static void init_jd(gc_job_desc *jd, gc_proc_id_t proc_id, unsigned log2_fft_length, - bool forward, + bool shift, std::complex<float> *out, const std::complex<float> *in, - const std::complex<float> *W) + const std::complex<float> *twiddle, + const float *window) { jd->proc_id = proc_id; jd->input.nargs = 2; jd->output.nargs = 0; - jd->eaa.nargs = 3; + jd->eaa.nargs = 4; jd->input.arg[0].u32 = log2_fft_length; - jd->input.arg[1].u32 = forward; + jd->input.arg[1].u32 = shift; unsigned int fft_length = 1 << log2_fft_length; jd->eaa.arg[0].ea_addr = ptr_to_ea(out); @@ -52,19 +53,28 @@ init_jd(gc_job_desc *jd, jd->eaa.arg[1].direction = GCJD_DMA_GET; jd->eaa.arg[1].get_size = sizeof(std::complex<float>) * fft_length; - jd->eaa.arg[2].ea_addr = ptr_to_ea(const_cast<std::complex<float>*>(W)); + jd->eaa.arg[2].ea_addr = ptr_to_ea(const_cast<std::complex<float>*>(twiddle)); jd->eaa.arg[2].direction = GCJD_DMA_GET; jd->eaa.arg[2].get_size = sizeof(std::complex<float>) * fft_length / 4; -} + jd->eaa.arg[3].ea_addr = ptr_to_ea(const_cast<float*>(window)); + jd->eaa.arg[3].direction = GCJD_DMA_GET; + if (window == 0) + jd->eaa.arg[3].get_size = 0; + else + jd->eaa.arg[3].get_size = sizeof(float) * fft_length; +} -gc_job_desc * + +gc_job_desc_sptr gcp_fft_1d_r2_submit(gc_job_manager_sptr mgr, unsigned int log2_fft_length, bool forward, + bool shift, std::complex<float> *out, const std::complex<float> *in, - const std::complex<float> *W) + const std::complex<float> *twiddle, + const float *window) { unsigned int fft_length = 1 << log2_fft_length; if (fft_length > 4096) @@ -74,29 +84,36 @@ gcp_fft_1d_r2_submit(gc_job_manager_sptr mgr, throw gc_bad_align("out"); if ((intptr_t)in & 0xf) throw gc_bad_align("in"); - if ((intptr_t)W & 0xf) - throw gc_bad_align("W"); + if ((intptr_t)twiddle & 0xf) + throw gc_bad_align("twiddle"); + if ((intptr_t)window & 0xf) + throw gc_bad_align("window"); + + std::string proc_name; + if (forward) + proc_name = "fwd_fft_1d_r2"; + else + proc_name = "inv_fft_1d_r2"; - gc_proc_id_t fft_id = mgr->lookup_proc("fft_1d_r2"); - gc_job_desc *jd = mgr->alloc_job_desc(); - init_jd(jd, fft_id, log2_fft_length, forward, out, in, W); - if (!mgr->submit_job(jd)){ + gc_proc_id_t fft_id = mgr->lookup_proc(proc_name); + gc_job_desc_sptr jd = gc_job_manager::alloc_job_desc(mgr); + init_jd(jd.get(), fft_id, log2_fft_length, shift, out, in, twiddle, window); + if (!mgr->submit_job(jd.get())){ gc_job_status_t s = jd->status; - mgr->free_job_desc(jd); - throw gc_bad_submit("fft_1d_r2", s); + throw gc_bad_submit(proc_name, s); } return jd; } void -gcp_fft_1d_r2_twiddle(unsigned int log2_fft_length, std::complex<float> *W) +gcp_fft_1d_r2_twiddle(unsigned int log2_fft_length, std::complex<float> *twiddle) { unsigned int n = 1 << log2_fft_length; - W[0].real() = 1.0; - W[0].imag() = 0.0; + twiddle[0].real() = 1.0; + twiddle[0].imag() = 0.0; for (unsigned i=1; i < n/4; i++){ - W[i].real() = cos(i * 2*M_PI/n); - W[n/4 - i].imag() = -W[i].real(); + twiddle[i].real() = cos(i * 2*M_PI/n); + twiddle[n/4 - i].imag() = -twiddle[i].real(); } } diff --git a/gcell/src/lib/wrapper/gcp_fft_1d_r2.h b/gcell/src/lib/wrapper/gcp_fft_1d_r2.h index ed1d9e783..1207a5f36 100644 --- a/gcell/src/lib/wrapper/gcp_fft_1d_r2.h +++ b/gcell/src/lib/wrapper/gcp_fft_1d_r2.h @@ -25,25 +25,32 @@ #include <complex> /*! - * \brief Submit a job that computes the forward or reverse FFT. + * \brief Submit a job that computes the forward or inverse FFT. * * \param mgr is the job manager instance * \param log2_fft_length is the log2 of the fft_length (4 <= x <= 12). - * \param forward is true to compute the forward xform + * \param forward is true to compute the forward transform, else the inverse. + * \param shift indicates if an "fftshift" should be applied to the output data * \param out is the fft_length output from FFT (must be 16-byte aligned). * \param in is the fft_length input to FFT (must be 16-byte aligned). - * \param W is fft_length/4 twiddle factor input to FFT (must be 16-byte aligned). + * \param twiddle is fft_length/4 twiddle factor input to FFT (must be 16-byte aligned). + * \param window is the window to be applied to the input data. + * The window length must be either 0 or fft_length (must be 16-byte aligned). * - * Returns a job descriptor which should be passed to wait_job*. + * Returns a shared_ptr to a job descriptor which should be passed to wait_job*. * Throws an exception in the event of a problem. + * This uses the FFTW conventions for scaling. That is, neither the forward nor inverse + * are scaled by 1/fft_length. */ -gc_job_desc * +gc_job_desc_sptr gcp_fft_1d_r2_submit(gc_job_manager_sptr mgr, unsigned int log2_fft_length, bool forward, + bool shift, std::complex<float> *out, const std::complex<float> *in, - const std::complex<float> *W); + const std::complex<float> *twiddle, + const float *window); /*! * \brief Compute twiddle factors diff --git a/gcell/src/lib/wrapper/qa_gcp_fft_1d_r2.cc b/gcell/src/lib/wrapper/qa_gcp_fft_1d_r2.cc index b177edede..404f83657 100644 --- a/gcell/src/lib/wrapper/qa_gcp_fft_1d_r2.cc +++ b/gcell/src/lib/wrapper/qa_gcp_fft_1d_r2.cc @@ -80,7 +80,7 @@ qa_gcp_fft_1d_r2::t1() #endif } -// test reverse FFT +// test inverse FFT void qa_gcp_fft_1d_r2::t2() { @@ -101,11 +101,13 @@ qa_gcp_fft_1d_r2::t2() void qa_gcp_fft_1d_r2::t3() { + // FIXME Test fwd and inv with windowing option } void qa_gcp_fft_1d_r2::t4() { + // FIXME Test fwd and inv with shift option } static inline float @@ -178,14 +180,12 @@ qa_gcp_fft_1d_r2::test(gc_job_manager_sptr mgr, int log2_fft_size, bool forward) // ------------------------------------------------------------------------ // compute the answer on the cell - gc_job_desc *jd = gcp_fft_1d_r2_submit(mgr, log2_fft_size, forward, - cell_out, cell_in, cell_twiddle); - if (!mgr->wait_job(jd)){ + gc_job_desc_sptr jd = gcp_fft_1d_r2_submit(mgr, log2_fft_size, forward, false, + cell_out, cell_in, cell_twiddle, 0); + if (!mgr->wait_job(jd.get())){ fprintf(stderr, "wait_job failed: %s\n", gc_job_status_string(jd->status).c_str()); - mgr->free_job_desc(jd); CPPUNIT_ASSERT(0); } - mgr->free_job_desc(jd); // ------------------------------------------------------------------------ // compute the maximum of the relative error diff --git a/gcell/src/lib/wrapper/spu/gcs_fft_1d_r2.c b/gcell/src/lib/wrapper/spu/gcs_fft_1d_r2.c index bf4bdfd20..81e5dfd87 100644 --- a/gcell/src/lib/wrapper/spu/gcs_fft_1d_r2.c +++ b/gcell/src/lib/wrapper/spu/gcs_fft_1d_r2.c @@ -21,6 +21,7 @@ #include <gc_declare_proc.h> #include <libfft.h> +#include <assert.h> /* * v is really vector complex<float> @@ -35,24 +36,59 @@ conjugate_vector(vector float *v, int nelements) } static void -gcs_fft_1d_r2(const gc_job_direct_args_t *input, - gc_job_direct_args_t *output __attribute__((unused)), - const gc_job_ea_args_t *eaa) +gcs_fwd_fft_1d_r2(const gc_job_direct_args_t *input, + gc_job_direct_args_t *output __attribute__((unused)), + const gc_job_ea_args_t *eaa) { - vector float *out = (vector float *) eaa->arg[0].ls_addr; - vector float *in = (vector float *) eaa->arg[1].ls_addr; - vector float *W = (vector float *) eaa->arg[2].ls_addr; + vector float *out = (vector float *) eaa->arg[0].ls_addr; // complex + vector float *in = (vector float *) eaa->arg[1].ls_addr; // complex + vector float *twiddle = (vector float *) eaa->arg[2].ls_addr; // complex + vector float *window = (vector float *) eaa->arg[3].ls_addr; // float + int log2_fft_length = input->arg[0].u32; - int forward = input->arg[1].u32; // non-zero if forward xform + int shift = input->arg[1].u32; // non-zero if we should apply fftshift - if (forward){ - fft_1d_r2(out, in, W, log2_fft_length); + if (eaa->arg[3].get_size){ // apply window + // FIXME pointwise multiply in *= window + assert(0); } - else { - conjugate_vector(in, 1 << (log2_fft_length - 1)); - fft_1d_r2(out, in, W, log2_fft_length); - conjugate_vector(out, 1 << (log2_fft_length - 1)); + + fft_1d_r2(out, in, twiddle, log2_fft_length); + + if (shift){ + // FIXME apply "fftshift" to output data in-place + assert(0); } } -GC_DECLARE_PROC(gcs_fft_1d_r2, "fft_1d_r2"); +GC_DECLARE_PROC(gcs_fwd_fft_1d_r2, "fwd_fft_1d_r2"); + +static void +gcs_inv_fft_1d_r2(const gc_job_direct_args_t *input, + gc_job_direct_args_t *output __attribute__((unused)), + const gc_job_ea_args_t *eaa) +{ + vector float *out = (vector float *) eaa->arg[0].ls_addr; // complex + vector float *in = (vector float *) eaa->arg[1].ls_addr; // complex + vector float *twiddle = (vector float *) eaa->arg[2].ls_addr; // complex + vector float *window = (vector float *) eaa->arg[3].ls_addr; // float + + int log2_fft_length = input->arg[0].u32; + int shift = input->arg[1].u32; // non-zero if we should apply fftshift + + if (eaa->arg[3].get_size){ // apply window + // FIXME pointwise multiply in *= window + assert(0); + } + + if (shift){ + // FIXME apply "fftshift" to input data in-place + assert(0); + } + + conjugate_vector(in, 1 << (log2_fft_length - 1)); + fft_1d_r2(out, in, twiddle, log2_fft_length); + conjugate_vector(out, 1 << (log2_fft_length - 1)); +} + +GC_DECLARE_PROC(gcs_inv_fft_1d_r2, "inv_fft_1d_r2"); diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index b499ee670..05ea84e12 100644 --- a/gnuradio-core/src/lib/general/Makefile.am +++ b/gnuradio-core/src/lib/general/Makefile.am @@ -72,6 +72,7 @@ libgeneral_la_SOURCES = \ gr_feedforward_agc_cc.cc \ gr_feval.cc \ gr_fft_vcc.cc \ + gr_fft_vcc_fftw.cc \ gr_fft_vfc.cc \ gr_firdes.cc \ gr_float_to_char.cc \ @@ -215,6 +216,7 @@ grinclude_HEADERS = \ gr_feedforward_agc_cc.h \ gr_feval.h \ gr_fft_vcc.h \ + gr_fft_vcc_fftw.h \ gr_fft_vfc.h \ gr_firdes.h \ gr_float_to_char.h \ diff --git a/gnuradio-core/src/lib/general/gr_fft_vcc.cc b/gnuradio-core/src/lib/general/gr_fft_vcc.cc index 3806041de..05de7fbd4 100644 --- a/gnuradio-core/src/lib/general/gr_fft_vcc.cc +++ b/gnuradio-core/src/lib/general/gr_fft_vcc.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2007 Free Software Foundation, Inc. + * Copyright 2004,2007,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,90 +24,35 @@ #include "config.h" #endif -#include <gr_fft_vcc.h> +#include <gr_fft_vcc.h> // abstract class +#include <gr_fft_vcc_fftw.h> // concrete class #include <gr_io_signature.h> #include <gri_fft.h> #include <math.h> gr_fft_vcc_sptr -gr_make_fft_vcc (int fft_size, bool forward,const std::vector<float> window, bool shift) +gr_make_fft_vcc (int fft_size, bool forward,const std::vector<float> &window, bool shift) { - return gr_fft_vcc_sptr (new gr_fft_vcc (fft_size, forward, window, shift)); + return gr_make_fft_vcc_fftw(fft_size, forward, window, shift); } -gr_fft_vcc::gr_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift) - : gr_sync_block ("fft_vcc", +gr_fft_vcc::gr_fft_vcc (const std::string &name, + int fft_size, bool forward, const std::vector<float> &window, + bool shift) + : gr_sync_block (name, gr_make_io_signature (1, 1, fft_size * sizeof (gr_complex)), gr_make_io_signature (1, 1, fft_size * sizeof (gr_complex))), d_fft_size(fft_size), d_forward(forward), d_shift(shift) { - d_fft = new gri_fft_complex (d_fft_size, forward); - set_window(window); - } gr_fft_vcc::~gr_fft_vcc () { - delete d_fft; -} - -int -gr_fft_vcc::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const gr_complex *in = (const gr_complex *) input_items[0]; - gr_complex *out = (gr_complex *) output_items[0]; - - unsigned int input_data_size = input_signature()->sizeof_stream_item (0); - unsigned int output_data_size = output_signature()->sizeof_stream_item (0); - - int count = 0; - - while (count++ < noutput_items){ - - // copy input into optimally aligned buffer - - if (d_window.size()){ - gr_complex *dst = d_fft->get_inbuf(); - for (unsigned int i = 0; i < d_fft_size; i++) // apply window - dst[i] = in[i] * d_window[i]; - } - else { - if(!d_forward && d_shift) { // apply an ifft shift on the data - gr_complex *dst = d_fft->get_inbuf(); - unsigned int len = (unsigned int)(floor(d_fft_size/2.0)); // half length of complex array - memcpy(&dst[0], &in[len], sizeof(gr_complex)*(d_fft_size - len)); - memcpy(&dst[d_fft_size - len], &in[0], sizeof(gr_complex)*len); - } - else { - memcpy (d_fft->get_inbuf(), in, input_data_size); - } - } - - // compute the fft - d_fft->execute (); - - // copy result to our output - if(d_forward && d_shift) { // apply a fft shift on the data - unsigned int len = (unsigned int)(ceil(d_fft_size/2.0)); - memcpy(&out[0], &d_fft->get_outbuf()[len], sizeof(gr_complex)*(d_fft_size - len)); - memcpy(&out[d_fft_size - len], &d_fft->get_outbuf()[0], sizeof(gr_complex)*len); - } - else { - memcpy (out, d_fft->get_outbuf (), output_data_size); - } - - in += d_fft_size; - out += d_fft_size; - } - - return noutput_items; } bool -gr_fft_vcc::set_window(const std::vector<float> window) +gr_fft_vcc::set_window(const std::vector<float> &window) { if(window.size()==0 || window.size()==d_fft_size) { d_window=window; @@ -116,18 +61,3 @@ gr_fft_vcc::set_window(const std::vector<float> window) else return false; } - -/* -fftshift - - for(i=0; i < ceil(d_occupied_carriers/2.0); i++) { - unsigned int k=ceil(d_occupied_carriers/2.0); - out[i] = gr_complex(-1+2*in[i+k],0); - } - for(; i < d_vlen - ceil(d_occupied_carriers/2.0); i++) { - out[i]=gr_complex(0,0); - } - for(unsigned int j=0;i<d_vlen;i++,j++) { - out[i]= gr_complex((-1+2*in[j]),0); - } -*/ diff --git a/gnuradio-core/src/lib/general/gr_fft_vcc.h b/gnuradio-core/src/lib/general/gr_fft_vcc.h index 71fe17353..705cbdd64 100644 --- a/gnuradio-core/src/lib/general/gr_fft_vcc.h +++ b/gnuradio-core/src/lib/general/gr_fft_vcc.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2007 Free Software Foundation, Inc. + * Copyright 2004,2007,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -25,40 +25,36 @@ #include <gr_sync_block.h> -class gri_fft_complex; - class gr_fft_vcc; typedef boost::shared_ptr<gr_fft_vcc> gr_fft_vcc_sptr; gr_fft_vcc_sptr -gr_make_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift=false); +gr_make_fft_vcc (int fft_size, bool forward, const std::vector<float> &window, bool shift=false); /*! * \brief Compute forward or reverse FFT. complex vector in / complex vector out. * \ingroup dft + * + * Abstract base class */ - class gr_fft_vcc : public gr_sync_block { +protected: friend gr_fft_vcc_sptr - gr_make_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift); + gr_make_fft_vcc (int fft_size, bool forward, const std::vector<float> &window, bool shift); - unsigned int d_fft_size; + unsigned int d_fft_size; std::vector<float> d_window; - gri_fft_complex *d_fft; bool d_forward; bool d_shift; - gr_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift); + gr_fft_vcc (const std::string &name, int fft_size, bool forward, + const std::vector<float> &window, bool shift); public: ~gr_fft_vcc (); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - bool set_window(const std::vector<float> window); + bool set_window(const std::vector<float> &window); }; - #endif /* INCLUDED_GR_FFT_VCC_H */ diff --git a/gnuradio-core/src/lib/general/gr_fft_vcc.i b/gnuradio-core/src/lib/general/gr_fft_vcc.i index 49ea4e451..247571374 100644 --- a/gnuradio-core/src/lib/general/gr_fft_vcc.i +++ b/gnuradio-core/src/lib/general/gr_fft_vcc.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2007 Free Software Foundation, Inc. + * Copyright 2004,2007,2008 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -28,8 +28,8 @@ gr_make_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bo class gr_fft_vcc : public gr_sync_block { protected: - gr_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift); + gr_fft_vcc (int fft_size, bool forward, const std::vector<float> &window, bool shift); public: - bool set_window(const std::vector<float> window); + bool set_window(const std::vector<float> &window); }; diff --git a/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc b/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc new file mode 100644 index 000000000..a70be014c --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.cc @@ -0,0 +1,103 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_fft_vcc_fftw.h> +#include <gr_io_signature.h> +#include <gri_fft.h> +#include <math.h> + +gr_fft_vcc_sptr +gr_make_fft_vcc_fftw (int fft_size, bool forward, const std::vector<float> &window, bool shift) +{ + return gr_fft_vcc_sptr (new gr_fft_vcc_fftw (fft_size, forward, window, shift)); +} + +gr_fft_vcc_fftw::gr_fft_vcc_fftw (int fft_size, bool forward, + const std::vector<float> &window, bool shift) + : gr_fft_vcc("fft_vcc_fftw", fft_size, forward, window, shift) +{ + d_fft = new gri_fft_complex (d_fft_size, forward); +} + +gr_fft_vcc_fftw::~gr_fft_vcc_fftw () +{ + delete d_fft; +} + +int +gr_fft_vcc_fftw::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + unsigned int input_data_size = input_signature()->sizeof_stream_item (0); + unsigned int output_data_size = output_signature()->sizeof_stream_item (0); + + int count = 0; + + while (count++ < noutput_items){ + + // copy input into optimally aligned buffer + + if (d_window.size()){ + gr_complex *dst = d_fft->get_inbuf(); + for (unsigned int i = 0; i < d_fft_size; i++) // apply window + dst[i] = in[i] * d_window[i]; + } + else { + if(!d_forward && d_shift) { // apply an ifft shift on the data + gr_complex *dst = d_fft->get_inbuf(); + unsigned int len = (unsigned int)(floor(d_fft_size/2.0)); // half length of complex array + memcpy(&dst[0], &in[len], sizeof(gr_complex)*(d_fft_size - len)); + memcpy(&dst[d_fft_size - len], &in[0], sizeof(gr_complex)*len); + } + else { + memcpy (d_fft->get_inbuf(), in, input_data_size); + } + } + + // compute the fft + d_fft->execute (); + + // copy result to our output + if(d_forward && d_shift) { // apply a fft shift on the data + unsigned int len = (unsigned int)(ceil(d_fft_size/2.0)); + memcpy(&out[0], &d_fft->get_outbuf()[len], sizeof(gr_complex)*(d_fft_size - len)); + memcpy(&out[d_fft_size - len], &d_fft->get_outbuf()[0], sizeof(gr_complex)*len); + } + else { + memcpy (out, d_fft->get_outbuf (), output_data_size); + } + + in += d_fft_size; + out += d_fft_size; + } + + return noutput_items; +} + diff --git a/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.h b/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.h new file mode 100644 index 000000000..93c8d3cce --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_fft_vcc_fftw.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2008 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_GR_FFT_VCC_FFTW_H +#define INCLUDED_GR_FFT_VCC_FFTW_H + +#include <gr_fft_vcc.h> + +class gri_fft_complex; + +gr_fft_vcc_sptr +gr_make_fft_vcc_fftw (int fft_size, bool forward, const std::vector<float> &window, bool shift=false); + +/*! + * \brief Compute forward or reverse FFT. complex vector in / complex vector out. + * \ingroup dft + * + * Concrete class that uses FFTW. + */ +class gr_fft_vcc_fftw : public gr_fft_vcc +{ + friend gr_fft_vcc_sptr + gr_make_fft_vcc_fftw (int fft_size, bool forward, const std::vector<float> &window, bool shift); + + gri_fft_complex *d_fft; + + gr_fft_vcc_fftw (int fft_size, bool forward, const std::vector<float> &window, bool shift); + + public: + ~gr_fft_vcc_fftw (); + + int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + + +#endif /* INCLUDED_GR_FFT_VCC_FFTW_H */ diff --git a/gnuradio-core/src/lib/general/gr_math.h b/gnuradio-core/src/lib/general/gr_math.h index 36392116e..74ac6086a 100644 --- a/gnuradio-core/src/lib/general/gr_math.h +++ b/gnuradio-core/src/lib/general/gr_math.h @@ -29,6 +29,12 @@ #include <gr_complex.h> +static inline bool +gr_is_power_of_2(long x) +{ + return x != 0 && (x & (x-1)) == 0; +} + long gr_gcd (long m, long n); // returns a non-zero value if value is "not-a-number" (NaN), and 0 otherwise diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am index 4f952d127..3d98bcd40 100644 --- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am @@ -58,6 +58,7 @@ noinst_PYTHON = \ qa_diff_phasor_cc.py \ qa_ecc_ccsds_27.py \ qa_feval.py \ + qa_fft.py \ qa_fft_filter.py \ qa_filter_delay_fc.py \ qa_fractional_interpolator.py \ diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_fft.py b/gnuradio-core/src/python/gnuradio/gr/qa_fft.py new file mode 100755 index 000000000..412c4c48b --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/qa_fft.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# +# Copyright 2008 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. +# + +from gnuradio import gr, gr_unittest +import sys +import random + +primes = (2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53, + 59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131, + 137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223, + 227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311) + + +class test_fft_filter(gr_unittest.TestCase): + + def setUp(self): + pass + + def tearDown(self): + pass + + def assert_fft_ok2(self, expected_result, result_data): + expected_result = expected_result[:len(result_data)] + self.assertComplexTuplesAlmostEqual2 (expected_result, result_data, + abs_eps=1e-9, rel_eps=4e-4) + + def assert_fft_float_ok2(self, expected_result, result_data, abs_eps=1e-9, rel_eps=4e-4): + expected_result = expected_result[:len(result_data)] + self.assertFloatTuplesAlmostEqual2 (expected_result, result_data, + abs_eps, rel_eps) + + def test_001(self): + tb = gr.top_block() + fft_size = 32 + src_data = tuple([complex(primes[2*i], primes[2*i+1]) for i in range(fft_size)]) + + expected_result = ((4377+4516j), + (-1706.1268310546875+1638.4256591796875j), + (-915.2083740234375+660.69427490234375j), + (-660.370361328125+381.59600830078125j), + (-499.96044921875+238.41630554199219j), + (-462.26748657226562+152.88948059082031j), + (-377.98440551757812+77.5928955078125j), + (-346.85821533203125+47.152004241943359j), + (-295+20j), + (-286.33609008789062-22.257017135620117j), + (-271.52999877929688-33.081821441650391j), + (-224.6358642578125-67.019538879394531j), + (-244.24473571777344-91.524826049804688j), + (-203.09068298339844-108.54627227783203j), + (-198.45195007324219-115.90768432617188j), + (-182.97744750976562-128.12318420410156j), + (-167-180j), + (-130.33688354492188-173.83778381347656j), + (-141.19784545898438-190.28807067871094j), + (-111.09677124023438-214.48896789550781j), + (-70.039543151855469-242.41630554199219j), + (-68.960540771484375-228.30015563964844j), + (-53.049201965332031-291.47097778320312j), + (-28.695289611816406-317.64553833007812j), + (57-300j), + (45.301143646240234-335.69509887695312j), + (91.936195373535156-373.32437133789062j), + (172.09465026855469-439.275146484375j), + (242.24473571777344-504.47515869140625j), + (387.81732177734375-666.6788330078125j), + (689.48553466796875-918.2142333984375j), + (1646.539306640625-1694.1956787109375j)) + + src = gr.vector_source_c(src_data) + s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + fft = gr.fft_vcc(fft_size, True, [], False) + v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + dst = gr.vector_sink_c() + tb.connect(src, s2v, fft, v2s, dst) + tb.run() + result_data = dst.data() + #print 'expected:', expected_result + #print 'results: ', result_data + #self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5) + self.assert_fft_ok2(expected_result, result_data) + + def test_002(self): + tb = gr.top_block() + fft_size = 32 + + tmp_data = ((4377+4516j), + (-1706.1268310546875+1638.4256591796875j), + (-915.2083740234375+660.69427490234375j), + (-660.370361328125+381.59600830078125j), + (-499.96044921875+238.41630554199219j), + (-462.26748657226562+152.88948059082031j), + (-377.98440551757812+77.5928955078125j), + (-346.85821533203125+47.152004241943359j), + (-295+20j), + (-286.33609008789062-22.257017135620117j), + (-271.52999877929688-33.081821441650391j), + (-224.6358642578125-67.019538879394531j), + (-244.24473571777344-91.524826049804688j), + (-203.09068298339844-108.54627227783203j), + (-198.45195007324219-115.90768432617188j), + (-182.97744750976562-128.12318420410156j), + (-167-180j), + (-130.33688354492188-173.83778381347656j), + (-141.19784545898438-190.28807067871094j), + (-111.09677124023438-214.48896789550781j), + (-70.039543151855469-242.41630554199219j), + (-68.960540771484375-228.30015563964844j), + (-53.049201965332031-291.47097778320312j), + (-28.695289611816406-317.64553833007812j), + (57-300j), + (45.301143646240234-335.69509887695312j), + (91.936195373535156-373.32437133789062j), + (172.09465026855469-439.275146484375j), + (242.24473571777344-504.47515869140625j), + (387.81732177734375-666.6788330078125j), + (689.48553466796875-918.2142333984375j), + (1646.539306640625-1694.1956787109375j)) + + src_data = tuple([x/fft_size for x in tmp_data]) + + expected_result = tuple([complex(primes[2*i], primes[2*i+1]) for i in range(fft_size)]) + + src = gr.vector_source_c(src_data) + s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + fft = gr.fft_vcc(fft_size, False, [], False) + v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + dst = gr.vector_sink_c() + tb.connect(src, s2v, fft, v2s, dst) + tb.run() + result_data = dst.data() + #print 'expected:', expected_result + #print 'results: ', result_data + #self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5) + self.assert_fft_ok2(expected_result, result_data) + + +if __name__ == '__main__': + gr_unittest.main () + diff --git a/gr-gcell/Makefile.am b/gr-gcell/Makefile.am new file mode 100644 index 000000000..2386f80ae --- /dev/null +++ b/gr-gcell/Makefile.am @@ -0,0 +1,24 @@ +# +# Copyright 2008 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. +# + +include $(top_srcdir)/Makefile.common + +SUBDIRS = src + diff --git a/gr-gcell/src/Makefile.am b/gr-gcell/src/Makefile.am new file mode 100644 index 000000000..8b1e09ea1 --- /dev/null +++ b/gr-gcell/src/Makefile.am @@ -0,0 +1,130 @@ +# +# Copyright 2008 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. +# + +include $(top_srcdir)/Makefile.common + +SUBDIRS = . examples + +EXTRA_DIST = run_tests.in +TESTS = run_tests + + +# Install the python portion so that it ends up as the gnuradio.gcell module +# ${prefix}/lib/python${python_version}/site-packages/gnuradio + +ourpythondir = $(grpythondir) +ourlibdir = $(grpyexecdir) + +AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(GCELL_INCLUDES) $(PYTHON_CPPFLAGS) $(WITH_INCLUDES) + +SWIGPYTHONARGS = $(SWIGPYTHONFLAGS) $(STD_DEFINES_AND_INCLUDES) $(GCELL_INCLUDES) \ + $(WITH_SWIG_INCLUDES) $(WITH_INCLUDES) + +# ---------------------------------------------------------------- +# The C++ blocks +# ---------------------------------------------------------------- + +# the library for the C++ blocks +lib_LTLIBRARIES = libgr_gcell.la + +libgr_gcell_la_SOURCES = \ + gcell_fft_vcc.cc + +grinclude_HEADERS = \ + gcell_fft_vcc.h + +libgr_gcell_la_LIBADD = \ + $(GNURADIO_CORE_LA) \ + $(GCELL_LA) + +libgr_gcell_la_LDFLAGS = $(NO_UNDEFINED) + + +# ---------------------------------------------------------------- +# SWIG stuff +# ---------------------------------------------------------------- + +# the library for the swig interface +ourlib_LTLIBRARIES = _gcell.la + +LOCAL_IFILES = \ + $(top_srcdir)/gr-gcell/src/gcell.i + +NON_LOCAL_IFILES = \ + $(GNURADIO_I) + +ALL_IFILES = \ + $(LOCAL_IFILES) \ + $(NON_LOCAL_IFILES) + +swig_built_sources = \ + gcell.cc \ + gcell.py + +ourpython_PYTHON = \ + gcell.py + +_gcell_la_SOURCES = \ + gcell.cc + +_gcell_la_LIBADD = \ + $(PYTHON_LDFLAGS) \ + libgr_gcell.la \ + -lstdc++ + +_gcell_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version + + +swiginclude_HEADERS = \ + $(LOCAL_IFILES) + +#gcell.cc gcell.py: $(LOCAL_IFILES) $(NON_LOCAL_IFILES) +# $(SWIG) $(SWIGPYTHONARGS) -module gcell -o gcell.cc $(LOCAL_IFILES) + +# KLUDGE: Force runtime include of gcell.d dependency file. +# This is not guaranteed to be portable, but will probably work. +# If it works, we have accurate dependencies for our swig stuff, which is good. +@am__include@ @am__quote@./gcell.d@am__quote@ + +gcell.py gcell.h: gcell.cc + +gcell.cc : gcell.i $(GNURADIO_I) + if $(SWIG) $(SWIGPYTHONARGS) -MMD -MF gcell.Td -module gcell -o gcell.cc $(srcdir)/gcell.i ;\ + then if test $(host_os) = mingw32; \ + then sed 's,\\\\,/,g' <gcell.Td >gcell.d; rm -f gcell.Td; \ + else mv -f gcell.Td gcell.d; fi \ + else rm -f gcell.Td; exit 1; fi + + +noinst_PYTHON = \ + qa_gcell.py + +# ---------------------------------------------------------------- + +MOSTLYCLEANFILES = \ + $(swig_built_sources) *~ *.pyc + +# Don't distribute output of swig +dist-hook: + @for file in $(swig_built_sources); do echo $(RM) $(distdir)/$$file; done + @for file in $(swig_built_sources); do $(RM) $(distdir)/$$file; done + +DISTCLEANFILES = \ + gcell.d diff --git a/gr-gcell/src/examples/Makefile.am b/gr-gcell/src/examples/Makefile.am new file mode 100644 index 000000000..d10c3dad6 --- /dev/null +++ b/gr-gcell/src/examples/Makefile.am @@ -0,0 +1,42 @@ +# +# Copyright 2008 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +include $(top_srcdir)/Makefile.common + +#EXTRA_DIST = \ +# README \ +# fsm_utils.py + + +ourdatadir = $(exampledir)/gcell +ourdata_DATA = $(EXTRA_DIST) + +# Make example scripts with #! executable +install-data-local: install-ourdataDATA + for i in `find $(ourdatadir) -type f ! -perm 755`; do \ + if head -1 $$i | grep -q '^#!'; then \ + chmod 755 $$i; \ + echo "made executable: $$i"; \ + fi; \ + done + +MOSTLYCLEANFILES = *.pyc + diff --git a/gr-gcell/src/gc_job_manager.i b/gr-gcell/src/gc_job_manager.i new file mode 100644 index 000000000..7bec48e19 --- /dev/null +++ b/gr-gcell/src/gc_job_manager.i @@ -0,0 +1,75 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +struct spe_program_handle_t; +typedef boost::shared_ptr<spe_program_handle_t> spe_program_handle_sptr; +%template(spe_program_handle_sptr) boost::shared_ptr<spe_program_handle_t>; + +class gc_job_manager; +typedef boost::shared_ptr<gc_job_manager> gc_job_manager_sptr; +%template(gc_job_manager_sptr) boost::shared_ptr<gc_job_manager>; + + +%rename(program_handle_from_filename) gc_program_handle_from_filename; +spe_program_handle_sptr +gc_program_handle_from_filename(const std::string &filename); + +%rename(program_handle_from_address) gc_program_handle_from_address; +spe_program_handle_sptr +gc_program_handle_from_address(spe_program_handle_t *handle); + + +%rename(jm_options) gc_jm_options; +struct gc_jm_options { + unsigned int max_jobs; // max # of job descriptors in system + unsigned int max_client_threads; // max # of client threads of job manager + unsigned int nspes; // how many SPEs shall we use? 0 -> all of them + bool gang_schedule; // shall we gang schedule? + bool use_affinity; // shall we try for affinity (FIXME not implmented) + bool enable_logging; // shall we log SPE events? + uint32_t log2_nlog_entries; // log2 of number of log entries (default is 12 == 4k) + spe_program_handle_sptr program_handle; // program to load into SPEs + + gc_jm_options(spe_program_handle_sptr program_handle_, + unsigned int nspes_ = 0) : + max_jobs(0), max_client_threads(0), nspes(nspes_), + gang_schedule(false), use_affinity(false), + enable_logging(false), log2_nlog_entries(12), + program_handle(program_handle_) + { + } +}; + +%rename(job_manager) gc_make_job_manager; +gc_job_manager_sptr +gc_make_job_manager(const gc_jm_options *options); + +%inline { + void set_singleton(gc_job_manager_sptr mgr) + { + gc_job_manager::set_singleton(mgr); + } + + gc_job_manager_sptr singleton() + { + return gc_job_manager::singleton(); + } +} diff --git a/gr-gcell/src/gcell.i b/gr-gcell/src/gcell.i new file mode 100644 index 000000000..23f602895 --- /dev/null +++ b/gr-gcell/src/gcell.i @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +%feature("autodoc","1"); + +//%include "exception.i" +%import "gnuradio.i" // the common stuff + +%{ +#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix +//#include <stdexcept> + +#include <gc_job_manager.h> +#include <gcell_fft_vcc.h> + +%} + +%include "gc_job_manager.i" +%include "gcell_fft_vcc.i" diff --git a/gr-gcell/src/gcell_fft_vcc.cc b/gr-gcell/src/gcell_fft_vcc.cc new file mode 100644 index 000000000..4b781696d --- /dev/null +++ b/gr-gcell/src/gcell_fft_vcc.cc @@ -0,0 +1,159 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2008 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 <gcell_fft_vcc.h> +#include <gr_io_signature.h> +#include <gc_job_manager.h> +#include <gc_aligned_alloc.h> +#include <gcp_fft_1d_r2.h> +#include <math.h> +#include <assert.h> +#include <stdexcept> + + +#define MIN_FFT_SIZE 32 +#define MAX_FFT_SIZE 4096 + +inline static bool +is_power_of_2(int x) +{ + return x != 0 && (x & (x-1)) == 0; +} + +static int +log2(int x) // x is an exact power of 2 +{ + for (int i = 0; i < 32; i++) + if (x == (1 << i)) + return i; + + assert(0); +} + +#if 0 +gr_fft_vcc_sptr +gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift) +{ + // If it doesn't meet our constraints, use standard implemenation + if (fft_size < MIN_FFT_SIZE || fft_size > MAX_FFT_SIZE + || !is_power_of_2(fft_size) + || (window.size() != 0 && fft_size > MAX_FFT_SIZE/2)) + return gr_make_fft_vcc(fft_size, forward, window, shift); + else + return gr_fft_vcc_sptr (new gcell_fft_vcc(fft_size, forward, window, shift)); +} +#else + +gcell_fft_vcc_sptr +gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift) +{ + return gcell_fft_vcc_sptr (new gcell_fft_vcc(fft_size, forward, window, shift)); +} + +#endif + +gcell_fft_vcc::gcell_fft_vcc (int fft_size, bool forward, + const std::vector<float> &window, bool shift) + : gr_fft_vcc("gcell_fft_vcc", fft_size, forward, window, shift) +{ + if (fft_size < MIN_FFT_SIZE || fft_size > MAX_FFT_SIZE || !is_power_of_2(fft_size)){ + throw std::invalid_argument("fft_size"); + } + + if (window.size() != 0 && fft_size > MAX_FFT_SIZE/2){ + throw std::invalid_argument("fft_size too big to use window"); + } + + d_log2_fft_size = log2(fft_size); + d_mgr = gc_job_manager::singleton(); // grab the singleton job manager + d_twiddle_boost = gc_aligned_alloc_sptr(sizeof(std::complex<float>) * fft_size/4, 128); + d_twiddle = (std::complex<float>*) d_twiddle_boost.get(); + gcp_fft_1d_r2_twiddle(d_log2_fft_size, d_twiddle); +} + +gcell_fft_vcc::~gcell_fft_vcc () +{ +} + +int +gcell_fft_vcc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + // unsigned int input_data_size = input_signature()->sizeof_stream_item(0); + // unsigned int output_data_size = output_signature()->sizeof_stream_item(0); + + float window_buf[MAX_FFT_SIZE/2] __attribute__((aligned (16))); + float *window = 0; + + // If we've got a window, ensure it's 16-byte aligned + // FIXME move this to set_window + if (d_window.size()){ + if ((((intptr_t)&d_window[0]) & 0xf) == 0) + window = &d_window[0]; // OK as is + else { + window = window_buf; // copy to aligned buffer + memcpy(window, &d_window[0], sizeof(float) * d_window.size()); + } + } + + std::vector<gc_job_desc_sptr> jd_sptr(noutput_items); + gc_job_desc *jd[noutput_items]; + bool done[noutput_items]; + + // submit noutput_items jobs in parallel + + for (int i = 0; i < noutput_items; i++){ + jd_sptr[i] = gcp_fft_1d_r2_submit(d_mgr, d_log2_fft_size, + d_forward, d_shift, + &out[i * d_fft_size], + &in[i * d_fft_size], + d_twiddle, + window); + jd[i] = jd_sptr[i].get(); + } + + int n = d_mgr->wait_jobs(noutput_items, jd, done, GC_WAIT_ALL); + if (n != noutput_items){ + fprintf(stderr, "gcell_fft_vcc: wait_jobs returned %d, expected %d\n", + n, noutput_items); + return -1; + } + + for (int i = 0; i < noutput_items; i++){ + if (jd[i]->status != JS_OK){ + fprintf(stderr, "gcell_fft_vcc jd[%d]->status = %s\n", + i, gc_job_status_string(jd[i]->status).c_str()); + return -1; + } + } + + return noutput_items; +} + diff --git a/gr-gcell/src/gcell_fft_vcc.h b/gr-gcell/src/gcell_fft_vcc.h new file mode 100644 index 000000000..2cf13b33d --- /dev/null +++ b/gr-gcell/src/gcell_fft_vcc.h @@ -0,0 +1,63 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2008 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_GCELL_FFT_VCC_H +#define INCLUDED_GCELL_FFT_VCC_H + +#include <gr_fft_vcc.h> + +class gc_job_manager; + +class gcell_fft_vcc; +typedef boost::shared_ptr<gcell_fft_vcc> gcell_fft_vcc_sptr; + +gcell_fft_vcc_sptr +gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift=false); + +/*! + * \brief Compute forward or reverse FFT. complex vector in / complex vector out. + * \ingroup dft + * + * Concrete class that uses gcell to offload FFT to SPEs. + */ +class gcell_fft_vcc : public gr_fft_vcc +{ + int d_log2_fft_size; + boost::shared_ptr<gc_job_manager> d_mgr; + std::complex<float> *d_twiddle; // twiddle values (16-byte aligned) + boost::shared_ptr<void> d_twiddle_boost; // automatic storage mgmt + + friend gcell_fft_vcc_sptr + gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift); + + gcell_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift); + + public: + ~gcell_fft_vcc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + + +#endif /* INCLUDED_GCELL_FFT_VCC_H */ diff --git a/gr-gcell/src/gcell_fft_vcc.i b/gr-gcell/src/gcell_fft_vcc.i new file mode 100644 index 000000000..1d4a359f9 --- /dev/null +++ b/gr-gcell/src/gcell_fft_vcc.i @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 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. + */ + +#if 1 + +// This version works. + +GR_SWIG_BLOCK_MAGIC(gcell, fft_vcc) + +gcell_fft_vcc_sptr +gcell_make_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift=false); + +class gcell_fft_vcc : public gr_sync_block +{ + protected: + gcell_fft_vcc (int fft_size, bool forward, const std::vector<float> &window, bool shift); + + public: + bool set_window(const std::vector<float> &window); +}; + +#else + +// This version gives swig heartburn. We end up with an object that's +// not quite usable. + +GR_SWIG_BLOCK_MAGIC(gcell, fft_vcc); + +gcell_fft_vcc_sptr +gcell_make_fft_vcc (int fft_size, bool forward, const std::vector<float> window, bool shift=false); + +class gcell_fft_vcc : public gr_fft_vcc +{ + protected: + gr_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift); +}; + +#endif diff --git a/gr-gcell/src/qa_fft.py b/gr-gcell/src/qa_fft.py new file mode 100755 index 000000000..d95b76c4c --- /dev/null +++ b/gr-gcell/src/qa_fft.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# +# Copyright 2008 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. +# + +from gnuradio import gr, gr_unittest +import gcell +import sys +import random + +primes = (2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53, + 59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131, + 137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223, + 227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311) + + +class test_fft_filter(gr_unittest.TestCase): + + def setUp(self): + ph = gcell.program_handle_from_filename("../../gcell/src/lib/spu/gcell_all") + opts = gcell.jm_options(ph, 1) + self.mgr = gcell.job_manager(opts) + gcell.set_singleton(self.mgr) + + def tearDown(self): + pass + + def assert_fft_ok2(self, expected_result, result_data): + expected_result = expected_result[:len(result_data)] + self.assertComplexTuplesAlmostEqual2 (expected_result, result_data, + abs_eps=1e-9, rel_eps=4e-4) + + def assert_fft_float_ok2(self, expected_result, result_data, abs_eps=1e-9, rel_eps=4e-4): + expected_result = expected_result[:len(result_data)] + self.assertFloatTuplesAlmostEqual2 (expected_result, result_data, + abs_eps, rel_eps) + + def test_001(self): + tb = gr.top_block() + fft_size = 32 + src_data = tuple([complex(primes[2*i], primes[2*i+1]) for i in range(fft_size)]) + + expected_result = ((4377+4516j), + (-1706.1268310546875+1638.4256591796875j), + (-915.2083740234375+660.69427490234375j), + (-660.370361328125+381.59600830078125j), + (-499.96044921875+238.41630554199219j), + (-462.26748657226562+152.88948059082031j), + (-377.98440551757812+77.5928955078125j), + (-346.85821533203125+47.152004241943359j), + (-295+20j), + (-286.33609008789062-22.257017135620117j), + (-271.52999877929688-33.081821441650391j), + (-224.6358642578125-67.019538879394531j), + (-244.24473571777344-91.524826049804688j), + (-203.09068298339844-108.54627227783203j), + (-198.45195007324219-115.90768432617188j), + (-182.97744750976562-128.12318420410156j), + (-167-180j), + (-130.33688354492188-173.83778381347656j), + (-141.19784545898438-190.28807067871094j), + (-111.09677124023438-214.48896789550781j), + (-70.039543151855469-242.41630554199219j), + (-68.960540771484375-228.30015563964844j), + (-53.049201965332031-291.47097778320312j), + (-28.695289611816406-317.64553833007812j), + (57-300j), + (45.301143646240234-335.69509887695312j), + (91.936195373535156-373.32437133789062j), + (172.09465026855469-439.275146484375j), + (242.24473571777344-504.47515869140625j), + (387.81732177734375-666.6788330078125j), + (689.48553466796875-918.2142333984375j), + (1646.539306640625-1694.1956787109375j)) + + src = gr.vector_source_c(src_data) + s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + fft = gcell.fft_vcc(fft_size, True, [], False) + v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + dst = gr.vector_sink_c() + tb.connect(src, s2v, fft, v2s, dst) + tb.run() + result_data = dst.data() + #print 'expected:', expected_result + #print 'results: ', result_data + #self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5) + self.assert_fft_ok2(expected_result, result_data) + + def test_002(self): + tb = gr.top_block() + fft_size = 32 + + tmp_data = ((4377+4516j), + (-1706.1268310546875+1638.4256591796875j), + (-915.2083740234375+660.69427490234375j), + (-660.370361328125+381.59600830078125j), + (-499.96044921875+238.41630554199219j), + (-462.26748657226562+152.88948059082031j), + (-377.98440551757812+77.5928955078125j), + (-346.85821533203125+47.152004241943359j), + (-295+20j), + (-286.33609008789062-22.257017135620117j), + (-271.52999877929688-33.081821441650391j), + (-224.6358642578125-67.019538879394531j), + (-244.24473571777344-91.524826049804688j), + (-203.09068298339844-108.54627227783203j), + (-198.45195007324219-115.90768432617188j), + (-182.97744750976562-128.12318420410156j), + (-167-180j), + (-130.33688354492188-173.83778381347656j), + (-141.19784545898438-190.28807067871094j), + (-111.09677124023438-214.48896789550781j), + (-70.039543151855469-242.41630554199219j), + (-68.960540771484375-228.30015563964844j), + (-53.049201965332031-291.47097778320312j), + (-28.695289611816406-317.64553833007812j), + (57-300j), + (45.301143646240234-335.69509887695312j), + (91.936195373535156-373.32437133789062j), + (172.09465026855469-439.275146484375j), + (242.24473571777344-504.47515869140625j), + (387.81732177734375-666.6788330078125j), + (689.48553466796875-918.2142333984375j), + (1646.539306640625-1694.1956787109375j)) + + src_data = tuple([x/fft_size for x in tmp_data]) + + expected_result = tuple([complex(primes[2*i], primes[2*i+1]) for i in range(fft_size)]) + + src = gr.vector_source_c(src_data) + s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + fft = gcell.fft_vcc(fft_size, False, [], False) + v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + dst = gr.vector_sink_c() + tb.connect(src, s2v, fft, v2s, dst) + tb.run() + result_data = dst.data() + #print 'expected:', expected_result + #print 'results: ', result_data + #self.assertComplexTuplesAlmostEqual (expected_result, result_data, 5) + self.assert_fft_ok2(expected_result, result_data) + + +if __name__ == '__main__': + gr_unittest.main () + diff --git a/gr-gcell/src/run_tests.in b/gr-gcell/src/run_tests.in new file mode 100644 index 000000000..f7d51750d --- /dev/null +++ b/gr-gcell/src/run_tests.in @@ -0,0 +1,10 @@ +#!/bin/sh + +# 1st parameter is absolute path to component source directory +# 2nd parameter is absolute path to component build directory +# 3rd parameter is path to Python QA directory + +@top_builddir@/run_tests.sh \ + @abs_top_srcdir@/gr-gcell \ + @abs_top_builddir@/gr-gcell \ + @srcdir@ |