安装依赖的软件包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
#安装预编译版本,为后续编译减少依赖,预编译版本太老了 $ sudo apt-get install libarmadillo-dev $ cd ~ #编译安装最新版本的armadillo,gr-doa需要这个库的支持 $ git clone https://github.com/conradsnicta/armadillo-code.git $ cd armadillo-code $ mkdir build $ cd build $ cmake .. $ make $ sudo make install #编译安装SoapySDR,为我们后续操作LimeSDR准备操作接口 $ cd ~ $ git clone https://github.com/pothosware/SoapySDR.git $ cd SoapySDR $ git pull origin master $ mkdir build && cd build $ cmake .. $ make -j4 $ sudo make install $ sudo ldconfig #编译安装GrOsmoSDR,后续为了支持GnuRadio,我们需要GrOsmoSDR帮我们完成一个中转 $ cd ~ $ git clone git://git.osmocom.org/gr-osmosdr $ cd gr-osmosdr #修正几处问题 $ sed -i '$a\from _osmosdr_swig import source_IQBalanceOff' ./python/__init__.py $ sed -i '$a\from _osmosdr_swig import source_IQBalanceManual' ./python/__init__.py $ sed -i '$a\from _osmosdr_swig import source_IQBalanceAutomatic' ./python/__init__.py $ mkdir build $ cd build $ cmake .. $ make $ sudo make install $ sudo ldconfig #编译安装LimeSDR的驱动 $ git clone https://github.com/myriadrf/LimeSuite.git $ cd LimeSuite #建议2018年4月以后的的主分支,早期版本存在相位随时间漂移的问题 $ git checkout master # 不可删除build目录,清理build目录后要还原被误删除的文件, # 原因在于build目录下存在mcu程序,默认应用启动后从这个目录提取mcu程序刷新到设备 $ mkdir build ; cd build # cmake -DCMAKE_BUILD_TYPE=Debug .. $ cmake .. $ make -j4 $ sudo make install $ sudo ldconfig $ cd ../udev-rules/ $ sudo ./install.sh # Download board firmware $ sudo LimeUtil --update |
下载最新的gr-doa
源代码
1 2 3 4 |
#编译安装gr-doa $ cd ~ $ git clone https://github.com/EttusResearch/gr-doa.git |
增加limesdr
的调用代码:
1 2 3 4 5 |
$ sed -i "s/__init__.py/__init__.py\nlimesdr_soapysdr_source.py/g" ~/gr-doa/python/CMakeLists.txt $ sed -i "s/from twinrx_usrp_source import twinrx_usrp_source/from twinrx_usrp_source import twinrx_usrp_source\nfrom limesdr_soapysdr_source import limesdr_soapysdr_source/g" ~/gr-doa/python/__init__.py $ vim ~/gr-doa/python/limesdr_soapysdr_source.py |
具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# -*- coding: utf-8 -*- # # Copyright 2018 # longsky <wangqiang1588@sina.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # from gnuradio import gr from gnuradio import blocks import SoapySDR from SoapySDR import * #SOAPY_SDR_ constants import osmosdr from osmosdr import * from gnuradio.filter import firdes def gen_sig_io(num_elements): # Dynamically create types for signature io = [] for i in range(num_elements): io.append(gr.sizeof_gr_complex*1) io.append(gr.sizeof_float*num_elements) return io class limesdr_soapysdr_source(gr.hier_block2): def __init__(self, samp_rate=1000000, center_freq=2400000000, gain=40, sources=2): gr.hier_block2.__init__( self, "LimeSDR SoapySDR", gr.io_signature(0, 0, 0), gr.io_signaturev(sources, sources, gen_sig_io(sources)), ) ################################################## # Parameters ################################################## self.samp_rate = samp_rate self.center_freq = center_freq self.gain = gain self.sources = sources args = dict(driver="lime") limesdr = SoapySDR.Device(args) # We need to detect the number of channels as the LimeSDR has two # and the LimeSDR-Mini has one chans = range(limesdr.getNumChannels(0)) if len(chans) < sources : raise Exception("limesdr device doesn't provide enough rx channels ") while len(chans) > sources : chans.pop() limesdr = None #warnning: args must be written like below args = 'soapy=0,driver=lime,nchan=' + str(sources) self.osmosdr_source_0 = osmosdr.source(args) self.osmosdr_source_0.set_clock_source('internal', 0) self.osmosdr_source_0.set_sample_rate(self.samp_rate) #self.osmosdr_source_0.set_time_now(osmosdr.time_spec_t()) for ch in chans: self.osmosdr_source_0.set_gain(self.gain, ch) # print(self.limesdr.listAntennas(SOAPY_SDR_RX, 0)) # ('NONE', 'LNAH', 'LNAL', 'LNAW', 'LB1', 'LB2') #RX_L : is lower then 2.5Ghz,RX_H : higher than 2.5GhZ self.osmosdr_source_0.set_antenna("LNAH", ch) #self.osmosdr_source_0.set_bandwidth(ch,20*1000*1000) self.osmosdr_source_0.set_dc_offset_mode(osmosdr.source_IQBalanceAutomatic,ch) # Use timed commands to set frequencies self.set_center_freq(center_freq,sources) ################################################## # Connections ################################################## for source in range(sources): self.connect((self.osmosdr_source_0, source), (self, source)) def __del__(self): self.disconnect_all() if hasattr(gr.hier_block2,"__del__") : gr.hier_block2.__del__(self) def get_samp_rate(self): return self.samp_rate def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate self.osmosdr_source_0.set_sample_rate(self.samp_rate) def set_center_freq(self, center_freq, sources): self.center_freq = center_freq for ch in range(self.sources): self.osmosdr_source_0.set_center_freq(self.center_freq, ch) def get_center_freq(self): return self.center_freq def get_gain(self): return self.gain def set_gain(self, gain): print "DO NOT TUNE GAINS DURING RUNTIME" def get_sources(self): return self.sources def set_sources(self, sources): print "DO NOT CHANGE SOURCES DURING RUNTIME" |
编译代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ cd ~ $ cd gr-doa $ mkdir build $ cd build $ cmake .. $ make $ sudo make install $ sudo ldconfig |
测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
#!/usr/bin/env python2 # -*- coding: utf-8 -*- ################################################## # GNU Radio Python Flow Graph # Title: Run Rootmusic Lin Array LimeSDR # Generated: Tue Apr 3 20:14:45 2018 ################################################## if __name__ == '__main__': import ctypes import sys if sys.platform.startswith('linux'): try: x11 = ctypes.cdll.LoadLibrary('libX11.so') x11.XInitThreads() except: print "Warning: failed to XInitThreads()" def struct(data): return type('Struct', (object,), data)() from PyQt4 import Qt from gnuradio import eng_notation from gnuradio import gr from gnuradio.eng_option import eng_option from gnuradio.filter import firdes from optparse import OptionParser import doa import sys class run_RootMUSIC_lin_array_LimeSDR(gr.top_block, Qt.QWidget): def __init__(self): gr.top_block.__init__(self, "Run Rootmusic Lin Array LimeSDR") Qt.QWidget.__init__(self) self.setWindowTitle("Run Rootmusic Lin Array LimeSDR") try: self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) except: pass self.top_scroll_layout = Qt.QVBoxLayout() self.setLayout(self.top_scroll_layout) self.top_scroll = Qt.QScrollArea() self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) self.top_scroll_layout.addWidget(self.top_scroll) self.top_scroll.setWidgetResizable(True) self.top_widget = Qt.QWidget() self.top_scroll.setWidget(self.top_widget) self.top_layout = Qt.QVBoxLayout(self.top_widget) self.top_grid_layout = Qt.QGridLayout() self.top_layout.addLayout(self.top_grid_layout) self.settings = Qt.QSettings("GNU Radio", "run_RootMUSIC_lin_array_LimeSDR") self.restoreGeometry(self.settings.value("geometry").toByteArray()) ################################################## # Variables # NormSpacing 天线之间的实际距离,单位为米,类型为浮点类型 # NumTargets 发出信号的设备数量 ################################################## self.input_variables = input_variables = struct({"SampleRate": 1000000, "CenterFreq": 2550000000, "Gain": 60, "NumArrayElements": 2, "NormSpacing": 0.5, "SnapshotSize": 2**11, "OverlapSize": 2**9, "NumTargets": 1, }) ################################################## # Blocks ################################################## self.limesdr = doa.limesdr_soapysdr_source( samp_rate=input_variables.SampleRate, center_freq=input_variables.CenterFreq, gain=input_variables.Gain, sources=input_variables.NumArrayElements ) self.tab = Qt.QTabWidget() self.tab_widget_0 = Qt.QWidget() self.tab_layout_0 = Qt.QBoxLayout(Qt.QBoxLayout.TopToBottom, self.tab_widget_0) self.tab_grid_layout_0 = Qt.QGridLayout() self.tab_layout_0.addLayout(self.tab_grid_layout_0) self.tab.addTab(self.tab_widget_0, "Angle of Arrival") self.top_layout.addWidget(self.tab) self.doa_rootMUSIC_linear_array_0 = doa.rootMUSIC_linear_array(input_variables.NormSpacing, input_variables.NumTargets, input_variables.NumArrayElements) self.doa_qt_compass_0 = doa.compass("", 0, 180, 10, 0) self.top_layout.addLayout(self.doa_qt_compass_0.this_layout) self.doa_autocorrelate_0 = doa.autocorrelate(input_variables.NumArrayElements, input_variables.SnapshotSize, input_variables.OverlapSize, 1) ################################################## # Connections ################################################## self.connect((self.doa_autocorrelate_0, 0), (self.doa_rootMUSIC_linear_array_0, 0)) self.connect((self.doa_rootMUSIC_linear_array_0, 0), (self.doa_qt_compass_0, 0)) for ch in range(input_variables.NumArrayElements) : self.connect((self.limesdr, ch), (self.doa_autocorrelate_0, ch)) def closeEvent(self, event): self.settings = Qt.QSettings("GNU Radio", "run_RootMUSIC_lin_array_LimeSDR") self.settings.setValue("geometry", self.saveGeometry()) event.accept() def main(top_block_cls=run_RootMUSIC_lin_array_LimeSDR, options=None): from distutils.version import StrictVersion if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"): style = gr.prefs().get_string('qtgui', 'style', 'raster') Qt.QApplication.setGraphicsSystem(style) qapp = Qt.QApplication(sys.argv) tb = top_block_cls() tb.start() tb.show() def quitting(): tb.stop() tb.wait() qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting) qapp.exec_() if __name__ == '__main__': main() |
如果上面的代码下载困难,可从本站下载一份代码拷贝
gr-doa,armadillo-code,SoapySDR源代码下载,gr-osmosdr
至于测试的信号发送设备,任何能产生自相关信号的设备都可以,一般建议对讲机即可,注意频率要调整到一致才可以。
参考链接
- Direction Finding with the USRP™ X-Series and TwinRX™
- pothosware/SoapySDR
- LimeSDR setup with GnuRadio
- Parameter needed to switch RX input in gnuradio for limesdr
- osmocom Gnu Radio Blocks
- Latest (Aug 2017) LimeSDR and GnuRadio
- Python osmosdr.source() Examples
- Two RX channels in GNU Radio
- RX channels alignment
- Application for using the 2 RX channels simultaneously
- TDOA application
- Issues with using LimeSDR in MIMO2x2 Spatial Multiplexing Mode