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

Reply via email to