Good morning! I started writing a small signal processing block (OFDM transmitter) and ran into some problems.
My starting point was the well written gr-how-to-write-a-block tutorial. I have, let's say, 1536 input samples and want to produce 1800 output samples with my block. When I run my code with small values (say fft size of 32) I get valid OFDM symbols but a lot of zeros in between. When I uses higher values either the scheduler quits ( sched: <gr_block ofdm_tx_vcc (0)> is requesting more input data than we can provide. ) or even the buffer can't be allocated. This makes me sure that there is a programming mistake on my part, but I can't seem to find it. I would be thankful if somebody could point out my mistake? The main files are attached, a modified gr-how-to-build-a-block can be found here: http://www.1c3.de/gr-dab.tar.bz2 . Yet another question: Can blocks somehow interchange values? I would like to write two blocks, one that estimates a frequency offset and another one that compensates it (simple modulation). Or do I have to do that in one block? Jens
/* -*- c++ -*- */ %feature("autodoc", "1"); // generate python docstrings %include "exception.i" %import "gnuradio.i" // the common stuff %{ #include "gnuradio_swig_bug_workaround.h" // mandatory bug fix #include "ofdm_tx_cc.h" #include <stdexcept> %} // ---------------------------------------------------------------- /* * First arg is the package prefix. * Second arg is the name of the class minus the prefix. * * This does some behind-the-scenes magic so we can * access howto_square_ff from python as howto.square_ff */ GR_SWIG_BLOCK_MAGIC(ofdm,tx_cc); ofdm_tx_cc_sptr ofdm_do_tx_cc (int ofdm_sym_len, int gi_len, int fft_len); class ofdm_tx_cc : public gr_sync_block { private: ofdm_tx_cc (int ofdm_sym_len, int gi_len, int fft_len); };
/* -*- c++ -*- */ /* * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * config.h is generated by configure. It contains the results * of probing for features, options etc. It should be the first * file included in your .cc file. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <ofdm_tx_cc.h> #include <gr_io_signature.h> #include <gri_fft.h> #include <math.h> /* * Create a new instance of gr_ofdm_tx_cc and return * a boost shared_ptr. This is effectively the public constructor. */ ofdm_tx_cc_sptr ofdm_do_tx_cc (int ofdm_sym_len, int gi_len, int fft_len) { return ofdm_tx_cc_sptr (new ofdm_tx_cc (ofdm_sym_len, gi_len, fft_len)); } /* * Specify constraints on number of input and output streams. * This info is used to construct the input and output signatures * (2nd & 3rd args to gr_block's constructor). The input and * output signatures are used by the runtime system to * check that a valid number and type of inputs and outputs * are connected to this block. In this case, we accept * only 1 input and 1 output. */ static const int MIN_IN = 1; // mininum number of input streams static const int MAX_IN = 1; // maximum number of input streams static const int MIN_OUT = 1; // minimum number of output streams static const int MAX_OUT = 1; // maximum number of output streams /* * The private constructor * Takes length of OFDM symbol (including guard interval) and guard interval length as * arguments. Variable FFT length and subcarrier selection mask is implemented later. */ ofdm_tx_cc::ofdm_tx_cc (int ofdm_sym_len, int gi_len, int fft_len) : gr_block ("ofdm_tx_vcc", gr_make_io_signature (MIN_IN, MAX_IN, (ofdm_sym_len-gi_len)*sizeof(gr_complex)), gr_make_io_signature (MIN_OUT, MAX_OUT, ofdm_sym_len * sizeof(gr_complex))) { d_ofdm_sym_len = ofdm_sym_len; d_gi_len = gi_len; d_fft_len = ofdm_sym_len-gi_len; // FIXME: not yet implemented // OFDM symbols can't be split, contrain request size set_output_multiple(d_ofdm_sym_len); // set approximate out rate set_relative_rate((double)(d_ofdm_sym_len) / (double)(d_ofdm_sym_len-d_gi_len)); d_fft = new gri_fft_complex(d_fft_len, true); } /* * Our virtual destructor. */ ofdm_tx_cc::~ofdm_tx_cc () { delete d_fft; } /* * Implementation of gr_block::forecast() - estimate the number of input samples, if we are asked to * output noutput_items samples. */ void ofdm_tx_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required) { // noutput_items should be a multiple of d_ofdm_sym_len (see constructor) assert ((noutput_items % d_ofdm_sym_len) == 0); int nblocks = noutput_items / d_ofdm_sym_len; int input_required = nblocks * (d_ofdm_sym_len-d_gi_len); unsigned ninputs = ninput_items_required.size(); for (unsigned int i = 0; i < ninputs; i++) ninput_items_required[i] = input_required; } /* * Here the actual work is done - "d_ofdm_sym_len-d_gi_len" complex samples are consumed and * "d_ofdm_sym_len" samples are written. */ int ofdm_tx_cc::general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { // pointers to data const gr_complex *in = (const gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; int out_count=0; // counts the number of written complex samples int in_count=0; // counts number of samples consumed printf("available in (samples): %i\n", ninput_items[0]); printf("requested out (samples): %i\n", noutput_items); while(out_count<noutput_items) { memcpy(d_fft->get_inbuf(), in, d_fft_len*sizeof(gr_complex)); // copy to input buffer d_fft->execute(); // compute fft // cyclic prefix is repetition of the end in the beginning memcpy(out, d_fft->get_outbuf()+(d_fft_len-d_gi_len), d_gi_len*sizeof(gr_complex)); // guard interval; last argument of memcpy is length in bytes memcpy(out+d_gi_len, d_fft->get_outbuf(), d_fft_len*sizeof(gr_complex)); // copy data // increase pointers, counters in += d_ofdm_sym_len-d_gi_len; out += d_ofdm_sym_len; out_count += d_ofdm_sym_len; in_count += d_ofdm_sym_len-d_gi_len; } // noutput_items should always be a multiple of d_ofdm_sym_len, so the assert shouldn't fail now assert (out_count == noutput_items); // Tell runtime system how many input items we consumed. consume_each(in_count); // Tell runtime system how many output items we produced. return out_count; }
/* -*- c++ -*- */ /* * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef INCLUDED_OFDM_TX_CC_H #define INCLUDED_OFDM_TX_CC_H #include <gr_block.h> class gri_fft_complex; class ofdm_tx_cc; /* * We use boost::shared_ptr's instead of raw pointers for all access * to gr_blocks (and many other data structures). The shared_ptr gets * us transparent reference counting, which greatly simplifies storage * management issues. This is especially helpful in our hybrid * C++ / Python system. * * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm * * As a convention, the _sptr suffix indicates a boost::shared_ptr */ typedef boost::shared_ptr<ofdm_tx_cc> ofdm_tx_cc_sptr; /*! * \brief Return a shared_ptr to a new instance of howto_square2_ff. * * To avoid accidental use of raw pointers, howto_square2_ff's * constructor is private. howto_make_square2_ff is the public * interface for creating new instances. */ ofdm_tx_cc_sptr ofdm_do_tx_cc (); /*! * \brief OFDM transmitter. * \ingroup block * * A simple OFDM transmitter block. */ class ofdm_tx_cc : public gr_block { private: // The friend declaration allows ofdm_do_tx_cc to // access the private constructor. friend ofdm_tx_cc_sptr ofdm_do_tx_cc (int ofdm_sym_len, int gi_len, int fft_len); ofdm_tx_cc (int ofdm_sym_len, int gi_len, int fft_len); // private constructor unsigned int d_ofdm_sym_len; unsigned int d_gi_len; unsigned int d_fft_len; gri_fft_complex *d_fft; public: ~ofdm_tx_cc (); // public destructor // Where all the action really happens int general_work (int noutput_items, gr_vector_int &ninput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); void forecast(int noutput_items, gr_vector_int &ninput_items_required); }; #endif /* INCLUDED_OFDM_TX_H */
#!/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., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # from gnuradio import gr, gr_unittest import ofdm, inspect class qa_ofdm (gr_unittest.TestCase): def setUp (self): self.fg = gr.flow_graph () def tearDown (self): self.fg = None def test_001_square_ff (self): fft_len = 32 # fails for higher values (eg. 512) gi_len = 4 ofdm_sym_len = fft_len+gi_len; ofdm_tx = ofdm.ofdm_do_tx_cc (ofdm_sym_len, gi_len, 0) print ofdm_tx.output_multiple() print ofdm_tx.relative_rate() s2p = gr.serial_to_parallel (gr.sizeof_gr_complex, fft_len) p2s = gr.parallel_to_serial (gr.sizeof_gr_complex, ofdm_sym_len) dst = gr.file_sink(gr.sizeof_gr_complex, "ofdm_sym_out") SNR=10 src = gr.noise_source_c(gr.GR_GAUSSIAN, pow(10.0,-SNR/20.0)) self.fg.connect(src, s2p) self.fg.connect(s2p, ofdm_tx) self.fg.connect(ofdm_tx, p2s) self.fg.connect(p2s, dst) self.fg.run() if __name__ == '__main__': gr_unittest.main ()
_______________________________________________ Discuss-gnuradio mailing list Discuss-gnuradio@gnu.org http://lists.gnu.org/mailman/listinfo/discuss-gnuradio