This project aims to provide a flexible software architecture, to implement and test DoA methods for various RF communication protocols.
- MultiSync for simultaneous processing and phase offset correction with multiple generic frame synchronizers based on Liquid-DSP
- multi_rx.h for synchronized processing of multiple USRP RX streams in separated threads
- ZMQ TCP interface for forwarding of CFRs to the python app running the DoA algorithm
- MATLAB export to generate .m files for plotting CFR and constellation diagrams (check matlabXport)
- MUSIC Algorithm (multiple signal classification) python app based on pyespargos
- Main Application to estimate the DoA of an OFDM transmitter using USRPs connected via UHD
Simulations provided in ./simulations demonstrate the usage of the provided modules, illustrate the underlying mathematical concepts and show the simulation results:
Measurements show the real-world DoA results of the Application using two USRP N210 with WBX daughterboard and provide the corresponding datasets.
The Main Application gives you a functioning example on how to employ the provided modules for DoA estimation with USRP N210.
---
config:
look: classic
layout: elk
theme: redux
---
flowchart TD
FrameGen["Frame Generator"]
subgraph HardwareInterface["SDR Hardware Interface"]
subgraph T_StreamWorker["Stream-Worker"]
UsrpDevices["USRP Device Interface [0..*]"]
UsrpConf["USRP Interface Setup"]
StreamConf["Timed Stream Command"]
end
subgraph T_RxWorker["RX-Worker [0..*]"]
RxStream["RX Stream Interface"]
SampleBlock["Sample Block Buffer"]
end
subgraph T_TxWorker["TX-Worker [0..*]"]
TxStream["TX Stream Interface"]
TxBuffer["TX Buffer"]
end
end
subgraph T_SyncWorker["Sync-Worker"]
MultiSync["Multi-Channel Synchronization"]
PhiErrorCorrection["Phase Offset Correction"]
end
subgraph T_CfrWorker["CFR-Worker"]
ZmqSocket["ZMQ socket"]
MatlabCfrExport["MATLAB Export"]
FindGroups["Find CFR Groups"]
end
subgraph T_CbDataWorker["Callback-Data-Worker"]
MatlabCbExport["MATLAB Export"]
end
subgraph T_TerminalWorker["Terminal-Worker"]
CheckForPhaseCmd["Check for Phase Adjustment Command"]
CheckForExitCmd["Check for Exit Command"]
Exit["Exit Streaming"]
ReadInput["Read Terminal Inputs"]
end
UsrpConf -- Configure Interfaces ---> UsrpDevices
UsrpDevices -- Provide Device Time --> StreamConf
StreamConf -- Issue Command --> UsrpDevices
UsrpDevices -- Provide Stream Instance ---> RxStream & TxStream
RxStream -- Forward Samples --> SampleBlock
RxStream -- Provide Timestamp --> SampleBlock
SampleBlock -- Push Sample Block --> RxSampleQueue["RX Sample Queue [0..*]"]
CheckForPhaseCmd -- Push Phase Offset ---> PhiErrorQueue["Phase Offset Queue"]
PhiErrorQueue -- Provide Phase Offset ---> PhiErrorCorrection
PhiErrorCorrection -- Adjust Phase ---> MultiSync
RxSampleQueue -- Provide Sample Blocks ---> MultiSync
FrameGen -- Write Content ---> TxBuffer
TxStream -- Transmit Content ---> TxBuffer
MultiSync -- Push Callback Data ---> CbDataQueue["CB-Data Queue"]
CbDataQueue -- Provide Callback Data ---> MatlabCbExport
MultiSync -- Push CFR ---> CfrQueue["CFR Queue"]
CfrQueue -- Provide CFR ---> FindGroups
FindGroups -- Provide Group ---> ZmqSocket & MatlabCfrExport
ReadInput -----> CheckForPhaseCmd & CheckForExitCmd
CheckForExitCmd -- Triggers ---> Exit
The following diagram illustrates, how samples are streamed from the two SDR-instance, synchronized as sample-blocks with a unique timestamp based on the SDRs device-time and ho the CFRs fro detected frames are grouped and forwarded to the MUISC-algorithm.
---
config:
look: classic
layout: elk
theme: redux
---
flowchart TD
Sdr1["SDR Channel 1"]
Sdr2["SDR Channel 2"]
subgraph HardwareInterface["SDR Hardware Interface"]
Rx1["RX Channel 1"]
Rx2["RX Channel 2"]
end
MultiSync["MultiSync"]
Socket["Socket"]
subgraph CbExport["Datasymbol Export"]
MatlabExportCb["Matlab Export"]
end
subgraph CfrExport["CFR Export"]
Grouping["Time-based Grouping"]
MatlabExportCfr["Matlab Export"]
ZmqExportCfr["Zmq Export"]
end
subgraph DoAAlgorithm["DoA Estimation"]
ZmqImportCfr["Zmq Import"]
MusicAlg["MUISC Algorithm"]
end
Sdr1 -- Sample-Stream ---> Rx1
Sdr2 -- Sample-Stream ---> Rx2
Sdr1 -- Timestamp ---> Rx1
Sdr2 -- Timestamp ---> Rx2
Rx1 -- Sample-Block & Timestamp ---> MultiSync
Rx2 -- Sample-Block & Timestamp ---> MultiSync
MultiSync -- Datasymbols & Timestamp ---> MatlabExportCb
MultiSync -- CFR & Timestamp ---> Grouping
Grouping -- CFR-Group & Timestamp ---> MatlabExportCfr
Grouping -- CFR-Group ---> ZmqExportCfr
ZmqExportCfr -- CFR-Group ---> Socket
Socket -- CFR-Groups [1..*] --->ZmqImportCfr
ZmqImportCfr -- CFR-Groups [1..*] ---> MusicAlg
The software is tested using two USRP N210 with the WBXv3 daughterboard. Phase synchronization is achieved with the MIMO-cable. The USRPs are connected to the host by separate ethernet interfaces. For utilizing a different type of SDRs, the interfaces can be implemented in separated threads similar to multi_rx.h
.
One USRP is used for transmitting and receiving the OFDM packages while the other USRP is used in RX-mode only. The MUSIC-spectrum visualizes the position of the TX-antenna.
Make sure, the receiving antennas are spaced by the half wavelength of the carrier frequency (e.g. 12cm for a carrier of 1.25GHz).
- Clone the Repo to your local machine
- Setup a virtual environment within the
./music/
directory
cd ./music python -m venv env
- Install all python dependencies specified in
requirements.txt
source env/bin/activate pip install -e .
- Use the CMake extension to configure the project
- Set
doa4rfc
as target for build and execution (or any example-file) - Go to the vscode "run and debug" menu and start the
Debug (Clang CMake Preset)
task to build and run the specified target
Make sure, that all USRPs are connected via separate Ethernet interfaces, since the datarate can possibly cause overflows in the shared-Etehrnet mode. Check the USRP connection by running uhd_find_devices
.
- ZMQ for socket communication with the Python-implemented DoA Algorithm
- Liquid-DSP for frame-detection, generation and synchronization
- UHD for USRP communication