diff options
author | Tom Rondeau <tom@trondeau.com> | 2013-08-27 13:44:27 -0400 |
---|---|---|
committer | Tom Rondeau <tom@trondeau.com> | 2013-08-27 13:44:27 -0400 |
commit | af8fcd9884c19456530ff42185fc3a549098e472 (patch) | |
tree | 2d139c72758b69736395da22313b304ab33bacd9 | |
parent | 584f201d23e266400111dd24657b7f63868941b8 (diff) | |
parent | 797b3b061a2ae79b51853e1b86fd9f511a8f36f4 (diff) |
Merge branch 'dynamic_channel'
22 files changed, 833 insertions, 26 deletions
diff --git a/gnuradio-runtime/include/gnuradio/fxpt_vco.h b/gnuradio-runtime/include/gnuradio/fxpt_vco.h index 77d58677ce..cbc204c1b8 100644 --- a/gnuradio-runtime/include/gnuradio/fxpt_vco.h +++ b/gnuradio-runtime/include/gnuradio/fxpt_vco.h @@ -61,6 +61,17 @@ namespace gr { *cosx = fxpt::cos(d_phase); } + // compute complex sine a block at a time + void sincos(gr_complex *output, const float *input, int noutput_items, + float k, float ampl = 1.0) + { + for(int i = 0; i < noutput_items; i++) { + output[i] = gr_complex((float)(fxpt::cos(d_phase) * ampl), + (float)(fxpt::sin(d_phase) * ampl)); + adjust_phase(input[i] * k); + } + } + // compute a block at a time void cos(float *output, const float *input, int noutput_items, float k, float ampl = 1.0) { diff --git a/gnuradio-runtime/lib/math/qa_fxpt_vco.cc b/gnuradio-runtime/lib/math/qa_fxpt_vco.cc index ee9865e926..8ee402fdc1 100644 --- a/gnuradio-runtime/lib/math/qa_fxpt_vco.cc +++ b/gnuradio-runtime/lib/math/qa_fxpt_vco.cc @@ -102,6 +102,26 @@ qa_fxpt_vco::t1() void qa_fxpt_vco::t2() { + gr::vco<gr_complex,float> ref_vco; + gr::fxpt_vco new_vco; + gr_complex ref_block[SIN_COS_BLOCK_SIZE]; + gr_complex new_block[SIN_COS_BLOCK_SIZE]; + float input[SIN_COS_BLOCK_SIZE]; + double max_error = 0; + + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + input[i] = sin(double(i)); + } + + ref_vco.sincos(ref_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); + new_vco.sincos(new_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); + + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + CPPUNIT_ASSERT_COMPLEXES_EQUAL(ref_block[i], new_block[i], SIN_COS_TOLERANCE); + max_error = max_d(max_error, abs(ref_block[i]-new_block[i])); + } + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); + // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, ref_vco.get_phase()-new_vco.get_phase()); } void diff --git a/gnuradio-runtime/lib/math/vco.h b/gnuradio-runtime/lib/math/vco.h index fa11732c1f..d8a6fbb415 100644 --- a/gnuradio-runtime/lib/math/vco.h +++ b/gnuradio-runtime/lib/math/vco.h @@ -64,6 +64,9 @@ namespace gr { // compute sin and cos for current phase angle void sincos(float *sinx, float *cosx) const; + void sincos(gr_complex *output, const float *input, + int noutput_items, double k, double ampl = 1.0); + // compute cos or sin for current phase angle float cos() const { return std::cos(d_phase); } float sin() const { return std::sin(d_phase); } @@ -85,6 +88,17 @@ namespace gr { template<class o_type, class i_type> void + vco<o_type,i_type>::sincos(gr_complex *output, const float *input, + int noutput_items, double k, double ampl) + { + for(int i = 0; i < noutput_items; i++) { + output[i] = gr_complex(cos() * ampl, sin() * ampl); + adjust_phase(input[i] * k); + } + } + + template<class o_type, class i_type> + void vco<o_type,i_type>::cos(float *output, const float *input, int noutput_items, double k, double ampl) { diff --git a/gr-blocks/grc/blocks_vco_c.xml b/gr-blocks/grc/blocks_vco_c.xml new file mode 100644 index 0000000000..f6246441b9 --- /dev/null +++ b/gr-blocks/grc/blocks_vco_c.xml @@ -0,0 +1,35 @@ +<?xml version="1.0"?> +<!-- +################################################### +##VCO +################################################### + --> +<block> + <name>VCO (complex)</name> + <key>blocks_vco_c</key> + <import>from gnuradio import blocks</import> + <make>blocks.vco_c($samp_rate, $sensitivity, $amplitude)</make> + <param> + <name>Sample Rate</name> + <key>samp_rate</key> + <type>real</type> + </param> + <param> + <name>Sensitivity</name> + <key>sensitivity</key> + <type>real</type> + </param> + <param> + <name>Amplitude</name> + <key>amplitude</key> + <type>real</type> + </param> + <sink> + <name>in</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt index 88ee184179..de52e3e3e7 100644 --- a/gr-blocks/include/gnuradio/blocks/CMakeLists.txt +++ b/gr-blocks/include/gnuradio/blocks/CMakeLists.txt @@ -202,6 +202,7 @@ install(FILES udp_source.h unpack_k_bits_bb.h vco_f.h + vco_c.h vector_map.h vector_to_stream.h vector_to_streams.h diff --git a/gr-blocks/include/gnuradio/blocks/vco_c.h b/gr-blocks/include/gnuradio/blocks/vco_c.h new file mode 100644 index 0000000000..ab9723af5b --- /dev/null +++ b/gr-blocks/include/gnuradio/blocks/vco_c.h @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + +#ifndef INCLUDED_GR_VCO_C_H +#define INCLUDED_GR_VCO_C_H + +#include <gnuradio/blocks/api.h> +#include <gnuradio/sync_block.h> + +namespace gr { + namespace blocks { + + /*! + * \brief VCO - Voltage controlled oscillator + * \ingroup modulators_blk + * \ingroup waveform_generators_blk + * + * \details + * input: float stream of control voltages; output: complex oscillator output + */ + class BLOCKS_API vco_c : virtual public sync_block + { + public: + // gr::blocks::vco_c::sptr + typedef boost::shared_ptr<vco_c> sptr; + + /*! + * \brief VCO - Voltage controlled oscillator + * + * \param sampling_rate sampling rate (Hz) + * \param sensitivity units are radians/sec/volt + * \param amplitude output amplitude + */ + static sptr make(double sampling_rate, double sensitivity, double amplitude); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_VCO_C_H */ diff --git a/gr-blocks/lib/CMakeLists.txt b/gr-blocks/lib/CMakeLists.txt index 987164fdf7..1c7bd80ae0 100644 --- a/gr-blocks/lib/CMakeLists.txt +++ b/gr-blocks/lib/CMakeLists.txt @@ -244,6 +244,7 @@ list(APPEND gr_blocks_sources udp_source_impl.cc unpack_k_bits_bb_impl.cc vco_f_impl.cc + vco_c_impl.cc vector_map_impl.cc vector_to_stream_impl.cc vector_to_streams_impl.cc diff --git a/gr-blocks/lib/vco_c_impl.cc b/gr-blocks/lib/vco_c_impl.cc new file mode 100644 index 0000000000..5103ce1851 --- /dev/null +++ b/gr-blocks/lib/vco_c_impl.cc @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 "vco_c_impl.h" +#include <gnuradio/io_signature.h> +#include <math.h> + +namespace gr { + namespace blocks { + + vco_c::sptr + vco_c::make(double sampling_rate, double sensitivity, double amplitude) + { + return gnuradio::get_initial_sptr + (new vco_c_impl(sampling_rate, sensitivity, amplitude)); + } + + vco_c_impl::vco_c_impl(double sampling_rate, double sensitivity, double amplitude) + : sync_block("vco_c", + io_signature::make(1, 1, sizeof(float)), + io_signature::make(1, 1, sizeof(gr_complex))), + d_sampling_rate(sampling_rate), d_sensitivity(sensitivity), + d_amplitude(amplitude), d_k(d_sensitivity/d_sampling_rate) + { + } + + vco_c_impl::~vco_c_impl() + { + } + + int + vco_c_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const float *input = (const float*)input_items[0]; + gr_complex *output = (gr_complex*)output_items[0]; + + d_vco.sincos(output, input, noutput_items, d_k, d_amplitude); + + return noutput_items; + } + + } /* namespace blocks */ +} /* namespace gr */ diff --git a/gr-blocks/lib/vco_c_impl.h b/gr-blocks/lib/vco_c_impl.h new file mode 100644 index 0000000000..53def4f1da --- /dev/null +++ b/gr-blocks/lib/vco_c_impl.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 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. + */ + +#ifndef INCLUDED_GR_VCO_F_IMPL_H +#define INCLUDED_GR_VCO_F_IMPL_H + +#include <gnuradio/blocks/vco_c.h> +#include <gnuradio/fxpt_vco.h> + +namespace gr { + namespace blocks { + + class vco_c_impl : public vco_c + { + private: + double d_sampling_rate; + double d_sensitivity; + double d_amplitude; + double d_k; + gr::fxpt_vco d_vco; + + public: + vco_c_impl(double sampling_rate, double sensitivity, double amplitude); + ~vco_c_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } /* namespace blocks */ +} /* namespace gr */ + +#endif /* INCLUDED_GR_VCO_C_H */ diff --git a/gr-blocks/python/blocks/qa_vco.py b/gr-blocks/python/blocks/qa_vco.py index 4ed2a71c04..fdd1eb1001 100644 --- a/gr-blocks/python/blocks/qa_vco.py +++ b/gr-blocks/python/blocks/qa_vco.py @@ -28,6 +28,12 @@ def sig_source_f(samp_rate, freq, amp, N): y = map(lambda x: amp*math.cos(2.*math.pi*freq*x), t) return y +def sig_source_c(samp_rate, freq, amp, N): + t = map(lambda x: float(x)/samp_rate, xrange(N)) + y = map(lambda x: math.cos(2.*math.pi*freq*x) + \ + 1j*math.sin(2.*math.pi*freq*x), t) + return y + class test_vco(gr_unittest.TestCase): def setUp (self): @@ -53,6 +59,23 @@ class test_vco(gr_unittest.TestCase): self.assertFloatTuplesAlmostEqual(expected_result, result_data, 5) + def test_002(self): + src_data = 200*[0,] + 200*[0.5,] + 200*[1,] + expected_result = 200*[1,] + \ + sig_source_c(1, 0.125, 1, 200) + \ + sig_source_c(1, 0.25, 1, 200) + + src = blocks.vector_source_f(src_data) + op = blocks.vco_c(1, math.pi/2.0, 1) + dst = blocks.vector_sink_c() + + self.tb.connect(src, op, dst) + self.tb.run() + + result_data = dst.data() + self.assertComplexTuplesAlmostEqual(expected_result, result_data, 5) + + if __name__ == '__main__': gr_unittest.run(test_vco, "test_vco.xml") diff --git a/gr-blocks/swig/blocks_swig5.i b/gr-blocks/swig/blocks_swig5.i index 2b19d8ec29..09679531d9 100644 --- a/gr-blocks/swig/blocks_swig5.i +++ b/gr-blocks/swig/blocks_swig5.i @@ -64,6 +64,7 @@ #include "gnuradio/blocks/unpacked_to_packed_ss.h" #include "gnuradio/blocks/unpacked_to_packed_ii.h" #include "gnuradio/blocks/vco_f.h" +#include "gnuradio/blocks/vco_c.h" #include "gnuradio/blocks/xor_bb.h" #include "gnuradio/blocks/xor_ss.h" #include "gnuradio/blocks/xor_ii.h" @@ -102,6 +103,7 @@ %include "gnuradio/blocks/unpacked_to_packed_ss.h" %include "gnuradio/blocks/unpacked_to_packed_ii.h" %include "gnuradio/blocks/vco_f.h" +%include "gnuradio/blocks/vco_c.h" %include "gnuradio/blocks/xor_bb.h" %include "gnuradio/blocks/xor_ss.h" %include "gnuradio/blocks/xor_ii.h" @@ -139,6 +141,7 @@ GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_bb); GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_ss); GR_SWIG_BLOCK_MAGIC2(blocks, unpacked_to_packed_ii); GR_SWIG_BLOCK_MAGIC2(blocks, vco_f); +GR_SWIG_BLOCK_MAGIC2(blocks, vco_c); GR_SWIG_BLOCK_MAGIC2(blocks, xor_bb); GR_SWIG_BLOCK_MAGIC2(blocks, xor_ss); GR_SWIG_BLOCK_MAGIC2(blocks, xor_ii); diff --git a/gr-channels/grc/channels_channel_model2.xml b/gr-channels/grc/channels_channel_model2.xml new file mode 100644 index 0000000000..e8162f53d4 --- /dev/null +++ b/gr-channels/grc/channels_channel_model2.xml @@ -0,0 +1,61 @@ +<?xml version="1.0"?> +<!-- +################################################### +##Channel Model +################################################### + --> +<block> + <name>Channel Model 2</name> + <key>channels_channel_model2</key> + <import>from gnuradio import channels</import> + <import>from gnuradio.filter import firdes</import> + <make>channels.channel_model2( + noise_voltage=$noise_voltage, + epsilon=$epsilon, + taps=$taps, + noise_seed=$seed, +)</make> + <callback>set_noise_voltage($noise_voltage)</callback> + <callback>set_taps($taps)</callback> + <callback>set_timing_offset($epsilon)</callback> + <param> + <name>Noise Voltage</name> + <key>noise_voltage</key> + <value>0.0</value> + <type>real</type> + </param> + <param> + <name>Time Offset</name> + <key>epsilon</key> + <value>1.0</value> + <type>real</type> + </param> + <param> + <name>Taps</name> + <key>taps</key> + <value>1.0 + 1.0j</value> + <type>complex_vector</type> + </param> + <param> + <name>Seed</name> + <key>seed</key> + <value>0</value> + <type>int</type> + </param> + <sink> + <name>in</name> + <type>complex</type> + </sink> + <sink> + <name>freq</name> + <type>float</type> + </sink> + <sink> + <name>time</name> + <type>float</type> + </sink> + <source> + <name>out</name> + <type>complex</type> + </source> +</block> diff --git a/gr-channels/include/gnuradio/channels/CMakeLists.txt b/gr-channels/include/gnuradio/channels/CMakeLists.txt index f9a535b9c0..cb618a7e8d 100644 --- a/gr-channels/include/gnuradio/channels/CMakeLists.txt +++ b/gr-channels/include/gnuradio/channels/CMakeLists.txt @@ -23,6 +23,7 @@ install(FILES api.h channel_model.h + channel_model2.h fading_model.h selective_fading_model.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/channels diff --git a/gr-channels/include/gnuradio/channels/channel_model2.h b/gr-channels/include/gnuradio/channels/channel_model2.h new file mode 100644 index 0000000000..05084931ee --- /dev/null +++ b/gr-channels/include/gnuradio/channels/channel_model2.h @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,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. + */ + +#ifndef INCLUDED_CHANNELS_CHANNEL_MODEL2_H +#define INCLUDED_CHANNELS_CHANNEL_MODEL2_H + +#include <gnuradio/channels/api.h> +#include <gnuradio/hier_block2.h> +#include <gnuradio/types.h> + +namespace gr { + namespace channels { + + /*! + * \brief channel model2 + * \ingroup channel_models_blk + * + * \details + * This block implements a basic channel model simulator that can + * be used to help evaluate, design, and test various signals, + * waveforms, and algorithms. + * + * This model allows the user to set the voltage of an AWGN noise + * source, an initial timing offset, and a noise seed to randomize + * the AWGN noise source. + * + * Multipath can be approximated in this model by using a FIR + * filter representation of a multipath delay profile. + * + * Unlike gr::channels::channel_model, this block is designed to + * enable time-varying frequency and timing offsets. + * * Port 0: input signal to be run through the channel. + * * Port 1: frequency function. A constant value between -0.5 and + * 0.5 here will turn into a constant frequency offset + * from -fs/2 to fs/2 (where fs is the sample rate). + * * Port 2: timing offset function. Sets the resampling rate of + * the channel model. A constant value here produces + * that value as the timing offset, so a constant 1.0 + * input stream is the same as not having a timing + * offset. + * + * Since the models for frequency and timing offset may vary and + * what we are trying to model may be different for different + * simulations, we provide the time-varying nature as an input + * function that is user-defined. If only constant frequency and + * timing offsets are required, it is easier and less expensive to + * use gr::channels::channel_model. + */ + class CHANNELS_API channel_model2 : virtual public hier_block2 + { + public: + // gr::channels::channel_model2::sptr + typedef boost::shared_ptr<channel_model2> sptr; + + /*! \brief Build the channel simulator. + * + * \param noise_voltage The AWGN noise level as a voltage (to be + * calculated externally to meet, say, a + * desired SNR). + * \param epsilon The initial sample timing offset to emulate the + * different rates between the sample clocks of + * the transmitter and receiver. 1.0 is no difference. + * \param taps Taps of a FIR filter to emulate a multipath delay profile. + * \param noise_seed A random number generator seed for the noise source. + */ + static sptr make(double noise_voltage=0.0, + double epsilon=1.0, + const std::vector<gr_complex> &taps=std::vector<gr_complex>(1,1), + double noise_seed=0); + + virtual void set_noise_voltage(double noise_voltage) = 0; + virtual void set_taps(const std::vector<gr_complex> &taps) = 0; + virtual void set_timing_offset(double epsilon) = 0; + + virtual double noise_voltage() const = 0; + virtual std::vector<gr_complex> taps() const = 0; + virtual double timing_offset() const = 0; + }; + + } /* namespace channels */ +} /* namespace gr */ + +#endif /* INCLUDED_CHANNELS_CHANNEL_MODEL2_H */ diff --git a/gr-channels/lib/CMakeLists.txt b/gr-channels/lib/CMakeLists.txt index 46c90671c2..f429fae0fc 100644 --- a/gr-channels/lib/CMakeLists.txt +++ b/gr-channels/lib/CMakeLists.txt @@ -43,6 +43,7 @@ endif(ENABLE_GR_CTRLPORT) ######################################################################## list(APPEND channels_sources channel_model_impl.cc + channel_model2_impl.cc fading_model_impl.cc selective_fading_model_impl.cc flat_fader_impl.cc diff --git a/gr-channels/lib/channel_model2_impl.cc b/gr-channels/lib/channel_model2_impl.cc new file mode 100644 index 0000000000..cd742305cb --- /dev/null +++ b/gr-channels/lib/channel_model2_impl.cc @@ -0,0 +1,174 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,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 "channel_model2_impl.h" +#include <gnuradio/io_signature.h> +#include <iostream> + +namespace gr { + namespace channels { + + channel_model2::sptr + channel_model2::make(double noise_voltage, + double epsilon, + const std::vector<gr_complex> &taps, + double noise_seed) + { + return gnuradio::get_initial_sptr + (new channel_model2_impl(noise_voltage, + epsilon, + taps, + noise_seed)); + } + + // Hierarchical block constructor + channel_model2_impl::channel_model2_impl(double noise_voltage, + double epsilon, + const std::vector<gr_complex> &taps, + double noise_seed) + : hier_block2("channel_model2", + io_signature::make2(3, 3, sizeof(gr_complex), sizeof(float)), + io_signature::make(1, 1, sizeof(gr_complex))) + { + d_taps = taps; + while(d_taps.size() < 2) { + d_taps.push_back(0); + } + + d_timing_offset = filter::fractional_resampler_cc::make(0, epsilon); + + d_multipath = filter::fir_filter_ccc::make(1, d_taps); + + d_noise_adder = blocks::add_cc::make(); + d_noise = analog::fastnoise_source_c::make(analog::GR_GAUSSIAN, + noise_voltage, noise_seed); + d_freq_gen = blocks::vco_c::make(1.0, 2*M_PI, 1.0); + + d_mixer_offset = blocks::multiply_cc::make(); + + connect(self(), 0, d_timing_offset, 0); + connect(self(), 2, d_timing_offset, 1); + connect(d_timing_offset, 0, d_multipath, 0); + connect(d_multipath, 0, d_mixer_offset, 0); + + connect(self(), 1, d_freq_gen, 0); + connect(d_freq_gen, 0, d_mixer_offset, 1); + + connect(d_mixer_offset, 0, d_noise_adder, 1); + connect(d_noise, 0, d_noise_adder, 0); + connect(d_noise_adder, 0, self(), 0); + } + + channel_model2_impl::~channel_model2_impl() + { + } + + void + channel_model2_impl::set_noise_voltage(double noise_voltage) + { + d_noise->set_amplitude(noise_voltage); + } + + void + channel_model2_impl::set_taps(const std::vector<gr_complex> &taps) + { + d_taps = taps; + while(d_taps.size() < 2) { + d_taps.push_back(0); + } + d_multipath->set_taps(d_taps); + } + + void + channel_model2_impl::set_timing_offset(double epsilon) + { + d_timing_offset->set_resamp_ratio(epsilon); + } + + double + channel_model2_impl::noise_voltage() const + { + return d_noise->amplitude(); + } + + std::vector<gr_complex> + channel_model2_impl::taps() const + { + return d_multipath->taps(); + } + + double + channel_model2_impl::timing_offset() const + { + return d_timing_offset->resamp_ratio(); + } + + void + channel_model2_impl::setup_rpc() + { +#ifdef GR_CTRLPORT + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<channel_model2, double>( + alias(), "noise", + &channel_model2::noise_voltage, + pmt::mp(-10.0f), pmt::mp(10.0f), pmt::mp(0.0f), + "", "Noise Voltage", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<channel_model2, double>( + alias(), "timing", + &channel_model2::timing_offset, + pmt::mp(0.0), pmt::mp(2.0), pmt::mp(0.0), + "", "Timing Offset", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<channel_model2, std::vector<gr_complex> >( + alias(), "taps", + &channel_model2::taps, + pmt::make_c32vector(0,-10), + pmt::make_c32vector(0,10), + pmt::make_c32vector(0,0), + "", "Multipath taps", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTCPLX | DISPOPTSTRIP))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<channel_model2, double>( + alias(), "noise", + &channel_model2::set_noise_voltage, + pmt::mp(-10.0), pmt::mp(10.0), pmt::mp(0.0), + "V", "Noise Voltage", + RPC_PRIVLVL_MIN, DISPNULL))); + + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<channel_model2, double>( + alias(), "timing", + &channel_model2::set_timing_offset, + pmt::mp(0.0f), pmt::mp(2.0f), pmt::mp(0.0f), + "", "Timing Offset", + RPC_PRIVLVL_MIN, DISPNULL))); +#endif /* GR_CTRLPORT */ + } + + } /* namespace channels */ +} /* namespace gr */ diff --git a/gr-channels/lib/channel_model2_impl.h b/gr-channels/lib/channel_model2_impl.h new file mode 100644 index 0000000000..db2a667f9c --- /dev/null +++ b/gr-channels/lib/channel_model2_impl.h @@ -0,0 +1,76 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009,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. + */ + +#ifndef INCLUDED_CHANNELS_CHANNEL_MODEL2_IMPL_H +#define INCLUDED_CHANNELS_CHANNEL_MODEL2_IMPL_H + +#include <gnuradio/channels/channel_model2.h> +#include <gnuradio/top_block.h> +#include <gnuradio/blocks/add_cc.h> +#include <gnuradio/blocks/multiply_cc.h> +#include <gnuradio/analog/sig_source_c.h> +#include <gnuradio/analog/fastnoise_source_c.h> +#include <gnuradio/filter/fractional_resampler_cc.h> +#include <gnuradio/filter/fir_filter_ccc.h> +#include <gnuradio/blocks/vco_c.h> + +namespace gr { + namespace channels { + + class CHANNELS_API channel_model2_impl : public channel_model2 + { + private: + blocks::add_cc::sptr d_noise_adder; + blocks::multiply_cc::sptr d_mixer_offset; + + blocks::vco_c::sptr d_freq_gen; + + analog::fastnoise_source_c::sptr d_noise; + + filter::fractional_resampler_cc::sptr d_timing_offset; + filter::fir_filter_ccc::sptr d_multipath; + + std::vector<gr_complex> d_taps; + + public: + channel_model2_impl(double noise_voltage, + double epsilon, + const std::vector<gr_complex> &taps, + double noise_seed); + + ~channel_model2_impl(); + + void setup_rpc(); + + void set_noise_voltage(double noise_voltage); + void set_taps(const std::vector<gr_complex> &taps); + void set_timing_offset(double epsilon); + + double noise_voltage() const; + std::vector<gr_complex> taps() const; + double timing_offset() const; + }; + + } /* namespace channels */ +} /* namespace gr */ + +#endif /* INCLUDED_CHANNELS_CHANNEL_MODEL2_IMPL_H */ diff --git a/gr-channels/swig/channels_swig.i b/gr-channels/swig/channels_swig.i index fb7ada7dae..784a10a085 100644 --- a/gr-channels/swig/channels_swig.i +++ b/gr-channels/swig/channels_swig.i @@ -29,14 +29,17 @@ %{ #include "gnuradio/channels/channel_model.h" +#include "gnuradio/channels/channel_model2.h" #include "gnuradio/channels/fading_model.h" #include "gnuradio/channels/selective_fading_model.h" %} %include "gnuradio/channels/channel_model.h" +%include "gnuradio/channels/channel_model2.h" %include "gnuradio/channels/fading_model.h" %include "gnuradio/channels/selective_fading_model.h" GR_SWIG_BLOCK_MAGIC2(channels, channel_model); +GR_SWIG_BLOCK_MAGIC2(channels, channel_model2); GR_SWIG_BLOCK_MAGIC2(channels, fading_model); GR_SWIG_BLOCK_MAGIC2(channels, selective_fading_model); diff --git a/gr-filter/grc/filter_fractional_resampler_xx.xml b/gr-filter/grc/filter_fractional_resampler_xx.xml index 48d624d432..40957b889d 100644 --- a/gr-filter/grc/filter_fractional_resampler_xx.xml +++ b/gr-filter/grc/filter_fractional_resampler_xx.xml @@ -39,6 +39,11 @@ <name>in</name> <type>$type</type> </sink> + <sink> + <name>rate</name> + <type>float</type> + <optional>1</optional> + </sink> <source> <name>out</name> <type>$type</type> diff --git a/gr-filter/lib/fractional_resampler_cc_impl.cc b/gr-filter/lib/fractional_resampler_cc_impl.cc index 27f139d813..b17e13638b 100644 --- a/gr-filter/lib/fractional_resampler_cc_impl.cc +++ b/gr-filter/lib/fractional_resampler_cc_impl.cc @@ -41,8 +41,8 @@ namespace gr { fractional_resampler_cc_impl::fractional_resampler_cc_impl (float phase_shift, float resamp_ratio) : block("fractional_resampler_cc", - io_signature::make(1, 1, sizeof(gr_complex)), - io_signature::make(1, 1, sizeof(gr_complex))), + io_signature::make2(1, 2, sizeof(gr_complex), sizeof(float)), + io_signature::make(1, 1, sizeof(gr_complex))), d_mu(phase_shift), d_mu_inc(resamp_ratio), d_resamp(new mmse_fir_interpolator_cc()) { @@ -82,19 +82,38 @@ namespace gr { int ii = 0; // input index int oo = 0; // output index - while(oo < noutput_items) { - out[oo++] = d_resamp->interpolate(&in[ii], d_mu); + if(ninput_items.size() == 1) { + while(oo < noutput_items) { + out[oo++] = d_resamp->interpolate(&in[ii], d_mu); - double s = d_mu + d_mu_inc; - double f = floor(s); - int incr = (int)f; - d_mu = s - f; - ii += incr; - } + double s = d_mu + d_mu_inc; + double f = floor(s); + int incr = (int)f; + d_mu = s - f; + ii += incr; + } - consume_each(ii); + consume_each(ii); + return noutput_items; + } - return noutput_items; + else { + const float *rr = (const float*)input_items[1]; + while(oo < noutput_items) { + out[oo++] = d_resamp->interpolate(&in[ii], d_mu); + d_mu_inc = rr[ii]; + + double s = d_mu + d_mu_inc; + double f = floor(s); + int incr = (int)f; + d_mu = s - f; + ii += incr; + } + + set_relative_rate(1.0 / d_mu_inc); + consume_each(ii); + return noutput_items; + } } float diff --git a/gr-filter/lib/fractional_resampler_ff_impl.cc b/gr-filter/lib/fractional_resampler_ff_impl.cc index 61950d92c0..131ccaae4e 100644 --- a/gr-filter/lib/fractional_resampler_ff_impl.cc +++ b/gr-filter/lib/fractional_resampler_ff_impl.cc @@ -41,8 +41,8 @@ namespace gr { fractional_resampler_ff_impl::fractional_resampler_ff_impl (float phase_shift, float resamp_ratio) : block("fractional_resampler_ff", - io_signature::make(1, 1, sizeof(float)), - io_signature::make(1, 1, sizeof(float))), + io_signature::make(1, 2, sizeof(float)), + io_signature::make(1, 1, sizeof(float))), d_mu (phase_shift), d_mu_inc (resamp_ratio), d_resamp(new mmse_fir_interpolator_ff()) { @@ -82,19 +82,37 @@ namespace gr { int ii = 0; // input index int oo = 0; // output index - while(oo < noutput_items) { - out[oo++] = d_resamp->interpolate(&in[ii], d_mu); + if(ninput_items.size() == 1) { + while(oo < noutput_items) { + out[oo++] = d_resamp->interpolate(&in[ii], d_mu); - double s = d_mu + d_mu_inc; - double f = floor(s); - int incr = (int)f; - d_mu = s - f; - ii += incr; - } - - consume_each(ii); + double s = d_mu + d_mu_inc; + double f = floor(s); + int incr = (int)f; + d_mu = s - f; + ii += incr; + } - return noutput_items; + consume_each(ii); + return noutput_items; + } + else { + const float *rr = (const float*)input_items[1]; + while(oo < noutput_items) { + out[oo++] = d_resamp->interpolate(&in[ii], d_mu); + d_mu_inc = rr[ii]; + + double s = d_mu + d_mu_inc; + double f = floor(s); + int incr = (int)f; + d_mu = s - f; + ii += incr; + } + + set_relative_rate(1.0 / d_mu_inc); + consume_each(ii); + return noutput_items; + } } float diff --git a/gr-filter/python/filter/qa_fractional_resampler.py b/gr-filter/python/filter/qa_fractional_resampler.py index 220ebd9e30..ea01cf7eef 100644 --- a/gr-filter/python/filter/qa_fractional_resampler.py +++ b/gr-filter/python/filter/qa_fractional_resampler.py @@ -35,6 +35,10 @@ def sig_source_c(samp_rate, freq, amp, N): 1j*math.sin(2.*math.pi*freq*x), t) return y +def const_source_f(amp, N): + y = N*[amp,] + return y + class test_fractional_resampler(gr_unittest.TestCase): def setUp(self): @@ -68,7 +72,6 @@ class test_fractional_resampler(gr_unittest.TestCase): self.assertFloatTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3) - def test_002_cc(self): N = 10000 # number of samples to use fs = 1000 # baseband sampling rate @@ -95,6 +98,62 @@ class test_fractional_resampler(gr_unittest.TestCase): self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3) + def test_003_ff(self): + N = 10000 # number of samples to use + fs = 1000 # baseband sampling rate + rrate = 1.123 # resampling rate + + freq = 10 + data = sig_source_f(fs, freq, 1, N) + ctrl = const_source_f(rrate, N) + signal = blocks.vector_source_f(data) + control = blocks.vector_source_f(ctrl) + op = filter.fractional_resampler_ff(0, 1) + snk = blocks.vector_sink_f() + + self.tb.connect(signal, op, snk) + self.tb.connect(control, (op,1)) + self.tb.run() + + Ntest = 5000 + L = len(snk.data()) + t = map(lambda x: float(x)/(fs/rrate), xrange(L)) + + phase = 0.1884 + expected_data = map(lambda x: math.sin(2.*math.pi*freq*x+phase), t) + + dst_data = snk.data() + + self.assertFloatTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3) + + def test_004_cc(self): + N = 10000 # number of samples to use + fs = 1000 # baseband sampling rate + rrate = 1.123 # resampling rate + + freq = 10 + data = sig_source_c(fs, freq, 1, N) + ctrl = const_source_f(rrate, N) + signal = blocks.vector_source_c(data) + control = blocks.vector_source_f(ctrl) + op = filter.fractional_resampler_cc(0.0, 1) + snk = blocks.vector_sink_c() + + self.tb.connect(signal, op, snk) + self.tb.connect(control, (op,1)) + self.tb.run() + + Ntest = 5000 + L = len(snk.data()) + t = map(lambda x: float(x)/(fs/rrate), xrange(L)) + + phase = 0.1884 + expected_data = map(lambda x: math.cos(2.*math.pi*freq*x+phase) + \ + 1j*math.sin(2.*math.pi*freq*x+phase), t) + + dst_data = snk.data() + + self.assertComplexTuplesAlmostEqual(expected_data[-Ntest:], dst_data[-Ntest:], 3) if __name__ == '__main__': gr_unittest.run(test_fractional_resampler, "test_fractional_resampler.xml") |