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)-r", "--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
typedef boost::shared_ptr<6829_my_block_cc>#include
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
6829_my_block_cc_sptr#include
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