diff options
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc | 91 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h | 57 | ||||
-rw-r--r-- | gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i | 10 | ||||
-rw-r--r-- | gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py | 8 | ||||
-rwxr-xr-x | gnuradio-examples/python/pfb/channelize.py | 4 | ||||
-rw-r--r-- | grc/gui/Param.py | 15 | ||||
-rw-r--r-- | grc/python/Param.py | 32 | ||||
-rw-r--r-- | usrp/firmware/include/usrp_ids.h | 1 | ||||
-rwxr-xr-x | usrp/firmware/src/common/build_eeprom.py | 4 |
9 files changed, 163 insertions, 59 deletions
diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc index 7e34551c8..5fda47880 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -33,20 +33,33 @@ #include <cstring> gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps) + const std::vector<float> &taps, + float oversample_rate) { - return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps)); + return gr_pfb_channelizer_ccf_sptr (new gr_pfb_channelizer_ccf (numchans, taps, + oversample_rate)); } gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps) - : gr_sync_block ("pfb_channelizer_ccf", - gr_make_io_signature (numchans, numchans, sizeof(gr_complex)), - gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))), - d_updated (false) + const std::vector<float> &taps, + float oversample_rate) + : gr_block ("pfb_channelizer_ccf", + gr_make_io_signature (numchans, numchans, sizeof(gr_complex)), + gr_make_io_signature (1, 1, numchans*sizeof(gr_complex))), + d_updated (false), d_numchans(numchans), d_oversample_rate(oversample_rate) { - d_numchans = numchans; + // The over sampling rate must be rationally related to the number of channels + // in that it must be N/i for i in [1,N], which gives an outputsample rate + // of [fs/N, fs] where fs is the input sample rate. + // This tests the specified input sample rate to see if it conforms to this + // requirement within a few significant figures. + double intp = 0; + double x = (10000.0*rint(numchans / oversample_rate)) / 10000.0; + double fltp = modf(numchans / oversample_rate, &intp); + if(fltp != 0.0) + throw std::invalid_argument("gr_pfb_channelizer: oversample rate must be N/i for i in [1, N]"); + d_filters = std::vector<gr_fir_ccf*>(d_numchans); // Create an FIR filter for each channel and zero out the taps @@ -60,10 +73,28 @@ gr_pfb_channelizer_ccf::gr_pfb_channelizer_ccf (unsigned int numchans, // Create the FFT to handle the output de-spinning of the channels d_fft = new gri_fft_complex (d_numchans, false); + + // Although the filters change, we use this look up table + // to set the index of the FFT input buffer, which equivalently + // performs the FFT shift operation on every other turn. + d_rate_ratio = (int)rintf(d_numchans / d_oversample_rate); + d_idxlut = new int[d_numchans]; + for(unsigned int i = 0; i < d_numchans; i++) { + d_idxlut[i] = d_numchans - ((i + d_rate_ratio) % d_numchans) - 1; + } + + // Calculate the number of filtering rounds to do to evenly + // align the input vectors with the output channels + d_output_multiple = 1; + while((d_output_multiple * d_rate_ratio) % d_numchans != 0) + d_output_multiple++; + set_output_multiple(d_output_multiple); } gr_pfb_channelizer_ccf::~gr_pfb_channelizer_ccf () { + delete [] d_idxlut; + for(unsigned int i = 0; i < d_numchans; i++) { delete d_filters[i]; } @@ -101,7 +132,7 @@ gr_pfb_channelizer_ccf::set_taps (const std::vector<float> &taps) } // Set the history to ensure enough input items for each filter - set_history (d_taps_per_filter); + set_history (d_taps_per_filter+1); d_updated = true; } @@ -121,9 +152,10 @@ gr_pfb_channelizer_ccf::print_taps() int -gr_pfb_channelizer_ccf::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) +gr_pfb_channelizer_ccf::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { gr_complex *in = (gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; @@ -133,20 +165,35 @@ gr_pfb_channelizer_ccf::work (int noutput_items, return 0; // history requirements may have changed. } - for(int i = 0; i < noutput_items; i++) { - // Move through filters from bottom to top - for(int j = d_numchans-1; j >= 0; j--) { - // Take in the items from the first input stream to d_numchans - in = (gr_complex*)input_items[d_numchans - 1 - j]; + int n=1, i=-1, j=0, last; + int toconsume = (int)rintf(noutput_items/d_oversample_rate); + while(n <= toconsume) { + j = 0; + i = (i + d_rate_ratio) % d_numchans; + last = i; + while(i >= 0) { + in = (gr_complex*)input_items[j]; + d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n]); + j++; + i--; + } - // Filter current input stream from bottom filter to top - d_fft->get_inbuf()[j] = d_filters[j]->filter(&in[i]); + i = d_numchans-1; + while(i > last) { + in = (gr_complex*)input_items[j]; + d_fft->get_inbuf()[d_idxlut[j]] = d_filters[i]->filter(&in[n-1]); + j++; + i--; } + n += (i+d_rate_ratio) >= (int)d_numchans; + // despin through FFT d_fft->execute(); - memcpy(&out[d_numchans*i], d_fft->get_outbuf(), d_numchans*sizeof(gr_complex)); + memcpy(out, d_fft->get_outbuf(), d_numchans*sizeof(gr_complex)); + out += d_numchans; } - + + consume_each(toconsume); return noutput_items; } diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h index b2e67e817..d56ccdbc6 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,12 +24,13 @@ #ifndef INCLUDED_GR_PFB_CHANNELIZER_CCF_H #define INCLUDED_GR_PFB_CHANNELIZER_CCF_H -#include <gr_sync_block.h> +#include <gr_block.h> class gr_pfb_channelizer_ccf; typedef boost::shared_ptr<gr_pfb_channelizer_ccf> gr_pfb_channelizer_ccf_sptr; gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps); + const std::vector<float> &taps, + float oversample_rate=1); class gr_fir_ccf; class gri_fft_complex; @@ -88,6 +89,19 @@ class gri_fft_complex; * <B><EM>self._taps = gr.firdes.low_pass_2(1, fs, BW, TB, * attenuation_dB=ATT, window=gr.firdes.WIN_BLACKMAN_hARRIS)</EM></B> * + * The filter output can also be overs ampled. The over sampling rate + * is the ratio of the the actual output sampling rate to the normal + * output sampling rate. It must be rationally related to the number + * of channels as N/i for i in [1,N], which gives an outputsample rate + * of [fs/N, fs] where fs is the input sample rate and N is the number + * of channels. + * + * For example, for 6 channels with fs = 6000 Hz, the normal rate is + * 6000/6 = 1000 Hz. Allowable oversampling rates are 6/6, 6/5, 6/4, + * 6/3, 6/2, and 6/1 where the output sample rate of a 6/1 oversample + * ratio is 6000 Hz, or 6 times the normal 1000 Hz. A rate of 6/5 = 1.2, + * so the output rate would be 1200 Hz. + * * The theory behind this block can be found in Chapter 6 of * the following book. * @@ -96,23 +110,40 @@ class gri_fft_complex; * */ -class gr_pfb_channelizer_ccf : public gr_sync_block +class gr_pfb_channelizer_ccf : public gr_block { private: /*! * Build the polyphase filterbank decimator. * \param numchans (unsigned integer) Specifies the number of channels <EM>M</EM> * \param taps (vector/list of floats) The prototype filter to populate the filterbank. + * \param oversample_rate (float) The over sampling rate is the ratio of the the actual + * output sampling rate to the normal output sampling rate. + * It must be rationally related to the number of channels + * as N/i for i in [1,N], which gives an outputsample rate + * of [fs/N, fs] where fs is the input sample rate and N is + * the number of channels. + * + * For example, for 6 channels with fs = 6000 Hz, the normal + * rate is 6000/6 = 1000 Hz. Allowable oversampling rates + * are 6/6, 6/5, 6/4, 6/3, 6/2, and 6/1 where the output + * sample rate of a 6/1 oversample ratio is 6000 Hz, or + * 6 times the normal 1000 Hz. */ friend gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps); + const std::vector<float> &taps, + float oversample_rate); + bool d_updated; + unsigned int d_numchans; + float d_oversample_rate; std::vector<gr_fir_ccf*> d_filters; std::vector< std::vector<float> > d_taps; - gri_fft_complex *d_fft; - unsigned int d_numchans; unsigned int d_taps_per_filter; - bool d_updated; + gri_fft_complex *d_fft; + int *d_idxlut; + int d_rate_ratio; + int d_output_multiple; /*! * Build the polyphase filterbank decimator. @@ -120,7 +151,8 @@ class gr_pfb_channelizer_ccf : public gr_sync_block * \param taps (vector/list of floats) The prototype filter to populate the filterbank. */ gr_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps); + const std::vector<float> &taps, + float oversample_rate); public: ~gr_pfb_channelizer_ccf (); @@ -136,9 +168,10 @@ public: */ void print_taps(); - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; #endif diff --git a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i index 4bef90e22..63e3e0fe6 100644 --- a/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i +++ b/gnuradio-core/src/lib/filter/gr_pfb_channelizer_ccf.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2010 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,13 +23,15 @@ GR_SWIG_BLOCK_MAGIC(gr,pfb_channelizer_ccf); gr_pfb_channelizer_ccf_sptr gr_make_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps); + const std::vector<float> &taps, + float oversample_rate=1); -class gr_pfb_channelizer_ccf : public gr_sync_block +class gr_pfb_channelizer_ccf : public gr_block { private: gr_pfb_channelizer_ccf (unsigned int numchans, - const std::vector<float> &taps); + const std::vector<float> &taps, + float oversample_rate); public: ~gr_pfb_channelizer_ccf (); diff --git a/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py b/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py index c45ae4d1a..a479ed48e 100644 --- a/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py +++ b/gnuradio-core/src/python/gnuradio/blks2impl/pfb_channelizer.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2009 Free Software Foundation, Inc. +# Copyright 2009,2010 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -29,16 +29,18 @@ class pfb_channelizer_ccf(gr.hier_block2): This simplifies the interface by allowing a single input stream to connect to this block. It will then output a stream for each channel. ''' - def __init__(self, numchans, taps): + def __init__(self, numchans, taps, oversample_rate=1): gr.hier_block2.__init__(self, "pfb_channelizer_ccf", gr.io_signature(1, 1, gr.sizeof_gr_complex), # Input signature gr.io_signature(numchans, numchans, gr.sizeof_gr_complex)) # Output signature self._numchans = numchans self._taps = taps + self._oversample_rate = oversample_rate self.s2ss = gr.stream_to_streams(gr.sizeof_gr_complex, self._numchans) - self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps) + self.pfb = gr.pfb_channelizer_ccf(self._numchans, self._taps, + self._oversample_rate) self.v2s = gr.vector_to_streams(gr.sizeof_gr_complex, self._numchans) self.connect(self, self.s2ss) diff --git a/gnuradio-examples/python/pfb/channelize.py b/gnuradio-examples/python/pfb/channelize.py index bc83fae27..27d87e558 100755 --- a/gnuradio-examples/python/pfb/channelize.py +++ b/gnuradio-examples/python/pfb/channelize.py @@ -101,7 +101,7 @@ def main(): X,freq = mlab.psd(d, NFFT=fftlen, noverlap=fftlen/4, Fs=fs, window = lambda d: d*winfunc(fftlen), scale_by_freq=True) - X_in = 10.0*scipy.log10(abs(fftpack.fftshift(X))) + X_in = 10.0*scipy.log10(abs(X)) f_in = scipy.arange(-fs/2.0, fs/2.0, fs/float(X_in.size)) pin_f = spin_f.plot(f_in, X_in, "b") spin_f.set_xlim([min(f_in), max(f_in)+1]) @@ -144,7 +144,7 @@ def main(): X,freq = mlab.psd(d, NFFT=fftlen, noverlap=fftlen/4, Fs=fs_o, window = lambda d: d*winfunc(fftlen), scale_by_freq=True) - X_o = 10.0*scipy.log10(abs(fftpack.fftshift(X))) + X_o = 10.0*scipy.log10(abs(X)) f_o = scipy.arange(-fs_o/2.0, fs_o/2.0, fs_o/float(X_o.size)) p2_f = sp1_f.plot(f_o, X_o, "b") sp1_f.set_xlim([min(f_o), max(f_o)+1]) diff --git a/grc/gui/Param.py b/grc/gui/Param.py index b3018dab2..7c00c1b67 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -135,10 +135,21 @@ PARAM_LABEL_MARKUP_TMPL="""\ <span underline="$underline" foreground="$foreground" font_desc="Sans 9">$encode($param.get_name())</span>""" TIP_MARKUP_TMPL="""\ +######################################## +#def truncate(string) + #set $max_len = 100 + #set $string = str($string) + #if len($string) > $max_len +$('%s...%s'%($string[:$max_len/2], $string[-$max_len/2:]))#slurp + #else +$string#slurp + #end if +#end def +######################################## Key: $param.get_key() Type: $param.get_type() #if $param.is_valid() -Value: $param.get_evaluated() +Value: $truncate($param.get_evaluated()) #elif len($param.get_error_messages()) == 1 Error: $(param.get_error_messages()[0]) #else diff --git a/grc/python/Param.py b/grc/python/Param.py index e04bc8fcb..6dd008d1d 100644 --- a/grc/python/Param.py +++ b/grc/python/Param.py @@ -1,5 +1,5 @@ """ -Copyright 2008, 2009 Free Software Foundation, Inc. +Copyright 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -108,7 +108,23 @@ class Param(_Param, _GUIParam): Get the repr (nice string format) for this param. @return the string representation """ - if not self.is_valid(): return self.get_value() + ################################################## + # truncate helper method + ################################################## + def _truncate(string, style=0): + max_len = max(27 - len(self.get_name()), 3) + if len(string) > max_len: + if style < 0: #front truncate + string = '...' + string[3-max_len:] + elif style == 0: #center truncate + string = string[:max_len/2 -3] + '...' + string[-max_len/2:] + elif style > 0: #rear truncate + string = string[:max_len-3] + '...' + return string + ################################################## + # simple conditions + ################################################## + if not self.is_valid(): return _truncate(self.get_value()) if self.get_value() in self.get_option_keys(): return self.get_option(self.get_value()).get_name() ################################################## # display logic for numbers @@ -126,7 +142,6 @@ class Param(_Param, _GUIParam): # split up formatting by type ################################################## truncate = 0 #default center truncate - max_len = max(27 - len(self.get_name()), 3) e = self.get_evaluated() t = self.get_type() if isinstance(e, bool): return str(e) @@ -141,16 +156,9 @@ class Param(_Param, _GUIParam): truncate = -1 else: dt_str = str(e) #other types ################################################## - # truncate + # done ################################################## - if len(dt_str) > max_len: - if truncate < 0: #front truncate - dt_str = '...' + dt_str[3-max_len:] - elif truncate == 0: #center truncate - dt_str = dt_str[:max_len/2 -3] + '...' + dt_str[-max_len/2:] - elif truncate > 0: #rear truncate - dt_str = dt_str[:max_len-3] + '...' - return dt_str + return _truncate(dt_str, truncate) def get_input(self, *args, **kwargs): if self.get_type() in ('file_open', 'file_save'): return FileParam(self, *args, **kwargs) diff --git a/usrp/firmware/include/usrp_ids.h b/usrp/firmware/include/usrp_ids.h index dd5daed01..4152600bd 100644 --- a/usrp/firmware/include/usrp_ids.h +++ b/usrp/firmware/include/usrp_ids.h @@ -55,6 +55,7 @@ #define USB_PID_FSF_BDALE_8 0x0012 // Bdale Garbee <bdale@gag.com> #define USB_PID_FSF_BDALE_9 0x0013 // Bdale Garbee <bdale@gag.com> #define USB_PID_FSF_HPSDR_HERMES 0x0014 // HPSDR Hermes +#define USB_PID_FSF_THINKRF 0x0015 // Catalin Patulea <catalin.patulea@thinkrf.com> #define USB_PID_FSF_LBNL_UXO 0x0018 // http://recycle.lbl.gov/~ldoolitt/uxo/ diff --git a/usrp/firmware/src/common/build_eeprom.py b/usrp/firmware/src/common/build_eeprom.py index ed9bb56a4..d73cbbc4f 100755 --- a/usrp/firmware/src/common/build_eeprom.py +++ b/usrp/firmware/src/common/build_eeprom.py @@ -146,7 +146,7 @@ def build_shell_script (out, ihx_filename, rev, prefix): out.write ('#!/bin/sh\n') out.write ('usrper -x load_firmware ' + prefix + '/share/usrp/rev%d/std.ihx\n' % rev) - out.write ('sleep 1\n') + out.write ('sleep 2\n') # print "len(image) =", len(image) @@ -161,7 +161,7 @@ def build_shell_script (out, ihx_filename, rev, prefix): (i2c_addr, rom_addr, ''.join (hex_image[0:l]))) hex_image = hex_image[l:] rom_addr = rom_addr + l - out.write ('sleep 1\n') + out.write ('sleep 2\n') if __name__ == '__main__': usage = "usage: %prog -p PREFIX -r REV [options] bootfile.ihx" |