基于UHD源码实现的四通道收发实例

2021/7/5 22:22:26

本文主要是介绍基于UHD源码实现的四通道收发实例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1. Introduction

        本次项目所用的PC环境为Ubuntu16.04,USRP型号为 N310。具体的N310设备简介可以参考ETTUS官网的用户手册(https://files.ettus.com/manual/page_usrp_n3xx.html)

图1

如图1所示,USRP-N310共具有四个收发通道,可以同时实现四路信号的收发。从LTE系统开始,MIMO技术已经逐渐开始应用。在未来的5G-R(5G for Railway)系统中也将采用MIMO技术。目前基于USRP的多通道收发范例都是通过Labview实现的,该语言由美国国家仪器(NI)公司研制开发,类似于C和BASIC开发环境,但是Labview与其他计算机语言的显著区别是:其他计算机语言都是采用基于文本的语言产生代码,而Labview使用的是图形化编程语言。同时Labview入门较困难,不适合SDR(Software-Defined Radio)初学者,因此推荐使用UHD( USRP Universal Hardware Driver)范例进行二次开发。UHD范例全部是由C++编写,适合SDR初学者阅读和开发。

2. UHD安装教程

CSDN上可以查找到很多关于UHD安装的资料,此部分不做详细阐述。具体的安装流程可以参考ubuntu16.04下安装uhd与gnuradio

需要注意的是,博主采用的UHD版本是v3.15.0.0,克隆UHD源码后,需要采用git checkout进行分支切换。

UHD github链接

3. 官方实例

UHD范例所在路径如下:XXX/uhd/host/build/examples (XXX为 第2部分中源码所在位置)

图2

本博客的四通道收发范例基于UHD基础范例:tx_waveforms编写,因此先介绍tx_waveforms范例的功能和代码架构。

相关范例的CPP文件在路径: XXX/uhd/host/example下,修改完相应的CPP文件后,需要重新进行 

sudo make

sudo make install

sudo ldconfig

进行编译,编译通过后便可运行相关的范例实例。

uhd_tx_waveforms可以通过USRP实现简单的波形发送(方波、正弦波、斜波等波形),该范例可以通过用户命令行配置,实现振幅、中心频率、带宽、天线等选择、设置。

范例功能:自定义带宽、采样率、频率、天线等参数,进行固定波形发送。

--args arg                指定USRP IP地址

--spb arg (=0)            指定每个buffer的采样数

--nsamps arg (=0)         发送的总采样数

--rate arg                采样发送速率

--freq arg                射频中心频率

--lo-offset arg (=0)         LO偏移频率

--ampl arg (=0.300000012) 发送波形幅值 [0 to 0.7]

--gain arg               射频增益

--ant arg                选择天线端口

--subdev arg             主板选择

--bw arg                 模拟前端滤波器

--wave-type arg (=CONST) 固定波形选择 (CONST, SQUARE, RAMP, SINE)

--wave-freq arg (=0)      发送波形频率

--ref arg (=internal)        时钟源 (internal, external, mimo, gpsdo)

--pps arg                 PPS source (internal, external, mimo, gpsdo)

--otw arg (=sc16)         over-the-wire sample mode 线缆采样模式

--channels arg (=0)       指定数据流传输通道

--int-n                   tune USRP with integer-N tuning (具体功能不太懂,百度可以查到相关论文,貌似是可以降低低频处的噪声信号)

范例的代码架构如图3所示,时间有点紧迫,因此这个框图采用在线软件画的,可能不是很清楚,需要的朋友可以私聊我,可以给你发具体的PDF文件。

图3

  • sig_int_handler [ void sig_int_handler(int) ]

此函数可以实现ctrl + c强行结束程序

  • po::variables_map vm 、 po::store(po::parse_command_line(argc, argv, desc), vm)、po::notify(vm)

通过调用boost库,可以实现从命令行直接读取参数,对变量进行赋值。

  • create a usrp device

uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args)

通过读取命令行设置的args (usrp 地址)实现对USRP的选择、驱动

  • 选择USRP子板

usrp->set_tx_subdev_spec(subdev);

通过读取命令行设置的subdev 实现对USRP子板的选择

  • 确定已用通道编号

boost::split(channel_strings, channel_list, boost::is_any_of("\"',"));

C++标准库,boost:split(存储切割结果的容器,要分割的内容,分割条件“\” 将channel list按照分割条件切割,存进channel_strings

  • 确定通道总数

利用for循环,channel_nums.push_back(std::stoi(channel_strings[ch])); 将channel_strings转换为十进制放入vector channel_num的尾部,以便后续读取

  • 锁定母板时钟

usrp->set_clock_source(ref)

  • 设定发送速率 & 实际发送速率

// 输出命令行预设速率

std::cout << boost::format("Setting TX Rate: %f Msps...") % (rate / 1e6) << std::endl;

// 输出实际发送速率

usrp->set_tx_rate(rate);

std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate() / 1e6)

  • 设定发送频率 & 实际发送频率

// 预设频率

std::cout << boost::format("Setting TX Freq: %f MHz...") % (freq / 1e6)

// 实际发送频率

利用for循环( size_t ch = 0; ch < channel_nums.size(); ch++ ),遍历每个通道

usrp->set_tx_freq(tune_request, channel_nums[ch]);

std::cout << boost::format("Actual TX Freq: %f MHz...")

% (usrp->get_tx_freq(channel_nums[ch]) / 1e6)

  • 设定发送增益

usrp->set_tx_gain(gain, channel_nums[ch]);

std::cout << boost::format("Actual TX Gain: %f dB...")

% usrp->get_tx_gain(channel_nums[ch])

  • 设定模拟前置滤波器带宽

usrp->set_tx_bandwidth(bw, channel_nums[ch]);

std::cout << boost::format("Actual TX Bandwidth: %f MHz...")

% usrp->get_tx_bandwidth(channel_nums[ch])

  • 设定天线

usrp->set_tx_antenna(ant, channel_nums[ch]);

  • 创建发送数据流 (Create a transmit streamer)

uhd::stream_args_t stream_args("fc32", otw);

// stream_args_t (cpu, otw)

cpu是指内存中的数据格式

fc64 - complex<double>

fc32 - complex<float>

sc16 - complex<int16_t>

sc8 - complex<int8_t>

       otw是指在线缆上传输的数据类型

              sc16 - Q16 I16

          sc8 - Q8_1 I8_1 Q8_0 I8_0

          sc12 (Only some devices)

uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);

从usrp中提取成员 get_tx_stream赋值给 tx_stream

创建buffer,通过通道间复用buffer实现多通道数据流发送

std::vector<std::complex<float>> buff(spb);

std::vector<std::complex<float>*> buffs(channel_nums.size(), &buff.front());

数据发送模式(先存再发)

利用for循环,向buff里存波表数据

for (size_t n = 0; n < buff.size(); n++) {

                      buff[n] = wave_table(index += step); }

发送数据

num_acc_samps += tx_stream->send(buffs, buff.size(), md)

4. 基于UHD源码编写的四通道实例

本实例是基于标准范例tx_waveforms编写,主要框架与第3部分框架相同,具体的程序逻辑可以参考图3。

本实例修改了部分help提示信息,便于使用者理解,同时代码里也有少量的英文注释。

--file arg 支持发送用户自定义的波形、信号信息。(文件后缀需要为.bin类型)使用者可以采用Matlab生成信号波形,然后经过USRP发送,连接示波器进行性能验证。

--otw arg 代表了线缆上传输的数据类型(Over the wire type)

sudo ./tx_samples_from_file --args "addr=192.168.20.2" --file "zp10M.bin" --rate "15.36e6" --freq "2100e6" --gain "15" --ant "TX/RX"  --channels "0,1,2,3" --otw "sc8" --int-n 4

(实验室的师姐使用该范例验证了Matlab 5G toolbox下的FRC信号,具体的IQ排列可以参考Matlab代码)

图4

终端运行状态:

图5

USRP N310运行状态

红灯亮代表该通道已激活,处在运行状态

图6 N310运行状态图

(范例完整代码将上传Github,但是今天梯子挂掉了,明天换个新的加速器后上传代码)

Github 链接如下:

XXXX



这篇关于基于UHD源码实现的四通道收发实例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程