...
 
Commits (43)
[submodule "CC/Sounder/mufft"]
path = CC/Sounder/mufft
url = https://github.com/themaister/mufft
......@@ -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 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})
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})
......@@ -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
......
......@@ -20,6 +20,7 @@
*/
#include "include/comms-lib.h"
#include <queue>
//#include <itpp/itbase.h>
int CommsLib::findLTS(const std::vector<std::complex<double>>& iq, int seqLen)
......@@ -41,14 +42,14 @@ int CommsLib::findLTS(const std::vector<std::complex<double>>& iq, int seqLen)
lts_seq = CommsLib::getSequence(seqLen, LTS_SEQ);
// Re-arrange into complex vector, flip, and compute conjugate
std::vector<std::complex<double>> lts_sym;
std::vector<std::complex<double>> lts_sym_conj;
for (int i = 0; i < 64; i++) {
std::vector<std::complex<double>> lts_sym(64);
std::vector<std::complex<double>> lts_sym_conj(lts_sym.size());
for (size_t i = 0; i < lts_sym.size(); i++) {
// lts_seq is a 2x160 matrix (real/imag by seqLen=160 elements)
// grab one symbol and flip around
lts_sym.push_back(std::complex<double>(lts_seq[0][seqLen - 1 - i], lts_seq[1][seqLen - 1 - i]));
lts_sym[i] = std::complex<double>(lts_seq[0][seqLen - 1 - i], lts_seq[1][seqLen - 1 - i]);
// conjugate
lts_sym_conj.push_back(std::conj(lts_sym[i]));
lts_sym_conj[i] = std::conj(lts_sym[i]);
}
// Equivalent to numpy's sign function
......@@ -56,62 +57,25 @@ int CommsLib::findLTS(const std::vector<std::complex<double>>& iq, int seqLen)
// Convolution
std::vector<double> lts_corr = CommsLib::convolve(iq_sign, lts_sym_conj);
double lts_limit = lts_thresh * *std::max_element(lts_corr.begin(), lts_corr.end());
// Find all peaks
std::vector<int> peaks;
for (size_t i = 0; i < lts_corr.size(); i++) {
if (lts_corr[i] > (lts_thresh * *std::max_element(lts_corr.begin(), lts_corr.end()))) {
// Index of valid peaks
peaks.push_back(i);
}
// Find all peaks, and pairs that are lts_sym.size() samples apart
std::queue<int> valid_peaks;
for (size_t i = lts_sym.size(); i < lts_corr.size(); i++) {
if (lts_corr[i] > lts_limit && lts_corr[i - lts_sym.size()] > lts_limit)
valid_peaks.push(i - lts_sym.size());
}
std::vector<std::vector<int>> x_vec(peaks.size());
std::vector<std::vector<int>> y_vec(peaks.size());
CommsLib::meshgrid(peaks, peaks, x_vec, y_vec);
// Find peaks that are 64 samples apart
std::vector<int> valid_peaks;
for (size_t i = 0; i < x_vec.size(); i++) {
for (size_t j = 0; j < x_vec[0].size(); j++) {
int idx_diff = y_vec[i][j] - x_vec[i][j];
if (idx_diff == static_cast<int>(lts_sym.size())) {
valid_peaks.push_back(peaks[i]);
}
}
}
// Use first LTS found
if (valid_peaks.empty()) {
best_peak = -1;
} else {
best_peak = valid_peaks[0];
best_peak = valid_peaks.front();
}
return best_peak;
}
void CommsLib::meshgrid(std::vector<int> x_in, std::vector<int> y_in, std::vector<std::vector<int>>& x, std::vector<std::vector<int>>& y)
{
/*
* Simplified version of numpy's meshgrid function. Input vectors must be of same length.
* Returns coordinate matrices from coordinate vectors.
*/
int nx = x_in.size();
int ny = y_in.size();
if (nx != ny) {
throw std::invalid_argument(" Input vectors to meshgrid function must have same length. ");
}
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
x[i].push_back(x_in[j]);
y[i].push_back(y_in[i]);
//std::cout << "XXXX x[" << i << "][" << j << "]: " << x[i][j] << std::endl;
//std::cout << "YYYY y[" << i << "][" << j << "]: " << y[i][j] << std::endl;
}
}
}
std::vector<std::complex<double>> CommsLib::csign(std::vector<std::complex<double>> iq)
{
/*
......@@ -514,7 +478,7 @@ std::vector<std::vector<double>> CommsLib::getSequence(int N, int type)
for (int i = 0; i < N; i++) {
matrix[i].resize(N);
for (int j = 0; j < N; j++)
matrix[i][j] = __builtin_parity(i & j) != 0 ? -1 : 1;
matrix[i][j] = hadamard2(i, j);
}
}
}
......
......@@ -56,7 +56,6 @@ 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());
txgain[0] = tddConf.value("txgainA", 20);
......@@ -76,7 +75,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();
......@@ -217,7 +216,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 +285,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 +342,7 @@ size_t Config::getNumAntennas()
{
if (!bsPresent)
return 1;
return nBsSdrs[0] * bsSdrCh;
return nBsSdrs[0] * bsChannel.length();
}
Config::~Config() {}
......@@ -354,9 +353,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 +364,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"],
"sdr_id" : ["files/iris_serials1.txt"],
"hub_id" : "files/hub_serials.txt",
"frequency" : 2.5e9,
"channel" : "AB",
"frequency" : 3.6e9,
"channel" : "A",
"rxgainA" : 20,
"txgainA" : 40,
"rxgainB" : 20,
......
......@@ -3,8 +3,8 @@
"cells" : 1,
"sdr_id" : ["files/iris_serials.txt"],
"hub_id" : "files/hub_serials.txt",
"frequency" : 2.5e9,
"channel" : "AB",
"frequency" : 3.6e9,
"channel" : "A",
"rxgainA" : 20,
"txgainA" : 40,
"rxgainB" : 20,
......@@ -23,14 +23,14 @@
"beamsweep" : true,
"sample_calibrate" : true,
"beacon_antenna" : 0,
"pilot_seq" : "lts-full"
"pilot_seq" : "lts-half"
},
"Clients" : {
"sdr_id" : [
"RF3E000145"
"RF3C000045"
],
"frequency" : 2.5e9,
"frequency" : 3.6e9,
"channel" : "A",
"agc_en" : false,
"rxgainA" : [20],
......@@ -48,7 +48,7 @@
"prefix" : 82,
"postfix" : 68,
"beacon_seq" : "gold_ifft",
"pilot_seq" : "lts-full",
"pilot_seq" : "lts-half",
"modulation" : "16QAM"
}
}
{
"Clients" : {
"frequency" : 2.5e9,
"frequency" : 3.6e9,
"channel" : "A",
"agc_en" : false,
"rxgainA" : [20],
......@@ -21,7 +21,7 @@
"modulation" : "QPSK",
"pilot_seq" : "lts-half",
"sdr_id" : [
"RF3E000145"
"RF3C000045"
]
}
}
......@@ -54,7 +54,7 @@ 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); }
//private:
// static inline float** init_qpsk();
// static inline float** init_qam16();
......
......@@ -61,7 +61,6 @@ public:
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;
......
......@@ -25,13 +25,14 @@ public:
static void* initBSRadio_launch(void* in_context);
void radioConfigure();
void radioStart();
void radioTrigger();
void radioStop();
void readSensors();
void radioTx(const void* const* buffs);
void radioRx(void* const* buffs);
int radioTx(size_t, const void* const* buffs, int flags, long long& frameTime);
int radioRx(size_t, void* const* buffs, long long& frameTime);
void initAGC(SoapySDR::Device * iclSdrs);
void initAGC(SoapySDR::Device* iclSdrs);
void sync_delays(int cellIdx);
~RadioConfig();
......@@ -45,6 +46,7 @@ public:
void initBSRadio(RadioConfigContext* context);
private:
SoapySDR::Device* baseRadio(int cellId);
void collectCSI(bool&);
static void drain_buffers(SoapySDR::Device* ibsSdrs, SoapySDR::Stream* istream, std::vector<void*> buffs, int symSamp);
Config* _cfg;
......
Subproject commit 47bb08652eab399c2c7d460abe5184857110f130
......@@ -11,6 +11,9 @@
#include "include/receiver.h"
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Receiver::Receiver(int n_rx_threads, Config* config, moodycamel::ConcurrentQueue<Event_data>* in_queue)
{
this->config_ = config;
......@@ -88,7 +91,7 @@ std::vector<pthread_t> Receiver::startRecvThreads(SampleBuffer* rx_buffer, unsig
}
sleep(1);
//sleep(.01);
pthread_cond_broadcast(&cond);
go();
return created_threads;
}
......@@ -127,10 +130,17 @@ void Receiver::loopRecv(ReceiverContext* context)
}
}
// Use mutex to sychronize data receiving across threads
pthread_mutex_lock(&mutex);
printf("Recv Thread %d: waiting for release\n", tid);
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex); // unlocking for all other threads
// use token to speed up
moodycamel::ProducerToken local_ptok(*message_queue_);
const int bsSdrCh = config_->bsSdrCh;
const int bsSdrCh = config_->bsChannel.length();
int buffer_frame_num = rx_buffer[0].pkg_buf_inuse.size();
// handle two channels at each radio
......@@ -143,18 +153,20 @@ void Receiver::loopRecv(ReceiverContext* context)
printf("receiver thread %d has %d radios\n", tid, radio_end - radio_start);
for (int cursor = 0; config_->running;
cursor += bsSdrCh, cursor %= buffer_frame_num) {
// if buffer is full, exit
if (pkg_buf_inuse[cursor]) {
printf("thread %d buffer full\n", tid);
exit(0);
}
int cursor = 0;
while (config_->running) {
// receive data
for (int it = radio_start; it < radio_end; it++) {
// if buffer is full, exit
if (pkg_buf_inuse[cursor]) {
printf("thread %d buffer full\n", tid);
exit(0);
}
Package* pkg[bsSdrCh];
void* samp[bsSdrCh];
for (auto ch = 0; ch < bsSdrCh; ++ch) {
samp[ch] = buffer + 4 * sizeof(int) + (cursor + ch) * config_->getPackageLength();
pkg[ch] = (Package*)(buffer + (cursor + ch) * config_->getPackageLength());
samp[ch] = pkg[ch]->data;
}
long long frameTime;
if (radioconfig_->radioRx(it, samp, frameTime) < 0) {
......@@ -166,16 +178,15 @@ void Receiver::loopRecv(ReceiverContext* context)
int symbol_id = (int)((frameTime >> 16) & 0xFFFF);
int ant_id = it * bsSdrCh;
#if DEBUG_PRINT
Package* pkg = (Package*)(buffer + cursor * config_->getPackageLength());
printf("receive thread %d, frame_id %d, symbol_id %d, cell_id %d, ant_id %d\n",
tid, frame_id, symbol_id, cell_id, ant_id);
printf("receive samples: %d %d %d %d %d %d %d %d ...\n",
pkg->data[1], pkg->data[2], pkg->data[3], pkg->data[4],
pkg->data[5], pkg->data[6], pkg->data[7], pkg->data[8]);
for (auto ch = 0; ch < bsSdrCh; ++ch) {
printf("receive thread %d, frame %d, symbol %d, cell %d, ant %d samples: %d %d %d %d %d %d %d %d ...\n",
tid, frame_id, symbol_id, 0, ant_id + ch,
pkg[ch]->data[1], pkg[ch]->data[2], pkg[ch]->data[3], pkg[ch]->data[4],
pkg[ch]->data[5], pkg[ch]->data[6], pkg[ch]->data[7], pkg[ch]->data[8]);
}
#endif
for (auto ch = 0; ch < bsSdrCh; ++ch) {
new (buffer + (cursor + ch) * config_->getPackageLength())
Package(frame_id, symbol_id, 0, ant_id + ch);
new (pkg[ch]) Package(frame_id, symbol_id, 0, ant_id + ch);
// move ptr & set status to full
pkg_buf_inuse[cursor + ch] = true; // has data, after it is read it should be set to 0
// push EVENT_RX_SYMBOL event into the queue
......@@ -183,12 +194,14 @@ void Receiver::loopRecv(ReceiverContext* context)
package_message.event_type = EVENT_RX_SYMBOL;
// data records the position of this packet in the buffer & tid of this socket
// (so that task thread could know which buffer it should visit)
package_message.data = cursor + tid * buffer_frame_num;
package_message.data = cursor + ch + tid * buffer_frame_num;
if (!message_queue_->enqueue(local_ptok, package_message)) {
printf("socket message enqueue failed\n");
exit(0);
}
}
cursor += bsSdrCh;
cursor %= buffer_frame_num;
}
}
}
......
......@@ -234,7 +234,7 @@ herr_t Recorder::initHDF5(const std::string& hdf5)
write_attribute(mainGroup, "BS_NUM_CELLS", (int)cfg->nCells);
// How many RF channels per Iris board are enabled ("single" or "dual")
write_attribute(mainGroup, "BS_CH_PER_RADIO", (int)cfg->bsSdrCh);
write_attribute(mainGroup, "BS_CH_PER_RADIO", (int)cfg->bsChannel.length());
// Frame schedule (vec of strings for now, this should change to matrix when we go to multi-cell)
write_attribute(mainGroup, "BS_FRAME_SCHED", cfg->frames);
......@@ -263,6 +263,9 @@ herr_t Recorder::initHDF5(const std::string& hdf5)
// Number of symbols in a frame
write_attribute(mainGroup, "BS_FRAME_LEN", cfg->symbolsPerFrame);
// Number of uplink symbols per frame
write_attribute(mainGroup, "UL_SYMS", (int)cfg->ulSymsPerFrame);
// ******* Clients ******** //
// Data subcarriers
write_attribute(mainGroup, "OFDM_DATA_SC", cfg->data_ind);
......@@ -297,36 +300,34 @@ herr_t Recorder::initHDF5(const std::string& hdf5)
// Number of Clients
write_attribute(mainGroup, "CL_NUM", (int)cfg->nClSdrs);
// Client antenna polarization
write_attribute(mainGroup, "CL_CH_PER_RADIO", cfg->clSdrCh);
// Client AGC enable flag
write_attribute(mainGroup, "CL_AGC_EN", cfg->clAgcEn ? 1 : 0);
// RX Gain RF channel A
write_attribute(mainGroup, "CL_RX_GAIN_A", cfg->clRxgain_vec[0]);
if (cfg->clPresent) {
// Client antenna polarization
write_attribute(mainGroup, "CL_CH_PER_RADIO", cfg->clSdrCh);
// TX Gain RF channel A
write_attribute(mainGroup, "CL_TX_GAIN_A", cfg->clTxgain_vec[0]);
// Client AGC enable flag
write_attribute(mainGroup, "CL_AGC_EN", cfg->clAgcEn ? 1 : 0);
// RX Gain RF channel B
write_attribute(mainGroup, "CL_RX_GAIN_B", cfg->clRxgain_vec[1]);
// RX Gain RF channel A
write_attribute(mainGroup, "CL_RX_GAIN_A", cfg->clRxgain_vec[0]);
// TX Gain RF channel B
write_attribute(mainGroup, "CL_TX_GAIN_B", cfg->clTxgain_vec[1]);
// TX Gain RF channel A
write_attribute(mainGroup, "CL_TX_GAIN_A", cfg->clTxgain_vec[0]);
// Client frame schedule (vec of strings)
write_attribute(mainGroup, "CL_FRAME_SCHED", cfg->clFrames);
// RX Gain RF channel B
write_attribute(mainGroup, "CL_RX_GAIN_B", cfg->clRxgain_vec[1]);
// Set of client SDR IDs (vec of strings)
write_attribute(mainGroup, "CL_SDR_ID", cfg->cl_sdr_ids);
// TX Gain RF channel B
write_attribute(mainGroup, "CL_TX_GAIN_B", cfg->clTxgain_vec[1]);
// Data modulation
write_attribute(mainGroup, "CL_MODULATION", cfg->clDataMod);
// Client frame schedule (vec of strings)
write_attribute(mainGroup, "CL_FRAME_SCHED", cfg->clFrames);
// Number of uplink symbols per frame
write_attribute(mainGroup, "UL_SYMS", (int)cfg->ulSymsPerFrame);
// Set of client SDR IDs (vec of strings)
write_attribute(mainGroup, "CL_SDR_ID", cfg->cl_sdr_ids);
// Data modulation
write_attribute(mainGroup, "CL_MODULATION", cfg->clDataMod);
}
// ********************* //
pilot_prop.close();
......@@ -382,6 +383,7 @@ void Recorder::openHDF5()
#if DEBUG_PRINT
hsize_t IQ = 2 * cfg->sampsPerSymbol;
int cndims_pilot = 0;
int ndims = pilot_filespace.getSimpleExtentNdims();
if (H5D_CHUNKED == pilot_prop.getLayout())
cndims_pilot = pilot_prop.getChunk(ndims, cdims_pilot);
using std::cout;
......@@ -390,9 +392,10 @@ void Recorder::openHDF5()
frame_number_pilot, cfg->nCells,
cfg->pilotSymsPerFrame, cfg->getNumAntennas(), IQ
};
cout << "New Pilot Dataset Dimension " << ndims << ",";
cout << "New Pilot Dataset Dimension: [";
cout << dims_pilot[0] << "," << dims_pilot[1] << ",";
cout << dims_pilot[2] << "," << dims_pilot[3] << "," << IQ < std::endl;
cout << dims_pilot[2] << "," << dims_pilot[3] << ",";
cout << IQ << "]" << std::endl;
#endif
pilot_filespace.close();
// Get Dataset for DATA (If Enabled) and check the shape of it
......@@ -557,9 +560,8 @@ herr_t Recorder::record(int, int offset)
char* cur_ptr_buffer = rx_buffer_[buffer_id].buffer.data() + offset * cfg->getPackageLength();
struct Package* pkg = (struct Package*)cur_ptr_buffer;
#if DEBUG_PRINT
printf("record process frame_id %d, symbol_id %d, cell_id %d, ant_id %d\n",
pkg->frame_id, pkg->symbol_id, pkg->cell_id, pkg->ant_id);
printf("record samples: %d %d %d %d %d %d %d %d ....\n",
printf("record frame %d, symbol %d, cell %d, ant %d samples: %d %d %d %d %d %d %d %d ....\n",
pkg->frame_id, pkg->symbol_id, pkg->cell_id, pkg->ant_id,
pkg->data[1], pkg->data[2], pkg->data[3], pkg->data[4],
pkg->data[5], pkg->data[6], pkg->data[7], pkg->data[8]);
#endif
......
This diff is collapsed.
......@@ -153,16 +153,11 @@ else
% calibration on the BS. This functionality will be added later.
% For now, we use only the 4-node chains:
% b_ids = ["RF3E000134", "RF3E000191", "RF3E000171", "RF3E000105",...
% "RF3E000053", "RF3E000177", "RF3E000192", "RF3E000117",...
% "RF3E000183", "RF3E000152", "RF3E000123", "RF3E000178", "RF3E000113", "RF3E000176", "RF3E000132", "RF3E000108", ...
% "RF3E000143", "RF3E000160", "RF3E000025", "RF3E000034",...
% "RF3E000189", "RF3E000024", "RF3E000139", "RF3E000032", "RF3E000154", "RF3E000182", "RF3E000038", "RF3E000137", ...
% "RF3E000103", "RF3E000180", "RF3E000181", "RF3E000188"];
% IDs of the 4-node chains:
b_ids = ["RF3E000134", "RF3E000191", "RF3E000171", "RF3E000105",...
"RF3E000053", "RF3E000177", "RF3E000192", "RF3E000117",...
"RF3E000183", "RF3E000152", "RF3E000123", "RF3E000178", "RF3E000113", "RF3E000176", "RF3E000132", "RF3E000108", ...
"RF3E000143", "RF3E000160", "RF3E000025", "RF3E000034",...
"RF3E000189", "RF3E000024", "RF3E000139", "RF3E000032", "RF3E000154", "RF3E000182", "RF3E000038", "RF3E000137", ...
"RF3E000103", "RF3E000180", "RF3E000181", "RF3E000188"];
hub_id = "FH4A000001";
......
......@@ -23,7 +23,7 @@ end
WRITE_PNG_FILES = 0; % Enable writing plots to PNG
CHANNEL = 11; % Channel to tune Tx and Rx radios
SIM_MOD = 0;
N_BS_NODE = 16;
N_BS_NODE = 32;
N_UE = 1;
if SIM_MOD
......@@ -152,16 +152,11 @@ else
% calibration on the BS. This functionality will be added later.
% For now, we use only the 4-node chains:
% b_ids = ["RF3E000134", "RF3E000191", "RF3E000171", "RF3E000105",...
% "RF3E000053", "RF3E000177", "RF3E000192", "RF3E000117",...
% "RF3E000183", "RF3E000152", "RF3E000123", "RF3E000178", "RF3E000113", "RF3E000176", "RF3E000132", "RF3E000108", ...
% "RF3E000143", "RF3E000160", "RF3E000025", "RF3E000034",...
% "RF3E000189", "RF3E000024", "RF3E000139", "RF3E000032", "RF3E000154", "RF3E000182", "RF3E000038", "RF3E000137", ...
% "RF3E000103", "RF3E000180", "RF3E000181", "RF3E000188"];
% IDs of the 4-node chains:
b_ids = ["RF3E000134", "RF3E000191", "RF3E000171", "RF3E000105",...
"RF3E000053", "RF3E000177", "RF3E000192", "RF3E000117",...
"RF3E000183", "RF3E000152", "RF3E000123", "RF3E000178", "RF3E000113", "RF3E000176", "RF3E000132", "RF3E000108", ...
"RF3E000143", "RF3E000160", "RF3E000025", "RF3E000034",...
"RF3E000189", "RF3E000024", "RF3E000139", "RF3E000032", "RF3E000154", "RF3E000182", "RF3E000038", "RF3E000137", ...
"RF3E000103", "RF3E000180", "RF3E000181", "RF3E000188"];
hub_id = "FH4A000001";
......@@ -224,28 +219,40 @@ l_rx_dec=length(rx_vec_iris);
a = 1;
unos = ones(size(preamble.'))';
data_len = (N_OFDM_SYM)*(N_SC +CP_LEN);
rx_lts_mat = double.empty();
payload_ind = int32.empty();
payload_rx = zeros(data_len,N_BS_NODE);
m_filt = zeros(length(rx_vec_iris),N_BS_NODE);
for ibs =1:N_BS_NODE
v0 = filter(flipud(preamble'),a,rx_vec_iris(:,ibs));
v1 = filter(unos,a,abs(rx_vec_iris(:,ibs)).^2);
m_filt(:,ibs) = (abs(v0).^2)./v1; % normalized correlation
[~, max_idx] = max(m_filt(:,ibs));
% In case of bad correlatons:
if (max_idx + data_len) > length(rx_vec_iris) || (max_idx < 0) || (max_idx - length(preamble) < 0)
fprintf('Bad correlation at antenna %d max_idx = %d \n', ibs, max_idx);
% Real value doesn't matter since we have corrrupt data:
max_idx = length(rx_vec_iris)-data_len -1;
end
payload_ind(ibs) = max_idx +1;
lts_ind = payload_ind(ibs) - length(preamble);
pl_idx = payload_ind(ibs) : payload_ind(ibs) + data_len;
rx_lts_mat(:,ibs) = rx_vec_iris(lts_ind: lts_ind + length(preamble) -1, ibs );
payload_rx(1:length(pl_idx) -1,ibs) = rx_vec_iris(payload_ind(ibs) : payload_ind(ibs) + length(pl_idx) -2, ibs);
end
% Just for plotting
lts_corr = sum(m_filt,2);
[rho_max, ipos] = max(lts_corr);
% Find all correlation peaks
payload_ind = ipos +1;
lts_ind = payload_ind - N_LTS_SYM*(N_SC + CP_LEN);
% Extract LTS for channel estimate
rx_lts = rx_vec_iris(lts_ind : lts_ind+159,:);
rx_lts_idx1 = -64+-FFT_OFFSET + (97:160);
rx_lts_idx2 = -FFT_OFFSET + (97:160);
% Just for two first brnaches: useful when 1x2 SIMO, to show the
% improvement:
rx_lts_b1 = [rx_lts(rx_lts_idx1,1) rx_lts(rx_lts_idx2,1)];
rx_lts_b2 = [rx_lts(rx_lts_idx1,2) rx_lts(rx_lts_idx2,2)];
% Just for two first brnaches: useful when 1x2 SIMO. Just to illustrate
% improvement of MRC over two branches:
rx_lts_b1 = [rx_lts_mat(rx_lts_idx1,1) rx_lts_mat(rx_lts_idx2,1)];
rx_lts_b2 = [rx_lts_mat(rx_lts_idx1,2) rx_lts_mat(rx_lts_idx2,2)];
% Received LTSs for each branch.
rx_lts_b1_f = fft(rx_lts_b1);
......@@ -263,7 +270,7 @@ H_b2(idx_0,:) = 0;
% Channel Estimate of multiple branches:
H_0_t = zeros(N_SC, N_LTS_SYM, N_BS_NODE);
% Take N_SC samples from each rx_lts (we have sent two LTS)
rx_lts_nsc = [rx_lts(rx_lts_idx1,:); rx_lts(rx_lts_idx2,:)];
rx_lts_nsc = [rx_lts_mat(rx_lts_idx1,:); rx_lts_mat(rx_lts_idx2,:)];
for ibs = 1:N_BS_NODE
H_0_t(:,:,ibs) = reshape(rx_lts_nsc(:,ibs),[],N_LTS_SYM);
end
......@@ -272,25 +279,11 @@ H_0 = H_0_f./ repmat(lts_f.',1,N_LTS_SYM,N_BS_NODE);
rx_H_est_2d = squeeze(mean(H_0,2));
rx_H_est_2d(idx_0,:) = 0;
%rx_H_est_2d = [H_b1 H_b2];
%% Rx payload processing
% Extract the payload samples (integer number of OFDM symbols following preamble)
if( (length(rx_vec_iris) - payload_ind ) > (N_SYM_SAMP * N_OFDM_SYM) )
payload_vec = rx_vec_iris(payload_ind : payload_ind + (N_SYM_SAMP * N_OFDM_SYM), :);
else
payload_vec = rx_vec_iris(payload_ind : end,:);
end
missed_samps = (N_SC+CP_LEN) * N_OFDM_SYM - length(payload_vec); %sometimes it's below .
if (missed_samps > 0)
payload_vec = [payload_vec; zeros( missed_samps, N_BS_NODE)];
elseif (missed_samps < 0)
payload_vec = payload_vec(1:end+missed_samps, :);
end
%% Rx payload processing
payload_mat = reshape(payload_vec, (N_SC+CP_LEN), N_OFDM_SYM, N_BS_NODE);
payload_mat = reshape(payload_rx, (N_SC+CP_LEN), N_OFDM_SYM, N_BS_NODE);
% Remove the cyclic prefix, keeping FFT_OFFSET samples of CP (on average)
payload_mat_noCP = payload_mat(CP_LEN-FFT_OFFSET+(1:N_SC), :,:);
......@@ -445,29 +438,19 @@ end
% Rx signal (only two branches)
cf = cf + 1;
figure(cf);
subplot(2,2,1);
plot(real(rx_vec_iris(:,1)));
axis([0 length(rx_vec_iris) -TX_SCALE TX_SCALE])
grid on;
title('Rx Waveform (I) 1');
subplot(2,2,2);
plot(imag(rx_vec_iris(:,1)), 'color', sec_clr);
axis([0 length(rx_vec_iris) -TX_SCALE TX_SCALE])
grid on;
title('Rx Waveform (Q) 1');
subplot(2,2,3);
plot(real(rx_vec_iris(:,2)));
axis([0 length(rx_vec_iris) -TX_SCALE TX_SCALE])
grid on;
title('Rx Waveform (I) 2');
for sp = 1:N_BS_NODE
subplot(N_BS_NODE,2,2*(sp -1) + 1 );
plot(real(rx_vec_iris(:,sp)));
axis([0 length(rx_vec_iris(:,sp)) -TX_SCALE TX_SCALE])
grid on;
%title(sprintf('BS antenna %d Rx Waveform (I)', sp));
subplot(2,2,4);
plot(imag(rx_vec_iris(:,2)), 'color', sec_clr);
axis([0 length(rx_vec_iris) -TX_SCALE TX_SCALE])
grid on;
title('Rx Waveform (Q) 2');
subplot(N_BS_NODE,2,2*sp);
plot(imag(rx_vec_iris(:,sp)), 'color' , sec_clr);
axis([0 length(rx_vec_iris(:,sp)) -TX_SCALE TX_SCALE]);
grid on;
%title(sprintf('BS antenna %d Rx Waveform (Q)', sp));
end
if(WRITE_PNG_FILES)
print(gcf,sprintf('wl_ofdm_plots_%s_rxIQ', example_mode_string), '-dpng', '-r96', '-painters')
......@@ -480,7 +463,7 @@ lts_to_plot = lts_corr;
plot(lts_to_plot, '.-b', 'LineWidth', 1);
hold on;
grid on;
title('LTS Correlation and Threshold')
title('LTS Correlation');
xlabel('Sample Index')
myAxis = axis();
axis([1, 1000, myAxis(3), myAxis(4)])
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,4 +6,9 @@ This repository contains all software designs flow for RENEW:
├── Sounder: Framework for collecting channel traces with massive-MIMO
├── Beamfromer
This software depends on other github projects:
https://github.com/Themaister/muFFT
Use 'git submodule update --init --recursive' to fetch them before building everything.
See documentation at https://docs.renew-wireless.org