summaryrefslogtreecommitdiff
path: root/gr-fft/python
diff options
context:
space:
mode:
Diffstat (limited to 'gr-fft/python')
-rw-r--r--gr-fft/python/CMakeLists.txt4
-rw-r--r--gr-fft/python/__init__.py2
-rw-r--r--gr-fft/python/logpwrfft.py176
-rwxr-xr-xgr-fft/python/qa_fft.py13
-rw-r--r--gr-fft/python/window.py179
5 files changed, 367 insertions, 7 deletions
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