summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gr-fft/include/fft/CMakeLists.txt4
-rw-r--r--gr-fft/include/fft/fft.h195
-rw-r--r--gr-fft/include/fft/fft_impl_fft.h189
-rw-r--r--gr-fft/include/fft/goertzel.h (renamed from gr-fft/include/fft/fft_impl_goertzel.h)59
-rw-r--r--gr-fft/lib/CMakeLists.txt4
-rw-r--r--gr-fft/lib/fft.cc338
-rw-r--r--gr-fft/lib/fft_impl_fft.cc330
-rw-r--r--gr-fft/lib/fft_impl_goertzel.cc78
-rw-r--r--gr-fft/lib/fft_vcc_fftw.cc2
-rw-r--r--gr-fft/lib/fft_vcc_fftw.h4
-rw-r--r--gr-fft/lib/fft_vfc_fftw.cc2
-rw-r--r--gr-fft/lib/fft_vfc_fftw.h4
-rw-r--r--gr-fft/lib/goertzel.cc84
-rw-r--r--gr-fft/lib/goertzel_fc_impl.h10
14 files changed, 665 insertions, 638 deletions
diff --git a/gr-fft/include/fft/CMakeLists.txt b/gr-fft/include/fft/CMakeLists.txt
index 33a8a1d21..bce3da674 100644
--- a/gr-fft/include/fft/CMakeLists.txt
+++ b/gr-fft/include/fft/CMakeLists.txt
@@ -22,11 +22,11 @@
########################################################################
install(FILES
api.h
+ fft.h
fft_vcc.h
fft_vfc.h
+ goertzel.h
goertzel_fc.h
- fft_impl_fft.h
- fft_impl_goertzel.h
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/fft
COMPONENT "fft_devel"
)
diff --git a/gr-fft/include/fft/fft.h b/gr-fft/include/fft/fft.h
new file mode 100644
index 000000000..5cc2e21e8
--- /dev/null
+++ b/gr-fft/include/fft/fft.h
@@ -0,0 +1,195 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2008,2012 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 _FFT_FFT_H_
+#define _FFT_FFT_H_
+
+/*
+ * Wrappers for FFTW single precision 1d dft
+ */
+
+#include <fft/api.h>
+#include <gr_complex.h>
+#include <boost/thread.hpp>
+
+namespace gr {
+ namespace fft {
+
+
+ /*! \brief Helper function for allocating complex fft buffers
+ */
+ gr_complex* malloc_complex(int size);
+
+ /*! \brief Helper function for allocating float fft buffers
+ */
+ float* malloc_float(int size);
+
+ /*! \brief Helper function for freeing fft buffers
+ */
+ void free(void *b);
+
+ /*!
+ * \brief Export reference to planner mutex for those apps that
+ * want to use FFTW w/o using the fft_impl_fftw* classes.
+ */
+ class FFT_API planner {
+ public:
+ typedef boost::mutex::scoped_lock scoped_lock;
+ /*!
+ * Return reference to planner mutex
+ */
+ static boost::mutex &mutex();
+ };
+
+ /*!
+ * \brief FFT: complex in, complex out
+ * \ingroup misc
+ */
+ class FFT_API fft_complex {
+ int d_fft_size;
+ int d_nthreads;
+ gr_complex *d_inbuf;
+ gr_complex *d_outbuf;
+ void *d_plan;
+
+ public:
+ fft_complex(int fft_size, bool forward = true, int nthreads=1);
+ virtual ~fft_complex();
+
+ /*
+ * These return pointers to buffers owned by fft_impl_fft_complex
+ * into which input and output take place. It's done this way in
+ * order to ensure optimal alignment for SIMD instructions.
+ */
+ gr_complex *get_inbuf() const { return d_inbuf; }
+ gr_complex *get_outbuf() const { return d_outbuf; }
+
+ int inbuf_length() const { return d_fft_size; }
+ int outbuf_length() const { return d_fft_size; }
+
+ /*!
+ * Set the number of threads to use for caclulation.
+ */
+ void set_nthreads(int n);
+
+ /*!
+ * Get the number of threads being used by FFTW
+ */
+ int nthreads() const { return d_nthreads; }
+
+ /*!
+ * compute FFT. The input comes from inbuf, the output is placed in
+ * outbuf.
+ */
+ void execute();
+ };
+
+ /*!
+ * \brief FFT: real in, complex out
+ * \ingroup misc
+ */
+ class FFT_API fft_real_fwd {
+ int d_fft_size;
+ int d_nthreads;
+ float *d_inbuf;
+ gr_complex *d_outbuf;
+ void *d_plan;
+
+ public:
+ fft_real_fwd (int fft_size, int nthreads=1);
+ virtual ~fft_real_fwd ();
+
+ /*
+ * These return pointers to buffers owned by fft_impl_fft_real_fwd
+ * into which input and output take place. It's done this way in
+ * order to ensure optimal alignment for SIMD instructions.
+ */
+ float *get_inbuf() const { return d_inbuf; }
+ gr_complex *get_outbuf() const { return d_outbuf; }
+
+ int inbuf_length() const { return d_fft_size; }
+ int outbuf_length() const { return d_fft_size / 2 + 1; }
+
+ /*!
+ * Set the number of threads to use for caclulation.
+ */
+ void set_nthreads(int n);
+
+ /*!
+ * Get the number of threads being used by FFTW
+ */
+ int nthreads() const { return d_nthreads; }
+
+ /*!
+ * compute FFT. The input comes from inbuf, the output is placed in
+ * outbuf.
+ */
+ void execute();
+ };
+
+ /*!
+ * \brief FFT: complex in, float out
+ * \ingroup misc
+ */
+ class FFT_API fft_real_rev {
+ int d_fft_size;
+ int d_nthreads;
+ gr_complex *d_inbuf;
+ float *d_outbuf;
+ void *d_plan;
+
+ public:
+ fft_real_rev(int fft_size, int nthreads=1);
+ virtual ~fft_real_rev();
+
+ /*
+ * These return pointers to buffers owned by fft_impl_fft_real_rev
+ * into which input and output take place. It's done this way in
+ * order to ensure optimal alignment for SIMD instructions.
+ */
+ gr_complex *get_inbuf() const { return d_inbuf; }
+ float *get_outbuf() const { return d_outbuf; }
+
+ int inbuf_length() const { return d_fft_size / 2 + 1; }
+ int outbuf_length() const { return d_fft_size; }
+
+ /*!
+ * Set the number of threads to use for caclulation.
+ */
+ void set_nthreads(int n);
+
+ /*!
+ * Get the number of threads being used by FFTW
+ */
+ int nthreads() const { return d_nthreads; }
+
+ /*!
+ * compute FFT. The input comes from inbuf, the output is placed in
+ * outbuf.
+ */
+ void execute();
+ };
+
+ } /* namespace fft */
+} /*namespace gr */
+
+#endif /* _FFT_FFT_H_ */
diff --git a/gr-fft/include/fft/fft_impl_fft.h b/gr-fft/include/fft/fft_impl_fft.h
deleted file mode 100644
index c27f2ae64..000000000
--- a/gr-fft/include/fft/fft_impl_fft.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2008,2012 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 _FFT_IMPL_FFT_H_
-#define _FFT_IMPL_FFT_H_
-
-/*
- * Wrappers for FFTW single precision 1d dft
- */
-
-#include <fft/api.h>
-#include <gr_complex.h>
-#include <boost/thread.hpp>
-
-/*! \brief Helper function for allocating complex fft buffers
- */
-gr_complex* fft_impl_fft_malloc_complex(int size);
-
-/*! \brief Helper function for allocating float fft buffers
- */
-float* fft_impl_fft_malloc_float(int size);
-
-/*! \brief Helper function for freeing fft buffers
- */
-void fft_impl_fft_free(void *b);
-
-
-/*!
- * \brief Export reference to planner mutex for those apps that
- * want to use FFTW w/o using the fft_impl_fftw* classes.
- */
-class FFT_API fft_impl_fft_planner {
- public:
- typedef boost::mutex::scoped_lock scoped_lock;
- /*!
- * Return reference to planner mutex
- */
- static boost::mutex &mutex();
-};
-
-/*!
- * \brief FFT: complex in, complex out
- * \ingroup misc
- */
-class FFT_API fft_impl_fft_complex {
- int d_fft_size;
- int d_nthreads;
- gr_complex *d_inbuf;
- gr_complex *d_outbuf;
- void *d_plan;
-
-public:
- fft_impl_fft_complex(int fft_size, bool forward = true, int nthreads=1);
- virtual ~fft_impl_fft_complex();
-
- /*
- * These return pointers to buffers owned by fft_impl_fft_complex
- * into which input and output take place. It's done this way in
- * order to ensure optimal alignment for SIMD instructions.
- */
- gr_complex *get_inbuf() const { return d_inbuf; }
- gr_complex *get_outbuf() const { return d_outbuf; }
-
- int inbuf_length() const { return d_fft_size; }
- int outbuf_length() const { return d_fft_size; }
-
- /*!
- * Set the number of threads to use for caclulation.
- */
- void set_nthreads(int n);
-
- /*!
- * Get the number of threads being used by FFTW
- */
- int nthreads() const { return d_nthreads; }
-
- /*!
- * compute FFT. The input comes from inbuf, the output is placed in
- * outbuf.
- */
- void execute();
-};
-
-/*!
- * \brief FFT: real in, complex out
- * \ingroup misc
- */
-class FFT_API fft_impl_fft_real_fwd {
- int d_fft_size;
- int d_nthreads;
- float *d_inbuf;
- gr_complex *d_outbuf;
- void *d_plan;
-
-public:
- fft_impl_fft_real_fwd (int fft_size, int nthreads=1);
- virtual ~fft_impl_fft_real_fwd ();
-
- /*
- * These return pointers to buffers owned by fft_impl_fft_real_fwd
- * into which input and output take place. It's done this way in
- * order to ensure optimal alignment for SIMD instructions.
- */
- float *get_inbuf() const { return d_inbuf; }
- gr_complex *get_outbuf() const { return d_outbuf; }
-
- int inbuf_length() const { return d_fft_size; }
- int outbuf_length() const { return d_fft_size / 2 + 1; }
-
- /*!
- * Set the number of threads to use for caclulation.
- */
- void set_nthreads(int n);
-
- /*!
- * Get the number of threads being used by FFTW
- */
- int nthreads() const { return d_nthreads; }
-
- /*!
- * compute FFT. The input comes from inbuf, the output is placed in
- * outbuf.
- */
- void execute();
-};
-
-/*!
- * \brief FFT: complex in, float out
- * \ingroup misc
- */
-class FFT_API fft_impl_fft_real_rev {
- int d_fft_size;
- int d_nthreads;
- gr_complex *d_inbuf;
- float *d_outbuf;
- void *d_plan;
-
-public:
- fft_impl_fft_real_rev(int fft_size, int nthreads=1);
- virtual ~fft_impl_fft_real_rev();
-
- /*
- * These return pointers to buffers owned by fft_impl_fft_real_rev
- * into which input and output take place. It's done this way in
- * order to ensure optimal alignment for SIMD instructions.
- */
- gr_complex *get_inbuf() const { return d_inbuf; }
- float *get_outbuf() const { return d_outbuf; }
-
- int inbuf_length() const { return d_fft_size / 2 + 1; }
- int outbuf_length() const { return d_fft_size; }
-
- /*!
- * Set the number of threads to use for caclulation.
- */
- void set_nthreads(int n);
-
- /*!
- * Get the number of threads being used by FFTW
- */
- int nthreads() const { return d_nthreads; }
-
- /*!
- * compute FFT. The input comes from inbuf, the output is placed in
- * outbuf.
- */
- void execute();
-};
-
-#endif
diff --git a/gr-fft/include/fft/fft_impl_goertzel.h b/gr-fft/include/fft/goertzel.h
index b6aa71d31..ff37355e6 100644
--- a/gr-fft/include/fft/fft_impl_goertzel.h
+++ b/gr-fft/include/fft/goertzel.h
@@ -26,32 +26,39 @@
#include <fft/api.h>
#include <gr_types.h>
-/*!
- * \brief Implements Goertzel single-bin DFT calculation
- * \ingroup misc
- */
-class FFT_API fft_impl_goertzel
-{
-public:
- fft_impl_goertzel() {}
- fft_impl_goertzel(int rate, int len, float freq);
- void set_params(int rate, int len, float freq);
-
- // Process a input array
- gr_complex batch(float *in);
-
- // Process sample by sample
- void input(const float &in);
- gr_complex output();
- bool ready() const { return d_processed == d_len; }
+namespace gr {
+ namespace fft {
-private:
- float d_d1;
- float d_d2;
- float d_wr;
- float d_wi;
- int d_len;
- int d_processed;
-};
+ /*!
+ * \brief Implements Goertzel single-bin DFT calculation
+ * \ingroup misc
+ */
+ class FFT_API goertzel
+ {
+ public:
+ goertzel(){}
+ goertzel(int rate, int len, float freq);
+
+ void set_params(int rate, int len, float freq);
+
+ // Process a input array
+ gr_complex batch(float *in);
+
+ // Process sample by sample
+ void input(const float &in);
+ gr_complex output();
+ bool ready() const { return d_processed == d_len; }
+
+ private:
+ float d_d1;
+ float d_d2;
+ float d_wr;
+ float d_wi;
+ int d_len;
+ int d_processed;
+ };
+
+ } /* namespace fft */
+} /* namespace gr */
#endif /* INCLUDED_FFT_IMPL_GOERTZEL_H */
diff --git a/gr-fft/lib/CMakeLists.txt b/gr-fft/lib/CMakeLists.txt
index eb2b9ee07..e2f17a183 100644
--- a/gr-fft/lib/CMakeLists.txt
+++ b/gr-fft/lib/CMakeLists.txt
@@ -40,11 +40,11 @@ link_directories(${FFTW3F_LIBRARY_DIRS})
# Setup library
########################################################################
list(APPEND fft_sources
+ fft.cc
fft_vcc_fftw.cc
fft_vfc_fftw.cc
goertzel_fc_impl.cc
- fft_impl_fft.cc
- fft_impl_goertzel.cc
+ goertzel.cc
)
list(APPEND fft_libs
diff --git a/gr-fft/lib/fft.cc b/gr-fft/lib/fft.cc
new file mode 100644
index 000000000..6074236e1
--- /dev/null
+++ b/gr-fft/lib/fft.cc
@@ -0,0 +1,338 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2003,2008,2011,2012 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 <fft/fft.h>
+#include <gr_sys_paths.h>
+#include <fftw3.h>
+
+#ifdef _MSC_VER //http://www.fftw.org/install/windows.html#DLLwisdom
+static void my_fftw_write_char(char c, void *f) { fputc(c, (FILE *) f); }
+#define fftw_export_wisdom_to_file(f) fftw_export_wisdom(my_fftw_write_char, (void*) (f))
+#define fftwf_export_wisdom_to_file(f) fftwf_export_wisdom(my_fftw_write_char, (void*) (f))
+#define fftwl_export_wisdom_to_file(f) fftwl_export_wisdom(my_fftw_write_char, (void*) (f))
+
+static int my_fftw_read_char(void *f) { return fgetc((FILE *) f); }
+#define fftw_import_wisdom_from_file(f) fftw_import_wisdom(my_fftw_read_char, (void*) (f))
+#define fftwf_import_wisdom_from_file(f) fftwf_import_wisdom(my_fftw_read_char, (void*) (f))
+#define fftwl_import_wisdom_from_file(f) fftwl_import_wisdom(my_fftw_read_char, (void*) (f))
+#endif //_MSC_VER
+
+#include <gr_complex.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <cassert>
+#include <stdexcept>
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+namespace fs = boost::filesystem;
+
+namespace gr {
+ namespace fft {
+
+ gr_complex *
+ malloc_complex(int size)
+ {
+ return (gr_complex*)fftwf_malloc(sizeof(gr_complex)*size);
+ }
+
+ float *
+ malloc_float(int size)
+ {
+ return (float*)fftwf_malloc(sizeof(float)*size);
+ }
+
+ void
+ free(void *b)
+ {
+ fftwf_free(b);
+ }
+
+ boost::mutex &
+ planner::mutex()
+ {
+ static boost::mutex s_planning_mutex;
+
+ return s_planning_mutex;
+ }
+
+ static const char *
+ wisdom_filename()
+ {
+ static fs::path path;
+ path = fs::path(gr_appdata_path()) / ".gr_fftw_wisdom";
+ return path.string().c_str();
+ }
+
+ static void
+ import_wisdom()
+ {
+ const char *filename = wisdom_filename ();
+ FILE *fp = fopen (filename, "r");
+ if (fp != 0){
+ int r = fftwf_import_wisdom_from_file (fp);
+ fclose (fp);
+ if (!r){
+ fprintf (stderr, "gr::fft: can't import wisdom from %s\n", filename);
+ }
+ }
+ }
+
+ static void
+ config_threading(int nthreads)
+ {
+ static int fftw_threads_inited = 0;
+
+#ifdef FFTW3F_THREADS
+ if (fftw_threads_inited == 0)
+ {
+ fftw_threads_inited = 1;
+ fftwf_init_threads();
+ }
+
+ fftwf_plan_with_nthreads(nthreads);
+#endif
+ }
+
+ static void
+ export_wisdom()
+ {
+ const char *filename = wisdom_filename ();
+ FILE *fp = fopen (filename, "w");
+ if (fp != 0){
+ fftwf_export_wisdom_to_file (fp);
+ fclose (fp);
+ }
+ else {
+ fprintf (stderr, "fft_impl_fftw: ");
+ perror (filename);
+ }
+ }
+
+// ----------------------------------------------------------------
+
+ fft_complex::fft_complex(int fft_size, bool forward, int nthreads)
+ {
+ // Hold global mutex during plan construction and destruction.
+ planner::scoped_lock lock(planner::mutex());
+
+ assert (sizeof (fftwf_complex) == sizeof (gr_complex));
+
+ if (fft_size <= 0)
+ throw std::out_of_range ("fft_impl_fftw: invalid fft_size");
+
+ d_fft_size = fft_size;
+ d_inbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * inbuf_length ());
+ if (d_inbuf == 0)
+ throw std::runtime_error ("fftwf_malloc");
+
+ d_outbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * outbuf_length ());
+ if (d_outbuf == 0){
+ fftwf_free (d_inbuf);
+ throw std::runtime_error ("fftwf_malloc");
+ }
+
+ d_nthreads = nthreads;
+ config_threading(nthreads);
+ import_wisdom(); // load prior wisdom from disk
+
+ d_plan = fftwf_plan_dft_1d (fft_size,
+ reinterpret_cast<fftwf_complex *>(d_inbuf),
+ reinterpret_cast<fftwf_complex *>(d_outbuf),
+ forward ? FFTW_FORWARD : FFTW_BACKWARD,
+ FFTW_MEASURE);
+
+ if (d_plan == NULL) {
+ fprintf(stderr, "gr::fft: error creating plan\n");
+ throw std::runtime_error ("fftwf_plan_dft_1d failed");
+ }
+ export_wisdom(); // store new wisdom to disk
+ }
+
+ fft_complex::~fft_complex()
+ {
+ // Hold global mutex during plan construction and destruction.
+ planner::scoped_lock lock(planner::mutex());
+
+ fftwf_destroy_plan ((fftwf_plan) d_plan);
+ fftwf_free (d_inbuf);
+ fftwf_free (d_outbuf);
+ }
+
+ void
+ fft_complex::set_nthreads(int n)
+ {
+ if (n <= 0)
+ throw std::out_of_range ("gr::fft: invalid number of threads");
+ d_nthreads = n;
+
+#ifdef FFTW3F_THREADS
+ fftwf_plan_with_nthreads(d_nthreads);
+#endif
+ }
+
+ void
+ fft_complex::execute()
+ {
+ fftwf_execute((fftwf_plan) d_plan);
+ }
+
+// ----------------------------------------------------------------
+
+ fft_real_fwd::fft_real_fwd (int fft_size, int nthreads)
+ {
+ // Hold global mutex during plan construction and destruction.
+ planner::scoped_lock lock(planner::mutex());
+
+ assert (sizeof (fftwf_complex) == sizeof (gr_complex));
+
+ if (fft_size <= 0)
+ throw std::out_of_range ("gr::fft: invalid fft_size");
+
+ d_fft_size = fft_size;
+ d_inbuf = (float *) fftwf_malloc (sizeof (float) * inbuf_length ());
+ if (d_inbuf == 0)
+ throw std::runtime_error ("fftwf_malloc");
+
+ d_outbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * outbuf_length ());
+ if (d_outbuf == 0){
+ fftwf_free (d_inbuf);
+ throw std::runtime_error ("fftwf_malloc");
+ }
+
+ d_nthreads = nthreads;
+ config_threading(nthreads);
+ import_wisdom(); // load prior wisdom from disk
+
+ d_plan = fftwf_plan_dft_r2c_1d (fft_size,
+ d_inbuf,
+ reinterpret_cast<fftwf_complex *>(d_outbuf),
+ FFTW_MEASURE);
+
+ if (d_plan == NULL) {
+ fprintf(stderr, "gr::fft::fft_real_fwd: error creating plan\n");
+ throw std::runtime_error ("fftwf_plan_dft_r2c_1d failed");
+ }
+ export_wisdom(); // store new wisdom to disk
+ }
+
+ fft_real_fwd::~fft_real_fwd()
+ {
+ // Hold global mutex during plan construction and destruction.
+ planner::scoped_lock lock(planner::mutex());
+
+ fftwf_destroy_plan ((fftwf_plan) d_plan);
+ fftwf_free (d_inbuf);
+ fftwf_free (d_outbuf);
+ }
+
+ void
+ fft_real_fwd::set_nthreads(int n)
+ {
+ if (n <= 0)
+ throw std::out_of_range ("gr::fft::fft_real_fwd::set_nthreads: invalid number of threads");
+ d_nthreads = n;
+
+#ifdef FFTW3F_THREADS
+ fftwf_plan_with_nthreads(d_nthreads);
+#endif
+ }
+
+ void
+ fft_real_fwd::execute()
+ {
+ fftwf_execute ((fftwf_plan) d_plan);
+ }
+
+ // ----------------------------------------------------------------
+
+ fft_real_rev::fft_real_rev(int fft_size, int nthreads)
+ {
+ // Hold global mutex during plan construction and destruction.
+ planner::scoped_lock lock(planner::mutex());
+
+ assert (sizeof (fftwf_complex) == sizeof (gr_complex));
+
+ if (fft_size <= 0)
+ throw std::out_of_range ("gr::fft::fft_real_rev: invalid fft_size");
+
+ d_fft_size = fft_size;
+ d_inbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * inbuf_length ());
+ if (d_inbuf == 0)
+ throw std::runtime_error ("fftwf_malloc");
+
+ d_outbuf = (float *) fftwf_malloc (sizeof (float) * outbuf_length ());
+ if (d_outbuf == 0){
+ fftwf_free (d_inbuf);
+ throw std::runtime_error ("fftwf_malloc");
+ }
+
+ d_nthreads = nthreads;
+ config_threading(nthreads);
+ import_wisdom(); // load prior wisdom from disk
+
+ // FIXME If there's ever a chance that the planning functions
+ // will be called in multiple threads, we've got to ensure single
+ // threaded access. They are not thread-safe.
+ d_plan = fftwf_plan_dft_c2r_1d (fft_size,
+ reinterpret_cast<fftwf_complex *>(d_inbuf),
+ d_outbuf,
+ FFTW_MEASURE);
+
+ if (d_plan == NULL) {
+ fprintf(stderr, "gr::fft::fft_real_rev: error creating plan\n");
+ throw std::runtime_error ("fftwf_plan_dft_c2r_1d failed");
+ }
+ export_wisdom (); // store new wisdom to disk
+ }
+
+ fft_real_rev::~fft_real_rev ()
+ {
+ // Hold global mutex during plan construction and destruction.
+ planner::scoped_lock lock(planner::mutex());
+
+ fftwf_destroy_plan ((fftwf_plan) d_plan);
+ fftwf_free (d_inbuf);
+ fftwf_free (d_outbuf);
+ }
+
+ void
+ fft_real_rev::set_nthreads(int n)
+ {
+ if (n <= 0)
+ throw std::out_of_range ("gr::fft::fft_real_rev::set_nthreads: invalid number of threads");
+ d_nthreads = n;
+
+#ifdef FFTW3F_THREADS
+ fftwf_plan_with_nthreads(d_nthreads);
+#endif
+ }
+
+ void
+ fft_real_rev::execute ()
+ {
+ fftwf_execute ((fftwf_plan) d_plan);
+ }
+
+ } /* namespace fft */
+} /* namespace gr */
diff --git a/gr-fft/lib/fft_impl_fft.cc b/gr-fft/lib/fft_impl_fft.cc
deleted file mode 100644
index 42bdf7778..000000000
--- a/gr-fft/lib/fft_impl_fft.cc
+++ /dev/null
@@ -1,330 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2003,2008,2011,2012 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 <fft/fft_impl_fft.h>
-#include <gr_sys_paths.h>
-#include <fftw3.h>
-
-#ifdef _MSC_VER //http://www.fftw.org/install/windows.html#DLLwisdom
-static void my_fftw_write_char(char c, void *f) { fputc(c, (FILE *) f); }
-#define fftw_export_wisdom_to_file(f) fftw_export_wisdom(my_fftw_write_char, (void*) (f))
-#define fftwf_export_wisdom_to_file(f) fftwf_export_wisdom(my_fftw_write_char, (void*) (f))
-#define fftwl_export_wisdom_to_file(f) fftwl_export_wisdom(my_fftw_write_char, (void*) (f))
-
-static int my_fftw_read_char(void *f) { return fgetc((FILE *) f); }
-#define fftw_import_wisdom_from_file(f) fftw_import_wisdom(my_fftw_read_char, (void*) (f))
-#define fftwf_import_wisdom_from_file(f) fftwf_import_wisdom(my_fftw_read_char, (void*) (f))
-#define fftwl_import_wisdom_from_file(f) fftwl_import_wisdom(my_fftw_read_char, (void*) (f))
-#endif //_MSC_VER
-
-#include <gr_complex.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <cassert>
-#include <stdexcept>
-
-#include <boost/filesystem/operations.hpp>
-#include <boost/filesystem/path.hpp>
-namespace fs = boost::filesystem;
-
-gr_complex *
-fft_impl_fft_malloc_complex(int size)
-{
- return (gr_complex*)fftwf_malloc(sizeof(gr_complex)*size);
-}
-
-float *
-fft_impl_fft_malloc_float(int size)
-{
- return (float*)fftwf_malloc(sizeof(float)*size);
-}
-
-void
-fft_impl_fft_free(void *b)
-{
- fftwf_free(b);
-}
-
-boost::mutex &
-fft_impl_fft_planner::mutex()
-{
- static boost::mutex s_planning_mutex;
-
- return s_planning_mutex;
-}
-
-static const char *
-wisdom_filename ()
-{
- static fs::path path;
- path = fs::path(gr_appdata_path()) / ".gr_fftw_wisdom";
- return path.string().c_str();
-}
-
-static void
-fft_impl_fftw_import_wisdom ()
-{
- const char *filename = wisdom_filename ();
- FILE *fp = fopen (filename, "r");
- if (fp != 0){
- int r = fftwf_import_wisdom_from_file (fp);
- fclose (fp);
- if (!r){
- fprintf (stderr, "fft_impl_fftw: can't import wisdom from %s\n", filename);
- }
- }
-}
-
-static void
-fft_impl_fftw_config_threading (int nthreads)
-{
- static int fftw_threads_inited = 0;
-
-#ifdef FFTW3F_THREADS
- if (fftw_threads_inited == 0)
- {
- fftw_threads_inited = 1;
- fftwf_init_threads();
- }
-
- fftwf_plan_with_nthreads(nthreads);
-#endif
-}
-
-static void
-fft_impl_fftw_export_wisdom ()
-{
- const char *filename = wisdom_filename ();
- FILE *fp = fopen (filename, "w");
- if (fp != 0){
- fftwf_export_wisdom_to_file (fp);
- fclose (fp);
- }
- else {
- fprintf (stderr, "fft_impl_fftw: ");
- perror (filename);
- }
-}
-
-// ----------------------------------------------------------------
-
-fft_impl_fft_complex::fft_impl_fft_complex (int fft_size, bool forward, int nthreads)
-{
- // Hold global mutex during plan construction and destruction.
- fft_impl_fft_planner::scoped_lock lock(fft_impl_fft_planner::mutex());
-
- assert (sizeof (fftwf_complex) == sizeof (gr_complex));
-
- if (fft_size <= 0)
- throw std::out_of_range ("fft_impl_fftw: invalid fft_size");
-
- d_fft_size = fft_size;
- d_inbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * inbuf_length ());
- if (d_inbuf == 0)
- throw std::runtime_error ("fftwf_malloc");
-
- d_outbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * outbuf_length ());
- if (d_outbuf == 0){
- fftwf_free (d_inbuf);
- throw std::runtime_error ("fftwf_malloc");
- }
-
- d_nthreads = nthreads;
- fft_impl_fftw_config_threading (nthreads);
- fft_impl_fftw_import_wisdom (); // load prior wisdom from disk
-
- d_plan = fftwf_plan_dft_1d (fft_size,
- reinterpret_cast<fftwf_complex *>(d_inbuf),
- reinterpret_cast<fftwf_complex *>(d_outbuf),
- forward ? FFTW_FORWARD : FFTW_BACKWARD,
- FFTW_MEASURE);
-
- if (d_plan == NULL) {
- fprintf(stderr, "fft_impl_fft_complex: error creating plan\n");
- throw std::runtime_error ("fftwf_plan_dft_1d failed");
- }
- fft_impl_fftw_export_wisdom (); // store new wisdom to disk
-}
-
-fft_impl_fft_complex::~fft_impl_fft_complex ()
-{
- // Hold global mutex during plan construction and destruction.
- fft_impl_fft_planner::scoped_lock lock(fft_impl_fft_planner::mutex());
-
- fftwf_destroy_plan ((fftwf_plan) d_plan);
- fftwf_free (d_inbuf);
- fftwf_free (d_outbuf);
-}
-
-void
-fft_impl_fft_complex::set_nthreads(int n)
-{
- if (n <= 0)
- throw std::out_of_range ("fft_impl_fftw: invalid number of threads");
- d_nthreads = n;
-
-#ifdef FFTW3F_THREADS
- fftwf_plan_with_nthreads(d_nthreads);
-#endif
-}
-
-void
-fft_impl_fft_complex::execute ()
-{
- fftwf_execute ((fftwf_plan) d_plan);
-}
-
-// ----------------------------------------------------------------
-
-fft_impl_fft_real_fwd::fft_impl_fft_real_fwd (int fft_size, int nthreads)
-{
- // Hold global mutex during plan construction and destruction.
- fft_impl_fft_planner::scoped_lock lock(fft_impl_fft_planner::mutex());
-
- assert (sizeof (fftwf_complex) == sizeof (gr_complex));
-
- if (fft_size <= 0)
- throw std::out_of_range ("fft_impl_fftw: invalid fft_size");
-
- d_fft_size = fft_size;
- d_inbuf = (float *) fftwf_malloc (sizeof (float) * inbuf_length ());
- if (d_inbuf == 0)
- throw std::runtime_error ("fftwf_malloc");
-
- d_outbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * outbuf_length ());
- if (d_outbuf == 0){
- fftwf_free (d_inbuf);
- throw std::runtime_error ("fftwf_malloc");
- }
-
- d_nthreads = nthreads;
- fft_impl_fftw_config_threading (nthreads);
- fft_impl_fftw_import_wisdom (); // load prior wisdom from disk
-
- d_plan = fftwf_plan_dft_r2c_1d (fft_size,
- d_inbuf,
- reinterpret_cast<fftwf_complex *>(d_outbuf),
- FFTW_MEASURE);
-
- if (d_plan == NULL) {
- fprintf(stderr, "fft_impl_fft_real_fwd: error creating plan\n");
- throw std::runtime_error ("fftwf_plan_dft_r2c_1d failed");
- }
- fft_impl_fftw_export_wisdom (); // store new wisdom to disk
-}
-
-fft_impl_fft_real_fwd::~fft_impl_fft_real_fwd ()
-{
- // Hold global mutex during plan construction and destruction.
- fft_impl_fft_planner::scoped_lock lock(fft_impl_fft_planner::mutex());
-
- fftwf_destroy_plan ((fftwf_plan) d_plan);
- fftwf_free (d_inbuf);
- fftwf_free (d_outbuf);
-}
-
-void
-fft_impl_fft_real_fwd::set_nthreads(int n)
-{
- if (n <= 0)
- throw std::out_of_range ("fft_impl_fftw: invalid number of threads");
- d_nthreads = n;
-
-#ifdef FFTW3F_THREADS
- fftwf_plan_with_nthreads(d_nthreads);
-#endif
-}
-
-void
-fft_impl_fft_real_fwd::execute ()
-{
- fftwf_execute ((fftwf_plan) d_plan);
-}
-
-// ----------------------------------------------------------------
-
-fft_impl_fft_real_rev::fft_impl_fft_real_rev (int fft_size, int nthreads)
-{
- // Hold global mutex during plan construction and destruction.
- fft_impl_fft_planner::scoped_lock lock(fft_impl_fft_planner::mutex());
-
- assert (sizeof (fftwf_complex) == sizeof (gr_complex));
-
- if (fft_size <= 0)
- throw std::out_of_range ("fft_impl_fftw: invalid fft_size");
-
- d_fft_size = fft_size;
- d_inbuf = (gr_complex *) fftwf_malloc (sizeof (gr_complex) * inbuf_length ());
- if (d_inbuf == 0)
- throw std::runtime_error ("fftwf_malloc");
-
- d_outbuf = (float *) fftwf_malloc (sizeof (float) * outbuf_length ());
- if (d_outbuf == 0){
- fftwf_free (d_inbuf);
- throw std::runtime_error ("fftwf_malloc");
- }
-
- d_nthreads = nthreads;
- fft_impl_fftw_config_threading (nthreads);
- fft_impl_fftw_import_wisdom (); // load prior wisdom from disk
-
- // FIXME If there's ever a chance that the planning functions
- // will be called in multiple threads, we've got to ensure single
- // threaded access. They are not thread-safe.
- d_plan = fftwf_plan_dft_c2r_1d (fft_size,
- reinterpret_cast<fftwf_complex *>(d_inbuf),
- d_outbuf,
- FFTW_MEASURE);
-
- if (d_plan == NULL) {
- fprintf(stderr, "fft_impl_fft_real_rev: error creating plan\n");
- throw std::runtime_error ("fftwf_plan_dft_c2r_1d failed");
- }
- fft_impl_fftw_export_wisdom (); // store new wisdom to disk
-}
-
-fft_impl_fft_real_rev::~fft_impl_fft_real_rev ()
-{
- fftwf_destroy_plan ((fftwf_plan) d_plan);
- fftwf_free (d_inbuf);
- fftwf_free (d_outbuf);
-}
-
-void
-fft_impl_fft_real_rev::set_nthreads(int n)
-{
- if (n <= 0)
- throw std::out_of_range ("fft_impl_fftw: invalid number of threads");
- d_nthreads = n;
-
-#ifdef FFTW3F_THREADS
- fftwf_plan_with_nthreads(d_nthreads);
-#endif
-}
-
-void
-fft_impl_fft_real_rev::execute ()
-{
- fftwf_execute ((fftwf_plan) d_plan);
-}
-
diff --git a/gr-fft/lib/fft_impl_goertzel.cc b/gr-fft/lib/fft_impl_goertzel.cc
deleted file mode 100644
index b008d0481..000000000
--- a/gr-fft/lib/fft_impl_goertzel.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2002,2011,2012 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 <cmath>
-#include <fft/fft_impl_goertzel.h>
-
-fft_impl_goertzel::fft_impl_goertzel(int rate, int len, float freq)
-{
- set_params(rate, len, freq);
-}
-
-void
-fft_impl_goertzel::set_params(int rate, int len, float freq)
-{
- d_d1 = 0.0;
- d_d2 = 0.0;
-
- float w = 2.0*M_PI*freq/rate;
- d_wr = 2.0*std::cos(w);
- d_wi = std::sin(w);
- d_len = len;
- d_processed = 0;
-
-}
-
-gr_complex
-fft_impl_goertzel::batch(float *in)
-{
- d_d1 = 0.0;
- d_d2 = 0.0;
-
- for(int i = 0; i < d_len; i++)
- input(in[i]);
-
- return output();
-}
-
-void
-fft_impl_goertzel::input(const float &input)
-{
- float y = input + d_wr*d_d1 - d_d2;
- d_d2 = d_d1;
- d_d1 = y;
- d_processed++;
-}
-
-gr_complex
-fft_impl_goertzel::output()
-{
- gr_complex out((0.5*d_wr*d_d1-d_d2)/d_len, (d_wi*d_d1)/d_len);
- d_d1 = 0.0;
- d_d2 = 0.0;
- d_processed = 0;
- return out;
-}
diff --git a/gr-fft/lib/fft_vcc_fftw.cc b/gr-fft/lib/fft_vcc_fftw.cc
index 92441f0d3..ebcd5ec53 100644
--- a/gr-fft/lib/fft_vcc_fftw.cc
+++ b/gr-fft/lib/fft_vcc_fftw.cc
@@ -49,7 +49,7 @@ namespace gr {
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 fft_impl_fft_complex(d_fft_size, forward, nthreads);
+ d_fft = new fft_complex(d_fft_size, forward, nthreads);
}
fft_vcc_fftw::~fft_vcc_fftw()
diff --git a/gr-fft/lib/fft_vcc_fftw.h b/gr-fft/lib/fft_vcc_fftw.h
index fb9312a64..ea15dd07b 100644
--- a/gr-fft/lib/fft_vcc_fftw.h
+++ b/gr-fft/lib/fft_vcc_fftw.h
@@ -24,7 +24,7 @@
#define INCLUDED_FFT_FFT_VCC_FFTW_IMPL_H
#include <fft/fft_vcc.h>
-#include <fft/fft_impl_fft.h>
+#include <fft/fft.h>
namespace gr {
namespace fft {
@@ -32,7 +32,7 @@ namespace gr {
class FFT_API fft_vcc_fftw : public fft_vcc
{
private:
- fft_impl_fft_complex *d_fft;
+ fft_complex *d_fft;
unsigned int d_fft_size;
std::vector<float> d_window;
bool d_forward;
diff --git a/gr-fft/lib/fft_vfc_fftw.cc b/gr-fft/lib/fft_vfc_fftw.cc
index 0643c180d..8f9b127e5 100644
--- a/gr-fft/lib/fft_vfc_fftw.cc
+++ b/gr-fft/lib/fft_vfc_fftw.cc
@@ -49,7 +49,7 @@ namespace gr {
gr_make_io_signature(1, 1, fft_size * sizeof(gr_complex))),
d_fft_size(fft_size), d_forward(forward)
{
- d_fft = new fft_impl_fft_complex(d_fft_size, forward, nthreads);
+ d_fft = new fft_complex(d_fft_size, forward, nthreads);
}
fft_vfc_fftw::~fft_vfc_fftw()
diff --git a/gr-fft/lib/fft_vfc_fftw.h b/gr-fft/lib/fft_vfc_fftw.h
index 54be6c128..1b6f78ba6 100644
--- a/gr-fft/lib/fft_vfc_fftw.h
+++ b/gr-fft/lib/fft_vfc_fftw.h
@@ -24,7 +24,7 @@
#define INCLUDED_FFT_FFT_VFC_FFTW_IMPL_H
#include <fft/fft_vfc.h>
-#include <fft/fft_impl_fft.h>
+#include <fft/fft.h>
namespace gr {
namespace fft {
@@ -32,7 +32,7 @@ namespace gr {
class FFT_API fft_vfc_fftw : public fft_vfc
{
private:
- fft_impl_fft_complex *d_fft;
+ fft_complex *d_fft;
unsigned int d_fft_size;
std::vector<float> d_window;
bool d_forward;
diff --git a/gr-fft/lib/goertzel.cc b/gr-fft/lib/goertzel.cc
new file mode 100644
index 000000000..4bcd5ee19
--- /dev/null
+++ b/gr-fft/lib/goertzel.cc
@@ -0,0 +1,84 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2011,2012 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 <cmath>
+#include <fft/goertzel.h>
+
+namespace gr {
+ namespace fft {
+
+ goertzel::goertzel(int rate, int len, float freq)
+ {
+ set_params(rate, len, freq);
+ }
+
+ void
+ goertzel::set_params(int rate, int len, float freq)
+ {
+ d_d1 = 0.0;
+ d_d2 = 0.0;
+
+ float w = 2.0*M_PI*freq/rate;
+ d_wr = 2.0*std::cos(w);
+ d_wi = std::sin(w);
+ d_len = len;
+ d_processed = 0;
+ }
+
+ gr_complex
+ goertzel::batch(float *in)
+ {
+ d_d1 = 0.0;
+ d_d2 = 0.0;
+
+ for(int i = 0; i < d_len; i++)
+ input(in[i]);
+
+ return output();
+ }
+
+ void
+ goertzel::input(const float &input)
+ {
+ float y = input + d_wr*d_d1 - d_d2;
+ d_d2 = d_d1;
+ d_d1 = y;
+ d_processed++;
+ }
+
+ gr_complex
+ goertzel::output()
+ {
+ gr_complex out((0.5*d_wr*d_d1-d_d2)/d_len, (d_wi*d_d1)/d_len);
+ d_d1 = 0.0;
+ d_d2 = 0.0;
+ d_processed = 0;
+ return out;
+ }
+
+ } /* namespace fft */
+}/* namespace gr */
+
diff --git a/gr-fft/lib/goertzel_fc_impl.h b/gr-fft/lib/goertzel_fc_impl.h
index d7bab1f1d..426bc71f6 100644
--- a/gr-fft/lib/goertzel_fc_impl.h
+++ b/gr-fft/lib/goertzel_fc_impl.h
@@ -24,7 +24,7 @@
#define INCLUDED_FFT_GOERTZEL_FC_IMPL_H
#include <fft/goertzel_fc.h>
-#include <fft/fft_impl_goertzel.h>
+#include <fft/goertzel.h>
namespace gr {
namespace fft {
@@ -32,10 +32,10 @@ namespace gr {
class FFT_API goertzel_fc_impl : public goertzel_fc
{
private:
- fft_impl_goertzel d_goertzel;
- int d_len;
- float d_freq;
- int d_rate;
+ goertzel d_goertzel;
+ int d_len;
+ float d_freq;
+ int d_rate;
public:
goertzel_fc_impl(int rate, int len, float freq);