diff options
Diffstat (limited to 'gr-fft')
-rw-r--r-- | gr-fft/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-fft/grc/CMakeLists.txt | 5 | ||||
-rw-r--r-- | gr-fft/grc/fft_block_tree.xml | 5 | ||||
-rw-r--r-- | gr-fft/grc/fft_fft_vxx.xml (renamed from gr-fft/grc/fft_vxx.xml) | 2 | ||||
-rw-r--r-- | gr-fft/grc/fft_goertzel_fc.xml (renamed from gr-fft/grc/goertzel_fc.xml) | 0 | ||||
-rw-r--r-- | gr-fft/grc/fft_logpwrfft_x.xml | 90 | ||||
-rw-r--r-- | gr-fft/include/fft/fft.h | 8 | ||||
-rw-r--r-- | gr-fft/lib/CMakeLists.txt | 5 | ||||
-rw-r--r-- | gr-fft/lib/fft.cc | 6 | ||||
-rw-r--r-- | gr-fft/python/CMakeLists.txt | 4 | ||||
-rw-r--r-- | gr-fft/python/__init__.py | 2 | ||||
-rw-r--r-- | gr-fft/python/logpwrfft.py | 176 | ||||
-rwxr-xr-x | gr-fft/python/qa_fft.py | 13 | ||||
-rw-r--r-- | gr-fft/python/window.py | 179 |
14 files changed, 484 insertions, 12 deletions
diff --git a/gr-fft/CMakeLists.txt b/gr-fft/CMakeLists.txt index 7d76dc7f93..6b37bd3caa 100644 --- a/gr-fft/CMakeLists.txt +++ b/gr-fft/CMakeLists.txt @@ -34,6 +34,7 @@ GR_REGISTER_COMPONENT("gr-fft" ENABLE_GR_FFT ENABLE_VOLK Boost_FOUND ENABLE_GR_CORE + ENABLE_GR_BLOCKS FFTW3F_FOUND ) diff --git a/gr-fft/grc/CMakeLists.txt b/gr-fft/grc/CMakeLists.txt index 632a9aaad9..4c96d21738 100644 --- a/gr-fft/grc/CMakeLists.txt +++ b/gr-fft/grc/CMakeLists.txt @@ -19,8 +19,9 @@ install(FILES fft_block_tree.xml - fft_vxx.xml - goertzel_fc.xml + fft_fft_vxx.xml + fft_goertzel_fc.xml + fft_logpwrfft_x.xml DESTINATION ${GRC_BLOCKS_DIR} COMPONENT "fft_python" ) diff --git a/gr-fft/grc/fft_block_tree.xml b/gr-fft/grc/fft_block_tree.xml index 3bda77eae1..5abbc3ef26 100644 --- a/gr-fft/grc/fft_block_tree.xml +++ b/gr-fft/grc/fft_block_tree.xml @@ -33,4 +33,9 @@ <block>fft_vxx</block> <block>goertzel_fc</block> </cat> + + <cat> + <name>Operators</name> + <block>logpwrfft_x</block> + </cat> </cat> diff --git a/gr-fft/grc/fft_vxx.xml b/gr-fft/grc/fft_fft_vxx.xml index 69f12ace77..028721fe25 100644 --- a/gr-fft/grc/fft_vxx.xml +++ b/gr-fft/grc/fft_fft_vxx.xml @@ -8,7 +8,7 @@ <name>FFT</name> <key>fft_vxx</key> <import>from gnuradio import fft</import> - <import>from gnuradio import window</import> + <import>from gnuradio.fft import window</import> <make>#if $type() == "complex" fft.fft_vcc($fft_size, $forward, $window, $shift, $nthreads) #else diff --git a/gr-fft/grc/goertzel_fc.xml b/gr-fft/grc/fft_goertzel_fc.xml index 3712843586..3712843586 100644 --- a/gr-fft/grc/goertzel_fc.xml +++ b/gr-fft/grc/fft_goertzel_fc.xml diff --git a/gr-fft/grc/fft_logpwrfft_x.xml b/gr-fft/grc/fft_logpwrfft_x.xml new file mode 100644 index 0000000000..936be1cc71 --- /dev/null +++ b/gr-fft/grc/fft_logpwrfft_x.xml @@ -0,0 +1,90 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Log Power FFT +################################################### + --> +<block> + <name>Log Power FFT</name> + <key>logpwrfft_x</key> + <import>from gnuradio import fft</import> + <make>fft.logpwrfft_$(type.fcn)( + sample_rate=$sample_rate, + fft_size=$fft_size, + ref_scale=$ref_scale, + frame_rate=$frame_rate, + avg_alpha=$avg_alpha, + average=$average, +)</make> + <callback>set_sample_rate($sample_rate)</callback> + <callback>set_avg_alpha($avg_alpha)</callback> + <callback>set_average($average)</callback> + <param> + <name>Input Type</name> + <key>type</key> + <type>enum</type> + <option> + <name>Complex</name> + <key>complex</key> + <opt>fcn:c</opt> + </option> + <option> + <name>Float</name> + <key>float</key> + <opt>fcn:f</opt> + </option> + </param> + <param> + <name>Sample Rate</name> + <key>sample_rate</key> + <value>samp_rate</value> + <type>real</type> + </param> + <param> + <name>FFT Size</name> + <key>fft_size</key> + <value>1024</value> + <type>int</type> + </param> + <param> + <name>Reference Scale</name> + <key>ref_scale</key> + <value>2</value> + <type>real</type> + </param> + <param> + <name>Frame Rate</name> + <key>frame_rate</key> + <value>30</value> + <type>real</type> + </param> + <param> + <name>Average</name> + <key>average</key> + <value>False</value> + <type>bool</type> + <option> + <name>On</name> + <key>True</key> + </option> + <option> + <name>Off</name> + <key>False</key> + </option> + </param> + <param> + <name>Average Alpha</name> + <key>avg_alpha</key> + <value>1.0</value> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>$type</type> + </sink> + <source> + <name>out</name> + <type>float</type> + <vlen>$fft_size</vlen> + </source> +</block> diff --git a/gr-fft/include/fft/fft.h b/gr-fft/include/fft/fft.h index e3fd3f278a..305b1cb711 100644 --- a/gr-fft/include/fft/fft.h +++ b/gr-fft/include/fft/fft.h @@ -35,14 +35,18 @@ namespace gr { namespace fft { - /*! \brief Helper function for allocating complex fft buffers + /*! \brief Helper function for allocating complex* buffers */ FFT_API gr_complex* malloc_complex(int size); - /*! \brief Helper function for allocating float fft buffers + /*! \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); diff --git a/gr-fft/lib/CMakeLists.txt b/gr-fft/lib/CMakeLists.txt index 9382a48c3b..6516ad42d4 100644 --- a/gr-fft/lib/CMakeLists.txt +++ b/gr-fft/lib/CMakeLists.txt @@ -33,6 +33,11 @@ include_directories( link_directories(${Boost_LIBRARY_DIRS}) link_directories(${FFTW3F_LIBRARY_DIRS}) +if(ENABLE_GR_CTRLPORT) + ADD_DEFINITIONS(-DGR_CTRLPORT) + include_directories(${ICE_INCLUDE_DIR}) +endif(ENABLE_GR_CTRLPORT) + ######################################################################## # Setup library ######################################################################## diff --git a/gr-fft/lib/fft.cc b/gr-fft/lib/fft.cc index 6074236e18..60838ee302 100644 --- a/gr-fft/lib/fft.cc +++ b/gr-fft/lib/fft.cc @@ -62,6 +62,12 @@ namespace gr { return (float*)fftwf_malloc(sizeof(float)*size); } + double * + malloc_double(int size) + { + return (double*)fftwf_malloc(sizeof(double)*size); + } + void free(void *b) { diff --git a/gr-fft/python/CMakeLists.txt b/gr-fft/python/CMakeLists.txt index 3b328780f2..415d87e2e8 100644 --- a/gr-fft/python/CMakeLists.txt +++ b/gr-fft/python/CMakeLists.txt @@ -23,6 +23,8 @@ include(GrPython) GR_PYTHON_INSTALL( FILES __init__.py + logpwrfft.py + window.py DESTINATION ${GR_PYTHON_DIR}/gnuradio/fft COMPONENT "fft_python" ) @@ -35,6 +37,8 @@ if(ENABLE_TESTING) list(APPEND GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/gr-fft/python ${CMAKE_BINARY_DIR}/gr-fft/swig + ${CMAKE_BINARY_DIR}/gr-blocks/python + ${CMAKE_BINARY_DIR}/gr-blocks/swig ) list(APPEND GR_TEST_TARGET_DEPS gnuradio-fft) diff --git a/gr-fft/python/__init__.py b/gr-fft/python/__init__.py index 0fa643e35d..093cc3c696 100644 --- a/gr-fft/python/__init__.py +++ b/gr-fft/python/__init__.py @@ -25,4 +25,4 @@ processing blocks for FFT and related functions. ''' from fft_swig import * - +from window import * diff --git a/gr-fft/python/logpwrfft.py b/gr-fft/python/logpwrfft.py new file mode 100644 index 0000000000..98303b1e1e --- /dev/null +++ b/gr-fft/python/logpwrfft.py @@ -0,0 +1,176 @@ +# +# Copyright 2008 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr +from gnuradio import blocks +import sys, math + +import fft_swig as fft +import window + +try: + from gnuradio import filter +except ImportError: + sys.stderr.write('fft.logpwrfft required gr-filter.\n') + sys.exit(1) + +class _logpwrfft_base(gr.hier_block2): + """ + Create a log10(abs(fft)) stream chain, with real or complex input. + """ + + def __init__(self, sample_rate, fft_size, ref_scale, frame_rate, avg_alpha, average, win=None): + """ + Create an log10(abs(fft)) stream chain. + Provide access to the setting the filter and sample rate. + + Args: + sample_rate: Incoming stream sample rate + fft_size: Number of FFT bins + ref_scale: Sets 0 dB value input amplitude + frame_rate: Output frame rate + avg_alpha: FFT averaging (over time) constant [0.0-1.0] + average: Whether to average [True, False] + win: the window taps generation function + """ + gr.hier_block2.__init__(self, self._name, + gr.io_signature(1, 1, self._item_size), # Input signature + gr.io_signature(1, 1, gr.sizeof_float*fft_size)) # Output signature + + self._sd = blocks.stream_to_vector_decimator(item_size=self._item_size, + sample_rate=sample_rate, + vec_rate=frame_rate, + vec_len=fft_size) + + if win is None: win = window.blackmanharris + fft_window = win(fft_size) + fft = self._fft_block[0](fft_size, True, fft_window) + window_power = sum(map(lambda x: x*x, fft_window)) + + c2magsq = blocks.complex_to_mag_squared(fft_size) + self._avg = filter.single_pole_iir_filter_ff(1.0, fft_size) + self._log = blocks.nlog10_ff(10, fft_size, + -20*math.log10(fft_size) # Adjust for number of bins + -10*math.log10(window_power/fft_size) # Adjust for windowing loss + -20*math.log10(ref_scale/2)) # Adjust for reference scale + self.connect(self, self._sd, fft, c2magsq, self._avg, self._log, self) + + self._average = average + self._avg_alpha = avg_alpha + self.set_avg_alpha(avg_alpha) + self.set_average(average) + + def set_decimation(self, decim): + """ + Set the decimation on stream decimator. + + Args: + decim: the new decimation + """ + self._sd.set_decimation(decim) + + def set_vec_rate(self, vec_rate): + """ + Set the vector rate on stream decimator. + + Args: + vec_rate: the new vector rate + """ + self._sd.set_vec_rate(vec_rate) + + def set_sample_rate(self, sample_rate): + """ + Set the new sampling rate + + Args: + sample_rate: the new rate + """ + self._sd.set_sample_rate(sample_rate) + + def set_average(self, average): + """ + Set the averaging filter on/off. + + Args: + average: true to set averaging on + """ + self._average = average + if self._average: + self._avg.set_taps(self._avg_alpha) + else: + self._avg.set_taps(1.0) + + def set_avg_alpha(self, avg_alpha): + """ + Set the average alpha and set the taps if average was on. + + Args: + avg_alpha: the new iir filter tap + """ + self._avg_alpha = avg_alpha + self.set_average(self._average) + + def sample_rate(self): + """ + Return the current sample rate. + """ + return self._sd.sample_rate() + + def decimation(self): + """ + Return the current decimation. + """ + return self._sd.decimation() + + def frame_rate(self): + """ + Return the current frame rate. + """ + return self._sd.frame_rate() + + def average(self): + """ + Return whether or not averaging is being performed. + """ + return self._average + + def avg_alpha(self): + """ + Return averaging filter constant. + """ + return self._avg_alpha + +class logpwrfft_f(_logpwrfft_base): + """ + Create an fft block chain, with real input. + """ + _name = "logpwrfft_f" + _item_size = gr.sizeof_float + _fft_block = (fft.fft_vfc, ) + +class logpwrfft_c(_logpwrfft_base): + """ + Create an fft block chain, with complex input. + """ + _name = "logpwrfft_c" + _item_size = gr.sizeof_gr_complex + _fft_block = (fft.fft_vcc, ) + diff --git a/gr-fft/python/qa_fft.py b/gr-fft/python/qa_fft.py index 1c45ac1484..0a66a2c1fc 100755 --- a/gr-fft/python/qa_fft.py +++ b/gr-fft/python/qa_fft.py @@ -21,6 +21,7 @@ from gnuradio import gr, gr_unittest import fft_swig as fft +import blocks_swig as blocks import sys import random @@ -87,9 +88,9 @@ class test_fft(gr_unittest.TestCase): (1646.539306640625-1694.1956787109375j)) src = gr.vector_source_c(src_data) - s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, fft_size) op = fft.fft_vcc(fft_size, True, [], False) - v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, fft_size) dst = gr.vector_sink_c() tb.connect(src, s2v, op, v2s, dst) tb.run() @@ -141,9 +142,9 @@ class test_fft(gr_unittest.TestCase): expected_result = tuple([complex(primes[2*i], primes[2*i+1]) for i in range(fft_size)]) src = gr.vector_source_c(src_data) - s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, fft_size) op = fft.fft_vcc(fft_size, False, [], False) - v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, fft_size) dst = gr.vector_sink_c() tb.connect(src, s2v, op, v2s, dst) tb.run() @@ -199,9 +200,9 @@ class test_fft(gr_unittest.TestCase): nthreads = 2 src = gr.vector_source_c(src_data) - s2v = gr.stream_to_vector(gr.sizeof_gr_complex, fft_size) + s2v = blocks.stream_to_vector(gr.sizeof_gr_complex, fft_size) op = fft.fft_vcc(fft_size, False, [], False, nthreads) - v2s = gr.vector_to_stream(gr.sizeof_gr_complex, fft_size) + v2s = blocks.vector_to_stream(gr.sizeof_gr_complex, fft_size) dst = gr.vector_sink_c() tb.connect(src, s2v, op, v2s, dst) tb.run() diff --git a/gr-fft/python/window.py b/gr-fft/python/window.py new file mode 100644 index 0000000000..0065a08a61 --- /dev/null +++ b/gr-fft/python/window.py @@ -0,0 +1,179 @@ +# +# 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 |