diff options
author | Johnathan Corgan <johnathan@corganlabs.com> | 2013-11-06 10:28:38 -0800 |
---|---|---|
committer | Johnathan Corgan <johnathan@corganlabs.com> | 2013-11-06 10:28:38 -0800 |
commit | 5f724cfd76ad52288db91b535b4366c176717d29 (patch) | |
tree | 7404cfc11c1493a022d6755104e5d8c9829adea0 | |
parent | ab255b39990e559d5e92ff08b1c23e4e4faa11b6 (diff) | |
parent | 10be863fab34d9d2ca8a080b623e48f4cac0df48 (diff) |
Merge remote-tracking branch 'tom/windows'
-rw-r--r-- | gr-fft/include/gnuradio/fft/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/window.h | 270 | ||||
-rw-r--r-- | gr-fft/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-fft/lib/window.cc | 333 | ||||
-rw-r--r-- | gr-fft/python/fft/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-fft/python/fft/__init__.py | 2 | ||||
-rw-r--r-- | gr-fft/python/fft/window.py | 179 | ||||
-rw-r--r-- | gr-fft/swig/fft_swig.i | 2 | ||||
-rw-r--r-- | gr-filter/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-filter/include/gnuradio/filter/firdes.h | 10 | ||||
-rw-r--r-- | gr-filter/lib/firdes.cc | 81 |
11 files changed, 617 insertions, 264 deletions
diff --git a/gr-fft/include/gnuradio/fft/CMakeLists.txt b/gr-fft/include/gnuradio/fft/CMakeLists.txt index 1dfa220022..55705ee660 100644 --- a/gr-fft/include/gnuradio/fft/CMakeLists.txt +++ b/gr-fft/include/gnuradio/fft/CMakeLists.txt @@ -27,6 +27,7 @@ install(FILES fft_vfc.h goertzel.h goertzel_fc.h + window.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/fft COMPONENT "fft_devel" ) diff --git a/gr-fft/include/gnuradio/fft/window.h b/gr-fft/include/gnuradio/fft/window.h new file mode 100644 index 0000000000..b7479f48fb --- /dev/null +++ b/gr-fft/include/gnuradio/fft/window.h @@ -0,0 +1,270 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2007,2008,2012,2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <gnuradio/fft/api.h> +#include <vector> +#include <cmath> +#include <gnuradio/gr_complex.h> + +namespace gr { + namespace fft { + + class FFT_API window { + public: + + enum win_type { + WIN_NONE = -1, //!< don't use a window + 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 + WIN_KAISER = 4, //!< Kaiser window; max attenuation a function of beta, google it + WIN_BLACKMAN_hARRIS = 5, //!< Blackman-harris window + WIN_BLACKMAN_HARRIS = 5, //!< alias to WIN_BLACKMAN_hARRIS for capitalization consistency + WIN_BARTLETT = 6, //!< Barlett (triangular) window + WIN_FLATTOP = 7, //!< flat top window; useful in FFTs + }; + + /*! + * \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 Nuttal (or Blackman-Nuttal) 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> nuttal(int ntaps); + + /*! + * \brief Alias to the Nuttal window. + * + * \param ntaps Number of coefficients in the window. + */ + static std::vector<float> blackman_nuttal(int ntaps); + + /*! + * \brief Build a Nuttal 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> nuttal_cfd(int ntaps); + + /*! + * \brief Build a Nuttal continuous first derivative 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 */ diff --git a/gr-fft/lib/CMakeLists.txt b/gr-fft/lib/CMakeLists.txt index c94d588f6a..045df5b4f8 100644 --- a/gr-fft/lib/CMakeLists.txt +++ b/gr-fft/lib/CMakeLists.txt @@ -46,6 +46,7 @@ list(APPEND fft_sources fft_vfc_fftw.cc goertzel_fc_impl.cc goertzel.cc + window.cc ) if(ENABLE_GR_CTRLPORT) diff --git a/gr-fft/lib/window.cc b/gr-fft/lib/window.cc new file mode 100644 index 0000000000..5a28b3239d --- /dev/null +++ b/gr-fft/lib/window.cc @@ -0,0 +1,333 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2007,2008,2012,2013 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gnuradio/fft/window.h> +#include <stdexcept> + +namespace gr { + namespace fft { + +#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */ + + 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; + 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*M_PI/ntaps; + } + + double rate(int ntaps) + { + return 1.0/(ntaps >> 1); + } + + 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*cos((2*M_PI*n)/M) + c2*cos((4*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*cos((2*M_PI*n)/M) + c2*cos((4*M_PI*n)/M) - c3*cos((6*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*cos((2*M_PI*n)/M) + c2*cos((4*M_PI*n)/M) - c3*cos((6*M_PI*n)/M) + c4*cos((8*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; + } + + 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++) + taps[n] = 0.54 - 0.46 * cos((2 * M_PI * n) / M); + return taps; + } + + 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++) + taps[n] = 0.5 - 0.5 * cos((2 * 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 coswindow(ntaps, 0.3635819, 0.4891775, 0.1365995, 0.0106411); + } + + std::vector<float> + window::blackman_nuttal(int ntaps) + { + return nuttal(ntaps); + } + + std::vector<float> + window::nuttal_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; + + for(int i = 0; i <= ntaps; i++) { + temp = 2*i*inm1 - 1; + taps[i] = Izero(beta*sqrt(1.0-temp*temp)) * 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) + 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; + } + 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: + throw std::out_of_range("window::build: type out of range"); + } + } + + } /* namespace fft */ +} /* namespace gr */ diff --git a/gr-fft/python/fft/CMakeLists.txt b/gr-fft/python/fft/CMakeLists.txt index 33d37b51b9..e0bc19124d 100644 --- a/gr-fft/python/fft/CMakeLists.txt +++ b/gr-fft/python/fft/CMakeLists.txt @@ -24,7 +24,6 @@ GR_PYTHON_INSTALL( FILES __init__.py logpwrfft.py - window.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/fft COMPONENT "fft_python" ) diff --git a/gr-fft/python/fft/__init__.py b/gr-fft/python/fft/__init__.py index e0803cbf38..1864353ed1 100644 --- a/gr-fft/python/fft/__init__.py +++ b/gr-fft/python/fft/__init__.py @@ -30,5 +30,3 @@ except ImportError: dirname, filename = os.path.split(os.path.abspath(__file__)) __path__.append(os.path.join(dirname, "..", "..", "swig")) from fft_swig import * - -from window import * diff --git a/gr-fft/python/fft/window.py b/gr-fft/python/fft/window.py deleted file mode 100644 index 0065a08a61..0000000000 --- a/gr-fft/python/fft/window.py +++ /dev/null @@ -1,179 +0,0 @@ -# -# Copyright 2004,2005,2009 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -''' -Routines for designing window functions. -''' - -import math - -def izero(x): - izeroepsilon = 1e-21 - halfx = x/2.0 - accum = u = n = 1 - while 1: - temp = halfx/n - n += 1 - temp *= temp - u *= temp - accum += u - if u >= IzeroEPSILON*sum: - break - return accum - -def midm1(fft_size): - return (fft_size - 1)/2 - -def midp1(fft_size): - return (fft_size+1)/2 - -def freq(fft_size): - return 2.0*math.pi/fft_size - -def rate(fft_size): - return 1.0/(fft_size >> 1) - -def expn(fft_size): - math.log(2.0)/(midn(fft_size) + 1.0) - -def hamming(fft_size): - window = [] - for index in xrange(fft_size): - window.append(0.54 - 0.46 * math.cos (2 * math.pi / fft_size * index)) # Hamming window - return window - -def hanning(fft_size): - window = [] - for index in xrange(fft_size): - window.append(0.5 - 0.5 * math.cos (2 * math.pi / fft_size * index)) # von Hann window - return window - -def welch(fft_size): - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - window[j] = window[index] = (1.0 - math.sqrt((index - midm1(fft_size)) / midp1(fft_size))) - j -= 1 - return window - -def parzen(fft_size): - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - window[j] = window[index] = (1.0 - math.abs((index - midm1(fft_size)) / midp1(fft_size))) - j -= 1 - return window - -def bartlett(fft_size): - mfrq = freq(fft_size) - angle = 0 - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - window[j] = window[index] = angle - angle += freq - j -= 1 - return window - -def blackman2(fft_size): - mfrq = freq(fft_size) - angle = 0 - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - cx = math.cos(angle) - window[j] = window[index] = (.34401 + (cx * (-.49755 + (cx * .15844)))) - angle += freq - j -= 1 - return window - -def blackman3(fft_size): - mfrq = freq(fft_size) - angle = 0 - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - cx = math.cos(angle) - window[j] = window[index] = (.21747 + (cx * (-.45325 + (cx * (.28256 - (cx * .04672)))))) - angle += freq - j -= 1 - return window - -def blackman4(fft_size): - mfrq = freq(fft_size) - angle = 0 - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - cx = math.cos(angle) - window[j] = window[index] = (.084037 + (cx * (-.29145 + (cx * (.375696 + (cx * (-.20762 + (cx * .041194)))))))) - angle += freq - j -= 1 - return window - -def exponential(fft_size): - expsum = 1.0 - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)+1): - window[j] = window[i] = (expsum - 1.0) - expsum *= expn(fft_size) - j -= 1 - return window - -def riemann(fft_size): - sr1 = freq(fft_size) - window = [0 for i in range(fft_size)] - j = fft_size-1 - for index in xrange(midn(fft_size)): - if index == midn(fft_size): - window[index] = window[j] = 1.0 - else: - cx = sr1*midn(fft_size) - index - window[index] = window[j] = math.sin(cx)/cx - j -= 1 - return window - -def kaiser(fft_size,beta): - ibeta = 1.0/izero(beta) - inm1 = 1.0/(fft_size) - window = [0 for i in range(fft_size)] - for index in xrange(fft_size): - window[index] = izero(beta*math.sqrt(1.0 - (index * inm1)*(index * inm1))) * ibeta - return window - -# Closure to generate functions to create cos windows - -def coswindow(coeffs): - def closure(fft_size): - window = [0] * fft_size - #print list(enumerate(coeffs)) - for w_index in range(fft_size): - for (c_index, coeff) in enumerate(coeffs): - window[w_index] += (-1)**c_index * coeff * math.cos(2.0*c_index*math.pi*(w_index+0.5)/(fft_size-1)) - return window - return closure - -blackmanharris = coswindow((0.35875,0.48829,0.14128,0.01168)) -nuttall = coswindow((0.3635819,0.4891775,0.1365995,0.0106411)) # Wikipedia calls this Blackman-Nuttall -nuttall_cfd = coswindow((0.355768,0.487396,0.144232,0.012604)) # Wikipedia calls this Nuttall, continuous first deriv -flattop = coswindow((1.0,1.93,1.29,0.388,0.032)) # Flat top window, coeffs from Wikipedia -rectangular = lambda fft_size: [1]*fft_size diff --git a/gr-fft/swig/fft_swig.i b/gr-fft/swig/fft_swig.i index edc3c594ac..062328f12a 100644 --- a/gr-fft/swig/fft_swig.i +++ b/gr-fft/swig/fft_swig.i @@ -31,11 +31,13 @@ #include "gnuradio/fft/fft_vcc.h" #include "gnuradio/fft/fft_vfc.h" #include "gnuradio/fft/goertzel_fc.h" +#include "gnuradio/fft/window.h" %} %include "gnuradio/fft/fft_vcc.h" %include "gnuradio/fft/fft_vfc.h" %include "gnuradio/fft/goertzel_fc.h" +%include "gnuradio/fft/window.h" GR_SWIG_BLOCK_MAGIC2(fft, fft_vcc); GR_SWIG_BLOCK_MAGIC2(fft, fft_vfc); diff --git a/gr-filter/CMakeLists.txt b/gr-filter/CMakeLists.txt index ccc9cb7fdf..c0d46d521a 100644 --- a/gr-filter/CMakeLists.txt +++ b/gr-filter/CMakeLists.txt @@ -40,6 +40,7 @@ GR_SET_GLOBAL(GR_FILTER_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/lib ${CMAKE_CURRENT_BINARY_DIR}/include + ${GR_FFT_INCLUDE_DIRS} ) SET(GR_PKG_FILTER_EXAMPLES_DIR ${GR_PKG_DATA_DIR}/examples/filter) diff --git a/gr-filter/include/gnuradio/filter/firdes.h b/gr-filter/include/gnuradio/filter/firdes.h index d2ab23d186..7e22cbde06 100644 --- a/gr-filter/include/gnuradio/filter/firdes.h +++ b/gr-filter/include/gnuradio/filter/firdes.h @@ -27,6 +27,7 @@ #include <vector> #include <cmath> #include <gnuradio/gr_complex.h> +#include <gnuradio/fft/window.h> namespace gr { namespace filter { @@ -38,7 +39,9 @@ namespace gr { class FILTER_API firdes { public: - + + // WARNING: deprecated, now located in gr::fft::window. + // We will be removing this in 3.8. enum win_type { WIN_NONE = -1, //!< don't use a window WIN_HAMMING = 0, //!< Hamming window; max attenuation 53 dB @@ -49,8 +52,10 @@ namespace gr { WIN_BLACKMAN_hARRIS = 5, //!< Blackman-harris window WIN_BLACKMAN_HARRIS = 5, //!< alias to WIN_BLACKMAN_hARRIS for capitalization consistency WIN_BARTLETT = 6, //!< Barlett (triangular) window + WIN_FLATTOP = 7, //!< flat top window; useful in FFTs }; + static std::vector<float> window(win_type type, int ntaps, double beta); // ... class methods ... @@ -353,9 +358,6 @@ namespace gr { double bt, // Bandwidth to bitrate ratio int ntaps); - // window functions ... - static std::vector<float> window (win_type type, int ntaps, double beta); - private: static double bessi0(double x); static void sanity_check_1f(double sampling_freq, double f1, diff --git a/gr-filter/lib/firdes.cc b/gr-filter/lib/firdes.cc index dd3c124565..93dfec5bc8 100644 --- a/gr-filter/lib/firdes.cc +++ b/gr-filter/lib/firdes.cc @@ -31,27 +31,13 @@ using std::vector; namespace gr { namespace filter { - -#define IzeroEPSILON 1E-21 /* Max error acceptable in Izero */ - static double Izero(double x) + std::vector<float> + firdes::window(win_type type, int ntaps, double beta) { - double sum, u, halfx, temp; - int 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); + return fft::window::build(static_cast<fft::window::win_type>(type), ntaps, beta); } - // // === Low Pass === // @@ -736,67 +722,6 @@ namespace gr { return ans; } - vector<float> - firdes::window (win_type type, int ntaps, double beta) - { - vector<float> taps(ntaps); - int M = ntaps - 1; // filter order - - switch (type) { - case WIN_RECTANGULAR: - for(int n = 0; n < ntaps; n++) - taps[n] = 1; - break; - - case WIN_HAMMING: - for(int n = 0; n < ntaps; n++) - taps[n] = 0.54 - 0.46 * cos((2 * M_PI * n) / M); - break; - - case WIN_HANN: - for(int n = 0; n < ntaps; n++) - taps[n] = 0.5 - 0.5 * cos((2 * M_PI * n) / M); - break; - - case WIN_BLACKMAN: - for(int n = 0; n < ntaps; n++) - taps[n] = 0.42 - 0.50 * cos((2*M_PI * n) / M) - + 0.08 * cos((4*M_PI * n) / M); - break; - - case WIN_BLACKMAN_hARRIS: - for(int n = -ntaps/2; n < ntaps/2; n++) - taps[n+ntaps/2] = 0.35875 + 0.48829*cos((2*M_PI * n) / (float)M) + - 0.14128*cos((4*M_PI * n) / (float)M) + 0.01168*cos((6*M_PI * n) / (float)M); - break; - - case WIN_KAISER: - { - double IBeta = 1.0/Izero(beta); - double inm1 = 1.0/((double)(ntaps-1)); - double temp; - - for(int i = 0; i <= ntaps; i++) { - temp = 2*i*inm1 - 1; - taps[i] = Izero(beta*sqrt(1.0-temp*temp)) * IBeta; - } - } - break; - - case WIN_BARTLETT: - for(int n = 0; n <= ntaps/2; n++) - taps[n] = 2*n / (float)M; - for(int n = ntaps/2 + 1; n < ntaps; n++) - taps[n] = 2 - 2*n / (float)M; - break; - - default: - throw std::out_of_range("firdes:window: type out of range"); - } - - return taps; - } - void firdes::sanity_check_1f(double sampling_freq, double fa, // cutoff freq |