diff options
author | Tom Rondeau | 2012-06-19 20:36:04 -0400 |
---|---|---|
committer | Tom Rondeau | 2012-06-19 20:36:04 -0400 |
commit | fad32dc397d731493dc88367d2b4648b35bb905b (patch) | |
tree | 9ed0d879ec2bf7099b09ba9d45ae6a2acdd32ec2 /gr-filter | |
parent | 5ab78aaeedb87f4a30c41dd9e7ede56b5dc01d04 (diff) | |
download | gnuradio-fad32dc397d731493dc88367d2b4648b35bb905b.tar.gz gnuradio-fad32dc397d731493dc88367d2b4648b35bb905b.tar.bz2 gnuradio-fad32dc397d731493dc88367d2b4648b35bb905b.zip |
filter: adding PFB synthesis filter with GRC and QA.
Diffstat (limited to 'gr-filter')
-rw-r--r-- | gr-filter/grc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-filter/grc/filter_block_tree.xml | 1 | ||||
-rw-r--r-- | gr-filter/grc/pfb_synthesizer.xml | 57 | ||||
-rw-r--r-- | gr-filter/include/filter/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-filter/include/filter/pfb_synthesizer_ccf.h | 107 | ||||
-rw-r--r-- | gr-filter/lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | gr-filter/lib/pfb_synthesizer_ccf_impl.cc | 288 | ||||
-rw-r--r-- | gr-filter/lib/pfb_synthesizer_ccf_impl.h | 85 | ||||
-rwxr-xr-x | gr-filter/python/qa_pfb_synthesizer.py | 87 | ||||
-rw-r--r-- | gr-filter/swig/filter_swig.i | 3 |
10 files changed, 631 insertions, 0 deletions
diff --git a/gr-filter/grc/CMakeLists.txt b/gr-filter/grc/CMakeLists.txt index 0747c7240..8bbb4c9e0 100644 --- a/gr-filter/grc/CMakeLists.txt +++ b/gr-filter/grc/CMakeLists.txt @@ -32,6 +32,7 @@ install(FILES pfb_channelizer.xml pfb_decimator.xml pfb_interpolator.xml + pfb_synthesizer.xml rational_resampler_base_xxx.xml single_pole_iir_filter_xx.xml DESTINATION ${GRC_BLOCKS_DIR} diff --git a/gr-filter/grc/filter_block_tree.xml b/gr-filter/grc/filter_block_tree.xml index de840a3fd..b16966eae 100644 --- a/gr-filter/grc/filter_block_tree.xml +++ b/gr-filter/grc/filter_block_tree.xml @@ -43,6 +43,7 @@ <block>pfb_channelizer_ccf</block> <block>pfb_decimator_ccf</block> <block>pfb_interpolator_ccf</block> + <block>pfb_synthesizer_ccf</block> <block>rational_resampler_base_xxx</block> <block>single_pole_iir_filter_xx</block> </cat> diff --git a/gr-filter/grc/pfb_synthesizer.xml b/gr-filter/grc/pfb_synthesizer.xml new file mode 100644 index 000000000..e84b25e62 --- /dev/null +++ b/gr-filter/grc/pfb_synthesizer.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Polyphase Synthesis Filterbank +################################################### + --> +<block> + <name>Polyphase Synthesizer</name> + <key>pfb_synthesizer_ccf</key> + <import>from gnuradio import filter</import> + <import>from gnuradio.filter import firdes</import> + <make>filter.pfb_synthesizer_ccf( + $numchans, $taps, $twox) +self.$(id).set_channel_map($ch_map) + </make> + <callback>set_taps($taps)</callback> + <callback>set_channel_map($ch_map)</callback> + + <param> + <name>Channels</name> + <key>numchans</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Connections</name> + <key>connections</key> + <value>2</value> + <type>int</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <type>real_vector</type> + </param> + <param> + <name>2x Sample Rate</name> + <key>twox</key> + <value>False</value> + <type>bool</type> + </param> + <param> + <name>Channel Map</name> + <key>ch_map</key> + <value>[]</value> + <type>int_vector</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + <nports>$connections</nports> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/gr-filter/include/filter/CMakeLists.txt b/gr-filter/include/filter/CMakeLists.txt index 9174bfc84..b30a1fc76 100644 --- a/gr-filter/include/filter/CMakeLists.txt +++ b/gr-filter/include/filter/CMakeLists.txt @@ -106,6 +106,7 @@ install(FILES pfb_channelizer_ccf.h pfb_decimator_ccf.h pfb_interpolator_ccf.h + pfb_synthesizer_ccf.h single_pole_iir_filter_cc.h single_pole_iir_filter_ff.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/filter diff --git a/gr-filter/include/filter/pfb_synthesizer_ccf.h b/gr-filter/include/filter/pfb_synthesizer_ccf.h new file mode 100644 index 000000000..ec6fb49c2 --- /dev/null +++ b/gr-filter/include/filter/pfb_synthesizer_ccf.h @@ -0,0 +1,107 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 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. + */ + + +#ifndef INCLUDED_PFB_SYNTHESIZER_CCF_H +#define INCLUDED_PFB_SYNTHESIZER_CCF_H + +#include <filter/api.h> +#include <gr_sync_interpolator.h> + +namespace gr { + namespace filter { + + /*! + * \class pfb_synthesizer_ccf + * + * \brief Polyphase synthesis filterbank with + * gr_complex input, gr_complex output and float taps + * + * \ingroup filter_blk + * \ingroup pfb_blk + */ + + class FILTER_API pfb_synthesizer_ccf : virtual public gr_sync_interpolator + { + public: + // gr::filter::pfb_synthesizer_ccf::sptr + typedef boost::shared_ptr<pfb_synthesizer_ccf> sptr; + + /*! + * Build the polyphase synthesis filterbank. + * \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 twox (bool) use 2x oversampling or not (default is no) + */ + static FILTER_API sptr make(unsigned int numchans, + const std::vector<float> &taps, + bool twox=false); + + /*! + * Resets the filterbank's filter taps with the new prototype filter + * \param taps (vector/list of floats) The prototype filter to + * populate the filterbank. + */ + virtual void set_taps(const std::vector<float> &taps) = 0; + + /*! + * Print all of the filterbank taps to screen. + */ + virtual void print_taps() = 0; + + /*! + * Return a vector<vector<>> of the filterbank taps + */ + virtual std::vector<std::vector<float> > taps() const = 0; + + /*! + * Set the channel map. Channels are numbers as: + * N/2+1 | ... | N-1 | 0 | 1 | 2 | ... | N/2 + * <------------------- 0 --------------------> + * freq + * + * So input stream 0 goes to channel 0, etc. Setting a new channel + * map allows the user to specify where in frequency he/she wants + * the input stream to go. This is especially useful to avoid + * putting signals into the channels on the edge of the spectrum + * which can either wrap around (in the case of odd number of + * channels) and be affected by filter rolloff in the transmitter. + * + * The map must be at least the number of streams being sent to the + * block. Less and the algorithm will not have enough data to + * properly setup the buffers. Any more channels specified will be + * ignored. + */ + virtual void set_channel_map(const std::vector<int> &map) = 0; + + /*! + * Gets the current channel map. + */ + virtual std::vector<int> channel_map() const = 0; + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_SYNTHESIZER_CCF_H */ diff --git a/gr-filter/lib/CMakeLists.txt b/gr-filter/lib/CMakeLists.txt index b3d456ec9..e29d69db5 100644 --- a/gr-filter/lib/CMakeLists.txt +++ b/gr-filter/lib/CMakeLists.txt @@ -133,6 +133,7 @@ list(APPEND filter_sources pfb_channelizer_ccf_impl.cc pfb_decimator_ccf_impl.cc pfb_interpolator_ccf_impl.cc + pfb_synthesizer_ccf_impl.cc single_pole_iir_filter_cc_impl.cc single_pole_iir_filter_ff_impl.cc ) diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.cc b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc new file mode 100644 index 000000000..1e9c099c1 --- /dev/null +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.cc @@ -0,0 +1,288 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 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 "pfb_synthesizer_ccf_impl.h" +#include <gr_io_signature.h> +#include <cstdio> + +namespace gr { + namespace filter { + + pfb_synthesizer_ccf::sptr + pfb_synthesizer_ccf::make(unsigned int numchans, + const std::vector<float> &taps, + bool twox) + { + return gnuradio::get_initial_sptr + (new pfb_synthesizer_ccf_impl(numchans, taps, twox)); + } + + + pfb_synthesizer_ccf_impl::pfb_synthesizer_ccf_impl(unsigned int numchans, + const std::vector<float> &taps, + bool twox) + : gr_sync_interpolator("pfb_synthesizer_ccf", + gr_make_io_signature(1, numchans, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex)), + numchans), + d_updated (false), d_numchans(numchans), d_state(0) + { + // set up 2x multiplier; if twox==True, set to 2, otherwise to 1 + d_twox = (twox ? 2 : 1); + if(d_numchans % d_twox != 0) { + throw std::invalid_argument("pfb_synthesizer_ccf: number of channels must be even for 2x oversampling.\n"); + } + + d_filters = std::vector<kernel::fir_filter_with_buffer_ccf*>(d_twox*d_numchans); + d_channel_map.resize(d_twox*d_numchans); + + // Create a FIR filter for each channel and zero out the taps + std::vector<float> vtaps(0, d_twox*d_numchans); + for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + d_filters[i] = new kernel::fir_filter_with_buffer_ccf(vtaps); + d_channel_map[i] = i; + } + + // Now, actually set the filters' taps + set_taps(taps); + + // Create the IFFT to handle the input channel rotations + d_fft = new fft::fft_complex(d_twox*d_numchans, false); + memset(d_fft->get_inbuf(), 0, d_twox*d_numchans*sizeof(gr_complex)); + + set_output_multiple(d_numchans); + } + + pfb_synthesizer_ccf_impl::~pfb_synthesizer_ccf_impl() + { + for(unsigned int i = 0; i < d_twox*d_numchans; i++) { + delete d_filters[i]; + } + } + + void + pfb_synthesizer_ccf_impl::set_taps(const std::vector<float> &taps) + { + gruel::scoped_lock guard(d_mutex); + + if(d_twox == 1) + set_taps1(taps); + else + set_taps2(taps); + + // Set the history to ensure enough input items for each filter + set_history(d_taps_per_filter+1); + + d_updated = true; + } + + void + pfb_synthesizer_ccf_impl::set_taps1(const std::vector<float> &taps) + { + unsigned int i,j; + + unsigned int ntaps = taps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_numchans); + + // Create d_numchan vectors to store each channel's taps + d_taps.resize(d_numchans); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector<float> tmp_taps; + tmp_taps = taps; + while((float)(tmp_taps.size()) < d_numchans*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_numchans; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + d_taps[i] = std::vector<float>(d_taps_per_filter, 0); + for(j = 0; j < d_taps_per_filter; j++) { + d_taps[i][j] = tmp_taps[i + j*d_numchans]; // add taps to channels in reverse order + } + + // Build a filter for each channel and add it's taps to it + d_filters[i]->set_taps(d_taps[i]); + } + } + + void + pfb_synthesizer_ccf_impl::set_taps2 (const std::vector<float> &taps) + { + unsigned int i,j; + int state = 0; + + unsigned int ntaps = taps.size(); + d_taps_per_filter = (unsigned int)ceil((double)ntaps/(double)d_numchans); + + // Create d_numchan vectors to store each channel's taps + d_taps.resize(d_twox*d_numchans); + + // Make a vector of the taps plus fill it out with 0's to fill + // each polyphase filter with exactly d_taps_per_filter + std::vector<float> tmp_taps; + tmp_taps = taps; + while((float)(tmp_taps.size()) < d_numchans*d_taps_per_filter) { + tmp_taps.push_back(0.0); + } + + // Partition the filter + for(i = 0; i < d_numchans; i++) { + // Each channel uses all d_taps_per_filter with 0's if not enough taps to fill out + d_taps[i] = std::vector<float>(d_taps_per_filter, 0); + d_taps[d_numchans+i] = std::vector<float>(d_taps_per_filter, 0); + state = 0; + for(j = 0; j < d_taps_per_filter; j++) { + // add taps to channels in reverse order + // Zero out every other tap + if(state == 0) { + d_taps[i][j] = tmp_taps[i + j*d_numchans]; + d_taps[d_numchans + i][j] = 0; + state = 1; + } + else { + d_taps[i][j] = 0; + d_taps[d_numchans + i][j] = tmp_taps[i + j*d_numchans]; + state = 0; + } + } + + // Build a filter for each channel and add it's taps to it + d_filters[i]->set_taps(d_taps[i]); + d_filters[d_numchans + i]->set_taps(d_taps[d_numchans + i]); + } + } + + void + pfb_synthesizer_ccf_impl::print_taps() + { + unsigned int i, j; + for(i = 0; i < d_twox*d_numchans; i++) { + printf("filter[%d]: [", i); + for(j = 0; j < d_taps_per_filter; j++) { + printf(" %.4e", d_taps[i][j]); + } + printf("]\n\n"); + } + } + + std::vector< std::vector<float> > + pfb_synthesizer_ccf_impl::taps() const + { + return d_taps; + } + + void + pfb_synthesizer_ccf_impl::set_channel_map(const std::vector<int> &map) + { + gruel::scoped_lock guard(d_mutex); + + if(map.size() > 0) { + unsigned int max = (unsigned int)*std::max_element(map.begin(), map.end()); + unsigned int min = (unsigned int)*std::min_element(map.begin(), map.end()); + if((max >= d_twox*d_numchans) || (min < 0)) { + throw std::invalid_argument("gr_pfb_synthesizer_ccf::set_channel_map: map range out of bounds.\n"); + } + d_channel_map = map; + + // Zero out fft buffer so that unused channels are always 0 + memset(d_fft->get_inbuf(), 0,d_twox*d_numchans*sizeof(gr_complex)); + } + } + + std::vector<int> + pfb_synthesizer_ccf_impl::channel_map() const + { + return d_channel_map; + } + + int + pfb_synthesizer_ccf_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + gruel::scoped_lock guard(d_mutex); + + gr_complex *in = (gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + if(d_updated) { + d_updated = false; + return 0; // history requirements may have changed. + } + + unsigned int n, i; + size_t ninputs = input_items.size(); + + // Algoritm for critically sampled channels + if(d_twox == 1) { + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < ninputs; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[d_channel_map[i]] = in[n]; + } + + // spin through IFFT + d_fft->execute(); + + for(i = 0; i < d_numchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[i]); + } + out += d_numchans; + } + } + + // Algorithm for oversampling by 2x + else { + for(n = 0; n < noutput_items/d_numchans; n++) { + for(i = 0; i < ninputs; i++) { + in = (gr_complex*)input_items[i]; + d_fft->get_inbuf()[d_channel_map[i]] = in[n]; + } + + // spin through IFFT + d_fft->execute(); + + // Output is sum of two filters, but the input buffer to the filters must be circularly + // shifted by numchans every time through, done by using d_state to determine which IFFT + // buffer position to pull from. + for(i = 0; i < d_numchans; i++) { + out[i] = d_filters[i]->filter(d_fft->get_outbuf()[d_state*d_numchans+i]); + out[i] += d_filters[d_numchans+i]->filter(d_fft->get_outbuf()[(d_state^1)*d_numchans+i]); + } + d_state ^= 1; + + out += d_numchans; + } + } + + return noutput_items; + } + + } /* namespace filter */ +} /* namespace gr */ diff --git a/gr-filter/lib/pfb_synthesizer_ccf_impl.h b/gr-filter/lib/pfb_synthesizer_ccf_impl.h new file mode 100644 index 000000000..adffc143f --- /dev/null +++ b/gr-filter/lib/pfb_synthesizer_ccf_impl.h @@ -0,0 +1,85 @@ +/* -*- c++ -*- */ +/* + * Copyright 2010,2012 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. + */ + + +#ifndef INCLUDED_PFB_SYNTHESIZER_CCF_IMPL_H +#define INCLUDED_PFB_SYNTHESIZER_CCF_IMPL_H + +#include <filter/pfb_synthesizer_ccf.h> +#include <filter/fir_filter_with_buffer.h> +#include <fft/fft.h> +#include <gruel/thread.h> + +namespace gr { + namespace filter { + + // While this is a polyphase_filterbank, we don't use the normal + // parent class because we have to use the fir_filter_with_buffer + // objects instead of normal filters. + + class FILTER_API pfb_synthesizer_ccf_impl : public pfb_synthesizer_ccf + { + private: + bool d_updated; + unsigned int d_numchans; + unsigned int d_taps_per_filter; + fft::fft_complex *d_fft; + std::vector< kernel::fir_filter_with_buffer_ccf*> d_filters; + std::vector< std::vector<float> > d_taps; + int d_state; + std::vector<int> d_channel_map; + unsigned int d_twox; + gruel::mutex d_mutex; // mutex to protect set/work access + + /*! + * \brief Tap setting algorithm for critically sampled channels + */ + void set_taps1(const std::vector<float> &taps); + + /*! + * \brief Tap setting algorithm for 2x over-sampled channels + */ + void set_taps2(const std::vector<float> &taps); + + + public: + pfb_synthesizer_ccf_impl(unsigned int numchans, + const std::vector<float> &taps, + bool twox); + ~pfb_synthesizer_ccf_impl(); + + void set_taps(const std::vector<float> &taps); + std::vector<std::vector<float> > taps() const; + void print_taps(); + + void set_channel_map(const std::vector<int> &map); + std::vector<int> channel_map() const; + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace filter */ +} /* namespace gr */ + +#endif /* INCLUDED_PFB_SYNTHESIZER_CCF_IMPL_H */ diff --git a/gr-filter/python/qa_pfb_synthesizer.py b/gr-filter/python/qa_pfb_synthesizer.py new file mode 100755 index 000000000..8b69ccb12 --- /dev/null +++ b/gr-filter/python/qa_pfb_synthesizer.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# +# Copyright 2012 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, gr_unittest +import filter_swig as filter +import math + +class test_pfb_synthesizer(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_000(self): + N = 10000 # number of samples to use + M = 5 # Number of channels + fs = 1000 # baseband sampling rate + ofs = M*fs # input samp rate to decimator + + taps = gr.firdes.low_pass_2(M, ofs, fs/2, fs/10, + attenuation_dB=80, + window=gr.firdes.WIN_BLACKMAN_hARRIS) + + signals = list() + freqs = [0, 100, 200, -200, -100] + for i in xrange(len(freqs)): + signals.append(gr.sig_source_c(fs, gr.GR_SIN_WAVE, freqs[i], 1)) + + head = gr.head(gr.sizeof_gr_complex, N) + pfb = filter.pfb_synthesizer_ccf(M, taps) + snk = gr.vector_sink_c() + + for i in xrange(M): + self.tb.connect(signals[i], (pfb,i)) + + self.tb.connect(pfb, head, snk) + + self.tb.run() + + Ntest = 1000 + L = len(snk.data()) + t = map(lambda x: float(x)/ofs, xrange(L)) + + # Create known data as sum of complex sinusoids at freqs + # of the output channels. + freqs = [-2200, -1100, 0, 1100, 2200] + expected_data = len(t)*[0,] + for i in xrange(len(t)): + expected_data[i] = math.cos(2.*math.pi*freqs[0]*t[i]) + \ + 1j*math.sin(2.*math.pi*freqs[0]*t[i]) + \ + math.cos(2.*math.pi*freqs[1]*t[i]) + \ + 1j*math.sin(2.*math.pi*freqs[1]*t[i]) + \ + math.cos(2.*math.pi*freqs[2]*t[i]) + \ + 1j*math.sin(2.*math.pi*freqs[2]*t[i]) + \ + math.cos(2.*math.pi*freqs[3]*t[i]) + \ + 1j*math.sin(2.*math.pi*freqs[3]*t[i]) + \ + math.cos(2.*math.pi*freqs[4]*t[i]) + \ + 1j*math.sin(2.*math.pi*freqs[4]*t[i]) + dst_data = snk.data() + + offset = 25 + self.assertComplexTuplesAlmostEqual(expected_data[2000-offset:2000-offset+Ntest], + dst_data[2000:2000+Ntest], 4) + +if __name__ == '__main__': + gr_unittest.run(test_pfb_synthesizer, "test_pfb_synthesizer.xml") diff --git a/gr-filter/swig/filter_swig.i b/gr-filter/swig/filter_swig.i index 5a8ebf975..bb4eab381 100644 --- a/gr-filter/swig/filter_swig.i +++ b/gr-filter/swig/filter_swig.i @@ -64,6 +64,7 @@ #include "filter/pfb_channelizer_ccf.h" #include "filter/pfb_decimator_ccf.h" #include "filter/pfb_interpolator_ccf.h" +#include "filter/pfb_synthesizer_ccf.h" #include "filter/rational_resampler_base_ccc.h" #include "filter/rational_resampler_base_ccf.h" #include "filter/rational_resampler_base_fcc.h" @@ -110,6 +111,7 @@ %include "filter/pfb_channelizer_ccf.h" %include "filter/pfb_decimator_ccf.h" %include "filter/pfb_interpolator_ccf.h" +%include "filter/pfb_synthesizer_ccf.h" %include "filter/rational_resampler_base_ccc.h" %include "filter/rational_resampler_base_ccf.h" %include "filter/rational_resampler_base_fcc.h" @@ -153,6 +155,7 @@ GR_SWIG_BLOCK_MAGIC2(filter, pfb_arb_resampler_fff); GR_SWIG_BLOCK_MAGIC2(filter, pfb_channelizer_ccf); GR_SWIG_BLOCK_MAGIC2(filter, pfb_decimator_ccf); GR_SWIG_BLOCK_MAGIC2(filter, pfb_interpolator_ccf); +GR_SWIG_BLOCK_MAGIC2(filter, pfb_synthesizer_ccf); GR_SWIG_BLOCK_MAGIC2(filter, rational_resampler_base_ccc); GR_SWIG_BLOCK_MAGIC2(filter, rational_resampler_base_ccf); GR_SWIG_BLOCK_MAGIC2(filter, rational_resampler_base_fcc); |