summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rondeau <tom@trondeau.com>2013-08-27 13:44:27 -0400
committerTom Rondeau <tom@trondeau.com>2013-08-27 13:44:27 -0400
commitaf8fcd9884c19456530ff42185fc3a549098e472 (patch)
tree2d139c72758b69736395da22313b304ab33bacd9
parent584f201d23e266400111dd24657b7f63868941b8 (diff)
parent797b3b061a2ae79b51853e1b86fd9f511a8f36f4 (diff)
Merge branch 'dynamic_channel'
-rw-r--r--gnuradio-runtime/include/gnuradio/fxpt_vco.h11
-rw-r--r--gnuradio-runtime/lib/math/qa_fxpt_vco.cc20
-rw-r--r--gnuradio-runtime/lib/math/vco.h14
-rw-r--r--gr-blocks/grc/blocks_vco_c.xml35
-rw-r--r--gr-blocks/include/gnuradio/blocks/CMakeLists.txt1
-rw-r--r--gr-blocks/include/gnuradio/blocks/vco_c.h59
-rw-r--r--gr-blocks/lib/CMakeLists.txt1
-rw-r--r--gr-blocks/lib/vco_c_impl.cc68
-rw-r--r--gr-blocks/lib/vco_c_impl.h53
-rw-r--r--gr-blocks/python/blocks/qa_vco.py23
-rw-r--r--gr-blocks/swig/blocks_swig5.i3
-rw-r--r--gr-channels/grc/channels_channel_model2.xml61
-rw-r--r--gr-channels/include/gnuradio/channels/CMakeLists.txt1
-rw-r--r--gr-channels/include/gnuradio/channels/channel_model2.h102
-rw-r--r--gr-channels/lib/CMakeLists.txt1
-rw-r--r--gr-channels/lib/channel_model2_impl.cc174
-rw-r--r--gr-channels/lib/channel_model2_impl.h76
-rw-r--r--gr-channels/swig/channels_swig.i3
-rw-r--r--gr-filter/grc/filter_fractional_resampler_xx.xml5
-rw-r--r--gr-filter/lib/fractional_resampler_cc_impl.cc43
-rw-r--r--gr-filter/lib/fractional_resampler_ff_impl.cc44
-rw-r--r--gr-filter/python/filter/qa_fractional_resampler.py61
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")