diff options
author | Marcus Müller <mmueller@gnuradio.org> | 2019-08-07 21:45:12 +0200 |
---|---|---|
committer | Marcus Müller <marcus@hostalia.de> | 2019-08-09 23:04:28 +0200 |
commit | f7bbf2c1d8d780294f3e016aff239ca35eb6516e (patch) | |
tree | e09ab6112e02b2215b2d59ac24d3d6ea2edac745 /gr-fft | |
parent | 78431dc6941e3acc67c858277dfe4a0ed583643c (diff) |
Tree: clang-format without the include sorting
Diffstat (limited to 'gr-fft')
-rw-r--r-- | gr-fft/include/gnuradio/fft/api.h | 4 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/ctrlport_probe_psd.h | 55 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/fft.h | 286 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/fft_shift.h | 61 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/fft_vcc.h | 97 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/fft_vfc.h | 94 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/goertzel.h | 62 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/goertzel_fc.h | 35 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/window.h | 554 | ||||
-rw-r--r-- | gr-fft/lib/ctrlport_probe_psd_impl.cc | 236 | ||||
-rw-r--r-- | gr-fft/lib/ctrlport_probe_psd_impl.h | 51 | ||||
-rw-r--r-- | gr-fft/lib/fft.cc | 574 | ||||
-rw-r--r-- | gr-fft/lib/fft_vcc_fftw.cc | 208 | ||||
-rw-r--r-- | gr-fft/lib/fft_vcc_fftw.h | 58 | ||||
-rw-r--r-- | gr-fft/lib/fft_vfc_fftw.cc | 140 | ||||
-rw-r--r-- | gr-fft/lib/fft_vfc_fftw.h | 55 | ||||
-rw-r--r-- | gr-fft/lib/goertzel.cc | 82 | ||||
-rw-r--r-- | gr-fft/lib/goertzel_fc_impl.cc | 85 | ||||
-rw-r--r-- | gr-fft/lib/goertzel_fc_impl.h | 41 | ||||
-rw-r--r-- | gr-fft/lib/qa_fft_shift.cc | 28 | ||||
-rw-r--r-- | gr-fft/lib/window.cc | 620 |
21 files changed, 1674 insertions, 1752 deletions
diff --git a/gr-fft/include/gnuradio/fft/api.h b/gr-fft/include/gnuradio/fft/api.h index ce2a49f4be..a498012e04 100644 --- a/gr-fft/include/gnuradio/fft/api.h +++ b/gr-fft/include/gnuradio/fft/api.h @@ -25,9 +25,9 @@ #include <gnuradio/attributes.h> #ifdef gnuradio_fft_EXPORTS -# define FFT_API __GR_ATTR_EXPORT +#define FFT_API __GR_ATTR_EXPORT #else -# define FFT_API __GR_ATTR_IMPORT +#define FFT_API __GR_ATTR_IMPORT #endif #endif /* INCLUDED_FFT_API_H */ diff --git a/gr-fft/include/gnuradio/fft/ctrlport_probe_psd.h b/gr-fft/include/gnuradio/fft/ctrlport_probe_psd.h index 5c872922c0..21438d5fa8 100644 --- a/gr-fft/include/gnuradio/fft/ctrlport_probe_psd.h +++ b/gr-fft/include/gnuradio/fft/ctrlport_probe_psd.h @@ -27,40 +27,39 @@ #include <gnuradio/sync_block.h> namespace gr { - namespace fft { +namespace fft { + +/*! + * \brief A ControlPort probe to export vectors of signals. + * \ingroup measurement_tools_blk + * \ingroup controlport_blk + * + * \details + * This block acts as a sink in the flowgraph but also exports + * vectors of complex samples over ControlPort. This block holds + * the latest \p len number of complex samples so that every query + * by a ControlPort client will get the same length vector. + */ +class FFT_API ctrlport_probe_psd : virtual public gr::sync_block +{ +public: + typedef boost::shared_ptr<ctrlport_probe_psd> sptr; /*! - * \brief A ControlPort probe to export vectors of signals. - * \ingroup measurement_tools_blk - * \ingroup controlport_blk - * - * \details - * This block acts as a sink in the flowgraph but also exports - * vectors of complex samples over ControlPort. This block holds - * the latest \p len number of complex samples so that every query - * by a ControlPort client will get the same length vector. + * \brief Make a ControlPort probe block. + * \param id A string ID to name the probe over ControlPort. + * \param desc A string describing the probe. + * \param len Number of samples to transmit. */ - class FFT_API ctrlport_probe_psd : virtual public gr::sync_block - { - public: - typedef boost::shared_ptr<ctrlport_probe_psd> sptr; + static sptr make(const std::string& id, const std::string& desc, int len); - /*! - * \brief Make a ControlPort probe block. - * \param id A string ID to name the probe over ControlPort. - * \param desc A string describing the probe. - * \param len Number of samples to transmit. - */ - static sptr make(const std::string &id, const std::string &desc, int len); + virtual std::vector<gr_complex> get() = 0; - virtual std::vector<gr_complex> get() = 0; + virtual void set_length(int len) = 0; + virtual int length() const = 0; +}; - virtual void set_length(int len) = 0; - virtual int length() const = 0; - }; - - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE_PSD_H */ - diff --git a/gr-fft/include/gnuradio/fft/fft.h b/gr-fft/include/gnuradio/fft/fft.h index 81cd51de21..d6f52d4c7d 100644 --- a/gr-fft/include/gnuradio/fft/fft.h +++ b/gr-fft/include/gnuradio/fft/fft.h @@ -32,168 +32,172 @@ #include <boost/thread.hpp> namespace gr { - namespace fft { +namespace fft { - /*! \brief Helper function for allocating complex* buffers +/*! \brief Helper function for allocating complex* buffers + */ +FFT_API gr_complex* malloc_complex(int size); + +/*! \brief Helper function for allocating float* buffers + */ +FFT_API float* malloc_float(int size); + +/*! \brief Helper function for allocating double* buffers + */ +FFT_API double* malloc_double(int size); + +/*! \brief Helper function for freeing fft buffers + */ +FFT_API 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 */ - FFT_API gr_complex* malloc_complex(int size); + int nthreads() const { return d_nthreads; } - /*! \brief Helper function for allocating float* buffers + /*! + * 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. */ - FFT_API float* malloc_float(int size); + float* get_inbuf() const { return d_inbuf; } + gr_complex* get_outbuf() const { return d_outbuf; } - /*! \brief Helper function for allocating double* buffers + 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. */ - FFT_API double* malloc_double(int size); + void set_nthreads(int n); - /*! \brief Helper function for freeing fft buffers + /*! + * Get the number of threads being used by FFTW */ - FFT_API void free(void *b); + int nthreads() const { return d_nthreads; } /*! - * \brief Export reference to planner mutex for those apps that - * want to use FFTW w/o using the fft_impl_fftw* classes. + * 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. */ - class FFT_API planner { - public: - typedef boost::mutex::scoped_lock scoped_lock; - /*! - * Return reference to planner mutex - */ - static boost::mutex &mutex(); - }; + 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; } /*! - * \brief FFT: complex in, complex out - * \ingroup misc + * Set the number of threads to use for caclulation. */ - 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(); - }; + void set_nthreads(int n); /*! - * \brief FFT: real in, complex out - * \ingroup misc + * Get the number of threads being used by FFTW */ - 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(); - }; + int nthreads() const { return d_nthreads; } /*! - * \brief FFT: complex in, float out - * \ingroup misc + * compute FFT. The input comes from inbuf, the output is placed in + * outbuf. */ - 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 */ + void execute(); +}; + +} /* namespace fft */ } /*namespace gr */ #endif /* _FFT_FFT_H_ */ diff --git a/gr-fft/include/gnuradio/fft/fft_shift.h b/gr-fft/include/gnuradio/fft/fft_shift.h index 1ee08915b9..a0fd5a6e2e 100644 --- a/gr-fft/include/gnuradio/fft/fft_shift.h +++ b/gr-fft/include/gnuradio/fft/fft_shift.h @@ -30,52 +30,55 @@ namespace gr { namespace fft { - /*! \brief reorder FFT results which are ordered from 0 to 1 in normalized frequency - * to -0.5 to 0.5 by cyclic shift - */ - template<typename T> - class fft_shift { - public: +/*! \brief reorder FFT results which are ordered from 0 to 1 in normalized frequency + * to -0.5 to 0.5 by cyclic shift + */ +template <typename T> +class fft_shift +{ +public: fft_shift(size_t fft_length) - : d_fftlen(fft_length) - , d_lenpos(fft_length/2 + (fft_length%2)) - , d_lenneg(fft_length/2) - , d_buf(fft_length) {} + : d_fftlen(fft_length), + d_lenpos(fft_length / 2 + (fft_length % 2)), + d_lenneg(fft_length / 2), + d_buf(fft_length) + { + } /*! performs the cyclic shift on a vector v */ - void shift(std::vector<T>& v) { - shift(&v.front(), v.size()); - } + void shift(std::vector<T>& v) { shift(&v.front(), v.size()); } /*! performs the cyclic shift on an array */ - void shift(T* data, size_t fft_len) { - resize(fft_len); - std::copy_n(data, d_lenpos, d_buf.begin()); - std::copy_n(data+d_lenpos, d_lenneg, data); - std::copy_n(d_buf.begin(), d_lenpos, data+d_lenneg); + void shift(T* data, size_t fft_len) + { + resize(fft_len); + std::copy_n(data, d_lenpos, d_buf.begin()); + std::copy_n(data + d_lenpos, d_lenneg, data); + std::copy_n(d_buf.begin(), d_lenpos, data + d_lenneg); } /*! if needed adjusts the buffer size to a new fft length */ - void resize(size_t fft_length) { - if (d_fftlen == fft_length) - return; - d_fftlen = fft_length; - d_lenpos = d_fftlen/2 + (d_fftlen%2); - d_lenneg = d_fftlen/2; - assert(d_lenpos + d_lenneg == d_fftlen); - d_buf.resize(d_lenpos); + void resize(size_t fft_length) + { + if (d_fftlen == fft_length) + return; + d_fftlen = fft_length; + d_lenpos = d_fftlen / 2 + (d_fftlen % 2); + d_lenneg = d_fftlen / 2; + assert(d_lenpos + d_lenneg == d_fftlen); + d_buf.resize(d_lenpos); } - protected: - private: +protected: +private: size_t d_fftlen; // FFT length size_t d_lenpos; // number of FFT bins with positive frequencies size_t d_lenneg; // number of FFT bins with negative frequencies std::vector<T> d_buf; // buffer used for cyclic shift - } ; +}; } // namespace fft } // namespace gr diff --git a/gr-fft/include/gnuradio/fft/fft_vcc.h b/gr-fft/include/gnuradio/fft/fft_vcc.h index 03e82a9989..a10398465e 100644 --- a/gr-fft/include/gnuradio/fft/fft_vcc.h +++ b/gr-fft/include/gnuradio/fft/fft_vcc.h @@ -27,60 +27,61 @@ #include <gnuradio/sync_block.h> namespace gr { - namespace fft { +namespace fft { - /*! - * \brief Compute forward or reverse FFT. complex vector in / complex vector out. - * \ingroup fourier_analysis_blk - * - * The FFT operation is defined for a vector \f$x\f$ with \f$N\f$ uniformly - * sampled points by - * - * \f[ X(a) = \sum_{k=0}^{N-1} x(a) \cdot e^{-j 2\pi k a / N} \f] - * - * \f$ X = FFT\{x\} \f$ is the the FFT transform of \f$x(a)\f$, \f$j\f$ is - * the imaginary unit, \f$k\f$ and \f$a\f$ range from \f$0\f$ to \f$N-1\f$. - * - * The IFFT operation is defined for a vector \f$y\f$ with \f$N\f$ - * uniformly sampled points by - * - * \f[ Y(b) = \sum_{k=0}^{N-1} y(b) \cdot e^{j 2\pi k b / N} \f] - * - * \f$Y = IFFT\{y\}\f$ is the the inverse FFT transform of \f$y(b)\f$, - * \f$j\f$ is the imaginary unit, \f$k\f$ and \f$b\f$ range from \f$0\f$ to - * \f$N-1\f$. - * - * \b Note, that due to the underlying FFTW library, the output of a FFT - * followed by an IFFT (or the other way arround) will be scaled i.e. - * \f$FFT\{ \, IFFT\{x\} \,\} = N \cdot x \neq x\f$. - * - * \see http://www.fftw.org/faq/section3.html#whyscaled +/*! + * \brief Compute forward or reverse FFT. complex vector in / complex vector out. + * \ingroup fourier_analysis_blk + * + * The FFT operation is defined for a vector \f$x\f$ with \f$N\f$ uniformly + * sampled points by + * + * \f[ X(a) = \sum_{k=0}^{N-1} x(a) \cdot e^{-j 2\pi k a / N} \f] + * + * \f$ X = FFT\{x\} \f$ is the the FFT transform of \f$x(a)\f$, \f$j\f$ is + * the imaginary unit, \f$k\f$ and \f$a\f$ range from \f$0\f$ to \f$N-1\f$. + * + * The IFFT operation is defined for a vector \f$y\f$ with \f$N\f$ + * uniformly sampled points by + * + * \f[ Y(b) = \sum_{k=0}^{N-1} y(b) \cdot e^{j 2\pi k b / N} \f] + * + * \f$Y = IFFT\{y\}\f$ is the the inverse FFT transform of \f$y(b)\f$, + * \f$j\f$ is the imaginary unit, \f$k\f$ and \f$b\f$ range from \f$0\f$ to + * \f$N-1\f$. + * + * \b Note, that due to the underlying FFTW library, the output of a FFT + * followed by an IFFT (or the other way arround) will be scaled i.e. + * \f$FFT\{ \, IFFT\{x\} \,\} = N \cdot x \neq x\f$. + * + * \see http://www.fftw.org/faq/section3.html#whyscaled + */ +class FFT_API fft_vcc : virtual public sync_block +{ +public: + // gr::fft::fft_vcc::sptr + typedef boost::shared_ptr<fft_vcc> sptr; + /*! \brief + * \param[in] fft_size N. + * \param[in] forward True performs FFT, False performs IFFT. + * \param[in] window Window function to be used. + * \param[in] shift True moves DC carrier to the middle. + * \param[in] nthreads Number of underlying threads. */ - class FFT_API fft_vcc : virtual public sync_block - { - public: - - // gr::fft::fft_vcc::sptr - typedef boost::shared_ptr<fft_vcc> sptr; - /*! \brief - * \param[in] fft_size N. - * \param[in] forward True performs FFT, False performs IFFT. - * \param[in] window Window function to be used. - * \param[in] shift True moves DC carrier to the middle. - * \param[in] nthreads Number of underlying threads. - */ - static sptr make(int fft_size, bool forward, - const std::vector<float> &window, - bool shift=false, int nthreads=1); + static sptr make(int fft_size, + bool forward, + const std::vector<float>& window, + bool shift = false, + int nthreads = 1); - virtual void set_nthreads(int n) = 0; + virtual void set_nthreads(int n) = 0; - virtual int nthreads() const = 0; + virtual int nthreads() const = 0; - virtual bool set_window(const std::vector<float> &window) = 0; - }; + virtual bool set_window(const std::vector<float>& window) = 0; +}; - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_FFT_VCC_H */ diff --git a/gr-fft/include/gnuradio/fft/fft_vfc.h b/gr-fft/include/gnuradio/fft/fft_vfc.h index e5ec9bf3ee..8b194ec8e3 100644 --- a/gr-fft/include/gnuradio/fft/fft_vfc.h +++ b/gr-fft/include/gnuradio/fft/fft_vfc.h @@ -27,60 +27,58 @@ #include <gnuradio/sync_block.h> namespace gr { - namespace fft { +namespace fft { - /*! - * \brief Compute forward or reverse FFT. complex vector in / complex vector out. - * \ingroup fourier_analysis_blk - * - * The FFT operation is defined for a vector \f$x\f$ with \f$N\f$ uniformly - * sampled points by - * - * \f[ X(a) = \sum_{k=0}^{N-1} x(a) \cdot e^{-j 2\pi k a / N} \f] - * - * \f$ X = FFT\{x\} \f$ is the the FFT transform of \f$x(a)\f$, \f$j\f$ is - * the imaginary unit, \f$k\f$ and \f$a\f$ range from \f$0\f$ to \f$N-1\f$. - * - * The IFFT operation is defined for a vector \f$y\f$ with \f$N\f$ - * uniformly sampled points by - * - * \f[ Y(b) = \sum_{k=0}^{N-1} y(b) \cdot e^{j 2\pi k b / N} \f] - * - * \f$Y = IFFT\{y\}\f$ is the the inverse FFT transform of \f$y(b)\f$, - * \f$j\f$ is the imaginary unit, \f$k\f$ and \f$b\f$ range from \f$0\f$ to - * \f$N-1\f$. - * - * \b Note, that due to the underlying FFTW library, the output of a FFT - * followed by an IFFT (or the other way arround) will be scaled i.e. - * \f$FFT\{ \, IFFT\{x\} \,\} = N \cdot x \neq x\f$. - * - * \see http://www.fftw.org/faq/section3.html#whyscaled - */ - class FFT_API fft_vfc : virtual public sync_block - { - public: - - // gr::fft::fft_vfc::sptr - typedef boost::shared_ptr<fft_vfc> sptr; +/*! + * \brief Compute forward or reverse FFT. complex vector in / complex vector out. + * \ingroup fourier_analysis_blk + * + * The FFT operation is defined for a vector \f$x\f$ with \f$N\f$ uniformly + * sampled points by + * + * \f[ X(a) = \sum_{k=0}^{N-1} x(a) \cdot e^{-j 2\pi k a / N} \f] + * + * \f$ X = FFT\{x\} \f$ is the the FFT transform of \f$x(a)\f$, \f$j\f$ is + * the imaginary unit, \f$k\f$ and \f$a\f$ range from \f$0\f$ to \f$N-1\f$. + * + * The IFFT operation is defined for a vector \f$y\f$ with \f$N\f$ + * uniformly sampled points by + * + * \f[ Y(b) = \sum_{k=0}^{N-1} y(b) \cdot e^{j 2\pi k b / N} \f] + * + * \f$Y = IFFT\{y\}\f$ is the the inverse FFT transform of \f$y(b)\f$, + * \f$j\f$ is the imaginary unit, \f$k\f$ and \f$b\f$ range from \f$0\f$ to + * \f$N-1\f$. + * + * \b Note, that due to the underlying FFTW library, the output of a FFT + * followed by an IFFT (or the other way arround) will be scaled i.e. + * \f$FFT\{ \, IFFT\{x\} \,\} = N \cdot x \neq x\f$. + * + * \see http://www.fftw.org/faq/section3.html#whyscaled + */ +class FFT_API fft_vfc : virtual public sync_block +{ +public: + // gr::fft::fft_vfc::sptr + typedef boost::shared_ptr<fft_vfc> sptr; - /*! \brief - * \param[in] fft_size N. - * \param[in] forward True performs FFT, False performs IFFT. - * \param[in] window Window function to be used. - * \param[in] nthreads Number of underlying threads. - */ - static sptr make(int fft_size, bool forward, - const std::vector<float> &window, - int nthreads=1); + /*! \brief + * \param[in] fft_size N. + * \param[in] forward True performs FFT, False performs IFFT. + * \param[in] window Window function to be used. + * \param[in] nthreads Number of underlying threads. + */ + static sptr + make(int fft_size, bool forward, const std::vector<float>& window, int nthreads = 1); - virtual void set_nthreads(int n) = 0; + virtual void set_nthreads(int n) = 0; - virtual int nthreads() const = 0; + virtual int nthreads() const = 0; - virtual bool set_window(const std::vector<float> &window) = 0; - }; + virtual bool set_window(const std::vector<float>& window) = 0; +}; - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_FFT_VFC_H */ diff --git a/gr-fft/include/gnuradio/fft/goertzel.h b/gr-fft/include/gnuradio/fft/goertzel.h index ac77e7d2dd..38b03a1b25 100644 --- a/gr-fft/include/gnuradio/fft/goertzel.h +++ b/gr-fft/include/gnuradio/fft/goertzel.h @@ -27,37 +27,37 @@ #include <gnuradio/types.h> namespace gr { - namespace fft { - - /*! - * \brief Implements Goertzel single-bin DFT calculation - * \ingroup misc - */ - class FFT_API goertzel - { - public: - 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 fft { + +/*! + * \brief Implements Goertzel single-bin DFT calculation + * \ingroup misc + */ +class FFT_API goertzel +{ +public: + 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/include/gnuradio/fft/goertzel_fc.h b/gr-fft/include/gnuradio/fft/goertzel_fc.h index daa0c5ec26..75d97380fd 100644 --- a/gr-fft/include/gnuradio/fft/goertzel_fc.h +++ b/gr-fft/include/gnuradio/fft/goertzel_fc.h @@ -27,31 +27,30 @@ #include <gnuradio/sync_decimator.h> namespace gr { - namespace fft { +namespace fft { - /*! - * \brief Goertzel single-bin DFT calculation. - * \ingroup fourier_analysis_blk - */ - class FFT_API goertzel_fc : virtual public sync_decimator - { - public: - - // gr::fft::goertzel_fc::sptr - typedef boost::shared_ptr<goertzel_fc> sptr; +/*! + * \brief Goertzel single-bin DFT calculation. + * \ingroup fourier_analysis_blk + */ +class FFT_API goertzel_fc : virtual public sync_decimator +{ +public: + // gr::fft::goertzel_fc::sptr + typedef boost::shared_ptr<goertzel_fc> sptr; - static sptr make(int rate, int len, float freq); + static sptr make(int rate, int len, float freq); - virtual void set_freq (float freq) = 0; + virtual void set_freq(float freq) = 0; - virtual void set_rate (int rate) = 0; + virtual void set_rate(int rate) = 0; - virtual float freq() = 0; + virtual float freq() = 0; - virtual int rate() = 0; - }; + virtual int rate() = 0; +}; - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_GOERTZEL_FC_H */ diff --git a/gr-fft/include/gnuradio/fft/window.h b/gr-fft/include/gnuradio/fft/window.h index 564753a61c..d6ccf9ff7c 100644 --- a/gr-fft/include/gnuradio/fft/window.h +++ b/gr-fft/include/gnuradio/fft/window.h @@ -29,284 +29,288 @@ #include <gnuradio/gr_complex.h> namespace gr { - namespace fft { - - class FFT_API window { - public: - - enum win_type { - WIN_HAMMING = 0, //!< Hamming window; max attenuation 53 dB - WIN_HANN = 1, //!< Hann window; max attenuation 44 dB - WIN_BLACKMAN = 2, //!< Blackman window; max attenuation 74 dB - WIN_RECTANGULAR = 3, //!< Basic rectangular window; max attenuation 21 dB - WIN_KAISER = 4, //!< Kaiser window; max attenuation see window::max_attenuation +namespace fft { + +class FFT_API window +{ +public: + enum win_type { + WIN_HAMMING = 0, //!< Hamming window; max attenuation 53 dB + WIN_HANN = 1, //!< Hann window; max attenuation 44 dB + WIN_BLACKMAN = 2, //!< Blackman window; max attenuation 74 dB + WIN_RECTANGULAR = 3, //!< Basic rectangular window; max attenuation 21 dB + WIN_KAISER = 4, //!< Kaiser window; max attenuation see window::max_attenuation WIN_BLACKMAN_hARRIS = 5, //!< Blackman-harris window; max attenuation 92 dB - WIN_BLACKMAN_HARRIS = 5, //!< alias to WIN_BLACKMAN_hARRIS for capitalization consistency - WIN_BARTLETT = 6, //!< Barlett (triangular) window; max attenuation 26 dB - WIN_FLATTOP = 7, //!< flat top window; useful in FFTs; max attenuation 93 dB - }; - - /*! - * \brief Given a window::win_type, this tells you the maximum - * attenuation you can expect. - * - * \details - * For most windows, this is a set value. For the Kaiser window, - * the attenuation is based on the value of beta. The actual - * relationship is a piece-wise exponential relationship to - * calculate beta from the desired attenuation and can be found - * on page 542 of Oppenheim and Schafer (Discrete-Time Signal - * Processing, 3rd edition). To simplify this function to solve - * for A given beta, we use a linear form that is exact for - * attenuation >= 50 dB. - * - * For an attenuation of 50 dB, beta = 4.55. - * - * For an attenuation of 70 dB, beta = 6.76. - * - * \param type The window::win_type enumeration of the window type. - * \param beta Beta value only used for the Kaiser window. - */ - static double max_attenuation(win_type type, double beta=6.76); - - /*! - * \brief Helper function to build cosine-based windows. 3-coefficient version. - */ - static std::vector<float> coswindow(int ntaps, float c0, float c1, float c2); - - /*! - * \brief Helper function to build cosine-based windows. 4-coefficient version. - */ - static std::vector<float> coswindow(int ntaps, float c0, float c1, float c2, float c3); - - /*! - * \brief Helper function to build cosine-based windows. 5-coefficient version. - */ - static std::vector<float> coswindow(int ntaps, float c0, float c1, float c2, float c3, float c4); - - /*! - * \brief Build a rectangular window. - * - * Taps are flat across the window. - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> rectangular(int ntaps); - - /*! - * \brief Build a Hamming window. - * - * See: - * <pre> - * A. V. Oppenheim and R. W. Schafer, "Discrete-Time - * Signal Processing," Upper Saddle River, N.J.: Prentice - * Hall, 2010, pp. 535-538. - * </pre> - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> hamming(int ntaps); - - /*! - * \brief Build a Hann window (sometimes known as Hanning). - * - * See: - * <pre> - * A. V. Oppenheim and R. W. Schafer, "Discrete-Time - * Signal Processing," Upper Saddle River, N.J.: Prentice - * Hall, 2010, pp. 535-538. - * </pre> - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> hann(int ntaps); - - /*! - * \brief Alias to build a Hann window. - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> hanning(int ntaps); - - /*! - * \brief Build an exact Blackman window. - * - * See: - * <pre> - * A. V. Oppenheim and R. W. Schafer, "Discrete-Time - * Signal Processing," Upper Saddle River, N.J.: Prentice - * Hall, 2010, pp. 535-538. - * </pre> - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> blackman(int ntaps); - - /*! - * \brief Build Blackman window, variation 1. - */ - static std::vector<float> blackman2(int ntaps); - - /*! - * \brief Build Blackman window, variation 2. - */ - static std::vector<float> blackman3(int ntaps); - - /*! - * \brief Build Blackman window, variation 3. - */ - static std::vector<float> blackman4(int ntaps); - - /*! - * \brief Build a Blackman-harris window with a given attenuation. - * - * <pre> - * f. j. harris, "On the use of windows for harmonic analysis - * with the discrete Fourier transforms," Proc. IEEE, Vol. 66, - * ppg. 51-83, Jan. 1978. - * </pre> - * - * \param ntaps Number of coefficients in the window. - - * \param atten Attenuation factor. Must be [61, 67, 74, 92]. - * See the above paper for details. - */ - static std::vector<float> blackman_harris(int ntaps, int atten=92); - - /*! - * Alias to gr::fft::window::blakcman_harris. - */ - static std::vector<float> blackmanharris(int ntaps, int atten=92); - - /*! - * \brief Build a Nuttall (or Blackman-Nuttall) window. - * - * See: http://en.wikipedia.org/wiki/Window_function#Blackman.E2.80.93Nuttall_window - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> nuttall(int ntaps); - - /*! - * Deprecated: use nuttall window instead. - */ - static std::vector<float> nuttal(int ntaps); - - /*! - * \brief Alias to the Nuttall window. - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> blackman_nuttall(int ntaps); - - /*! - * Deprecated: use blackman_nuttall window instead. - */ - static std::vector<float> blackman_nuttal(int ntaps); - - /*! - * \brief Build a Nuttall continuous first derivative window. - * - * See: http://en.wikipedia.org/wiki/Window_function#Nuttall_window.2C_continuous_first_derivative - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> nuttall_cfd(int ntaps); - - /*! - * Deprecated: use nuttall_cfd window instead. - */ - static std::vector<float> nuttal_cfd(int ntaps); - - /*! - * \brief Build a flat top window. - * - * See: http://en.wikipedia.org/wiki/Window_function#Flat_top_window - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> flattop(int ntaps); - - /*! - * \brief Build a Kaiser window with a given beta. - * - * See: - * <pre> - * A. V. Oppenheim and R. W. Schafer, "Discrete-Time - * Signal Processing," Upper Saddle River, N.J.: Prentice - * Hall, 2010, pp. 541-545. - * </pre> - * - * \param ntaps Number of coefficients in the window. - * \param beta Shaping parameter of the window. See the - * discussion in Oppenheim and Schafer. - */ - static std::vector<float> kaiser(int ntaps, double beta); - - /*! - * \brief Build a Barlett (triangular) window. - * - * See: - * <pre> - * A. V. Oppenheim and R. W. Schafer, "Discrete-Time - * Signal Processing," Upper Saddle River, N.J.: Prentice - * Hall, 2010, pp. 535-538. - * </pre> - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> bartlett(int ntaps); - - static std::vector<float> welch(int ntaps); - - /*! - * \brief Build a Parzen (or de la Valle-Poussin) window. - * - * See: - * <pre> - * A. D. Poularikas, "Handbook of Formulas and Tables for - * Signal Processing," Springer, Oct 28, 1998 - * </pre> - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> parzen(int ntaps); - - /*! - * \brief Build an exponential window with a given decay. - * - * See: http://en.wikipedia.org/wiki/Window_function#Exponential_or_Poisson_window - * - * \param ntaps Number of coefficients in the window. - * \param d Decay of \p d dB over half the window length. - */ - static std::vector<float> exponential(int ntaps, double d); - - /*! - * \brief Build a Riemann window. - * - * See: - * <pre> - * A. D. Poularikas, "Handbook of Formulas and Tables for - * Signal Processing," Springer, Oct 28, 1998 - * </pre> - * - * \param ntaps Number of coefficients in the window. - */ - static std::vector<float> riemann(int ntaps); - - /*! - * \brief Build a window using gr::fft::win_type to index the - * type of window desired. - * - * \param type a gr::fft::win_type index for the type of window. - * \param ntaps Number of coefficients in the window. - * \param beta Used only for building Kaiser windows. - */ - static std::vector<float> build(win_type type, int ntaps, double beta); + WIN_BLACKMAN_HARRIS = + 5, //!< alias to WIN_BLACKMAN_hARRIS for capitalization consistency + WIN_BARTLETT = 6, //!< Barlett (triangular) window; max attenuation 26 dB + WIN_FLATTOP = 7, //!< flat top window; useful in FFTs; max attenuation 93 dB }; - } /* namespace fft */ + /*! + * \brief Given a window::win_type, this tells you the maximum + * attenuation you can expect. + * + * \details + * For most windows, this is a set value. For the Kaiser window, + * the attenuation is based on the value of beta. The actual + * relationship is a piece-wise exponential relationship to + * calculate beta from the desired attenuation and can be found + * on page 542 of Oppenheim and Schafer (Discrete-Time Signal + * Processing, 3rd edition). To simplify this function to solve + * for A given beta, we use a linear form that is exact for + * attenuation >= 50 dB. + * + * For an attenuation of 50 dB, beta = 4.55. + * + * For an attenuation of 70 dB, beta = 6.76. + * + * \param type The window::win_type enumeration of the window type. + * \param beta Beta value only used for the Kaiser window. + */ + static double max_attenuation(win_type type, double beta = 6.76); + + /*! + * \brief Helper function to build cosine-based windows. 3-coefficient version. + */ + static std::vector<float> coswindow(int ntaps, float c0, float c1, float c2); + + /*! + * \brief Helper function to build cosine-based windows. 4-coefficient version. + */ + static std::vector<float> + coswindow(int ntaps, float c0, float c1, float c2, float c3); + + /*! + * \brief Helper function to build cosine-based windows. 5-coefficient version. + */ + static std::vector<float> + coswindow(int ntaps, float c0, float c1, float c2, float c3, float c4); + + /*! + * \brief Build a rectangular window. + * + * Taps are flat across the window. + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> rectangular(int ntaps); + + /*! + * \brief Build a Hamming window. + * + * See: + * <pre> + * A. V. Oppenheim and R. W. Schafer, "Discrete-Time + * Signal Processing," Upper Saddle River, N.J.: Prentice + * Hall, 2010, pp. 535-538. + * </pre> + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> hamming(int ntaps); + + /*! + * \brief Build a Hann window (sometimes known as Hanning). + * + * See: + * <pre> + * A. V. Oppenheim and R. W. Schafer, "Discrete-Time + * Signal Processing," Upper Saddle River, N.J.: Prentice + * Hall, 2010, pp. 535-538. + * </pre> + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> hann(int ntaps); + + /*! + * \brief Alias to build a Hann window. + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> hanning(int ntaps); + + /*! + * \brief Build an exact Blackman window. + * + * See: + * <pre> + * A. V. Oppenheim and R. W. Schafer, "Discrete-Time + * Signal Processing," Upper Saddle River, N.J.: Prentice + * Hall, 2010, pp. 535-538. + * </pre> + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> blackman(int ntaps); + + /*! + * \brief Build Blackman window, variation 1. + */ + static std::vector<float> blackman2(int ntaps); + + /*! + * \brief Build Blackman window, variation 2. + */ + static std::vector<float> blackman3(int ntaps); + + /*! + * \brief Build Blackman window, variation 3. + */ + static std::vector<float> blackman4(int ntaps); + + /*! + * \brief Build a Blackman-harris window with a given attenuation. + * + * <pre> + * f. j. harris, "On the use of windows for harmonic analysis + * with the discrete Fourier transforms," Proc. IEEE, Vol. 66, + * ppg. 51-83, Jan. 1978. + * </pre> + * + * \param ntaps Number of coefficients in the window. + + * \param atten Attenuation factor. Must be [61, 67, 74, 92]. + * See the above paper for details. + */ + static std::vector<float> blackman_harris(int ntaps, int atten = 92); + + /*! + * Alias to gr::fft::window::blakcman_harris. + */ + static std::vector<float> blackmanharris(int ntaps, int atten = 92); + + /*! + * \brief Build a Nuttall (or Blackman-Nuttall) window. + * + * See: http://en.wikipedia.org/wiki/Window_function#Blackman.E2.80.93Nuttall_window + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> nuttall(int ntaps); + + /*! + * Deprecated: use nuttall window instead. + */ + static std::vector<float> nuttal(int ntaps); + + /*! + * \brief Alias to the Nuttall window. + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> blackman_nuttall(int ntaps); + + /*! + * Deprecated: use blackman_nuttall window instead. + */ + static std::vector<float> blackman_nuttal(int ntaps); + + /*! + * \brief Build a Nuttall continuous first derivative window. + * + * See: + * http://en.wikipedia.org/wiki/Window_function#Nuttall_window.2C_continuous_first_derivative + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> nuttall_cfd(int ntaps); + + /*! + * Deprecated: use nuttall_cfd window instead. + */ + static std::vector<float> nuttal_cfd(int ntaps); + + /*! + * \brief Build a flat top window. + * + * See: http://en.wikipedia.org/wiki/Window_function#Flat_top_window + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> flattop(int ntaps); + + /*! + * \brief Build a Kaiser window with a given beta. + * + * See: + * <pre> + * A. V. Oppenheim and R. W. Schafer, "Discrete-Time + * Signal Processing," Upper Saddle River, N.J.: Prentice + * Hall, 2010, pp. 541-545. + * </pre> + * + * \param ntaps Number of coefficients in the window. + * \param beta Shaping parameter of the window. See the + * discussion in Oppenheim and Schafer. + */ + static std::vector<float> kaiser(int ntaps, double beta); + + /*! + * \brief Build a Barlett (triangular) window. + * + * See: + * <pre> + * A. V. Oppenheim and R. W. Schafer, "Discrete-Time + * Signal Processing," Upper Saddle River, N.J.: Prentice + * Hall, 2010, pp. 535-538. + * </pre> + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> bartlett(int ntaps); + + static std::vector<float> welch(int ntaps); + + /*! + * \brief Build a Parzen (or de la Valle-Poussin) window. + * + * See: + * <pre> + * A. D. Poularikas, "Handbook of Formulas and Tables for + * Signal Processing," Springer, Oct 28, 1998 + * </pre> + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> parzen(int ntaps); + + /*! + * \brief Build an exponential window with a given decay. + * + * See: http://en.wikipedia.org/wiki/Window_function#Exponential_or_Poisson_window + * + * \param ntaps Number of coefficients in the window. + * \param d Decay of \p d dB over half the window length. + */ + static std::vector<float> exponential(int ntaps, double d); + + /*! + * \brief Build a Riemann window. + * + * See: + * <pre> + * A. D. Poularikas, "Handbook of Formulas and Tables for + * Signal Processing," Springer, Oct 28, 1998 + * </pre> + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> riemann(int ntaps); + + /*! + * \brief Build a window using gr::fft::win_type to index the + * type of window desired. + * + * \param type a gr::fft::win_type index for the type of window. + * \param ntaps Number of coefficients in the window. + * \param beta Used only for building Kaiser windows. + */ + static std::vector<float> build(win_type type, int ntaps, double beta); +}; + +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_WINDOW_H */ diff --git a/gr-fft/lib/ctrlport_probe_psd_impl.cc b/gr-fft/lib/ctrlport_probe_psd_impl.cc index a12341e931..cb172666c9 100644 --- a/gr-fft/lib/ctrlport_probe_psd_impl.cc +++ b/gr-fft/lib/ctrlport_probe_psd_impl.cc @@ -28,139 +28,139 @@ #include <gnuradio/io_signature.h> namespace gr { - namespace fft { - - ctrlport_probe_psd::sptr - ctrlport_probe_psd::make(const std::string &id, - const std::string &desc, int len) - { - return gnuradio::get_initial_sptr - (new ctrlport_probe_psd_impl(id, desc, len)); - } - - ctrlport_probe_psd_impl::ctrlport_probe_psd_impl(const std::string &id, - const std::string &desc, int len) - : gr::sync_block("probe_psd", - gr::io_signature::make(1, 1, sizeof(gr_complex)), - gr::io_signature::make(0, 0, 0)), - d_id(id), d_desc(desc), d_len(len), - d_fft(len, true, 1) - { - set_length(len); - } - - ctrlport_probe_psd_impl::~ctrlport_probe_psd_impl() - { - } - - void - ctrlport_probe_psd_impl::forecast(int noutput_items, - gr_vector_int &ninput_items_required) - { - // make sure all inputs have noutput_items available - unsigned ninputs = ninput_items_required.size(); - for(unsigned i = 0; i < ninputs; i++) +namespace fft { + +ctrlport_probe_psd::sptr +ctrlport_probe_psd::make(const std::string& id, const std::string& desc, int len) +{ + return gnuradio::get_initial_sptr(new ctrlport_probe_psd_impl(id, desc, len)); +} + +ctrlport_probe_psd_impl::ctrlport_probe_psd_impl(const std::string& id, + const std::string& desc, + int len) + : gr::sync_block("probe_psd", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(0, 0, 0)), + d_id(id), + d_desc(desc), + d_len(len), + d_fft(len, true, 1) +{ + set_length(len); +} + +ctrlport_probe_psd_impl::~ctrlport_probe_psd_impl() {} + +void ctrlport_probe_psd_impl::forecast(int noutput_items, + gr_vector_int& ninput_items_required) +{ + // make sure all inputs have noutput_items available + unsigned ninputs = ninput_items_required.size(); + for (unsigned i = 0; i < ninputs; i++) ninput_items_required[i] = d_len; +} + +// boost::shared_mutex mutex_buffer; +// mutable boost::mutex mutex_notify; +// boost::condition_variable condition_buffer_ready; +std::vector<gr_complex> ctrlport_probe_psd_impl::get() +{ + mutex_buffer.lock(); + d_buffer.clear(); + mutex_buffer.unlock(); + + // wait for condition + boost::mutex::scoped_lock lock(mutex_notify); + condition_buffer_ready.wait(lock); + + mutex_buffer.lock(); + + memcpy(d_fft.get_inbuf(), &d_buffer[0], d_len * sizeof(gr_complex)); + d_fft.execute(); + std::vector<gr_complex> buf_copy; + + buf_copy.resize(d_len); + + gr_complex* out = d_fft.get_outbuf(); + for (size_t i = 0; i < d_len; i++) { + size_t idx = (i + d_len / 2) % d_len; + float x = i / (d_len - 1.0f) - 0.5; + buf_copy[i] = gr_complex(x, 10 * log10((out[idx] * std::conj(out[idx])).real())); } - - // boost::shared_mutex mutex_buffer; - // mutable boost::mutex mutex_notify; - // boost::condition_variable condition_buffer_ready; - std::vector<gr_complex> - ctrlport_probe_psd_impl::get() - { - mutex_buffer.lock(); - d_buffer.clear(); - mutex_buffer.unlock(); - - // wait for condition - boost::mutex::scoped_lock lock(mutex_notify); - condition_buffer_ready.wait(lock); - - mutex_buffer.lock(); - - memcpy(d_fft.get_inbuf(), &d_buffer[0], d_len*sizeof(gr_complex)); - d_fft.execute(); - std::vector<gr_complex> buf_copy; - - buf_copy.resize(d_len); - - gr_complex* out = d_fft.get_outbuf(); - for(size_t i=0; i<d_len; i++){ - size_t idx = (i + d_len/2)%d_len; - float x = i/(d_len-1.0f)-0.5; - buf_copy[i] = gr_complex(x, 10*log10( (out[idx]*std::conj(out[idx])).real() ) ); - } - mutex_buffer.unlock(); - return buf_copy; - } - - void - ctrlport_probe_psd_impl::set_length(int len) - { - if(len > 8191) { - std::cerr << "probe_psd: length " << len - << " exceeds maximum buffer size of 8191" << std::endl; + mutex_buffer.unlock(); + return buf_copy; +} + +void ctrlport_probe_psd_impl::set_length(int len) +{ + if (len > 8191) { + std::cerr << "probe_psd: length " << len << " exceeds maximum buffer size of 8191" + << std::endl; len = 8191; - } - - d_len = len; - d_buffer.reserve(d_len); } - int - ctrlport_probe_psd_impl::length() const - { - return (int)d_len; - } + d_len = len; + d_buffer.reserve(d_len); +} - int - ctrlport_probe_psd_impl::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]; +int ctrlport_probe_psd_impl::length() const { return (int)d_len; } - // copy samples to get buffer if we need samples - mutex_buffer.lock(); - if(d_buffer.size() < d_len) { +int ctrlport_probe_psd_impl::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]; + + // copy samples to get buffer if we need samples + mutex_buffer.lock(); + if (d_buffer.size() < d_len) { // copy smaller of remaining buffer space and num inputs to work() - int num_copy = std::min( (int)(d_len - d_buffer.size()), noutput_items ); + int num_copy = std::min((int)(d_len - d_buffer.size()), noutput_items); // TODO: convert this to a copy operator for speed... - for(int i = 0; i < num_copy; i++) { - d_buffer.push_back(in[i]); + for (int i = 0; i < num_copy; i++) { + d_buffer.push_back(in[i]); } // notify the waiting get() if we fill up the buffer - if(d_buffer.size() == d_len) { - condition_buffer_ready.notify_one(); + if (d_buffer.size() == d_len) { + condition_buffer_ready.notify_one(); } - } - mutex_buffer.unlock(); - - return noutput_items; } + mutex_buffer.unlock(); - void - ctrlport_probe_psd_impl::setup_rpc() - { + return noutput_items; +} + +void ctrlport_probe_psd_impl::setup_rpc() +{ #ifdef GR_CTRLPORT - int len = static_cast<int>(d_len); - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe_psd, std::vector<std::complex<float> > >( - alias(), d_id.c_str(), &ctrlport_probe_psd::get, - pmt::make_c32vector(0,-2), - pmt::make_c32vector(0,2), - pmt::make_c32vector(0,0), - "dB", d_desc.c_str(), RPC_PRIVLVL_MIN, - DISPXY | DISPOPTSCATTER))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<ctrlport_probe_psd, int>( - alias(), "length", &ctrlport_probe_psd::length, - pmt::mp(1), pmt::mp(10*len), pmt::mp(len), - "samples", "get vector length", RPC_PRIVLVL_MIN, DISPNULL))); + int len = static_cast<int>(d_len); + d_rpc_vars.push_back(rpcbasic_sptr( + new rpcbasic_register_get<ctrlport_probe_psd, std::vector<std::complex<float>>>( + alias(), + d_id.c_str(), + &ctrlport_probe_psd::get, + pmt::make_c32vector(0, -2), + pmt::make_c32vector(0, 2), + pmt::make_c32vector(0, 0), + "dB", + d_desc.c_str(), + RPC_PRIVLVL_MIN, + DISPXY | DISPOPTSCATTER))); + + d_rpc_vars.push_back(rpcbasic_sptr( + new rpcbasic_register_get<ctrlport_probe_psd, int>(alias(), + "length", + &ctrlport_probe_psd::length, + pmt::mp(1), + pmt::mp(10 * len), + pmt::mp(len), + "samples", + "get vector length", + RPC_PRIVLVL_MIN, + DISPNULL))); // d_rpc_vars.push_back( // rpcbasic_sptr(new rpcbasic_register_set<ctrlport_probe_psd, int>( @@ -168,7 +168,7 @@ namespace gr { // pmt::mp(1), pmt::mp(10*len), pmt::mp(len), // "samples", "set vector length", RPC_PRIVLVL_MIN, DISPNULL))); #endif /* GR_CTRLPORT */ - } +} - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ diff --git a/gr-fft/lib/ctrlport_probe_psd_impl.h b/gr-fft/lib/ctrlport_probe_psd_impl.h index c8277a4022..58b1f10414 100644 --- a/gr-fft/lib/ctrlport_probe_psd_impl.h +++ b/gr-fft/lib/ctrlport_probe_psd_impl.h @@ -29,41 +29,40 @@ #include <gnuradio/fft/fft.h> namespace gr { - namespace fft { +namespace fft { - class ctrlport_probe_psd_impl : public ctrlport_probe_psd - { - private: - std::string d_id; - std::string d_desc; - size_t d_len; - boost::shared_mutex mutex_buffer; - mutable boost::mutex mutex_notify; - boost::condition_variable condition_buffer_ready; +class ctrlport_probe_psd_impl : public ctrlport_probe_psd +{ +private: + std::string d_id; + std::string d_desc; + size_t d_len; + boost::shared_mutex mutex_buffer; + mutable boost::mutex mutex_notify; + boost::condition_variable condition_buffer_ready; - std::vector<gr_complex> d_buffer; - gr::fft::fft_complex d_fft; + std::vector<gr_complex> d_buffer; + gr::fft::fft_complex d_fft; - public: - ctrlport_probe_psd_impl(const std::string &id, const std::string &desc, int len); - ~ctrlport_probe_psd_impl(); +public: + ctrlport_probe_psd_impl(const std::string& id, const std::string& desc, int len); + ~ctrlport_probe_psd_impl(); - void setup_rpc(); + void setup_rpc(); - void forecast(int noutput_items, gr_vector_int &ninput_items_required); + void forecast(int noutput_items, gr_vector_int& ninput_items_required); - std::vector<gr_complex> get(); + std::vector<gr_complex> get(); - void set_length(int len); - int length() const; + void set_length(int len); + int length() const; - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace blocks */ +} // namespace fft } /* namespace gr */ #endif /* INCLUDED_CTRLPORT_PROBE_PSD_IMPL_H */ - diff --git a/gr-fft/lib/fft.cc b/gr-fft/lib/fft.cc index 718cd0990f..68070d2399 100644 --- a/gr-fft/lib/fft.cc +++ b/gr-fft/lib/fft.cc @@ -26,17 +26,19 @@ #include <volk/volk.h> #include <fftw3.h> -#ifdef _WIN32 //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)) -#include <fcntl.h> +#ifdef _WIN32 // 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)) +#include <fcntl.h> #include <io.h> #define O_NOCTTY 0 #define O_NONBLOCK 0 @@ -54,349 +56,319 @@ static int my_fftw_read_char(void *f) { return fgetc((FILE *) f); } namespace fs = boost::filesystem; namespace gr { - namespace fft { - static boost::mutex wisdom_thread_mutex; - boost::interprocess::file_lock wisdom_lock; - static bool wisdom_lock_init_done = false; // Modify while holding 'wisdom_thread_mutex' - - gr_complex * - malloc_complex(int size) - { - return (gr_complex*) volk_malloc (sizeof (gr_complex)*size, volk_get_alignment ()); - } - - float * - malloc_float(int size) - { - return (float*) volk_malloc (sizeof (float)*size, volk_get_alignment ()); - } +namespace fft { +static boost::mutex wisdom_thread_mutex; +boost::interprocess::file_lock wisdom_lock; +static bool wisdom_lock_init_done = false; // Modify while holding 'wisdom_thread_mutex' + +gr_complex* malloc_complex(int size) +{ + return (gr_complex*)volk_malloc(sizeof(gr_complex) * size, volk_get_alignment()); +} + +float* malloc_float(int size) +{ + return (float*)volk_malloc(sizeof(float) * size, volk_get_alignment()); +} + +double* malloc_double(int size) +{ + return (double*)volk_malloc(sizeof(double) * size, volk_get_alignment()); +} + +void free(void* b) { volk_free(b); } + +boost::mutex& planner::mutex() +{ + static boost::mutex s_planning_mutex; + + return s_planning_mutex; +} + +static std::string wisdom_filename() +{ + static fs::path path; + path = fs::path(gr::appdata_path()) / ".gr_fftw_wisdom"; + return path.string(); +} + +static void wisdom_lock_init() +{ + if (wisdom_lock_init_done) + return; - double * - malloc_double(int size) - { - return (double*) volk_malloc (sizeof (double)*size, volk_get_alignment ()); + const std::string wisdom_lock_file = wisdom_filename() + ".lock"; + // std::cerr << "Creating FFTW wisdom lockfile: " << wisdom_lock_file << std::endl; + int fd = + open(wisdom_lock_file.c_str(), O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0666); + if (fd < 0) { + throw std::runtime_error("Failed to create FFTW wisdom lockfile: " + + wisdom_lock_file); } - - void - free(void *b) - { - volk_free(b); + close(fd); + wisdom_lock = boost::interprocess::file_lock(wisdom_lock_file.c_str()); + wisdom_lock_init_done = true; +} + +static void lock_wisdom() +{ + wisdom_thread_mutex.lock(); + wisdom_lock_init(); + wisdom_lock.lock(); +} + +static void unlock_wisdom() +{ + // Assumes 'lock_wisdom' has already been called (i.e. this file_lock is valid) + wisdom_lock.unlock(); + wisdom_thread_mutex.unlock(); +} + +static void import_wisdom() +{ + const std::string filename = wisdom_filename(); + FILE* fp = fopen(filename.c_str(), "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.c_str()); + } } +} - boost::mutex & - planner::mutex() - { - static boost::mutex s_planning_mutex; +static void config_threading(int nthreads) +{ + static int fftw_threads_inited = 0; - return s_planning_mutex; +#ifdef FFTW3F_THREADS + if (fftw_threads_inited == 0) { + fftw_threads_inited = 1; + fftwf_init_threads(); } - static std::string - wisdom_filename() - { - static fs::path path; - path = fs::path(gr::appdata_path()) / ".gr_fftw_wisdom"; - return path.string(); + fftwf_plan_with_nthreads(nthreads); +#endif +} + +static void export_wisdom() +{ + const std::string filename = wisdom_filename(); + FILE* fp = fopen(filename.c_str(), "w"); + if (fp != 0) { + fftwf_export_wisdom_to_file(fp); + fclose(fp); + } else { + fprintf(stderr, "fft_impl_fftw: "); + perror(filename.c_str()); } +} - static void - wisdom_lock_init() - { - if (wisdom_lock_init_done) - return; +// ---------------------------------------------------------------- - const std::string wisdom_lock_file = wisdom_filename() + ".lock"; - // std::cerr << "Creating FFTW wisdom lockfile: " << wisdom_lock_file << std::endl; - int fd = open(wisdom_lock_file.c_str(), - O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, - 0666); - if (fd < 0) { - throw std::runtime_error("Failed to create FFTW wisdom lockfile: " + wisdom_lock_file); - } - close(fd); - wisdom_lock = boost::interprocess::file_lock(wisdom_lock_file.c_str()); - wisdom_lock_init_done = true; - } +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()); - static void - lock_wisdom() - { - wisdom_thread_mutex.lock(); - wisdom_lock_init(); - wisdom_lock.lock(); - } + assert(sizeof(fftwf_complex) == sizeof(gr_complex)); - static void - unlock_wisdom() - { - // Assumes 'lock_wisdom' has already been called (i.e. this file_lock is valid) - wisdom_lock.unlock(); - wisdom_thread_mutex.unlock(); + if (fft_size <= 0) { + throw std::out_of_range("fft_impl_fftw: invalid fft_size"); } - static void - import_wisdom() - { - const std::string filename = wisdom_filename (); - FILE *fp = fopen (filename.c_str(), "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.c_str()); - } - } + d_fft_size = fft_size; + d_inbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * inbuf_length(), + volk_get_alignment()); + if (d_inbuf == 0) { + throw std::runtime_error("volk_malloc"); } - - 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(); + d_outbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * outbuf_length(), + volk_get_alignment()); + if (d_outbuf == 0) { + volk_free(d_inbuf); + throw std::runtime_error("volk_malloc"); } - fftwf_plan_with_nthreads(nthreads); -#endif - } + d_nthreads = nthreads; + config_threading(nthreads); + lock_wisdom(); + import_wisdom(); // load prior wisdom from disk - static void - export_wisdom() - { - const std::string filename = wisdom_filename (); - FILE *fp = fopen (filename.c_str(), "w"); - if (fp != 0){ - fftwf_export_wisdom_to_file (fp); - fclose (fp); - } - else { - fprintf (stderr, "fft_impl_fftw: "); - perror (filename.c_str()); - } - } - -// ---------------------------------------------------------------- + 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); - 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 *) volk_malloc (sizeof (gr_complex) * inbuf_length (), volk_get_alignment ()); - if (d_inbuf == 0) { - throw std::runtime_error ("volk_malloc"); - } - d_outbuf = (gr_complex *) volk_malloc (sizeof (gr_complex) * outbuf_length (), volk_get_alignment ()); - if (d_outbuf == 0) { - volk_free (d_inbuf); - throw std::runtime_error ("volk_malloc"); - } - - d_nthreads = nthreads; - config_threading(nthreads); - lock_wisdom(); - 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) { + 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 - unlock_wisdom(); + throw std::runtime_error("fftwf_plan_dft_1d failed"); } - - 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); - volk_free (d_inbuf); - volk_free (d_outbuf); + export_wisdom(); // store new wisdom to disk + unlock_wisdom(); +} + +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); + volk_free(d_inbuf); + volk_free(d_outbuf); +} + +void fft_complex::set_nthreads(int n) +{ + if (n <= 0) { + throw std::out_of_range("gr::fft: invalid number of threads"); } - - void - fft_complex::set_nthreads(int n) - { - if (n <= 0) { - throw std::out_of_range ("gr::fft: invalid number of threads"); - } - d_nthreads = n; + d_nthreads = n; #ifdef FFTW3F_THREADS - fftwf_plan_with_nthreads(d_nthreads); + fftwf_plan_with_nthreads(d_nthreads); #endif - } +} - void - fft_complex::execute() - { - fftwf_execute((fftwf_plan) d_plan); - } +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()); +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)); + assert(sizeof(fftwf_complex) == sizeof(gr_complex)); - if (fft_size <= 0) { - throw std::out_of_range ("gr::fft: invalid fft_size"); - } + if (fft_size <= 0) { + throw std::out_of_range("gr::fft: invalid fft_size"); + } - d_fft_size = fft_size; - d_inbuf = (float *) volk_malloc (sizeof (float) * inbuf_length (), volk_get_alignment ()); - if (d_inbuf == 0) { - throw std::runtime_error ("volk_malloc"); - } + d_fft_size = fft_size; + d_inbuf = (float*)volk_malloc(sizeof(float) * inbuf_length(), volk_get_alignment()); + if (d_inbuf == 0) { + throw std::runtime_error("volk_malloc"); + } - d_outbuf = (gr_complex *) volk_malloc (sizeof (gr_complex) * outbuf_length (), volk_get_alignment ()); - if (d_outbuf == 0) { - volk_free (d_inbuf); - throw std::runtime_error ("volk_malloc"); - } + d_outbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * outbuf_length(), + volk_get_alignment()); + if (d_outbuf == 0) { + volk_free(d_inbuf); + throw std::runtime_error("volk_malloc"); + } - d_nthreads = nthreads; - config_threading(nthreads); - lock_wisdom(); - import_wisdom(); // load prior wisdom from disk + d_nthreads = nthreads; + config_threading(nthreads); + lock_wisdom(); + 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); + d_plan = fftwf_plan_dft_r2c_1d( + fft_size, d_inbuf, reinterpret_cast<fftwf_complex*>(d_outbuf), FFTW_MEASURE); - if (d_plan == NULL) { + 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 - unlock_wisdom(); + throw std::runtime_error("fftwf_plan_dft_r2c_1d failed"); } - - 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); - volk_free (d_inbuf); - volk_free (d_outbuf); + export_wisdom(); // store new wisdom to disk + unlock_wisdom(); +} + +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); + volk_free(d_inbuf); + volk_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"); } - - 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; + d_nthreads = n; #ifdef FFTW3F_THREADS - fftwf_plan_with_nthreads(d_nthreads); + 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"); } - void - fft_real_fwd::execute() - { - fftwf_execute ((fftwf_plan) d_plan); + d_fft_size = fft_size; + d_inbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * inbuf_length(), + volk_get_alignment()); + if (d_inbuf == 0) { + throw std::runtime_error("volk_malloc"); } - // ---------------------------------------------------------------- - - 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 *) volk_malloc (sizeof (gr_complex) * inbuf_length (), volk_get_alignment ()); - if (d_inbuf == 0) { - throw std::runtime_error ("volk_malloc"); - } - - d_outbuf = (float *) volk_malloc (sizeof (float) * outbuf_length (), volk_get_alignment ()); - if (d_outbuf == 0) { - volk_free (d_inbuf); - throw std::runtime_error ("volk_malloc"); - } - - d_nthreads = nthreads; - config_threading(nthreads); - lock_wisdom(); - 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 - unlock_wisdom(); + d_outbuf = (float*)volk_malloc(sizeof(float) * outbuf_length(), volk_get_alignment()); + if (d_outbuf == 0) { + volk_free(d_inbuf); + throw std::runtime_error("volk_malloc"); } - fft_real_rev::~fft_real_rev () - { - // Hold global mutex during plan construction and destruction. - planner::scoped_lock lock(planner::mutex()); + d_nthreads = nthreads; + config_threading(nthreads); + lock_wisdom(); + import_wisdom(); // load prior wisdom from disk - fftwf_destroy_plan ((fftwf_plan) d_plan); - volk_free (d_inbuf); - volk_free (d_outbuf); - } + // 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); - 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; + 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 + unlock_wisdom(); +} + +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); + volk_free(d_inbuf); + volk_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); + fftwf_plan_with_nthreads(d_nthreads); #endif - } +} - void - fft_real_rev::execute () - { - fftwf_execute ((fftwf_plan) d_plan); - } +void fft_real_rev::execute() { fftwf_execute((fftwf_plan)d_plan); } - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ diff --git a/gr-fft/lib/fft_vcc_fftw.cc b/gr-fft/lib/fft_vcc_fftw.cc index 3b23058df5..9c546a92d7 100644 --- a/gr-fft/lib/fft_vcc_fftw.cc +++ b/gr-fft/lib/fft_vcc_fftw.cc @@ -30,117 +30,111 @@ #include <volk/volk.h> namespace gr { - namespace fft { - - fft_vcc::sptr fft_vcc::make(int fft_size, bool forward, - const std::vector<float> &window, - bool shift, int nthreads) - { - return gnuradio::get_initial_sptr(new fft_vcc_fftw - (fft_size, forward, window, - shift, nthreads)); - } - - fft_vcc_fftw::fft_vcc_fftw(int fft_size, bool forward, - const std::vector<float> &window, - bool shift, int nthreads) - : sync_block("fft_vcc_fftw", - io_signature::make(1, 1, fft_size * sizeof(gr_complex)), - io_signature::make(1, 1, fft_size * sizeof(gr_complex))), - d_fft_size(fft_size), d_forward(forward), d_shift(shift) - { - d_fft = new fft_complex(d_fft_size, forward, nthreads); - if(!set_window(window)) +namespace fft { + +fft_vcc::sptr fft_vcc::make(int fft_size, + bool forward, + const std::vector<float>& window, + bool shift, + int nthreads) +{ + return gnuradio::get_initial_sptr( + new fft_vcc_fftw(fft_size, forward, window, shift, nthreads)); +} + +fft_vcc_fftw::fft_vcc_fftw(int fft_size, + bool forward, + const std::vector<float>& window, + bool shift, + int nthreads) + : sync_block("fft_vcc_fftw", + io_signature::make(1, 1, fft_size * sizeof(gr_complex)), + io_signature::make(1, 1, fft_size * sizeof(gr_complex))), + d_fft_size(fft_size), + d_forward(forward), + d_shift(shift) +{ + d_fft = new fft_complex(d_fft_size, forward, nthreads); + if (!set_window(window)) throw std::runtime_error("fft_vcc: window not the same length as fft_size\n"); - } - - fft_vcc_fftw::~fft_vcc_fftw() - { - delete d_fft; - } - - void - fft_vcc_fftw::set_nthreads(int n) - { - d_fft->set_nthreads(n); - } +} + +fft_vcc_fftw::~fft_vcc_fftw() { delete d_fft; } + +void fft_vcc_fftw::set_nthreads(int n) { d_fft->set_nthreads(n); } + +int fft_vcc_fftw::nthreads() const { return d_fft->nthreads(); } + +bool fft_vcc_fftw::set_window(const std::vector<float>& window) +{ + if (window.size() == 0 || window.size() == d_fft_size) { + d_window = window; + return true; + } else + return false; +} + +int 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(); + if (!d_forward && d_shift) { + unsigned int offset = (!d_forward && d_shift) ? (d_fft_size / 2) : 0; + int fft_m_offset = d_fft_size - offset; + volk_32fc_32f_multiply_32fc( + &dst[fft_m_offset], &in[0], &d_window[0], offset); + volk_32fc_32f_multiply_32fc( + &dst[0], &in[offset], &d_window[offset], d_fft_size - offset); + } else { + volk_32fc_32f_multiply_32fc(&dst[0], in, &d_window[0], d_fft_size); + } + } 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); + } + } - int - fft_vcc_fftw::nthreads() const - { - return d_fft->nthreads(); - } + // 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); + } - bool - fft_vcc_fftw::set_window(const std::vector<float> &window) - { - if(window.size()==0 || window.size()==d_fft_size) { - d_window=window; - return true; - } - else - return false; + in += d_fft_size; + out += d_fft_size; } - int - 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(); - if(!d_forward && d_shift) { - unsigned int offset = (!d_forward && d_shift)?(d_fft_size/2):0; - int fft_m_offset = d_fft_size - offset; - volk_32fc_32f_multiply_32fc(&dst[fft_m_offset], &in[0], &d_window[0], offset); - volk_32fc_32f_multiply_32fc(&dst[0], &in[offset], &d_window[offset], d_fft_size-offset); - } - else { - volk_32fc_32f_multiply_32fc(&dst[0], in, &d_window[0], d_fft_size); - } - } - 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; - } + return noutput_items; +} - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ diff --git a/gr-fft/lib/fft_vcc_fftw.h b/gr-fft/lib/fft_vcc_fftw.h index 375bb62a35..45afdd024f 100644 --- a/gr-fft/lib/fft_vcc_fftw.h +++ b/gr-fft/lib/fft_vcc_fftw.h @@ -27,34 +27,36 @@ #include <gnuradio/fft/fft.h> namespace gr { - namespace fft { - - class FFT_API fft_vcc_fftw : public fft_vcc - { - private: - fft_complex *d_fft; - unsigned int d_fft_size; - std::vector<float> d_window; - bool d_forward; - bool d_shift; - - public: - fft_vcc_fftw(int fft_size, bool forward, - const std::vector<float> &window, - bool shift, int nthreads=1); - - ~fft_vcc_fftw(); - - void set_nthreads(int n); - int nthreads() const; - bool set_window(const std::vector<float> &window); - - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; - - } /* namespace fft */ +namespace fft { + +class FFT_API fft_vcc_fftw : public fft_vcc +{ +private: + fft_complex* d_fft; + unsigned int d_fft_size; + std::vector<float> d_window; + bool d_forward; + bool d_shift; + +public: + fft_vcc_fftw(int fft_size, + bool forward, + const std::vector<float>& window, + bool shift, + int nthreads = 1); + + ~fft_vcc_fftw(); + + void set_nthreads(int n); + int nthreads() const; + bool set_window(const std::vector<float>& window); + + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_FFT_VCC_FFTW_IMPL_H */ diff --git a/gr-fft/lib/fft_vfc_fftw.cc b/gr-fft/lib/fft_vfc_fftw.cc index b635c3b9bd..eac4268ba5 100644 --- a/gr-fft/lib/fft_vfc_fftw.cc +++ b/gr-fft/lib/fft_vfc_fftw.cc @@ -30,97 +30,81 @@ #include <string.h> namespace gr { - namespace fft { - - fft_vfc::sptr fft_vfc::make(int fft_size, bool forward, - const std::vector<float> &window, - int nthreads) - { - return gnuradio::get_initial_sptr(new fft_vfc_fftw - (fft_size, forward, window, - nthreads)); - } - - fft_vfc_fftw::fft_vfc_fftw(int fft_size, bool forward, - const std::vector<float> &window, - int nthreads) - : sync_block("fft_vfc_fftw", - io_signature::make(1, 1, fft_size * sizeof(float)), - io_signature::make(1, 1, fft_size * sizeof(gr_complex))), - d_fft_size(fft_size), d_forward(forward) - { - d_fft = new fft_complex(d_fft_size, d_forward, nthreads); - if(!set_window(window)) +namespace fft { + +fft_vfc::sptr +fft_vfc::make(int fft_size, bool forward, const std::vector<float>& window, int nthreads) +{ + return gnuradio::get_initial_sptr( + new fft_vfc_fftw(fft_size, forward, window, nthreads)); +} + +fft_vfc_fftw::fft_vfc_fftw(int fft_size, + bool forward, + const std::vector<float>& window, + int nthreads) + : sync_block("fft_vfc_fftw", + io_signature::make(1, 1, fft_size * sizeof(float)), + io_signature::make(1, 1, fft_size * sizeof(gr_complex))), + d_fft_size(fft_size), + d_forward(forward) +{ + d_fft = new fft_complex(d_fft_size, d_forward, nthreads); + if (!set_window(window)) throw std::runtime_error("fft_vfc: window not the same length as fft_size\n"); - } - - fft_vfc_fftw::~fft_vfc_fftw() - { - delete d_fft; - } +} - void - fft_vfc_fftw::set_nthreads(int n) - { - d_fft->set_nthreads(n); - } +fft_vfc_fftw::~fft_vfc_fftw() { delete d_fft; } - int - fft_vfc_fftw::nthreads() const - { - return d_fft->nthreads(); - } +void fft_vfc_fftw::set_nthreads(int n) { d_fft->set_nthreads(n); } - bool - fft_vfc_fftw::set_window(const std::vector<float> &window) - { - if(window.size()==0 || window.size()==d_fft_size) { - d_window=window; - return true; - } - else - return false; - } +int fft_vfc_fftw::nthreads() const { return d_fft->nthreads(); } - int - fft_vfc_fftw::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - const float *in = (const float *)input_items[0]; - gr_complex *out = (gr_complex *)output_items[0]; +bool fft_vfc_fftw::set_window(const std::vector<float>& window) +{ + if (window.size() == 0 || window.size() == d_fft_size) { + d_window = window; + return true; + } else + return false; +} - unsigned int output_data_size = output_signature()->sizeof_stream_item (0); +int fft_vfc_fftw::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + const float* in = (const float*)input_items[0]; + gr_complex* out = (gr_complex*)output_items[0]; - int count = 0; + unsigned int output_data_size = output_signature()->sizeof_stream_item(0); - while(count++ < noutput_items) { + int count = 0; - // 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 { - gr_complex *dst = d_fft->get_inbuf(); - for(unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion - dst[i] = in[i]; - } + while (count++ < noutput_items) { - // compute the fft - d_fft->execute(); + // 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 { + gr_complex* dst = d_fft->get_inbuf(); + for (unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion + dst[i] = in[i]; + } - // copy result to output stream - memcpy(out, d_fft->get_outbuf(), output_data_size); + // compute the fft + d_fft->execute(); - in += d_fft_size; - out += d_fft_size; - } + // copy result to output stream + memcpy(out, d_fft->get_outbuf(), output_data_size); - return noutput_items; + in += d_fft_size; + out += d_fft_size; } - } /* namespace fft */ -} /* namespace gr */ + return noutput_items; +} +} /* namespace fft */ +} /* namespace gr */ diff --git a/gr-fft/lib/fft_vfc_fftw.h b/gr-fft/lib/fft_vfc_fftw.h index f500129e2e..4b0e905643 100644 --- a/gr-fft/lib/fft_vfc_fftw.h +++ b/gr-fft/lib/fft_vfc_fftw.h @@ -27,33 +27,34 @@ #include <gnuradio/fft/fft.h> namespace gr { - namespace fft { - - class FFT_API fft_vfc_fftw : public fft_vfc - { - private: - fft_complex *d_fft; - unsigned int d_fft_size; - std::vector<float> d_window; - bool d_forward; - - public: - fft_vfc_fftw(int fft_size, bool forward, - const std::vector<float> &window, - int nthreads=1); - - ~fft_vfc_fftw(); - - void set_nthreads(int n); - int nthreads() const; - bool set_window(const std::vector<float> &window); - - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; - - } /* namespace fft */ +namespace fft { + +class FFT_API fft_vfc_fftw : public fft_vfc +{ +private: + fft_complex* d_fft; + unsigned int d_fft_size; + std::vector<float> d_window; + bool d_forward; + +public: + fft_vfc_fftw(int fft_size, + bool forward, + const std::vector<float>& window, + int nthreads = 1); + + ~fft_vfc_fftw(); + + void set_nthreads(int n); + int nthreads() const; + bool set_window(const std::vector<float>& window); + + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_FFT_VFC_FFTW_IMPL_H */ diff --git a/gr-fft/lib/goertzel.cc b/gr-fft/lib/goertzel.cc index 324d2a76a2..96b41b0126 100644 --- a/gr-fft/lib/goertzel.cc +++ b/gr-fft/lib/goertzel.cc @@ -29,57 +29,49 @@ #include <cmath> namespace gr { - namespace fft { +namespace fft { - goertzel::goertzel(int rate, int len, float freq) - { - set_params(rate, len, freq); - } +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; +void goertzel::set_params(int rate, int len, float freq) +{ + d_d1 = 0.0; + d_d2 = 0.0; - float w = 2.0*GR_M_PI*freq/rate; - d_wr = 2.0*std::cos(w); - d_wi = std::sin(w); - d_len = len; - d_processed = 0; - } + float w = 2.0 * GR_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; +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]); + for (int i = 0; i < d_len; i++) + input(in[i]); - return output(); - } + 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++; - } +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 */ +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.cc b/gr-fft/lib/goertzel_fc_impl.cc index ba26df0ca3..a8f9d58b5a 100644 --- a/gr-fft/lib/goertzel_fc_impl.cc +++ b/gr-fft/lib/goertzel_fc_impl.cc @@ -28,58 +28,53 @@ #include <gnuradio/io_signature.h> namespace gr { - namespace fft { +namespace fft { - goertzel_fc::sptr goertzel_fc::make(int rate, int len, float freq) - { - return gnuradio::get_initial_sptr(new goertzel_fc_impl(rate, len, freq)); - } +goertzel_fc::sptr goertzel_fc::make(int rate, int len, float freq) +{ + return gnuradio::get_initial_sptr(new goertzel_fc_impl(rate, len, freq)); +} - goertzel_fc_impl::goertzel_fc_impl(int rate, int len, float freq) - : sync_decimator("goertzel_fc", - io_signature::make (1, 1, sizeof(float)), - io_signature::make (1, 1, sizeof(gr_complex)), - len), - d_goertzel(rate, len, freq) - { - d_len = len; - d_rate = rate; - d_freq = freq; - } +goertzel_fc_impl::goertzel_fc_impl(int rate, int len, float freq) + : sync_decimator("goertzel_fc", + io_signature::make(1, 1, sizeof(float)), + io_signature::make(1, 1, sizeof(gr_complex)), + len), + d_goertzel(rate, len, freq) +{ + d_len = len; + d_rate = rate; + d_freq = freq; +} - goertzel_fc_impl::~goertzel_fc_impl() - { - } +goertzel_fc_impl::~goertzel_fc_impl() {} - void - goertzel_fc_impl::set_freq(float freq) - { - d_freq = freq; - d_goertzel.set_params(d_rate, d_len, d_freq); - } +void goertzel_fc_impl::set_freq(float freq) +{ + d_freq = freq; + d_goertzel.set_params(d_rate, d_len, d_freq); +} - void - goertzel_fc_impl::set_rate(int rate) - { - d_rate = rate; - d_goertzel.set_params(d_rate, d_len, d_freq); - } - - int - goertzel_fc_impl::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - float *in = (float *)input_items[0]; - gr_complex *out = (gr_complex *)output_items[0]; +void goertzel_fc_impl::set_rate(int rate) +{ + d_rate = rate; + d_goertzel.set_params(d_rate, d_len, d_freq); +} - for(int i = 0; i < noutput_items; i++) { - *out++ = d_goertzel.batch(in); - in += d_len; - } +int goertzel_fc_impl::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + float* in = (float*)input_items[0]; + gr_complex* out = (gr_complex*)output_items[0]; - return noutput_items; + for (int i = 0; i < noutput_items; i++) { + *out++ = d_goertzel.batch(in); + in += d_len; } - } /* namespace fft */ + return noutput_items; +} + +} /* namespace fft */ } /* namespace gr */ diff --git a/gr-fft/lib/goertzel_fc_impl.h b/gr-fft/lib/goertzel_fc_impl.h index e007bcfb73..607e7e1f95 100644 --- a/gr-fft/lib/goertzel_fc_impl.h +++ b/gr-fft/lib/goertzel_fc_impl.h @@ -27,34 +27,33 @@ #include <gnuradio/fft/goertzel.h> namespace gr { - namespace fft { +namespace fft { - class FFT_API goertzel_fc_impl : public goertzel_fc - { - private: - goertzel d_goertzel; - int d_len; - float d_freq; - int d_rate; +class FFT_API goertzel_fc_impl : public goertzel_fc +{ +private: + goertzel d_goertzel; + int d_len; + float d_freq; + int d_rate; - public: - goertzel_fc_impl(int rate, int len, float freq); +public: + goertzel_fc_impl(int rate, int len, float freq); - ~goertzel_fc_impl(); + ~goertzel_fc_impl(); - void set_freq(float freq); - void set_rate(int rate); + void set_freq(float freq); + void set_rate(int rate); - float freq() { return d_freq; } - int rate() { return d_rate; } + float freq() { return d_freq; } + int rate() { return d_rate; } - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ #endif /* INCLUDED_FFT_GOERTZEL_FC_IMPL_H */ - diff --git a/gr-fft/lib/qa_fft_shift.cc b/gr-fft/lib/qa_fft_shift.cc index e924af8629..fb587ec1dc 100644 --- a/gr-fft/lib/qa_fft_shift.cc +++ b/gr-fft/lib/qa_fft_shift.cc @@ -33,29 +33,29 @@ namespace fft { BOOST_AUTO_TEST_CASE(t1) { - fft::fft_shift<int> s(1023); + fft::fft_shift<int> s(1023); - std::vector<int> x_even{ 0, 1, 2, 3, -4, -3, -2, -1 }; - std::vector<int> y_even{ -4, -3, -2, -1, 0, 1, 2, 3 }; // expected result + std::vector<int> x_even{ 0, 1, 2, 3, -4, -3, -2, -1 }; + std::vector<int> y_even{ -4, -3, -2, -1, 0, 1, 2, 3 }; // expected result - s.shift(x_even); - BOOST_TEST(x_even == y_even, boost::test_tools::per_element()); + s.shift(x_even); + BOOST_TEST(x_even == y_even, boost::test_tools::per_element()); - // two shifts should not change the result - s.shift(x_even); - s.shift(x_even); - BOOST_TEST(x_even == y_even, boost::test_tools::per_element()); + // two shifts should not change the result + s.shift(x_even); + s.shift(x_even); + BOOST_TEST(x_even == y_even, boost::test_tools::per_element()); } BOOST_AUTO_TEST_CASE(t2) { - fft::fft_shift<int> s(7); + fft::fft_shift<int> s(7); - std::vector<int> x_odd{ 0, 1, 2, 3, -3, -2, -1 }; - std::vector<int> y_odd{ -3, -2, -1, 0, 1, 2, 3 }; // expected result + std::vector<int> x_odd{ 0, 1, 2, 3, -3, -2, -1 }; + std::vector<int> y_odd{ -3, -2, -1, 0, 1, 2, 3 }; // expected result - s.shift(x_odd); - BOOST_TEST(x_odd == y_odd, boost::test_tools::per_element()); + s.shift(x_odd); + BOOST_TEST(x_odd == y_odd, boost::test_tools::per_element()); } } /* namespace fft */ diff --git a/gr-fft/lib/window.cc b/gr-fft/lib/window.cc index 0c1e27f66a..9a1f4600b5 100644 --- a/gr-fft/lib/window.cc +++ b/gr-fft/lib/window.cc @@ -29,352 +29,328 @@ #include <stdexcept> namespace gr { - namespace fft { +namespace fft { -#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */ +#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */ - static double Izero(double x) - { - double sum, u, halfx, temp; - int n; +static double Izero(double x) +{ + double sum, u, halfx, temp; + int n; - sum = u = n = 1; - halfx = x/2.0; - do { - temp = halfx/(double)n; + sum = u = n = 1; + halfx = x / 2.0; + do { + temp = halfx / (double)n; n += 1; temp *= temp; u *= temp; sum += u; - } while (u >= IzeroEPSILON*sum); - return(sum); - } - - double midn(int ntaps) - { - return ntaps/2.0; - } - - double midm1(int ntaps) - { - return (ntaps - 1.0)/2.0; - } - - double midp1(int ntaps) - { - return (ntaps + 1.0)/2.0; - } - - double freq(int ntaps) - { - return 2.0*GR_M_PI/ntaps; - } - - double rate(int ntaps) - { - return 1.0/(ntaps >> 1); - } - - double - window::max_attenuation(win_type type, double beta) - { - switch(type) { - case(WIN_HAMMING): return 53; break; - case(WIN_HANN): return 44; break; - case(WIN_BLACKMAN): return 74; break; - case(WIN_RECTANGULAR): return 21; break; - case(WIN_KAISER): return (beta/0.1102 + 8.7); break; - case(WIN_BLACKMAN_hARRIS): return 92; break; - case(WIN_BARTLETT): return 27; break; - case(WIN_FLATTOP): return 93; break; - default: + } while (u >= IzeroEPSILON * sum); + return (sum); +} + +double midn(int ntaps) { return ntaps / 2.0; } + +double midm1(int ntaps) { return (ntaps - 1.0) / 2.0; } + +double midp1(int ntaps) { return (ntaps + 1.0) / 2.0; } + +double freq(int ntaps) { return 2.0 * GR_M_PI / ntaps; } + +double rate(int ntaps) { return 1.0 / (ntaps >> 1); } + +double window::max_attenuation(win_type type, double beta) +{ + switch (type) { + case (WIN_HAMMING): + return 53; + break; + case (WIN_HANN): + return 44; + break; + case (WIN_BLACKMAN): + return 74; + break; + case (WIN_RECTANGULAR): + return 21; + break; + case (WIN_KAISER): + return (beta / 0.1102 + 8.7); + break; + case (WIN_BLACKMAN_hARRIS): + return 92; + break; + case (WIN_BARTLETT): + return 27; + break; + case (WIN_FLATTOP): + return 93; + break; + default: throw std::out_of_range("window::max_attenuation: unknown window type provided."); - } - } - - std::vector<float> - window::coswindow(int ntaps, float c0, float c1, float c2) - { - std::vector<float> taps(ntaps); - float M = static_cast<float>(ntaps - 1); - - for(int n = 0; n < ntaps; n++) - taps[n] = c0 - c1*cosf((2.0f*GR_M_PI*n)/M) + c2*cosf((4.0f*GR_M_PI*n)/M); - return taps; - } - - std::vector<float> - window::coswindow(int ntaps, float c0, float c1, float c2, float c3) - { - std::vector<float> taps(ntaps); - float M = static_cast<float>(ntaps - 1); - - for(int n = 0; n < ntaps; n++) - taps[n] = c0 - c1*cosf((2.0f*GR_M_PI*n)/M) + c2*cosf((4.0f*GR_M_PI*n)/M) \ - - c3*cosf((6.0f*GR_M_PI*n)/M); - return taps; } - - std::vector<float> - window::coswindow(int ntaps, float c0, float c1, float c2, float c3, float c4) - { - std::vector<float> taps(ntaps); - float M = static_cast<float>(ntaps - 1); - - for(int n = 0; n < ntaps; n++) - taps[n] = c0 - c1*cosf((2.0f*GR_M_PI*n)/M) + c2*cosf((4.0f*GR_M_PI*n)/M) \ - - c3*cosf((6.0f*GR_M_PI*n)/M) + c4*cosf((8.0f*GR_M_PI*n)/M); - return taps; - } - - std::vector<float> - window::rectangular(int ntaps) - { - std::vector<float> taps(ntaps); - for(int n = 0; n < ntaps; n++) +} + +std::vector<float> window::coswindow(int ntaps, float c0, float c1, float c2) +{ + std::vector<float> taps(ntaps); + float M = static_cast<float>(ntaps - 1); + + for (int n = 0; n < ntaps; n++) + taps[n] = c0 - c1 * cosf((2.0f * GR_M_PI * n) / M) + + c2 * cosf((4.0f * GR_M_PI * n) / M); + return taps; +} + +std::vector<float> window::coswindow(int ntaps, float c0, float c1, float c2, float c3) +{ + std::vector<float> taps(ntaps); + float M = static_cast<float>(ntaps - 1); + + for (int n = 0; n < ntaps; n++) + taps[n] = c0 - c1 * cosf((2.0f * GR_M_PI * n) / M) + + c2 * cosf((4.0f * GR_M_PI * n) / M) - + c3 * cosf((6.0f * GR_M_PI * n) / M); + return taps; +} + +std::vector<float> +window::coswindow(int ntaps, float c0, float c1, float c2, float c3, float c4) +{ + std::vector<float> taps(ntaps); + float M = static_cast<float>(ntaps - 1); + + for (int n = 0; n < ntaps; n++) + taps[n] = c0 - c1 * cosf((2.0f * GR_M_PI * n) / M) + + c2 * cosf((4.0f * GR_M_PI * n) / M) - + c3 * cosf((6.0f * GR_M_PI * n) / M) + + c4 * cosf((8.0f * GR_M_PI * n) / M); + return taps; +} + +std::vector<float> window::rectangular(int ntaps) +{ + std::vector<float> taps(ntaps); + for (int n = 0; n < ntaps; n++) taps[n] = 1; - return taps; - } + return taps; +} - std::vector<float> - window::hamming(int ntaps) - { - std::vector<float> taps(ntaps); - float M = static_cast<float>(ntaps - 1); +std::vector<float> window::hamming(int ntaps) +{ + std::vector<float> taps(ntaps); + float M = static_cast<float>(ntaps - 1); - for(int n = 0; n < ntaps; n++) + for (int n = 0; n < ntaps; n++) taps[n] = 0.54 - 0.46 * cos((2 * GR_M_PI * n) / M); - return taps; - } + return taps; +} - std::vector<float> - window::hann(int ntaps) - { - std::vector<float> taps(ntaps); - float M = static_cast<float>(ntaps - 1); +std::vector<float> window::hann(int ntaps) +{ + std::vector<float> taps(ntaps); + float M = static_cast<float>(ntaps - 1); - for(int n = 0; n < ntaps; n++) + for (int n = 0; n < ntaps; n++) taps[n] = 0.5 - 0.5 * cos((2 * GR_M_PI * n) / M); - return taps; - } - - std::vector<float> - window::hanning(int ntaps) - { - return hann(ntaps); - } - - std::vector<float> - window::blackman(int ntaps) - { - return coswindow(ntaps, 0.42, 0.5, 0.08); - } - - std::vector<float> - window::blackman2(int ntaps) - { - return coswindow(ntaps, 0.34401, 0.49755, 0.15844); - } - - std::vector<float> - window::blackman3(int ntaps) - { - return coswindow(ntaps, 0.21747, 0.45325, 0.28256, 0.04672); - } - - std::vector<float> - window::blackman4(int ntaps) - { - return coswindow(ntaps, 0.084037, 0.29145, 0.375696, 0.20762, 0.041194); - } - - std::vector<float> - window::blackman_harris(int ntaps, int atten) - { - switch(atten) { - case(61): return coswindow(ntaps, 0.42323, 0.49755, 0.07922); - case(67): return coswindow(ntaps, 0.44959, 0.49364, 0.05677); - case(74): return coswindow(ntaps, 0.40271, 0.49703, 0.09392, 0.00183); - case(92): return coswindow(ntaps, 0.35875, 0.48829, 0.14128, 0.01168); - default: - throw std::out_of_range("window::blackman_harris: unknown attenuation value (must be 61, 67, 74, or 92)"); - } - } - - std::vector<float> - window::blackmanharris(int ntaps, int atten) - { - return blackman_harris(ntaps, atten); - } - - std::vector<float> - window::nuttal(int ntaps) - { - return nuttall(ntaps); - } - - std::vector<float> - window::nuttall(int ntaps) - { - return coswindow(ntaps, 0.3635819, 0.4891775, 0.1365995, 0.0106411); - } - - std::vector<float> - window::blackman_nuttal(int ntaps) - { - return nuttall(ntaps); - } - - std::vector<float> - window::blackman_nuttall(int ntaps) - { - return nuttall(ntaps); - } - - std::vector<float> - window::nuttal_cfd(int ntaps) - { - return nuttall_cfd(ntaps); - } - - std::vector<float> - window::nuttall_cfd(int ntaps) - { - return coswindow(ntaps, 0.355768, 0.487396, 0.144232, 0.012604); - } - - std::vector<float> - window::flattop(int ntaps) - { - double scale = 4.63867; - return coswindow(ntaps, 1.0/scale, 1.93/scale, 1.29/scale, 0.388/scale, 0.028/scale); - } - - std::vector<float> - window::kaiser(int ntaps, double beta) - { - if(beta < 0) + return taps; +} + +std::vector<float> window::hanning(int ntaps) { return hann(ntaps); } + +std::vector<float> window::blackman(int ntaps) +{ + return coswindow(ntaps, 0.42, 0.5, 0.08); +} + +std::vector<float> window::blackman2(int ntaps) +{ + return coswindow(ntaps, 0.34401, 0.49755, 0.15844); +} + +std::vector<float> window::blackman3(int ntaps) +{ + return coswindow(ntaps, 0.21747, 0.45325, 0.28256, 0.04672); +} + +std::vector<float> window::blackman4(int ntaps) +{ + return coswindow(ntaps, 0.084037, 0.29145, 0.375696, 0.20762, 0.041194); +} + +std::vector<float> window::blackman_harris(int ntaps, int atten) +{ + switch (atten) { + case (61): + return coswindow(ntaps, 0.42323, 0.49755, 0.07922); + case (67): + return coswindow(ntaps, 0.44959, 0.49364, 0.05677); + case (74): + return coswindow(ntaps, 0.40271, 0.49703, 0.09392, 0.00183); + case (92): + return coswindow(ntaps, 0.35875, 0.48829, 0.14128, 0.01168); + default: + throw std::out_of_range("window::blackman_harris: unknown attenuation value " + "(must be 61, 67, 74, or 92)"); + } +} + +std::vector<float> window::blackmanharris(int ntaps, int atten) +{ + return blackman_harris(ntaps, atten); +} + +std::vector<float> window::nuttal(int ntaps) { return nuttall(ntaps); } + +std::vector<float> window::nuttall(int ntaps) +{ + return coswindow(ntaps, 0.3635819, 0.4891775, 0.1365995, 0.0106411); +} + +std::vector<float> window::blackman_nuttal(int ntaps) { return nuttall(ntaps); } + +std::vector<float> window::blackman_nuttall(int ntaps) { return nuttall(ntaps); } + +std::vector<float> window::nuttal_cfd(int ntaps) { return nuttall_cfd(ntaps); } + +std::vector<float> window::nuttall_cfd(int ntaps) +{ + return coswindow(ntaps, 0.355768, 0.487396, 0.144232, 0.012604); +} + +std::vector<float> window::flattop(int ntaps) +{ + double scale = 4.63867; + return coswindow( + ntaps, 1.0 / scale, 1.93 / scale, 1.29 / scale, 0.388 / scale, 0.028 / scale); +} + +std::vector<float> window::kaiser(int ntaps, double beta) +{ + if (beta < 0) throw std::out_of_range("window::kaiser: beta must be >= 0"); - std::vector<float> taps(ntaps); - - double IBeta = 1.0/Izero(beta); - double inm1 = 1.0/((double)(ntaps-1)); - double temp; - - /* extracting first and last element out of the loop, since - sqrt(1.0-temp*temp) might trigger unexpected floating point behaviour - if |temp| = 1.0+epsilon, which can happen for i==0 and - 1/i==1/(ntaps-1)==inm1 ; compare - https://github.com/gnuradio/gnuradio/issues/1348 . - In any case, the 0. Bessel function of first kind is 1 at point 0. - */ - taps[0] = IBeta; - for(int i = 1; i < ntaps-1; i++) { - temp = 2*i*inm1 - 1; - taps[i] = Izero(beta*sqrt(1.0-temp*temp)) * IBeta; - } - taps[ntaps-1] = IBeta; - return taps; - } - - std::vector<float> - window::bartlett(int ntaps) - { - std::vector<float> taps(ntaps); - float M = static_cast<float>(ntaps - 1); - - for(int n = 0; n < ntaps/2; n++) - taps[n] = 2*n/M; - for(int n = ntaps/2; n < ntaps; n++) - taps[n] = 2 - 2*n/M; - - return taps; - } - - std::vector<float> - window::welch(int ntaps) - { - std::vector<float> taps(ntaps); - double m1 = midm1(ntaps); - double p1 = midp1(ntaps); - for(int i = 0; i < midn(ntaps)+1; i++) { + std::vector<float> taps(ntaps); + + double IBeta = 1.0 / Izero(beta); + double inm1 = 1.0 / ((double)(ntaps - 1)); + double temp; + + /* extracting first and last element out of the loop, since + sqrt(1.0-temp*temp) might trigger unexpected floating point behaviour + if |temp| = 1.0+epsilon, which can happen for i==0 and + 1/i==1/(ntaps-1)==inm1 ; compare + https://github.com/gnuradio/gnuradio/issues/1348 . + In any case, the 0. Bessel function of first kind is 1 at point 0. + */ + taps[0] = IBeta; + for (int i = 1; i < ntaps - 1; i++) { + temp = 2 * i * inm1 - 1; + taps[i] = Izero(beta * sqrt(1.0 - temp * temp)) * IBeta; + } + taps[ntaps - 1] = IBeta; + return taps; +} + +std::vector<float> window::bartlett(int ntaps) +{ + std::vector<float> taps(ntaps); + float M = static_cast<float>(ntaps - 1); + + for (int n = 0; n < ntaps / 2; n++) + taps[n] = 2 * n / M; + for (int n = ntaps / 2; n < ntaps; n++) + taps[n] = 2 - 2 * n / M; + + return taps; +} + +std::vector<float> window::welch(int ntaps) +{ + std::vector<float> taps(ntaps); + double m1 = midm1(ntaps); + double p1 = midp1(ntaps); + for (int i = 0; i < midn(ntaps) + 1; i++) { taps[i] = 1.0 - pow((i - m1) / p1, 2); - taps[ntaps-i-1] = taps[i]; - } - return taps; - } - - std::vector<float> - window::parzen(int ntaps) - { - std::vector<float> taps(ntaps); - double m1 = midm1(ntaps); - double m = midn(ntaps); - int i; - for(i = ntaps/4; i < 3*ntaps/4; i++) { - taps[i] = 1.0 - 6.0*pow((i-m1)/m, 2.0) * (1.0 - fabs(i-m1)/m); - } - for(; i < ntaps; i++) { - taps[i] = 2.0 * pow(1.0 - fabs(i-m1)/m, 3.0); - taps[ntaps-i-1] = taps[i]; - } - return taps; - } - - std::vector<float> - window::exponential(int ntaps, double d) - { - if(d < 0) + taps[ntaps - i - 1] = taps[i]; + } + return taps; +} + +std::vector<float> window::parzen(int ntaps) +{ + std::vector<float> taps(ntaps); + double m1 = midm1(ntaps); + double m = midn(ntaps); + int i; + for (i = ntaps / 4; i < 3 * ntaps / 4; i++) { + taps[i] = 1.0 - 6.0 * pow((i - m1) / m, 2.0) * (1.0 - fabs(i - m1) / m); + } + for (; i < ntaps; i++) { + taps[i] = 2.0 * pow(1.0 - fabs(i - m1) / m, 3.0); + taps[ntaps - i - 1] = taps[i]; + } + return taps; +} + +std::vector<float> window::exponential(int ntaps, double d) +{ + if (d < 0) throw std::out_of_range("window::exponential: d must be >= 0"); - double m1 = midm1(ntaps); - double p = 1.0 / (8.69*ntaps/(2.0*d)); - std::vector<float> taps(ntaps); - for(int i = 0; i < midn(ntaps)+1; i++) { - taps[i] = exp(-fabs(i - m1)*p); - taps[ntaps-i-1] = taps[i]; - } - return taps; - } - - std::vector<float> - window::riemann(int ntaps) - { - double cx; - double sr1 = freq(ntaps); - double mid = midn(ntaps); - std::vector<float> taps(ntaps); - for(int i = 0; i < mid; i++) { - if(i == midn(ntaps)) { - taps[i] = 1.0; - taps[ntaps-i-1] = 1.0; + double m1 = midm1(ntaps); + double p = 1.0 / (8.69 * ntaps / (2.0 * d)); + std::vector<float> taps(ntaps); + for (int i = 0; i < midn(ntaps) + 1; i++) { + taps[i] = exp(-fabs(i - m1) * p); + taps[ntaps - i - 1] = taps[i]; + } + return taps; +} + +std::vector<float> window::riemann(int ntaps) +{ + double cx; + double sr1 = freq(ntaps); + double mid = midn(ntaps); + std::vector<float> taps(ntaps); + for (int i = 0; i < mid; i++) { + if (i == midn(ntaps)) { + taps[i] = 1.0; + taps[ntaps - i - 1] = 1.0; + } else { + cx = sr1 * (i - mid); + taps[i] = sin(cx) / cx; + taps[ntaps - i - 1] = sin(cx) / cx; } - else { - cx = sr1*(i - mid); - taps[i] = sin(cx)/cx; - taps[ntaps-i-1] = sin(cx)/cx; - } - } - return taps; } - - std::vector<float> - window::build(win_type type, int ntaps, double beta) - { - switch (type) { - case WIN_RECTANGULAR: return rectangular(ntaps); - case WIN_HAMMING: return hamming(ntaps); - case WIN_HANN: return hann(ntaps); - case WIN_BLACKMAN: return blackman(ntaps); - case WIN_BLACKMAN_hARRIS: return blackman_harris(ntaps); - case WIN_KAISER: return kaiser(ntaps, beta); - case WIN_BARTLETT: return bartlett(ntaps); - case WIN_FLATTOP: return flattop(ntaps); - default: + return taps; +} + +std::vector<float> window::build(win_type type, int ntaps, double beta) +{ + switch (type) { + case WIN_RECTANGULAR: + return rectangular(ntaps); + case WIN_HAMMING: + return hamming(ntaps); + case WIN_HANN: + return hann(ntaps); + case WIN_BLACKMAN: + return blackman(ntaps); + case WIN_BLACKMAN_hARRIS: + return blackman_harris(ntaps); + case WIN_KAISER: + return kaiser(ntaps, beta); + case WIN_BARTLETT: + return bartlett(ntaps); + case WIN_FLATTOP: + return flattop(ntaps); + default: throw std::out_of_range("window::build: type out of range"); - } } +} - } /* namespace fft */ +} /* namespace fft */ } /* namespace gr */ |