...
 
Commits (241)
[submodule "CC/Sounder/mufft"]
path = CC/Sounder/mufft
url = https://github.com/themaister/mufft
......@@ -35,6 +35,6 @@ message(STATUS "HDF5_INCLUDE_DIRS: ${HDF5_INCLUDE_DIRS}")
message(STATUS "HDF5_LIBRARIES: ${HDF5_LIBRARIES}")
include_directories(${SoapySDR_INCLUDE_DIRS} ${HDF5_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS})
add_executable(sounder main.cc config.cc receiver.cc recorder.cc sdr-lib.cc comms-lib.cc utils.cc signalHandler.cpp)
target_link_libraries(sounder -lpthread -lhdf5_cpp --enable-threadsafe ${SoapySDR_LIBRARIES} ${HDF5_LIBRARIES} ${CMAKE_SOURCE_DIR}/lib/libmuFFT.a ${CMAKE_SOURCE_DIR}/lib/libmuFFT-sse.a ${CMAKE_SOURCE_DIR}/lib/libmuFFT-sse3.a ${CMAKE_SOURCE_DIR}/lib/libmuFFT-avx.a ${PYTHON_LIBRARIES})
add_executable(sounder main.cc ClientRadioSet.cc config.cc Radio.cc receiver.cc recorder.cc sdr-lib.cc sdr-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})
#include "include/ClientRadioSet.h"
#include "include/Radio.h"
#include "include/comms-lib.h"
#include "include/macros.h"
#include "include/utils.h"
#include <SoapySDR/Errors.hpp>
#include <SoapySDR/Formats.hpp>
#include <SoapySDR/Time.hpp>
ClientRadioSet::ClientRadioSet(Config* cfg)
: _cfg(cfg)
{
//load channels
auto channels = Utils::strToChannels(_cfg->clChannel);
radios.reserve(_cfg->nClSdrs);
for (size_t i = 0; i < _cfg->nClSdrs; i++) {
SoapySDR::Kwargs args;
args["timeout"] = "1000000";
args["serial"] = _cfg->cl_sdr_ids.at(i);
try {
radios.push_back(new Radio(args, SOAPY_SDR_CF32, channels, _cfg->rate));
} catch (std::runtime_error) {
std::cerr << "Ignoring serial " << _cfg->cl_sdr_ids.at(i) << std::endl;
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]
double txgain = _cfg->clTxgain_vec[ch][i]; // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:105]
radios.back()->dev_init(_cfg, ch, rxgain, txgain);
}
initAGC(dev);
}
radios.shrink_to_fit();
//beaconSize + 82 (BS FE delay) + 68 (path delay) + 17 (correlator delay) + 82 (Client FE Delay)
int clTrigOffset = _cfg->beaconSize + 249;
int sf_start = clTrigOffset / _cfg->sampsPerSymbol;
int sp_start = clTrigOffset % _cfg->sampsPerSymbol;
for (size_t i = 0; i < radios.size(); i++) {
auto dev = radios[i]->dev;
std::string corrConfString = "{\"corr_enabled\":true,\"corr_threshold\":" + std::to_string(1) + "}";
dev->writeSetting("CORR_CONFIG", corrConfString);
dev->writeRegisters("CORR_COE", 0, _cfg->coeffs);
std::string tddSched = _cfg->clFrames[i];
for (size_t s = 0; s < _cfg->clFrames[i].size(); s++) {
char c = _cfg->clFrames[i].at(s);
if (c == 'B')
tddSched.replace(s, 1, "G");
else if (c == 'U')
tddSched.replace(s, 1, "T");
else if (c == 'D')
tddSched.replace(s, 1, "R");
}
std::cout << "Client " << i << " schedule: " << tddSched << std::endl;
#ifdef JSON
json tddConf;
tddConf["tdd_enabled"] = true;
tddConf["frame_mode"] = _cfg->frame_mode;
int max_frame_ = (int)(2.0 / ((_cfg->sampsPerSymbol * _cfg->symbolsPerFrame) / _cfg->rate));
tddConf["max_frame"] = max_frame_;
//std::cout << "max_frames for client " << i << " is " << max_frame_ << std::endl;
if (_cfg->clSdrCh == 2)
tddConf["dual_pilot"] = true;
tddConf["frames"] = json::array();
tddConf["frames"].push_back(tddSched);
tddConf["symbol_size"] = _cfg->sampsPerSymbol;
std::string tddConfStr = tddConf.dump();
#else
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] + "\"]}";
std::cout << tddConfStr << std::endl;
#endif
dev->writeSetting("TDD_CONFIG", tddConfStr);
dev->setHardwareTime(SoapySDR::ticksToTimeNs((sf_start << 16) | sp_start, _cfg->rate), "TRIGGER");
dev->writeSetting("TX_SW_DELAY", "30"); // experimentally good value for dev front-end
dev->writeSetting("TDD_MODE", "true");
// write pilot to FPGA buffers
for (char const& c : _cfg->bsChannel) {
std::string tx_ram = "TX_RAM_";
dev->writeRegisters(tx_ram + c, 0, _cfg->pilot);
}
radios[i]->activateRecv();
radios[i]->activateXmit();
dev->writeSetting("CORR_START", (_cfg->bsChannel == "B") ? "B" : "A");
}
std::cout << __func__ << " done!" << std::endl;
}
ClientRadioSet::~ClientRadioSet(void)
{
for (size_t i = 0; i < radios.size(); i++)
delete radios[i];
}
void ClientRadioSet::radioStop(void)
{
std::string corrConfStr = "{\"corr_enabled\":false}";
std::string tddConfStr = "{\"tdd_enabled\":false}";
for (size_t i = 0; i < _cfg->nClSdrs; i++) {
auto dev = radios[i]->dev;
dev->writeSetting("CORR_CONFIG", corrConfStr);
const auto timeStamp = SoapySDR::timeNsToTicks(dev->getHardwareTime(""), _cfg->rate);
std::cout << "device " << i << ": Frame=" << (timeStamp >> 32)
<< ", Symbol=" << ((timeStamp && 0xFFFFFFFF) >> 16) << std::endl;
dev->writeSetting("TDD_CONFIG", tddConfStr);
dev->writeSetting("TDD_MODE", "false");
radios[i]->reset_DATA_clk_domain();
}
}
int ClientRadioSet::triggers(int i)
{
return (radios[i]->getTriggers());
}
int ClientRadioSet::radioRx(size_t radio_id, void* const* buffs, int numSamps, long long& frameTime)
{
if (radio_id < radios.size()) {
long long frameTimeNs = 0;
int ret = radios[radio_id]->recv(buffs, numSamps, frameTimeNs);
frameTime = frameTimeNs; //SoapySDR::timeNsToTicks(frameTimeNs, _rate);
return ret;
}
std::cout << "invalid radio id " << radio_id << std::endl;
return 0;
}
int ClientRadioSet::radioTx(size_t radio_id, const void* const* buffs, int numSamps, int flags, long long& frameTime)
{
return radios[radio_id]->xmit(buffs, numSamps, flags, frameTime);
}
void ClientRadioSet::initAGC(SoapySDR::Device* dev)
{
/*
* Initialize AGC parameters
*/
#ifdef JSON
json agcConf;
agcConf["agc_enabled"] = _cfg->clAgcEn;
agcConf["agc_gain_init"] = _cfg->clAgcGainInit;
std::string agcConfStr = agcConf.dump();
#else
std::string agcConfStr = "{\"agc_enabled\":" + _cfg->clAgcEn ? "true" : "false";
agcConfStr += ",\"agc_gain_init\":" + std::to_string(_cfg->clAgcGainInit);
agcConfStr += "}";
#endif
dev->writeSetting("AGC_CONFIG", agcConfStr);
}
......@@ -5,6 +5,11 @@ This folder includes a library of code for running channel sounding
experiments with an RENEW base station hardware. To run, follow steps below:
```shell
cd mufft
git submodule update --init
cmake ./
make -j
cd ../
cmake ./
make -j
./sounder files/tddconfig.json
......
#include "include/Radio.h"
#include "include/macros.h"
#include <SoapySDR/Errors.hpp>
#include <iostream>
void Radio::dev_init(Config* _cfg, int ch, double rxgain, double txgain)
{
// these params are sufficient to set before DC offset and IQ imbalance calibration
dev->setAntenna(SOAPY_SDR_RX, ch, "TRX");
dev->setBandwidth(SOAPY_SDR_RX, ch, _cfg->bwFilter);
dev->setBandwidth(SOAPY_SDR_TX, ch, _cfg->bwFilter);
dev->setFrequency(SOAPY_SDR_RX, ch, "RF", _cfg->radioRfFreq);
dev->setFrequency(SOAPY_SDR_RX, ch, "BB", _cfg->nco);
dev->setFrequency(SOAPY_SDR_TX, ch, "RF", _cfg->radioRfFreq);
dev->setFrequency(SOAPY_SDR_TX, ch, "BB", _cfg->nco);
// Unified gains for both lime and frontend
dev->setGain(SOAPY_SDR_RX, ch, rxgain); // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:108]
dev->setGain(SOAPY_SDR_TX, ch, txgain); // w/CBRS 3.6GHz [0:105], 2.5GHZ [0:105]
// DC Offset
dev->setDCOffsetMode(SOAPY_SDR_RX, ch, true);
}
void Radio::drain_buffers(std::vector<void*> buffs, int symSamp)
{
/*
* "Drain" rx buffers during initialization
* Input:
* buffs - Vector to which we will write received IQ samples
* symSamp - Number of samples
*
* Output:
* None
*/
long long frameTime = 0;
int flags = 0, r = 0, i = 0;
while (r != -1) {
r = dev->readStream(rxs, buffs.data(), symSamp, flags, frameTime, 0);
i++;
}
//std::cout << "Number of reads needed to drain: " << i << std::endl;
}
Radio::Radio(const SoapySDR::Kwargs& args, const char soapyFmt[],
const std::vector<size_t>& channels, double rate)
{
dev = SoapySDR::Device::make(args);
for (auto ch : channels) {
dev->setSampleRate(SOAPY_SDR_RX, ch, rate);
dev->setSampleRate(SOAPY_SDR_TX, ch, rate);
}
rxs = dev->setupStream(SOAPY_SDR_RX, soapyFmt, channels);
txs = dev->setupStream(SOAPY_SDR_TX, soapyFmt, channels);
reset_DATA_clk_domain();
}
Radio::~Radio(void)
{
deactivateRecv();
deactivateXmit();
dev->closeStream(rxs);
dev->closeStream(txs);
SoapySDR::Device::unmake(dev);
}
int Radio::recv(void* const* buffs, int samples, long long& frameTime)
{
int flags(0);
return dev->readStream(rxs, buffs, samples, flags, frameTime, 1000000);
}
int Radio::activateRecv(const long long rxTime, const size_t numSamps)
{
return dev->activateStream(rxs, 0, rxTime, numSamps);
}
void Radio::deactivateRecv(void)
{
dev->deactivateStream(rxs);
}
int Radio::xmit(const void* const* buffs, int samples, int flags, long long& frameTime)
{
int soapyFlags[] = {
0,
SOAPY_SDR_HAS_TIME,
SOAPY_SDR_HAS_TIME | SOAPY_SDR_END_BURST,
SOAPY_SDR_WAIT_TRIGGER | SOAPY_SDR_END_BURST
};
int flag_args = soapyFlags[flags];
int r = dev->writeStream(txs, buffs, samples, flag_args, frameTime, 1000000);
if (r != samples)
std::cerr << "unexpected writeStream error " << SoapySDR::errToStr(r) << std::endl;
return (r);
}
void Radio::activateXmit(void)
{
dev->activateStream(txs);
}
void Radio::deactivateXmit(void)
{
dev->deactivateStream(txs);
}
int Radio::getTriggers(void) const
{
return std::stoi(dev->readSetting("TRIGGER_COUNT"));
}
void Radio::reset_DATA_clk_domain(void)
{
dev->writeSetting("RESET_DATA_LOGIC", "");
}
This diff is collapsed.
......@@ -10,6 +10,8 @@
#include "include/config.h"
#include "include/comms-lib.h"
#include "include/macros.h"
#include "include/utils.h"
Config::Config(const std::string& jsonfile)
{
......@@ -38,6 +40,9 @@ Config::Config(const std::string& jsonfile)
if (bsPresent) {
freq = tddConf.value("frequency", 3.6e9);
rate = tddConf.value("rate", 5e6);
nco = tddConf.value("nco_frequency", 0.75 * rate);
bwFilter = rate + 2 * nco;
radioRfFreq = freq - nco;
int samps = tddConf.value("subframe_size", 0);
prefix = tddConf.value("prefix", 0);
postfix = tddConf.value("postfix", 0);
......@@ -56,16 +61,16 @@ Config::Config(const std::string& jsonfile)
bsChannel = tddConf.value("channel", "A");
if (bsChannel != "A" && bsChannel != "B" && bsChannel != "AB")
throw std::invalid_argument("error channel config: not any of A/B/AB!\n");
bsSdrCh = (bsChannel == "AB") ? 2 : 1;
auto jBsFrames = tddConf.value("frame_schedule", json::array());
frames.assign(jBsFrames.begin(), jBsFrames.end());
txgainA = tddConf.value("txgainA", 20);
rxgainA = tddConf.value("rxgainA", 20);
txgainB = tddConf.value("txgainB", 20);
rxgainB = tddConf.value("rxgainB", 20);
calTxGainA = tddConf.value("calTxGainA", 10);
calTxGainB = tddConf.value("calTxGainB", 10);
txgain[0] = tddConf.value("txgainA", 20);
rxgain[0] = tddConf.value("rxgainA", 20);
txgain[1] = tddConf.value("txgainB", 20);
rxgain[1] = tddConf.value("rxgainB", 20);
calTxGain[0] = tddConf.value("calTxGainA", 10);
calTxGain[1] = tddConf.value("calTxGainB", 10);
sampleCalEn = tddConf.value("sample_calibrate", false);
imbalanceCalEn = tddConf.value("imbalance_calibrate", false);
beamsweep = tddConf.value("beamsweep", false);
beacon_ant = tddConf.value("beacon_antenna", 0);
max_frame = tddConf.value("max_frame", 0);
......@@ -76,7 +81,7 @@ Config::Config(const std::string& jsonfile)
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] = bsSdrCh * nBsSdrs[i];
nBsAntennas[i] = bsChannel.length() * nBsSdrs[i];
}
Utils::loadDevices(hub_file, hub_ids);
symbolsPerFrame = frames.at(0).size();
......@@ -126,17 +131,18 @@ Config::Config(const std::string& jsonfile)
throw std::invalid_argument("error channel config: not any of A/B/AB!\n");
clSdrCh = (clChannel == "AB") ? 2 : 1;
clAgcEn = tddConfCl.value("agc_en", false);
clAgcGainInit = tddConfCl.value("agc_gain_init", 70); // 0 to 108
clDataMod = tddConfCl.value("modulation", "QPSK");
frame_mode = tddConfCl.value("frame_mode", "continuous_resync");
auto jClTxgainA_vec = tddConfCl.value("txgainA", json::array());
clTxgainA_vec.assign(jClTxgainA_vec.begin(), jClTxgainA_vec.end());
clTxgain_vec[0].assign(jClTxgainA_vec.begin(), jClTxgainA_vec.end());
auto jClRxgainA_vec = tddConfCl.value("rxgainA", json::array());
clRxgainA_vec.assign(jClRxgainA_vec.begin(), jClRxgainA_vec.end());
clRxgain_vec[0].assign(jClRxgainA_vec.begin(), jClRxgainA_vec.end());
auto jClTxgainB_vec = tddConfCl.value("txgainB", json::array());
clTxgainB_vec.assign(jClTxgainB_vec.begin(), jClTxgainB_vec.end());
clTxgain_vec[1].assign(jClTxgainB_vec.begin(), jClTxgainB_vec.end());
auto jClRxgainB_vec = tddConfCl.value("rxgainB", json::array());
clRxgainB_vec.assign(jClRxgainB_vec.begin(), jClRxgainB_vec.end());
clRxgain_vec[1].assign(jClRxgainB_vec.begin(), jClRxgainB_vec.end());
auto jClFrames = tddConfCl.value("frame_schedule", json::array());
assert(jClSdrs.size() == jClFrames.size());
......@@ -149,19 +155,21 @@ Config::Config(const std::string& jsonfile)
if (!bsPresent) {
freq = tddConfCl.value("frequency", 3.6e9);
rate = tddConfCl.value("rate", 5e6);
nco = tddConfCl.value("nco_frequency", 0.75 * rate);
bwFilter = rate + 2 * nco;
radioRfFreq = freq - nco;
int samps = tddConfCl.value("subframe_size", 0);
prefix = tddConfCl.value("prefix", 0);
postfix = tddConfCl.value("postfix", 0);
sampsPerSymbol = samps + prefix + postfix;
fftSize = tddConfCl.value("fft_size", 0);
cpSize = tddConfCl.value("cp_size", 0);
tx_scale = tddConf.value("tx_scale", 0.5);
tx_scale = tddConfCl.value("tx_scale", 0.5);
beacon_seq = tddConfCl.value("beacon_seq", "gold_ifft");
pilot_seq = tddConfCl.value("pilot_seq", "lts-full");
symbolsPerFrame = clFrames.at(0).size();
}
}
bbf_ratio = 0.75;
// Signal Generation
if (bsPresent or clPresent) {
......@@ -181,17 +189,35 @@ Config::Config(const std::string& jsonfile)
std::vector<std::vector<std::complex<float>>> txdata_freq_dom_conf = txdata_freq_dom;
// Generate Beacon STS Sequence + GOLD Sequence
srand(time(NULL));
std::vector<std::vector<double>> gold_ifft = CommsLib::getSequence(128, CommsLib::GOLD_IFFT);
beacon_ci16.resize(256);
std::vector<std::vector<double>> sts_seq = CommsLib::getSequence(0, CommsLib::STS_SEQ);
int stsSymLen = sts_seq[0].size();
int stsReps = 15;
int stsLen = stsReps * stsSymLen; // length of entire STS sequence
beaconSize = 256 + stsLen;
beacon_ci16.resize(beaconSize); // OBCH: Original gold_ifft(256)+10repsSTS(160)
// Populate gold sequence (two reps, 128 each)
for (int i = 0; i < 128; i++) {
beacon_ci16[i] = std::complex<int16_t>((int16_t)(gold_ifft[0][i] * 32768), (int16_t)(gold_ifft[1][i] * 32768));
beacon_ci16[i + 128] = beacon_ci16[i];
beacon_ci16[stsLen + i] = std::complex<int16_t>((int16_t)(gold_ifft[0][i] * 32768), (int16_t)(gold_ifft[1][i] * 32768));
beacon_ci16[stsLen + i + 128] = beacon_ci16[stsLen + i];
}
// Populate STS (stsReps repetitions)
for (int i = 0; i < stsReps; i++) {
for (int j = 0; j < stsSymLen; j++) {
int16_t re = sts_seq[0][j] * 32768;
int16_t im = sts_seq[1][j] * 32768;
beacon_ci16[stsSymLen * i + j] = std::complex<int16_t>(re, im);
}
}
if (sampsPerSymbol < beaconSize + prefix + postfix) {
std::cout << "Subframe size too small!"
<< " Increasing to "
<< beaconSize << std::endl;
sampsPerSymbol = beaconSize + prefix + postfix;
}
std::vector<std::complex<int16_t>> pre0(prefix, 0);
std::vector<std::complex<int16_t>> post0(sampsPerSymbol - 256 - prefix, 0);
beacon_ci16.insert(beacon_ci16.begin(), pre0.begin(), pre0.end());
beacon_ci16.insert(beacon_ci16.end(), post0.begin(), post0.end());
beacon = Utils::cint16_to_uint32(beacon_ci16, false, "QI");
......@@ -217,7 +243,7 @@ Config::Config(const std::string& jsonfile)
pilot = Utils::cint16_to_uint32(pilot_ci16, false, "QI");
#if DEBUG_PRINT
for (int j = 0; j < pilot.size(); j++) {
for (size_t j = 0; j < pilot.size(); j++) {
std::cout << "Pilot[" << j << "]: \t " << pilot_ci16[j] << std::endl;
}
#endif
......@@ -286,13 +312,13 @@ Config::Config(const std::string& jsonfile)
txdata_freq_dom.push_back(data_freq_dom);
}
#if DEBUG_PRINT
for (int i = 0; i < txdata.size(); i++) {
for (int j = 0; j < txdata[i].size(); j++) {
for (size_t i = 0; i < txdata.size(); i++) {
for (size_t j = 0; j < txdata[i].size(); j++) {
std::cout << "Values[" << i << "][" << j << "]: \t " << txdata[i][j] << std::endl;
}
}
for (int i = 0; i < txdata_freq_dom.size(); i++) {
for (int j = 0; j < txdata_freq_dom[i].size(); j++) {
for (size_t i = 0; i < txdata_freq_dom.size(); i++) {
for (size_t j = 0; j < txdata_freq_dom[i].size(); j++) {
std::cout << "FREQ DOMAIN Values[" << i << "][" << j << "]: \t " << txdata_freq_dom[i][j] << std::endl;
}
}
......@@ -343,7 +369,7 @@ size_t Config::getNumAntennas()
{
if (!bsPresent)
return 1;
return nBsSdrs[0] * bsSdrCh;
return nBsSdrs[0] * bsChannel.length();
}
Config::~Config() {}
......@@ -354,9 +380,6 @@ int Config::getClientId(int frame_id, int symbol_id)
int fid = frame_id % frames.size();
it = find(pilotSymbols[fid].begin(), pilotSymbols[fid].end(), symbol_id);
if (it != pilotSymbols[fid].end()) {
#if DEBUG_PRINT
printf("getClientId(%d, %d) = %d\n", frame_id, symbol_id, it - pilotSymbols[fid].begin());
#endif
return it - pilotSymbols[fid].begin();
}
return -1;
......@@ -368,9 +391,6 @@ int Config::getUlSFIndex(int frame_id, int symbol_id)
int fid = frame_id % frames.size();
it = find(ULSymbols[fid].begin(), ULSymbols[fid].end(), symbol_id);
if (it != ULSymbols[fid].end()) {
#if DEBUG_PRINT
printf("getUlSFIndexId(%d, %d) = %d\n", frame_id, symbol_id, it - ULSymbols[fid].begin());
#endif
return it - ULSymbols[fid].begin();
}
return -1;
......
{
"BaseStations" : {
"cells" : 1,
"sdr_id" : ["files/iris_serials.txt"],
"hub_id" : "files/hub_serials.txt",
"sdr_id" : ["files/powder-iris-serials.txt"],
"hub_id" : "files/powder-hub-serials.txt",
"frequency" : 2.5e9,
"channel" : "AB",
"rxgainA" : 20,
......@@ -11,10 +11,10 @@
"txgainB" : 40,
"rate" : 5e6,
"frame_schedule" : [
"BGPGUGGGGGGGGGGGGGGG"
"BGPPGGGGGGGGGGGGGGGG"
],
"max_frame" : 0,
"subframe_size" : 400,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
......
......@@ -9,7 +9,7 @@
"txgainB" : [40],
"rate" : 5e6,
"fft_size" : 64,
"subframe_size" : 400,
"subframe_size" : 640,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
......@@ -21,7 +21,7 @@
"modulation" : "QPSK",
"pilot_seq" : "lts-half",
"sdr_id" : [
"RF3E000145"
"RF3E000060"
]
}
}
{
"BaseStations" : {
"cells" : 1,
"sdr_id" : ["files/powder-iris-serials.txt"],
"hub_id" : "files/powder-hub-serials.txt",
"frequency" : 2.5e9,
"channel" : "AB",
"rxgainA" : 20,
"txgainA" : 40,
"rxgainB" : 20,
"txgainB" : 40,
"rate" : 5e6,
"frame_schedule" : [
"BGPPPGGGGGGGGGGGGGGG"
],
"max_frame" : 6000,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"beamsweep" : true,
"sample_calibrate" : true,
"beacon_antenna" : 0,
"pilot_seq" : "lts-half"
},
"Clients" : {
"sdr_id" : [
"RF3E000060"
],
"frequency" : 2.5e9,
"channel" : "AB",
"agc_en" : false,
"agc_gain_init": 70,
"rxgainA" : [20],
"txgainA" : [40],
"rxgainB" : [20],
"txgainB" : [40],
"rate" : 5e6,
"frame_schedule" : [
"GGPPGGGGGGGGGGGGGGGG"
],
"frame_mode" : "continuous_resync",
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"pilot_seq" : "lts-half",
"modulation" : "16QAM"
}
}
{
"BaseStations" : {
"cells" : 1,
"sdr_id" : ["files/iris_serials.txt"],
"hub_id" : "files/hub_serials.txt",
"sdr_id" : ["files/powder-iris-serials.txt"],
"hub_id" : "files/powder-hub-serials.txt",
"frequency" : 2.5e9,
"channel" : "AB",
"rxgainA" : 20,
......@@ -13,8 +13,8 @@
"frame_schedule" : [
"BGPGUGGGGGGGGGGGGGGG"
],
"max_frame" : 4000,
"subframe_size" : 400,
"max_frame" : 6000,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
......@@ -23,16 +23,17 @@
"beamsweep" : true,
"sample_calibrate" : true,
"beacon_antenna" : 0,
"pilot_seq" : "lts-full"
"pilot_seq" : "lts-half"
},
"Clients" : {
"sdr_id" : [
"RF3E000145"
"RF3E000060"
],
"frequency" : 2.5e9,
"channel" : "A",
"agc_en" : false,
"agc_gain_init": 70,
"rxgainA" : [20],
"txgainA" : [40],
"rxgainB" : [20],
......@@ -42,13 +43,13 @@
"GDPGUGGGGGGGGGGGGGGG"
],
"frame_mode" : "continuous_resync",
"subframe_size" : 400,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"pilot_seq" : "lts-full",
"pilot_seq" : "lts-half",
"modulation" : "16QAM"
}
}
{
"BaseStations" : {
"cells" : 1,
"sdr_id" : ["files/iris_serials.txt"],
"hub_id" : "files/hub_serials.txt",
"frequency" : 3.6e9,
"channel" : "A",
"sdr_id" : ["files/powder-iris-serials.txt"],
"hub_id" : "files/powder-hub-serials.txt",
"frequency" : 2.5e9,
"channel" : "AB",
"rxgainA" : 20,
"txgainA" : 35,
"txgainA" : 40,
"rxgainB" : 20,
"txgainB" : 35,
"txgainB" : 40,
"rate" : 5e6,
"frame_schedule" : [
"BGPPGGGGGGGGGGGGGGGG"
"BGPPPGGGGGGGGGGGGGGG"
],
"max_frame" : 0,
"subframe_size" : 400,
"max_frame" : 4000,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
......@@ -28,23 +28,23 @@
"Clients" : {
"sdr_id" : [
"RF3C000045",
"RF3C000025"
"RF3E000060",
"RF3E000157"
],
"frequency" : 3.6e9,
"frequency" : 2.5e9,
"channel" : "A",
"agc_en" : false,
"rxgainA" : [20, 20],
"txgainA" : [35, 35],
"txgainA" : [40, 40],
"rxgainB" : [20, 20],
"txgainB" : [35, 35],
"txgainB" : [40, 40],
"rate" : 5e6,
"frame_schedule" : [
"GGPGGGGGGGGGGGGGGGGG",
"GGGPGGGGGGGGGGGGGGGG"
],
"frame_mode" : "continuous_resync",
"subframe_size" : 400,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
......
{
"BaseStations" : {
"cells" : 1,
"sdr_id" : ["files/renew-iris-serials1.txt"],
"hub_id" : "files/renew-hub-serials1.txt",
"frequency" : 3.6e9,
"channel" : "AB",
"rxgainA" : 20,
"txgainA" : 40,
"rxgainB" : 20,
"txgainB" : 40,
"rate" : 5e6,
"frame_schedule" : [
"BGPPGGGGGGGGGGGGGGGG"
],
"max_frame" : 0,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"beamsweep" : true,
"sample_calibrate" : false,
"beacon_antenna" : 0,
"pilot_seq" : "lts-half"
}
}
{
"Clients" : {
"frequency" : 3.6e9,
"channel" : "A",
"agc_en" : false,
"rxgainA" : [20],
"txgainA" : [40],
"rxgainB" : [20],
"txgainB" : [40],
"rate" : 5e6,
"fft_size" : 64,
"subframe_size" : 640,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"frame_schedule" : [
"GGPGGGGGGGGGGGGGGGGG"
],
"frame_mode" : "continuous_resync",
"beacon_type" : "gold_ifft",
"modulation" : "QPSK",
"pilot_seq" : "lts-half",
"sdr_id" : [
"RF3E000375"
]
}
}
{
"BaseStations" : {
"cells" : 1,
"sdr_id" : ["files/renew-iris-serials1.txt"],
"hub_id" : "files/renew-hub-serials1.txt",
"frequency" : 3.6e9,
"channel" : "AB",
"rxgainA" : 20,
"txgainA" : 40,
"rxgainB" : 20,
"txgainB" : 40,
"rate" : 5e6,
"frame_schedule" : [
"BGPPGGGGGGGGGGGGGGGG"
],
"max_frame" : 4000,
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"beamsweep" : true,
"sample_calibrate" : true,
"beacon_antenna" : 0,
"pilot_seq" : "lts-half"
},
"Clients" : {
"sdr_id" : [
"RF3C000045",
"RF3C000025"
],
"frequency" : 3.6e9,
"channel" : "A",
"agc_en" : false,
"rxgainA" : [50, 50],
"txgainA" : [40, 40],
"rxgainB" : [50, 50],
"txgainB" : [40, 40],
"rate" : 5e6,
"frame_schedule" : [
"GGPGGGGGGGGGGGGGGGGG",
"GGGPGGGGGGGGGGGGGGGG"
],
"frame_mode" : "continuous_resync",
"subframe_size" : 640,
"fft_size" : 64,
"cp_size" : 16,
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"pilot_seq" : "lts-half",
"modulation" : "16QAM"
}
}
0328
0339
0268
0282
0344
0233
0334
0402
#include "config.h"
#include <SoapySDR/Device.hpp>
class Radio;
class ClientRadioSet {
public:
ClientRadioSet(Config* cfg);
~ClientRadioSet(void);
int triggers(int i);
int radioRx(size_t radio_id, void* const* buffs, int numSamps, long long& frameTime);
int radioTx(size_t radio_id, const void* const* buffs, int numSamps, int flags, long long& frameTime);
void radioStop(void);
private:
void initAGC(SoapySDR::Device* iclSdrs);
Config* _cfg;
std::vector<Radio*> radios;
};
#include "config.h"
#include <SoapySDR/Device.hpp>
class Radio {
private:
SoapySDR::Device* dev;
SoapySDR::Stream* rxs;
SoapySDR::Stream* txs;
void reset_DATA_clk_domain(void);
void dev_init(Config* _cfg, int ch, double rxgain, double txgain);
friend class ClientRadioSet;
friend class BaseRadioSet;
public:
Radio(const SoapySDR::Kwargs& args, const char soapyFmt[], const std::vector<size_t>& channels, double rate);
~Radio(void);
int recv(void* const* buffs, int samples, long long& frameTime);
int activateRecv(const long long rxTime = 0, const size_t numSamps = 0);
void deactivateRecv(void);
int xmit(const void* const* buffs, int samples, int flags, long long& frameTime);
void activateXmit(void);
void deactivateXmit(void);
int getTriggers(void) const;
void drain_buffers(std::vector<void*> buffs, int symSamp);
};
......@@ -23,6 +23,7 @@
#include <string.h> /* for memcpy */
#include <unistd.h>
#include <vector>
#include <thread>
class CommsLib {
public:
......@@ -54,7 +55,13 @@ public:
static int findLTS(const std::vector<std::complex<double>>& iq, int seqLen);
static std::vector<double> convolve(std::vector<std::complex<double>> const& f, std::vector<std::complex<double>> const& g);
static std::vector<std::complex<double>> csign(std::vector<std::complex<double>> iq);
static void meshgrid(std::vector<int> x_in, std::vector<int> y_in, std::vector<std::vector<int>>& x, std::vector<std::vector<int>>& y);
static inline int hadamard2(int i, int j) { return (__builtin_parity(i & j) != 0 ? -1 : 1); }
static std::vector<float> magnitudeFFT(std::vector<std::complex<float>> const&, std::vector<float> const&, size_t);
static std::vector<float> hannWindowFunction(size_t);
static double windowFunctionPower(std::vector<float> const&);
template <typename T>
static T findTone(std::vector<T> const&, double, double, size_t, const size_t delta = 10);
static float measureTone(std::vector<std::complex<float>> const&, std::vector<float> const&, double, double, size_t, const size_t delta = 10);
//private:
// static inline float** init_qpsk();
// static inline float** init_qam16();
......
......@@ -11,15 +11,8 @@
#ifndef CONFIG_HEADER
#define CONFIG_HEADER
#include "macros.h"
#include "utils.h"
#include <algorithm>
#include <atomic>
#include <complex.h>
#include <fstream> // std::ifstream
#include <iostream>
#include <stdexcept>
#include <stdio.h> /* for fprintf */
#include <unistd.h>
#include <vector>
#ifdef JSON
#include <nlohmann/json.hpp>
......@@ -35,18 +28,20 @@ public:
// common features
double freq;
double bbf_ratio;
double nco; // baseband frequency controlled by NCO
double rate;
double radioRfFreq; // RF frequency set on the radio after NCO adjustments
double bwFilter;
int sampsPerSymbol;
int prefix;
int postfix;
int symbolsPerFrame;
int pilotSymsPerFrame;
int ulSymsPerFrame;
size_t pilotSymsPerFrame;
size_t ulSymsPerFrame;
int dlSymsPerFrame;
int fftSize;
int cpSize;
double tx_scale;
float tx_scale;
std::string pilot_seq;
std::string beacon_seq;
......@@ -57,25 +52,25 @@ public:
std::string ref_sdr;
std::vector<std::vector<std::string>> bs_sdr_ids;
std::vector<std::string> hub_ids;
std::vector<uint32_t> beacon;
std::vector<std::complex<int16_t>> beacon_ci16;
int beaconSize;
size_t beacon_ant;
bool beamsweep;
std::vector<size_t> nBsSdrs;
std::vector<size_t> nBsAntennas;
size_t bsSdrCh;
std::string bsChannel;
std::vector<std::string> frames;
std::string frame_mode;
int max_frame;
size_t max_frame;
std::vector<std::vector<size_t>> pilotSymbols;
std::vector<std::vector<size_t>> ULSymbols;
std::vector<std::vector<size_t>> DLSymbols;
double txgainA;
double rxgainA;
double txgainB;
double rxgainB;
double calTxGainA;
double calTxGainB;
double txgain[2];
double rxgain[2];
double calTxGain[2];
bool sampleCalEn;
bool imbalanceCalEn;
std::string trace_file;
// Clients features
......@@ -84,12 +79,11 @@ public:
int clSdrCh;
std::string clChannel;
bool clAgcEn;
int clAgcGainInit;
std::string clDataMod;
std::vector<int> data_ind;
std::vector<uint32_t> coeffs;
std::vector<std::complex<int16_t>> coeffs_ci16;
std::vector<uint32_t> beacon;
std::vector<std::complex<int16_t>> beacon_ci16;
std::vector<std::complex<int16_t>> pilot_ci16;
std::vector<uint32_t> pilot;
std::vector<std::vector<int>> pilot_sc;
......@@ -104,14 +98,9 @@ public:
std::vector<std::vector<size_t>> clULSymbols;
std::vector<std::vector<size_t>> clDLSymbols;
std::vector<double> clTxgainA_vec;
std::vector<double> clRxgainA_vec;
std::vector<double> clTxgainB_vec;
std::vector<double> clRxgainB_vec;
std::vector<double> clTxgain_vec[2];
std::vector<double> clRxgain_vec[2];
const int data_offset = sizeof(int) * 4;
// header 4 int for: frame_id, subframe_id, cell_id, ant_id
// ushort for: I/Q samples
size_t getPackageLength()
{
return sizeof(int) * 4 + sizeof(ushort) * (size_t)sampsPerSymbol * 2;
......
......@@ -25,10 +25,33 @@
#define MAX_FRAME_INC 2000
#define TIME_DELTA 20 //ms
#define SETTLE_TIME_MS 1
// Triggers - Used for Samples Offset Calibration
#define FPGA_IRIS30_TRIGGERS 44
#define FPGA_IRIS30_INCR_TIME (1 << 2)
#define FPGA_IRIS30_DECR_TIME (1 << 3)
// AGC and Packet Detect
#define FPGA_IRIS030_WR_AGC_ENABLE_FLAG 232
#define FPGA_IRIS030_WR_AGC_RESET_FLAG 236
#define FPGA_IRIS030_WR_IQ_THRESH 240
#define FPGA_IRIS030_WR_NUM_SAMPS_SAT 244
#define FPGA_IRIS030_WR_MAX_NUM_SAMPS_AGC 248
#define FPGA_IRIS030_WR_RSSI_TARGET 252
#define FPGA_IRIS030_WR_WAIT_COUNT_THRESH 256
#define FPGA_IRIS030_WR_AGC_SMALL_JUMP 260
#define FPGA_IRIS030_WR_AGC_BIG_JUMP 264
#define FPGA_IRIS030_WR_AGC_TEST_GAIN_SETTINGS 268
#define FPGA_IRIS030_WR_AGC_GAIN_INIT 316
// RSSI register Set
#define FPGA_IRIS030_RD_MEASURED_RSSI 284
// Packet Detect Register Set
#define FPGA_IRIS030_WR_PKT_DET_THRESH 288
#define FPGA_IRIS030_WR_PKT_DET_NUM_SAMPS 292
#define FPGA_IRIS030_WR_PKT_DET_ENABLE 296
#define FPGA_IRIS030_WR_PKT_DET_NEW_FRAME 300
#endif
......@@ -26,27 +26,37 @@
#include <sys/socket.h>
#include <sys/types.h>
typedef unsigned short ushort;
struct complex_float {
float real;
float imag;
};
struct Event_data {
int event_type;
int data;
};
struct Package {
uint32_t frame_id;
uint32_t symbol_id;
uint32_t cell_id;
uint32_t ant_id;
short data[];
Package(int f, int s, int c, int a)
: frame_id(f)
, symbol_id(s)
, cell_id(c)
, ant_id(a)
{
}
};
struct SampleBuffer {
std::vector<char> buffer;
std::vector<int> buffer_status;
std::atomic_int* pkg_buf_inuse;
};
//std::atomic_int thread_count(0);
//std::mutex d_mutex;
//std::condition_variable cond;
class ClientRadioSet;
class Receiver {
public:
// use for create pthread
......@@ -65,9 +75,6 @@ public:
int txStartSym;
unsigned txFrameDelta;
double rate;
SoapySDR::Device* device;
SoapySDR::Stream* rxs;
SoapySDR::Stream* txs;
std::string data_file;
int core;
Receiver* ptr;
......@@ -81,18 +88,16 @@ public:
void completeRecvThreads(const std::vector<pthread_t>& recv_thread);
std::vector<pthread_t> startClientThreads();
void go();
static void* loopRecv(void* in_context);
static void* clientTxRx(void* context);
static void* loopRecv_launch(void* in_context);
void loopRecv(ReceiverContext* context);
static void* clientTxRx_launch(void* in_context);
void clientTxRx(dev_profile* context);
void getPathLoss();
private:
Config* config_;
struct sockaddr_in servaddr_; /* server address */
int* socket_;
RadioConfig* radioconfig_;
int buffer_length_;
int buffer_frame_num_;
ClientRadioSet* clientRadioSet_;
BaseRadioSet* baseRadioSet_;
int thread_num_;
// pointer of message_queue_
......
......@@ -12,54 +12,41 @@
#define DATARECORDER_HEADER
#include "H5Cpp.h"
#include "hdf5.h"
#include "receiver.h"
#include "signalHandler.hpp"
#include <algorithm>
#include <complex>
#include <ctime>
#include <fcntl.h>
#include <math.h>
#include <memory>
#include <pthread.h>
#include <queue>
#include <signal.h>
#include <sstream>
#include <string>
#include <system_error>
#include <unistd.h>
using std::cout;
using std::endl;
using namespace H5;
class Recorder {
public:
// buffer length of each rx thread
static const int SAMPLE_BUFFER_FRAME_NUM = 80;
// buffer length of recording part
static const int TASK_BUFFER_FRAME_NUM = 60;
// dequeue bulk size, used to reduce the overhead of dequeue in main thread
static const int dequeue_bulk_size = 5;
Recorder(Config* cfg);
~Recorder();
void do_it();
herr_t initHDF5(const std::string&);
void openHDF5();
void closeHDF5();
void finishHDF5();
static void* taskThread(void* in_context);
herr_t record(int tid, int offset);
private:
struct EventHandlerContext {
Recorder* obj_ptr;
int id;
};
herr_t record(int tid, int offset);
void taskThread(EventHandlerContext* context);
herr_t initHDF5(const std::string&);
void openHDF5();
void closeHDF5();
void finishHDF5();
static void* taskThread_launch(void* in_context);
// buffer length of each rx thread
static const int SAMPLE_BUFFER_FRAME_NUM;
// buffer length of recording part
static const int TASK_BUFFER_FRAME_NUM;
// dequeue bulk size, used to reduce the overhead of dequeue in main thread
static const int dequeue_bulk_size;
// pilot dataset size increment
static const int config_pilot_extent_step;
// data dataset size increment
static const int config_data_extent_step;
private:
Config* cfg;
bool core_alloc;
std::unique_ptr<Receiver> receiver_;
SampleBuffer* rx_buffer_;
......@@ -67,34 +54,23 @@ private:
H5std_string hdf5group;
H5File* file;
Group* group;
// Group* group;
DSetCreatPropList pilot_prop;
DSetCreatPropList data_prop;
DataSpace* data_filespace;
DataSet* pilot_dataset;
DataSet* data_dataset;
int ndims;
int cndims;
hsize_t dims_pilot[5];
hsize_t dims_data[5];
size_t frame_number_pilot;
size_t frame_number_data;
#if DEBUG_PRINT
hsize_t cdims_pilot[5];
hsize_t cdims_data[5];
#endif
int config_pilot_extent_step = 400;
int config_data_extent_step = 400;
bool config_dump_data;
int maxFrameNumber;
int rx_thread_num;
int task_thread_num;
size_t maxFrameNumber;
moodycamel::ConcurrentQueue<Event_data> task_queue_;
moodycamel::ConcurrentQueue<Event_data> message_queue_;
pthread_t* task_threads; //[TASK_THREAD_NUM];
std::vector<pthread_t> recv_thread;
std::vector<std::unique_ptr<moodycamel::ProducerToken>> task_ptok; //[TASK_THREAD_NUM];
// std::vector<std::unique_ptr<moodycamel::ProducerToken>> task_ptok; //[TASK_THREAD_NUM];
};
#endif
#include "config.h"
#include <SoapySDR/Device.hpp>
#include <SoapySDR/Errors.hpp>
#include <SoapySDR/Formats.hpp>
#include <SoapySDR/Time.hpp>
#include <chrono>
#include <complex>
#include <csignal>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
class RadioConfig {
class Radio;
class BaseRadioSet {
public:
RadioConfig(Config* cfg);
static void* initBSRadio(void* in_context);
void radioConfigure();
void radioStart();
void radioStop();
void readSensors();
BaseRadioSet(Config* cfg);
~BaseRadioSet(void);
void radioTx(const void* const* buffs);
void radioRx(void* const* buffs);
int radioTx(int, const void* const* buffs, int flags, long long& frameTime);
int radioRx(int, void* const* buffs, long long& frameTime);
void collectCSI(bool&);
static void drain_buffers(SoapySDR::Device* ibsSdrs, SoapySDR::Stream* istream, std::vector<void*> buffs, int symSamp);
void sync_delays(int cellIdx);
int radioTx(size_t radio_id, const void* const* buffs, int flags, long long& frameTime);
int radioRx(size_t radio_id, void* const* buffs, long long& frameTime);