Search code examples
gnuradiognuradio-companion

GNU Radio BPSK BER simulation: RRC Pulse Magnitude Normalization


A very basic BPSK BER test is being performed (only AWGN is considered). The test is accomplished by using the gr-mapper OOT. The first simulation is based on a simple BPSK mapper (1->1, 0->-1) shown below. BER without MF

The results are very close to theoretical BER as shown below BER In the simulation, SNR is specified by varying the noise voltage of the Gaussian noise source. Eb = RMS = sqrt((1^2 + 1^2)/2) = 1. Thus, Noise Voltage = sqrt(No) = math.sqrt(1/math.pow(10,SNR/10.0)). More information can be found at this link

I'm now focusing on adding a matched filter accomplished by one RRC filter at transmitter and receiver as shown below. This flowgraph has very poor BER performance.

flowgraph

Upon close examination of the filtered BPSK signal, the magnitude is no longer 1 (actual value is around 0.15) and hence the value of Eb being used is not accurate. To further verify my conclusion, I used the gnuradio filter design tool. The tool shows that to get a magnitude of 1, the gain has to be set around 7 (at this value, the BER is somehow close to theory).

  1. Question: How do I make sure that the pulse magnitude (at t=0) is 1 without manipulating the filter gain to an arbitrary value?

RRC pulse The code for the pulse-shaper (debug_pulseshape_pam_2) is shown below

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gnuradio/io_signature.h>
#include "debug_pulseshape_pam_2_impl.h"
#include <gnuradio/blocks/char_to_float.h>
#include <gnuradio/digital/map_bb.h>
#include <gnuradio/filter/interp_fir_filter_fff.h>

namespace gr {
     namespace baseband {

debug_pulseshape_pam_2::sptr
debug_pulseshape_pam_2::make(std::vector<float> taps,float sps)
{
  return gnuradio::get_initial_sptr
    (new debug_pulseshape_pam_2_impl(taps, sps));
}

/*
 * The private constructor
 */
debug_pulseshape_pam_2_impl::debug_pulseshape_pam_2_impl(std::vector<float> taps,float sps)
  : gr::hier_block2("debug_pulseshape_pam_2",
          gr::io_signature::make(1, 1, sizeof(unsigned char)),
          gr::io_signature::make(1, 1, sizeof(float)))
{
  //Initializing the map block
  std::vector<int> map;
  map.push_back(-1);
  map.push_back(1);
  gr::digital::map_bb::sptr mapper(gr::digital::map_bb::make(map));

  //Initializing char_to_float block
  gr::blocks::char_to_float::sptr float_char(gr::blocks::char_to_float::make());

  //Initializing add const block
  //gr::blocks::add_const_ff::sptr const_add(gr::blocks::add_const_ff::make(-0.5));

  //Initializing an interpolating FIR filter
  gr::filter::interp_fir_filter_fff::sptr fir(gr::filter::interp_fir_filter_fff::make(int(sps),taps));

  connect(self(),0,mapper,0);
  connect(mapper,0,float_char,0);
  connect(float_char,0, fir, 0);
  connect(fir, 0,    self(), 0);
}

/*
 * Our virtual destructor.
 */
debug_pulseshape_pam_2_impl::~debug_pulseshape_pam_2_impl()
{
}


} /* namespace baseband */
} /* namespace gr */

Please do not hesitate to ask for more information if needed.

Regards,


Solution

  • I was able to solve the problem finally. Turned out the noise has to be divided by the number of samples per symbol. enter image description here