UHD介绍
UHD是USRP开源软件无线电硬件架构的底层软件包,包含上位机和USRP设备中的FPGA的bit文件两个部分。提供了上位机控制FPGA和射频前端采集和处理数据的软件接口。具体实现了数字变频,射频电路切换,数据采集传输,IO口控制等功能。NI labview usrp的实例包含在uhd的框架规范内。
如果想把usrp当作复杂系统里的一个数据采集设备,采用matlab,labview等软件无法方便的和其他设备与深度学习等算法相集成。采用UHD提供的Python API可以方便简单的在系统中集成一些基本功能。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210414003018785.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ1NDE0Nw==,size_16,color_FFFFFF,t_70)
安装UHD
Windows下直接下载相应版本安装包VS2019版本下载链接进行安装,也可以选择其他版本,安装后可以参照UHD VS配置教程检查环境变量是否正确。
烧写X310固件
运行UHD API 上位机API需要对应版本的X310固件,按照官方教程,连接网线,配置上位机IP地址,在cmd中使用预编译好的tools直接下载fpga固件。
uhd_image_loader --args="type=x300,addr=192.168.10.2" --fpga-path="<path_to_images>/usrp_x310_fpga_HG.bit"
在uhd的安装文件加下可以找到对应的bit文件。
安装uhd python API
UHD官方说明文档仅仅给出了源码编译的安装方案,需要安装cmake等依赖后编译半小时左右。其实可以直接在conda 里面直接安装。
conda create -n usrp python=3.7 #新建一个环境防止依赖冲突
conda activate usrp
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ #添加清华镜像源
conda install uhd
在3.7环境下安装的是UHD4.0.0版本,在py3.6环境下自动安装的是3.15版本
测量功率实例
该实例是github UHD上自带的python例程,仅支持uhd4.0.0
#!/usr/bin/env python3
#
# Copyright 2020 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
"""
Use a calibrated USRP as a power meter
"""
import sys
import signal
import argparse
import uhd
def parse_args():
"""Parse the command line arguments"""
parser = argparse.ArgumentParser()
parser.add_argument("-a", "--args", default="", # ip=192.168.10.3
help="USRP Device Args")
parser.add_argument("-f", "--freq", type=float, default=2412000000, # required=True,
help="Center Frequency")
parser.add_argument("-o", "--lo-offset", type=float, default=0.0,
help="Optional LO offset")
parser.add_argument("-c", "--channel", type=int, default=[0],
help="USRP RX Channel Index")
parser.add_argument("-t", "--antenna", default='TX/RX',
help="USRP RX Antenna")
parser.add_argument("-r", "--rate", default=1e6, type=float,
help="Sampling Rate")
parser.add_argument("-b", "--bandwidth", type=float,
help="Analog filter bandwidth (if supported)")
parser.add_argument("-l", "--ref-level", type=float, default=-15,
help="RX reference power level. "
"This should be higher than the expected power.")
parser.add_argument("-n", "--samps-per-est", type=float, default=1e6,
help="Samples per estimate.")
parser.add_argument("--mode", choices=['one-shot', 'continuous'], default='continuous',
help="Measure once, or keep measuring until Ctrl-C is pressed.")
return parser.parse_args()
def get_streamer(usrp, chan):
"""
Return an RX streamer with fc32 output
"""
stream_args = uhd.usrp.StreamArgs('fc32', 'sc16')
stream_args.channels = [chan]
return usrp.get_rx_stream(stream_args)
def setup_device(usrp, args):
"""
Apply the settings from args to the device
"""
chan = args.channel[0]
# if chan > usrp.get_rx_num_channels():
# print("ERROR: Invalid channel selected: {} (only {} channels available!)"
# .format(chan, usrp.get_rx_num_channels()))
# raise RuntimeError("Invalid channel selected")
# print("Using channel: {}".format(chan))
if args.antenna:
print("Setting RX antenna to `{}'...".format(args.antenna), end='')
usrp.set_rx_antenna(args.antenna, chan)
print("OK")
# if not usrp.has_rx_power_reference(chan):
# antenna = usrp.get_rx_antenna()
# print("ERROR: This device is not calibrated for RX at RF%d-%s!" % (chan, antenna))
# raise RuntimeError("Device not calibrated for selected antenna")
print("Requesting RX rate of {} Msps...".format(args.rate / 1e6), end='')
usrp.set_rx_rate(args.rate, chan)
if abs(usrp.get_rx_rate(chan) - args.rate) > 1.0:
print("ALMOST. Actual rate: {} Msps"
.format(usrp.get_rx_rate(chan) / 1e6))
else:
print("OK")
print("Requesting RX frequency of {} MHz...".format(args.freq / 1e6), end='')
tr = uhd.types.TuneRequest(args.freq, args.lo_offset)
usrp.set_rx_freq(tr, chan)
if abs(usrp.get_rx_freq(chan) - args.freq) > 1.0:
print("ALMOST. Actual frequency: {} MHz".format(usrp.get_rx_freq(chan) / 1e6))
else:
print("OK")
print("Requesting RX power reference level of {:.2f} dBm..."
.format(args.ref_level), end='')
# usrp.set_rx_power_reference(args.ref_level, chan)
# # ref_level = usrp.get_rx_power_reference(chan)
# if abs(ref_level - args.ref_level) > 1.0:
# print("ALMOST. Actual ref level: {:.2f} dBm".format(ref_level))
# else:
# print("OK")
if args.bandwidth:
print("Requesting analog RX bandwidth of {} Msps..."
.format(args.bandwidth), end='')
usrp.set_rx_bandwidth(args.bandwidth, chan)
if abs(usrp.get_rx_bandwidth(chan) - args.bandwidth) > 1.0:
print("ALMOST. Actual bandwidth: {} MHz"
.format(usrp.get_rx_bandwidth(chan) / 1e6))
else:
print("OK")
ref_level = 0
return (chan, ref_level)
def setup_device2(usrp, args):
"""
Apply the settings from args to the device
"""
chan = args.channel[0]
# if chan > usrp.get_rx_num_channels():
# print("ERROR: Invalid channel selected: {} (only {} channels available!)"
# .format(chan, usrp.get_rx_num_channels()))
# raise RuntimeError("Invalid channel selected")
# print("Using channel: {}".format(chan))
if args.antenna:
print("Setting RX antenna to `{}'...".format(args.antenna), end='')
usrp.set_rx_antenna(args.antenna, chan)
print("OK")
# if not usrp.has_rx_power_reference(chan):
# antenna = usrp.get_rx_antenna()
# print("ERROR: This device is not calibrated for RX at RF%d-%s!" % (chan, antenna))
# raise RuntimeError("Device not calibrated for selected antenna")
print("Requesting RX rate of {} Msps...".format(args.rate / 1e6), end='')
usrp.set_rx_rate(args.rate, chan)
if abs(usrp.get_rx_rate(chan) - args.rate) > 1.0:
print("ALMOST. Actual rate: {} Msps"
.format(usrp.get_rx_rate(chan) / 1e6))
else:
print("OK")
print("Requesting RX frequency of {} MHz...".format(args.freq / 1e6), end='')
tr = uhd.types.TuneRequest(args.freq, args.lo_offset)
usrp.set_rx_freq(tr, chan)
if abs(usrp.get_rx_freq(chan) - args.freq) > 1.0:
print("ALMOST. Actual frequency: {} MHz".format(usrp.get_rx_freq(chan) / 1e6))
else:
print("OK")
print("Requesting RX power reference level of {:.2f} dBm..."
.format(args.ref_level), end='')
# usrp.set_rx_power_reference(args.ref_level, chan)
# # ref_level = usrp.get_rx_power_reference(chan)
# if abs(ref_level - args.ref_level) > 1.0:
# print("ALMOST. Actual ref level: {:.2f} dBm".format(ref_level))
# else:
# print("OK")
if args.bandwidth:
print("Requesting analog RX bandwidth of {} Msps..."
.format(args.bandwidth), end='')
usrp.set_rx_bandwidth(args.bandwidth, chan)
if abs(usrp.get_rx_bandwidth(chan) - args.bandwidth) > 1.0:
print("ALMOST. Actual bandwidth: {} MHz"
.format(usrp.get_rx_bandwidth(chan) / 1e6))
else:
print("OK")
ref_level = 0
return (chan, ref_level)
RUN = True
def main():
"""
gogogo
"""
args = parse_args()
usrp = uhd.usrp.MultiUSRP(args.args)
# uhd.usrp.SubdevSpec("A:0 B:1")
(chan, ref_level) = setup_device(usrp, args)
setup_device2(usrp, args)
streamer = get_streamer(usrp, args.channel[0])
if args.mode == 'continuous':
def handle_sigint(_sig, _frame):
print("Caught Ctrl-C, exiting...")
global RUN
RUN = False
signal.signal(signal.SIGINT, handle_sigint)
while RUN:
try:
power_dbfs = uhd.dsp.signals.get_usrp_power(
streamer, num_samps=int(args.samps_per_est), chan=chan)
except RuntimeError:
# This is a hack b/c the signal handler is not gracefully handling
# SIGINT
break
power_dbm = power_dbfs + ref_level
print("Received power: {:+6.2f} dBm".format(power_dbm))
if args.mode == 'one-shot':
break
return True
if __name__ == "__main__":
sys.exit(not main())
运行结果如下
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210414160234975.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ1NDE0Nw==,size_16,color_FFFFFF,t_70)
MATLAB中读取usrp保存的数据
f = fopen('C:/Users/admin/Desktop/usrppy/uhd/host/examples/python/a.txt','rb')
[data,count] = fread(f,inf,"float32")
plot(data(1:2:10000))
hold on
plot(data(2:2:10000))
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210504145933852.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ1NDE0Nw==,size_16,color_FFFFFF,t_70)