From: eb Date: Wed, 27 Sep 2006 05:14:03 +0000 (+0000) Subject: Merged changes from eb/digital-wip into trunk. X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=f1c41f807cb29472d0924149e39d6ec8ad90e6a2;p=debian%2Fgnuradio Merged changes from eb/digital-wip into trunk. This includes: * renaming gnuradio-examples/python/gmsk2 to gnuradio-examples/python/digital * refactoring the digital data tx and rx test code into benchmark_tx and benchmark_rx. These accept a -m argument. can currently be selected from gmsk, dbpsk, dqpsk * Two new AGC blocks: gr_agc2: separate attack and delay rates; gr_feedforward_agc: FIR-ish compressor. Normalizes to peak envelope. * Working DBPSK mod/demod (works fine) * Working DQPSK mod/demod (works, but still needs more work) git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3662 221aa14e-8319-0410-a670-987f0aec2ac5 --- diff --git a/config/grc_gnuradio_examples.m4 b/config/grc_gnuradio_examples.m4 index 910da587..60b93bb0 100644 --- a/config/grc_gnuradio_examples.m4 +++ b/config/grc_gnuradio_examples.m4 @@ -27,8 +27,7 @@ AC_DEFUN([GRC_GNURADIO_EXAMPLES],[ gnuradio-examples/python/channel-coding/Makefile \ gnuradio-examples/python/channel-coding/fsm_files/Makefile \ gnuradio-examples/python/digital_voice/Makefile \ - gnuradio-examples/python/gmsk2/Makefile \ - gnuradio-examples/python/mc4020/Makefile \ + gnuradio-examples/python/digital/Makefile \ gnuradio-examples/python/usrp/Makefile \ gnuradio-examples/python/multi_usrp/Makefile \ ]) diff --git a/gnuradio-core/src/lib/general/Makefile.am b/gnuradio-core/src/lib/general/Makefile.am index c22d8a7c..ace399ab 100644 --- a/gnuradio-core/src/lib/general/Makefile.am +++ b/gnuradio-core/src/lib/general/Makefile.am @@ -95,6 +95,8 @@ libgeneral_la_SOURCES = \ $(GENERATED_CC) \ gr_agc_cc.cc \ gr_agc_ff.cc \ + gr_agc2_cc.cc \ + gr_agc2_ff.cc \ gr_align_on_samplenumbers_ss.cc \ gr_binary_slicer_fb.cc \ gr_bytes_to_syms.cc \ @@ -120,6 +122,7 @@ libgeneral_la_SOURCES = \ gr_diff_phasor_cc.cc \ gr_fake_channel_coder_pp.cc \ gr_fast_atan2f.cc \ + gr_feedforward_agc_cc.cc \ gr_feval.cc \ gr_fft_vcc.cc \ gr_fft_vfc.cc \ @@ -213,6 +216,8 @@ grinclude_HEADERS = \ $(GENERATED_H) \ gr_agc_cc.h \ gr_agc_ff.h \ + gr_agc2_cc.h \ + gr_agc2_ff.h \ gr_align_on_samplenumbers_ss.h \ gr_binary_slicer_fb.h \ gr_bytes_to_syms.h \ @@ -239,6 +244,7 @@ grinclude_HEADERS = \ gr_endianness.h \ gr_expj.h \ gr_fake_channel_coder_pp.h \ + gr_feedforward_agc_cc.h \ gr_feval.h \ gr_fft_vcc.h \ gr_fft_vfc.h \ @@ -315,8 +321,10 @@ grinclude_HEADERS = \ gr_vector_to_stream.h \ gr_vector_to_streams.h \ gri_add_const_ss.h \ - gri_agc.h \ gri_agc_cc.h \ + gri_agc_ff.h \ + gri_agc2_cc.h \ + gri_agc2_ff.h \ gri_char_to_float.h \ gri_debugger_hook.h \ gri_fft.h \ @@ -348,6 +356,8 @@ swiginclude_HEADERS = \ general_generated.i \ gr_agc_cc.i \ gr_agc_ff.i \ + gr_agc2_cc.i \ + gr_agc2_ff.i \ gr_align_on_samplenumbers_ss.i \ gr_binary_slicer_fb.i \ gr_bytes_to_syms.i \ @@ -371,6 +381,7 @@ swiginclude_HEADERS = \ gr_deinterleave.i \ gr_endianness.i \ gr_fake_channel_coder_pp.i \ + gr_feedforward_agc_cc.i \ gr_feval.i \ gr_fft_vcc.i \ gr_fft_vfc.i \ @@ -432,9 +443,11 @@ swiginclude_HEADERS = \ gr_vco_f.i \ gr_vector_to_stream.i \ gr_vector_to_streams.i \ - gri_agc.i \ - gri_agc_cc.i \ - gr_unpack_k_bits_bb.i + gr_unpack_k_bits_bb.i \ + gri_agc_cc.i \ + gri_agc_ff.i \ + gri_agc2_cc.i \ + gri_agc2_ff.i CLEANFILES = $(BUILT_SOURCES) *.pyc diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index 2247a3e6..691cd833 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -64,6 +64,8 @@ #include #include #include +#include +#include #include #include #include @@ -109,6 +111,7 @@ #include #include #include +#include %} %include "gr_sync_block.i" @@ -154,6 +157,8 @@ %include "gr_simple_squelch_cc.i" %include "gr_agc_ff.i" %include "gr_agc_cc.i" +%include "gr_agc2_ff.i" +%include "gr_agc2_cc.i" %include "gr_rms_cf.i" %include "gr_rms_ff.i" %include "gr_nlog10_ff.i" @@ -199,5 +204,6 @@ %include "gr_pwr_squelch_cc.i" %include "gr_pwr_squelch_ff.i" %include "gr_ctcss_squelch_ff.i" +%include "gr_feedforward_agc_cc.i" %include "general_generated.i" diff --git a/gnuradio-core/src/lib/general/gr_agc2_cc.cc b/gnuradio-core/src/lib/general/gr_agc2_cc.cc new file mode 100644 index 00000000..16bd64e3 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_agc2_cc.cc @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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 +#include +#include + +gr_agc2_cc_sptr +gr_make_agc2_cc (float attack_rate, float decay_rate, float reference, + float gain, float max_gain) +{ + return gr_agc2_cc_sptr (new gr_agc2_cc (attack_rate, decay_rate, reference, gain, max_gain)); +} + +gr_agc2_cc::gr_agc2_cc (float attack_rate, float decay_rate, float reference, + float gain, float max_gain) + : gr_sync_block ("gr_agc2_cc", + gr_make_io_signature (1, 1, sizeof (gr_complex)), + gr_make_io_signature (1, 1, sizeof (gr_complex))), + gri_agc2_cc (attack_rate, decay_rate, reference, gain, max_gain) +{ +} + +int +gr_agc2_cc::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + scaleN (out, in, noutput_items); + return noutput_items; +} diff --git a/gnuradio-core/src/lib/general/gr_agc2_cc.h b/gnuradio-core/src/lib/general/gr_agc2_cc.h new file mode 100644 index 00000000..d022b780 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_agc2_cc.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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_AGC2_CC_H +#define INCLUDED_GR_AGC2_CC_H + +#include +#include + +class gr_agc2_cc; +typedef boost::shared_ptr gr_agc2_cc_sptr; + +gr_agc2_cc_sptr +gr_make_agc2_cc (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); +/*! + * \brief high performance Automatic Gain Control class + * + * For Power the absolute value of the complex number is used. + */ + +class gr_agc2_cc : public gr_sync_block, public gri_agc2_cc +{ + friend gr_agc2_cc_sptr gr_make_agc2_cc (float attack_rate, float decay_rate, float reference, + float gain, float max_gain); + gr_agc2_cc (float attack_rate, float decay_rate, float reference, + float gain, float max_gain); + + public: + virtual int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_GR_AGC2_CC_H */ diff --git a/gnuradio-core/src/lib/general/gr_agc2_cc.i b/gnuradio-core/src/lib/general/gr_agc2_cc.i new file mode 100644 index 00000000..666738ea --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_agc2_cc.i @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,agc2_cc) + +%include + +gr_agc2_cc_sptr +gr_make_agc2_cc (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); + +class gr_agc2_cc : public gr_sync_block , public gri_agc2_cc +{ + gr_agc2_cc (float attack_rate, float decay_rate, float reference, + float gain, float max_gain); +}; diff --git a/gnuradio-core/src/lib/general/gr_agc2_ff.cc b/gnuradio-core/src/lib/general/gr_agc2_ff.cc new file mode 100644 index 00000000..23809934 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_agc2_ff.cc @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006 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 2, 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 +#include +#include + +gr_agc2_ff_sptr +gr_make_agc2_ff (float attack_rate, float decay_rate, float reference, + float gain, float max_gain) +{ + return gr_agc2_ff_sptr (new gr_agc2_ff (attack_rate, decay_rate, reference, + gain, max_gain)); +} + +gr_agc2_ff::gr_agc2_ff (float attack_rate, float decay_rate, float reference, + float gain, float max_gain) + : gr_sync_block ("gr_agc2_ff", + gr_make_io_signature (1, 1, sizeof (float)), + gr_make_io_signature (1, 1, sizeof (float))) + , gri_agc2_ff (attack_rate, decay_rate, reference, gain, max_gain) +{ +} + +int +gr_agc2_ff::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const float *in = (const float *) input_items[0]; + float *out = (float *) output_items[0]; + scaleN (out, in, noutput_items); + return noutput_items; +} diff --git a/gnuradio-core/src/lib/general/gr_agc2_ff.h b/gnuradio-core/src/lib/general/gr_agc2_ff.h new file mode 100644 index 00000000..25aa1d36 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_agc2_ff.h @@ -0,0 +1,52 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006 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 2, 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_AGC2_FF_H +#define INCLUDED_GR_AGC2_FF_H + +#include +#include +class gr_agc2_ff; +typedef boost::shared_ptr gr_agc2_ff_sptr; + +gr_agc2_ff_sptr +gr_make_agc2_ff (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); +/*! + * \brief high performance Automatic Gain Control class + * + * Power is approximated by absolute value + */ + +class gr_agc2_ff : public gr_sync_block, public gri_agc2_ff +{ + friend gr_agc2_ff_sptr gr_make_agc2_ff (float attack_rate, float decay_rate, + float reference, float gain, float max_gain); + gr_agc2_ff (float attack_rate, float decay_rate, float reference, float gain, float max_gain); + + public: + virtual int work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_GR_FLOAT_AGC2_FF_H */ diff --git a/gnuradio-core/src/lib/general/gr_agc2_ff.i b/gnuradio-core/src/lib/general/gr_agc2_ff.i new file mode 100644 index 00000000..527dc61a --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_agc2_ff.i @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,agc2_ff) + +%include + +gr_agc2_ff_sptr +gr_make_agc2_ff (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); + +class gr_agc2_ff : public gr_sync_block , public gri_agc2_ff +{ + gr_agc2_ff (float attack_rate, float decay_rate, float reference, + float gain, float max_gain); +}; diff --git a/gnuradio-core/src/lib/general/gr_agc_cc.cc b/gnuradio-core/src/lib/general/gr_agc_cc.cc index 6c6c4356..1aaa917e 100644 --- a/gnuradio-core/src/lib/general/gr_agc_cc.cc +++ b/gnuradio-core/src/lib/general/gr_agc_cc.cc @@ -29,23 +29,25 @@ #include gr_agc_cc_sptr -gr_make_agc_cc (float rate, float reference, float gain, float max_gain) +gr_make_agc_cc (float rate, float reference, + float gain, float max_gain) { return gr_agc_cc_sptr (new gr_agc_cc (rate, reference, gain, max_gain)); } -gr_agc_cc::gr_agc_cc (float rate, float reference, float gain, float max_gain) +gr_agc_cc::gr_agc_cc (float rate, float reference, + float gain, float max_gain) : gr_sync_block ("gr_agc_cc", gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (gr_complex))) - , gri_agc_cc (rate, reference, gain, max_gain) + gr_make_io_signature (1, 1, sizeof (gr_complex))), + gri_agc_cc (rate, reference, gain, max_gain) { } int gr_agc_cc::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { const gr_complex *in = (const gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; diff --git a/gnuradio-core/src/lib/general/gr_agc_cc.h b/gnuradio-core/src/lib/general/gr_agc_cc.h index 7bddd499..18145da4 100644 --- a/gnuradio-core/src/lib/general/gr_agc_cc.h +++ b/gnuradio-core/src/lib/general/gr_agc_cc.h @@ -29,7 +29,8 @@ class gr_agc_cc; typedef boost::shared_ptr gr_agc_cc_sptr; gr_agc_cc_sptr -gr_make_agc_cc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0); +gr_make_agc_cc (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); /*! * \brief high performance Automatic Gain Control class * @@ -38,8 +39,10 @@ gr_make_agc_cc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, floa class gr_agc_cc : public gr_sync_block, public gri_agc_cc { - friend gr_agc_cc_sptr gr_make_agc_cc (float rate, float reference, float gain, float max_gain); - gr_agc_cc (float rate, float reference, float gain, float max_gain); + friend gr_agc_cc_sptr gr_make_agc_cc (float rate, float reference, + float gain, float max_gain); + gr_agc_cc (float rate, float reference, + float gain, float max_gain); public: virtual int work (int noutput_items, diff --git a/gnuradio-core/src/lib/general/gr_agc_cc.i b/gnuradio-core/src/lib/general/gr_agc_cc.i index aae327d8..c936f03f 100644 --- a/gnuradio-core/src/lib/general/gr_agc_cc.i +++ b/gnuradio-core/src/lib/general/gr_agc_cc.i @@ -25,9 +25,11 @@ GR_SWIG_BLOCK_MAGIC(gr,agc_cc) %include gr_agc_cc_sptr -gr_make_agc_cc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0); +gr_make_agc_cc (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); class gr_agc_cc : public gr_sync_block , public gri_agc_cc { - gr_agc_cc (float rate, float reference, float gain, float max_gain); + gr_agc_cc (float rate, float reference, + float gain, float max_gain); }; diff --git a/gnuradio-core/src/lib/general/gr_agc_ff.cc b/gnuradio-core/src/lib/general/gr_agc_ff.cc index 0fa2bc5b..581b78c8 100644 --- a/gnuradio-core/src/lib/general/gr_agc_ff.cc +++ b/gnuradio-core/src/lib/general/gr_agc_ff.cc @@ -26,7 +26,7 @@ #include #include -#include +#include gr_agc_ff_sptr gr_make_agc_ff (float rate, float reference, float gain, float max_gain) @@ -38,7 +38,7 @@ gr_agc_ff::gr_agc_ff (float rate, float reference, float gain, float max_gain) : gr_sync_block ("gr_agc_ff", gr_make_io_signature (1, 1, sizeof (float)), gr_make_io_signature (1, 1, sizeof (float))) - , gri_agc (rate, reference, gain, max_gain) + , gri_agc_ff (rate, reference, gain, max_gain) { } diff --git a/gnuradio-core/src/lib/general/gr_agc_ff.h b/gnuradio-core/src/lib/general/gr_agc_ff.h index 8931b5af..a12026b6 100644 --- a/gnuradio-core/src/lib/general/gr_agc_ff.h +++ b/gnuradio-core/src/lib/general/gr_agc_ff.h @@ -24,21 +24,24 @@ #define INCLUDED_GR_AGC_FF_H #include -#include +#include class gr_agc_ff; typedef boost::shared_ptr gr_agc_ff_sptr; gr_agc_ff_sptr -gr_make_agc_ff (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0); +gr_make_agc_ff (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); + /*! * \brief high performance Automatic Gain Control class * * Power is approximated by absolute value */ -class gr_agc_ff : public gr_sync_block, public gri_agc +class gr_agc_ff : public gr_sync_block, public gri_agc_ff { - friend gr_agc_ff_sptr gr_make_agc_ff (float rate, float reference, float gain, float max_gain); + friend gr_agc_ff_sptr gr_make_agc_ff (float rate, float reference, + float gain, float max_gain); gr_agc_ff (float rate, float reference, float gain, float max_gain); public: diff --git a/gnuradio-core/src/lib/general/gr_agc_ff.i b/gnuradio-core/src/lib/general/gr_agc_ff.i index d3ba2828..8abea082 100644 --- a/gnuradio-core/src/lib/general/gr_agc_ff.i +++ b/gnuradio-core/src/lib/general/gr_agc_ff.i @@ -22,12 +22,13 @@ GR_SWIG_BLOCK_MAGIC(gr,agc_ff) -%include +%include gr_agc_ff_sptr -gr_make_agc_ff (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0); +gr_make_agc_ff (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); -class gr_agc_ff : public gr_sync_block , public gri_agc +class gr_agc_ff : public gr_sync_block , public gri_agc_ff { gr_agc_ff (float rate, float reference, float gain, float max_gain); }; diff --git a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc index 31338e94..88cd1407 100644 --- a/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc +++ b/gnuradio-core/src/lib/general/gr_clock_recovery_mm_cc.cc @@ -48,7 +48,7 @@ gr_clock_recovery_mm_cc::gr_clock_recovery_mm_cc (float omega, float gain_omega, float gain_mu, float omega_relative_limit) : gr_block ("clock_recovery_mm_cc", gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (gr_complex))), + gr_make_io_signature (1, 2, sizeof (gr_complex))), d_mu (mu), d_omega(omega), d_gain_omega(gain_omega), d_omega_relative_limit(omega_relative_limit), d_gain_mu(gain_mu), d_last_sample(0), d_interp(new gri_mmse_fir_interpolator_cc()), @@ -119,6 +119,9 @@ gr_clock_recovery_mm_cc::general_work (int noutput_items, { const gr_complex *in = (const gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; + gr_complex *foptr = (gr_complex *) output_items[1]; + + bool write_foptr = output_items.size() >= 2; int ii = 0; // input index int oo = 0; // output index @@ -165,6 +168,10 @@ gr_clock_recovery_mm_cc::general_work (int noutput_items, printf("%f\t%f\n", d_omega, d_mu); } + // write the error signal to the second output + if (write_foptr) + foptr[oo-1] = gr_complex(d_mu,0); + if (ii < 0) // clamp it. This should only happen with bogus input ii = 0; } diff --git a/gnuradio-core/src/lib/general/gr_costas_loop_cc.cc b/gnuradio-core/src/lib/general/gr_costas_loop_cc.cc index 1c2e4a3e..f06be47e 100644 --- a/gnuradio-core/src/lib/general/gr_costas_loop_cc.cc +++ b/gnuradio-core/src/lib/general/gr_costas_loop_cc.cc @@ -49,7 +49,7 @@ gr_costas_loop_cc::gr_costas_loop_cc (float alpha, float beta, ) throw (std::invalid_argument) : gr_sync_block ("costas_loop_cc", gr_make_io_signature (1, 1, sizeof (gr_complex)), - gr_make_io_signature (1, 1, sizeof (gr_complex))), + gr_make_io_signature (1, 2, sizeof (gr_complex))), d_alpha(alpha), d_beta(beta), d_max_freq(max_freq), d_min_freq(min_freq), d_phase(0), d_freq((max_freq+min_freq)/2), @@ -92,6 +92,9 @@ gr_costas_loop_cc::work (int noutput_items, { const gr_complex *iptr = (gr_complex *) input_items[0]; gr_complex *optr = (gr_complex *) output_items[0]; + gr_complex *foptr = (gr_complex *) output_items[1]; + + bool write_foptr = output_items.size() >= 2; float error; gr_complex nco_out; @@ -101,18 +104,28 @@ gr_costas_loop_cc::work (int noutput_items, optr[i] = iptr[i] * nco_out; error = (*this.*d_phase_detector)(optr[i]); + if (error > 1) + error = 1; + else if (error < -1) + error = -1; d_freq = d_freq + d_beta * error; d_phase = d_phase + d_freq + d_alpha * error; + while(d_phase>M_TWOPI) d_phase -= M_TWOPI; while(d_phase<-M_TWOPI) d_phase += M_TWOPI; - if (d_freq > d_max_freq) + if (d_freq > d_max_freq) d_freq = d_max_freq; else if (d_freq < d_min_freq) d_freq = d_min_freq; + + if (write_foptr){ + foptr[i] = gr_complex(d_freq,0); + //foptr[i] = gr_complex(error, 0); + } } return noutput_items; } diff --git a/gnuradio-core/src/lib/general/gr_costas_loop_cc.h b/gnuradio-core/src/lib/general/gr_costas_loop_cc.h index 46d73b81..d7d0db67 100644 --- a/gnuradio-core/src/lib/general/gr_costas_loop_cc.h +++ b/gnuradio-core/src/lib/general/gr_costas_loop_cc.h @@ -26,6 +26,7 @@ #include #include +#include class gr_costas_loop_cc; typedef boost::shared_ptr gr_costas_loop_cc_sptr; diff --git a/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.cc b/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.cc new file mode 100644 index 00000000..7d15e1d7 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.cc @@ -0,0 +1,91 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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 +#include +#include + +gr_feedforward_agc_cc_sptr +gr_make_feedforward_agc_cc(int nsamples, float reference) +{ + return gr_feedforward_agc_cc_sptr(new gr_feedforward_agc_cc (nsamples, reference)); +} + +gr_feedforward_agc_cc::gr_feedforward_agc_cc (int nsamples, float reference) + : gr_sync_block ("gr_feedforward_agc_cc", + gr_make_io_signature (1, 1, sizeof (gr_complex)), + gr_make_io_signature (1, 1, sizeof (gr_complex))), + d_nsamples(nsamples), d_reference(reference) +{ + if (nsamples < 1) + throw std::invalid_argument("gr_feedforward_agc_cc: nsamples must be >= 1"); + + set_history(nsamples); +} + +gr_feedforward_agc_cc::~gr_feedforward_agc_cc() +{ +} + +inline static float +mag_squared(gr_complex x) +{ + return x.real() * x.real() + x.imag() * x.imag(); +} + +// approximate sqrt(x^2 + y^2) +inline static float +envelope(gr_complex x) +{ + float r_abs = std::fabs(x.real()); + float i_abs = std::fabs(x.imag()); + + if (r_abs > i_abs) + return r_abs + 0.4 * i_abs; + else + return i_abs + 0.4 * r_abs; +} + +int +gr_feedforward_agc_cc::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + int nsamples = d_nsamples; + float gain; + + for (int i = 0; i < noutput_items; i++){ + //float max_env = 1e-12; // avoid divide by zero + float max_env = 1e-4; // avoid divide by zero, indirectly set max gain + for (int j = 0; j < nsamples; j++) + max_env = std::max(max_env, envelope(in[i+j])); + gain = d_reference / max_env; + out[i] = gain * in[i]; + } + return noutput_items; +} diff --git a/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.h b/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.h new file mode 100644 index 00000000..ba7c8366 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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_FEEDFORWARD_AGC_CC_H +#define INCLUDED_GR_FEEDFORWARD_AGC_CC_H + +#include + +class gr_feedforward_agc_cc; +typedef boost::shared_ptr gr_feedforward_agc_cc_sptr; + +gr_feedforward_agc_cc_sptr +gr_make_feedforward_agc_cc(int nsamples, float reference = 1.0); + +/*! + * \brief Non-causal AGC which computes required gain based on max absolute value over nsamples + */ +class gr_feedforward_agc_cc : public gr_sync_block +{ + friend gr_feedforward_agc_cc_sptr + gr_make_feedforward_agc_cc(int nsamples, float reference); + + int d_nsamples; + float d_reference; + + gr_feedforward_agc_cc(int nsamples, float reference); + + public: + ~gr_feedforward_agc_cc(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_GR_FEEDFORWARD_AGC_CC_H */ diff --git a/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.i b/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.i new file mode 100644 index 00000000..064e72e6 --- /dev/null +++ b/gnuradio-core/src/lib/general/gr_feedforward_agc_cc.i @@ -0,0 +1,34 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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. + */ + +GR_SWIG_BLOCK_MAGIC(gr,feedforward_agc_cc); + +gr_feedforward_agc_cc_sptr +gr_make_feedforward_agc_cc(int nsamples, float reference = 1.0); + +class gr_feedforward_agc_cc : public gr_sync_block +{ + gr_feedforward_agc_cc(int nsamples, float reference); + + public: + ~gr_feedforward_agc_cc(); +}; diff --git a/gnuradio-core/src/lib/general/gri_agc.h b/gnuradio-core/src/lib/general/gri_agc.h deleted file mode 100644 index aff81c35..00000000 --- a/gnuradio-core/src/lib/general/gri_agc.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2002,2006 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 2, 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 _GRI_AGC_H_ -#define _GRI_AGC_H_ - -#include - -/*! - * \brief high performance Automatic Gain Control class - * - * Power is approximated by absolute value - */ - -class gri_agc { - - public: - gri_agc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0) - : _rate(rate), _reference(reference), _gain(gain), _max_gain(max_gain) {}; - - float rate () const { return _rate; } - float reference () const { return _reference; } - float gain () const { return _gain; } - float max_gain () const { return _max_gain; } - - void set_rate (float rate) { _rate = rate; } - void set_reference (float reference) { _reference = reference; } - void set_gain (float gain) { _gain = gain; } - void set_max_gain (float max_gain) { _max_gain = max_gain; } - - float scale (float input){ - float output = input * _gain; - _gain += (_reference - fabsf (output)) * _rate; - if (_max_gain > 0.0 && _gain > _max_gain) - _gain = _max_gain; - return output; - } - - void scaleN (float output[], const float input[], unsigned n){ - for (unsigned i = 0; i < n; i++) - output[i] = scale (input[i]); - } - - protected: - float _rate; // adjustment rate - float _reference; // reference value - float _gain; // current gain - float _max_gain; // maximum gain -}; - -#endif /* _GRI_AGC_H_ */ diff --git a/gnuradio-core/src/lib/general/gri_agc.i b/gnuradio-core/src/lib/general/gri_agc.i deleted file mode 100644 index 03781388..00000000 --- a/gnuradio-core/src/lib/general/gri_agc.i +++ /dev/null @@ -1,36 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2006 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 2, 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 - -/*! - * \brief high performance Automatic Gain Control class - * - * Power is approximated by absolute value - */ - - -class gri_agc { - - public: - gri_agc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0); - }; diff --git a/gnuradio-core/src/lib/general/gri_agc2_cc.h b/gnuradio-core/src/lib/general/gri_agc2_cc.h new file mode 100644 index 00000000..a8ca699c --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_agc2_cc.h @@ -0,0 +1,91 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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 _GRI_AGC2_CC_H_ +#define _GRI_AGC2_CC_H_ + +#include + +/*! + * \brief high performance Automatic Gain Control class + * + * For Power the absolute value of the complex number is used. + */ + +class gri_agc2_cc { + + public: + gri_agc2_cc (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0) + : _attack_rate(attack_rate), _decay_rate(decay_rate), _reference(reference), + _gain(gain), _max_gain(max_gain) {}; + + float decay_rate () const { return _decay_rate; } + float attack_rate () const { return _attack_rate; } + float reference () const { return _reference; } + float gain () const { return _gain; } + float max_gain() const { return _max_gain; } + + void set_decay_rate (float rate) { _decay_rate = rate; } + void set_attack_rate (float rate) { _attack_rate = rate; } + void set_reference (float reference) { _reference = reference; } + void set_gain (float gain) { _gain = gain; } + void set_max_gain(float max_gain) { _max_gain = max_gain; } + + gr_complex scale (gr_complex input){ + gr_complex output = input * _gain; + + float tmp = -_reference + sqrt(output.real()*output.real() + + output.imag()*output.imag()); + float rate = _decay_rate; + if((tmp) > _gain) + rate = _attack_rate; + _gain -= tmp*rate; + +#if 0 + fprintf(stdout, "rate = %f\ttmp = %f\t gain = %f\n", rate, tmp, _gain); +#endif + + // Not sure about this; will blow up if _gain < 0 (happens when rates are too high), + // but is this the solution? + if (_gain < 0.0) + _gain = 10e-5; + + if (_max_gain > 0.0 && _gain > _max_gain) + _gain = _max_gain; + return output; + } + + void scaleN (gr_complex output[], const gr_complex input[], unsigned n){ + for (unsigned i = 0; i < n; i++) + output[i] = scale (input[i]); + } + + protected: + float _decay_rate; // decay rate for slow changing signals + float _attack_rate; // attack rate for fast changing signals + float _reference; // reference value + float _gain; // current gain + float _max_gain; // max allowable gain +}; + +#endif /* _GRI_AGC2_CC_H_ */ diff --git a/gnuradio-core/src/lib/general/gri_agc2_cc.i b/gnuradio-core/src/lib/general/gri_agc2_cc.i new file mode 100644 index 00000000..0257e905 --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_agc2_cc.i @@ -0,0 +1,42 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 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 2, 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 + +/*! + * \brief high performance Automatic Gain Control class with attack and decay rates + * + * For Power the absolute value of the complex number is used. + */ + + +class gri_agc2_cc { + + public: + gri_agc2_cc (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); + float decay_rate (); + float attack_rate (); + float reference (); + float gain (); + float max_gain (); + }; diff --git a/gnuradio-core/src/lib/general/gri_agc2_ff.h b/gnuradio-core/src/lib/general/gri_agc2_ff.h new file mode 100644 index 00000000..b0bff04c --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_agc2_ff.h @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2006 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 2, 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 _GRI_AGC2_FF_H_ +#define _GRI_AGC2_FF_H_ + +#include + +/*! + * \brief high performance Automatic Gain Control class with attack and decay rate + * + * Power is approximated by absolute value + */ + +class gri_agc2_ff { + + public: + gri_agc2_ff (float attack_rate = 1e-1, float decay_rate = 1e-2, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0) + : _attack_rate(attack_rate), _decay_rate(decay_rate), _reference(reference), + _gain(gain), _max_gain(max_gain) {}; + + float decay_rate () const { return _decay_rate; } + float attack_rate () const { return _attack_rate; } + float reference () const { return _reference; } + float gain () const { return _gain; } + float max_gain () const { return _max_gain; } + + void set_decay_rate (float rate) { _decay_rate = rate; } + void set_attack_rate (float rate) { _attack_rate = rate; } + void set_reference (float reference) { _reference = reference; } + void set_gain (float gain) { _gain = gain; } + void set_max_gain (float max_gain) { _max_gain = max_gain; } + + float scale (float input){ + float output = input * _gain; + + float tmp = (fabsf(output)) - _reference; + float rate = _decay_rate; + if(fabsf(tmp) > _gain) + rate = _attack_rate; + _gain -= tmp*rate; + +#if 0 + fprintf(stdout, "rate = %f\ttmp = %f\t gain = %f\n", rate, tmp, _gain); +#endif + + // Not sure about this + if (_gain < 0.0) + _gain = 10e-5; + + if (_max_gain > 0.0 && _gain > _max_gain) + _gain = _max_gain; + return output; + } + + void scaleN (float output[], const float input[], unsigned n){ + for (unsigned i = 0; i < n; i++) + output[i] = scale (input[i]); + } + + protected: + float _decay_rate; // decay rate for slow changing signals + float _attack_rate; // attack_rate for fast changing signals + float _reference; // reference value + float _gain; // current gain + float _max_gain; // maximum gain +}; + +#endif /* _GRI_AGC2_FF_H_ */ diff --git a/gnuradio-core/src/lib/general/gri_agc2_ff.i b/gnuradio-core/src/lib/general/gri_agc2_ff.i new file mode 100644 index 00000000..56bb3651 --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_agc2_ff.i @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006 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 2, 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 + +/*! + * \brief high performance Automatic Gain Control class + * + * Power is approximated by absolute value + */ + + +class gri_agc2_ff { + + public: + gri_agc2_ff (float attack_rate = 1e-1, float decay_rate = 1e-2, + float reference = 1.0, float gain = 1.0, float max_gain = 0.0); + }; diff --git a/gnuradio-core/src/lib/general/gri_agc_cc.h b/gnuradio-core/src/lib/general/gri_agc_cc.h index f68eec4c..5ebd67cc 100644 --- a/gnuradio-core/src/lib/general/gri_agc_cc.h +++ b/gnuradio-core/src/lib/general/gri_agc_cc.h @@ -20,8 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef _GRI_AGC_CC_H_ -#define _GRI_AGC_CC_H_ +#ifndef INCLUDED_GRI_AGC_CC_H +#define INCLUDED_GRI_AGC_CC_H #include @@ -34,8 +34,10 @@ class gri_agc_cc { public: - gri_agc_cc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0) - : _rate(rate), _reference(reference), _gain(gain), _max_gain(max_gain) {}; + gri_agc_cc (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0) + : _rate(rate), _reference(reference), + _gain(gain), _max_gain(max_gain) {}; float rate () const { return _rate; } float reference () const { return _reference; } @@ -46,11 +48,12 @@ class gri_agc_cc { void set_reference (float reference) { _reference = reference; } void set_gain (float gain) { _gain = gain; } void set_max_gain(float max_gain) { _max_gain = max_gain; } - + gr_complex scale (gr_complex input){ gr_complex output = input * _gain; - _gain += (_reference - sqrt(output.real()*output.real()+output.imag()*output.imag())) * _rate; //use abs or cabs to get approximation by absolute value, - //note that abs is computationally more intensive then norm for a complex number + + _gain += _rate * (_reference - sqrt(output.real()*output.real() + + output.imag()*output.imag())); if (_max_gain > 0.0 && _gain > _max_gain) _gain = _max_gain; return output; @@ -68,4 +71,4 @@ class gri_agc_cc { float _max_gain; // max allowable gain }; -#endif /* _GRI_AGC_CC_H_ */ +#endif /* INCLUDED_GRI_AGC_CC_H */ diff --git a/gnuradio-core/src/lib/general/gri_agc_cc.i b/gnuradio-core/src/lib/general/gri_agc_cc.i index 88473bc5..7e109ea5 100644 --- a/gnuradio-core/src/lib/general/gri_agc_cc.i +++ b/gnuradio-core/src/lib/general/gri_agc_cc.i @@ -32,7 +32,8 @@ class gri_agc_cc { public: - gri_agc_cc (float rate = 1e-4, float reference = 1.0, float gain = 1.0, float max_gain = 0.0); + gri_agc_cc (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); float rate (); float reference (); float gain (); diff --git a/gnuradio-core/src/lib/general/gri_agc_ff.h b/gnuradio-core/src/lib/general/gri_agc_ff.h new file mode 100644 index 00000000..cdf1b23a --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_agc_ff.h @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2006 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 2, 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_GRI_AGC_FF_H +#define INCLUDED_GRI_AGC_FF_H + +#include + +/*! + * \brief high performance Automatic Gain Control class + * + * Power is approximated by absolute value + */ + +class gri_agc_ff { + + public: + gri_agc_ff (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0) + : _rate(rate), _reference(reference), _gain(gain), _max_gain(max_gain) {}; + + float rate () const { return _rate; } + float reference () const { return _reference; } + float gain () const { return _gain; } + float max_gain () const { return _max_gain; } + + void set_rate (float rate) { _rate = rate; } + void set_reference (float reference) { _reference = reference; } + void set_gain (float gain) { _gain = gain; } + void set_max_gain (float max_gain) { _max_gain = max_gain; } + + float scale (float input){ + float output = input * _gain; + _gain += (_reference - fabsf (output)) * _rate; + if (_max_gain > 0.0 && _gain > _max_gain) + _gain = _max_gain; + return output; + } + + void scaleN (float output[], const float input[], unsigned n){ + for (unsigned i = 0; i < n; i++) + output[i] = scale (input[i]); + } + + protected: + float _rate; // adjustment rate + float _reference; // reference value + float _gain; // current gain + float _max_gain; // maximum gain +}; + +#endif /* INCLUDED_GRI_AGC_FF_H */ + diff --git a/gnuradio-core/src/lib/general/gri_agc_ff.i b/gnuradio-core/src/lib/general/gri_agc_ff.i new file mode 100644 index 00000000..20bd6c05 --- /dev/null +++ b/gnuradio-core/src/lib/general/gri_agc_ff.i @@ -0,0 +1,36 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2006 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 2, 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 + +/*! + * \brief high performance Automatic Gain Control class + * + * Power is approximated by absolute value + */ + +class gri_agc_ff { + + public: + gri_agc_ff (float rate = 1e-4, float reference = 1.0, + float gain = 1.0, float max_gain = 0.0); +}; diff --git a/gnuradio-core/src/python/gnuradio/Makefile.am b/gnuradio-core/src/python/gnuradio/Makefile.am index 05e42a73..4f8972f0 100644 --- a/gnuradio-core/src/python/gnuradio/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/Makefile.am @@ -28,6 +28,7 @@ grpython_PYTHON = \ audio.py \ eng_notation.py \ eng_option.py \ + modulation_utils.py \ packet_utils.py \ gr_unittest.py \ optfir.py \ diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am index 184aa7a2..8122bfa6 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/blksimpl/Makefile.am @@ -29,14 +29,16 @@ grblkspythondir = $(grpythondir)/blksimpl grblkspython_PYTHON = \ __init__.py \ am_demod.py \ + dbpsk.py \ + dqpsk.py \ filterbank.py \ fm_demod.py \ fm_emph.py \ - gmsk2.py \ - gmsk2_pkt.py \ + gmsk.py \ nbfm_rx.py \ nbfm_tx.py \ pkt.py \ + psk.py \ rational_resampler.py \ standard_squelch.py \ wfm_rcv.py \ diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/dbpsk.py b/gnuradio-core/src/python/gnuradio/blksimpl/dbpsk.py new file mode 100644 index 00000000..20b940bf --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/dbpsk.py @@ -0,0 +1,370 @@ +# +# Copyright 2005,2006 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 2, 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. +# + +# See gnuradio-examples/python/gmsk2 for examples + +""" +differential BPSK modulation and demodulation. +""" + +from gnuradio import gr, gru, modulation_utils +from math import pi, sqrt +import psk +import cmath +import Numeric +from pprint import pprint + +# default values (used in __init__ and add_options) +_def_samples_per_symbol = 2 +_def_excess_bw = 0.35 +_def_gray_code = True +_def_verbose = False +_def_log = False + +_def_costas_alpha = 0.05 +_def_gain_mu = 0.03 +_def_mu = 0.05 +_def_omega_relative_limit = 0.005 + + +# ///////////////////////////////////////////////////////////////////////////// +# DBPSK modulator +# ///////////////////////////////////////////////////////////////////////////// + +class dbpsk_mod(gr.hier_block): + + def __init__(self, fg, + samples_per_symbol=_def_samples_per_symbol, + excess_bw=_def_excess_bw, + gray_code=_def_gray_code, + verbose=_def_verbose, + log=_def_log): + """ + Hierarchical block for RRC-filtered differential BPSK modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + @param fg: flow graph + @type fg: flow graph + @param samples_per_symbol: samples per baud >= 2 + @type samples_per_symbol: integer + @param excess_bw: Root-raised cosine filter excess bandwidth + @type excess_bw: float + @param gray_code: Tell modulator to Gray code the bits + @type gray_code: bool + @param verbose: Print information about modulator? + @type verbose: bool + @param log: Log modulation data to files? + @type log: bool + """ + + self._fg = fg + self._samples_per_symbol = samples_per_symbol + self._excess_bw = excess_bw + self._gray_code = gray_code + + if not isinstance(self._samples_per_symbol, int) or self._samples_per_symbol < 2: + raise TypeError, ("sbp must be an integer >= 2, is %d" % self._samples_per_symbol) + + ntaps = 11 * self._samples_per_symbol + + arity = pow(2,self.bits_per_symbol()) + + # turn bytes into k-bit vectors + self.bytes2chunks = \ + gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) + + if self._gray_code: + self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity]) + else: + self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity]) + + self.diffenc = gr.diff_encoder_bb(arity) + + self.chunks2symbols = gr.chunks_to_symbols_bc(psk.constellation[arity]) + + # pulse shaping filter + self.rrc_taps = gr.firdes.root_raised_cosine( + self._samples_per_symbol, # gain (samples_per_symbol since we're + # interpolating by samples_per_symbol) + self._samples_per_symbol, # sampling rate + 1.0, # symbol rate + self._excess_bw, # excess bandwidth (roll-off factor) + ntaps) + + self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, + self.rrc_taps) + + # Connect + fg.connect(self.bytes2chunks, self.symbol_mapper, self.diffenc, + self.chunks2symbols, self.rrc_filter) + + if verbose: + self._print_verbage() + + if log: + self._setup_logging() + + # Initialize base class + gr.hier_block.__init__(self, self._fg, self.bytes2chunks, self.rrc_filter) + + def samples_per_symbol(self): + return self._samples_per_symbol + + def bits_per_symbol(self=None): # static method that's also callable on an instance + return 1 + bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM + + def add_options(parser): + """ + Adds DBPSK modulation-specific options to the standard parser + """ + parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, + help="set RRC excess bandwith factor [default=%default]") + parser.add_option("", "--no-gray-code", dest="gray_code", + action="store_false", default=True, + help="disable gray coding on modulated bits (PSK)") + add_options=staticmethod(add_options) + + def extract_kwargs_from_options(options): + """ + Given command line options, create dictionary suitable for passing to __init__ + """ + return modulation_utils.extract_kwargs_from_options(dbpsk_mod.__init__, + ('self', 'fg'), options) + extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) + + + def _print_verbage(self): + print "bits per symbol = %d" % self.bits_per_symbol() + print "Gray code = %s" % self._gray_code + print "RRC roll-off factor = %.2f" % self._excess_bw + + def _setup_logging(self): + print "Modulation logging turned on." + self._fg.connect(self.bytes2chunks, + gr.file_sink(gr.sizeof_char, "bytes2chunks.dat")) + self._fg.connect(self.symbol_mapper, + gr.file_sink(gr.sizeof_char, "graycoder.dat")) + self._fg.connect(self.diffenc, + gr.file_sink(gr.sizeof_char, "diffenc.dat")) + self._fg.connect(self.chunks2symbols, + gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat")) + self._fg.connect(self.rrc_filter, + gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat")) + + +# ///////////////////////////////////////////////////////////////////////////// +# DBPSK demodulator +# +# Differentially coherent detection of differentially encoded BPSK +# ///////////////////////////////////////////////////////////////////////////// + +class dbpsk_demod(gr.hier_block): + + def __init__(self, fg, + samples_per_symbol=_def_samples_per_symbol, + excess_bw=_def_excess_bw, + costas_alpha=_def_costas_alpha, + gain_mu=_def_gain_mu, + mu=_def_mu, + omega_relative_limit=_def_omega_relative_limit, + gray_code=_def_gray_code, + verbose=_def_verbose, + log=_def_log): + """ + Hierarchical block for RRC-filtered differential BPSK demodulation + + The input is the complex modulated signal at baseband. + The output is a stream of bits packed 1 bit per byte (LSB) + + @param fg: flow graph + @type fg: flow graph + @param samples_per_symbol: samples per symbol >= 2 + @type samples_per_symbol: float + @param excess_bw: Root-raised cosine filter excess bandwidth + @type excess_bw: float + @param costas_alpha: loop filter gain + @type costas_alphas: float + @param gain_mu: for M&M block + @type gain_mu: float + @param mu: for M&M block + @type mu: float + @param omega_relative_limit: for M&M block + @type omega_relative_limit: float + @param gray_code: Tell modulator to Gray code the bits + @type gray_code: bool + @param verbose: Print information about modulator? + @type verbose: bool + @param debug: Print modualtion data to files? + @type debug: bool + """ + + self._fg = fg + self._samples_per_symbol = samples_per_symbol + self._excess_bw = excess_bw + self._costas_alpha = costas_alpha + self._gain_mu = gain_mu + self._mu = mu + self._omega_relative_limit = omega_relative_limit + self._gray_code = gray_code + + if samples_per_symbol < 2: + raise TypeError, "samples_per_symbol must be >= 2, is %r" % (samples_per_symbol,) + + arity = pow(2,self.bits_per_symbol()) + + # Automatic gain control + scale = (1.0/16384.0) + self.pre_scaler = gr.multiply_const_cc(scale) # scale the signal from full-range to +-1 + #self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) + self.agc = gr.feedforward_agc_cc(16, 1.0) + + + # Costas loop (carrier tracking) + # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? + costas_order = 2 + beta = .25 * self._costas_alpha * self._costas_alpha + self.costas_loop = gr.costas_loop_cc(self._costas_alpha, beta, 0.002, -0.002, costas_order) + + # RRC data filter + ntaps = 11 * self._samples_per_symbol + self.rrc_taps = gr.firdes.root_raised_cosine( + 1.0, # gain + self._samples_per_symbol, # sampling rate + 1.0, # symbol rate + self._excess_bw, # excess bandwidth (roll-off factor) + ntaps) + + self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) + + # symbol clock recovery + omega = self._samples_per_symbol + gain_omega = .25 * self._gain_mu * self._gain_mu + self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, + self._mu, self._gain_mu, + self._omega_relative_limit) + + # find closest constellation point + rot = 1 + rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) + #print "rotated_const =", rotated_const + + self.diffdec = gr.diff_phasor_cc() + #self.diffdec = gr.diff_decoder_bb(arity) + + self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) + + if self._gray_code: + self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity]) + else: + self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity]) + + # unpack the k bit vector into a stream of bits + self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol()) + + if verbose: + self._print_verbage() + + if log: + self._setup_logging() + + # Connect and Initialize base class + self._fg.connect(self.pre_scaler, self.agc, self.costas_loop, + self.rrc_filter, self.clock_recovery, self.diffdec, + self.slicer, self.symbol_mapper, self.unpack) + + gr.hier_block.__init__(self, self._fg, self.pre_scaler, self.unpack) + + def samples_per_symbol(self): + return self._samples_per_symbol + + def bits_per_symbol(self=None): # staticmethod that's also callable on an instance + return 1 + bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM + + def _print_verbage(self): + print "bits per symbol = %d" % self.bits_per_symbol() + print "Gray code = %s" % self._gray_code + print "RRC roll-off factor = %.2f" % self._excess_bw + print "Costas Loop alpha = %.5f" % self._costas_alpha + print "M&M symbol sync gain = %.5f" % self._gain_mu + print "M&M symbol sync mu = %.5f" % self._mu + print "M&M omega relative limit = %.5f" % self._omega_relative_limit + + def _setup_logging(self): + print "Modulation logging turned on." + self._fg.connect(self.pre_scaler, + gr.file_sink(gr.sizeof_gr_complex, "prescaler.dat")) + self._fg.connect(self.agc, + gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) + self._fg.connect(self.costas_loop, + gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) + self._fg.connect((self.costas_loop,1), + gr.file_sink(gr.sizeof_gr_complex, "costas_error.dat")) + self._fg.connect(self.rrc_filter, + gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat")) + self._fg.connect(self.clock_recovery, + gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) + self._fg.connect((self.clock_recovery,1), + gr.file_sink(gr.sizeof_gr_complex, "clock_recovery_error.dat")) + self._fg.connect(self.diffdec, + gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat")) + self._fg.connect(self.slicer, + gr.file_sink(gr.sizeof_char, "slicer.dat")) + self._fg.connect(self.gray_decoder, + gr.file_sink(gr.sizeof_char, "gray_decoder.dat")) + self._fg.connect(self.unpack, + gr.file_sink(gr.sizeof_char, "unpack.dat")) + + def add_options(parser): + """ + Adds DBPSK demodulation-specific options to the standard parser + """ + parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, + help="set RRC excess bandwith factor [default=%default] (PSK)") + parser.add_option("", "--no-gray-code", dest="gray_code", + action="store_false", default=_def_gray_code, + help="disable gray coding on modulated bits (PSK)") + parser.add_option("", "--costas-alpha", type="float", default=None, + help="set Costas loop alpha value [default=%default] (PSK)") + parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu, + help="set M&M symbol sync loop gain mu value [default=%default] (GMSK/PSK)") + parser.add_option("", "--mu", type="float", default=_def_mu, + help="set M&M symbol sync loop mu value [default=%default] (GMSK/PSK)") + parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit, + help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)") + add_options=staticmethod(add_options) + + def extract_kwargs_from_options(options): + """ + Given command line options, create dictionary suitable for passing to __init__ + """ + return modulation_utils.extract_kwargs_from_options( + dbpsk_demod.__init__, ('self', 'fg'), options) + extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) + +# +# Add these to the mod/demod registry +# +modulation_utils.add_type_1_mod('dbpsk', dbpsk_mod) +modulation_utils.add_type_1_demod('dbpsk', dbpsk_demod) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/dqpsk.py b/gnuradio-core/src/python/gnuradio/blksimpl/dqpsk.py new file mode 100644 index 00000000..3b60f224 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/dqpsk.py @@ -0,0 +1,370 @@ +# +# Copyright 2005,2006 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 2, 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. +# + +# See gnuradio-examples/python/gmsk2 for examples + +""" +differential QPSK modulation and demodulation. +""" + +from gnuradio import gr, gru, modulation_utils +from math import pi, sqrt +import psk +import cmath +import Numeric +from pprint import pprint + +# default values (used in __init__ and add_options) +_def_samples_per_symbol = 2 +_def_excess_bw = 0.35 +_def_gray_code = True +_def_verbose = False +_def_log = False + +_def_costas_alpha = 0.10 +_def_gain_mu = 0.03 +_def_mu = 0.05 +_def_omega_relative_limit = 0.005 + + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK modulator +# ///////////////////////////////////////////////////////////////////////////// + +class dqpsk_mod(gr.hier_block): + + def __init__(self, fg, + samples_per_symbol=_def_samples_per_symbol, + excess_bw=_def_excess_bw, + gray_code=_def_gray_code, + verbose=_def_verbose, + log=_def_log): + """ + Hierarchical block for RRC-filtered QPSK modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + @param fg: flow graph + @type fg: flow graph + @param samples_per_symbol: samples per symbol >= 2 + @type samples_per_symbol: integer + @param excess_bw: Root-raised cosine filter excess bandwidth + @type excess_bw: float + @param gray_code: Tell modulator to Gray code the bits + @type gray_code: bool + @param verbose: Print information about modulator? + @type verbose: bool + @param debug: Print modualtion data to files? + @type debug: bool + """ + + self._fg = fg + self._samples_per_symbol = samples_per_symbol + self._excess_bw = excess_bw + self._gray_code = gray_code + + if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: + raise TypeError, ("sbp must be an integer >= 2, is %d" % samples_per_symbol) + + ntaps = 11 * samples_per_symbol + + arity = pow(2,self.bits_per_symbol()) + + # turn bytes into k-bit vectors + self.bytes2chunks = \ + gr.packed_to_unpacked_bb(self.bits_per_symbol(), gr.GR_MSB_FIRST) + + if self._gray_code: + self.symbol_mapper = gr.map_bb(psk.binary_to_gray[arity]) + else: + self.symbol_mapper = gr.map_bb(psk.binary_to_ungray[arity]) + + self.diffenc = gr.diff_encoder_bb(arity) + + rot = .707 + .707j + rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) + self.chunks2symbols = gr.chunks_to_symbols_bc(rotated_const) + + # pulse shaping filter + self.rrc_taps = gr.firdes.root_raised_cosine( + self._samples_per_symbol, # gain (sps since we're interpolating by sps) + self._samples_per_symbol, # sampling rate + 1.0, # symbol rate + self._excess_bw, # excess bandwidth (roll-off factor) + ntaps) + + self.rrc_filter = gr.interp_fir_filter_ccf(self._samples_per_symbol, self.rrc_taps) + + if verbose: + self._print_verbage() + + if log: + self._setup_logging() + + # Connect & Initialize base class + self._fg.connect(self.bytes2chunks, self.symbol_mapper, self.diffenc, + self.chunks2symbols, self.rrc_filter) + gr.hier_block.__init__(self, self._fg, self.bytes2chunks, self.rrc_filter) + + def samples_per_symbol(self): + return self._samples_per_symbol + + def bits_per_symbol(self=None): # staticmethod that's also callable on an instance + return 2 + bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM + + def _print_verbage(self): + print "bits per symbol = %d" % self.bits_per_symbol() + print "Gray code = %s" % self._gray_code + print "RRS roll-off factor = %f" % self._excess_bw + + def _setup_logging(self): + print "Modulation logging turned on." + self._fg.connect(self.bytes2chunks, + gr.file_sink(gr.sizeof_char, "bytes2chunks.dat")) + self._fg.connect(self.symbol_mapper, + gr.file_sink(gr.sizeof_char, "graycoder.dat")) + self._fg.connect(self.diffenc, + gr.file_sink(gr.sizeof_char, "diffenc.dat")) + self._fg.connect(self.chunks2symbols, + gr.file_sink(gr.sizeof_gr_complex, "chunks2symbols.dat")) + self._fg.connect(self.rrc_filter, + gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat")) + + def add_options(parser): + """ + Adds QPSK modulation-specific options to the standard parser + """ + parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, + help="set RRC excess bandwith factor [default=%default] (PSK)") + parser.add_option("", "--no-gray-code", dest="gray_code", + action="store_false", default=_def_gray_code, + help="disable gray coding on modulated bits (PSK)") + add_options=staticmethod(add_options) + + + def extract_kwargs_from_options(options): + """ + Given command line options, create dictionary suitable for passing to __init__ + """ + return modulation_utils.extract_kwargs_from_options(dqpsk_mod.__init__, + ('self', 'fg'), options) + extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) + + +# ///////////////////////////////////////////////////////////////////////////// +# DQPSK demodulator +# +# Differentially coherent detection of differentially encoded qpsk +# ///////////////////////////////////////////////////////////////////////////// + +class dqpsk_demod(gr.hier_block): + + def __init__(self, fg, + samples_per_symbol=_def_samples_per_symbol, + excess_bw=_def_excess_bw, + costas_alpha=_def_costas_alpha, + gain_mu=_def_gain_mu, + mu=_def_mu, + omega_relative_limit=_def_omega_relative_limit, + gray_code=_def_gray_code, + verbose=_def_verbose, + log=_def_log): + """ + Hierarchical block for RRC-filtered DQPSK demodulation + + The input is the complex modulated signal at baseband. + The output is a stream of bits packed 1 bit per byte (LSB) + + @param fg: flow graph + @type fg: flow graph + @param samples_per_symbol: samples per symbol >= 2 + @type samples_per_symbol: float + @param excess_bw: Root-raised cosine filter excess bandwidth + @type excess_bw: float + @param costas_alpha: loop filter gain + @type costas_alphas: float + @param gain_mu: for M&M block + @type gain_mu: float + @param mu: for M&M block + @type mu: float + @param omega_relative_limit: for M&M block + @type omega_relative_limit: float + @param gray_code: Tell modulator to Gray code the bits + @type gray_code: bool + @param verbose: Print information about modulator? + @type verbose: bool + @param debug: Print modualtion data to files? + @type debug: bool + """ + + self._fg = fg + self._samples_per_symbol = samples_per_symbol + self._excess_bw = excess_bw + self._costas_alpha = costas_alpha + self._gain_mu = gain_mu + self._mu = mu + self._omega_relative_limit = omega_relative_limit + self._gray_code = gray_code + + if samples_per_symbol < 2: + raise TypeError, "sbp must be >= 2, is %d" % samples_per_symbol + + arity = pow(2,self.bits_per_symbol()) + + # Automatic gain control + scale = (1.0/16384.0) + self.pre_scaler = gr.multiply_const_cc(scale) # scale the signal from full-range to +-1 + #self.agc = gr.agc2_cc(0.6e-1, 1e-3, 1, 1, 100) + self.agc = gr.feedforward_agc_cc(16, 1.0) + + # Costas loop (carrier tracking) + # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? + costas_order = 4 + beta = .25 * self._costas_alpha * self._costas_alpha + #self.costas_loop = gr.costas_loop_cc(self._costas_alpha, beta, 0.1, -0.1, costas_order) + self.costas_loop = gr.costas_loop_cc(self._costas_alpha, beta, 0.002, -0.002, costas_order) + + # RRC data filter + ntaps = 11 * samples_per_symbol + self.rrc_taps = gr.firdes.root_raised_cosine( + self._samples_per_symbol, # gain + self._samples_per_symbol, # sampling rate + 1.0, # symbol rate + self._excess_bw, # excess bandwidth (roll-off factor) + ntaps) + + self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) + + # symbol clock recovery + omega = self._samples_per_symbol + gain_omega = .25 * self._gain_mu * self._gain_mu + self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, + self._mu, self._gain_mu, + self._omega_relative_limit) + + self.diffdec = gr.diff_phasor_cc() + #self.diffdec = gr.diff_decoder_bb(arity) + + # find closest constellation point + rot = 1 + #rot = .707 + .707j + rotated_const = map(lambda pt: pt * rot, psk.constellation[arity]) + #print "rotated_const = %s" % rotated_const + + self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) + + if self._gray_code: + self.symbol_mapper = gr.map_bb(psk.gray_to_binary[arity]) + else: + self.symbol_mapper = gr.map_bb(psk.ungray_to_binary[arity]) + + + # unpack the k bit vector into a stream of bits + self.unpack = gr.unpack_k_bits_bb(self.bits_per_symbol()) + + if verbose: + self._print_verbage() + + if log: + self._setup_logging() + + # Connect & Initialize base class + self._fg.connect(self.pre_scaler, self.agc, self.costas_loop, + self.rrc_filter, self.clock_recovery, + self.diffdec, self.slicer, self.symbol_mapper, + self.unpack) + gr.hier_block.__init__(self, self._fg, self.pre_scaler, self.unpack) + + def samples_per_symbol(self): + return self._samples_per_symbol + + def bits_per_symbol(self=None): # staticmethod that's also callable on an instance + return 2 + bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. RTFM + + def _print_verbage(self): + print "bits per symbol = %d" % self.bits_per_symbol() + print "Gray code = %s" % self._gray_code + print "RRC roll-off factor = %.2f" % self._excess_bw + print "Costas Loop alpha = %.5f" % self._costas_alpha + print "M&M symbol sync gain = %.5f" % self._gain_mu + print "M&M symbol sync mu = %.5f" % self._mu + print "M&M omega relative limit = %.5f" % self._omega_relative_limit + + + def _setup_logging(self): + print "Modulation logging turned on." + self._fg.connect(self.pre_scaler, + gr.file_sink(gr.sizeof_gr_complex, "prescaler.dat")) + self._fg.connect(self.agc, + gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) + self._fg.connect(self.costas_loop, + gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) + self._fg.connect((self.costas_loop,1), + gr.file_sink(gr.sizeof_gr_complex, "costas_error.dat")) + self._fg.connect(self.rrc_filter, + gr.file_sink(gr.sizeof_gr_complex, "rrc_filter.dat")) + self._fg.connect(self.clock_recovery, + gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) + self._fg.connect((self.clock_recovery,1), + gr.file_sink(gr.sizeof_gr_complex, "clock_recovery_error.dat")) + self._fg.connect(self.diffdec, + gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat")) + self._fg.connect(self.slicer, + gr.file_sink(gr.sizeof_char, "slicer.dat")) + self._fg.connect(self.symbol_mapper, + gr.file_sink(gr.sizeof_char, "gray_decoder.dat")) + self._fg.connect(self.unpack, + gr.file_sink(gr.sizeof_char, "unpack.dat")) + + def add_options(parser): + """ + Adds modulation-specific options to the standard parser + """ + parser.add_option("", "--excess-bw", type="float", default=_def_excess_bw, + help="set RRC excess bandwith factor [default=%default] (PSK)") + parser.add_option("", "--no-gray-code", dest="gray_code", + action="store_false", default=_def_gray_code, + help="disable gray coding on modulated bits (PSK)") + parser.add_option("", "--costas-alpha", type="float", default=None, + help="set Costas loop alpha value [default=%default] (PSK)") + parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu, + help="set M&M symbol sync loop gain mu value [default=%default] (PSK)") + parser.add_option("", "--mu", type="float", default=_def_mu, + help="set M&M symbol sync loop mu value [default=%default] (PSK)") + add_options=staticmethod(add_options) + + def extract_kwargs_from_options(options): + """ + Given command line options, create dictionary suitable for passing to __init__ + """ + return modulation_utils.extract_kwargs_from_options( + dqpsk_demod.__init__, ('self', 'fg'), options) + extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) + + +# +# Add these to the mod/demod registry +# +modulation_utils.add_type_1_mod('dqpsk', dqpsk_mod) +modulation_utils.add_type_1_demod('dqpsk', dqpsk_demod) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk.py b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk.py new file mode 100644 index 00000000..098aa74b --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk.py @@ -0,0 +1,289 @@ +# +# GMSK modulation and demodulation. +# +# +# Copyright 2005,2006 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 2, 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. +# + +# See gnuradio-examples/python/gmsk2 for examples + +from gnuradio import gr +from gnuradio import modulation_utils +from math import pi +import Numeric +from pprint import pprint +import inspect + +# default values (used in __init__ and add_options) +_def_samples_per_symbol = 2 +_def_bt = 0.35 +_def_verbose = False +_def_log = False + +_def_gain_mu = 0.05 +_def_mu = 0.5 +_def_freq_error = 0.0 +_def_omega_relative_limit = 0.005 + + +# ///////////////////////////////////////////////////////////////////////////// +# GMSK modulator +# ///////////////////////////////////////////////////////////////////////////// + +class gmsk_mod(gr.hier_block): + + def __init__(self, fg, + samples_per_symbol=_def_samples_per_symbol, + bt=_def_bt, + verbose=_def_verbose, + log=_def_log): + """ + Hierarchical block for Gaussian Minimum Shift Key (GMSK) + modulation. + + The input is a byte stream (unsigned char) and the + output is the complex modulated signal at baseband. + + @param fg: flow graph + @type fg: flow graph + @param samples_per_symbol: samples per baud >= 2 + @type samples_per_symbol: integer + @param bt: Gaussian filter bandwidth * symbol time + @type bt: float + @param verbose: Print information about modulator? + @type verbose: bool + @param debug: Print modualtion data to files? + @type debug: bool + """ + + self._fg = fg + self._samples_per_symbol = samples_per_symbol + self._bt = bt + + if not isinstance(samples_per_symbol, int) or samples_per_symbol < 2: + raise TypeError, ("samples_per_symbol must be an integer >= 2, is %r" % (samples_per_symbol,)) + + ntaps = 4 * samples_per_symbol # up to 3 bits in filter at once + sensitivity = (pi / 2) / samples_per_symbol # phase change per bit = pi / 2 + + # Turn it into NRZ data. + self.nrz = gr.bytes_to_syms() + + # Form Gaussian filter + # Generate Gaussian response (Needs to be convolved with window below). + self.gaussian_taps = gr.firdes.gaussian( + 1, # gain + samples_per_symbol, # symbol_rate + bt, # bandwidth * symbol time + ntaps # number of taps + ) + + self.sqwave = (1,) * samples_per_symbol # rectangular window + self.taps = Numeric.convolve(Numeric.array(self.gaussian_taps),Numeric.array(self.sqwave)) + self.gaussian_filter = gr.interp_fir_filter_fff(samples_per_symbol, self.taps) + + # FM modulation + self.fmmod = gr.frequency_modulator_fc(sensitivity) + + if verbose: + self._print_verbage() + + if log: + self._setup_logging() + + # Connect & Initialize base class + self._fg.connect(self.nrz, self.gaussian_filter, self.fmmod) + gr.hier_block.__init__(self, self._fg, self.nrz, self.fmmod) + + def samples_per_symbol(self): + return self._samples_per_symbol + + def bits_per_symbol(self=None): # staticmethod that's also callable on an instance + return 1 + bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. + + + def _print_verbage(self): + print "bits per symbol = %d" % self.bits_per_symbol() + print "Gaussian filter bt = %.2f" % self._bt + + + def _setup_logging(self): + print "Modulation logging turned on." + self._fg.connect(self.nrz, + gr.file_sink(gr.sizeof_float, "nrz.dat")) + self._fg.connect(self.gaussian_filter, + gr.file_sink(gr.sizeof_float, "gaussian_filter.dat")) + self._fg.connect(self.fmmod, + gr.file_sink(gr.sizeof_gr_complex, "fmmod.dat")) + + + def add_options(parser): + """ + Adds GMSK modulation-specific options to the standard parser + """ + parser.add_option("", "--bt", type="float", default=_def_bt, + help="set bandwidth-time product [default=%default] (GMSK)") + add_options=staticmethod(add_options) + + + def extract_kwargs_from_options(options): + """ + Given command line options, create dictionary suitable for passing to __init__ + """ + return modulation_utils.extract_kwargs_from_options(gmsk_mod.__init__, + ('self', 'fg'), options) + extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) + + + +# ///////////////////////////////////////////////////////////////////////////// +# GMSK demodulator +# ///////////////////////////////////////////////////////////////////////////// + +class gmsk_demod(gr.hier_block): + + def __init__(self, fg, + samples_per_symbol=_def_samples_per_symbol, + gain_mu=_def_gain_mu, + mu=_def_mu, + omega_relative_limit=_def_omega_relative_limit, + freq_error=_def_freq_error, + verbose=_def_verbose, + log=_def_log): + """ + Hierarchical block for Gaussian Minimum Shift Key (GMSK) + demodulation. + + The input is the complex modulated signal at baseband. + The output is a stream of bits packed 1 bit per byte (the LSB) + + @param fg: flow graph + @type fg: flow graph + @param samples_per_symbol: samples per baud + @type samples_per_symbol: integer + @param verbose: Print information about modulator? + @type verbose: bool + @param log: Print modualtion data to files? + @type log: bool + + Clock recovery parameters. These all have reasonble defaults. + + @param gain_mu: controls rate of mu adjustment + @type gain_mu: float + @param mu: fractional delay [0.0, 1.0] + @type mu: float + @param omega_relative_limit: sets max variation in omega + @type omega_relative_limit: float, typically 0.000200 (200 ppm) + @param freq_error: bit rate error as a fraction + @param float + """ + + self._fg = fg + self._samples_per_symbol = samples_per_symbol + self._gain_mu = gain_mu + self._mu = mu + self._omega_relative_limit = omega_relative_limit + self._freq_error = freq_error + + if samples_per_symbol < 2: + raise TypeError, "samples_per_symbol >= 2, is %f" % samples_per_symbol + + self._omega = samples_per_symbol*(1+self._freq_error) + + self._gain_omega = .25 * self._gain_mu * self._gain_mu # critically damped + + # Demodulate FM + sensitivity = (pi / 2) / samples_per_symbol + self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity) + + # the clock recovery block tracks the symbol clock and resamples as needed. + # the output of the block is a stream of soft symbols (float) + self.clock_recovery = gr.clock_recovery_mm_ff(self._omega, self._gain_omega, + self._mu, self._gain_mu, + self._omega_relative_limit) + + # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample + self.slicer = gr.binary_slicer_fb() + + if verbose: + self._print_verbage() + + if log: + self._setup_logging() + + # Connect & Initialize base class + self._fg.connect(self.fmdemod, self.clock_recovery, self.slicer) + gr.hier_block.__init__(self, self._fg, self.fmdemod, self.slicer) + + def samples_per_symbol(self): + return self._samples_per_symbol + + def bits_per_symbol(self=None): # staticmethod that's also callable on an instance + return 1 + bits_per_symbol = staticmethod(bits_per_symbol) # make it a static method. + + + def _print_verbage(self): + print "bits per symbol = %d" % self.bits_per_symbol() + print "M&M clock recovery omega = %f" % self._omega + print "M&M clock recovery gain mu = %f" % self._gain_mu + print "M&M clock recovery mu = %f" % self._mu + print "M&M clock recovery omega rel. limit = %f" % self._omega_relative_limit + print "frequency error = %f" % self._freq_error + + + def _setup_logging(self): + print "Demodulation logging turned on." + self._fg.connect(self.fmdemod, + gr.file_sink(gr.sizeof_float, "fmdemod.dat")) + self._fg.connect(self.clock_recovery, + gr.file_sink(gr.sizeof_float, "clock_recovery.dat")) + self._fg.connect(self.slicer, + gr.file_sink(gr.sizeof_char, "slicer.dat")) + + def add_options(parser): + """ + Adds GMSK demodulation-specific options to the standard parser + """ + parser.add_option("", "--gain-mu", type="float", default=_def_gain_mu, + help="M&M clock recovery gain mu [default=%default] (GMSK/PSK)") + parser.add_option("", "--mu", type="float", default=_def_mu, + help="M&M clock recovery mu [default=%default] (GMSK/PSK)") + parser.add_option("", "--omega-relative-limit", type="float", default=_def_omega_relative_limit, + help="M&M clock recovery omega relative limit [default=%default] (GMSK/PSK)") + parser.add_option("", "--freq-error", type="float", default=_def_freq_error, + help="M&M clock recovery frequency error [default=%default] (GMSK)") + add_options=staticmethod(add_options) + + def extract_kwargs_from_options(options): + """ + Given command line options, create dictionary suitable for passing to __init__ + """ + return modulation_utils.extract_kwargs_from_options(gmsk_demod.__init__, + ('self', 'fg'), options) + extract_kwargs_from_options=staticmethod(extract_kwargs_from_options) + + +# +# Add these to the mod/demod registry +# +modulation_utils.add_type_1_mod('gmsk', gmsk_mod) +modulation_utils.add_type_1_demod('gmsk', gmsk_demod) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py deleted file mode 100644 index 4fc03397..00000000 --- a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2.py +++ /dev/null @@ -1,159 +0,0 @@ -# -# GMSK modulation and demodulation. -# -# -# Copyright 2005,2006 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 2, 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. -# - -# See gnuradio-examples/python/gmsk2 for examples - -from gnuradio import gr -from math import pi -import Numeric - -# ///////////////////////////////////////////////////////////////////////////// -# GMSK mod/demod with steams of bytes as data i/o -# ///////////////////////////////////////////////////////////////////////////// - -class gmsk2_mod(gr.hier_block): - - def __init__(self, fg, spb = 2, bt = 0.3): - """ - Hierarchical block for Gaussian Minimum Shift Key (GMSK) - modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: integer - @param bt: Gaussian filter bandwidth * symbol time - @type bt: float - """ - if not isinstance(spb, int) or spb < 2: - raise TypeError, "sbp must be an integer >= 2" - self.spb = spb - - ntaps = 4 * spb # up to 3 bits in filter at once - sensitivity = (pi / 2) / spb # phase change per bit = pi / 2 - - # Turn it into NRZ data. - self.nrz = gr.bytes_to_syms() - - # Form Gaussian filter - - # Generate Gaussian response (Needs to be convolved with window below). - self.gaussian_taps = gr.firdes.gaussian( - 1, # gain - spb, # symbol_rate - bt, # bandwidth * symbol time - ntaps # number of taps - ) - - self.sqwave = (1,) * spb # rectangular window - self.taps = Numeric.convolve(Numeric.array(self.gaussian_taps),Numeric.array(self.sqwave)) - self.gaussian_filter = gr.interp_fir_filter_fff(spb, self.taps) - - # FM modulation - self.fmmod = gr.frequency_modulator_fc(sensitivity) - - # Connect - fg.connect(self.nrz, self.gaussian_filter, self.fmmod) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.nrz, self.fmmod) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - -class gmsk2_demod(gr.hier_block): - - def __init__(self, fg, spb=2, omega=None, gain_mu=0.03, mu=0.5, - omega_relative_limit=0.000200, freq_error=0.0): - """ - Hierarchical block for Gaussian Minimum Shift Key (GMSK) - demodulation. - - The input is the complex modulated signal at baseband. - The output is a stream of symbols ready to be sliced at zero. - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud - @type spb: integer - - Clock recovery parameters. These all have reasonble defaults. - - @param omega: nominal relative freq (defaults to spb) - @type omega: float - @param gain_mu: controls rate of mu adjustment - @type gain_mu: float - @param mu: fractional delay [0.0, 1.0] - @type mu: float - @param omega_relative_limit: sets max variation in omega - @type omega_relative_limit: float, typically 0.000200 (200 ppm) - @param freq_error: bit rate error as a fraction - @param float - """ - if spb < 2: - raise TypeError, "sbp >= 2" - self.spb = spb - - if omega is None: - omega = spb*(1+freq_error) - - gain_omega = .25*gain_mu*gain_mu # critically damped - - # Automatic gain control - self.preamp = gr.multiply_const_cc(10e-5) - self.agc = gr.agc_cc(1e-3, 1, 1, 1000) - - # Demodulate FM - sensitivity = (pi / 2) / spb - self.fmdemod = gr.quadrature_demod_cf(1.0 / sensitivity) - - alpha = 0.0008 - - # the clock recovery block tracks the symbol clock and resamples as needed. - # the output of the block is a stream of soft symbols (float) - self.clock_recovery = gr.clock_recovery_mm_ff(omega, gain_omega, mu, gain_mu, - omega_relative_limit) - - # slice the floats at 0, outputting 1 bit (the LSB of the output byte) per sample - self.slicer = gr.binary_slicer_fb() - - fg.connect(self.preamp, self.agc, self.fmdemod, self.clock_recovery, self.slicer) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.preamp, self.slicer) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py b/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py deleted file mode 100644 index 672dbbd6..00000000 --- a/gnuradio-core/src/python/gnuradio/blksimpl/gmsk2_pkt.py +++ /dev/null @@ -1,174 +0,0 @@ -# -# Copyright 2005,2006 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 2, 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 math import pi -import Numeric - -from gnuradio import gr, packet_utils -import gnuradio.gr.gr_threading as _threading -import gmsk2 - - -def _deprecation_warning(old_name, new_name): - print '#' - print '# Warning: %s is deprecated and will be removed soon.' % (old_name,) - print '# Please use the modulation independent block, %s.' % (new_name,) - print "#" - - -# ///////////////////////////////////////////////////////////////////////////// -# GMSK mod/demod with packets as i/o -# ///////////////////////////////////////////////////////////////////////////// - -class gmsk2_mod_pkts(gr.hier_block): - """ - GSM modulator that is a GNU Radio source. - - Send packets by calling send_pkt - """ - def __init__(self, fg, access_code=None, msgq_limit=2, pad_for_usrp=True, *args, **kwargs): - """ - Hierarchical block for Gaussian Minimum Shift Key (GMSK) modulation. - - Packets to be sent are enqueued by calling send_pkt. - The output is the complex modulated signal at baseband. - - @param fg: flow graph - @type fg: flow graph - @param access_code: AKA sync vector - @type access_code: string of 1's and 0's between 1 and 64 long - @param msgq_limit: maximum number of messages in message queue - @type msgq_limit: int - @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples - - See gmsk_mod for remaining parameters - """ - _deprecation_warning('gmsk2_mod_pkts', 'mod_pkts') - - self.pad_for_usrp = pad_for_usrp - if access_code is None: - access_code = packet_utils.default_access_code - if not packet_utils.is_1_0_string(access_code): - raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) - self._access_code = access_code - - # accepts messages from the outside world - self.pkt_input = gr.message_source(gr.sizeof_char, msgq_limit) - self.gmsk_mod = gmsk2.gmsk2_mod(fg, *args, **kwargs) - fg.connect(self.pkt_input, self.gmsk_mod) - gr.hier_block.__init__(self, fg, None, self.gmsk_mod) - - def send_pkt(self, payload='', eof=False): - """ - Send the payload. - - @param payload: data to send - @type payload: string - """ - if eof: - msg = gr.message(1) # tell self.pkt_input we're not sending any more packets - else: - # print "original_payload =", string_to_hex_list(payload) - pkt = packet_utils.make_packet(payload, - self.gmsk_mod.samples_per_baud(), - self.gmsk_mod.bits_per_baud(), - self._access_code, - self.pad_for_usrp) - #print "pkt =", string_to_hex_list(pkt) - msg = gr.message_from_string(pkt) - self.pkt_input.msgq().insert_tail(msg) - - - -class gmsk2_demod_pkts(gr.hier_block): - """ - GSM demodulator that is a GNU Radio sink. - - The input is complex baseband. When packets are demodulated, they are passed to the - app via the callback. - """ - - def __init__(self, fg, access_code=None, callback=None, threshold=-1, *args, **kwargs): - """ - Hierarchical block for Gaussian Minimum Shift Key (GMSK) - demodulation. - - The input is the complex modulated signal at baseband. - Demodulated packets are sent to the handler. - - @param fg: flow graph - @type fg: flow graph - @param access_code: AKA sync vector - @type access_code: string of 1's and 0's - @param callback: function of two args: ok, payload - @type callback: ok: bool; payload: string - @param threshold: detect access_code with up to threshold bits wrong (-1 -> use default) - @type threshold: int - - See gmsk_demod for remaining parameters. - """ - - _deprecation_warning('gmsk2_demod_pkts', 'demod_pkts') - - if access_code is None: - access_code = packet_utils.default_access_code - if not packet_utils.is_1_0_string(access_code): - raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) - self._access_code = access_code - - if threshold == -1: - threshold = 12 # FIXME raise exception - - self._rcvd_pktq = gr.msg_queue() # holds packets from the PHY - self.gmsk_demod = gmsk2.gmsk2_demod(fg, *args, **kwargs) - self.correlator = gr.correlate_access_code_bb(access_code, threshold) - - self.framer_sink = gr.framer_sink_1(self._rcvd_pktq) - fg.connect(self.gmsk_demod, self.correlator, self.framer_sink) - - gr.hier_block.__init__(self, fg, self.gmsk_demod, None) - self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback) - - def carrier_sensed(self): - """ - Return True if we detect carrier. - """ - return False # FIXME - - -class _queue_watcher_thread(_threading.Thread): - def __init__(self, rcvd_pktq, callback): - _threading.Thread.__init__(self) - self.setDaemon(1) - self.rcvd_pktq = rcvd_pktq - self.callback = callback - self.keep_running = True - self.start() - - #def stop(self): - # self.keep_running = False - - def run(self): - while self.keep_running: - msg = self.rcvd_pktq.delete_head() - ok, payload = packet_utils.unmake_packet(msg.to_string()) - if self.callback: - self.callback(ok, payload) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py b/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py index 05e22c90..a1ece893 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py +++ b/gnuradio-core/src/python/gnuradio/blksimpl/pkt.py @@ -81,8 +81,8 @@ class mod_pkts(gr.hier_block): else: # print "original_payload =", string_to_hex_list(payload) pkt = packet_utils.make_packet(payload, - self._modulator.samples_per_baud(), - self._modulator.bits_per_baud(), + self._modulator.samples_per_symbol(), + self._modulator.bits_per_symbol(), self._access_code, self._pad_for_usrp) #print "pkt =", string_to_hex_list(pkt) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/psk.py b/gnuradio-core/src/python/gnuradio/blksimpl/psk.py new file mode 100644 index 00000000..fdb6c9e6 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/blksimpl/psk.py @@ -0,0 +1,67 @@ +# +# Copyright 2005,2006 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 2, 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 math import pi, sqrt +import cmath + +def make_constellation(m): + return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)] + +# Common definition of constellations for Tx and Rx +constellation = { + 2 : make_constellation(2), # BPSK + 4 : make_constellation(4), # QPSK + 8 : make_constellation(8) # 8PSK + } + +# ----------------------- +# Do Gray code +# ----------------------- +# binary to gray coding +binary_to_gray = { + 2 : (0, 1), + 4 : (0, 1, 3, 2), + 8 : (0, 1, 3, 2, 7, 6, 4, 5) + } + +# gray to binary +gray_to_binary = { + 2 : (0, 1), + 4 : (0, 1, 3, 2), + 8 : (0, 1, 3, 2, 6, 7, 5, 4) + } + +# ----------------------- +# Don't Gray code +# ----------------------- +# identity mapping +binary_to_ungray = { + 2 : (0, 1), + 4 : (0, 1, 2, 3), + 8 : (0, 1, 2, 3, 4, 5, 6, 7) + } + +# identity mapping +ungray_to_binary = { + 2 : (0, 1), + 4 : (0, 1, 2, 3), + 8 : (0, 1, 2, 3, 4, 5, 6, 7) + } diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am index 538f2717..f562cd71 100644 --- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am @@ -44,6 +44,7 @@ grgrpython_PYTHON = \ noinst_PYTHON = \ qa_add_and_friends.py \ + qa_agc.py \ qa_basic_flow_graph.py \ qa_complex_to_xxx.py \ qa_correlate_access_code.py \ diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_agc.py b/gnuradio-core/src/python/gnuradio/gr/qa_agc.py new file mode 100755 index 00000000..01159173 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/qa_agc.py @@ -0,0 +1,433 @@ +#!/usr/bin/env python +# +# Copyright 2004 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 2, 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 math + +test_output = False + +class test_sig_source (gr_unittest.TestCase): + + def setUp (self): + self.fg = gr.flow_graph () + + def tearDown (self): + self.fg = None + + + def test_001(self): + ''' Test the complex AGC loop (single rate input) ''' + fg = self.fg + + expected_result = ( + (100.000244140625+7.2191943445432116e-07j), + (72.892257690429688+52.959323883056641j), + (25.089065551757812+77.216217041015625j), + (-22.611061096191406+69.589706420898438j), + (-53.357715606689453+38.766635894775391j), + (-59.458671569824219+3.4792964243024471e-07j), + (-43.373462677001953-31.512666702270508j), + (-14.94139289855957-45.984889984130859j), + (13.478158950805664-41.48150634765625j), + (31.838506698608398-23.132022857666016j), + (35.519271850585938-3.1176801940091536e-07j), + (25.942903518676758+18.848621368408203j), + (8.9492912292480469+27.5430908203125j), + (-8.0852642059326172+24.883890151977539j), + (-19.131628036499023+13.899936676025391j), + (-21.383295059204102+3.1281737733479531e-07j), + (-15.650330543518066-11.370632171630859j), + (-5.4110145568847656-16.65339469909668j), + (4.9008159637451172-15.083160400390625j), + (11.628337860107422-8.4484796524047852j), + (13.036135673522949-2.288476110834381e-07j), + (9.5726661682128906+6.954948902130127j), + (3.3216962814331055+10.223132133483887j), + (-3.0204284191131592+9.2959251403808594j), + (-7.1977195739746094+5.2294478416442871j), + (-8.1072216033935547+1.8976157889483147e-07j), + (-5.9838657379150391-4.3475332260131836j), + (-2.0879747867584229-6.4261269569396973j), + (1.9100792407989502-5.8786196708679199j), + (4.5814824104309082-3.3286411762237549j), + (5.1967458724975586-1.3684227440080576e-07j), + (3.8647139072418213+2.8078789710998535j), + (1.3594740629196167+4.1840314865112305j), + (-1.2544282674789429+3.8607344627380371j), + (-3.0366206169128418+2.2062335014343262j), + (-3.4781389236450195+1.1194014604143376e-07j), + (-2.6133756637573242-1.8987287282943726j), + (-0.9293016791343689-2.8600969314575195j), + (0.86727333068847656-2.6691930294036865j), + (2.1243946552276611-1.5434627532958984j), + (2.4633183479309082-8.6486437567145913e-08j), + (1.8744727373123169+1.3618841171264648j), + (0.67528903484344482+2.0783262252807617j), + (-0.63866174221038818+1.965599536895752j), + (-1.5857341289520264+1.152103066444397j), + (-1.8640764951705933+7.6355092915036948e-08j), + (-1.4381576776504517-1.0448826551437378j), + (-0.52529704570770264-1.6166983842849731j), + (0.50366902351379395-1.5501341819763184j), + (1.26766037940979-0.92100900411605835j)) + + sampling_freq = 100 + src1 = gr.sig_source_c (sampling_freq, gr.GR_SIN_WAVE, + sampling_freq * 0.10, 100.0) + dst1 = gr.vector_sink_c () + head = gr.head (gr.sizeof_gr_complex, int (5*sampling_freq * 0.10)) + + agc = gr.agc_cc(1e-3, 1, 1, 1000) + + fg.connect (src1, head) + fg.connect (head, agc) + fg.connect (agc, dst1) + + if test_output == True: + fg.connect (agc, gr.file_sink(gr.sizeof_gr_complex, "test_agc_cc.dat")) + + fg.run () + dst_data = dst1.data () + self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 4) + + def test_002(self): + ''' Test the floating point AGC loop (single rate input) ''' + fg = self.fg + + expected_result = ( + 7.2191943445432116e-07, + 58.837181091308594, + 89.700050354003906, + 81.264183044433594, + 45.506141662597656, + 4.269894304798072e-07, + -42.948936462402344, + -65.50335693359375, + -59.368724822998047, + -33.261005401611328, + -4.683740257860336e-07, + 31.423542022705078, + 47.950984954833984, + 43.485683441162109, + 24.378345489501953, + 5.7254135299444897e-07, + -23.062990188598633, + -35.218441009521484, + -31.964075088500977, + -17.934831619262695, + -5.0591745548445033e-07, + 16.998210906982422, + 25.982204437255859, + 23.606258392333984, + 13.260685920715332, + 4.9936483037527069e-07, + -12.59880542755127, + -19.28221321105957, + -17.54347038269043, + -9.8700437545776367, + -4.188150626305287e-07, + 9.4074573516845703, + 14.422011375427246, + 13.145503044128418, + 7.41046142578125, + 3.8512698097292741e-07, + -7.0924453735351562, + -10.896408081054688, + -9.9552040100097656, + -5.6262712478637695, + -3.1982864356905338e-07, + 5.4131259918212891, + 8.3389215469360352, + 7.6409502029418945, + 4.3320145606994629, + 2.882407841298118e-07, + -4.194943904876709, + -6.4837145805358887, + -5.9621825218200684, + -3.3931560516357422) + + sampling_freq = 100 + src1 = gr.sig_source_f (sampling_freq, gr.GR_SIN_WAVE, + sampling_freq * 0.10, 100.0) + dst1 = gr.vector_sink_f () + head = gr.head (gr.sizeof_float, int (5*sampling_freq * 0.10)) + + agc = gr.agc_ff(1e-3, 1, 1, 1000) + + fg.connect (src1, head) + fg.connect (head, agc) + fg.connect (agc, dst1) + + if test_output == True: + fg.connect (agc, gr.file_sink(gr.sizeof_float, "test_agc_ff.dat")) + + fg.run () + dst_data = dst1.data () + self.assertFloatTuplesAlmostEqual (expected_result, dst_data, 4) + + def test_003(self): + ''' Test the complex AGC loop (attack and decay rate inputs) ''' + fg = self.fg + + expected_result = \ + ((100.000244140625+7.2191943445432116e-07j), + (0.80881959199905396+0.58764183521270752j), + (0.30894950032234192+0.95084899663925171j), + (-0.30895623564720154+0.95086973905563354j), + (-0.80887287855148315+0.58768033981323242j), + (-0.99984413385391235+5.850709250410091e-09j), + (-0.80889981985092163-0.58770018815994263j), + (-0.30897706747055054-0.95093393325805664j), + (0.30898112058639526-0.95094609260559082j), + (0.80893135070800781-0.58772283792495728j), + (0.99990922212600708-8.7766354184282136e-09j), + (0.80894720554351807+0.58773452043533325j), + (0.30899339914321899+0.95098406076431274j), + (-0.30899572372436523+0.95099133253097534j), + (-0.80896598100662231+0.58774799108505249j), + (-0.99994778633117676+1.4628290578855285e-08j), + (-0.80897533893585205-0.58775502443313599j), + (-0.30900305509567261-0.95101380348205566j), + (0.30900448560714722-0.95101797580718994j), + (0.80898630619049072-0.58776277303695679j), + (0.99997037649154663-1.7554345532744264e-08j), + (0.80899184942245483+0.58776694536209106j), + (0.30900871753692627+0.95103120803833008j), + (-0.30900952219963074+0.95103377103805542j), + (-0.8089984655380249+0.58777159452438354j), + (-0.99998390674591064+2.3406109050938539e-08j), + (-0.809001624584198-0.58777409791946411j), + (-0.30901208519935608-0.95104163885116577j), + (0.30901262164115906-0.95104306936264038j), + (0.80900543928146362-0.587776780128479j), + (0.99999171495437622-2.6332081404234486e-08j), + (0.80900734663009644+0.58777821063995361j), + (0.30901408195495605+0.95104765892028809j), + (-0.30901429057121277+0.95104855298995972j), + (-0.80900967121124268+0.58777981996536255j), + (-0.99999648332595825+3.2183805842578295e-08j), + (-0.80901080369949341-0.58778077363967896j), + (-0.30901527404785156-0.95105135440826416j), + (0.30901545286178589-0.95105189085006714j), + (0.80901217460632324-0.58778166770935059j), + (0.99999916553497314-3.5109700036173308e-08j), + (0.809012770652771+0.58778214454650879j), + (0.30901595950126648+0.9510534405708313j), + (-0.30901598930358887+0.95105385780334473j), + (-0.80901366472244263+0.58778274059295654j), + (-1.0000008344650269+4.0961388947380328e-08j), + (-0.8090139627456665-0.58778303861618042j), + (-0.30901634693145752-0.95105475187301636j), + (0.30901640653610229-0.95105493068695068j), + (0.80901449918746948-0.5877833366394043j)) + + sampling_freq = 100 + src1 = gr.sig_source_c (sampling_freq, gr.GR_SIN_WAVE, + sampling_freq * 0.10, 100) + dst1 = gr.vector_sink_c () + head = gr.head (gr.sizeof_gr_complex, int (5*sampling_freq * 0.10)) + + agc = gr.agc2_cc(1e-2, 1e-3, 1, 1, 1000) + + fg.connect (src1, head) + fg.connect (head, agc) + fg.connect (agc, dst1) + + if test_output == True: + fg.connect (agc, gr.file_sink(gr.sizeof_gr_complex, "test_agc2_cc.dat")) + + fg.run () + dst_data = dst1.data () + self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 4) + + def test_004(self): + ''' Test the floating point AGC loop (attack and decay rate inputs) ''' + fg = self.fg + + expected_result = \ + (7.2191943445432116e-07, + 58.837181091308594, + 40.194305419921875, + 2.9183335304260254, + 0.67606079578399658, + 8.6260438791896377e-09, + -1.4542514085769653, + -1.9210131168365479, + -1.0450780391693115, + -0.61939650774002075, + -1.2590258613442984e-08, + 1.4308931827545166, + 1.9054338932037354, + 1.0443156957626343, + 0.61937344074249268, + 2.0983527804219193e-08, + -1.4308838844299316, + -1.9054274559020996, + -1.0443152189254761, + -0.61937344074249268, + -2.5180233009791664e-08, + 1.4308837652206421, + 1.9054274559020996, + 1.0443154573440552, + 0.61937344074249268, + 3.3573645197293445e-08, + -1.4308838844299316, + -1.9054274559020996, + -1.0443152189254761, + -0.61937350034713745, + -3.7770352179222755e-08, + 1.4308837652206421, + 1.9054274559020996, + 1.0443154573440552, + 0.61937350034713745, + 4.6163762590367696e-08, + -1.4308838844299316, + -1.9054274559020996, + -1.0443153381347656, + -0.61937344074249268, + -5.0360466019583328e-08, + 1.4308837652206421, + 1.9054274559020996, + 1.0443155765533447, + 0.61937344074249268, + 5.8753879983441948e-08, + -1.4308837652206421, + -1.9054274559020996, + -1.0443153381347656, + -0.61937344074249268) + + sampling_freq = 100 + src1 = gr.sig_source_f (sampling_freq, gr.GR_SIN_WAVE, + sampling_freq * 0.10, 100) + dst1 = gr.vector_sink_f () + head = gr.head (gr.sizeof_float, int (5*sampling_freq * 0.10)) + + agc = gr.agc2_ff(1e-2, 1e-3, 1, 1, 1000) + + fg.connect (src1, head) + fg.connect (head, agc) + fg.connect (agc, dst1) + + if test_output == True: + fg.connect (agc, gr.file_sink(gr.sizeof_float, "test_agc2_ff.dat")) + + fg.run () + dst_data = dst1.data () + self.assertFloatTuplesAlmostEqual (expected_result, dst_data, 4) + + + def test_005(self): + ''' Test the complex AGC loop (attack and decay rate inputs) ''' + fg = self.fg + + expected_result = \ + ((100.000244140625+7.2191943445432116e-07j), + (0.80881959199905396+0.58764183521270752j), + (0.30894950032234192+0.95084899663925171j), + (-0.30895623564720154+0.95086973905563354j), + (-0.80887287855148315+0.58768033981323242j), + (-0.99984413385391235+5.850709250410091e-09j), + (-0.80889981985092163-0.58770018815994263j), + (-0.30897706747055054-0.95093393325805664j), + (0.30898112058639526-0.95094609260559082j), + (0.80893135070800781-0.58772283792495728j), + (0.99990922212600708-8.7766354184282136e-09j), + (0.80894720554351807+0.58773452043533325j), + (0.30899339914321899+0.95098406076431274j), + (-0.30899572372436523+0.95099133253097534j), + (-0.80896598100662231+0.58774799108505249j), + (-0.99994778633117676+1.4628290578855285e-08j), + (-0.80897533893585205-0.58775502443313599j), + (-0.30900305509567261-0.95101380348205566j), + (0.30900448560714722-0.95101797580718994j), + (0.80898630619049072-0.58776277303695679j), + (0.99997037649154663-1.7554345532744264e-08j), + (0.80899184942245483+0.58776694536209106j), + (0.30900871753692627+0.95103120803833008j), + (-0.30900952219963074+0.95103377103805542j), + (-0.8089984655380249+0.58777159452438354j), + (-0.99998390674591064+2.3406109050938539e-08j), + (-0.809001624584198-0.58777409791946411j), + (-0.30901208519935608-0.95104163885116577j), + (0.30901262164115906-0.95104306936264038j), + (0.80900543928146362-0.587776780128479j), + (0.99999171495437622-2.6332081404234486e-08j), + (0.80900734663009644+0.58777821063995361j), + (0.30901408195495605+0.95104765892028809j), + (-0.30901429057121277+0.95104855298995972j), + (-0.80900967121124268+0.58777981996536255j), + (-0.99999648332595825+3.2183805842578295e-08j), + (-0.80901080369949341-0.58778077363967896j), + (-0.30901527404785156-0.95105135440826416j), + (0.30901545286178589-0.95105189085006714j), + (0.80901217460632324-0.58778166770935059j), + (0.99999916553497314-3.5109700036173308e-08j), + (0.809012770652771+0.58778214454650879j), + (0.30901595950126648+0.9510534405708313j), + (-0.30901598930358887+0.95105385780334473j), + (-0.80901366472244263+0.58778274059295654j), + (-1.0000008344650269+4.0961388947380328e-08j), + (-0.8090139627456665-0.58778303861618042j), + (-0.30901634693145752-0.95105475187301636j), + (0.30901640653610229-0.95105493068695068j), + (0.80901449918746948-0.5877833366394043j)) + + sampling_freq = 100 + src1 = gr.sig_source_c (sampling_freq, gr.GR_SIN_WAVE, + sampling_freq * 0.10, 100) + dst1 = gr.vector_sink_c () + head = gr.head (gr.sizeof_gr_complex, int (5*sampling_freq * 0.10)) + + agc = gr.agc2_cc(1e-2, 1e-3, 1, 1, 1000) + + fg.connect (src1, head) + fg.connect (head, agc) + fg.connect (agc, dst1) + + if test_output == True: + fg.connect (agc, gr.file_sink(gr.sizeof_gr_complex, "test_agc2_cc.dat")) + + fg.run () + dst_data = dst1.data () + self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 4) + + + def test_100(self): # FIXME needs work + ''' Test complex feedforward agc with constant input ''' + input_data = 16*(0.0,) + 64*(1.0,) + 64*(0.0,) + expected_result = () + + src = gr.vector_source_c(input_data) + agc = gr.feedforward_agc_cc(16, 2.0) + dst = gr.vector_sink_c () + self.fg.connect (src, agc, dst) + + if test_output == True: + self.fg.connect (agc, gr.file_sink(gr.sizeof_gr_complex, "test_feedforward_cc.dat")) + + self.fg.run () + dst_data = dst.data () + #self.assertComplexTuplesAlmostEqual (expected_result, dst_data, 4) + + +if __name__ == '__main__': + gr_unittest.main () diff --git a/gnuradio-core/src/python/gnuradio/modulation_utils.py b/gnuradio-core/src/python/gnuradio/modulation_utils.py new file mode 100644 index 00000000..a8bd7189 --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/modulation_utils.py @@ -0,0 +1,81 @@ +# +# Copyright 2006 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 2, 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 this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# + +""" +Miscellaneous utilities for managing mods and demods, as well as other items +useful in dealing with generalized handling of different modulations and demods. +""" + +import inspect + + +# Type 1 modulators accept a stream of bytes on their input and produce complex baseband output +_type_1_modulators = {} + +def type_1_mods(): + return _type_1_modulators + +def add_type_1_mod(name, mod_class): + _type_1_modulators[name] = mod_class + + +# Type 1 demodulators accept complex baseband input and produce a stream of bits, packed +# 1 bit / byte as their output. Their output is completely unambiguous. There is no need +# to resolve phase or polarity ambiguities. +_type_1_demodulators = {} + +def type_1_demods(): + return _type_1_demodulators + +def add_type_1_demod(name, demod_class): + _type_1_demodulators[name] = demod_class + + +def extract_kwargs_from_options(function, excluded_args, options): + """ + Given a function, a list of excluded arguments and the result of + parsing command line options, create a dictionary of key word + arguments suitable for passing to the function. The dictionary + will be populated with key/value pairs where the keys are those + that are common to the function's argument list (minus the + excluded_args) and the attributes in options. The values are the + corresponding values from options unless that value is None. + In that case, the corresponding dictionary entry is not populated. + + (This allows different modulations that have the same parameter + names, but different default values to coexist. The downside is + that --help in the option parser will list the default as None, + but in that case the default provided in the __init__ argument + list will be used since there is no kwargs entry.) + + @param function: the function whose parameter list will be examined + @param excluded_args: function arguments that are NOT to be added to the dictionary + @type excluded_args: sequence of strings + @param options: result of command argument parsing + @type options: optparse.Values + """ + # Try this in C++ ;) + args, varargs, varkw, defaults = inspect.getargspec(function) + d = {} + for kw in [a for a in args if a not in excluded_args]: + if hasattr(options, kw): + if getattr(options, kw) is not None: + d[kw] = getattr(options, kw) + return d diff --git a/gnuradio-core/src/python/gnuradio/packet_utils.py b/gnuradio-core/src/python/gnuradio/packet_utils.py index 7d487147..1dab48ab 100644 --- a/gnuradio-core/src/python/gnuradio/packet_utils.py +++ b/gnuradio-core/src/python/gnuradio/packet_utils.py @@ -71,7 +71,8 @@ def conv_1_0_string_to_packed_binary_string(s): default_access_code = \ conv_packed_binary_string_to_1_0_string('\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC') - +preamble = \ + conv_packed_binary_string_to_1_0_string('\xAA\xAA\xAA\xAB') def is_1_0_string(s): if not isinstance(s, str): @@ -97,16 +98,17 @@ def dewhiten(s): def make_header(payload_len): return struct.pack('!HH', payload_len, payload_len) -def make_packet(payload, spb, bits_per_baud, access_code=default_access_code, pad_for_usrp=True): +def make_packet(payload, samples_per_symbol, bits_per_symbol, + access_code=default_access_code, pad_for_usrp=True): """ Build a packet, given access code and payload. - @param payload: packet payload, len [0, 4096] - @param spb: samples per baud (needed for padding calculation) - @type spb: int - @param bits_per_baud: (needed for padding calculation) - @type bits_per_baud: int - @param access_code: string of ascii 0's and 1's + @param payload: packet payload, len [0, 4096] + @param samples_per_symbol: samples per symbol (needed for padding calculation) + @type samples_per_symbol: int + @param bits_per_symbol: (needed for padding calculation) + @type bits_per_symbol: int + @param access_code: string of ascii 0's and 1's Packet will have access code at the beginning, followed by length, payload and finally CRC-32. @@ -115,6 +117,7 @@ def make_packet(payload, spb, bits_per_baud, access_code=default_access_code, pa raise ValueError, "access_code must be a string containing only 0's and 1's (%r)" % (access_code,) (packed_access_code, padded) = conv_1_0_string_to_packed_binary_string(access_code) + (packed_preamble, ignore) = conv_1_0_string_to_packed_binary_string(preamble) payload_with_crc = gru.gen_and_append_crc32(payload) #print "outbound crc =", string_to_hex_list(payload_with_crc[-4:]) @@ -124,14 +127,14 @@ def make_packet(payload, spb, bits_per_baud, access_code=default_access_code, pa if L > MAXLEN: raise ValueError, "len(payload) must be in [0, %d]" % (MAXLEN,) - pkt = ''.join((packed_access_code, make_header(L), whiten(payload_with_crc), '\x55')) + pkt = ''.join((packed_preamble, packed_access_code, make_header(L), whiten(payload_with_crc), '\x55')) if pad_for_usrp: - pkt = pkt + (_npadding_bytes(len(pkt), spb, bits_per_baud) * '\x55') + pkt = pkt + (_npadding_bytes(len(pkt), samples_per_symbol, bits_per_symbol) * '\x55') #print "make_packet: len(pkt) =", len(pkt) return pkt -def _npadding_bytes(pkt_byte_len, spb, bits_per_baud): +def _npadding_bytes(pkt_byte_len, samples_per_symbol, bits_per_symbol): """ Generate sufficient padding such that each packet ultimately ends up being a multiple of 512 bytes when sent across the USB. We @@ -140,13 +143,13 @@ def _npadding_bytes(pkt_byte_len, spb, bits_per_baud): is a multiple of 128 samples. @param ptk_byte_len: len in bytes of packet, not including padding. - @param spb: samples per baud == samples per bit (1 bit / baud with GMSK) - @type spb: int + @param samples_per_symbol: samples per bit (1 bit / symbolwith GMSK) + @type samples_per_symbol: int @returns number of bytes of padding to append. """ modulus = 128 - byte_modulus = gru.lcm(modulus/8, spb) * bits_per_baud / spb + byte_modulus = gru.lcm(modulus/8, samples_per_symbol) * bits_per_symbol / samples_per_symbol r = pkt_byte_len % byte_modulus if r == 0: return 0 diff --git a/gnuradio-examples/python/Makefile.am b/gnuradio-examples/python/Makefile.am index f548eff3..49d2ba3a 100644 --- a/gnuradio-examples/python/Makefile.am +++ b/gnuradio-examples/python/Makefile.am @@ -19,4 +19,4 @@ # Boston, MA 02110-1301, USA. # -SUBDIRS = audio channel-coding digital_voice gmsk2 mc4020 multi_usrp usrp +SUBDIRS = audio channel-coding digital_voice digital multi_usrp usrp diff --git a/gnuradio-examples/python/digital/Makefile.am b/gnuradio-examples/python/digital/Makefile.am new file mode 100644 index 00000000..ad2fa4d6 --- /dev/null +++ b/gnuradio-examples/python/digital/Makefile.am @@ -0,0 +1,33 @@ +# +# Copyright 2004 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 2, 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. +# + +EXTRA_DIST = \ + README \ + benchmark_rx.py \ + benchmark_tx.py \ + fusb_options.py \ + gen_whitener.py \ + pick_bitrate.py \ + receive_path.py \ + rx_voice.py \ + transmit_path.py \ + tunnel.py \ + tx_voice.py diff --git a/gnuradio-examples/python/digital/README b/gnuradio-examples/python/digital/README new file mode 100644 index 00000000..adc3fe07 --- /dev/null +++ b/gnuradio-examples/python/digital/README @@ -0,0 +1,77 @@ +Quick overview of what's here: + +* benchmark_tx.py: generates packets of the size you +specify and sends them across the air using the USRP. Known to work +well using the USRP with the RFX transceiver daughterboards. +You can specify the bitrate to use with the -r command line +parameter. The default is 500k. Some machines will do 1M or more. +You can select the modulation to use with the -m command +line argument. The legal values for are gmsk, dbpsk and dqpsk. + +* benchmark_tx.py: the receiver half of benchmark_tx.py. +Command line arguments are pretty much the same as rx. Works well +with a USRP and RFX transceiver daughterboards. Will also work +with TVRX daugherboard, but you'll need to fiddle with the gain. See +below. Prints a summary of each packet received and keeps a running +total of packets received, and how many of them were error free. +There are two levels of error reporting going on. If the access code +(PN code) and header of a packet were properly detected, then you'll +get an output line. If the CRC32 of the payload was correct you get +"ok = True", else "ok = False". The "pktno" is extracted from the +received packet. If there are skipped numbers, you're missing some +packets. Be sure you've got a suitable antenna connected to the TX/RX +port on each board. For the RFX-400, "70 cm" / 420 MHz antennas for ham +handi-talkies work great. These are available at ham radio supplies, +etc. The boards need to be at least 3m apart. You can also try +experimenting with the rx gain (-g command line option). + +Generally speaking, I start the rx first on one machine, and then fire +up the tx on the other machine. The tx also supports a discontinous +transmission mode where it sends bursts of 5 packets and then waits 1 +second. This is useful for ensuring that all the receiver control +loops lock up fast enough. + +* tunnel.py: This program provides a framework for building your own +MACs. It creates a "TAP" interface in the kernel, typically gr0, +and sends and receives ethernet frames through it. See +/usr/src/linux/Documentation/networking/tuntap.txt and/or Google for +"universal tun tap". The Linux 2.6 kernel includes the tun module, you +don't have to build it. You may have to "modprobe tun" if it's not +loaded by default. If /dev/net/tun doesn't exist, try "modprobe tun". + +To run this program you'll need to be root or running with the +appropriate capability to open the tun interface. You'll need to fire +up two copies on different machines. Once each is running you'll need +to ifconfig the gr0 interface to set the IP address. + +This will allow two machines to talk, but anything beyond the two +machines depends on your networking setup. Left as an exercise... + +On machine A: + + $ su + # ./tunnel.py --freq 423.0M --bitrate 500k + # # in another window on A, also as root... + # ifconfig gr0 192.168.200.1 + + +On machine B: + + $ su + # ./tunnel.py --freq 423.0M --bitrate 500k + # # in another window on B, also as root... + # ifconfig gr0 192.168.200.2 + +Now, on machine A you shold be able to ping machine B: + + $ ping 192.168.200.2 + +and you should see some output for each packet in the +tunnel.py window if you used the -v option. + +Likewise, on machine B: + + $ ping 192.168.200.1 + +This now uses a carrier sense MAC, so you should be able to ssh +between the machines, web browse, etc. diff --git a/gnuradio-examples/python/digital/benchmark_rx.py b/gnuradio-examples/python/digital/benchmark_rx.py new file mode 100755 index 00000000..26ccdac4 --- /dev/null +++ b/gnuradio-examples/python/digital/benchmark_rx.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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, gru, modulation_utils +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import struct +import sys + +# from current dir +from receive_path import receive_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter: ') + + +class my_graph(gr.flow_graph): + + def __init__(self, demod_class, rx_callback, options): + gr.flow_graph.__init__(self) + self.rxpath = receive_path(self, demod_class, rx_callback, options) + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +global n_rcvd, n_right + +def main(): + global n_rcvd, n_right + + n_rcvd = 0 + n_right = 0 + + def rx_callback(ok, payload): + global n_rcvd, n_right + (pktno,) = struct.unpack('!H', payload[0:2]) + n_rcvd += 1 + if ok: + n_right += 1 + + print "ok = %5s pktno = %4d n_rcvd = %4d n_right = %4d" % ( + ok, pktno, n_rcvd, n_right) + + + demods = modulation_utils.type_1_demods() + + # Create Options Parser: + parser = OptionParser (option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), + default='gmsk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(demods.keys()),)) + + receive_path.add_options(parser, expert_grp) + + for mod in demods.values(): + mod.add_options(expert_grp) + + fusb_options.add_options(expert_grp) + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help(sys.stderr) + sys.exit(1) + + if options.rx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + + # build the graph + fg = my_graph(demods[options.modulation], rx_callback, options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: Failed to enable realtime scheduling." + + fg.start() # start flow graph + fg.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/benchmark_tx.py b/gnuradio-examples/python/digital/benchmark_tx.py new file mode 100755 index 00000000..55f30932 --- /dev/null +++ b/gnuradio-examples/python/digital/benchmark_tx.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# +# Copyright 2005, 2006 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 2, 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, gru, modulation_utils +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random, time, struct, sys + +# from current dir +from transmit_path import transmit_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + + +class my_graph(gr.flow_graph): + def __init__(self, modulator_class, options): + gr.flow_graph.__init__(self) + self.txpath = transmit_path(self, modulator_class, options) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + def send_pkt(payload='', eof=False): + return fg.txpath.send_pkt(payload, eof) + + def rx_callback(ok, payload): + print "ok = %r, payload = '%s'" % (ok, payload) + + mods = modulation_utils.type_1_mods() + + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), + default='gmsk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(mods.keys()),)) + + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, + help="set megabytes to transmit [default=%default]") + parser.add_option("","--discontinuous", action="store_true", default=False, + help="enable discontinous transmission (bursts of 5 packets)") + + transmit_path.add_options(parser, expert_grp) + + for mod in mods.values(): + mod.add_options(expert_grp) + + fusb_options.add_options(expert_grp) + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.tx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + # build the graph + fg = my_graph(mods[options.modulation], options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: failed to enable realtime scheduling" + + fg.start() # start flow graph + + + # generate and send packets + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + pkt_size = int(options.size) + + while n < nbytes: + send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) + n += pkt_size + sys.stderr.write('.') + if options.discontinuous and pktno % 5 == 4: + time.sleep(1) + pktno += 1 + + send_pkt(eof=True) + fg.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/fusb_options.py b/gnuradio-examples/python/digital/fusb_options.py new file mode 100644 index 00000000..cdb15d72 --- /dev/null +++ b/gnuradio-examples/python/digital/fusb_options.py @@ -0,0 +1,31 @@ +# +# Copyright 2006 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 2, 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. +# + +def add_options(parser): + """ + Add Fast USB specifc options to command line parser. + + @param parser: instance of OptionParser + """ + parser.add_option("-B", "--fusb-block-size", type="int", default=0, + help="specify fast usb block size [default=%default]") + parser.add_option("-N", "--fusb-nblocks", type="int", default=0, + help="specify number of fast usb blocks [default=%default]") diff --git a/gnuradio-examples/python/digital/gen_whitener.py b/gnuradio-examples/python/digital/gen_whitener.py new file mode 100755 index 00000000..93aea2b8 --- /dev/null +++ b/gnuradio-examples/python/digital/gen_whitener.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +from gnuradio import gr, gru +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import sys + +class my_graph(gr.flow_graph): + + def __init__(self): + gr.flow_graph.__init__(self) + + parser = OptionParser(option_class=eng_option) + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help() + raise SystemExit, 1 + + src = gr.lfsr_32k_source_s() + head = gr.head(gr.sizeof_short, 2048) + self.dst = gr.vector_sink_s() + self.connect(src, head, self.dst) + +if __name__ == '__main__': + try: + fg = my_graph() + fg.run() + f = sys.stdout + i = 0 + for s in fg.dst.data(): + f.write("%3d, " % (s & 0xff,)) + f.write("%3d, " % ((s >> 8) & 0xff,)) + i = i+2 + if i % 16 == 0: + f.write('\n') + + except KeyboardInterrupt: + pass + + diff --git a/gnuradio-examples/python/digital/limbo/README b/gnuradio-examples/python/digital/limbo/README new file mode 100644 index 00000000..fe48f435 --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/README @@ -0,0 +1,12 @@ +Files in here are in various states of disrepair and/or have been +superceded by revised code in the directory above. + +They're here until we figure out what to do with them. + + +* gmsk_test.py: stand-alone program that exercises the GMSK packet tx +and rx code. The two halves are connected with a simulated noisy +channel. It's easy to add extra instrumentation to log various internal +states. We used a variant of this code to get this working in the +first place. + diff --git a/gnuradio-examples/python/digital/limbo/benchmark_gmsk_rx.py b/gnuradio-examples/python/digital/limbo/benchmark_gmsk_rx.py new file mode 100755 index 00000000..0e072d0f --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/benchmark_gmsk_rx.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# +# Copyright 2005 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 2, 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, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import struct + +# from current dir +from receive_path import receive_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + + +class my_graph(gr.flow_graph): + + def __init__(self, demod_class, rx_subdev_spec, + bitrate, decim_rate, spb, + rx_callback, options, demod_kwargs): + gr.flow_graph.__init__(self) + self.rxpath = receive_path(self, demod_class, rx_subdev_spec, + bitrate, decim_rate, spb, + rx_callback, options, demod_kwargs) + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +global n_rcvd, n_right + +def main(): + global n_rcvd, n_right + + n_rcvd = 0 + n_right = 0 + + def rx_callback(ok, payload): + global n_rcvd, n_right + (pktno,) = struct.unpack('!H', payload[0:2]) + n_rcvd += 1 + if ok: + n_right += 1 + + print "ok = %r pktno = %4d n_rcvd = %4d n_right = %4d" % ( + ok, pktno, n_rcvd, n_right) + + parser = OptionParser (option_class=eng_option) + parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B") + parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, + help="set Rx frequency to FREQ [default=%default]", + metavar="FREQ") + parser.add_option("-r", "--bitrate", type="eng_float", default=None, + help="specify bitrate. spb and interp will be derived.") + parser.add_option("-g", "--rx-gain", type="eng_float", default=27, + help="set rx gain") + parser.add_option("-S", "--spb", type="int", default=None, + help="set samples/baud [default=%default]") + parser.add_option("-d", "--decim", type="intx", default=None, + help="set fpga decim rate to DECIM [default=%default]") + fusb_options.add_options(parser) + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.freq < 1e6: + options.freq *= 1e6 + + demod_kwargs = { } # placeholder + + # build the graph + fg = my_graph(blks.gmsk_demod, + options.rx_subdev_spec, options.bitrate, + options.decim, options.spb, rx_callback, + options, demod_kwargs) + + print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),) + print "spb: %3d" % (fg.rxpath.spb(),) + print "decim: %3d" % (fg.rxpath.decim(),) + + ok = fg.rxpath.set_freq(options.freq) + if not ok: + print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.freq),) + raise SystemExit + + fg.rxpath.set_gain(options.rx_gain) + print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", fg.rxpath.gain + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: Failed to enable realtime scheduling." + + fg.start() # start flow graph + fg.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/limbo/benchmark_gmsk_tx.py b/gnuradio-examples/python/digital/limbo/benchmark_gmsk_tx.py new file mode 100755 index 00000000..ec78d24b --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/benchmark_gmsk_tx.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import time +import struct +import sys + +# from current dir +from transmit_path import transmit_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + +class my_graph(gr.flow_graph): + + def __init__(self, options, mod_kwargs): + gr.flow_graph.__init__(self) + self.txpath = transmit_path(self, options, mod_kwargs) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + def send_pkt(payload='', eof=False): + return fg.txpath.send_pkt(payload, eof) + + def rx_callback(ok, payload): + print "ok = %r, payload = '%s'" % (ok, payload) + + parser = OptionParser (option_class=eng_option) + parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, + help="select USRP Tx side A or B") + parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, + help="set Tx and Rx frequency to FREQ [default=%default]", + metavar="FREQ") + parser.add_option("-r", "--bitrate", type="eng_float", default=None, + help="specify bitrate. spb and interp will be derived.") + parser.add_option("-S", "--spb", type="int", default=2, + help="set samples/baud [default=%default]") + parser.add_option("-i", "--interp", type="intx", default=None, + help="set fpga interpolation rate to INTERP [default=%default]") + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("", "--bt", type="float", default=0.3, + help="set bandwidth-time product [default=%default]") + parser.add_option("-g", "--gain", type="eng_float", default=100.0, + help="transmitter gain [default=%default]") + parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, + help="set megabytes to transmit [default=%default]") + parser.add_option("","--discontinuous", action="store_true", default=False, + help="enable discontinous transmission (bursts of 5 packets)") + fusb_options.add_options(parser) + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.freq < 1e6: + options.freq *= 1e6 + + pkt_size = int(options.size) + + # Add gmsk_mod modulator class to options list + options.modulation = getattr(blks, "gmsk_mod") + + # Add GMSK modulator's properties + mod_kwargs = { + 'spb': options.spb, + 'bt' : options.bt, + 'verbose' : False, + 'debug' : False, + } + + # build the graph + fg = my_graph(options, mod_kwargs) + + print "bitrate: %sbps" % (eng_notation.num_to_str(fg.txpath.bitrate()),) + print "spb: %3d" % (fg.txpath.spb(),) + print "interp: %3d" % (fg.txpath.interp(),) + + ok = fg.txpath.set_freq(options.freq) + if not ok: + print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(options.freq),) + raise SystemExit + else: + print "Transmitting on frequency %s" % (eng_notation.num_to_str(options.freq)) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: failed to enable realtime scheduling" + else: + print "Started realtime scheduling" + + fg.start() # start flow graph + + # generate and send packets + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + + while n < nbytes: + send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) + n += pkt_size + sys.stderr.write('.') + if options.discontinuous and pktno % 5 == 4: + time.sleep(1) + pktno += 1 + + send_pkt(eof=True) + fg.wait() # wait for it to finish + fg.txpath.set_auto_tr(False) + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/limbo/benchmark_mpsk_rx.py b/gnuradio-examples/python/digital/limbo/benchmark_mpsk_rx.py new file mode 100755 index 00000000..9bb70106 --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/benchmark_mpsk_rx.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Copyright 2006 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 2, 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, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import struct + +# from current dir +from bpsk import bpsk_demod +from dbpsk import dbpsk_demod +from dqpsk import dqpsk_demod +from receive_path import receive_path +import fusb_options + +if 1: + import os + print os.getpid() + raw_input('Attach and press enter') + + +class my_graph(gr.flow_graph): + + def __init__(self, demod_class, rx_subdev_spec, + bitrate, decim_rate, spb, + rx_callback, options, demod_kwargs): + gr.flow_graph.__init__(self) + self.rxpath = receive_path(self, demod_class, rx_subdev_spec, + bitrate, decim_rate, spb, + rx_callback, options, demod_kwargs) + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +global n_rcvd, n_right + +def main(): + global n_rcvd, n_right + + n_rcvd = 0 + n_right = 0 + + def rx_callback(ok, payload): + global n_rcvd, n_right + (pktno,) = struct.unpack('!H', payload[0:2]) + n_rcvd += 1 + if ok: + n_right += 1 + + print "ok = %r pktno = %4d n_rcvd = %4d n_right = %4d" % ( + ok, pktno, n_rcvd, n_right) + + parser = OptionParser (option_class=eng_option) + parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B") + parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, + help="set Rx frequency to FREQ [default=%default]", + metavar="FREQ") + parser.add_option("-r", "--bitrate", type="eng_float", default=None, + help="specify bitrate. spb and interp will be derived.") + parser.add_option("-S", "--spb", type="int", default=None, + help="set samples/baud [default=%default]") + parser.add_option("-d", "--decim", type="intx", default=None, + help="set fpga decim rate to DECIM [default=%default]") + parser.add_option("-m", "--modulation", type="string", default='dbpsk', + help="modulation type (bpsk, dbpsk, dqpsk) [default=%default]") + parser.add_option("", "--excess-bw", type="float", default=0.3, + help="set RRC excess bandwith factor [default=%default]") + parser.add_option("-g", "--gain", type="eng_float", default=27, + help="set rx gain") + parser.add_option("","--log", action="store_true", default=False, + help="enable diagnostic logging") + fusb_options.add_options(parser) + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.freq < 1e6: + options.freq *= 1e6 + + demod_kwargs = { + 'excess_bw' : options.excess_bw, + } + + #FIXME: Needs to be worked in to overall structure; this will be fixed + # once static class definitions for modulations are defined + if(options.modulation=='bpsk'): + modulation=bpsk_demod + elif(options.modulation=='dbpsk'): + modulation=dbpsk_demod + else: + modulation=dqpsk_demod + + # build the graph + fg = my_graph(modulation, + options.rx_subdev_spec, options.bitrate, + options.decim, options.spb, + rx_callback, options, demod_kwargs) + + print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),) + print "spb: %3d" % (fg.rxpath.spb(),) + print "decim: %3d" % (fg.rxpath.decim(),) + + ok = fg.rxpath.set_freq(options.freq) + if not ok: + print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.freq),) + raise SystemExit + + fg.rxpath.set_gain(options.gain) + print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", fg.rxpath.gain + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: Failed to enable realtime scheduling." + + fg.start() # start flow graph + fg.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/limbo/benchmark_mpsk_tx.py b/gnuradio-examples/python/digital/limbo/benchmark_mpsk_tx.py new file mode 100755 index 00000000..ec08fb68 --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/benchmark_mpsk_tx.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# +# Copyright 2005, 2006 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 2, 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, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random, time, struct, sys + +# from current dir +from transmit_path import transmit_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + + +class my_graph(gr.flow_graph): + + def __init__(self, options, mod_kwargs): + gr.flow_graph.__init__(self) + self.txpath = transmit_path(self, options, mod_kwargs) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + def send_pkt(payload='', eof=False): + return fg.txpath.send_pkt(payload, eof) + + def rx_callback(ok, payload): + print "ok = %r, payload = '%s'" % (ok, payload) + + parser = OptionParser (option_class=eng_option) + parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, + help="select USRP Tx side A or B") + parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, + help="set Tx and Rx frequency to FREQ [default=%default]", + metavar="FREQ") + parser.add_option("-r", "--bitrate", type="eng_float", default=None, + help="specify bitrate. spb and interp will be derived.") + parser.add_option("-S", "--spb", type="int", default=2, + help="set samples/baud [default=%default]") + parser.add_option("-i", "--interp", type="intx", default=None, + help="set fpga interpolation rate to INTERP [default=%default]") + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("-g", "--gain", type="eng_float", default=100.0, + help="transmitter gain [default=%default]") + parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, + help="set megabytes to transmit [default=%default]") + parser.add_option("","--discontinuous", action="store_true", default=False, + help="enable discontinous transmission (bursts of 5 packets)") + + parser.add_option("-m", "--modulation", type="string", default='dbpsk', + help="modulation type (bpsk, dbpsk, dqpsk) [default=%default]") + parser.add_option("", "--excess-bw", type="float", default=0.3, + help="set RRC excess bandwith factor [default=%default]") + parser.add_option("", "--no-gray-code", action="store_false", default=True, + help="Don't use gray coding on modulated bits [default=%default]") + + fusb_options.add_options(parser) + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.freq < 1e6: + options.freq *= 1e6 + + pkt_size = int(options.size) + + # Add PSK modulator class to options list + options.modulation = getattr(blks, options.modulation + "_mod") + + # Add PSK modulator's properties + mod_kwargs = { + 'spb' : options.spb, + 'excess_bw' : options.excess_bw, + 'gray_code' : options.no_gray_code, + 'verbose' : False, + 'debug' : False, + } + + # build the graph + fg = my_graph(options, mod_kwargs) + + print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) + print "spb: %3d" % (fg.txpath.spb(),) + print "interp: %3d" % (fg.txpath.interp(),) + + ok = fg.txpath.set_freq(options.freq) + if not ok: + print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(options.freq),) + raise SystemExit + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: failed to enable realtime scheduling" + + fg.start() # start flow graph + + # generate and send packets + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + + while n < nbytes: + send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) + n += pkt_size + sys.stderr.write('.') + if options.discontinuous and pktno % 5 == 4: + time.sleep(1) + pktno += 1 + + send_pkt(eof=True) + fg.wait() # wait for it to finish + fg.txpath.set_auto_tr(False) + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/limbo/gmsk_test.py b/gnuradio-examples/python/digital/limbo/gmsk_test.py new file mode 100755 index 00000000..7ae69a0a --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/gmsk_test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +from gnuradio import gr, blks +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import random +import struct + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + + +class my_graph(gr.flow_graph): + + def __init__(self, rx_callback, spb, bt, SNR, freq_error): + gr.flow_graph.__init__(self) + + fg = self + + # Tuning Parameters + gain_mu = 0.002*spb + omega = spb*(1+freq_error) + + # transmitter + self.packet_transmitter = blks.gmsk2_mod_pkts(fg, spb=spb, bt=bt) + + # add some noise + add = gr.add_cc() + noise = gr.noise_source_c(gr.GR_GAUSSIAN, pow(10.0,-SNR/20.0)) + + # channel filter + rx_filt_taps = gr.firdes.low_pass(1,spb,0.8,0.1,gr.firdes.WIN_HANN) + rx_filt = gr.fir_filter_ccf(1,rx_filt_taps) + + # receiver + self.packet_receiver = blks.gmsk2_demod_pkts(fg, callback=rx_callback, + spb=spb, gain_mu=gain_mu, + freq_error=freq_error, omega=omega) + + fg.connect (self.packet_transmitter, (add,0)) + fg.connect (noise, (add,1)) + fg.connect(add, rx_filt, self.packet_receiver) + + +class stats(object): + def __init__(self): + self.npkts = 0 + self.nright = 0 + +def main(): + st = stats() + + def send_pkt(payload='', eof=False): + fg.packet_transmitter.send_pkt(payload, eof) + + def rx_callback(ok, payload): + st.npkts += 1 + if ok: + st.nright += 1 + if len(payload) <= 16: + print "ok = %5r payload = '%s' %d/%d" % (ok, payload, st.nright, st.npkts) + else: + (pktno,) = struct.unpack('!H', payload[0:2]) + print "ok = %5r pktno = %4d len(payload) = %4d %d/%d" % (ok, pktno, len(payload), + st.nright, st.npkts) + + + parser = OptionParser (option_class=eng_option) + parser.add_option("-M", "--megabytes", type="eng_float", default=1, + help="set megabytes to transmit [default=%default]") + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("","--spb", type=int, default=4, + help="set samples per baud to SPB [default=%default]") + parser.add_option("", "--bt", type="eng_float", default=0.3, + help="set bandwidth time product for Gaussian filter [default=%default]") + parser.add_option("", "--snr", type="eng_float", default=20, + help="set SNR in dB for simulation [default=%default]") + parser.add_option("", "--freq-error", type="eng_float", default=0, + help="set frequency error for simulation [default=%default]") + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + pkt_size = int(options.size) + + fg = my_graph(rx_callback, options.spb, options.bt, options.snr, options.freq_error) + fg.start() + + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + + send_pkt('Hello World') + + # generate and send packets + while n < nbytes: + send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) + n += pkt_size + pktno += 1 + + send_pkt('Goodbye World') + send_pkt(eof=True) # tell modulator we're not sending any more pkts + + fg.wait() + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/limbo/mpsk_test.py b/gnuradio-examples/python/digital/limbo/mpsk_test.py new file mode 100755 index 00000000..1f257d9c --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/mpsk_test.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python + +from gnuradio import gr, blks +from gnuradio.eng_option import eng_option +from optparse import OptionParser +import random +import struct +from mpsk_pkt import * +import cmath + +class my_graph(gr.flow_graph): + + def __init__(self, rx_callback, spb, excess_bw, SNR, freq_error, arity): + gr.flow_graph.__init__(self) + + fg = self + + # Tuning Parameters + gain_mu = 0.05/spb + + # transmitter + self.packet_transmitter = \ + mpsk_mod_pkts(fg, spb=spb, excess_bw=excess_bw, diff=True, arity=arity) + + # ---------------------------------------------------------------- + # Channel model + # ---------------------------------------------------------------- + + awgn = gr.noise_source_c(gr.GR_GAUSSIAN, pow(10.0,-SNR/20.0)) + add = gr.add_cc() # add some noise + fg.connect(awgn, (add,1)) + radians = 17*pi/180 + phase_rotate = gr.multiply_const_cc(cmath.exp(radians * 1j)) + + # ---------------------------------------------------------------- + + # channel filter + rx_filt_taps = gr.firdes.low_pass(1,spb,0.8,0.1,gr.firdes.WIN_HANN) + #rx_filt_taps = (1,) + rx_filt = gr.fir_filter_ccf(1,rx_filt_taps) + + # receiver + self.packet_receiver = \ + mpsk_demod_pkts(fg, callback=rx_callback, + excess_bw=excess_bw, arity=arity, diff=True, + costas_alpha=.005, gain_mu=gain_mu, spb=spb) + + fg.connect (self.packet_transmitter, (add,0)) + fg.connect(add, phase_rotate, rx_filt, self.packet_receiver) + + +class stats(object): + def __init__(self): + self.npkts = 0 + self.nright = 0 + +def main(): + st = stats() + + def send_pkt(payload='', eof=False): + fg.packet_transmitter.send_pkt(payload, eof) + + def rx_callback(ok, payload): + st.npkts += 1 + if ok: + st.nright += 1 + if len(payload) <= 16: + print "ok = %5r payload = '%s' %d/%d" % (ok, payload, st.nright, st.npkts) + else: + (pktno,) = struct.unpack('!H', payload[0:2]) + print "ok = %5r pktno = %4d len(payload) = %4d %d/%d" % (ok, pktno, len(payload), + st.nright, st.npkts) + + + parser = OptionParser (option_class=eng_option) + parser.add_option("-M", "--megabytes", type="eng_float", default=1, + help="set megabytes to transmit [default=%default]") + parser.add_option("-s", "--size", type="eng_float", default=1500, + help="set packet size [default=%default]") + parser.add_option("","--spb", type=int, default=4, + help="set samples per baud to SPB [default=%default]") + parser.add_option("", "--excess-bw", type="eng_float", default=0.4, + help="set excess bandwidth for RRC filter [default=%default]") + parser.add_option("", "--snr", type="eng_float", default=40, + help="set SNR in dB for simulation [default=%default]") + parser.add_option("", "--m-arity", type=int, default=4, + help="PSK arity [default=%default]") + parser.add_option("", "--freq-error", type="eng_float", default=0, + help="set frequency error for simulation [default=%default]") + + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + pkt_size = int(options.size) + + fg = my_graph(rx_callback, options.spb, options.excess_bw, options.snr, + options.freq_error, options.m_arity) + fg.start() + + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + + send_pkt('Hello World') + + # generate and send packets + while n < nbytes: + send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) + n += pkt_size + pktno += 1 + + send_pkt('Goodbye World') + send_pkt(eof=True) # tell modulator we're not sending any more pkts + + fg.wait() + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/limbo/qpsk_tester.py b/gnuradio-examples/python/digital/limbo/qpsk_tester.py new file mode 100644 index 00000000..ea7bae2e --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/qpsk_tester.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +import random +from gnuradio import gr + +default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + +def string_to_1_0_list(s): + r = [] + for ch in s: + x = ord(ch) + for i in range(8): + t = (x >> i) & 0x1 + r.append(t) + + return r + +def to_1_0_string(L): + return ''.join(map(lambda x: chr(x + ord('0')), L)) + +code = string_to_1_0_list(default_access_code) +access_code = to_1_0_string(code) + +use_agc = 0 +use_rrc_tx = 1 +use_rrc_rx = 1 +use_sync_loop = 1 +use_clock_sync = 1 + +def main(): + fg = gr.flow_graph() + +# data = (1,2,3,4,5,6,7,8,9) + random.seed() + data = [random.randint(1,100) for i in range(20000)] + data[0] = 0 # you know, for the diff encoding stuff + bytes_src = gr.vector_source_b(data,False) + + k = 2 + spb = 50 + ntaps = 11*spb + excess_bw = 0.9 + threshold = 12 + constellation = (1+0j, 0+1j, -1+0j, 0-1j) + + bytes2chunks = gr.packed_to_unpacked_bb(k, gr.GR_MSB_FIRST) + diffenc = gr.diff_encoder_bb(4) + chunks2symbols = gr.chunks_to_symbols_bc(constellation) + + if use_rrc_tx: + rrc_taps_tx = gr.firdes.root_raised_cosine(spb, spb, 1.0, \ + excess_bw, ntaps) + rrc_tx = gr.interp_fir_filter_ccf(spb, rrc_taps_tx) + else: + rrc_tx = gr.interp_fir_filter_ccf(1, (1,)) + +################### CHANNEL MODEL ############################# + + phase_rotate = gr.multiply_const_cc(1-0.36j) + channel = gr.add_cc() + awgn = gr.noise_source_c(gr.GR_GAUSSIAN, 0.5) + fg.connect(awgn, (channel,1)) + +################### CHANNEL MODEL ############################# + + if use_agc: + agc = gr.agc_cc(1e-4, 1, 1) + else: + agc = gr.multiply_const_cc(1) + + # Downconverter + if use_sync_loop: + costas_alpha=0.005 + beta = costas_alpha*costas_alpha*0.25 + sync_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 0) + else: + sync_loop = gr.multiply_const_cc(1) + + if use_rrc_rx: + rrc_taps_rx = gr.firdes.root_raised_cosine(1, spb, 1.0, \ + excess_bw, ntaps) + rrc_rx = gr.fir_filter_ccf(1, rrc_taps_rx) + else: + rrc_rx = gr.fir_filter_ccf(1, (1,)) + + # Sampler + if use_clock_sync: + mu = 0.05 + omega = spb + gain_mu = 0.05 + gain_omega = 0.25*gain_mu*gain_mu + omega_rel_limit = 0.5 + clock_sync = gr.clock_recovery_mm_cc(omega, gain_omega, mu, \ + gain_mu, omega_rel_limit) + #clock_sync.set_verbose(True); + else: + clock_sync = gr.fir_filter_ccf(1, (1,)) + + diff_phasor = gr.diff_phasor_cc() + slicer = gr.constellation_decoder_cb((constellation), (0,1,2,3)) + unpack = gr.unpack_k_bits_bb(k) + access = gr.correlate_access_code_bb(access_code,threshold) + + sink = gr.file_sink(gr.sizeof_char, 'output.dat') + + fg.connect(bytes_src, bytes2chunks, diffenc, chunks2symbols, rrc_tx) + fg.connect(rrc_tx, phase_rotate, channel, agc) + fg.connect(agc, sync_loop, rrc_rx, clock_sync, diff_phasor, slicer, sink) + + test = gr.file_sink(gr.sizeof_gr_complex, 'test.dat') + fg.connect(rrc_rx, test) + + fg.connect(chunks2symbols, gr.file_sink(gr.sizeof_gr_complex, 'rrc_tx.dat')) # into TX RRC + fg.connect(channel, gr.file_sink(gr.sizeof_gr_complex, 'channel.dat')) # Out of TX RRC + fg.connect(rrc_rx, gr.file_sink(gr.sizeof_gr_complex, 'rrc_rx.dat')) # Out of RX RRC -> clock_sync + fg.connect(clock_sync, gr.file_sink(gr.sizeof_gr_complex, 'clock_sync.dat')) # Out of M&M sync loop + fg.connect(bytes2chunks, gr.file_sink(gr.sizeof_char, 'source.dat')) + + fg.start() + fg.wait() + +if __name__ == "__main__": + main() + + + + diff --git a/gnuradio-examples/python/digital/limbo/qpsk_usrp_tester.py b/gnuradio-examples/python/digital/limbo/qpsk_usrp_tester.py new file mode 100644 index 00000000..bf7698a2 --- /dev/null +++ b/gnuradio-examples/python/digital/limbo/qpsk_usrp_tester.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python + +import random +from gnuradio import gr, gru, usrp + +default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' + +def string_to_1_0_list(s): + r = [] + for ch in s: + x = ord(ch) + for i in range(8): + t = (x >> i) & 0x1 + r.append(t) + + return r + +def to_1_0_string(L): + return ''.join(map(lambda x: chr(x + ord('0')), L)) + +code = string_to_1_0_list(default_access_code) + +access_code = to_1_0_string(code) + +def main(): + + fg = gr.flow_graph() + f_rf = 5e6 + fs = 400e3 + sr = 100e3 + alpha = 0.5 + M = 4 + k = int(gru.log2(M)) + + # Source + src = usrp.source_c () + adc_rate = src.adc_rate() + usrp_decim = int(adc_rate / fs) + src.set_decim_rate(usrp_decim) + + subdev_spec = usrp.pick_rx_subdevice(src) + subdev = usrp.selected_subdev(src, subdev_spec) + print "Using RX d'board %s" % (subdev.side_and_name(),) + src.set_mux(usrp.determine_rx_mux_value(src, subdev_spec)) + src.tune(0, subdev, f_rf) + + g = subdev.gain_range() + subdev.set_gain(g[1]) + subdev.set_auto_tr(True) + + print "USRP Decimation Rate = %d" % usrp_decim + print "RF Frequency = %d" % f_rf + + agc = gr.multiply_const_cc(0.0025) + + # Downconverter + costas_alpha=0.005 + beta = costas_alpha*costas_alpha*0.25 + sync_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 0) + + # Stage 2 +# fs2 = 200e3 +# D = int(fs / fs2) +# decimator = gr.keep_one_in_n(gr.sizeof_gr_complex, D) +# print "D = %d\nAfter decimator fs = %f" % (D, fs2) + + # Demodulator + taps = gr.firdes.root_raised_cosine(1, fs, sr, alpha, 45) + rrc = gr.fir_filter_ccf(1, taps) + + # Sampler + mu = 0.01 + omega = 4.3 + gain_mu = 0.05 + gain_omega = 0.25*gain_mu*gain_mu + omega_rel_limit = 0.5 + clock_sync = gr.clock_recovery_mm_cc(omega, gain_omega, mu, + gain_mu, omega_rel_limit) + clock_sync.set_verbose(False) + + diff_phasor = gr.diff_phasor_cc() + + threshold = 12 + constellation = (1+0j, 0+1j, -1+0j, 0-1j) + slicer = gr.constellation_decoder_cb((constellation), (0,1,2,3)) + unpack = gr.unpack_k_bits_bb(k) + access = gr.correlate_access_code_bb(access_code,threshold) + + test = gr.file_sink(gr.sizeof_gr_complex, 'test.dat') + sink = gr.file_sink(gr.sizeof_char, 'output.dat') + + fg.connect(src, agc, sync_loop, rrc, clock_sync) + fg.connect(clock_sync, diff_phasor, slicer, unpack, access, sink) + + fg.connect(slicer, gr.file_sink(gr.sizeof_char, 'chunks.dat')) + fg.connect(unpack, gr.file_sink(gr.sizeof_char, 'unpack.dat')) + fg.connect(clock_sync, gr.file_sink(gr.sizeof_gr_complex, 'phasor.dat')) + + fg.start() + fg.wait() + +if __name__ == "__main__": + main() diff --git a/gnuradio-examples/python/digital/pick_bitrate.py b/gnuradio-examples/python/digital/pick_bitrate.py new file mode 100644 index 00000000..42aefa94 --- /dev/null +++ b/gnuradio-examples/python/digital/pick_bitrate.py @@ -0,0 +1,143 @@ +# +# Copyright 2005,2006 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 2, 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. +# + +_default_bitrate = 500e3 + +_valid_samples_per_symbol = (2,3,4,5,6,7) + +def _gen_tx_info(converter_rate): + results = [] + for samples_per_symbol in _valid_samples_per_symbol: + for interp in range(16, 512 + 1, 4): + bitrate = converter_rate / interp / samples_per_symbol + results.append((bitrate, samples_per_symbol, interp)) + results.sort() + return results + +def _gen_rx_info(converter_rate): + results = [] + for samples_per_symbol in _valid_samples_per_symbol: + for decim in range(8, 256 + 1, 2): + bitrate = converter_rate / decim / samples_per_symbol + results.append((bitrate, samples_per_symbol, decim)) + results.sort() + return results + +def _filter_info(info, samples_per_symbol, xrate): + if samples_per_symbol is not None: + info = [x for x in info if x[1] == samples_per_symbol] + if xrate is not None: + info = [x for x in info if x[2] == xrate] + return info + +def _pick_best(target_bitrate, bits_per_symbol, info): + """ + @returns tuple (bitrate, samples_per_symbol, interp_rate_or_decim_rate) + """ + if len(info) == 0: + raise RuntimeError, "info is zero length!" + + if target_bitrate is None: # return the fastest one + return info[-1] + + # convert bit rate to symbol rate + target_symbolrate = target_bitrate / bits_per_symbol + + # Find the closest matching symbol rate. + # In the event of a tie, the one with the lowest samples_per_symbol wins. + # (We already sorted them, so the first one is the one we take) + + best = info[0] + best_delta = abs(target_symbolrate - best[0]) + for x in info[1:]: + delta = abs(target_symbolrate - x[0]) + if delta < best_delta: + best_delta = delta + best = x + + # convert symbol rate back to bit rate + return ((best[0] * bits_per_symbol),) + best[1:] + +def _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + xrate, converter_rate, gen_info): + """ + @returns tuple (bitrate, samples_per_symbol, interp_rate_or_decim_rate) + """ + if not isinstance(bits_per_symbol, int) or bits_per_symbol < 1: + raise ValueError, "bits_per_symbol must be an int >= 1" + + if samples_per_symbol is not None and xrate is not None: # completely determined + return (float(converter_rate) / xrate / samples_per_symbol, + samples_per_symbol, xrate) + + if bitrate is None and samples_per_symbol is None and xrate is None: + bitrate = _default_bitrate + + # now we have a target bitrate and possibly an xrate or + # samples_per_symbol constraint, but not both of them. + + return _pick_best(bitrate, bits_per_symbol, + _filter_info(gen_info(converter_rate), samples_per_symbol, xrate)) + +# --------------------------------------------------------------------------------------- + +def pick_tx_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + interp_rate, converter_rate=128e6): + """ + Given the 4 input parameters, return at configuration that matches + + @param bitrate: desired bitrate or None + @type bitrate: number or None + @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3 + @type bits_per_symbol: integer >= 1 + @param samples_per_symbol: samples/baud (aka samples/symbol) + @type samples_per_symbol: number or None + @param interp_rate: USRP interpolation factor + @type interp_rate: integer or None + @param converter_rate: converter sample rate in Hz + @type converter_rate: number + + @returns tuple (bitrate, samples_per_symbol, interp_rate) + """ + return _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + interp_rate, converter_rate, _gen_tx_info) + + +def pick_rx_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + decim_rate, converter_rate=64e6): + """ + Given the 4 input parameters, return at configuration that matches + + @param bitrate: desired bitrate or None + @type bitrate: number or None + @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3 + @type bits_per_symbol: integer >= 1 + @param samples_per_symbol: samples/baud (aka samples/symbol) + @type samples_per_symbol: number or None + @param decim_rate: USRP decimation factor + @type decim_rate: integer or None + @param converter_rate: converter sample rate in Hz + @type converter_rate: number + + @returns tuple (bitrate, samples_per_symbol, decim_rate) + """ + return _pick_bitrate(bitrate, bits_per_symbol, samples_per_symbol, + decim_rate, converter_rate, _gen_rx_info) diff --git a/gnuradio-examples/python/digital/receive_path.py b/gnuradio-examples/python/digital/receive_path.py new file mode 100644 index 00000000..9d55c88d --- /dev/null +++ b/gnuradio-examples/python/digital/receive_path.py @@ -0,0 +1,252 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation +import copy +import sys + +# from current dir +from pick_bitrate import pick_rx_bitrate + +# ///////////////////////////////////////////////////////////////////////////// +# receive path +# ///////////////////////////////////////////////////////////////////////////// + +class receive_path(gr.hier_block): + def __init__(self, fg, demod_class, rx_callback, options): + + options = copy.copy(options) # make a copy so we can destructively modify + + self._verbose = options.verbose + self._rx_freq = options.rx_freq # receiver's center frequency + self._rx_gain = options.rx_gain # receiver's gain + self._rx_subdev_spec = options.rx_subdev_spec # daughterboard to use + self._bitrate = options.bitrate # desired bit rate + self._decim = options.decim # Decimating rate for the USRP (prelim) + self._samples_per_symbol = options.samples_per_symbol # desired samples/symbol + self._fusb_block_size = options.fusb_block_size # usb info for USRP + self._fusb_nblocks = options.fusb_nblocks # usb info for USRP + + self._rx_callback = rx_callback # this callback is fired when there's a packet available + self._demod_class = demod_class # the demodulator_class we're using + + if self._rx_freq is None: + sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n") + raise SystemExit + + # Set up USRP source; also adjusts decim, samples_per_symbol, and bitrate + self._setup_usrp_source() + + # copy the final answers back into options for use by demodulator + options.samples_per_symbol = self._samples_per_symbol + options.bitrate = self._bitrate + options.decim = self._decim + + # Get demod_kwargs + demod_kwargs = self._demod_class.extract_kwargs_from_options(options) + + # Design filter to get actual channel we want + sw_decim = 1 + chan_coeffs = gr.firdes.low_pass (1.0, # gain + sw_decim * self._samples_per_symbol, # sampling rate + 1.0, # midpoint of trans. band + 0.1, # width of trans. band + gr.firdes.WIN_HANN) # filter type + + # Decimating channel filter + # complex in and out, float taps + self.chan_filt = gr.fft_filter_ccc(sw_decim, chan_coeffs) + #self.chan_filt = gr.fir_filter_ccf(sw_decim, chan_coeffs) + + # receiver + self.packet_receiver = \ + blks.demod_pkts(fg, + self._demod_class(fg, **demod_kwargs), + access_code=None, + callback=self._rx_callback, + threshold=-1) + + ok = self.set_freq(self._rx_freq) + if not ok: + print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(self._rx_freq)) + raise ValueError, eng_notation.num_to_str(self._rx_freq) + + g = self.subdev.gain_range() + if options.show_rx_gain_range: + print "Rx Gain Range: minimum = %g, maximum = %g, step size = %g" \ + % (g[0], g[1], g[2]) + + self.set_gain(options.rx_gain) + + self.set_auto_tr(True) # enable Auto Transmit/Receive switching + + # Carrier Sensing Blocks + alpha = 0.001 + thresh = 30 # in dB, will have to adjust + self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha) + fg.connect(self.chan_filt, self.probe) + + # Display some information about the setup + if self._verbose: + self._print_verbage() + + fg.connect(self.u, self.chan_filt, self.packet_receiver) + gr.hier_block.__init__(self, fg, None, None) + + def _setup_usrp_source(self): + self.u = usrp.source_c (fusb_block_size=self._fusb_block_size, + fusb_nblocks=self._fusb_nblocks) + adc_rate = self.u.adc_rate() + + # derive values of bitrate, samples_per_symbol, and decim from desired info + (self._bitrate, self._samples_per_symbol, self._decim) = \ + pick_rx_bitrate(self._bitrate, self._demod_class.bits_per_symbol(), \ + self._samples_per_symbol, self._decim, adc_rate) + + self.u.set_decim_rate(self._decim) + + # determine the daughterboard subdevice we're using + if self._rx_subdev_spec is None: + self._rx_subdev_spec = usrp.pick_rx_subdevice(self.u) + self.subdev = usrp.selected_subdev(self.u, self._rx_subdev_spec) + + self.u.set_mux(usrp.determine_rx_mux_value(self.u, self._rx_subdev_spec)) + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital up converter. + """ + r = self.u.tune(0, self.subdev, target_freq) + if r: + return True + + return False + + def set_gain(self, gain): + """ + Sets the analog gain in the USRP + """ + if gain is None: + r = self.subdev.gain_range() + gain = (r[0] + r[1])/2 # set gain to midpoint + self.gain = gain + return self.subdev.set_gain(gain) + + def set_auto_tr(self, enable): + return self.subdev.set_auto_tr(enable) + + def bitrate(self): + return self._bitrate + + def samples_per_symbol(self): + return self._samples_per_symbol + + def decim(self): + return self._decim + + def carrier_sensed(self): + """ + Return True if we think carrier is present. + """ + #return self.probe.level() > X + return self.probe.unmuted() + + def carrier_threshold(self): + """ + Return current setting in dB. + """ + return self.probe.threshold() + + def set_carrier_threshold(self, threshold_in_db): + """ + Set carrier threshold. + + @param threshold_in_db: set detection threshold + @type threshold_in_db: float (dB) + """ + self.probe.set_threshold(threshold_in_db) + + + def add_options(normal, expert): + """ + Adds receiver-specific options to the Options Parser + """ + add_freq_option(normal) + if not normal.has_option("--bitrate"): + normal.add_option("-r", "--bitrate", type="eng_float", default=None, + help="specify bitrate. samples-per-symbol and interp/decim will be derived.") + normal.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B") + normal.add_option("", "--rx-gain", type="eng_float", default=None, metavar="GAIN", + help="set receiver gain in dB [default=midpoint]. See also --show-rx-gain-range") + normal.add_option("", "--show-rx-gain-range", action="store_true", default=False, + help="print min and max Rx gain available on selected daughterboard") + normal.add_option("-v", "--verbose", action="store_true", default=False) + expert.add_option("-S", "--samples-per-symbol", type="int", default=None, + help="set samples/symbol [default=%default]") + expert.add_option("", "--rx-freq", type="eng_float", default=None, + help="set Rx frequency to FREQ [default=%default]", metavar="FREQ") + expert.add_option("-d", "--decim", type="intx", default=None, + help="set fpga decimation rate to DECIM [default=%default]") + expert.add_option("", "--log", action="store_true", default=False, + help="Log all parts of flow graph to files (CAUTION: lots of data)") + + # Make a static method to call before instantiation + add_options = staticmethod(add_options) + + + def _print_verbage(self): + """ + Prints information about the receive path + """ + print "Using RX d'board %s" % (self.subdev.side_and_name(),) + print "Rx gain: %g" % (self.gain,) + print "modulation: %s" % (self._demod_class.__name__) + print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate)) + print "samples/symbol: %3d" % (self._samples_per_symbol) + print "decim: %3d" % (self._decim) + print "Rx Frequency: %s" % (eng_notation.num_to_str(self._rx_freq)) + # print "Rx Frequency: %f" % (self._rx_freq) + +def add_freq_option(parser): + """ + Hackery that has the -f / --freq option set both tx_freq and rx_freq + """ + def freq_callback(option, opt_str, value, parser): + parser.values.rx_freq = value + parser.values.tx_freq = value + + if not parser.has_option('--freq'): + parser.add_option('-f', '--freq', type="eng_float", + action="callback", callback=freq_callback, + help="set Tx and/or Rx frequency to FREQ [default=%default]", + metavar="FREQ") diff --git a/gnuradio-examples/python/digital/rx_voice.py b/gnuradio-examples/python/digital/rx_voice.py new file mode 100755 index 00000000..13048624 --- /dev/null +++ b/gnuradio-examples/python/digital/rx_voice.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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, gru, modulation_utils +from gnuradio import usrp +from gnuradio import audio +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +from gnuradio.vocoder import gsm_full_rate + +import random +import struct + +# from current dir +from receive_path import receive_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + + +class audio_tx(gr.hier_block): + def __init__(self, fg, audio_output_dev): + self.packet_src = gr.message_source(33) + voice_decoder = gsm_full_rate.decode_ps() + s2f = gr.short_to_float () + sink_scale = gr.multiply_const_ff(1.0/32767.) + audio_sink = audio.sink(8000, audio_output_dev) + fg.connect(self.packet_src, voice_decoder, s2f, sink_scale, audio_sink) + gr.hier_block.__init__(self, fg, self.packet_src, audio_sink) + + def msgq(self): + return self.packet_src.msgq() + + +class my_graph(gr.flow_graph): + + def __init__(self, demod_class, rx_callback, options): + gr.flow_graph.__init__(self) + self.rxpath = receive_path(self, demod_class, rx_callback, options) + self.audio_tx = audio_tx(self, options.audio_output) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +global n_rcvd, n_right + +def main(): + global n_rcvd, n_right + + n_rcvd = 0 + n_right = 0 + + def rx_callback(ok, payload): + global n_rcvd, n_right + n_rcvd += 1 + if ok: + n_right += 1 + + fg.audio_tx.msgq().insert_tail(gr.message_from_string(payload)) + + print "ok = %r n_rcvd = %4d n_right = %4d" % ( + ok, n_rcvd, n_right) + + demods = modulation_utils.type_1_demods() + + # Create Options Parser: + parser = OptionParser (option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), + default='gmsk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(demods.keys()),)) + parser.add_option("-O", "--audio-output", type="string", default="", + help="pcm output device name. E.g., hw:0,0 or /dev/dsp") + + receive_path.add_options(parser, expert_grp) + + for mod in demods.values(): + mod.add_options(expert_grp) + + fusb_options.add_options(expert_grp) + + parser.set_defaults(bitrate=50e3) # override default bitrate default + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help(sys.stderr) + sys.exit(1) + + if options.rx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + + # build the graph + fg = my_graph(demods[options.modulation], rx_callback, options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: Failed to enable realtime scheduling." + + fg.start() # start flow graph + fg.wait() # wait for it to finish + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/transmit_path.py b/gnuradio-examples/python/digital/transmit_path.py new file mode 100644 index 00000000..5c401736 --- /dev/null +++ b/gnuradio-examples/python/digital/transmit_path.py @@ -0,0 +1,232 @@ +# +# Copyright 2005,2006 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 2, 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, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation + +import copy +import sys + +# from current dir +from pick_bitrate import pick_tx_bitrate + +# ///////////////////////////////////////////////////////////////////////////// +# transmit path +# ///////////////////////////////////////////////////////////////////////////// + +class transmit_path(gr.hier_block): + def __init__(self, fg, modulator_class, options): + ''' + See below for what options should hold + ''' + + options = copy.copy(options) # make a copy so we can destructively modify + + self._verbose = options.verbose + self._tx_freq = options.tx_freq # tranmitter's center frequency + self._tx_amplitude = options.tx_amplitude # digital amplitude sent to USRP + self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use + self._bitrate = options.bitrate # desired bit rate + self._interp = options.interp # interpolating rate for the USRP (prelim) + self._samples_per_symbol = options.samples_per_symbol # desired samples/baud + self._fusb_block_size = options.fusb_block_size # usb info for USRP + self._fusb_nblocks = options.fusb_nblocks # usb info for USRP + + self._modulator_class = modulator_class # the modulator_class we are using + + if self._tx_freq is None: + sys.stderr.write("-f FREQ or --freq FREQ or --tx-freq FREQ must be specified\n") + raise SystemExit + + # Set up USRP sink; also adjusts interp, samples_per_symbol, and bitrate + self._setup_usrp_sink() + + # copy the final answers back into options for use by modulator + options.samples_per_symbol = self._samples_per_symbol + options.bitrate = self._bitrate + options.interp = self._interp + + # Get mod_kwargs + mod_kwargs = self._modulator_class.extract_kwargs_from_options(options) + + # Set center frequency of USRP + ok = self.set_freq(self._tx_freq) + if not ok: + print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(self._tx_freq),) + raise ValueError + + # transmitter + self.packet_transmitter = \ + blks.mod_pkts(fg, + self._modulator_class(fg, **mod_kwargs), + access_code=None, + msgq_limit=4, + pad_for_usrp=True) + + + # Set the USRP for maximum transmit gain + # (Note that on the RFX cards this is a nop.) + self.set_gain(self.subdev.gain_range()[0]) + + self.amp = gr.multiply_const_cc(1) + self.set_tx_amplitude(self._tx_amplitude) + + # enable Auto Transmit/Receive switching + self.set_auto_tr(True) + + # Display some information about the setup + if self._verbose: + self._print_verbage() + + # Create and setup transmit path flow graph + fg.connect(self.packet_transmitter, self.amp, self.u) + gr.hier_block.__init__(self, fg, None, None) + + def _setup_usrp_sink(self): + """ + Creates a USRP sink, determines the settings for best bitrate, + and attaches to the transmitter's subdevice. + """ + self.u = usrp.sink_c(fusb_block_size=self._fusb_block_size, + fusb_nblocks=self._fusb_nblocks) + dac_rate = self.u.dac_rate(); + + # derive values of bitrate, samples_per_symbol, and interp from desired info + (self._bitrate, self._samples_per_symbol, self._interp) = \ + pick_tx_bitrate(self._bitrate, self._modulator_class.bits_per_symbol(), + self._samples_per_symbol, self._interp, dac_rate) + + self.u.set_interp_rate(self._interp) + + # determine the daughterboard subdevice we're using + if self._tx_subdev_spec is None: + self._tx_subdev_spec = usrp.pick_tx_subdevice(self.u) + self.u.set_mux(usrp.determine_tx_mux_value(self.u, self._tx_subdev_spec)) + self.subdev = usrp.selected_subdev(self.u, self._tx_subdev_spec) + + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital up converter. + """ + r = self.u.tune(self.subdev._which, self.subdev, target_freq) + if r: + return True + + return False + + def set_gain(self, gain): + """ + Sets the analog gain in the USRP + """ + self.gain = gain + self.subdev.set_gain(gain) + + def set_tx_amplitude(self, ampl): + """ + Sets the transmit amplitude sent to the USRP + @param: ampl 0 <= ampl < 32768. Try 8000 + """ + self._tx_amplitude = max(0.0, min(ampl, 32767.0)) + self.amp.set_k(self._tx_amplitude) + + def set_auto_tr(self, enable): + """ + Turns on auto transmit/receive of USRP daughterboard (if exits; else ignored) + """ + return self.subdev.set_auto_tr(enable) + + def send_pkt(self, payload='', eof=False): + """ + Calls the transmitter method to send a packet + """ + return self.packet_transmitter.send_pkt(payload, eof) + + def bitrate(self): + return self._bitrate + + def samples_per_symbol(self): + return self._samples_per_symbol + + def interp(self): + return self._interp + + def add_options(normal, expert): + """ + Adds transmitter-specific options to the Options Parser + """ + add_freq_option(normal) + if not normal.has_option('--bitrate'): + normal.add_option("-r", "--bitrate", type="eng_float", default=None, + help="specify bitrate. samples-per-symbol and interp/decim will be derived.") + normal.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, + help="select USRP Tx side A or B") + normal.add_option("", "--tx-amplitude", type="eng_float", default=12000, metavar="AMPL", + help="set transmitter digital amplitude: 0 <= AMPL < 32768 [default=%default]") + normal.add_option("-v", "--verbose", action="store_true", default=False) + + expert.add_option("-S", "--samples-per-symbol", type="int", default=None, + help="set samples/symbol [default=%default]") + expert.add_option("", "--tx-freq", type="eng_float", default=None, + help="set transmit frequency to FREQ [default=%default]", metavar="FREQ") + expert.add_option("-i", "--interp", type="intx", default=None, + help="set fpga interpolation rate to INTERP [default=%default]") + expert.add_option("", "--log", action="store_true", default=False, + help="Log all parts of flow graph to file (CAUTION: lots of data)") + + # Make a static method to call before instantiation + add_options = staticmethod(add_options) + + def _print_verbage(self): + """ + Prints information about the transmit path + """ + print "Using TX d'board %s" % (self.subdev.side_and_name(),) + print "Tx amplitude %s" % (self._tx_amplitude) + print "modulation: %s" % (self._modulator_class.__name__) + print "bitrate: %sb/s" % (eng_notation.num_to_str(self._bitrate)) + print "samples/symbol: %3d" % (self._samples_per_symbol) + print "interp: %3d" % (self._interp) + print "Tx Frequency: %s" % (eng_notation.num_to_str(self._tx_freq)) + + +def add_freq_option(parser): + """ + Hackery that has the -f / --freq option set both tx_freq and rx_freq + """ + def freq_callback(option, opt_str, value, parser): + parser.values.rx_freq = value + parser.values.tx_freq = value + + if not parser.has_option('--freq'): + parser.add_option('-f', '--freq', type="eng_float", + action="callback", callback=freq_callback, + help="set Tx and/or Rx frequency to FREQ [default=%default]", + metavar="FREQ") diff --git a/gnuradio-examples/python/digital/tunnel.py b/gnuradio-examples/python/digital/tunnel.py new file mode 100755 index 00000000..56229f53 --- /dev/null +++ b/gnuradio-examples/python/digital/tunnel.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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. +# + + +# ///////////////////////////////////////////////////////////////////////////// +# +# This code sets up up a virtual ethernet interface (typically gr0), +# and relays packets between the interface and the GNU Radio PHY+MAC +# +# What this means in plain language, is that if you've got a couple +# of USRPs on different machines, and if you run this code on those +# machines, you can talk between them using normal TCP/IP networking. +# +# ///////////////////////////////////////////////////////////////////////////// + + +from gnuradio import gr, gru, modulation_utils +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import time +import struct +import sys +import os + +# from current dir +from transmit_path import transmit_path +from receive_path import receive_path +import fusb_options + +#print os.getpid() +#raw_input('Attach and press enter') + + +# ///////////////////////////////////////////////////////////////////////////// +# +# Use the Universal TUN/TAP device driver to move packets to/from kernel +# +# See /usr/src/linux/Documentation/networking/tuntap.txt +# +# ///////////////////////////////////////////////////////////////////////////// + +# Linux specific... +# TUNSETIFF ifr flags from + +IFF_TUN = 0x0001 # tunnel IP packets +IFF_TAP = 0x0002 # tunnel ethernet frames +IFF_NO_PI = 0x1000 # don't pass extra packet info +IFF_ONE_QUEUE = 0x2000 # beats me ;) + +def open_tun_interface(tun_device_filename): + from fcntl import ioctl + + mode = IFF_TAP | IFF_NO_PI + TUNSETIFF = 0x400454ca + + tun = os.open(tun_device_filename, os.O_RDWR) + ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode)) + ifname = ifs[:16].strip("\x00") + return (tun, ifname) + + +# ///////////////////////////////////////////////////////////////////////////// +# the flow graph +# ///////////////////////////////////////////////////////////////////////////// + +class my_graph(gr.flow_graph): + + def __init__(self, mod_class, demod_class, + rx_callback, options): + + gr.flow_graph.__init__(self) + self.txpath = transmit_path(self, mod_class, options) + self.rxpath = receive_path(self, demod_class, rx_callback, options) + + def send_pkt(self, payload='', eof=False): + return self.txpath.send_pkt(payload, eof) + + def carrier_sensed(self): + """ + Return True if the receive path thinks there's carrier + """ + return self.rxpath.carrier_sensed() + + +# ///////////////////////////////////////////////////////////////////////////// +# Carrier Sense MAC +# ///////////////////////////////////////////////////////////////////////////// + +class cs_mac(object): + """ + Prototype carrier sense MAC + + Reads packets from the TUN/TAP interface, and sends them to the PHY. + Receives packets from the PHY via phy_rx_callback, and sends them + into the TUN/TAP interface. + + Of course, we're not restricted to getting packets via TUN/TAP, this + is just an example. + """ + def __init__(self, tun_fd, verbose=False): + self.tun_fd = tun_fd # file descriptor for TUN/TAP interface + self.verbose = verbose + self.fg = None # flow graph (access to PHY) + + def set_flow_graph(self, fg): + self.fg = fg + + def phy_rx_callback(self, ok, payload): + """ + Invoked by thread associated with PHY to pass received packet up. + + @param ok: bool indicating whether payload CRC was OK + @param payload: contents of the packet (string) + """ + if self.verbose: + print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload)) + if ok: + os.write(self.tun_fd, payload) + + def main_loop(self): + """ + Main loop for MAC. + Only returns if we get an error reading from TUN. + + FIXME: may want to check for EINTR and EAGAIN and reissue read + """ + min_delay = 0.001 # seconds + + while 1: + payload = os.read(self.tun_fd, 10*1024) + if not payload: + self.fg.send_pkt(eof=True) + break + + if self.verbose: + print "Tx: len(payload) = %4d" % (len(payload),) + + delay = min_delay + while self.fg.carrier_sensed(): + sys.stderr.write('B') + time.sleep(delay) + if delay < 0.050: + delay = delay * 2 # exponential back-off + + self.fg.send_pkt(payload) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + mods = modulation_utils.type_1_mods() + demods = modulation_utils.type_1_demods() + + parser = OptionParser (option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), + default='gmsk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(mods.keys()),)) + + parser.add_option("-v","--verbose", action="store_true", default=False) + expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30, + help="set carrier detect threshold (dB) [default=%default]") + expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun", + help="path to tun device file [default=%default]") + + transmit_path.add_options(parser, expert_grp) + receive_path.add_options(parser, expert_grp) + + for mod in mods.values(): + mod.add_options(expert_grp) + + for demod in demods.values(): + demod.add_options(expert_grp) + + fusb_options.add_options(expert_grp) + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help(sys.stderr) + sys.exit(1) + + if options.rx_freq is None or options.tx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + # open the TUN/TAP interface + (tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename) + + # Attempt to enable realtime scheduling + r = gr.enable_realtime_scheduling() + if r == gr.RT_OK: + realtime = True + else: + realtime = False + print "Note: failed to enable realtime scheduling" + + + # If the user hasn't set the fusb_* parameters on the command line, + # pick some values that will reduce latency. + + if options.fusb_block_size == 0 and options.fusb_nblocks == 0: + if realtime: # be more aggressive + options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024) + options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16) + else: + options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096) + options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16) + + #print "fusb_block_size =", options.fusb_block_size + #print "fusb_nblocks =", options.fusb_nblocks + + # instantiate the MAC + mac = cs_mac(tun_fd, verbose=True) + + + # build the graph (PHY) + fg = my_graph(mods[options.modulation], + demods[options.modulation], + mac.phy_rx_callback, + options) + + mac.set_flow_graph(fg) # give the MAC a handle for the PHY + + if fg.txpath.bitrate() != fg.rxpath.bitrate(): + print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % ( + eng_notation.num_to_str(fg.txpath.bitrate()), + eng_notation.num_to_str(fg.rxpath.bitrate())) + + print "modulation: %s" % (options.modulation,) + print "freq: %s" % (eng_notation.num_to_str(options.tx_freq)) + print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) + print "samples/symbol: %3d" % (fg.txpath.samples_per_symbol(),) + #print "interp: %3d" % (fg.txpath.interp(),) + #print "decim: %3d" % (fg.rxpath.decim(),) + + fg.rxpath.set_carrier_threshold(options.carrier_threshold) + print "Carrier sense threshold:", options.carrier_threshold, "dB" + + print + print "Allocated virtual ethernet interface: %s" % (tun_ifname,) + print "You must now use ifconfig to set its IP address. E.g.," + print + print " $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,) + print + print "Be sure to use a different address in the same subnet for each machine." + print + + + fg.start() # Start executing the flow graph (runs in separate threads) + + mac.main_loop() # don't expect this to return... + + fg.stop() # but if it does, tell flow graph to stop. + fg.wait() # wait for it to finish + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/digital/tx_voice.py b/gnuradio-examples/python/digital/tx_voice.py new file mode 100755 index 00000000..eba0c3c7 --- /dev/null +++ b/gnuradio-examples/python/digital/tx_voice.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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, gru, modulation_utils +from gnuradio import usrp +from gnuradio import audio +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +from gnuradio.vocoder import gsm_full_rate + +import random +import time +import struct +import sys + +# from current dir +from transmit_path import transmit_path +import fusb_options + +#import os +#print os.getpid() +#raw_input('Attach and press enter') + + +class audio_rx(gr.hier_block): + def __init__(self, fg, audio_input_dev): + sample_rate = 8000 + src = audio.source(sample_rate, audio_input_dev) + src_scale = gr.multiply_const_ff(32767) + f2s = gr.float_to_short() + voice_coder = gsm_full_rate.encode_sp() + self.packets_from_encoder = gr.msg_queue() + packet_sink = gr.message_sink(33, self.packets_from_encoder, False) + fg.connect(src, src_scale, f2s, voice_coder, packet_sink) + gr.hier_block.__init__(self, fg, src, packet_sink) + + def get_encoded_voice_packet(self): + return self.packets_from_encoder.delete_head() + + +class my_graph(gr.flow_graph): + + def __init__(self, modulator_class, options): + gr.flow_graph.__init__(self) + self.txpath = transmit_path(self, modulator_class, options) + self.audio_rx = audio_rx(self, options.audio_input) + + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + def send_pkt(payload='', eof=False): + return fg.txpath.send_pkt(payload, eof) + + def rx_callback(ok, payload): + print "ok = %r, payload = '%s'" % (ok, payload) + + mods = modulation_utils.type_1_mods() + + parser = OptionParser(option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), + default='gmsk', + help="Select modulation from: %s [default=%%default]" + % (', '.join(mods.keys()),)) + parser.add_option("-M", "--megabytes", type="eng_float", default=0, + help="set megabytes to transmit [default=inf]") + parser.add_option("-I", "--audio-input", type="string", default="", + help="pcm input device name. E.g., hw:0,0 or /dev/dsp") + + transmit_path.add_options(parser, expert_grp) + + for mod in mods.values(): + mod.add_options(expert_grp) + + fusb_options.add_options(expert_grp) + + parser.set_defaults(bitrate=50e3) # override default bitrate default + (options, args) = parser.parse_args () + + if len(args) != 0: + parser.print_help() + sys.exit(1) + + if options.tx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + + # build the graph + fg = my_graph(mods[options.modulation], options) + + r = gr.enable_realtime_scheduling() + if r != gr.RT_OK: + print "Warning: failed to enable realtime scheduling" + + + fg.start() # start flow graph + + # generate and send packets + nbytes = int(1e6 * options.megabytes) + n = 0 + pktno = 0 + + while nbytes == 0 or n < nbytes: + packet = fg.audio_rx.get_encoded_voice_packet() + s = packet.to_string() + send_pkt(s) + n += len(s) + sys.stderr.write('.') + pktno += 1 + + send_pkt(eof=True) + fg.wait() # wait for it to finish + fg.txpath.set_auto_tr(False) + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass diff --git a/gnuradio-examples/python/gmsk2/Makefile.am b/gnuradio-examples/python/gmsk2/Makefile.am deleted file mode 100644 index 9c5c88dc..00000000 --- a/gnuradio-examples/python/gmsk2/Makefile.am +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright 2004 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 2, 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. -# - -EXTRA_DIST = \ - README \ - benchmark_gmsk_rx.py \ - benchmark_gmsk_tx.py \ - benchmark_mpsk_rx.py \ - benchmark_mpsk_tx.py \ - fusb_options.py \ - gen_whitener.py \ - gmsk_test.py \ - pick_bitrate.py \ - receive_path.py \ - transmit_path.py - - - - diff --git a/gnuradio-examples/python/gmsk2/README b/gnuradio-examples/python/gmsk2/README deleted file mode 100644 index b3c343e4..00000000 --- a/gnuradio-examples/python/gmsk2/README +++ /dev/null @@ -1,81 +0,0 @@ -Quick overview of what's here: - -* gmsk_test.py: stand-alone program that exercises the GMSK packet tx -and rx code. The two halves are connected with a simulated noisy -channel. It's easy to add extra instrumentation to log various internal -states. We used a variant of this code to get this working in the -first place. - -* benchmark_gmsk_tx.py: generates packets of the size you -specify and sends them across the air using the USRP. Known to work -well using the USRP with the Flex 400 transceiver daughterboard. -You can specify the bitrate to use with the -r command line -parameter. The default is 500k. Some machines will do 1M or more. - -* benchmark_gmsk_rx.py: the receiver half of benchmark_gmsk_tx.py. -Command line arguments are pretty much the same as tx. Works well -with a USRP and Flex 400 transceiver daughterboard. Will also work -with TVRX daugherboard, but you'll need to fiddle with the gain. See -below. Prints a summary of each packet received and keeps a running -total of packets received, and how many of them were error free. -There are two levels of error reporting going on. If the access code -(PN code) and header of a packet were properly detected, then you'll -get an output line. If the CRC32 of the payload was correct you get -"ok = True", else "ok = False". The "pktno" is extracted from the -received packet. If there are skipped numbers, you're missing some -packets. Be sure you've got a suitable antenna connected to the TX/RX -port on each board. A "70 cm" / 420 MHz antenna for a ham -handi-talkie works great. These are available at ham radio supplies, -etc. The boards need to be at least 3m apart. You can also try -experimenting with the rx gain (-g command line option). - -Generally speaking, I start the rx first on one machine, and then fire -up the tx on the other machine. The tx also supports a discontinous -transmission mode where it sends bursts of 5 packets and then waits 1 -second. This is useful for ensuring that all the receiver control -loops lock up fast enough. - -* tunnel.py: This program provides a framework for building your own -MACs. It creates a "TAP" interface in the kernel, typically gr0, -and sends and receives ethernet frames through it. See -/usr/src/linux/Documentation/networking/tuntap.txt and/or Google for -"universal tun tap". The Linux 2.6 kernel includes the tun module, you -don't have to build it. You may have to "modprobe tun" if it's not -loaded by default. If /dev/net/tun doesn't exist, try "modprobe tun". - -To run this program you'll need to be root or running with the -appropriate capability to open the tun interface. You'll need to fire -up two copies on different machines. Once each is running you'll need -to ifconfig the gr0 interface to set the IP address. - -This will allow two machines to talk, but anything beyond the two -machines depends on your networking setup. Left as an exercise... - -On machine A: - - $ su - # ./tunnel.py --freq 423.0M --bitrate 500k - # # in another window on A, also as root... - # ifconfig gr0 10.10.10.1 - - -On machine B: - - $ su - # ./tunnel.py --freq 423.0M --bitrate 500k - # # in another window on B, also as root... - # ifconfig gr0 10.10.10.2 - -Now, on machine A you shold be able to ping machine B: - - $ ping 10.10.10.2 - -and you should see some output for each packet in the -tunnel.py window if you used the -v option. - -Likewise, on machine B: - - $ ping 10.10.10.1 - -This now uses a carrier sense MAC, so you should be able to ssh -between the machines, web browse, etc. diff --git a/gnuradio-examples/python/gmsk2/benchmark_gmsk_rx.py b/gnuradio-examples/python/gmsk2/benchmark_gmsk_rx.py deleted file mode 100755 index f511e334..00000000 --- a/gnuradio-examples/python/gmsk2/benchmark_gmsk_rx.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005 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 2, 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, gru, blks -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -import random -import struct - -# from current dir -from receive_path import receive_path -import fusb_options - -#import os -#print os.getpid() -#raw_input('Attach and press enter') - - -class my_graph(gr.flow_graph): - - def __init__(self, demod_class, rx_subdev_spec, - bitrate, decim_rate, spb, - rx_callback, options, demod_kwargs): - gr.flow_graph.__init__(self) - self.rxpath = receive_path(self, demod_class, rx_subdev_spec, - bitrate, decim_rate, spb, - rx_callback, options, demod_kwargs) - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -global n_rcvd, n_right - -def main(): - global n_rcvd, n_right - - n_rcvd = 0 - n_right = 0 - - def rx_callback(ok, payload): - global n_rcvd, n_right - (pktno,) = struct.unpack('!H', payload[0:2]) - n_rcvd += 1 - if ok: - n_right += 1 - - print "ok = %r pktno = %4d n_rcvd = %4d n_right = %4d" % ( - ok, pktno, n_rcvd, n_right) - - parser = OptionParser (option_class=eng_option) - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, - help="select USRP Rx side A or B") - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Rx frequency to FREQ [default=%default]", - metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-g", "--rx-gain", type="eng_float", default=27, - help="set rx gain") - parser.add_option("-S", "--spb", type="int", default=None, - help="set samples/baud [default=%default]") - parser.add_option("-d", "--decim", type="intx", default=None, - help="set fpga decim rate to DECIM [default=%default]") - fusb_options.add_options(parser) - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - demod_kwargs = { } # placeholder - - # build the graph - fg = my_graph(blks.gmsk2_demod, - options.rx_subdev_spec, options.bitrate, - options.decim, options.spb, rx_callback, - options, demod_kwargs) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),) - print "spb: %3d" % (fg.rxpath.spb(),) - print "decim: %3d" % (fg.rxpath.decim(),) - - ok = fg.rxpath.set_freq(options.freq) - if not ok: - print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.freq),) - raise SystemExit - - fg.rxpath.set_gain(options.rx_gain) - print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", fg.rxpath.gain - - r = gr.enable_realtime_scheduling() - if r != gr.RT_OK: - print "Warning: Failed to enable realtime scheduling." - - fg.start() # start flow graph - fg.wait() # wait for it to finish - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py b/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py deleted file mode 100755 index 36bced29..00000000 --- a/gnuradio-examples/python/gmsk2/benchmark_gmsk_tx.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005,2006 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 2, 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, gru, blks -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -import random -import time -import struct -import sys - -# from current dir -from transmit_path import transmit_path -import fusb_options - -#import os -#print os.getpid() -#raw_input('Attach and press enter') - - -class my_graph(gr.flow_graph): - - def __init__(self, mod_class, tx_subdev_spec, - bitrate, interp_rate, spb, gain, - options, mod_kwargs): - gr.flow_graph.__init__(self) - self.txpath = transmit_path(self, mod_class, tx_subdev_spec, - bitrate, interp_rate, spb, gain, - options, mod_kwargs) - - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -def main(): - - def send_pkt(payload='', eof=False): - return fg.txpath.send_pkt(payload, eof) - - def rx_callback(ok, payload): - print "ok = %r, payload = '%s'" % (ok, payload) - - parser = OptionParser (option_class=eng_option) - parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, - help="select USRP Tx side A or B") - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Tx and Rx frequency to FREQ [default=%default]", - metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-S", "--spb", type="int", default=None, - help="set samples/baud [default=%default]") - parser.add_option("-i", "--interp", type="intx", default=None, - help="set fpga interpolation rate to INTERP [default=%default]") - parser.add_option("-s", "--size", type="eng_float", default=1500, - help="set packet size [default=%default]") - parser.add_option("", "--bt", type="float", default=0.3, - help="set bandwidth-time product [default=%default]") - parser.add_option("-g", "--gain", type="eng_float", default=100.0, - help="transmitter gain [default=%default]") - parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, - help="set megabytes to transmit [default=%default]") - parser.add_option("","--discontinuous", action="store_true", default=False, - help="enable discontinous transmission (bursts of 5 packets)") - fusb_options.add_options(parser) - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - pkt_size = int(options.size) - - mod_kwargs = { - 'bt' : options.bt, - } - - # build the graph - fg = my_graph(blks.gmsk2_mod, options.tx_subdev_spec, - options.bitrate, options.interp, options.spb, options.gain, - options, mod_kwargs) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) - print "spb: %3d" % (fg.txpath.spb(),) - print "interp: %3d" % (fg.txpath.interp(),) - - ok = fg.txpath.set_freq(options.freq) - if not ok: - print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(options.freq),) - raise SystemExit - - r = gr.enable_realtime_scheduling() - if r != gr.RT_OK: - print "Warning: failed to enable realtime scheduling" - - fg.start() # start flow graph - - # generate and send packets - nbytes = int(1e6 * options.megabytes) - n = 0 - pktno = 0 - - while n < nbytes: - send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) - n += pkt_size - sys.stderr.write('.') - if options.discontinuous and pktno % 5 == 4: - time.sleep(1) - pktno += 1 - - send_pkt(eof=True) - fg.wait() # wait for it to finish - fg.txpath.set_auto_tr(False) - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py b/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py deleted file mode 100755 index 9bb70106..00000000 --- a/gnuradio-examples/python/gmsk2/benchmark_mpsk_rx.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2006 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 2, 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, gru, blks -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -import random -import struct - -# from current dir -from bpsk import bpsk_demod -from dbpsk import dbpsk_demod -from dqpsk import dqpsk_demod -from receive_path import receive_path -import fusb_options - -if 1: - import os - print os.getpid() - raw_input('Attach and press enter') - - -class my_graph(gr.flow_graph): - - def __init__(self, demod_class, rx_subdev_spec, - bitrate, decim_rate, spb, - rx_callback, options, demod_kwargs): - gr.flow_graph.__init__(self) - self.rxpath = receive_path(self, demod_class, rx_subdev_spec, - bitrate, decim_rate, spb, - rx_callback, options, demod_kwargs) - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -global n_rcvd, n_right - -def main(): - global n_rcvd, n_right - - n_rcvd = 0 - n_right = 0 - - def rx_callback(ok, payload): - global n_rcvd, n_right - (pktno,) = struct.unpack('!H', payload[0:2]) - n_rcvd += 1 - if ok: - n_right += 1 - - print "ok = %r pktno = %4d n_rcvd = %4d n_right = %4d" % ( - ok, pktno, n_rcvd, n_right) - - parser = OptionParser (option_class=eng_option) - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, - help="select USRP Rx side A or B") - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Rx frequency to FREQ [default=%default]", - metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-S", "--spb", type="int", default=None, - help="set samples/baud [default=%default]") - parser.add_option("-d", "--decim", type="intx", default=None, - help="set fpga decim rate to DECIM [default=%default]") - parser.add_option("-m", "--modulation", type="string", default='dbpsk', - help="modulation type (bpsk, dbpsk, dqpsk) [default=%default]") - parser.add_option("", "--excess-bw", type="float", default=0.3, - help="set RRC excess bandwith factor [default=%default]") - parser.add_option("-g", "--gain", type="eng_float", default=27, - help="set rx gain") - parser.add_option("","--log", action="store_true", default=False, - help="enable diagnostic logging") - fusb_options.add_options(parser) - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - demod_kwargs = { - 'excess_bw' : options.excess_bw, - } - - #FIXME: Needs to be worked in to overall structure; this will be fixed - # once static class definitions for modulations are defined - if(options.modulation=='bpsk'): - modulation=bpsk_demod - elif(options.modulation=='dbpsk'): - modulation=dbpsk_demod - else: - modulation=dqpsk_demod - - # build the graph - fg = my_graph(modulation, - options.rx_subdev_spec, options.bitrate, - options.decim, options.spb, - rx_callback, options, demod_kwargs) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),) - print "spb: %3d" % (fg.rxpath.spb(),) - print "decim: %3d" % (fg.rxpath.decim(),) - - ok = fg.rxpath.set_freq(options.freq) - if not ok: - print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.freq),) - raise SystemExit - - fg.rxpath.set_gain(options.gain) - print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", fg.rxpath.gain - - r = gr.enable_realtime_scheduling() - if r != gr.RT_OK: - print "Warning: Failed to enable realtime scheduling." - - fg.start() # start flow graph - fg.wait() # wait for it to finish - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py b/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py deleted file mode 100755 index 2808f1d5..00000000 --- a/gnuradio-examples/python/gmsk2/benchmark_mpsk_tx.py +++ /dev/null @@ -1,157 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005, 2006 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 2, 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, gru, blks -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -import random, time, struct, sys - -# from current dir -from bpsk import bpsk_mod -from dbpsk import dbpsk_mod -from dqpsk import dqpsk_mod -from transmit_path import transmit_path -import fusb_options - -#import os -#print os.getpid() -#raw_input('Attach and press enter') - - -class my_graph(gr.flow_graph): - - def __init__(self, mod_class, tx_subdev_spec, - bitrate, interp_rate, spb, gain, - options, mod_kwargs): - gr.flow_graph.__init__(self) - self.txpath = transmit_path(self, mod_class, tx_subdev_spec, - bitrate, interp_rate, spb, gain, - options, mod_kwargs) - - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -def main(): - - def send_pkt(payload='', eof=False): - return fg.txpath.send_pkt(payload, eof) - - def rx_callback(ok, payload): - print "ok = %r, payload = '%s'" % (ok, payload) - - parser = OptionParser (option_class=eng_option) - parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, - help="select USRP Tx side A or B") - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Tx and Rx frequency to FREQ [default=%default]", - metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-S", "--spb", type="int", default=None, - help="set samples/baud [default=%default]") - parser.add_option("-i", "--interp", type="intx", default=None, - help="set fpga interpolation rate to INTERP [default=%default]") - parser.add_option("-s", "--size", type="eng_float", default=1500, - help="set packet size [default=%default]") - parser.add_option("-m", "--modulation", type="string", default='dbpsk', - help="modulation type (bpsk, dbpsk, dqpsk) [default=%default]") - parser.add_option("", "--excess-bw", type="float", default=0.3, - help="set RRC excess bandwith factor [default=%default]") - parser.add_option("-g", "--gain", type="eng_float", default=100.0, - help="transmitter gain [default=%default]") - parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, - help="set megabytes to transmit [default=%default]") - parser.add_option("","--discontinuous", action="store_true", default=False, - help="enable discontinous transmission (bursts of 5 packets)") - fusb_options.add_options(parser) - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - pkt_size = int(options.size) - - mod_kwargs = { - 'excess_bw' : options.excess_bw, - } - - #FIXME: rework when static class defintions are ready for the modulation types - if(options.modulation=='bpsk'): - modulation=bpsk_mod - elif( options.modulation=='dbpsk'): - modulation=dbpsk_mod - else: - modulation=dqpsk_mod - - # build the graph - fg = my_graph(modulation, - options.tx_subdev_spec, options.bitrate, options.interp, - options.spb, options.gain, - options, mod_kwargs) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) - print "spb: %3d" % (fg.txpath.spb(),) - print "interp: %3d" % (fg.txpath.interp(),) - - ok = fg.txpath.set_freq(options.freq) - if not ok: - print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(options.freq),) - raise SystemExit - - r = gr.enable_realtime_scheduling() - if r != gr.RT_OK: - print "Warning: failed to enable realtime scheduling" - - fg.start() # start flow graph - - # generate and send packets - nbytes = int(1e6 * options.megabytes) - n = 0 - pktno = 0 - - while n < nbytes: - send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) - n += pkt_size - sys.stderr.write('.') - if options.discontinuous and pktno % 5 == 4: - time.sleep(1) - pktno += 1 - - send_pkt(eof=True) - fg.wait() # wait for it to finish - fg.txpath.set_auto_tr(False) - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/bpsk.py b/gnuradio-examples/python/gmsk2/bpsk.py deleted file mode 100644 index dcf8a10b..00000000 --- a/gnuradio-examples/python/gmsk2/bpsk.py +++ /dev/null @@ -1,256 +0,0 @@ -# -# Copyright 2005,2006 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 2, 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. -# - -# See gnuradio-examples/python/gmsk2 for examples - -""" -BPSK modulation and demodulation. -""" - -from gnuradio import gr, gru -from math import pi, sqrt -import cmath -import Numeric -from pprint import pprint - -_use_gray_code = True - -def make_constellation(m): - return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)] - -# Common definition of constellations for Tx and Rx -constellation = { - 2 : make_constellation(2), # BPSK - 4 : make_constellation(4), # QPSK - 8 : make_constellation(8) # 8PSK - } - -if 0: - print "const(2) =" - pprint(constellation[2]) - print "const(4) =" - pprint(constellation[4]) - print "const(8) =" - pprint(constellation[8]) - - -if _use_gray_code: - # ----------------------- - # Do Gray code - # ----------------------- - # binary to gray coding - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 7, 6, 4, 5) - } - - # gray to binary - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 6, 7, 5, 4) - } -else: - # ----------------------- - # Don't Gray code - # ----------------------- - # identity mapping - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - # identity mapping - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - -# ///////////////////////////////////////////////////////////////////////////// -# mPSK mod/demod with steams of bytes as data i/o -# ///////////////////////////////////////////////////////////////////////////// - - -class bpsk_mod(gr.hier_block): - - def __init__(self, fg, spb, excess_bw): - """ - Hierarchical block for RRC-filtered BPSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - """ - if not isinstance(spb, int) or spb < 2: - raise TypeError, "sbp must be an integer >= 2" - self.spb = spb - - ntaps = 11 * spb - - bits_per_symbol = self.bits_per_baud() - arity = pow(2,bits_per_symbol) - print "bits_per_symbol =", bits_per_symbol - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) - - self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity]) - - # pulse shaping filter - self.rrc_taps = gr.firdes.root_raised_cosine( - spb, # gain (spb since we're interpolating by spb) - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps) - - # Connect - fg.connect(self.bytes2chunks, self.chunks2symbols, self.rrc_filter) - - if 1: - fg.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rrc.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - -class bpsk_demod__coherent_detection_of_psk(gr.hier_block): - def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05): - """ - Hierarchical block for RRC-filtered BPSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param costas_alpha: loop filter gain - @type costas_alphas: float - @param gain_mu: - @type gain_mu: float - """ - if spb < 2: - raise TypeError, "sbp must be >= 2" - self.spb = spb - - bits_per_symbol = self.bits_per_baud() - arity = pow(2,bits_per_symbol) - print "bits_per_symbol =", bits_per_symbol - - # Automatic gain control - self.preamp = gr.multiply_const_cc(10e-5) - self.agc = gr.agc_cc(1e-3, 1, 1) - - # Costas loop (carrier tracking) - # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? - costas_order = 2 - costas_alpha *= 15 # 2nd order loop needs more gain - beta = .25 * costas_alpha * costas_alpha - self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, costas_order) - - # RRC data filter - ntaps = 11 * spb - self.rrc_taps = gr.firdes.root_raised_cosine( - 1.0, # gain - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) - - # symbol clock recovery - omega = spb - gain_omega = .25 * gain_mu * gain_mu - omega_rel_limit = 0.5 - mu = 0.05 - gain_mu = 0.1 - self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, - mu, gain_mu, omega_rel_limit) - - # find closest constellation point - #rot = .707 + .707j - rot = 1 - rotated_const = map(lambda pt: pt * rot, constellation[arity]) - print "rotated_const =", rotated_const - - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - self.gray_decoder = gr.map_bb(gray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(bits_per_symbol) - - fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - self.slicer, self.gray_decoder, self.unpack) - - # Debug sinks - if 1: - fg.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) - fg.connect(self.costas_loop, - gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) - fg.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rrc.dat")) - fg.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) - fg.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) - fg.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "unpack.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.preamp, self.unpack) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - -bpsk_demod = bpsk_demod__coherent_detection_of_psk - diff --git a/gnuradio-examples/python/gmsk2/dbpsk.py b/gnuradio-examples/python/gmsk2/dbpsk.py deleted file mode 100644 index 7d2765df..00000000 --- a/gnuradio-examples/python/gmsk2/dbpsk.py +++ /dev/null @@ -1,282 +0,0 @@ -# -# Copyright 2005,2006 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 2, 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. -# - -# See gnuradio-examples/python/gmsk2 for examples - -""" -differential BPSK modulation and demodulation. -""" - -from gnuradio import gr, gru -from math import pi, sqrt -import cmath -import Numeric -from pprint import pprint - -_use_gray_code = True - -def make_constellation(m): - return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)] - -# Common definition of constellations for Tx and Rx -constellation = { - 2 : make_constellation(2), # BPSK - 4 : make_constellation(4), # QPSK - 8 : make_constellation(8) # 8PSK - } - -if 0: - print "const(2) =" - pprint(constellation[2]) - print "const(4) =" - pprint(constellation[4]) - print "const(8) =" - pprint(constellation[8]) - - -if _use_gray_code: - # ----------------------- - # Do Gray code - # ----------------------- - # binary to gray coding - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 7, 6, 4, 5) - } - - # gray to binary - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 6, 7, 5, 4) - } -else: - # ----------------------- - # Don't Gray code - # ----------------------- - # identity mapping - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - # identity mapping - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - -# ///////////////////////////////////////////////////////////////////////////// -# BPSK mod/demod with steams of bytes as data i/o -# ///////////////////////////////////////////////////////////////////////////// - - -class dbpsk_mod(gr.hier_block): - - def __init__(self, fg, spb, excess_bw): - """ - Hierarchical block for RRC-filtered QPSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - """ - if not isinstance(spb, int) or spb < 2: - raise TypeError, "sbp must be an integer >= 2" - self.spb = spb - - ntaps = 11 * spb - - bits_per_symbol = self.bits_per_baud() - arity = pow(2,bits_per_symbol) - self.bits_per_symbol = bits_per_symbol - print "bits_per_symbol =", bits_per_symbol - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) - - if True: - self.gray_coder = gr.map_bb(binary_to_gray[arity]) - else: - self.gray_coder = None - - self.diffenc = gr.diff_encoder_bb(arity) - - self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity]) - - # pulse shaping filter - self.rrc_taps = gr.firdes.root_raised_cosine( - spb, # gain (spb since we're interpolating by spb) - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps) - - # Connect - if self.gray_coder: - fg.connect(self.bytes2chunks, self.gray_coder) - t = self.gray_coder - else: - t = self.bytes2chunks - - fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter) - - if 1: - fg.connect(self.gray_coder, - gr.file_sink(gr.sizeof_char, "graycoder.dat")) - fg.connect(self.diffenc, - gr.file_sink(gr.sizeof_char, "diffenc.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - - -class dbpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block): - def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05): - """ - Hierarchical block for RRC-filtered BPSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param costas_alpha: loop filter gain - @type costas_alphas: float - @param gain_mu: - @type gain_mu: float - """ - if spb < 2: - raise TypeError, "sbp must be >= 2" - self.spb = spb - - bits_per_symbol = self.bits_per_baud() - arity = pow(2,bits_per_symbol) - print "bits_per_symbol =", bits_per_symbol - - # Automatic gain control - self.preamp = gr.multiply_const_cc(10e-5) - self.agc = gr.agc_cc(1e-3, 1, 1, 1000) - - # Costas loop (carrier tracking) - # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? - costas_order = 2 - costas_alpha *= 15 # 2nd order loop needs more gain - beta = .25 * costas_alpha * costas_alpha - self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, costas_order) - - # RRC data filter - ntaps = 11 * spb - self.rrc_taps = gr.firdes.root_raised_cosine( - 1.0, # gain - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) - - # symbol clock recovery - omega = spb - gain_omega = .25 * gain_mu * gain_mu - omega_rel_limit = 0.5 - mu = 0.05 - gain_mu = 0.1 - self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, - mu, gain_mu, omega_rel_limit) - - # find closest constellation point - #rot = .707 + .707j - rot = 1 - rotated_const = map(lambda pt: pt * rot, constellation[arity]) - print "rotated_const =", rotated_const - - self.diffdec = gr.diff_phasor_cc() - #self.diffdec = gr.diff_decoder_bb(arity) - - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - self.gray_decoder = gr.map_bb(gray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(bits_per_symbol) - - fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - self.diffdec, self.slicer, self.gray_decoder, self.unpack) - #fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - # self.slicer, self.diffdec, self.gray_decoder, self.unpack) - - # Debug sinks - if 1: - fg.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) - fg.connect(self.costas_loop, - gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) - fg.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rrc.dat")) - fg.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) - fg.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) - fg.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat")) - #fg.connect(self.diffdec, - # gr.file_sink(gr.sizeof_char, "diffdec.dat")) - fg.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "unpack.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.preamp, self.unpack) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 1 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - -dbpsk_demod = dbpsk_demod__coherent_detection_of_differentially_encoded_psk - diff --git a/gnuradio-examples/python/gmsk2/dqpsk.py b/gnuradio-examples/python/gmsk2/dqpsk.py deleted file mode 100644 index a18f28b7..00000000 --- a/gnuradio-examples/python/gmsk2/dqpsk.py +++ /dev/null @@ -1,280 +0,0 @@ -# -# Copyright 2005,2006 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 2, 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. -# - -# See gnuradio-examples/python/gmsk2 for examples - -""" -differential QPSK modulation and demodulation. -""" - -from gnuradio import gr, gru -from math import pi, sqrt -import cmath -import Numeric -from pprint import pprint - -_use_gray_code = True - -def make_constellation(m): - return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)] - -# Common definition of constellations for Tx and Rx -constellation = { - 2 : make_constellation(2), # BPSK - 4 : make_constellation(4), # QPSK - 8 : make_constellation(8) # 8PSK - } - -if 0: - print "const(2) =" - pprint(constellation[2]) - print "const(4) =" - pprint(constellation[4]) - print "const(8) =" - pprint(constellation[8]) - - -if _use_gray_code: - # ----------------------- - # Do Gray code - # ----------------------- - # binary to gray coding - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 7, 6, 4, 5) - } - - # gray to binary - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 6, 7, 5, 4) - } -else: - # ----------------------- - # Don't Gray code - # ----------------------- - # identity mapping - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - # identity mapping - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - -# ///////////////////////////////////////////////////////////////////////////// -# QPSK mod/demod with steams of bytes as data i/o -# ///////////////////////////////////////////////////////////////////////////// - - -class dqpsk_mod(gr.hier_block): - - def __init__(self, fg, spb, excess_bw): - """ - Hierarchical block for RRC-filtered QPSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - """ - if not isinstance(spb, int) or spb < 2: - raise TypeError, "sbp must be an integer >= 2" - self.spb = spb - - ntaps = 11 * spb - - bits_per_symbol = self.bits_per_baud() - arity = pow(2,bits_per_symbol) - print "bits_per_symbol =", bits_per_symbol - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) - - if True: - self.gray_coder = gr.map_bb(binary_to_gray[arity]) - else: - self.gray_coder = None - - self.diffenc = gr.diff_encoder_bb(arity) - - self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity]) - - # pulse shaping filter - self.rrc_taps = gr.firdes.root_raised_cosine( - spb, # gain (spb since we're interpolating by spb) - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps) - - # Connect - if self.gray_coder: - fg.connect(self.bytes2chunks, self.gray_coder) - t = self.gray_coder - else: - t = self.bytes2chunks - - fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter) - - if 1: - fg.connect(self.gray_coder, - gr.file_sink(gr.sizeof_char, "graycoder.dat")) - fg.connect(self.diffenc, - gr.file_sink(gr.sizeof_char, "diffenc.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 2 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - - -class dqpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block): - def __init__(self, fg, spb, excess_bw, costas_alpha=0.005, gain_mu=0.05): - """ - Hierarchical block for RRC-filtered QPSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param costas_alpha: loop filter gain - @type costas_alphas: float - @param gain_mu: - @type gain_mu: float - """ - if spb < 2: - raise TypeError, "sbp must be >= 2" - self.spb = spb - - bits_per_symbol = self.bits_per_baud() - arity = pow(2,bits_per_symbol) - print "bits_per_symbol =", bits_per_symbol - - # Automatic gain control - self.preamp = gr.multiply_const_cc(10e-5) - self.agc = gr.agc_cc(1e-3, 1, 1) - - # Costas loop (carrier tracking) - # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? - costas_order = 4 - beta = .25 * costas_alpha * costas_alpha - self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, costas_order) - - # RRC data filter - ntaps = 11 * spb - self.rrc_taps = gr.firdes.root_raised_cosine( - 1.0, # gain - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) - - # symbol clock recovery - omega = spb - gain_omega = .25 * gain_mu * gain_mu - omega_rel_limit = 0.5 - mu = 0.05 - gain_mu = 0.1 - self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, - mu, gain_mu, omega_rel_limit) - - # find closest constellation point - #rot = .707 + .707j - rot = 1 - rotated_const = map(lambda pt: pt * rot, constellation[arity]) - print "rotated_const =", rotated_const - - self.diffdec = gr.diff_phasor_cc() - #self.diffdec = gr.diff_decoder_bb(arity) - - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - self.gray_decoder = gr.map_bb(gray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(bits_per_symbol) - - fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - self.diffdec, self.slicer, self.gray_decoder, self.unpack) - #fg.connect(self.preamp, self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - # self.slicer, self.diffdec, self.gray_decoder, self.unpack) - - # Debug sinks - if 1: - fg.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) - fg.connect(self.costas_loop, - gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) - fg.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rrc.dat")) - fg.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) - fg.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) - fg.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat")) - #fg.connect(self.diffdec, - # gr.file_sink(gr.sizeof_char, "diffdec.dat")) - fg.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "unpack.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.preamp, self.unpack) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self=None): # staticmethod that's also callable on an instance - return 2 - bits_per_baud = staticmethod(bits_per_baud) # make it a static method. RTFM - - -dqpsk_demod = dqpsk_demod__coherent_detection_of_differentially_encoded_psk - diff --git a/gnuradio-examples/python/gmsk2/fusb_options.py b/gnuradio-examples/python/gmsk2/fusb_options.py deleted file mode 100644 index cdb15d72..00000000 --- a/gnuradio-examples/python/gmsk2/fusb_options.py +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright 2006 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 2, 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. -# - -def add_options(parser): - """ - Add Fast USB specifc options to command line parser. - - @param parser: instance of OptionParser - """ - parser.add_option("-B", "--fusb-block-size", type="int", default=0, - help="specify fast usb block size [default=%default]") - parser.add_option("-N", "--fusb-nblocks", type="int", default=0, - help="specify number of fast usb blocks [default=%default]") diff --git a/gnuradio-examples/python/gmsk2/gen_whitener.py b/gnuradio-examples/python/gmsk2/gen_whitener.py deleted file mode 100755 index 93aea2b8..00000000 --- a/gnuradio-examples/python/gmsk2/gen_whitener.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python - -from gnuradio import gr, gru -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import sys - -class my_graph(gr.flow_graph): - - def __init__(self): - gr.flow_graph.__init__(self) - - parser = OptionParser(option_class=eng_option) - (options, args) = parser.parse_args () - if len(args) != 0: - parser.print_help() - raise SystemExit, 1 - - src = gr.lfsr_32k_source_s() - head = gr.head(gr.sizeof_short, 2048) - self.dst = gr.vector_sink_s() - self.connect(src, head, self.dst) - -if __name__ == '__main__': - try: - fg = my_graph() - fg.run() - f = sys.stdout - i = 0 - for s in fg.dst.data(): - f.write("%3d, " % (s & 0xff,)) - f.write("%3d, " % ((s >> 8) & 0xff,)) - i = i+2 - if i % 16 == 0: - f.write('\n') - - except KeyboardInterrupt: - pass - - diff --git a/gnuradio-examples/python/gmsk2/gmsk_test.py b/gnuradio-examples/python/gmsk2/gmsk_test.py deleted file mode 100755 index 7ae69a0a..00000000 --- a/gnuradio-examples/python/gmsk2/gmsk_test.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python - -from gnuradio import gr, blks -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import random -import struct - -#import os -#print os.getpid() -#raw_input('Attach and press enter') - - -class my_graph(gr.flow_graph): - - def __init__(self, rx_callback, spb, bt, SNR, freq_error): - gr.flow_graph.__init__(self) - - fg = self - - # Tuning Parameters - gain_mu = 0.002*spb - omega = spb*(1+freq_error) - - # transmitter - self.packet_transmitter = blks.gmsk2_mod_pkts(fg, spb=spb, bt=bt) - - # add some noise - add = gr.add_cc() - noise = gr.noise_source_c(gr.GR_GAUSSIAN, pow(10.0,-SNR/20.0)) - - # channel filter - rx_filt_taps = gr.firdes.low_pass(1,spb,0.8,0.1,gr.firdes.WIN_HANN) - rx_filt = gr.fir_filter_ccf(1,rx_filt_taps) - - # receiver - self.packet_receiver = blks.gmsk2_demod_pkts(fg, callback=rx_callback, - spb=spb, gain_mu=gain_mu, - freq_error=freq_error, omega=omega) - - fg.connect (self.packet_transmitter, (add,0)) - fg.connect (noise, (add,1)) - fg.connect(add, rx_filt, self.packet_receiver) - - -class stats(object): - def __init__(self): - self.npkts = 0 - self.nright = 0 - -def main(): - st = stats() - - def send_pkt(payload='', eof=False): - fg.packet_transmitter.send_pkt(payload, eof) - - def rx_callback(ok, payload): - st.npkts += 1 - if ok: - st.nright += 1 - if len(payload) <= 16: - print "ok = %5r payload = '%s' %d/%d" % (ok, payload, st.nright, st.npkts) - else: - (pktno,) = struct.unpack('!H', payload[0:2]) - print "ok = %5r pktno = %4d len(payload) = %4d %d/%d" % (ok, pktno, len(payload), - st.nright, st.npkts) - - - parser = OptionParser (option_class=eng_option) - parser.add_option("-M", "--megabytes", type="eng_float", default=1, - help="set megabytes to transmit [default=%default]") - parser.add_option("-s", "--size", type="eng_float", default=1500, - help="set packet size [default=%default]") - parser.add_option("","--spb", type=int, default=4, - help="set samples per baud to SPB [default=%default]") - parser.add_option("", "--bt", type="eng_float", default=0.3, - help="set bandwidth time product for Gaussian filter [default=%default]") - parser.add_option("", "--snr", type="eng_float", default=20, - help="set SNR in dB for simulation [default=%default]") - parser.add_option("", "--freq-error", type="eng_float", default=0, - help="set frequency error for simulation [default=%default]") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - pkt_size = int(options.size) - - fg = my_graph(rx_callback, options.spb, options.bt, options.snr, options.freq_error) - fg.start() - - nbytes = int(1e6 * options.megabytes) - n = 0 - pktno = 0 - - send_pkt('Hello World') - - # generate and send packets - while n < nbytes: - send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) - n += pkt_size - pktno += 1 - - send_pkt('Goodbye World') - send_pkt(eof=True) # tell modulator we're not sending any more pkts - - fg.wait() - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/mpsk_test.py b/gnuradio-examples/python/gmsk2/mpsk_test.py deleted file mode 100755 index 1f257d9c..00000000 --- a/gnuradio-examples/python/gmsk2/mpsk_test.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python - -from gnuradio import gr, blks -from gnuradio.eng_option import eng_option -from optparse import OptionParser -import random -import struct -from mpsk_pkt import * -import cmath - -class my_graph(gr.flow_graph): - - def __init__(self, rx_callback, spb, excess_bw, SNR, freq_error, arity): - gr.flow_graph.__init__(self) - - fg = self - - # Tuning Parameters - gain_mu = 0.05/spb - - # transmitter - self.packet_transmitter = \ - mpsk_mod_pkts(fg, spb=spb, excess_bw=excess_bw, diff=True, arity=arity) - - # ---------------------------------------------------------------- - # Channel model - # ---------------------------------------------------------------- - - awgn = gr.noise_source_c(gr.GR_GAUSSIAN, pow(10.0,-SNR/20.0)) - add = gr.add_cc() # add some noise - fg.connect(awgn, (add,1)) - radians = 17*pi/180 - phase_rotate = gr.multiply_const_cc(cmath.exp(radians * 1j)) - - # ---------------------------------------------------------------- - - # channel filter - rx_filt_taps = gr.firdes.low_pass(1,spb,0.8,0.1,gr.firdes.WIN_HANN) - #rx_filt_taps = (1,) - rx_filt = gr.fir_filter_ccf(1,rx_filt_taps) - - # receiver - self.packet_receiver = \ - mpsk_demod_pkts(fg, callback=rx_callback, - excess_bw=excess_bw, arity=arity, diff=True, - costas_alpha=.005, gain_mu=gain_mu, spb=spb) - - fg.connect (self.packet_transmitter, (add,0)) - fg.connect(add, phase_rotate, rx_filt, self.packet_receiver) - - -class stats(object): - def __init__(self): - self.npkts = 0 - self.nright = 0 - -def main(): - st = stats() - - def send_pkt(payload='', eof=False): - fg.packet_transmitter.send_pkt(payload, eof) - - def rx_callback(ok, payload): - st.npkts += 1 - if ok: - st.nright += 1 - if len(payload) <= 16: - print "ok = %5r payload = '%s' %d/%d" % (ok, payload, st.nright, st.npkts) - else: - (pktno,) = struct.unpack('!H', payload[0:2]) - print "ok = %5r pktno = %4d len(payload) = %4d %d/%d" % (ok, pktno, len(payload), - st.nright, st.npkts) - - - parser = OptionParser (option_class=eng_option) - parser.add_option("-M", "--megabytes", type="eng_float", default=1, - help="set megabytes to transmit [default=%default]") - parser.add_option("-s", "--size", type="eng_float", default=1500, - help="set packet size [default=%default]") - parser.add_option("","--spb", type=int, default=4, - help="set samples per baud to SPB [default=%default]") - parser.add_option("", "--excess-bw", type="eng_float", default=0.4, - help="set excess bandwidth for RRC filter [default=%default]") - parser.add_option("", "--snr", type="eng_float", default=40, - help="set SNR in dB for simulation [default=%default]") - parser.add_option("", "--m-arity", type=int, default=4, - help="PSK arity [default=%default]") - parser.add_option("", "--freq-error", type="eng_float", default=0, - help="set frequency error for simulation [default=%default]") - - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - pkt_size = int(options.size) - - fg = my_graph(rx_callback, options.spb, options.excess_bw, options.snr, - options.freq_error, options.m_arity) - fg.start() - - nbytes = int(1e6 * options.megabytes) - n = 0 - pktno = 0 - - send_pkt('Hello World') - - # generate and send packets - while n < nbytes: - send_pkt(struct.pack('!H', pktno) + (pkt_size - 2) * chr(pktno & 0xff)) - n += pkt_size - pktno += 1 - - send_pkt('Goodbye World') - send_pkt(eof=True) # tell modulator we're not sending any more pkts - - fg.wait() - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/pick_bitrate.py b/gnuradio-examples/python/gmsk2/pick_bitrate.py deleted file mode 100644 index 35074f1d..00000000 --- a/gnuradio-examples/python/gmsk2/pick_bitrate.py +++ /dev/null @@ -1,143 +0,0 @@ -# -# Copyright 2005 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 2, 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. -# - -_default_bitrate = 500e3 - -_valid_spbs = (2,3,4,5,6,7) - -def _gen_tx_info(converter_rate): - results = [] - for spb in _valid_spbs: - for interp in range(16, 512 + 1, 4): - bitrate = converter_rate / interp / spb - results.append((bitrate, spb, interp)) - results.sort() - return results - -def _gen_rx_info(converter_rate): - results = [] - for spb in _valid_spbs: - for decim in range(8, 256 + 1, 2): - bitrate = converter_rate / decim / spb - results.append((bitrate, spb, decim)) - results.sort() - return results - -def _filter_info(info, samples_per_baud, xrate): - if samples_per_baud is not None: - info = [x for x in info if x[1] == samples_per_baud] - if xrate is not None: - info = [x for x in info if x[2] == xrate] - return info - -def _pick_best(target_bitrate, bits_per_symbol, info): - """ - @returns tuple (bitrate, samples_per_baud, interp_rate_or_decim_rate) - """ - if len(info) == 0: - raise RuntimeError, "info is zero length!" - - if target_bitrate is None: # return the fastest one - return info[-1] - - # convert bit rate to symbol rate - target_symbolrate = target_bitrate / bits_per_symbol - - # Find the closest matching symbol rate. - # In the event of a tie, the one with the lowest samples_per_baud wins. - # (We already sorted them, so the first one is the one we take) - - best = info[0] - best_delta = abs(target_symbolrate - best[0]) - for x in info[1:]: - delta = abs(target_symbolrate - x[0]) - if delta < best_delta: - best_delta = delta - best = x - - # convert symbol rate back to bit rate - return ((best[0] * bits_per_symbol),) + best[1:] - -def _pick_bitrate(bitrate, bits_per_symbol, samples_per_baud, - xrate, converter_rate, gen_info): - """ - @returns tuple (bitrate, samples_per_baud, interp_rate_or_decim_rate) - """ - if not isinstance(bits_per_symbol, int) or bits_per_symbol < 1: - raise ValueError, "bits_per_symbol must be an int >= 1" - - if samples_per_baud is not None and xrate is not None: # completely determined - return (float(converter_rate) / xrate / samples_per_baud, - samples_per_baud, xrate) - - if bitrate is None and samples_per_baud is None and xrate is None: - bitrate = _default_bitrate - - # now we have a target bitrate and possibly an xrate or - # samples_per_baud constraint, but not both of them. - - return _pick_best(bitrate, bits_per_symbol, - _filter_info(gen_info(converter_rate), samples_per_baud, xrate)) - -# --------------------------------------------------------------------------------------- - -def pick_tx_bitrate(bitrate, bits_per_symbol, samples_per_baud, - interp_rate, converter_rate=128e6): - """ - Given the 4 input parameters, return at configuration that matches - - @param bitrate: desired bitrate or None - @type bitrate: number or None - @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3 - @type bits_per_symbol: integer >= 1 - @param samples_per_baud: samples/baud (aka samples/symbol) - @type samples_per_baud: number or None - @param interp_rate: USRP interpolation factor - @type interp_rate: integer or None - @param converter_rate: converter sample rate in Hz - @type converter_rate: number - - @returns tuple (bitrate, samples_per_baud, interp_rate) - """ - return _pick_bitrate(bitrate, bits_per_symbol, samples_per_baud, - interp_rate, converter_rate, _gen_tx_info) - - -def pick_rx_bitrate(bitrate, bits_per_symbol, samples_per_baud, - decim_rate, converter_rate=64e6): - """ - Given the 4 input parameters, return at configuration that matches - - @param bitrate: desired bitrate or None - @type bitrate: number or None - @param bits_per_symbol: E.g., BPSK -> 1, QPSK -> 2, 8-PSK -> 3 - @type bits_per_symbol: integer >= 1 - @param samples_per_baud: samples/baud (aka samples/symbol) - @type samples_per_baud: number or None - @param decim_rate: USRP decimation factor - @type decim_rate: integer or None - @param converter_rate: converter sample rate in Hz - @type converter_rate: number - - @returns tuple (bitrate, samples_per_baud, decim_rate) - """ - return _pick_bitrate(bitrate, bits_per_symbol, samples_per_baud, - decim_rate, converter_rate, _gen_rx_info) diff --git a/gnuradio-examples/python/gmsk2/qpsk.py b/gnuradio-examples/python/gmsk2/qpsk.py deleted file mode 100644 index 26d95ed7..00000000 --- a/gnuradio-examples/python/gmsk2/qpsk.py +++ /dev/null @@ -1,418 +0,0 @@ -# -# Copyright 2005,2006 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 2, 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. -# - -# See gnuradio-examples/python/gmsk2 for examples - -""" -PSK and differential PSK modulation and demodulation. -""" - -from gnuradio import gr, gru -from math import pi, sqrt -import cmath -import Numeric -from pprint import pprint - -_use_gray_code = True - -def make_constellation(m): - return [cmath.exp(i * 2 * pi / m * 1j) for i in range(m)] - -# Common definition of constellations for Tx and Rx -constellation = { - 2 : make_constellation(2), # BPSK - 4 : make_constellation(4), # QPSK - 8 : make_constellation(8) # 8PSK - } - -if 0: - print "const(2) =" - pprint(constellation[2]) - print "const(4) =" - pprint(constellation[4]) - print "const(8) =" - pprint(constellation[8]) - - -if _use_gray_code: - # ----------------------- - # Do Gray code - # ----------------------- - # binary to gray coding - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 7, 6, 4, 5) - } - - # gray to binary - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 3, 2), - 8 : (0, 1, 3, 2, 6, 7, 5, 4) - } -else: - # ----------------------- - # Don't Gray code - # ----------------------- - # identity mapping - binary_to_gray = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - # identity mapping - gray_to_binary = { - 2 : (0, 1), - 4 : (0, 1, 2, 3), - 8 : (0, 1, 2, 3, 4, 5, 6, 7) - } - - -# ///////////////////////////////////////////////////////////////////////////// -# mPSK mod/demod with steams of bytes as data i/o -# ///////////////////////////////////////////////////////////////////////////// - - -class mpsk_mod(gr.hier_block): - - def __init__(self, fg, spb, arity, excess_bw, diff=False): - """ - Hierarchical block for RRC-filtered PSK modulation. - - The input is a byte stream (unsigned char) and the - output is the complex modulated signal at baseband. - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: integer - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param arity: whick PSK: 2, 4, 8 - @type arity: int in {2, 4, 8} - @param diff: differential PSK if true - @type diff: bool - """ - if not isinstance(spb, int) or spb < 2: - raise TypeError, "sbp must be an integer >= 2" - self.spb = spb - - if not arity in (2, 4): - raise ValueError, "n must be 2, 4, or 8" - - ntaps = 11 * spb - - bits_per_symbol = int(gru.log2(arity)) - self.bits_per_symbol = bits_per_symbol - print "bits_per_symbol =", bits_per_symbol - - # turn bytes into k-bit vectors - self.bytes2chunks = \ - gr.packed_to_unpacked_bb(bits_per_symbol, gr.GR_MSB_FIRST) - - if True or arity > 2: - self.gray_coder = gr.map_bb(binary_to_gray[arity]) - else: - self.gray_coder = None - - if diff: - self.diffenc = gr.diff_encoder_bb(arity) - else: - self.diffenc = None - - self.chunks2symbols = gr.chunks_to_symbols_bc(constellation[arity]) - - # pulse shaping filter - self.rrc_taps = gr.firdes.root_raised_cosine( - spb, # gain (spb since we're interpolating by spb) - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter = gr.interp_fir_filter_ccf(spb, self.rrc_taps) - - # Connect - if self.gray_coder: - fg.connect(self.bytes2chunks, self.gray_coder) - t = self.gray_coder - else: - t = self.bytes2chunks - - if diff: - fg.connect(t, self.diffenc, self.chunks2symbols, self.rrc_filter) - else: - fg.connect(t, self.chunks2symbols, self.rrc_filter) - - if 1: - fg.connect(self.gray_coder, - gr.file_sink(gr.sizeof_char, "graycoder.dat")) - if diff: - fg.connect(self.diffenc, - gr.file_sink(gr.sizeof_char, "diffenc.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.bytes2chunks, self.rrc_filter) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self): - return self.bits_per_symbol - - -class mpsk_demod__coherent_detection_of_differentially_encoded_psk(gr.hier_block): - def __init__(self, fg, spb, arity, excess_bw, diff=False, costas_alpha=0.005, gain_mu=0.05): - """ - Hierarchical block for RRC-filtered PSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param arity: whick PSK: 2, 4, 8 - @type arity: int in {2, 4, 8} - @param diff: differential PSK if true - @type diff: bool - @param costas_alpha: loop filter gain - @type costas_alphas: float - @param gain_mu: - @type gain_mu: float - """ - if spb < 2: - raise TypeError, "sbp must be >= 2" - self.spb = spb - - if not arity in (2, 4): - raise ValueError, "n must be 2 or 4" - - if not diff and arity==4: - raise NotImplementedError, "non-differential QPSK not supported yet" - - bits_per_symbol = int(gru.log2(arity)) - print "bits_per_symbol =", bits_per_symbol - - # Automatic gain control - self.agc = gr.agc_cc(1e-3, 1, 1) - - # Costas loop (carrier tracking) - # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? - if arity == 2: - costas_order = 2 - costas_alpha *= 15 # 2nd order loop needs more gain - else: - costas_order = 4 - beta = .25 * costas_alpha * costas_alpha - self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, costas_order) - - # RRC data filter - ntaps = 11 * spb - self.rrc_taps = gr.firdes.root_raised_cosine( - 1.0, # gain - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) - - # symbol clock recovery - omega = spb - gain_omega = .25 * gain_mu * gain_mu - omega_rel_limit = 0.5 - mu = 0.05 - gain_mu = 0.1 - self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, - mu, gain_mu, omega_rel_limit) - - # find closest constellation point - #rot = .707 + .707j - rot = 1 - rotated_const = map(lambda pt: pt * rot, constellation[arity]) - print "rotated_const =", rotated_const - - if(diff): - self.diffdec = gr.diff_phasor_cc() - #self.diffdec = gr.diff_decoder_bb(arity) - - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - self.gray_decoder = gr.map_bb(gray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(bits_per_symbol) - - if(diff): - fg.connect(self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - self.diffdec, self.slicer, self.gray_decoder, self.unpack) - else: - fg.connect(self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - self.slicer, self.gray_decoder, self.unpack) - - #fg.connect(self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - # self.slicer, self.diffdec, self.gray_decoder, self.unpack) - - # Debug sinks - if 1: - fg.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) - fg.connect(self.costas_loop, - gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) - fg.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rrc.dat")) - fg.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) - fg.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) - if(diff): - fg.connect(self.diffdec, - gr.file_sink(gr.sizeof_gr_complex, "diffdec.dat")) - #fg.connect(self.diffdec, - # gr.file_sink(gr.sizeof_char, "diffdec.dat")) - fg.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "unpack.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.agc, self.unpack) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self): - return self.bits_per_symbol - - -######################################################################### - -class mpsk_demod__coherent_detection_of_nondifferentially_encoded_psk(gr.hier_block): - def __init__(self, fg, spb, arity, excess_bw, diff=False, costas_alpha=0.005, gain_mu=0.05): - """ - Hierarchical block for RRC-filtered PSK demodulation - - The input is the complex modulated signal at baseband. - The output is a stream of bits packed 1 bit per byte (LSB) - - @param fg: flow graph - @type fg: flow graph - @param spb: samples per baud >= 2 - @type spb: float - @param excess_bw: Root-raised cosine filter excess bandwidth - @type excess_bw: float - @param arity: whick PSK: 2, 4, 8 - @type arity: int in {2, 4, 8} - @param diff: differential PSK if true - @type diff: bool - @param costas_alpha: loop filter gain - @type costas_alphas: float - @param gain_mu: - @type gain_mu: float - """ - if spb < 2: - raise TypeError, "sbp must be >= 2" - self.spb = spb - - if not arity in (2, 4): - raise ValueError, "n must be 2 or 4" - - bits_per_symbol = int(gru.log2(arity)) - print "bits_per_symbol =", bits_per_symbol - - # Automatic gain control - self.agc = gr.agc_cc(1e-3, 1, 1) - - # Costas loop (carrier tracking) - # FIXME: need to decide how to handle this more generally; do we pull it from higher layer? - if arity == 2: - costas_order = 2 - costas_alpha *= 15 # 2nd order loop needs more gain - else: - costas_order = 4 - beta = .25 * costas_alpha * costas_alpha - self.costas_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, costas_order) - - # RRC data filter - ntaps = 11 * spb - self.rrc_taps = gr.firdes.root_raised_cosine( - 1.0, # gain - spb, # sampling rate - 1.0, # symbol rate - excess_bw, # excess bandwidth (roll-off factor) - ntaps) - - self.rrc_filter=gr.fir_filter_ccf(1, self.rrc_taps) - - # symbol clock recovery - omega = spb - gain_omega = .25 * gain_mu * gain_mu - omega_rel_limit = 0.5 - mu = 0.05 - gain_mu = 0.1 - self.clock_recovery=gr.clock_recovery_mm_cc(omega, gain_omega, - mu, gain_mu, omega_rel_limit) - - # find closest constellation point - #rot = .707 + .707j - rot = 1 - rotated_const = map(lambda pt: pt * rot, constellation[arity]) - print "rotated_const =", rotated_const - - self.slicer = gr.constellation_decoder_cb(rotated_const, range(arity)) - self.gray_decoder = gr.map_bb(gray_to_binary[arity]) - - # unpack the k bit vector into a stream of bits - self.unpack = gr.unpack_k_bits_bb(bits_per_symbol) - - fg.connect(self.agc, self.costas_loop, self.rrc_filter, self.clock_recovery, - self.slicer, self.gray_decoder, self.unpack) - - # Debug sinks - if 1: - fg.connect(self.agc, - gr.file_sink(gr.sizeof_gr_complex, "agc.dat")) - fg.connect(self.costas_loop, - gr.file_sink(gr.sizeof_gr_complex, "costas_loop.dat")) - fg.connect(self.rrc_filter, - gr.file_sink(gr.sizeof_gr_complex, "rrc.dat")) - fg.connect(self.clock_recovery, - gr.file_sink(gr.sizeof_gr_complex, "clock_recovery.dat")) - fg.connect(self.slicer, - gr.file_sink(gr.sizeof_char, "slicer.dat")) - fg.connect(self.unpack, - gr.file_sink(gr.sizeof_char, "unpack.dat")) - - # Initialize base class - gr.hier_block.__init__(self, fg, self.agc, self.unpack) - - def samples_per_baud(self): - return self.spb - - def bits_per_baud(self): - return self.bits_per_symbol - - -mpsk_demod = mpsk_demod__coherent_detection_of_differentially_encoded_psk -#mpsk_demod = mpsk_demod__coherent_detection_of_nondifferentially_encoded_psk diff --git a/gnuradio-examples/python/gmsk2/qpsk_tester.py b/gnuradio-examples/python/gmsk2/qpsk_tester.py deleted file mode 100644 index ea7bae2e..00000000 --- a/gnuradio-examples/python/gmsk2/qpsk_tester.py +++ /dev/null @@ -1,127 +0,0 @@ -#!/usr/bin/env python - -import random -from gnuradio import gr - -default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' - -def string_to_1_0_list(s): - r = [] - for ch in s: - x = ord(ch) - for i in range(8): - t = (x >> i) & 0x1 - r.append(t) - - return r - -def to_1_0_string(L): - return ''.join(map(lambda x: chr(x + ord('0')), L)) - -code = string_to_1_0_list(default_access_code) -access_code = to_1_0_string(code) - -use_agc = 0 -use_rrc_tx = 1 -use_rrc_rx = 1 -use_sync_loop = 1 -use_clock_sync = 1 - -def main(): - fg = gr.flow_graph() - -# data = (1,2,3,4,5,6,7,8,9) - random.seed() - data = [random.randint(1,100) for i in range(20000)] - data[0] = 0 # you know, for the diff encoding stuff - bytes_src = gr.vector_source_b(data,False) - - k = 2 - spb = 50 - ntaps = 11*spb - excess_bw = 0.9 - threshold = 12 - constellation = (1+0j, 0+1j, -1+0j, 0-1j) - - bytes2chunks = gr.packed_to_unpacked_bb(k, gr.GR_MSB_FIRST) - diffenc = gr.diff_encoder_bb(4) - chunks2symbols = gr.chunks_to_symbols_bc(constellation) - - if use_rrc_tx: - rrc_taps_tx = gr.firdes.root_raised_cosine(spb, spb, 1.0, \ - excess_bw, ntaps) - rrc_tx = gr.interp_fir_filter_ccf(spb, rrc_taps_tx) - else: - rrc_tx = gr.interp_fir_filter_ccf(1, (1,)) - -################### CHANNEL MODEL ############################# - - phase_rotate = gr.multiply_const_cc(1-0.36j) - channel = gr.add_cc() - awgn = gr.noise_source_c(gr.GR_GAUSSIAN, 0.5) - fg.connect(awgn, (channel,1)) - -################### CHANNEL MODEL ############################# - - if use_agc: - agc = gr.agc_cc(1e-4, 1, 1) - else: - agc = gr.multiply_const_cc(1) - - # Downconverter - if use_sync_loop: - costas_alpha=0.005 - beta = costas_alpha*costas_alpha*0.25 - sync_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 0) - else: - sync_loop = gr.multiply_const_cc(1) - - if use_rrc_rx: - rrc_taps_rx = gr.firdes.root_raised_cosine(1, spb, 1.0, \ - excess_bw, ntaps) - rrc_rx = gr.fir_filter_ccf(1, rrc_taps_rx) - else: - rrc_rx = gr.fir_filter_ccf(1, (1,)) - - # Sampler - if use_clock_sync: - mu = 0.05 - omega = spb - gain_mu = 0.05 - gain_omega = 0.25*gain_mu*gain_mu - omega_rel_limit = 0.5 - clock_sync = gr.clock_recovery_mm_cc(omega, gain_omega, mu, \ - gain_mu, omega_rel_limit) - #clock_sync.set_verbose(True); - else: - clock_sync = gr.fir_filter_ccf(1, (1,)) - - diff_phasor = gr.diff_phasor_cc() - slicer = gr.constellation_decoder_cb((constellation), (0,1,2,3)) - unpack = gr.unpack_k_bits_bb(k) - access = gr.correlate_access_code_bb(access_code,threshold) - - sink = gr.file_sink(gr.sizeof_char, 'output.dat') - - fg.connect(bytes_src, bytes2chunks, diffenc, chunks2symbols, rrc_tx) - fg.connect(rrc_tx, phase_rotate, channel, agc) - fg.connect(agc, sync_loop, rrc_rx, clock_sync, diff_phasor, slicer, sink) - - test = gr.file_sink(gr.sizeof_gr_complex, 'test.dat') - fg.connect(rrc_rx, test) - - fg.connect(chunks2symbols, gr.file_sink(gr.sizeof_gr_complex, 'rrc_tx.dat')) # into TX RRC - fg.connect(channel, gr.file_sink(gr.sizeof_gr_complex, 'channel.dat')) # Out of TX RRC - fg.connect(rrc_rx, gr.file_sink(gr.sizeof_gr_complex, 'rrc_rx.dat')) # Out of RX RRC -> clock_sync - fg.connect(clock_sync, gr.file_sink(gr.sizeof_gr_complex, 'clock_sync.dat')) # Out of M&M sync loop - fg.connect(bytes2chunks, gr.file_sink(gr.sizeof_char, 'source.dat')) - - fg.start() - fg.wait() - -if __name__ == "__main__": - main() - - - - diff --git a/gnuradio-examples/python/gmsk2/qpsk_usrp_tester.py b/gnuradio-examples/python/gmsk2/qpsk_usrp_tester.py deleted file mode 100644 index bf7698a2..00000000 --- a/gnuradio-examples/python/gmsk2/qpsk_usrp_tester.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python - -import random -from gnuradio import gr, gru, usrp - -default_access_code = '\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC' - -def string_to_1_0_list(s): - r = [] - for ch in s: - x = ord(ch) - for i in range(8): - t = (x >> i) & 0x1 - r.append(t) - - return r - -def to_1_0_string(L): - return ''.join(map(lambda x: chr(x + ord('0')), L)) - -code = string_to_1_0_list(default_access_code) - -access_code = to_1_0_string(code) - -def main(): - - fg = gr.flow_graph() - f_rf = 5e6 - fs = 400e3 - sr = 100e3 - alpha = 0.5 - M = 4 - k = int(gru.log2(M)) - - # Source - src = usrp.source_c () - adc_rate = src.adc_rate() - usrp_decim = int(adc_rate / fs) - src.set_decim_rate(usrp_decim) - - subdev_spec = usrp.pick_rx_subdevice(src) - subdev = usrp.selected_subdev(src, subdev_spec) - print "Using RX d'board %s" % (subdev.side_and_name(),) - src.set_mux(usrp.determine_rx_mux_value(src, subdev_spec)) - src.tune(0, subdev, f_rf) - - g = subdev.gain_range() - subdev.set_gain(g[1]) - subdev.set_auto_tr(True) - - print "USRP Decimation Rate = %d" % usrp_decim - print "RF Frequency = %d" % f_rf - - agc = gr.multiply_const_cc(0.0025) - - # Downconverter - costas_alpha=0.005 - beta = costas_alpha*costas_alpha*0.25 - sync_loop = gr.costas_loop_cc(costas_alpha, beta, 0.05, -0.05, 0) - - # Stage 2 -# fs2 = 200e3 -# D = int(fs / fs2) -# decimator = gr.keep_one_in_n(gr.sizeof_gr_complex, D) -# print "D = %d\nAfter decimator fs = %f" % (D, fs2) - - # Demodulator - taps = gr.firdes.root_raised_cosine(1, fs, sr, alpha, 45) - rrc = gr.fir_filter_ccf(1, taps) - - # Sampler - mu = 0.01 - omega = 4.3 - gain_mu = 0.05 - gain_omega = 0.25*gain_mu*gain_mu - omega_rel_limit = 0.5 - clock_sync = gr.clock_recovery_mm_cc(omega, gain_omega, mu, - gain_mu, omega_rel_limit) - clock_sync.set_verbose(False) - - diff_phasor = gr.diff_phasor_cc() - - threshold = 12 - constellation = (1+0j, 0+1j, -1+0j, 0-1j) - slicer = gr.constellation_decoder_cb((constellation), (0,1,2,3)) - unpack = gr.unpack_k_bits_bb(k) - access = gr.correlate_access_code_bb(access_code,threshold) - - test = gr.file_sink(gr.sizeof_gr_complex, 'test.dat') - sink = gr.file_sink(gr.sizeof_char, 'output.dat') - - fg.connect(src, agc, sync_loop, rrc, clock_sync) - fg.connect(clock_sync, diff_phasor, slicer, unpack, access, sink) - - fg.connect(slicer, gr.file_sink(gr.sizeof_char, 'chunks.dat')) - fg.connect(unpack, gr.file_sink(gr.sizeof_char, 'unpack.dat')) - fg.connect(clock_sync, gr.file_sink(gr.sizeof_gr_complex, 'phasor.dat')) - - fg.start() - fg.wait() - -if __name__ == "__main__": - main() diff --git a/gnuradio-examples/python/gmsk2/receive_path.py b/gnuradio-examples/python/gmsk2/receive_path.py deleted file mode 100644 index c2eba7b7..00000000 --- a/gnuradio-examples/python/gmsk2/receive_path.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005,2006 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 2, 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, gru, blks -from gnuradio import usrp - -# from current dir -from pick_bitrate import pick_rx_bitrate - -# ///////////////////////////////////////////////////////////////////////////// -# receive path -# ///////////////////////////////////////////////////////////////////////////// - -class receive_path(gr.hier_block): - def __init__(self, fg, demod_class, rx_subdev_spec, - bitrate, decim, spb, - rx_callback, options, demod_kwargs): - - self.u = usrp.source_c (fusb_block_size=options.fusb_block_size, - fusb_nblocks=options.fusb_nblocks) - adc_rate = self.u.adc_rate() - - (self._bitrate, self._spb, self._decim) = \ - pick_rx_bitrate(bitrate, demod_class.bits_per_baud(), spb, decim, adc_rate) - - self.u.set_decim_rate(self._decim) - sw_decim = 1 - - if rx_subdev_spec is None: - rx_subdev_spec = usrp.pick_rx_subdevice(self.u) - self.subdev = usrp.selected_subdev(self.u, rx_subdev_spec) - print "Using RX d'board %s" % (self.subdev.side_and_name(),) - - self.u.set_mux(usrp.determine_rx_mux_value(self.u, rx_subdev_spec)) - - # Create filter to get actual channel we want - chan_coeffs = gr.firdes.low_pass (1.0, # gain - sw_decim * self._spb, # sampling rate - 1.0, # midpoint of trans. band - 0.1, # width of trans. band - gr.firdes.WIN_HANN) # filter type - - print "len(rx_chan_coeffs) =", len(chan_coeffs) - - # Decimating Channel filter - # complex in and out, float taps - self.chan_filt = gr.fft_filter_ccc(sw_decim, chan_coeffs) - #self.chan_filt = gr.fir_filter_ccf(sw_decim, chan_coeffs) - - # receiver - self.packet_receiver = \ - blks.demod_pkts(fg, - demod_class(fg, spb=self._spb, **demod_kwargs), - access_code=None, - callback=rx_callback, - threshold=-1) - - fg.connect(self.u, self.chan_filt, self.packet_receiver) - gr.hier_block.__init__(self, fg, None, None) - - g = self.subdev.gain_range() - #self.set_gain((g[0] + g[1])/2) # set gain to midpoint - self.set_gain(g[1]) # set gain to max - self.set_auto_tr(True) # enable Auto Transmit/Receive switching - - # Carrier Sensing Blocks - alpha = 0.001 - thresh = 30 # in dB, will have to adjust - self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha) - fg.connect(self.chan_filt, self.probe) - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital up converter. - """ - r = self.u.tune(0, self.subdev, target_freq) - if r: - return True - - return False - - def set_gain(self, gain): - if gain is None: - r = self.subdev.gain_range() - gain = (r[0] + r[1])/2 # set gain to midpoint - self.gain = gain - return self.subdev.set_gain(gain) - - def set_auto_tr(self, enable): - return self.subdev.set_auto_tr(enable) - - def bitrate(self): - return self._bitrate - - def spb(self): - return self._spb - - def decim(self): - return self._decim - - - def carrier_sensed(self): - """ - Return True if we think carrier is present. - """ - #return self.probe.level() > X - return self.probe.unmuted() - - def carrier_threshold(self): - """ - Return current setting in dB. - """ - return self.probe.threshold() - - def set_carrier_threshold(self, threshold_in_db): - """ - Set carrier threshold. - - @param threshold_in_db: set detection threshold - @type threshold_in_db: float (dB) - """ - self.probe.set_threshold(threshold_in_db) - diff --git a/gnuradio-examples/python/gmsk2/rx_voice.py b/gnuradio-examples/python/gmsk2/rx_voice.py deleted file mode 100755 index 605b4636..00000000 --- a/gnuradio-examples/python/gmsk2/rx_voice.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005 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 2, 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, gru, blks -from gnuradio import usrp -from gnuradio import audio -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -from gnuradio.vocoder import gsm_full_rate - -import random -import struct - -# from current dir -from receive_path import receive_path - -#import os -#print os.getpid() -#raw_input('Attach and press enter') - - -class audio_tx(gr.hier_block): - def __init__(self, fg): - self.packet_src = gr.message_source(33) - voice_decoder = gsm_full_rate.decode_ps() - s2f = gr.short_to_float () - sink_scale = gr.multiply_const_ff(1.0/32767.) - audio_sink = audio.sink(8000) - fg.connect(self.packet_src, voice_decoder, s2f, sink_scale, audio_sink) - gr.hier_block.__init__(self, fg, self.packet_src, audio_sink) - - def msgq(self): - return self.packet_src.msgq() - - -class my_graph(gr.flow_graph): - - def __init__(self, rx_subdev_spec, bitrate, decim_rate, spb, rx_callback, log): - gr.flow_graph.__init__(self) - self.rxpath = receive_path(self, rx_subdev_spec, bitrate, decim_rate, - spb, rx_callback, log) - - self.audio_tx = audio_tx(self) - - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -global n_rcvd, n_right - -def main(): - global n_rcvd, n_right - - n_rcvd = 0 - n_right = 0 - - def rx_callback(ok, payload): - global n_rcvd, n_right - n_rcvd += 1 - if ok: - n_right += 1 - - fg.audio_tx.msgq().insert_tail(gr.message_from_string(payload)) - - print "ok = %r n_rcvd = %4d n_right = %4d" % ( - ok, n_rcvd, n_right) - - parser = OptionParser (option_class=eng_option) - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, - help="select USRP Rx side A or B") - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Rx frequency to FREQ [default=%default]", metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=100e3, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-S", "--spb", type="int", default=None, help="set samples/baud [default=%default]") - parser.add_option("-d", "--decim", type="intx", default=None, - help="set fpga decim rate to DECIM [default=%default]") - parser.add_option("-g", "--gain", type="eng_float", default=27, - help="set rx gain") - parser.add_option("","--log", action="store_true", default=False, - help="enable diagnostic logging") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - # build the graph - fg = my_graph(options.rx_subdev_spec, options.bitrate, - options.decim, options.spb, rx_callback, options.log) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.rxpath.bitrate()),) - print "spb: %3d" % (fg.rxpath.spb(),) - print "decim: %3d" % (fg.rxpath.decim(),) - - fg.rxpath.set_freq(options.freq) - fg.rxpath.set_gain(options.gain) - print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", fg.rxpath.gain - - fg.start() # start flow graph - fg.wait() # wait for it to finish - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/transmit_path.py b/gnuradio-examples/python/gmsk2/transmit_path.py deleted file mode 100644 index d360d1a5..00000000 --- a/gnuradio-examples/python/gmsk2/transmit_path.py +++ /dev/null @@ -1,108 +0,0 @@ -# -# Copyright 2005,2006 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 2, 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, gru, blks -from gnuradio import usrp - -# from current dir -from pick_bitrate import pick_tx_bitrate - -# ///////////////////////////////////////////////////////////////////////////// -# transmit path -# ///////////////////////////////////////////////////////////////////////////// - -class transmit_path(gr.hier_block): - def __init__(self, fg, mod_class, tx_subdev_spec, - bitrate, interp, spb, gain, - options, mod_kwargs): - - self.normal_gain = gain - - self.u = usrp.sink_c (fusb_block_size=options.fusb_block_size, - fusb_nblocks=options.fusb_nblocks) - dac_rate = self.u.dac_rate(); - - print mod_class - print mod_class.bits_per_baud() - (self._bitrate, self._spb, self._interp) = \ - pick_tx_bitrate(bitrate, mod_class.bits_per_baud(), spb, interp, dac_rate) - - self.u.set_interp_rate(self._interp) - - # determine the daughterboard subdevice we're using - if tx_subdev_spec is None: - tx_subdev_spec = usrp.pick_tx_subdevice(self.u) - self.u.set_mux(usrp.determine_tx_mux_value(self.u, tx_subdev_spec)) - self.subdev = usrp.selected_subdev(self.u, tx_subdev_spec) - print "Using TX d'board %s" % (self.subdev.side_and_name(),) - - # transmitter - self.packet_transmitter = \ - blks.mod_pkts(fg, - mod_class(fg, spb=self._spb, **mod_kwargs), - access_code=None, - msgq_limit=4, - pad_for_usrp=True) - - self.amp = gr.multiply_const_cc (self.normal_gain) - - fg.connect(self.packet_transmitter, self.amp, self.u) - gr.hier_block.__init__(self, fg, None, None) - - self.set_gain(self.subdev.gain_range()[1]) # set max Tx gain - self.set_auto_tr(True) # enable Auto Transmit/Receive switching - - def set_freq(self, target_freq): - """ - Set the center frequency we're interested in. - - @param target_freq: frequency in Hz - @rypte: bool - - Tuning is a two step process. First we ask the front-end to - tune as close to the desired frequency as it can. Then we use - the result of that operation and our target_frequency to - determine the value for the digital up converter. - """ - r = self.u.tune(self.subdev._which, self.subdev, target_freq) - if r: - return True - - return False - - def set_gain(self, gain): - self.gain = gain - self.subdev.set_gain(gain) - - def set_auto_tr(self, enable): - return self.subdev.set_auto_tr(enable) - - def send_pkt(self, payload='', eof=False): - return self.packet_transmitter.send_pkt(payload, eof) - - def bitrate(self): - return self._bitrate - - def spb(self): - return self._spb - - def interp(self): - return self._interp diff --git a/gnuradio-examples/python/gmsk2/tunnel.py b/gnuradio-examples/python/gmsk2/tunnel.py deleted file mode 100755 index faf16a63..00000000 --- a/gnuradio-examples/python/gmsk2/tunnel.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005,2006 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 2, 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. -# - - -# ///////////////////////////////////////////////////////////////////////////// -# -# This code sets up up a virtual ethernet interface (typically gr0), -# and relays packets between the interface and the GNU Radio PHY+MAC -# -# What this means in plain language, is that if you've got a couple -# of USRPs on different machines, and if you run this code on those -# machines, you can talk between them using normal TCP/IP networking. -# -# ///////////////////////////////////////////////////////////////////////////// - - -from gnuradio import gr, gru, blks -from gnuradio import usrp -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -import random -import time -import struct -import sys -import os - -# from current dir -from transmit_path import transmit_path -from receive_path import receive_path -import fusb_options - -#print os.getpid() -#raw_input('Attach and press enter') - - -# ///////////////////////////////////////////////////////////////////////////// -# -# Use the Universal TUN/TAP device driver to move packets to/from kernel -# -# See /usr/src/linux/Documentation/networking/tuntap.txt -# -# ///////////////////////////////////////////////////////////////////////////// - -# Linux specific... -# TUNSETIFF ifr flags from - -IFF_TUN = 0x0001 # tunnel IP packets -IFF_TAP = 0x0002 # tunnel ethernet frames -IFF_NO_PI = 0x1000 # don't pass extra packet info -IFF_ONE_QUEUE = 0x2000 # beats me ;) - -def open_tun_interface(tun_device_filename): - from fcntl import ioctl - - mode = IFF_TAP | IFF_NO_PI - TUNSETIFF = 0x400454ca - - tun = os.open(tun_device_filename, os.O_RDWR) - ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode)) - ifname = ifs[:16].strip("\x00") - return (tun, ifname) - - -# ///////////////////////////////////////////////////////////////////////////// -# the flow graph -# ///////////////////////////////////////////////////////////////////////////// - -class my_graph(gr.flow_graph): - - def __init__(self, mod_class, demod_class, - tx_subdev_spec, rx_subdev_spec, - rx_callback, - options, kwargs): - - gr.flow_graph.__init__(self) - self.txpath = transmit_path(self, mod_class, tx_subdev_spec, - options.bitrate, options.interp, options.spb, - options.tx_gain, options, kwargs) - self.rxpath = receive_path(self, demod_class, rx_subdev_spec, - options.bitrate, options.decim, options.spb, - rx_callback, options, {}) - - def send_pkt(self, payload='', eof=False): - return self.txpath.send_pkt(payload, eof) - - def carrier_sensed(self): - """ - Return True if the receive path thinks there's carrier - """ - return self.rxpath.carrier_sensed() - - -# ///////////////////////////////////////////////////////////////////////////// -# Carrier Sense MAC -# ///////////////////////////////////////////////////////////////////////////// - -class cs_mac(object): - """ - Prototype carrier sense MAC - - Reads packets from the TUN/TAP interface, and sends them to the PHY. - Receives packets from the PHY via phy_rx_callback, and sends them - into the TUN/TAP interface. - - Of course, we're not restricted to getting packets via TUN/TAP, this - is just an example. - """ - def __init__(self, tun_fd, verbose=False): - self.tun_fd = tun_fd # file descriptor for TUN/TAP interface - self.verbose = verbose - self.fg = None # flow graph (access to PHY) - - def set_flow_graph(self, fg): - self.fg = fg - - def phy_rx_callback(self, ok, payload): - """ - Invoked by thread associated with PHY to pass received packet up. - - @param ok: bool indicating whether payload CRC was OK - @param payload: contents of the packet (string) - """ - if self.verbose: - print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload)) - if ok: - os.write(self.tun_fd, payload) - - def main_loop(self): - """ - Main loop for MAC. - Only returns if we get an error reading from TUN. - - FIXME: may want to check for EINTR and EAGAIN and reissue read - """ - min_delay = 0.001 # seconds - - while 1: - payload = os.read(self.tun_fd, 10*1024) - if not payload: - self.fg.send_pkt(eof=True) - break - - if self.verbose: - print "Tx: len(payload) = %4d" % (len(payload),) - - delay = min_delay - while self.fg.carrier_sensed(): - sys.stderr.write('B') - time.sleep(delay) - if delay < 0.050: - delay = delay * 2 # exponential back-off - - self.fg.send_pkt(payload) - - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -def main(): - - parser = OptionParser (option_class=eng_option) - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Tx and Rx frequency to FREQ [default=%default]", - metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=None, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-g", "--rx-gain", type="eng_float", default=27, - help="set rx gain") - parser.add_option("-p", "--tx-gain", type="eng_float", default=100, - help="set tx gain") - parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, - help="select USRP Tx side A or B") - parser.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, - help="select USRP Rx side A or B") - parser.add_option("-S", "--spb", type="int", default=None, - help="set samples/baud [default=%default]") - parser.add_option("-d", "--decim", type="intx", default=None, - help="set fpga decim rate to DECIM [default=%default]") - parser.add_option("-i", "--interp", type="intx", default=None, - help="set fpga interpolation rate to INTERP [default=%default]") - parser.add_option("-c", "--carrier-threshold", type="eng_float", default=30, - help="set carrier detect threshold (dB) [default=%default]") - parser.add_option("", "--bt", type="float", default=0.3, - help="set bandwidth-time product [default=%default]") - parser.add_option("","--tun-device-filename", default="/dev/net/tun", - help="path to tun device file [default=%default]") - parser.add_option("-v","--verbose", action="store_true", default=False) - fusb_options.add_options(parser) - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - mod_kwargs = { - 'bt' : options.bt, - } - - # open the TUN/TAP interface - (tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename) - - # Attempt to enable realtime scheduling - r = gr.enable_realtime_scheduling() - if r == gr.RT_OK: - realtime = True - else: - realtime = False - print "Note: failed to enable realtime scheduling" - - - # If the user hasn't set the fusb_* parameters on the command line, - # pick some values that will reduce latency. - - if options.fusb_block_size == 0 and options.fusb_nblocks == 0: - if realtime: # be more aggressive - options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024) - options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16) - else: - options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096) - options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16) - - print "fusb_block_size =", options.fusb_block_size - print "fusb_nblocks =", options.fusb_nblocks - - # instantiate the MAC - mac = cs_mac(tun_fd, verbose=True) - - - # build the graph (PHY) - fg = my_graph(blks.gmsk2_mod, blks.gmsk2_demod, - options.tx_subdev_spec, options.rx_subdev_spec, - mac.phy_rx_callback, - options, mod_kwargs) - - mac.set_flow_graph(fg) # give the MAC a handle for the PHY - - if fg.txpath.bitrate() != fg.rxpath.bitrate(): - print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % ( - eng_notation.num_to_str(fg.txpath.bitrate()), - eng_notation.num_to_str(fg.rxpath.bitrate())) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) - print "spb: %3d" % (fg.txpath.spb(),) - print "interp: %3d" % (fg.txpath.interp(),) - - ok = fg.txpath.set_freq(options.freq) - if not ok: - print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(options.freq),) - raise SystemExit - - ok = fg.rxpath.set_freq(options.freq) - if not ok: - print "Failed to set Rx frequency to %s" % (eng_notation.num_to_str(options.freq),) - raise SystemExit - - print "Tx gain: ", options.tx_gain - fg.rxpath.set_gain(options.rx_gain) - print "Rx gain_range: ", fg.rxpath.subdev.gain_range(), " using", fg.rxpath.gain - - fg.rxpath.set_carrier_threshold(options.carrier_threshold) - print "Carrier sense threshold:", options.carrier_threshold, "dB" - - print - print "Allocated virtual ethernet interface: %s" % (tun_ifname,) - print "You must now use ifconfig to set its IP address. E.g.," - print - print " $ sudo ifconfig %s 10.10.10.1" % (tun_ifname,) - print - print "Be sure to use a different address in the same subnet for each machine." - print - - - fg.start() # Start executing the flow graph (runs in separate threads) - - mac.main_loop() # don't expect this to return... - - fg.stop() # but if it does, tell flow graph to stop. - fg.wait() # wait for it to finish - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/gmsk2/tx_voice.py b/gnuradio-examples/python/gmsk2/tx_voice.py deleted file mode 100755 index b1f6b0ab..00000000 --- a/gnuradio-examples/python/gmsk2/tx_voice.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2005 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 2, 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, gru, blks -from gnuradio import usrp -from gnuradio import audio -from gnuradio import eng_notation -from gnuradio.eng_option import eng_option -from optparse import OptionParser - -from gnuradio.vocoder import gsm_full_rate - -import random -import time -import struct -import sys - -# from current dir -from transmit_path import transmit_path - -#import os -#print os.getpid() -#raw_input('Attach and press enter') - - -class my_graph(gr.flow_graph): - - def __init__(self, tx_subdev_spec, bitrate, interp_rate, spb, bt): - gr.flow_graph.__init__(self) - self.txpath = transmit_path(self, tx_subdev_spec, bitrate, interp_rate, spb, bt) - - audio_input = "" - sample_rate = 8000 - src = audio.source(sample_rate, audio_input) - src_scale = gr.multiply_const_ff(32767) - f2s = gr.float_to_short() - voice_coder = gsm_full_rate.encode_sp() - self.packets_from_encoder = gr.msg_queue() - packet_sink = gr.message_sink(33, self.packets_from_encoder, False) - self.connect(src, src_scale, f2s, voice_coder, packet_sink) - - - -# ///////////////////////////////////////////////////////////////////////////// -# main -# ///////////////////////////////////////////////////////////////////////////// - -def main(): - - def send_pkt(payload='', eof=False): - return fg.txpath.send_pkt(payload, eof) - - def rx_callback(ok, payload): - print "ok = %r, payload = '%s'" % (ok, payload) - - parser = OptionParser (option_class=eng_option) - parser.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, - help="select USRP Tx side A or B") - parser.add_option("-f", "--freq", type="eng_float", default=423.1e6, - help="set Tx and Rx frequency to FREQ [default=%default]", metavar="FREQ") - parser.add_option("-r", "--bitrate", type="eng_float", default=100e3, - help="specify bitrate. spb and interp will be derived.") - parser.add_option("-S", "--spb", type="int", default=None, help="set samples/baud [default=%default]") - parser.add_option("-i", "--interp", type="intx", default=None, - help="set fpga interpolation rate to INTERP [default=%default]") - parser.add_option("-s", "--size", type="eng_float", default=1500, - help="set packet size [default=%default]") - parser.add_option("", "--bt", type="float", default=0.3, help="set bandwidth-time product [default=%default]") - parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, - help="set megabytes to transmit [default=%default]") - parser.add_option("","--discontinuous", action="store_true", default=False, - help="enable discontinous transmission (bursts of 5 packets)") - (options, args) = parser.parse_args () - - if len(args) != 0: - parser.print_help() - sys.exit(1) - - if options.freq < 1e6: - options.freq *= 1e6 - - pkt_size = int(options.size) - - # build the graph - fg = my_graph(options.tx_subdev_spec, options.bitrate, options.interp, - options.spb, options.bt) - - print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) - print "spb: %3d" % (fg.txpath.spb(),) - print "interp: %3d" % (fg.txpath.interp(),) - - fg.txpath.set_freq(options.freq) - - fg.start() # start flow graph - - # generate and send packets - nbytes = int(1e6 * options.megabytes) - n = 0 - pktno = 0 - - while n < nbytes: - packet = fg.packets_from_encoder.delete_head() - s = packet.to_string() - send_pkt(s) - n += len(s) - sys.stderr.write('.') - if options.discontinuous and pktno % 5 == 4: - time.sleep(1) - pktno += 1 - - send_pkt(eof=True) - fg.wait() # wait for it to finish - fg.txpath.set_auto_tr(False) - - -if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - pass diff --git a/gnuradio-examples/python/mc4020/Makefile.am b/gnuradio-examples/python/mc4020/Makefile.am deleted file mode 100644 index 45f48b46..00000000 --- a/gnuradio-examples/python/mc4020/Makefile.am +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright 2004 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 2, 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. -# - -EXTRA_DIST = \ - fm_demod.py \ - mc4020_fft.py - - - - diff --git a/gnuradio-examples/python/mc4020/fm_demod.py b/gnuradio-examples/python/mc4020/fm_demod.py deleted file mode 100755 index e58407f7..00000000 --- a/gnuradio-examples/python/mc4020/fm_demod.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env python - -from gnuradio import gr -from gnuradio import audio -from gnuradio import mc4020 -import sys - -def high_speed_adc (fg, input_rate): - # return gr.file_source (gr.sizeof_short, "dummy.dat", False) - return mc4020.source (input_rate, mc4020.MCC_CH3_EN | mc4020.MCC_ALL_1V) - -# -# return a gr.flow_graph -# -def build_graph (freq1, freq2): - input_rate = 20e6 - cfir_decimation = 125 - audio_decimation = 5 - - quad_rate = input_rate / cfir_decimation - audio_rate = quad_rate / audio_decimation - - fg = gr.flow_graph () - - # use high speed ADC as input source - src = high_speed_adc (fg, input_rate) - - # compute FIR filter taps for channel selection - channel_coeffs = \ - gr.firdes.low_pass (1.0, # gain - input_rate, # sampling rate - 250e3, # low pass cutoff freq - 8*100e3, # width of trans. band - gr.firdes.WIN_HAMMING) - - # input: short; output: complex - chan_filter1 = \ - gr.freq_xlating_fir_filter_scf (cfir_decimation, - channel_coeffs, - freq1, # 1st station freq - input_rate) - - (head1, tail1) = build_pipeline (fg, quad_rate, audio_decimation) - - # sound card as final sink - audio_sink = audio.sink (int (audio_rate)) - - # now wire it all together - fg.connect (src, chan_filter1) - fg.connect (chan_filter1, head1) - fg.connect (tail1, (audio_sink, 0)) - - # two stations at once? - if freq2: - # Extract the second station and connect - # it to a second pipeline... - - # input: short; output: complex - chan_filter2 = \ - gr.freq_xlating_fir_filter_scf (cfir_decimation, - channel_coeffs, - freq2, # 2nd station freq - input_rate) - - (head2, tail2) = build_pipeline (fg, quad_rate, audio_decimation) - - fg.connect (src, chan_filter2) - fg.connect (chan_filter2, head2) - fg.connect (tail2, (audio_sink, 1)) - - return fg - -def build_pipeline (fg, quad_rate, audio_decimation): - '''Given a flow_graph, fg, construct a pipeline - for demodulating a broadcast FM signal. The - input is the downconverteed complex baseband - signal. The output is the demodulated audio. - - build_pipeline returns a two element tuple - containing the input and output endpoints. - ''' - fm_demod_gain = 2200.0/32768.0 - audio_rate = quad_rate / audio_decimation - volume = 1.0 - - # input: complex; output: float - fm_demod = gr.quadrature_demod_cf (volume*fm_demod_gain) - - # compute FIR filter taps for audio filter - width_of_transition_band = audio_rate / 32 - audio_coeffs = gr.firdes.low_pass (1.0, # gain - quad_rate, # sampling rate - audio_rate/2 - width_of_transition_band, - width_of_transition_band, - gr.firdes.WIN_HAMMING) - - # input: float; output: float - audio_filter = gr.fir_filter_fff (audio_decimation, audio_coeffs) - - fg.connect (fm_demod, audio_filter) - return ((fm_demod, 0), (audio_filter, 0)) - - -def main (args): - nargs = len (args) - if nargs == 1: - freq1 = float (args[0]) * 1e6 - freq2 = None - elif nargs == 2: - freq1 = float (args[0]) * 1e6 - freq2 = float (args[1]) * 1e6 - else: - sys.stderr.write ('usage: fm_demod freq1 [freq2]\n') - sys.exit (1) - - # connect to RF front end - rf_front_end = gr.microtune_4937_eval_board () - if not rf_front_end.board_present_p (): - raise IOError, 'RF front end not found' - - # set front end gain - rf_front_end.set_AGC (300) - IF_freq = rf_front_end.get_output_freq () - IF_freq = 5.75e6 - - if not freq2: # one station - - rf_front_end.set_RF_freq (freq1) - fg = build_graph (IF_freq, None) - - else: # two stations - - if abs (freq1 - freq2) > 5.5e6: - raise IOError, 'freqs too far apart' - - target_freq = (freq1 + freq2) / 2 - actual_freq = rf_front_end.set_RF_freq (target_freq) - #actual_freq = target_freq - - fg = build_graph (IF_freq + freq1 - actual_freq, - IF_freq + freq2 - actual_freq) - - fg.start () # fork thread(s) and return - raw_input ('Press Enter to quit: ') - fg.stop () - -if __name__ == '__main__': - main (sys.argv[1:]) - - diff --git a/gnuradio-examples/python/mc4020/mc4020_fft.py b/gnuradio-examples/python/mc4020/mc4020_fft.py deleted file mode 100755 index d226b9ca..00000000 --- a/gnuradio-examples/python/mc4020/mc4020_fft.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2004 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 2, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. -# - -from gnuradio import gr -from gnuradio import mc4020 -from gnuradio.eng_option import eng_option -from gnuradio.wxgui import stdgui, fftsink -from optparse import OptionParser -import wx - -class app_flow_graph (stdgui.gui_flow_graph): - def __init__(self, frame, panel, vbox, argv): - stdgui.gui_flow_graph.__init__ (self, frame, panel, vbox, argv) - - - parser = OptionParser (option_class=eng_option) - (options, args) = parser.parse_args () - - input_rate = 20e6 - src = mc4020.source (input_rate, mc4020.MCC_CH3_EN | mc4020.MCC_ALL_1V) - cvt = gr.short_to_float () - block, fft_win = fftsink.make_fft_sink_f (self, panel, "Rx Data", 512, input_rate) - - self.connect (src, cvt) - self.connect (cvt, block) - vbox.Add (fft_win, 1, wx.EXPAND) - - -def main (): - app = stdgui.stdapp (app_flow_graph, "USRP FFT") - app.MainLoop () - -if __name__ == '__main__': - main () diff --git a/gnuradio-examples/python/usrp/usrp_siggen.py b/gnuradio-examples/python/usrp/usrp_siggen.py index 59e01e0a..6a41f74b 100755 --- a/gnuradio-examples/python/usrp/usrp_siggen.py +++ b/gnuradio-examples/python/usrp/usrp_siggen.py @@ -101,10 +101,10 @@ class my_graph(gr.flow_graph): """ r = self.u.tune(self.subdev._which, self.subdev, target_freq) if r: - print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) - print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) - print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) - print "r.inverted =", r.inverted + #print "r.baseband_freq =", eng_notation.num_to_str(r.baseband_freq) + #print "r.dxc_freq =", eng_notation.num_to_str(r.dxc_freq) + #print "r.residual_freq =", eng_notation.num_to_str(r.residual_freq) + #print "r.inverted =", r.inverted return True return False diff --git a/gr-atsc/src/lib/atsc_fpll.h b/gr-atsc/src/lib/atsc_fpll.h index ae00c051..f62b78b4 100644 --- a/gr-atsc/src/lib/atsc_fpll.h +++ b/gr-atsc/src/lib/atsc_fpll.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -67,7 +67,7 @@ public: double initial_phase; bool debug_no_update; gr_nco nco; - gri_agc agc; // automatic gain control + gri_agc_ff agc; // automatic gain control gr_single_pole_iir afci; gr_single_pole_iir afcq;