ECE 598HH: Advanced Wireless Networks and Sensing Systems

Lecture 3: Part 2: Software Defined Radio Tutorial Haitham Hassanieh Software Defined Radios

• Idea: Flexibility, Portability, Multifunction … – Programmable Radio Frontend: • Change Center Frequency, Bandwidth, Sampling Rate, Gain, …. – Baseband Processing in Software: • Implement baseband functions on host in software (C++, Python, …) • Implement some function on FPGA. Many Open Source SDR Platforms

USRP: Universal Software Radio Peripheral (Ettus) Warp: Wireless Open Access Research Platform (Rice)

SORA: SOftware-defined Radio (Microsoft) RTL-SDR GNU-Radio USRP Platform

USRP: Universal Software Radio Peripheral (Ettus) • What is GNU Radio? • Basic Concepts Software Radio • Developing Applications • UHD

2 • What is GNU Radio?

• Basic •ConceptsWhat is GNU Radio? • Basic Concepts • Developing• Developing Applications Applications • UHD • UHD

3

3 BASEBAND DIGITAL & RF ANTENNA PROCESSING FRONTEND

BASEBAND DIGITAL & RF ANTENNA PROCESSING FRONTEND What is GNU Radio?

• Software toolkit for signal processing • ProvidingWhat ais fast,GNU low Radio?-cost way to test algorithms and •waveformSoftware toolkit design for signal processing • Providing a fast, low-cost way to test algorithms and waveform design • USRP (Universal Software Radio Peripheral) • USRP (Universal Software Radio Peripheral) • Hardware TX/RX frontend • Hardware TX/RX frontend GNU Radio Components

GNU Radio Components Host Computer Hardware Frontend

Host Computer Hardware Frontend ADC/DAC and GNU Radio RF Frontend DigitalADC/DAC Frontend and GNU Radio RF Frontend Software Digital Frontend (Daughterboard) Software (USRP) (Daughterboard) (USRP) USRP1

• Features: – Frequency Range: DC-6 GHz – Connectivity for Two, Complete Tx/Rx chains – Two Dual 64 MS/s 12-bit ADCs – Two Dual 128 MS/s, 14-bit DACs – Up to 16 MS/s USB Streaming – Altera Cyclone FPGA USRP2/N200/N210

• Features: – Frequency Range: DC-6 GHz – 100 MS/s 14-bit ADC – 400 MS/s, 16-bit DAC – Up to 25 MS/s through Gigabit Ethernet Streaming (50 MS/s at 8 bits per sample) – Xilinx Spartan XC3SD3400A FPGA: 2368K Memory, 53K logic cells – MIMO Extension/ External Clock Synchronization USRP X300/310

• Features: – Frequency Range: DC-6 GHz – Two 200 MS/s 14-bit ADC – Two 800 MS/s, 16-bit DAC – Up to 200 MS/s through 10 Gigabit Ethernet or PCI Express – Xilinx Kintex-7 FPGA: 28620K memory, 406K logic cells – MIMO Extension External Clock Synchronization USRP Daughter Boards • Define Bandwidth, Frequency Range, Gain

SBX: 400MHz-4.4GHz WBX: 40MHz-2.2GHz CBX: 1.2GHz-6GHz (40MHz/120MHz) (40MHz/120MHz) (40MHz/120MHz)

UBX: 10MHz-6GHz Basic TX/RX LFTX/LFRX (40MHz/160MHz) 1MHz-250MHz 0MHz-30MHz GNU Radio Software

• Open source (GPL) GNU Radio Software • Existing examples: 802.11b, Zigbee, OFDM, DBPSK, • Open source (GPL) DQPSK … • Existing examples: 802.11b, Zigbee, OFDM, DBPSK, DQPSK … • Extensive library of signal processing blocks (C++) • Extensive library of signal processing blocks (C++)

• Modular• Modular design design (flow (flow graph) graph)

• GNU Radio + UHD • GNU Radio + UHD • What is GNU Radio?

• Basic •ConceptsWhat is GNU Radio? • Basic Concepts • Developing• Developing Applications Applications • UHD • UHD

11

11 Blocks

• Signal Processing Block

• AcceptsBlocks input streams

• Produces• Signal output Processing streams Block • Accepts input streams

• Source: No• inputProduces output streams • noise_source,• Source: No input • noise_source, signal_source,signal_source, usrp_sourceusrp_source • Sink: No outputs • Sink: No outputs • audio_alsa_sink, usrp_sink • audio_alsa_sink, usrp_sink Data Types

• Blocks operate on certain data types

• float,Data complex, Types int, char … • Blocks operate on certain data types • Vectors 1 or 2 streams • float, complex, int, char … of float

• Vectors 1 or 2 streams • IO Signature: of float • IO Signature: • Number of input ports • Number of input ports • Number• Numberof output of output ports ports • Item size of each port 1 stream • of complex Item size of each port 1 stream of complex

Flow Graph

• Blocks composed as a flow graph • DataFlow stream Graph flowing from sources to sinks • Blocks composed as a flow graph Signal• Data Source stream flowing from sources to sinks Sample Rate: 32k Waveform:Signal Sine Source Sample Rate: 32k FrequencyWaveform: 350Hz: Sine AmplitudeFrequency: 0.1 : 350Hz Amplitude: 0.1 AudioAudio Sink Sink Signal Source SampleSample Rate: 32k Rate : 32k Signal SourceSample Rate : 32k Sample RateWaveform: 32k: Sine Frequency: 440Hz WaveformAmplitude: Sine : 0.1 Frequency: 440Hz Amplitude: 0.1 Example Code

Example Code QPSK Demodulator Example

QPSK Demodulator Example • What is GNU Radio?

• Basic •ConceptsWhat is GNU Radio? • Basic Concepts • Developing• Developing Applications Applications • UHD • UHD

18

18 Development Architecture

• Python Development Architecture Python • Flow graph construction Flow graph construction • Python Python • Flow graph construction Flow graph construction

• C++ C++ • C++ C++ • Signal processing• Signal processing blocks blocks SignalSignal processing processing blocks blocks Python Example

Python Example Signal Source Sample Rate: option Waveform: Sine Signal Source FrequencySample: 350Hz Rate : option AmplitudeWaveform: 0.1 : Sine Frequency: 350Hz Amplitude: 0.1 Audio Sink SampleAudio Sink Rate: option Signal SourceSignal Source Sample Rate: option Sample RateSample: option Rate: option Waveform: Sine WaveformFrequency: Sine : 440Hz FrequencyAmplitude: 440Hz: 0.1 Amplitude: 0.1 #!/usr/bin/env python from gnuradio import gr from gnuradio import audio from gnuradio.eng_option import eng_option from optparse import OptionParser class my_top_block(gr.top_block): def __init__(self):#!/usr/bin/env python

gr.top_block.__init__(self)from gnuradio import gr from gnuradio import audio from gnuradio.eng_option import eng_option parser =from OptionParser(option_class=eng_option) optparse import OptionParser parser.add_option(" -O", "--audio-output", type="string", default="", class my_top_block(gr.top_block): def __init__(self): help="pcm output device name. E.g., hw:0,0") parser.add_option(" gr.top_block.__init__(self)-", "--sample -rate", type="eng_float", default=48000,

parser = help="setOptionParser(option_class=eng_option) sample rate to RATE (48000)") (options, args) parser.add_option(" = parser.parse_args-O", "--audio-output", () type="string", default="", help="pcm output device name. E.g., hw:0,0") if len(args) parser.add_option("!= 0: -r", "--sample-rate", type="eng_float", default=48000, parser.print_help() help="set sample rate to RATE (48000)") (options, args) = parser.parse_args () raise SystemExit, if len(args) != 1 0: parser.print_help() raise SystemExit, 1 sample_rate = int(options.sample_rate) ampl = 0.1 sample_rate = int(options.sample_rate) ampl = 0.1

src0 = gr.sig_source_f src0 = gr.sig_source_f (sample_rate, (sample_rate, gr.GR_SIN_WAVE,gr.GR_SIN_WAVE, 350, ampl) 350, ampl) src1 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 440, ampl) src1 = gr.sig_source_f dst = audio.sink (sample_rate,(sample_rate, options.audio_output) gr.GR_SIN_WAVE, 440, ampl) dst = audio.sink self.connect (sample_rate, (src0, (dst, 0)) options.audio_output) self.connect (src1, (dst, 1)) self.connect (src0, (dst, 0)) self.connectif __name__ (src1, == '__main__': (dst, 1)) try: my_top_block().run() if __name__ == '__main__': except KeyboardInterrupt: pass try: my_top_block().run() except KeyboardInterrupt: pass

from gnuradio import gr Import modules from GNU Radio library from gnuradio import audio from gnuradio.eng_option import eng_option from optparse import OptionParser

from gnuradio import gr Import modules from GNU Radio library from gnuradio import audio from gnuradio.eng_option import eng_option from optparse import OptionParser

class my_top_block(gr.top_block): Define container for Flow Graph def __init__(self): gr.top_block.__init__(self) gr.top_block class maintains the graph

class my_top_block(gr.top_block): Define container for Flow Graph def __init__(self): gr.top_block.__init__(self) gr.top_block class maintains the graph

Define and parse command-line options

parser = OptionParser(option_class=eng_option) Define and parse command-line options parser.add_option("-O", "--audio-output", type="string", default="", help="pcm output device name. E.g., hw:0,0") parser = OptionParser(option_class=eng_option) parser.add_option(" parser.add_option("-r", -"O",-- sample"--audio--output",rate", type="string", type="eng_float", default="", default=48000, help="pcm output device name. E.g., hw:0,0") parser.add_option(" help="set-r", "--samplesample-rate", rate type="eng_float", to RATE (48000)") default=48000, (options, args) = parser.parse_args help="set sample rate () to RATE (48000)") (options, args) = parser.parse_args () if len(args) if !=len(args) 0: != 0: parser.print_help() parser.print_help() raise SystemExit, 1 raise SystemExit, 1

Create and connect signal processing blocks

Create and connect signal processing blocks sample_rate = int(options.sample_rate) ampl = 0.1 sample_rate = int(options.sample_rate) ampl = 0.1 src0 = gr.sig_source_f src0 = gr.sig_source_f (sample_rate, (sample_rate, gr.GR_SIN_WAVE, gr.GR_SIN_WAVE, 350, ampl) 350, ampl) src1 = gr.sig_source_f (sample_rate, gr.GR_SIN_WAVE, 440, ampl) src1 = gr.sig_source_f dst = audio.sink (sample_rate,(sample_rate, options.audio_output) gr.GR_SIN_WAVE, 440, ampl) dst = audio.sink self.connect (sample_rate, (src0, (dst, 0)) options.audio_output) self.connect (src1, (dst, 1)) self.connect (src0, (dst, 0)) self.connect (src1, (dst, 1))

if __name__ == '__main__': try: my_top_block().run() Run the flow graph when the program is executed if __name__ == '__main__': except KeyboardInterrupt: try: pass

my_top_block().run() Run the flow graph when the program is executed except KeyboardInterrupt: pass

Creating Your Own Block

• Basics • A blockCreating is a C++ Your class Own Block • Typically• Basics derived from gr_block class • A block is a C++ class • Typically derived from gr_block class • Three components • my_block_xx.h• Three components: Block definition • my_block_xx.h: Block definition • my_block_xx.cc• my_block_xx.cc: Block: Block implementation implementation • my_block_xx.i• my_block_xx.i: Python: Python bindings bindings (SWIG (SWIG interface) interface) Block Definition

#include class my_block_cc;Block Definition

typedef boost::shared_ptr<6829_my_block_cc>#include 6829_my_block_cc_sptr;

class my_block_cc; 6829_my_block_cc_sptr 6829_make_my_block_cc(); Create instances of block typedef boost::shared_ptr<6829_my_block_cc> 6829_my_block_cc_sptr; class my_block_cc6829_my_block_cc_sptr : public gr_sync_block 6829_make_my_block_cc(); Create instances of block { class my_block_cc : public gr_sync_block private: { unsigned int d_count;private: unsigned int d_count;

friend 6829_my_block_cc_sptr friend 6829_my_block_cc_sptr 6829_make_my_block_cc(); 6829_make_my_block_cc();

6829_my_block_cc(); 6829_my_block_cc(); public: int work(int noutput_items, Method for processing public: gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); input streams and int work(int noutput_items,}; producing outputMethod streams for processing gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); input streams and }; producing output streams

Block Implementation

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

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

6829_my_block_cc_sptr#include 6829_make_my_block_cc() #include { return 6829_my_block_cc_sptr(new6829_my_block_cc_sptr 6829_make_my_block_cc() 6829_my_block_cc()); { } return 6829_my_block_cc_sptr(new 6829_my_block_cc()); }

6829_hw_sample_block_cc::6829_hw_sample_block_cc()6829_hw_sample_block_cc::6829_hw_sample_block_cc() : gr_sync_block("my_block_cc", : gr_sync_block("my_block_cc", gr_make_io_signature(1, 1, sizeof(gr_complex)), gr_make_io_signature(1, gr_make_io_signature(1, 1,1, sizeof(gr_complex))), sizeof(gr_complex)), d_count(0)gr_make_io_signature(1, 1, sizeof(gr_complex))), { Define input and d_count(0) } output signatures { Define input and } output signatures Block Implementation

int 6829_my_block_cc::work(int noutput_items, gr_vector_const_void_star &input_items, Block gr_vector_void_star Implementation &output_items) {

const gr_complex*int 6829_my_block_cc::work(int in = (const gr_complex*)input_items[0]; noutput_items, gr_complex* out = (gr_complex*)output_items[0]; gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { Copy input stream memcpy(out, in, const sizeof(*out) gr_complex* in = (const* noutput_items); gr_complex*)input_items[0]; gr_complex* out = (gr_complex*)output_items[0]; to output stream Copy input stream for (int i = 0; memcpy(out, i < noutput_items; in, sizeof(*out) * noutput_items);++i) to output stream

fprintf(stderr, for (int i = 0; i"%u < noutput_items;\t<%.6f, %.6f>++i) \n", Echo samples d_count++,fprintf(stderr, in[i].real(), "%u\t<%.6f, %.6f>\ n",in[i].imag()); Echo samples d_count++, in[i].real(), in[i].imag()); stderr stderr

return noutput_items; return noutput_items; Return number } Return number } of items processed of items processed • What is GNU Radio?

• Basic •ConceptsWhat is GNU Radio? • Basic Concepts • Developing• Developing Applications Applications • UHD • UHD

32

32 UHD (USRP Hardware Driver) • Why UHD? UHD (USRP Hardware Driver) • Why UHD?

• Having N drivers isn’t going to scale … • Having N drivers isn’t going to scale … UHD (USRP Hardware Driver) • Single API for all USRP devices • C++ basedUHD (USRP API Hardware Driver) • All daughterboards• Single API for all USRP devices • C++ based API • Inherent• All multidaughterboards-channel support - Synchronization• Inherent multi -channel support - Channel- Synchronization alignment - Channel alignment • Gnuradio• Gnuradio–UHD–UHD Blocks Blocks • Source Block, Sink Block • Source• Python,Block, C++ Sink Block • Python, C++

UHD (USRP Hardware Driver)

Send/Recv Samples USRPUHD (USRP Hardware Driver)C++ API Hardware Multi-USRP Send/Recv Samples USRP Set/Get Properties C++ API Hardware Multi-USRP Set/Get Properties

• Send/receive• Send/receive samples samples • device• device->send->send(...)(...) andand device device->recv-(...)>recv (...) • Set/get properties • Set/get properties

Device Properties • Set/get gain Device Properties • Set center frequency • Set/get gain • Set/get• Setdevice center frequencytime • Set/get• Set/getsample device rate time • Set/get sample rate • Antenna• Antenna selection selection • Frontend• Frontend selection selection ⁞ ⁞

Example: MIMO TX sudo ./tx_samples_multi_from_file_repeat --args="addr0=192.168.10.2,addr1=192.168.20.2"Example: MIMO TX --file_prefix="TX"sudo ./tx_samples_multi_from_file_repeat --rate=1000000--args="addr0=192.168.10.2,addr1=192.168.20.2" --file_prefix="TX" --freq=922000000--rate=1000000 --ant="TX/RX"--freq=922000000 --ant="TX/RX" --gain=10-- gain=10 --ref="external"--ref="external" --num_transmits=10 --num_transmits=10--scale=0.5 --scale=0.5 Example: MIMO TX sudo ./tx_samples_multi_from_file_repeat --args="addr0=192.168.10.2,addr1=192.168.20.2" Example: MIMO TX tx_samples_multi_from_file_repeat.cppsudo ./tx_samples_multi_from_file_repeat --args="addr0=192.168.10.2,addr1=192.168.20.2" uhd::usrp::multi_usrp ::sptr usrp = uhd::usrp::multi_usrp::make(args); tx_samples_multi_from_file_repeat.cpp uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args); Example: MIMO TX sudo ./tx_samples_multi_from_file_repeat --args="addr0=192.168.10.2,addr1=192.168.20.2"Example: MIMO TX --file_prefix="TX"sudo ./tx_samples_multi_from_file_repeat --rate=1000000--args="addr0=192.168.10.2,addr1=192.168.20.2" --file_prefix="TX" --freq=922000000--rate=1000000 --ant="TX/RX"--freq=922000000 --ant="TX/RX" --gain=10-- gain=10 tx_samples_multi_from_file_repeat.cpptx_samples_multi_from_file_repeat.cpp usrp->set_tx_rate(rate, i); usrp->set_tx_rate(rate,usrp->set_tx_freq(freq, i); i); usrp->set_tx_freq(freq,usrp->set_tx_antenna(ant, i); i); usrp->set_tx_gain(gain, i); usrp->set_tx_antenna(ant, i); usrp->set_tx_gain(gain, i);

Example: MIMO TX sudo ./tx_samples_multi_from_file_repeat --args="addr0=192.168.10.2,addr1=192.168.20.2"Example: MIMO TX --file_prefixsudo ./tx_samples_multi_from_file_repeat="TX" --rate=1000000--args="addr0=192.168.10.2,addr1=192.168.20.2" --file_prefix="TX" --freq=922000000--rate=1000000 --ant="TX/RX"--freq=922000000 --ant="TX/RX" --gain=10-- gain=10 --ref="external"--ref="external"

tx_samples_multi_from_file_repeat.cpp tx_samples_multi_from_file_repeat.cppusrp->set_clock_config(uhd::clock_config_t::external()); usrp->set_clock_config(uhd::clock_config_t::external()); • USRP http://www.ettus.com/resource • GNU Radio http://gnuradio.org/redmine/projects/gnuradio/wiki• USRP http://www.ettus.com/resource • Available Signal• GNU Radio Processing Blocks http://gnuradio.org/doc/doxygen/hierarchy.htmlhttp://gnuradio.org/redmine/projects/gnuradio/wiki • Available Signal Processing Blocks • GNU Radio http://gnuradio.org/doc/doxygen/hierarchy.htmlMailing List Archives http://www.gnu.org/software/gnuradio/mailinglists.html• GNU Radio Mailing List Archives http://www.gnu.org/software/gnuradio/mailinglists.html • USRP Mailing• USRP List Mailing List http://lists.ettus.com/pipermail/usrphttp://lists.ettus.com/pipermail/usrp-users_lists.ettus.com/-users_lists.ettus.com/ • UHD • UHD http://ettus-apps.sourcerepo.com/redmine/ettus/projects/uhd/wiki http://ettus-apps.sourcerepo.com/redmine/ettus/projects/uhd/wiki