Data in USRP : Dive in usrp_rx_c…

2011-9-21

Data <wbr>in <wbr>USRP <wbr>: <wbr>Dive <wbr>in <wbr>usrp_rx_cfile.cc

These days, I was working in Gnuradio and USRP. I always felt confuse about this development platform. Because there were not an integrated documents and it also didn’t provide any tutorials to teach you how to use it.

 

Before we handle the signal using kinds of DSP method, I need to know what data come from the USRP. So I try to analyze usrp_rx_cfile.cc.

 

Every code has a header file.

Look at it.

 

#include <gr_top_block.h>

#include <usrp_source_base.h>

#include <usrp_source_c.h>

#include <usrp_source_s.h>

#include <gr_file_sink.h>

 

class usrp_rx_cfile;

typedef boost::shared_ptr<usrp_rx_cfile> usrp_rx_cfile_sptr;

usrp_rx_cfile_sptr make_usrp_rx_cfile(int which, usrp_subdev_spec spec,

                 int decim, double freq, float gain,

                 bool width8, bool nohb,

                 bool output_shorts, int nsamples,

                 const std::string &filename);

 

class usrp_rx_cfile : public gr_top_block

{

private:

    usrp_rx_cfile(int which, usrp_subdev_spec spec,

        int decim, double freq, float gain,

        bool width8, bool nohb,

        bool output_shorts, int nsamples,

        const std::string &filename);

    friend usrp_rx_cfile_sptr make_usrp_rx_cfile(int which, usrp_subdev_spec spec,

                  int decim, double freq, float gain,

                  bool width8, bool nohb,

                  bool output_shorts, int nsamples,

                  const std::string &filename);

 

    int d_which;

    usrp_subdev_spec d_spec;

    int d_decim;

    double d_freq;

    float d_gain;

    bool d_width8, d_nohb;

    int d_nsamples;

    std::string d_filename;

 

 public:

    gr_block_sptr d_head;

    gr_block_sptr d_dst;

};

 

The header file of usrp_rx_cfile.cc define a class: usrp_rx_cfile.

It inherits from another class gr_top_block but it isn’t important for us now.

There are two private functions: one is constructor. Another is a friend function make_usrp_rx_cfile. It returns a pointer which point to a new allocated usrp_rx_cfile. This function implements in usrp_rx_cfile.cc:

 

// Shared pointer constructor

usrp_rx_cfile_sptr make_usrp_rx_cfile(int which, usrp_subdev_spec spec,

                 int decim, double freq, float gain,

                 bool width8, bool nohb,

                 bool output_shorts, int nsamples,

                 const std::string &filename)

{

  return gnuradio::get_initial_sptr(new usrp_rx_cfile(which, spec,

                       decim, freq, gain,

                       width8, nohb,

                       output_shorts,

                       nsamples,

                       filename));

}

 

There are also some private values :

int d_which;

    usrp_subdev_spec d_spec;

    int d_decim;

    double d_freq;

    float d_gain;

    bool d_width8, d_nohb;

    int d_nsamples;

std::string d_filename;

 

these values describe parameters of USRP which they should be set before it works.

 

public:

    gr_block_sptr d_head;

gr_block_sptr d_dst;

 

d_head and d_dst are gr_block pointers which provide a interface to other gnuradio parts to connect.

 

 

Now, let’s locate at usrp_rx_cfile::usrp_rx_cfile in usrp_rx_cfile.cc.

We can see that : 

if(d_nsamples == -1) {

    connect(usrp, 0, d_dst, 0);

  }

  else {

    d_head = gr_make_head(sizeof(gr_complex), d_nsamples*2);

    connect(usrp, 0, d_head, 0);

    connect(d_head, 0, d_dst, 0);

  }

Usrp connects to d_dst. What is usrp?

Look at this: usrp_source_c_sptr usrp;

usrp_source_c_sptr is a new pointer type defined in usrp_source_c.h :

 

class usrp_source_c;

typedef boost::shared_ptr<usrp_source_c> usrp_source_c_sptr;

 

yeah, it is a boost smart pointer which point to class usrp_source_c.

usrp_source_c is a class which handle complex data.

Inheritance diagram for usrp_source_c:

 

 

class usrp_source_c : public usrp_source_base {

 private:

  friend usrp_source_c_sptr

  usrp_make_source_c (int which_board,

             unsigned int decim_rate,

             int nchan,

             int mux,

             int mode,

             int fusb_block_size,

             int fusb_nblocks,

             const std::string fpga_filename,

             const std::string firmware_filename

             ) throw (std::runtime_error);

 

 protected:

  usrp_source_c (int which_board,

        unsigned int decim_rate,

        int nchan,

        int mux,

        int mode,

        int fusb_block_size,

        int fusb_nblocks,

        const std::string fpga_filename,

        const std::string firmware_filename

        ) throw (std::runtime_error);

 

  virtual int ninput_bytes_reqd_for_noutput_items (int noutput_items);

 

  virtual void copy_from_usrp_buffer (gr_vector_void_star &output_items,

                 int output_index,

                 int output_items_available,

                 int &output_items_produced,

                 const void *usrp_buffer,

                 int usrp_buffer_length,

                 int &bytes_read);

 

 public:

  ~usrp_source_c ();

};

 

Interface to Universal Software Radio Peripheral Rx path

output: 1 stream of complex<float>.

The only thing we are interesting is how it works and what data it returns.

ninput_bytes_reqd_for_noutput_items and copy_from_usrp_buffer are virtual functions.

In gnuradio system, it will call both functions.

Look at copy_from_usrp_buffer implementation.

 

void

usrp_source_c::copy_from_usrp_buffer (gr_vector_void_star &output_items,

                  int output_index,

                  int output_items_available,

                  int &output_items_produced,

                  const void *usrp_buffer,

                  int usrp_buffer_length,

                  int &bytes_read)

{

  gr_complex *out = &((gr_complex *) output_items[0])[output_index];

  unsigned sbs = sizeof_basic_sample();

  unsigned nusrp_bytes_per_item = NBASIC_SAMPLES_PER_ITEM * sbs;

 

  int nitems = std::min (output_items_available,

         (int)(usrp_buffer_length / nusrp_bytes_per_item));

 

  signed char *s8 = (signed char *) usrp_buffer;

  short *s16 = (short *) usrp_buffer;

 

  switch (sbs){

  case 1:

    for (int i = 0; i < nitems; i++){

      out[i] = gr_complex ((float)(s8[2*i+0] << 8), (float)(s8[2*i+1] << 8));

    }

    break;

 

  case 2:

    for (int i = 0; i < nitems; i++){

      out[i] = gr_complex ((float) usrp_to_host_short(s16[2*i+0]),

           (float) usrp_to_host_short(s16[2*i+1]));

    }

    break;

 

  default:

    assert(0);

  }

 

  output_items_produced = nitems;

  bytes_read = nitems * nusrp_bytes_per_item;

}

 

It defines a gr_complex pointer out

gr_complex *out = &((gr_complex *) output_items[0])[output_index];

 

It force output_items[0] to be gr_complex type. out points to output_items.

What is gr_complex ?

In gr_complex.h:

00025 #include <complex>
00026 typedef std::complex<float>                     gr_complex;
00027 typedef std::complex<double>                    gr_complexd;
00028 
00029 
00030 inline bool is_complex (gr_complex x) { return true;}
00031 inline bool is_complex (gr_complexd x) { return true;}
00032 inline bool is_complex (float x) { return false;}
00033 inline bool is_complex (double x) { return false;}
00034 inline bool is_complex (int x) { return false;}
00035 inline bool is_complex (char x) { return false;}
00036 inline bool is_complex (short x) { return false;}

It is compatible with C++ standard complex type.

 

Next it defines to pointers. One of them point to 8 bit (a byte) value and 16 bit (two byte) value.

  signed char *s8 = (signed char *) usrp_buffer;

short *s16 = (short *) usrp_buffer;

Let s8 and s16 point to usrp_buffer. Because it provides both 8bit and 16bit choices for user. Default we use 16bit.

 

  switch (sbs){

  case 1:

    for (int i = 0; i < nitems; i++){

      out[i] = gr_complex ((float)(s8[2*i+0] << 8), (float)(s8[2*i+1] << 8));

    }

    break;

 

  case 2:

    for (int i = 0; i < nitems; i++){

      out[i] = gr_complex ((float) usrp_to_host_short(s16[2*i+0]),

           (float) usrp_to_host_short(s16[2*i+1]));

    }

    break;

 

  default:

    assert(0);

  }

This part is main data transceiver. It handles the input data from usrp_buffer and dump them to out.

We can see that even in usrp_buffer is real part and odd in usrp_buffer is image part.

If we choose 8bit complex, the data shift left 8 bits and then dump to out.

If we choose 16bit complex, the data using a function to get and dump to out.

 

Now we conclude:

usrp_source_c  converts interleaved 8 or 16-bit I & Q from usrp buffer into a single complex output stream.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值