...
 
Commits (7)
......@@ -17,10 +17,12 @@
#include "include/Radio.h"
#include "include/comms-lib.h"
#include "include/macros.h"
#include "include/matplotlibcpp.h"
#include "include/utils.h"
#ifdef MATPLOTLIB
#include "include/matplotlibcpp.h"
namespace plt = matplotlibcpp;
#endif
static std::vector<std::complex<float>> snoopSamples(SoapySDR::Device* dev, size_t channel, size_t readSize)
{
......@@ -169,6 +171,7 @@ static void adjustCalibrationGains(std::vector<SoapySDR::Device*> rxDevs, SoapyS
}
toneLevels[r] = toneLevel;
cout << "Node " << r << ": toneLevel3=" << toneLevel << endl;
#ifdef MATPLOTLIB
if (plot) {
auto fftMag = CommsLib::magnitudeFFT(samps, win, N);
std::vector<double> magDouble(N);
......@@ -191,6 +194,7 @@ static void adjustCalibrationGains(std::vector<SoapySDR::Device*> rxDevs, SoapyS
plt::legend();
plt::save("rx" + std::to_string(rxDevsSize) + "_" + std::to_string(r) + "_ch" + std::to_string(channel) + ".png");
}
#endif
}
std::cout << rxDevsSize - remainingRadios << " radios reached target level" << std::endl;
......
......@@ -2,9 +2,9 @@ cmake_minimum_required (VERSION 2.8)
project (Sounder)
set(CMAKE_C_FLAGS "-std=c99 -Wall")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -O3 -mavx2 -mavx")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall -O3")
find_package(nlohmann_json 3.2.0 REQUIRED)
#find_package(nlohmann_json 3.2.0 REQUIRED)
find_package(PythonLibs REQUIRED)
########################################################################
......@@ -25,7 +25,7 @@ endif ()
set(directory "logs")
file(MAKE_DIRECTORY ${directory})
add_definitions(-DJSON)
#add_definitions(-DJSON)
add_definitions(-DTHREADED_INIT)
message(STATUS "PYTHON_LIBRARIES: ${PYTHON_LIBRARIES}")
......@@ -36,5 +36,5 @@ message(STATUS "HDF5_LIBRARIES: ${HDF5_LIBRARIES}")
include_directories(${SoapySDR_INCLUDE_DIRS} ${HDF5_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
add_executable(sounder main.cc ClientRadioSet.cc config.cc Radio.cc receiver.cc recorder.cc BaseRadioSet.cc BaseRadioSet-calibrate.cc comms-lib.cc utils.cc signalHandler.cpp)
target_link_libraries(sounder -lpthread -lhdf5_cpp --enable-threadsafe ${SoapySDR_LIBRARIES} ${HDF5_LIBRARIES} ${CMAKE_SOURCE_DIR}/mufft/libmuFFT.a ${CMAKE_SOURCE_DIR}/mufft/libmuFFT-sse.a ${CMAKE_SOURCE_DIR}/mufft/libmuFFT-sse3.a ${CMAKE_SOURCE_DIR}/mufft/libmuFFT-avx.a ${PYTHON_LIBRARIES})
target_link_libraries(sounder -lpthread -lhdf5_cpp --enable-threadsafe ${SoapySDR_LIBRARIES} ${HDF5_LIBRARIES} ${CMAKE_SOURCE_DIR}/mufft/libmuFFT.a)
......@@ -46,8 +46,6 @@ ClientRadioSet::ClientRadioSet(Config* cfg)
continue;
}
auto dev = radios.back()->dev;
SoapySDR::Kwargs info = dev->getHardwareInfo();
for (auto ch : { 0, 1 }) //channels)
{
double rxgain = _cfg->clRxgain_vec[ch][i]; // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:108]
......@@ -100,11 +98,11 @@ ClientRadioSet::ClientRadioSet(Config* cfg)
tddConf["symbol_size"] = _cfg->sampsPerSymbol;
std::string tddConfStr = tddConf.dump();
#else
std::string tddConfStr = "{\"tdd_enabled\":true,\"frame_mode\":" + _cfg->frame_mode + ",";
std::string tddConfStr = "{\"tdd_enabled\":true,\"frame_mode\":\"" + _cfg->frame_mode + "\",";
tddConfStr += "\"symbol_size\":" + std::to_string(_cfg->sampsPerSymbol);
if (_cfg->clSdrCh == 2)
tddConfStr += "\"dual_pilot\":true,";
tddConfStr += ",\"frames\":[\"" + tddSched[i] + "\"]}";
tddConfStr += ",\"frames\":[\"" + tddSched + "\"]}";
std::cout << tddConfStr << std::endl;
#endif
dev->writeSetting("TDD_CONFIG", tddConfStr);
......@@ -180,7 +178,8 @@ static void initAGC(SoapySDR::Device* dev, Config* cfg)
agcConf["agc_gain_init"] = cfg->clAgcGainInit;
std::string agcConfStr = agcConf.dump();
#else
std::string agcConfStr = "{\"agc_enabled\":" + cfg->clAgcEn ? "true" : "false";
std::string agcEn = cfg->clAgcEn ? "true" : "false";
std::string agcConfStr = "{\"agc_enabled\":" + agcEn;
agcConfStr += ",\"agc_gain_init\":" + std::to_string(cfg->clAgcGainInit);
agcConfStr += "}";
#endif
......
......@@ -21,13 +21,15 @@ void Radio::dev_init(Config* _cfg, int ch, double rxgain, double txgain)
dev->setGain(SOAPY_SDR_RX, ch, "LNA", std::min(30.0, rxgain)); // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:108]
dev->setGain(SOAPY_SDR_RX, ch, "TIA", 0);
dev->setGain(SOAPY_SDR_RX, ch, "PGA", 0);
dev->setGain(SOAPY_SDR_RX, ch, "LNA2", 17); // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:108]
dev->setGain(SOAPY_SDR_RX, ch, "ATTN", _cfg->radioRfFreq < 3e9 ? -12 : 0);
dev->setGain(SOAPY_SDR_TX, ch, "PAD", std::min(42.0, txgain)); // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:105]
dev->setGain(SOAPY_SDR_TX, ch, "IAMP", 0);
dev->setGain(SOAPY_SDR_TX, ch, "PA2", 0);
dev->setGain(SOAPY_SDR_TX, ch, "ATTN", -6);
if (dev->getHardwareInfo()["frontend"].find("CBRS") != std::string::npos)
{
dev->setGain(SOAPY_SDR_RX, ch, "LNA2", 17); // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:108]
dev->setGain(SOAPY_SDR_RX, ch, "ATTN", _cfg->radioRfFreq < 3e9 ? -12 : 0);
dev->setGain(SOAPY_SDR_TX, ch, "PA2", 0);
dev->setGain(SOAPY_SDR_TX, ch, "ATTN", -6);
}
// DC Offset
dev->setDCOffsetMode(SOAPY_SDR_RX, ch, true);
}
......
......@@ -17,6 +17,7 @@ Config::Config(const std::string& jsonfile)
{
std::string conf;
Utils::loadTDDConfig(jsonfile, conf);
#ifdef JSON
const auto jConf = json::parse(conf);
std::stringstream ss;
json tddConf;
......@@ -171,7 +172,150 @@ Config::Config(const std::string& jsonfile)
symbolsPerFrame = clFrames.at(0).size();
}
}
#else
std::string line;
std::string bs_config = jsonfile;
std::ifstream configFile(bs_config);
// first initialize all variables
calTxGain[0] = 10;
calTxGain[1] = 10;
bsChannel = "A";
freq = 3.6e9;
rate = 5e6;
txgain[0] = txgain[1] = rxgain[0] = rxgain[1] = 20;
subframeSize = 0;
prefix = postfix = 0;
nco = rate * 0.75;
fftSize = cpSize = 0;
tx_scale = 0.5;
beacon_seq = "gold_ifft";
pilot_seq = "lts-half";
beacon_ant = 0;
beamsweep = false;
sampleCalEn = false;
imbalanceCalEn = false;
txAdvance = 250;
max_frame = 0;
frame_mode = "continuous_resync";
clAgcGainInit = 70;
clAgcEn = false;
clDataMod = "QPSK";
if (configFile.is_open()) {
while (getline(configFile, line)) {
std::vector<std::string> param = Utils::split(line, ':');
std::cout << param[0] << ":" << param[1] << std::endl;
if (param[0] == "hub_id") hub_file = param[1];
else if (param[0] == "bs_sdr_id") {
bs_sdr_file = Utils::split(param[1], ',');
}
else if (param[0] == "sdr_id") {
cl_sdr_ids = Utils::split(param[1], ',');
}
else if (param[0] == "channel") {
clChannel = param[1];
bsChannel = param[1];
}
else if (param[0] == "frequency") freq = std::stod(param[1]);
else if (param[0] == "nco_frequency") nco = std::stod(param[1]);
else if (param[0] == "txgainA") {
txgain[0] = std::stod(param[1]);
clTxgain_vec[0].push_back(txgain[0]);
}
else if (param[0] == "rxgainA") {
rxgain[0] = std::stod(param[1]);
clRxgain_vec[0].push_back(rxgain[0]);
}
else if (param[0] == "txgainB") {
txgain[1] = std::stod(param[1]);
clTxgain_vec[1].push_back(txgain[1]);
}
else if (param[0] == "rxgainB") {
rxgain[1] = std::stod(param[1]);
clRxgain_vec[1].push_back(rxgain[1]);
}
else if (param[0] == "rate") rate = std::stod(param[1]);
else if (param[0] == "subframe_size") subframeSize = std::stoul(param[1],nullptr, 0);
else if (param[0] == "prefix") prefix = std::stoul(param[1],nullptr, 0);
else if (param[0] == "postfix") postfix = std::stoul(param[1],nullptr, 0);
else if (param[0] == "fft_size") fftSize = std::stoul(param[1],nullptr, 0);
else if (param[0] == "cp_size") cpSize = std::stoul(param[1],nullptr, 0);
else if (param[0] == "tx_scale") tx_scale = std::stod(param[1]);
else if (param[0] == "beacon_seq") beacon_seq = param[1];
else if (param[0] == "pilot_seq") pilot_seq = param[1];
else if (param[0] == "beacon_antenna") beacon_ant = std::stoul(param[1],nullptr, 0);
else if (param[0] == "frame_schedule") {
frames = Utils::split(param[1], ',');
clFrames = Utils::split(param[1], ',');
}
else if (param[0] == "calTxGainA") calTxGain[0] = std::stod(param[1]);
else if (param[0] == "calTxGainB") calTxGain[1] = std::stod(param[1]);
else if (param[0] == "sample_calibrate") sampleCalEn = param[1] == "true" ? true : false;
else if (param[0] == "imbalance_calibrate") imbalanceCalEn = param[1] == "true" ? true : false;
else if (param[0] == "beamsweep") beamsweep = param[1] == "true" ? true : false;
else if (param[0] == "max_frame") max_frame = std::stoul(param[1],nullptr, 0);
else if (param[0] == "agc_en") clAgcEn = param[1] == "true" ? true : false;
else if (param[0] == "tx_advance") txAdvance = std::stoul(param[1],nullptr, 0);
else if (param[0] == "frame_mode") frame_mode = param[1];
else if (param[0] == "agc_gain_init") clAgcGainInit = std::stod(param[1]);
else if (param[0] == "modulation") clDataMod = param[1];
}
configFile.close();
}
else {
std::cerr << "Unable to open config file " << bs_config << std::endl;
exit(1);
}
bwFilter = rate + 2 * nco;
radioRfFreq = freq - nco;
sampsPerSymbol = subframeSize + prefix + postfix;
nCells = bs_sdr_file.size();
bs_sdr_ids.resize(nCells);
nBsSdrs.resize(nCells);
nBsAntennas.resize(nCells);
for (size_t i = 0; i < nCells; i++) {
Utils::loadDevices(bs_sdr_file[i], bs_sdr_ids[i]);
nBsSdrs[i] = bs_sdr_ids[i].size();
nBsAntennas[i] = bsChannel.length() * nBsSdrs[i];
}
bsPresent = bs_sdr_ids.size() > 0 and bs_sdr_ids[0].size() > 0;
Utils::loadDevices(hub_file, hub_ids);
symbolsPerFrame = frames.at(0).size();
pilotSymbols.resize(frames.size());
ULSymbols.resize(frames.size());
DLSymbols.resize(frames.size());
for (auto fr = frames.begin(); fr != frames.end(); ++fr) {
size_t f = fr - frames.begin();
for (int g = 0; g < symbolsPerFrame; g++) {
switch ((*fr)[g]) {
case 'P':
pilotSymbols[f].push_back(g);
break;
case 'U':
ULSymbols[f].push_back(g);
break;
case 'D':
DLSymbols[f].push_back(g);
break;
default:
break;
}
}
}
pilotSymsPerFrame = pilotSymbols[0].size();
ulSymsPerFrame = ULSymbols[0].size();
dlSymsPerFrame = DLSymbols[0].size();
nClSdrs = cl_sdr_ids.size();
clPresent = nClSdrs > 0;
clSdrCh = (clChannel == "AB") ? 2 : 1;
nClAntennas = nClSdrs * clSdrCh;
clPilotSymbols = Utils::loadSymbols(clFrames, 'P');
clULSymbols = Utils::loadSymbols(clFrames, 'U');
clDLSymbols = Utils::loadSymbols(clFrames, 'D');
std::cout << "bsPresent " << (bsPresent ? "true" : "false")
<< ", clPresent " << (clPresent ? "true" : "false")
<< std::endl;
#endif
ulDataSymPresent = (bsPresent && !ULSymbols[0].empty())
|| (clPresent && !clULSymbols[0].empty());
......@@ -333,7 +477,11 @@ Config::Config(const std::string& jsonfile)
int ant_num = getNumAntennas();
std::string ulPresentStr = (ulDataSymPresent ? "uplink-" : "");
std::string filename = "logs/trace-" + ulPresentStr + std::to_string(1900 + ltm->tm_year) + "-" + std::to_string(1 + ltm->tm_mon) + "-" + std::to_string(ltm->tm_mday) + "-" + std::to_string(ltm->tm_hour) + "-" + std::to_string(ltm->tm_min) + "-" + std::to_string(ltm->tm_sec) + "_" + std::to_string(cell_num) + "x" + std::to_string(ant_num) + "x" + std::to_string(pilotSymsPerFrame) + ".hdf5";
#ifdef JSON
trace_file = tddConf.value("trace_file", filename);
#else
trace_file = filename;
#endif
}
// Multi-threading settings
......
frequency:3.6e9
channel:A
agc_en:false
rxgainA:20
txgainA:42
rxgainB:20
txgainB:42
rate:5e6
fft_size:64
subframe_size:640
cp_size:16
prefix:82
postfix:68
frame_schedule:GGPGGGGGGGGGGGGG
frame_mode:continuous_resync
beacon_type:gold_ifft
modulation:QPSK
pilot_seq:lts-half
sdr_id:RF3C000025
......@@ -24,6 +24,7 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <exception>
#include <string.h>
class ReceiverException : public std::exception {
virtual const char* what() const throw()
......
......@@ -126,7 +126,7 @@ void Utils::loadDevices(const std::string& filename, std::vector<std::string>& d
else {
std::cerr << "Unable to open device file " << filename << std::endl;
exit(1);
//exit(1);
}
}
......
......@@ -173,7 +173,7 @@ def signal_handler(rate, numSyms, signal, frame):
def main():
parser = OptionParser()
parser.add_option("--hub", type="string", dest="hub", help="serial number of the hub device", default="")
parser.add_option("--serials", type="string", dest="serials", help="serial numbers of the devices", default="")
parser.add_option("--serials", type="string", dest="serials", help="serial numbers of the devices", default="RF3E000143,RF3E000160,RF3E000025,RF3E000034")
parser.add_option("--rate", type="float", dest="rate", help="Tx sample rate", default=5e6)
parser.add_option("--freq", type="float", dest="freq", help="Optional Tx freq (Hz)", default=3.6e9)
parser.add_option("--txgain", type="float", dest="txgain", help="Optional Tx gain (dB)", default=30.0)
......
......@@ -684,8 +684,8 @@ def init(hub, bnodes, cnodes, ref_ant, ampl, rate, freq, txgain, rxgain, cp, plo
def main():
parser = OptionParser()
parser.add_option("--args", type="string", dest="args", help="arguments", default="")
parser.add_option("--bnodes", type="string", dest="bnodes", help="file name containing serials on the base station", default="bs_serials.txt")
parser.add_option("--cnodes", type="string", dest="cnodes", help="file name containing serials to be used as clients", default="client_serials.txt")
parser.add_option("--bnodes", type="string", dest="bnodes", help="file name containing serials on the base station", default="../IrisUtils/data_in/bs_serials.txt")
parser.add_option("--cnodes", type="string", dest="cnodes", help="file name containing serials to be used as clients", default="../IrisUtils/data_in/cl_serials.txt")
parser.add_option("--hub", type="string", dest="hub", help="Hub node", default="")
parser.add_option("--ref-ant", type="int", dest="ref_ant", help="Calibration reference antenna", default=0)
parser.add_option("--ampl", type="float", dest="ampl", help="Amplitude coefficient for downCal/upCal", default=0.5)
......
......@@ -5,16 +5,16 @@
NOTE: IRIS BOARDS MUST BE CHAINED FOR THIS SCRIPT TO WORK.
ORDER MATTERS; FIRST NON-REF BOARD (SERIALS) IS THE ONE SENDING THE TRIGGER.
This script is useful watching the recprocity amplitude and phases of
narrow-band (sine) signals between all boards and a reference board .
It programs two Irises in TDD mode with the following framing
schedule.
This script is used for watching the recprocity amplitude and phases of
narrow-band (sine) signals between all boards and a reference board.
The reference board will be the first serial that appears in the bs_serials.txt
file.
It programs two Irises in TDD mode with the a framing schedule.
Example:
python3 NB_CAL_DEMO.py --serials=../IrisUtils/data_in/bs_serials.txt --ref-serial="xxxx"
python3 NB_CAL_DEMO.py --serials=../IrisUtils/data_in/bs_serials.txt
where "xxxx" is the serial number of an Iris node in the base station.
This reference node should not be included in the bs_serials.txt file
---------------------------------------------------------------------
Copyright © 2018-2019. Rice University.
......@@ -240,8 +240,7 @@ def calibrate_array(hub_serial, serials, ref_serial, rate, freq, txgain, rxgain,
def main():
parser = OptionParser()
parser.add_option("--hub-serial", type="string", dest="hub_serial", help="hub serial number of the base station", default="")
parser.add_option("--serials", type="string", dest="serials", help="serial number of all devices", default="bs_serials.txt")
parser.add_option("--ref-serial", type="string", dest="ref_serial", help="reference serial number of the device", default="")
parser.add_option("--serials", type="string", dest="serials", help="serial number of all devices, reference node will be first serial", default="../IrisUtils/data_in/bs_serials.txt")
parser.add_option("--rate", type="float", dest="rate", help="Tx sample rate", default=1e6)
parser.add_option("--txgain", type="float", dest="txgain", help="Optional Tx gain (dB) w/CBRS 3.6GHz [0:105], 2.5GHZ [0:105]", default=30.0)
parser.add_option("--rxgain", type="float", dest="rxgain", help="Optional Rx gain (dB) w/CBRS 3.6GHz [0:105], 2.5GHZ [0:108]", default=30.0)
......@@ -260,10 +259,20 @@ def main():
else:
continue
ref_serial = bserials[0]
if len(bserials) > 1:
bserials = bserials[1::]
else:
print("Need more than one board (in bs_serials.txt) to run calibration")
sys.exit(0)
print("SERIALS (EXCEPT REFERENCE NODE): {}".format(bserials))
print("REFERENCE NODE SERIAL: {}".format(ref_serial))
calibrate_array(
hub_serial=options.hub_serial,
serials=bserials,
ref_serial=options.ref_serial,
ref_serial=ref_serial,
rate=options.rate,
freq=options.freq,
txgain=options.txgain,
......
......@@ -256,7 +256,7 @@ def animate(i, num_samps_rd, rxStream, sdr, sdrTx, ofdm_params, tx_struct, ota,
0, # timeNs (dont care unless using SOAPY_SDR_HAS_TIME)
buff0.size) # numElems - this is the burst size
if agc_en and "CBRS" in infoTx["frontend"]:
if agc_en and "CBRS" in infoRx["frontend"]:
sdr.writeRegister("IRIS30", FPGA_IRIS030_WR_AGC_RESET_FLAG, 1)
sdr.writeRegister("IRIS30", FPGA_IRIS030_WR_AGC_RESET_FLAG, 0)
sdr.writeRegister("IRIS30", FPGA_IRIS030_WR_PKT_DET_NEW_FRAME, 1)
......@@ -277,8 +277,7 @@ def animate(i, num_samps_rd, rxStream, sdr, sdrTx, ofdm_params, tx_struct, ota,
lna1_rd = sdr.getGain(SOAPY_SDR_RX, 0, 'LNA1') # ChanA (0)
lna2_rd = sdr.getGain(SOAPY_SDR_RX, 0, 'LNA2') # ChanA (0)
attn_rd1 = sdr.getGain(SOAPY_SDR_RX, 0, 'ATTN') # ChanA (0)
print("RSSI: {} \t LNA: {} \t TIA: {} \t PGA: {} \t LNA1: {} \t LNA2: {} \t ATTN1: {}".format(rssi_fpga,
lna_rd,
print("LNA: {} \t TIA: {} \t PGA: {} \t LNA1: {} \t LNA2: {} \t ATTN1: {}".format(lna_rd,
tia_rd,
pga_rd,
lna1_rd,
......@@ -288,7 +287,7 @@ def animate(i, num_samps_rd, rxStream, sdr, sdrTx, ofdm_params, tx_struct, ota,
lna_rd = sdr.getGain(SOAPY_SDR_RX, 0, 'LNA') # ChanA (0)
tia_rd = sdr.getGain(SOAPY_SDR_RX, 0, 'TIA') # ChanA (0)
pga_rd = sdr.getGain(SOAPY_SDR_RX, 0, 'PGA') # ChanA (0)
print("RSSI: {} \t LNA: {} \t TIA: {} \t PGA: {}".format(rssi_fpga, lna_rd, tia_rd, pga_rd))
print("LNA: {} \t TIA: {} \t PGA: {}".format(lna_rd, tia_rd, pga_rd))
else:
# Simulation Mode
......@@ -434,13 +433,13 @@ def txrx_app(args, rate, ampl, ant, txgain, rxgain, freq, bbfreq, serialTx, seri
sdrRx = SoapySDR.Device(dict(serial=serialRx))
infoRx = sdrRx.getHardwareInfo()
# AGC - target might need to change for different frequencies (tested with 30 at 3.6GHz)
rssi_target_idx = 30
agc_init(sdrRx, rssi_target_idx, agc_en)
# Reset
sdrRx.writeSetting("RESET_DATA_LOGIC", "")
# AGC - target might need to change for different frequencies (tested with 30 at 3.6GHz)
rssi_target_idx = 25
agc_init(sdrRx, rssi_target_idx, agc_en)
if ant == 'A':
txChannel = [0]
elif ant == 'B':
......@@ -471,8 +470,20 @@ def txrx_app(args, rate, ampl, ant, txgain, rxgain, freq, bbfreq, serialTx, seri
if "CBRS" in infoTx["frontend"]:
# Set gains to high val (initially)
sdr.setGain(SOAPY_SDR_TX, c, txgain) # txgain: at 2.5GHz [16:1:93], at 3.6GHz [15:1:102]
sdr.setGain(SOAPY_SDR_RX, c, rxgain) # rxgain: at 2.5GHz [3:1:105], at 3.6GHz [3:1:102]
#sdr.setGain(SOAPY_SDR_TX, c, txgain) # txgain: at 2.5GHz [16:1:93], at 3.6GHz [15:1:102]
#sdr.setGain(SOAPY_SDR_RX, c, rxgain) # rxgain: at 2.5GHz [3:1:105], at 3.6GHz [3:1:102]
sdr.setGain(SOAPY_SDR_RX, c, 'LNA', 20)
sdr.setGain(SOAPY_SDR_RX, c, 'PGA', 10)
sdr.setGain(SOAPY_SDR_RX, c, 'TIA', 3)
sdr.setGain(SOAPY_SDR_RX, c, 'ATTN', -18)
sdr.setGain(SOAPY_SDR_TX, c, 'PAD', 30)
sdr.setGain(SOAPY_SDR_TX, c, 'IAMP', 0)
sdr.setGain(SOAPY_SDR_TX, c, 'PA1', 17)
sdr.setGain(SOAPY_SDR_TX, c, 'PA2', 14)
sdr.setGain(SOAPY_SDR_TX, c, 'PA3', 31.5)
sdr.setGain(SOAPY_SDR_TX, c, 'ATTN', -6)
else:
# No CBRS board gains, only changing LMS7 gains
sdr.setGain(SOAPY_SDR_TX, c, "PAD", txgain) # [0:1:42]
......@@ -484,8 +495,9 @@ def txrx_app(args, rate, ampl, ant, txgain, rxgain, freq, bbfreq, serialTx, seri
else:
# Simulation Mode
sdrRx = []
infoTx = []
if agc_en and "CBRS" in info["frontend"]:
if agc_en and "CBRS" in infoRx["frontend"]:
sdrRx.writeRegister("IRIS30", FPGA_IRIS030_WR_PKT_DET_ENABLE, 1)
sdrRx.writeRegister("IRIS30", FPGA_IRIS030_WR_AGC_ENABLE_FLAG, 1)
sdrRx.writeRegister("IRIS30", FPGA_IRIS030_WR_PKT_DET_NEW_FRAME, 1)
......@@ -565,7 +577,7 @@ def main():
parser.add_option("--rate", type="float", dest="rate", help="Tx and Rx sample rate", default=5e6)
parser.add_option("--ampl", type="float", dest="ampl", help="Tx digital amplitude scale", default=1)
parser.add_option("--ant", type="string", dest="ant", help="Optional Tx antenna", default="A")
parser.add_option("--txgain", type="float", dest="txgain", help="Tx gain (dB)", default=60.0) # See documentation at top of file for info on gain range
parser.add_option("--txgain", type="float", dest="txgain", help="Tx gain (dB)", default=55.0) # See documentation at top of file for info on gain range
parser.add_option("--rxgain", type="float", dest="rxgain", help="Rx gain (dB)", default=55.0) # See documentation at top of file for info on gain range
parser.add_option("--freq", type="float", dest="freq", help="Tx RF freq (Hz)", default=3.597e9)
parser.add_option("--bbfreq", type="float", dest="bbfreq", help="Lime chip Baseband frequency (Hz)", default=0)
......@@ -575,11 +587,11 @@ def main():
parser.add_option("--nSC", type="int", dest="nSC", help="# of subcarriers. Only supports 64 sc at the moment", default=64)
parser.add_option("--fftOfset", type="int", dest="fftOffset", help="FFT Offset: # of CP samples for FFT", default=6)
parser.add_option("--modOrder", type="int", dest="modOrder", help="Modulation Order 2=BPSK/4=QPSK/16=16QAM/64=64QAM", default=16)
parser.add_option("--serialTx", type="string", dest="serialTx", help="Serial # of TX device", default="")
parser.add_option("--serialRx", type="string", dest="serialRx", help="Serial # of RX device", default="")
parser.add_option("--serialTx", type="string", dest="serialTx", help="Serial # of TX device", default="RF3E000157")
parser.add_option("--serialRx", type="string", dest="serialRx", help="Serial # of RX device", default="RF3E000060")
parser.add_option("--nSampsRead", type="int", dest="nSampsRead", help="# Samples to read", default=FIG_LEN)
parser.add_option("--mode", type="string", dest="mode", help="Simulation vs Over-the-Air (i.e., SIM/OTA)", default="OTA")
parser.add_option("--agc_en", action="store_true", dest="agc_en", help="Flag to enable AGC", default=False) # Only supported if using CBRS board
parser.add_option("--agc_en", action="store_true", dest="agc_en", help="Flag to enable AGC", default=False) # Currently under testing
(options, args) = parser.parse_args()
ofdm_params = [options.nOFDMsym, options.ltsCpLen, options.dataCpLen, options.nSC, options.modOrder, options.fftOffset]
......
......@@ -437,7 +437,7 @@ def main():
parser.add_option("--elevation", type="float", dest="elevation", help="Elevation", default=0.0)
parser.add_option("--freq", type="float", dest="freq", help="Optional Rx freq (Hz)", default=3.6e9)
parser.add_option("--numSamps", type="int", dest="numSamps", help="Num samples to receive", default=16384)
parser.add_option("--serial", type="string", dest="serial", help="Serial number of the device", default="")
parser.add_option("--serial", type="string", dest="serial", help="Serial number of the device", default="RF3E000060")
parser.add_option("--rxMode", type="string", dest="rxMode", help="RX Mode, Options:BASIC/REC/REPLAY", default="BASIC")
parser.add_option("--AGCen", type="int", dest="AGCen", help="Enable AGC Flag. Options:0/1", default=0)
parser.add_option("--wait-trigger", action="store_true", dest="wait_trigger", help="wait for a trigger to start a frame",default=False)
......
......@@ -215,7 +215,7 @@ def main():
parser.add_option("--bbfreq", type="float", dest="bbfreq", help="Lime chip Baseband frequency (Hz)", default=0)
parser.add_option("--waveFreq", type="float", dest="waveFreq", help="Baseband waveform freq (Hz)", default=None)
parser.add_option("--numSamps", type="int", dest="numSamps", help="Num samples to receive", default=1024)
parser.add_option("--serial", type="string", dest="serial", help="serial number of the device", default="")
parser.add_option("--serial", type="string", dest="serial", help="serial number of the device", default="RF3E000157")
parser.add_option("--sigType", type="string", dest="sigType", help="Signal Type: LTE/LTS/STS/SINE", default="SINE")
parser.add_option("--lo-tone", action="store_true", dest="lo_tone", help="generate tone using the LO ", default=False)
(options, args) = parser.parse_args()
......
......@@ -224,8 +224,8 @@ def siso_tdd_burst(serial1, serial2, rate, freq, txgain, rxgain, numSamps, prefi
#########################################
def main():
parser = OptionParser()
parser.add_option("--serial1", type="string", dest="serial1", help="serial number of the device 1", default="")
parser.add_option("--serial2", type="string", dest="serial2", help="serial number of the device 2", default="")
parser.add_option("--serial1", type="string", dest="serial1", help="serial number of the device 1", default="RF3E000143")
parser.add_option("--serial2", type="string", dest="serial2", help="serial number of the device 2", default="RF3E000160")
parser.add_option("--rate", type="float", dest="rate", help="Tx sample rate", default=5e6)
parser.add_option("--txgain", type="float", dest="txgain", help="Tx gain (dB)", default=25.0) # See documentation at top of file for info on gain range
parser.add_option("--rxgain", type="float", dest="rxgain", help="Rx gain (dB)", default=20.0) # See documentation at top of file for info on gain range
......
......@@ -50,7 +50,11 @@
python3 SOUNDER_TXRX.py --bsnode="RF3C000042" --clnode="RF3C000025"
where bsnode corresponds to a base station node and clnode corresponds
to a client node
to a client node.
OUTPUT:
The script will generate binary files that can be analyzed using the
plt_simp.py script in folder PYTHON/IrisUtils/
IMPORTANT NOTE:
The client firmware has different features than the base station node
......@@ -429,7 +433,7 @@ def main():
parser.add_option("--use-trig", action="store_true", dest="use_trig", help="uses chain triggers for synchronization", default=False)
parser.add_option("--wait-trigger", action="store_true", dest="wait_trigger", help="wait for a trigger to start a frame", default=False)
parser.add_option("--tx-power-loop", action="store_true", dest="tx_power_loop", help="loop over a set of tx gains in consecutive frames", default=False)
parser.add_option("--record", action="store_true", dest="record", help="record received pilots and data", default=False)
parser.add_option("--record", action="store_true", dest="record", help="record received pilots and data", default=True)
parser.add_option("--agc-enable", action="store_true", dest="agc_en", help="Enable AGC flag", default=False)
(options, args) = parser.parse_args()
......
RF3C000045
RF3C000025
RF3E000060
RF3E000157
......@@ -27,7 +27,7 @@ import multiprocessing as mp
import extract_pilots_data as epd
#@staticmethod
def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0, frame_to_plot=0, ref_ant=0):
def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0, frame_to_plot=0, ref_ant=0, ref_user = 0):
"""
Finds the end of the pilots' frames, finds all the lts indices relative to that.
Divides the data with lts sequences, calculates csi per lts, csi per frame, csi total.
......@@ -49,8 +49,8 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
n_iq = pilots_dump.shape[4] # no. of IQ samples per frame
if debug:
print("input : z_padding = {}, fft_size={}, cp={}, frm_st_idx = {}, frame_to_plot = {}, ref_ant={}".format(
z_padding, fft_size, cp, frm_st_idx, frame_to_plot, ref_ant))
print("input : z_padding = {}, fft_size={}, cp={}, frm_st_idx = {}, frame_to_plot = {}, ref_ant={}, ref_user = {}".format(
z_padding, fft_size, cp, frm_st_idx, frame_to_plot, ref_ant, ref_user))
print("n_frame = {}, n_cell = {}, n_ue = {}, n_ant = {}, n_iq = {}".format(
n_frame, n_cell, n_ue, n_ant, n_iq))
......@@ -78,9 +78,9 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
# take a time-domain lts sequence, concatenate more copies, flip, conjugate
lts_t, lts_f = generate_training_seq(preamble_type='lts', seq_length=[
], cp=32, upsample=1, reps=[]) # TD LTS sequences (x2.5), FD LTS sequences
], cp = cp, upsample=1, reps=[]) # TD LTS sequences (x2.5), FD LTS sequences
# last 80 samps (assume 16 cp)
lts_tmp = lts_t[-80:]
lts_tmp = lts_t[- cp - fft_size:]
n_lts = len(lts_tmp)
# no. of LTS sequences in a pilot SF
k_lts = n_csamp // n_lts
......@@ -173,6 +173,9 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
indexing_end = time.time()
pool.close()
# WZC: added pilots_rx_t_btc (pilots_rx_t before truncation) for output
pilots_rx_t_btc = np.copy(pilots_rx_t)
# *************** This fancy indexing is slower than the for loop! **************
# aaa= np.reshape(cmpx_pilots, (n_frame*n_cell* n_ue * n_ant, n_cmpx))
# idxx = np.expand_dims(sf_start.flatten(), axis=1)
......@@ -199,8 +202,10 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
if debug:
print("Indexing time: %f \n" % (indexing_end - indexing_start))
print("Shape of: pilots_rx_t = {}\n".format(pilots_rx_t.shape))
print("Shape of: rho_max = {}, rho_min = {}, ipos = {}, sf_start = {}".format(
rho_max.shape, rho_min.shape, ipos.shape, sf_start.shape))
# WZC: rho_max might not be defined in current version
# print("Shape of: rho_max = {}, rho_min = {}, ipos = {}, sf_start = {}".format(
# rho_max.shape, rho_min.shape, ipos.shape, sf_start.shape))
# take fft and get the raw CSI matrix (no averaging)
# align SCs based on how they were Tx-ec
......@@ -218,8 +223,9 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
csi = np.fft.fftshift(csi, 5)
if debug:
print(">>>> number of NaN indices = {} NaN indices =\n{}".format(
nan_indices.shape, nan_indices))
# # WZC: rho_max might not be defined in current version
# print(">>>> number of NaN indices = {} NaN indices =\n{}".format(
# nan_indices.shape, nan_indices))
print("Shape of: csi = {}\n".format(csi.shape))
# plot something to see if it worked!
......@@ -228,12 +234,12 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
ax1 = fig.add_subplot(3, 1, 1)
ax1.grid(True)
ax1.set_title(
'channel_analysis:csi_from_pilots(): Re of Rx pilot - ref frame {} and ref ant. {} (UE 0)'.format(frame_to_plot, ref_ant))
'channel_analysis:csi_from_pilots(): Re of Rx pilot - ref frame {} ref ant {} ref user {}'.format(frame_to_plot, ref_ant, ref_user))
if debug:
print("cmpx_pilots.shape = {}".format(cmpx_pilots.shape))
ax1.plot(
np.real(cmpx_pilots[frame_to_plot - frm_st_idx, 0, 0, ref_ant, :]))
np.real(cmpx_pilots[frame_to_plot - frm_st_idx, 0, ref_user, ref_ant, :]))
if debug:
loc_sec = lts_t_rep_tst
......@@ -252,14 +258,15 @@ def csi_from_pilots(pilots_dump, z_padding=150, fft_size=64, cp=16, frm_st_idx=0
ax3 = fig.add_subplot(3, 1, 3)
ax3.grid(True)
ax3.set_title(
'channel_analysis:csi_from_pilots(): MF (uncleared peaks) - ref frame {} and ref ant. {} (UE 0)'.format(frame_to_plot, ref_ant))
ax3.stem(m_filt[frame_to_plot - frm_st_idx, 0, 0, ref_ant, :])
'channel_analysis:csi_from_pilots(): MF (uncleared peaks) - ref frame {} ref ant {} ref user {}'.format(frame_to_plot, ref_ant, ref_user))
ax3.stem(m_filt[frame_to_plot - frm_st_idx, 0, ref_user, ref_ant, :])
ax3.set_xlabel('Samples')
# plt.show()
print("********************* ******************** *********************\n")
return csi, m_filt, sf_start, cmpx_pilots, k_lts, n_lts
# add frame_start for plot indexing!
return csi, m_filt, sf_start, cmpx_pilots, k_lts, n_lts, sf_start, pilots_rx_t_btc
# add frame_start for plot indexing!
# WZC: add pilots_rx_t_btc
class hdf5_lib:
......@@ -554,6 +561,10 @@ class hdf5_lib:
for k in range(n_ue):
for l in range(n_ant):
mfa = mf_amax[i,j,k,l]
# WZC: indexs where side peaks might be
side_idx = np.delete(np.arange(n_corr), (mfa - base_arr))
# NB: addition: try to detect early packets: TEST it!
if dtct_eal_tx:
sim_thrsh = 0.95 # similarity threshold bewtween two consequitive peaks
......@@ -574,16 +585,24 @@ class hdf5_lib:
cp_idx3 = (mfa + -1 + cp) - base_arr[m]
idx_30 = (mfa + 30) - base_arr[m]
idx_29 = (mfa + 29) - base_arr[m]
if adj_idx1 >= 0 and adj_idx2 >=0 and adj_idx2 < n_corr:
match_filt[i,j,k,l, adj_idx1 ] = 0
match_filt[i,j,k,l, adj_idx2 ] = 0
if (cp_idx1 >=0) and (cp_idx1 < n_corr) and (cp_idx2 < n_corr) and (cp_idx3 < n_corr):
match_filt[i,j,k,l, cp_idx1 ] = 0
match_filt[i,j,k,l, cp_idx2 ] = 0
match_filt[i,j,k,l, cp_idx3 ] = 0
if (idx_30 >=0) and (idx_30 < n_corr) and (idx_29 >=0) and (idx_29 < n_corr):
match_filt[i,j,k,l,idx_30] = 0
match_filt[i,j,k,l,idx_29] = 0
idx_tot = [adj_idx1, adj_idx2, cp_idx1, cp_idx2, cp_idx3, idx_30, idx_29]
# WZC: removing possible side peaks
for idx in idx_tot:
if idx in side_idx:
match_filt[i,j,k,l, idx] = 0
# if adj_idx1 >= 0 and adj_idx2 >=0 and adj_idx2 < n_corr:
# match_filt[i,j,k,l, adj_idx1 ] = 0
# match_filt[i,j,k,l, adj_idx2 ] = 0
# if (cp_idx1 >=0) and (cp_idx1 < n_corr) and (cp_idx2 < n_corr) and (cp_idx3 < n_corr):
# match_filt[i,j,k,l, cp_idx1 ] = 0
# match_filt[i,j,k,l, cp_idx2 ] = 0
# match_filt[i,j,k,l, cp_idx3 ] = 0
# if (idx_30 >=0) and (idx_30 < n_corr) and (idx_29 >=0) and (idx_29 < n_corr):
# match_filt[i,j,k,l,idx_30] = 0
# match_filt[i,j,k,l,idx_29] = 0
# get the k_lts largest peaks and their position
k_max = np.sort(match_filt, axis = -1)[:,:,:,:, -k_lts:]
......@@ -605,12 +624,14 @@ class hdf5_lib:
if debug:
print("f_st = {}".format(f_st[frame_to_plot - st_frame,0,0,:]))
print("frame_sanity(): Shape of k_max.shape = {}, k_amax.shape = {}, lst_pk_idx.shape = {}".format(
k_max.shape, k_amax.shape, lst_pk_idx.shape) )
k_max.shape, k_amax.shape, lst_pk_idx.shape))
print("frame_sanity(): k_amax = {}".format(k_amax))
print("frame_sanity(): frame_map.shape = {}\n".format(frame_map.shape))
print(k_amax[frame_to_plot - st_frame,0,0,plt_ant,:])
print(idx_diff[frame_to_plot - st_frame,0,0,plt_ant,:])
peak_map = np.copy(frame_map)
frame_map[frame_map == 1] = -1
frame_map[frame_map >= (k_lts -1)] = 1
frame_map[frame_map > 1] = 0
......@@ -628,5 +649,5 @@ class hdf5_lib:
n_rf, n_gf, n_bf, n_pr,))
print("===================== ============================= ============")
return match_filt, frame_map, f_st
return match_filt, frame_map, f_st, peak_map
# WZC: added peak_map for peak_number analysis
......@@ -72,6 +72,7 @@ def verify_hdf5(hdf5, default_frame=100, ant_i =0, user_i=0, n_frm_st=0, thresh=
postfix_len = int(metadata['POSTFIX_LEN'])
z_padding = prefix_len + postfix_len
offset = int(prefix_len)
fft_size = int(metadata['FFT_SIZE'])
print(" symbol_length = {}, cp = {}, prefix_len = {}, postfix_len = {}, z_padding = {}".format(symbol_length, cp, prefix_len, postfix_len, z_padding))
......@@ -81,12 +82,12 @@ def verify_hdf5(hdf5, default_frame=100, ant_i =0, user_i=0, n_frm_st=0, thresh=
if deep_inspect:
csi_from_pilots_start = time.time()
csi_mat, match_filt, sub_fr_strt, cmpx_pilots, k_lts, n_lts = csi_from_pilots(
pilot_samples, z_padding, frm_st_idx=n_frm_st, frame_to_plot=frm_plt, ref_ant=ant_i)
csi_mat, match_filt, sub_fr_strt, cmpx_pilots, k_lts, n_lts, sf_start, pilots_rx_t_btc = csi_from_pilots(
pilot_samples, z_padding, fft_size = fft_size, cp = cp, frm_st_idx=n_frm_st, frame_to_plot=frm_plt, ref_ant=ant_i, ref_user = user_i)
csi_from_pilots_end = time.time()
frame_sanity_start = time.time()
match_filt_clr, frame_map, f_st = hdf5_lib.frame_sanity(match_filt, k_lts, n_lts, n_frm_st, frm_plt, plt_ant=ant_i)
match_filt_clr, frame_map, f_st, peak_map = hdf5_lib.frame_sanity(match_filt, k_lts, n_lts, n_frm_st, frm_plt, plt_ant=ant_i, cp = cp)
frame_sanity_end = time.time()
print(">>>> csi_from_pilots time: %f \n" % ( csi_from_pilots_end - csi_from_pilots_start) )
......@@ -111,8 +112,8 @@ def verify_hdf5(hdf5, default_frame=100, ant_i =0, user_i=0, n_frm_st=0, thresh=
# Samps: #Frames, #Cell, #Users, #Antennas, #Samples
# CSI: #Frames, #Cell, #Users, #Pilot Rep, #Antennas, #Subcarrier
# For correlation use a fft size of 64
print("*verify_hdf5(): Calling samps2csi with fft_size = 64, offset = {}, bound = cp = 0 *".format(offset))
csi, samps = hdf5_lib.samps2csi(samples, num_cl_tmp, symbol_length, fft_size=64, offset=offset, bound=0, cp=0, sub=sub_sample)
print("*verify_hdf5(): Calling samps2csi with fft_size = {}, offset = {}, bound = cp = 0 *".format(fft_size, offset))
csi, samps = hdf5_lib.samps2csi(samples, num_cl_tmp, symbol_length, fft_size = fft_size, offset = offset, bound = 0, cp = cp, sub = sub_sample)
# Correlation (Debug plot useful for checking sync)
amps = np.mean(np.abs(samps[:, 0, user_i, 0, ant_i, :]), axis=1)
......
......@@ -8,17 +8,17 @@ then
fi
sudo apt -y install libhdf5-dev $HDF5_LIB $ITPP_LIB
BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
LIBDIR="$BASEDIR"/CC/Sounder/lib
mkdir -p $LIBDIR
mkdir -p deps
cd deps/
git clone https://github.com/nlohmann/json.git
cd json/
mkdir -p build/
cd build/
cmake ..
make -j
sudo make install
cd ../..
#BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
#LIBDIR="$BASEDIR"/CC/Sounder/lib
#mkdir -p $LIBDIR
#
#mkdir -p deps
#cd deps/
#git clone https://github.com/nlohmann/json.git
#cd json/
#mkdir -p build/
#cd build/
#cmake ..
#make -j
#sudo make install
#cd ../..