SRSUE: Added SCell synchronizer and measurements based on reference signals

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent 8e17aba5d8
commit 35f85c651c

@ -0,0 +1,58 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_REFSIGNAL_DL_SYNC_H_
#define SRSLTE_REFSIGNAL_DL_SYNC_H_
#include <srslte/phy/ch_estimation/refsignal_dl.h>
#include <srslte/phy/dft/ofdm.h>
#include <srslte/phy/utils/convolution.h>
typedef struct {
srslte_refsignal_t refsignal;
srslte_ofdm_t ifft;
cf_t* ifft_buffer_in;
cf_t* ifft_buffer_out;
cf_t* sequences[SRSLTE_NOF_SF_X_FRAME];
cf_t* correlation;
srslte_conv_fft_cc_t conv_fft_cc;
// Results
bool found;
float rsrp_dBfs;
float rssi_dBfs;
float rsrq_dB;
float cfo_Hz;
uint32_t peak_index;
} srslte_refsignal_dl_sync_t;
SRSLTE_API int srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q);
SRSLTE_API int srslte_refsignal_dl_sync_set_cell(srslte_refsignal_dl_sync_t* q, srslte_cell_t cell);
SRSLTE_API void srslte_refsignal_dl_sync_free(srslte_refsignal_dl_sync_t* q);
SRSLTE_API void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples);
SRSLTE_API void srslte_refsignal_dl_sync_measure_sf(
srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t sf_idx, float* rsrp, float* rssi, float* cfo);
#endif // SRSLTE_REFSIGNAL_DL_SYNC_H_

@ -114,12 +114,13 @@ extern "C" {
#include "srslte/phy/scrambling/scrambling.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/sync/cp.h"
#include "srslte/phy/sync/pss.h"
#include "srslte/phy/sync/refsignal_dl_sync.h"
#include "srslte/phy/sync/sfo.h"
#include "srslte/phy/sync/sss.h"
#include "srslte/phy/sync/sync.h"
#include "srslte/phy/sync/cfo.h"
#include "srslte/phy/sync/cp.h"
#ifdef __cplusplus
}

@ -0,0 +1,351 @@
/*
* Copyright 2013-2019 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <complex.h>
#include <math.h>
#include <memory.h>
#include <srslte/phy/sync/refsignal_dl_sync.h>
#include <srslte/phy/utils/vector.h>
#include <srslte/srslte.h>
int srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q) {
// Initialise internals
bzero(q, sizeof(srslte_refsignal_dl_sync_t));
// Initialise Reference signals
ret = srslte_refsignal_cs_init(&q->refsignal, SRSLTE_MAX_PRB);
// Allocate time buffers
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
q->sequences[i] = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
if (!q->sequences[i]) {
perror("Allocating sequence\n");
}
}
// Allocate Temporal OFDM buffer
q->ifft_buffer_in = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
if (!q->ifft_buffer_in) {
perror("Allocating ifft_buffer_in\n");
}
q->ifft_buffer_out = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
if (!q->ifft_buffer_out) {
perror("Allocating ifft_buffer_out\n");
}
// Allocate correlation
q->correlation = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX * 2);
if (!q->correlation) {
perror("Allocating correlation\n");
}
// Initiate OFDM modulator
if (!ret) {
ret = srslte_ofdm_tx_init(&q->ifft, SRSLTE_CP_NORM, q->ifft_buffer_in, q->ifft_buffer_out, SRSLTE_MAX_PRB);
}
// Set PRB
if (!ret) {
ret = srslte_ofdm_tx_set_prb(&q->ifft, SRSLTE_CP_NORM, SRSLTE_MAX_PRB);
}
// Initiate FFT Convolution
if (!ret) {
ret = srslte_conv_fft_cc_init(&q->conv_fft_cc, q->ifft.sf_sz, q->ifft.sf_sz);
}
}
return ret;
}
int srslte_refsignal_dl_sync_set_cell(srslte_refsignal_dl_sync_t* q, srslte_cell_t cell)
{
int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q) {
cf_t pss_signal[SRSLTE_PSS_LEN];
float sss_signal0[SRSLTE_SSS_LEN];
float sss_signal5[SRSLTE_SSS_LEN];
// Generate Synchronization signals
srslte_pss_generate(pss_signal, cell.id % 3);
srslte_sss_generate(sss_signal0, sss_signal5, cell.id);
// Set cell for Ref signals
ret = srslte_refsignal_cs_set_cell(&q->refsignal, cell);
// Resize OFDM
if (!ret && q->ifft.nof_re != cell.nof_prb * SRSLTE_NRE) {
ret = srslte_ofdm_tx_set_prb(&q->ifft, cell.cp, cell.nof_prb);
}
// Replan convolution
if (q->conv_fft_cc.filter_len != q->ifft.sf_sz) {
srslte_conv_fft_cc_replan(&q->conv_fft_cc, q->ifft.sf_sz, q->ifft.sf_sz);
}
// Generate frame with references
if (!ret) {
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME && ret == SRSLTE_SUCCESS; i++) {
uint32_t nof_re = 0;
// Default Subframe configuration
srslte_dl_sf_cfg_t dl_sf_cfg = {};
dl_sf_cfg.tti = i;
// Reset OFDM buffer
bzero(q->ifft_buffer_in, sizeof(cf_t) * q->ifft.sf_sz);
// Put Synchronization signals
if (i == 0 || i == 5) {
srslte_pss_put_slot(pss_signal, q->ifft_buffer_in, cell.nof_prb, cell.cp);
srslte_sss_put_slot(i ? sss_signal5 : sss_signal0, q->ifft_buffer_in, cell.nof_prb, cell.cp);
}
// Increase correlation for 2 port eNb
cell.nof_ports = 2;
// Put Reference signals
for (int p = 0; p < cell.nof_ports; p++) {
ret = srslte_refsignal_cs_put_sf(&q->refsignal, &dl_sf_cfg, p, q->ifft_buffer_in);
// Increment number of resource elements
if (p == 0) {
nof_re += srslte_refsignal_cs_nof_re(&q->refsignal, &dl_sf_cfg, p);
}
}
// Run OFDM modulator
srslte_ofdm_tx_sf(&q->ifft);
// Undo scaling and normalize overall power to 1
float scale = 1.0f / nof_re;
// Copy time domain signal, normalized by number of RE
srslte_vec_sc_prod_cfc(q->ifft_buffer_out, scale, q->sequences[i], q->ifft.sf_sz);
}
}
}
return ret;
}
void srslte_refsignal_dl_sync_free(srslte_refsignal_dl_sync_t* q)
{
if (q) {
srslte_refsignal_free(&q->refsignal);
srslte_ofdm_tx_free(&q->ifft);
if (q->ifft_buffer_in) {
free(q->ifft_buffer_in);
}
if (q->ifft_buffer_out) {
free(q->ifft_buffer_out);
}
if (q->correlation) {
free(q->correlation);
}
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) {
if (q->sequences[i]) {
free(q->sequences[i]);
}
}
}
}
int srslte_refsignal_dl_sync_find_peak(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples)
{
int ret = SRSLTE_ERROR;
float thr = 5.5f;
float peak_value = 0.0f;
int peak_idx = 0;
float rms_avg = 0;
uint32_t sf_len = q->ifft.sf_sz;
// Load correlation sequence and convert to frequency domain
cf_t* ptr_filt = q->conv_fft_cc.filter_fft;
memcpy(ptr_filt, q->sequences[0], sizeof(cf_t) * sf_len);
bzero(&ptr_filt[sf_len], sizeof(cf_t) * sf_len);
srslte_dft_run_c(&q->conv_fft_cc.filter_plan, ptr_filt, ptr_filt);
// Limit correlate for a frame or less
nsamples = SRSLTE_MIN(nsamples - sf_len, SRSLTE_NOF_SF_X_FRAME * sf_len);
// Correlation
for (int n = 0; n < nsamples; n += sf_len) {
// Set input data, two subframes
cf_t* ptr_in = &buffer[n];
// Correlate
srslte_corr_fft_cc_run_opt(&q->conv_fft_cc, ptr_in, ptr_filt, q->correlation);
// Find maximum, calculate RMS and peak
uint32_t imax = srslte_vec_max_abs_ci(q->correlation, sf_len);
float peak = cabsf(q->correlation[imax]);
float rms = sqrtf(srslte_vec_avg_power_cf(q->correlation, sf_len));
rms_avg += rms;
// Found bigger peak
if (peak > peak_value) {
peak_value = peak;
peak_idx = imax + n;
}
}
// Condition of peak detection
rms_avg /= floorf((float)nsamples / sf_len);
if (peak_value > rms_avg * thr) {
ret = peak_idx;
}
INFO("pci=%03d; sf_len=%d; imax=%d; peak=%.3f; rms=%.3f; peak/rms=%.3f\n",
q->refsignal.cell.id,
sf_len,
peak_idx,
peak_value,
rms_avg,
peak_value / rms_avg);
// Return the peak position if found, -1 otherwise
return ret;
}
void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples)
{
if (q) {
uint32_t sf_len = q->ifft.sf_sz;
uint32_t sf_count = 0;
float rsrp_lin = 0.0f;
float rssi_lin = 0.0f;
float cfo_acc = 0.0f;
// Stage 1: find peak
int peak_idx = srslte_refsignal_dl_sync_find_peak(q, buffer, nsamples);
// Stage 2: Proccess subframes
if (peak_idx >= 0) {
// Calculate initial subframe index and sample
uint32_t sf_idx_init = (2 * SRSLTE_NOF_SF_X_FRAME - peak_idx / sf_len) % SRSLTE_NOF_SF_X_FRAME;
uint32_t n_init = peak_idx % sf_len;
for (int sf_idx = sf_idx_init, n = n_init; n < (nsamples - sf_len + 1);
sf_idx = (sf_idx + 1) % SRSLTE_NOF_SF_X_FRAME, n += sf_len) {
cf_t* buf = &buffer[n];
// Measure subframe rsrp, rssi and accumulate
float rsrp, rssi, cfo;
srslte_refsignal_dl_sync_measure_sf(q, buf, sf_idx, &rsrp, &rssi, &cfo);
rsrp_lin += rsrp;
rssi_lin += rssi;
cfo_acc += cfo;
sf_count++;
}
// Average measurements
rsrp_lin /= sf_count;
rssi_lin /= sf_count;
cfo_acc /= sf_count;
// Calculate in dBm
q->rsrp_dBfs = 10.0f * log10f(rsrp_lin) + 30.0f;
// Calculate RSSI in dBm
q->rssi_dBfs = 10.0f * log10f(rssi_lin) + 30.0f;
// Calculate RSRQ
q->rsrq_dB = 10.0f * log10f(q->refsignal.cell.nof_prb) + q->rsrp_dBfs - q->rssi_dBfs;
q->found = true;
q->cfo_Hz = cfo_acc;
q->peak_index = peak_idx;
} else {
q->found = false;
q->rsrp_dBfs = NAN;
q->rssi_dBfs = NAN;
q->rsrq_dB = NAN;
q->cfo_Hz = NAN;
q->peak_index = UINT32_MAX;
}
}
}
void srslte_refsignal_dl_sync_measure_sf(
srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t sf_idx, float* rsrp, float* rssi, float* cfo)
{
float rsrp_lin = 0.0f;
float rssi_lin = 0.0f;
cf_t corr[4] = {};
srslte_dl_sf_cfg_t dl_sf_cfg = {};
dl_sf_cfg.tti = sf_idx;
if (q) {
cf_t* sf_sequence = q->sequences[sf_idx % SRSLTE_NOF_SF_X_FRAME];
uint32_t symbol_sz = q->ifft.symbol_sz;
uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(&q->refsignal, &dl_sf_cfg, 0);
uint32_t cp_len0 = SRSLTE_CP_LEN_NORM(0, symbol_sz);
uint32_t cp_len1 = SRSLTE_CP_LEN_NORM(1, symbol_sz);
for (uint32_t l = 0; l < nsymbols; l++) {
// Calculate FFT window offset for reference signals symbols
uint32_t symbidx = srslte_refsignal_cs_nsymbol(l, q->refsignal.cell.cp, 0);
uint32_t offset = cp_len0 + (symbol_sz + cp_len1) * symbidx;
if (l >= nsymbols / 2) {
offset += cp_len0 - cp_len1;
}
// Complex correlation
corr[l] = srslte_vec_dot_prod_conj_ccc(&buffer[offset], &sf_sequence[offset], symbol_sz);
// Calculate RSRP
rsrp_lin += __real__(corr[l] * conjf(corr[l]));
// Calculate RSSI
rssi_lin += srslte_vec_dot_prod_conj_ccc(&buffer[offset], &buffer[offset], symbol_sz);
}
// Return measurements
if (rsrp) {
*rsrp = rsrp_lin * nsymbols;
}
if (rssi) {
*rssi = (float)q->refsignal.cell.nof_prb * rssi_lin / (float)nsymbols * 7.41f;
}
if (cfo) {
*cfo = 0;
*cfo += cargf(corr[2] * conjf(corr[0])) / (2.0f * M_PI * 7.5f) * 15000.0f;
*cfo += cargf(corr[3] * conjf(corr[1])) / (2.0f * M_PI * 7.5f) * 15000.0f;
*cfo /= 2;
}
}
}

@ -71,6 +71,8 @@ private:
uint32_t measure_tti;
uint32_t receive_cnt;
srslte_ringbuffer_t ring_buffer;
srslte_refsignal_dl_sync_t refsignal_dl_sync;
};
} // namespace scell

@ -72,6 +72,9 @@ void intra_measure::init(phy_common* common, rrc_interface_phy_lte* rrc, srslte:
this->common = common;
receive_enabled = false;
// Initialise Reference signal measurement
srslte_refsignal_dl_sync_init(&refsignal_dl_sync);
// Start scell
scell.init(log_h, common->args->sic_pss_enabled, common->args->intra_freq_meas_len_ms, common);
@ -93,6 +96,7 @@ void intra_measure::stop()
srslte_ringbuffer_stop(&ring_buffer);
tti_sync.increase();
wait_thread_finish();
srslte_refsignal_dl_sync_free(&refsignal_dl_sync);
}
void intra_measure::set_primay_cell(uint32_t earfcn, srslte_cell_t cell)
@ -187,10 +191,71 @@ void intra_measure::run_thread()
search_buffer, common->rx_gain_offset, primary_cell, common->args->intra_freq_meas_len_ms, info);
receiving = false;
// Look for other cells not found automatically
// Using Cell Reference signal synchronization for all known active PCI
for (auto q : active_pci) {
srslte_cell_t cell = primary_cell;
cell.id = q;
srslte_refsignal_dl_sync_set_cell(&refsignal_dl_sync, cell);
srslte_refsignal_dl_sync_run(
&refsignal_dl_sync, search_buffer, common->args->intra_freq_meas_len_ms * current_sflen);
if (refsignal_dl_sync.found) {
Info("INTRA: Found neighbour cell: PCI=%03d, RSRP=%5.1f dBm, RSRQ=%5.1f, peak_idx=%5d, CFO=%+.1fHz\n",
cell.id,
refsignal_dl_sync.rsrp_dBfs,
refsignal_dl_sync.rsrq_dB,
refsignal_dl_sync.peak_index,
refsignal_dl_sync.cfo_Hz);
bool found = false;
float weakest_rsrp_value = +INFINITY;
uint32_t weakest_rsrp_index = 0;
// Try to find PCI in info list
for (int i = 0; i < found_cells && !found; i++) {
// Finds cell, update
if (info[i].pci == cell.id) {
info[i].rsrp = refsignal_dl_sync.rsrp_dBfs;
info[i].rsrq = refsignal_dl_sync.rsrq_dB;
info[i].offset = refsignal_dl_sync.peak_index;
found = true;
} else if (weakest_rsrp_value > info[i].rsrp) {
// Update weakest
weakest_rsrp_value = info[i].rsrp;
weakest_rsrp_index = i;
}
}
if (!found) {
// If number of cells exceeds
if (found_cells >= scell_recv::MAX_CELLS) {
// overwrite weakest cell if stronger
if (refsignal_dl_sync.rsrp_dBfs > weakest_rsrp_value) {
info[weakest_rsrp_index].pci = cell.id;
info[weakest_rsrp_index].rsrp = refsignal_dl_sync.rsrp_dBfs;
info[weakest_rsrp_index].rsrq = refsignal_dl_sync.rsrq_dB;
info[weakest_rsrp_index].offset = refsignal_dl_sync.peak_index;
} else {
// Ignore measurement
}
} else {
// Otherwise append cell
info[found_cells].pci = cell.id;
info[found_cells].rsrp = refsignal_dl_sync.rsrp_dBfs;
info[found_cells].rsrq = refsignal_dl_sync.rsrq_dB;
info[found_cells].offset = refsignal_dl_sync.peak_index;
found_cells++;
}
}
}
}
// Send measurements to RRC
for (int i = 0; i < found_cells; i++) {
rrc->new_phy_meas(info[i].rsrp, info[i].rsrq, measure_tti, current_earfcn, info[i].pci);
}
// Look for other cells not found automatically
}
}
}

@ -32,8 +32,15 @@ link_directories(
add_executable(scell_search_test scell_search_test.cc)
target_link_libraries(scell_search_test
srsue_phy
srsue_stack
srsue_upper
srsue_mac
srsue_rrc
srslte_common
srslte_phy
srslte_radio
srslte_upper
rrc_asn1
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES})
add_test(scell_search_test scell_search_test)

@ -21,6 +21,7 @@
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <c++/7/bits/basic_string.h>
#include <iostream>
#include <map>
#include <memory>
@ -31,16 +32,18 @@
#include <vector>
// Common execution parameters
static uint32_t duration_execution_s;
static srslte_cell_t cell_base = {.nof_prb = 6,
static uint32_t duration_execution_s;
static srslte_cell_t cell_base = {.nof_prb = 6,
.nof_ports = 1,
.id = 0,
.cp = SRSLTE_CP_NORM,
.phich_length = SRSLTE_PHICH_NORM,
.phich_resources = SRSLTE_PHICH_R_1_6,
.frame_type = SRSLTE_FDD};
static std::string intra_meas_log_level;
static int phy_lib_log_level;
static std::string intra_meas_log_level;
static std::string cell_list;
static int phy_lib_log_level;
static srsue::phy_args_t phy_args;
// On the Fly parameters
static int earfcn_dl;
@ -141,7 +144,7 @@ public:
const srslte_timestamp_t& ts)
{
int ret = SRSLTE_ERROR;
int ret = SRSLTE_SUCCESS;
uint32_t sf_len = SRSLTE_SF_LEN_PRB(enb_dl.cell.nof_prb);
srslte_enb_dl_put_base(&enb_dl, dl_sf);
@ -150,14 +153,14 @@ public:
if (dci && dci_cfg && softbuffer_tx && data_tx) {
if (srslte_enb_dl_put_pdcch_dl(&enb_dl, dci_cfg, dci)) {
ERROR("Error putting PDCCH sf_idx=%d\n", dl_sf->tti);
goto quit;
ret = SRSLTE_ERROR;
}
// Create pdsch config
srslte_pdsch_cfg_t pdsch_cfg;
if (srslte_ra_dl_dci_to_grant(&enb_dl.cell, dl_sf, serving_cell_pdsch_tm, false, dci, &pdsch_cfg.grant)) {
ERROR("Computing DL grant sf_idx=%d\n", dl_sf->tti);
goto quit;
ret = SRSLTE_ERROR;
}
char str[512];
srslte_dci_dl_info(dci, str, 512);
@ -176,7 +179,7 @@ public:
if (srslte_enb_dl_put_pdsch(&enb_dl, &pdsch_cfg, data_tx) < 0) {
ERROR("Error putting PDSCH sf_idx=%d\n", dl_sf->tti);
goto quit;
ret = SRSLTE_ERROR;
}
srslte_pdsch_tx_info(&pdsch_cfg, str, 512);
INFO("eNb PDSCH: rnti=0x%x, %s\n", serving_cell_pdsch_rnti, str);
@ -187,22 +190,26 @@ public:
// Apply channel
channel->run(signal_buffer, signal_buffer, sf_len, ts);
// Add to baseband
// Combine Tx ports
for (uint32_t i = 1; i < enb_dl.cell.nof_ports; i++) {
srslte_vec_sum_ccc(signal_buffer[0], signal_buffer[i], signal_buffer[0], sf_len);
}
if (enb_dl.cell.id != cell_base.id) {
srslte_vec_sc_prod_cfc(
signal_buffer[0],
powf(10.0f, (-ncell_attenuation_dB + (enb_dl.cell.id == cell_id_start + cell_id_step ? 3 : 0)) / 20.0f),
signal_buffer[0],
sf_len);
// Undo srslte_enb_dl_gen_signal scaling
float scale = sqrt(cell_base.nof_prb) / 0.05f / enb_dl.ifft->symbol_sz;
// Apply Neighbour cell attenuation
if (enb_dl.cell.id != cell_id_start) {
float scale_dB = -ncell_attenuation_dB;
scale *= powf(10.0f, scale_dB / 20.0f);
}
srslte_vec_sum_ccc(signal_buffer[0], baseband_buffer, baseband_buffer, sf_len);
ret = SRSLTE_SUCCESS;
// Scale signal
srslte_vec_sc_prod_cfc(signal_buffer[0], scale, signal_buffer[0], sf_len);
// Add signal to baseband buffer
srslte_vec_sum_ccc(signal_buffer[0], baseband_buffer, baseband_buffer, sf_len);
quit:
return ret;
}
@ -223,8 +230,12 @@ class dummy_rrc : public srsue::rrc_interface_phy_lte
{
public:
typedef struct {
float rsrp;
float rsrq;
float rsrp_avg;
float rsrp_min;
float rsrp_max;
float rsrq_avg;
float rsrq_min;
float rsrq_max;
uint32_t count;
} cell_meas_t;
@ -235,12 +246,21 @@ public:
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci) override
{
if (!cells.count(pci)) {
cells[pci].rsrp = rsrp;
cells[pci].rsrq = rsrq;
cells[pci].rsrp_min = rsrp;
cells[pci].rsrp_max = rsrp;
cells[pci].rsrp_avg = rsrp;
cells[pci].rsrq_min = rsrq;
cells[pci].rsrq_max = rsrq;
cells[pci].rsrq_avg = rsrq;
cells[pci].count = 1;
} else {
cells[pci].rsrp = (rsrp + cells[pci].rsrp * cells[pci].count) / (cells[pci].count + 1);
cells[pci].rsrq = (rsrq + cells[pci].rsrq * cells[pci].count) / (cells[pci].count + 1);
cells[pci].rsrp_min = SRSLTE_MIN(cells[pci].rsrp_min, rsrp);
cells[pci].rsrp_max = SRSLTE_MAX(cells[pci].rsrp_max, rsrp);
cells[pci].rsrp_avg = (rsrp + cells[pci].rsrp_avg * cells[pci].count) / (cells[pci].count + 1);
cells[pci].rsrq_min = SRSLTE_MIN(cells[pci].rsrq_min, rsrq);
cells[pci].rsrq_max = SRSLTE_MAX(cells[pci].rsrq_max, rsrq);
cells[pci].rsrq_avg = (rsrq + cells[pci].rsrq_avg * cells[pci].count) / (cells[pci].count + 1);
cells[pci].count++;
}
}
@ -257,11 +277,16 @@ public:
}
}
printf(" pci=%03d; count=%3d; false=%s; rsrp=%+.1f\n",
printf(" pci=%03d; count=%3d; false=%s; rsrp=%+.1f|%+.1f|%+.1fdBfs; rsrq=%+.1f|%+.1f|%+.1fdB;\n",
e.first,
e.second.count,
false_alarm ? "y" : "n",
e.second.rsrp);
e.second.rsrp_min,
e.second.rsrp_avg,
e.second.rsrp_max,
e.second.rsrq_min,
e.second.rsrq_avg,
e.second.rsrq_max);
}
}
};
@ -280,39 +305,44 @@ int parse_args(int argc, char** argv)
// clang-format off
common.add_options()
("duration", bpo::value<uint32_t >(&duration_execution_s)->default_value(300), "Duration of the execution in seconds")
("cell.nof_prb", bpo::value<uint32_t >(&cell_base.nof_prb)->default_value(6), "Cell Number of PRB")
("intra_meas_log_level", bpo::value<std::string>(&intra_meas_log_level)->default_value("none"), "Intra measurement log level (none, warning, info, debug)")
("phy_lib_log_level", bpo::value<int>(&phy_lib_log_level)->default_value(SRSLTE_VERBOSE_NONE), "Phy lib log level (0: none, 1: info, 2: debug)")
("duration", bpo::value<uint32_t>(&duration_execution_s)->default_value(60), "Duration of the execution in seconds")
("cell.nof_prb", bpo::value<uint32_t>(&cell_base.nof_prb)->default_value(100), "Cell Number of PRB")
("intra_meas_log_level", bpo::value<std::string>(&intra_meas_log_level)->default_value("none"), "Intra measurement log level (none, warning, info, debug)")
("intra_freq_meas_len_ms", bpo::value<uint32_t>(&phy_args.intra_freq_meas_len_ms)->default_value(20), "Intra measurement measurement length")
("intra_freq_meas_period_ms", bpo::value<uint32_t>(&phy_args.intra_freq_meas_period_ms)->default_value(200), "Intra measurement measurement period")
("phy_lib_log_level", bpo::value<int>(&phy_lib_log_level)->default_value(SRSLTE_VERBOSE_NONE), "Phy lib log level (0: none, 1: info, 2: debug)")
("cell_list", bpo::value<std::string>(&cell_list)->default_value("10,17,24,31,38,45,52"), "Comma separated neighbour PCI cell list")
;
over_the_air.add_options()
("rf.dl_earfcn", bpo::value<int>(&earfcn_dl)->default_value(-1), "DL EARFCN (setting this param enables over-the-air execution)")
("rf.device_name", bpo::value<std::string>(&radio_device_name)->default_value("auto"), "RF Device Name")
("rf.device_args", bpo::value<std::string>(&radio_device_args)->default_value("auto"), "RF Device arguments")
("rf.log_level", bpo::value<std::string>(&radio_log_level)->default_value("info"), "RF Log level (none, warning, info, debug)")
("rf.rx_gain", bpo::value<float>(&rx_gain)->default_value(30.0f), "RF Receiver gain in dB")
("radio_log_level", bpo::value<std::string>(&radio_log_level)->default_value("info"), "RF Log level")
("rf.dl_earfcn", bpo::value<int>(&earfcn_dl)->default_value(-1), "DL EARFCN (setting this param enables over-the-air execution)")
("rf.device_name", bpo::value<std::string>(&radio_device_name)->default_value("auto"), "RF Device Name")
("rf.device_args", bpo::value<std::string>(&radio_device_args)->default_value("auto"), "RF Device arguments")
("rf.log_level", bpo::value<std::string>(&radio_log_level)->default_value("info"), "RF Log level (none, warning, info, debug)")
("rf.rx_gain", bpo::value<float>(&rx_gain)->default_value(30.0f), "RF Receiver gain in dB")
("radio_log_level", bpo::value<std::string>(&radio_log_level)->default_value("info"), "RF Log level")
;
simulation.add_options()
("nof_enb", bpo::value<uint32_t >(&nof_enb)->default_value(3), "Number of eNb")
("cell_id_start", bpo::value<uint16_t>(&cell_id_start)->default_value(10), "Cell id start")
("cell_id_step", bpo::value<uint16_t>(&cell_id_step)->default_value(7), "Cell id step")
("cell_cfi", bpo::value<uint32_t >(&cfi)->default_value(1), "Cell CFI")
("channel_period_s", bpo::value<float>(&channel_period_s)->default_value(16.8), "Channel period for HST and delay")
("ncell_attenuation", bpo::value<float>(&ncell_attenuation_dB)->default_value(3.0f), "Neighbour cell attenuation relative to serving cell in dB")
("channel.hst.fd", bpo::value<float>(&channel_hst_fd_hz)->default_value(750.0f), "Channel High Speed Train doppler in Hz. Set to 0 for disabling")
("channel.delay_max", bpo::value<float>(&channel_delay_max_us)->default_value(4.7f), "Maximum simulated delay in microseconds. Set to 0 for disabling")
("channel.log_level", bpo::value<std::string>(&channel_log_level)->default_value("info"), "Channel simulator logging level")
("serving_cell_pdsch_enable", bpo::value<bool>(&serving_cell_pdsch_enable)->default_value(true), "Enable simulated PDSCH in serving cell")
("serving_cell_pdsch_rnti", bpo::value<uint16_t >(&serving_cell_pdsch_rnti)->default_value(0x1234), "Simulated PDSCH RNTI")
("serving_cell_pdsch_tm", bpo::value<int>((int*) &serving_cell_pdsch_tm)->default_value(SRSLTE_TM1), "Simulated Transmission mode 0: TM1, 1: TM2, 2: TM3, 3: TM4")
("serving_cell_pdsch_mcs", bpo::value<uint16_t >(&serving_cell_pdsch_mcs)->default_value(20), "Simulated PDSCH MCS")
("nof_enb", bpo::value<uint32_t >(&nof_enb)->default_value(4), "Number of eNb")
("cell_id_start", bpo::value<uint16_t>(&cell_id_start)->default_value(10), "Cell id start")
("cell_id_step", bpo::value<uint16_t>(&cell_id_step)->default_value(7), "Cell id step")
("cell_cfi", bpo::value<uint32_t >(&cfi)->default_value(1), "Cell CFI")
("channel_period_s", bpo::value<float>(&channel_period_s)->default_value(16.8), "Channel period for HST and delay")
("ncell_attenuation", bpo::value<float>(&ncell_attenuation_dB)->default_value(3.0f), "Neighbour cell attenuation relative to serving cell in dB")
("channel.hst.fd", bpo::value<float>(&channel_hst_fd_hz)->default_value(750.0f), "Channel High Speed Train doppler in Hz. Set to 0 for disabling")
("channel.delay_max", bpo::value<float>(&channel_delay_max_us)->default_value(4.7f), "Maximum simulated delay in microseconds. Set to 0 for disabling")
("channel.log_level", bpo::value<std::string>(&channel_log_level)->default_value("info"), "Channel simulator logging level")
("serving_cell_pdsch_enable", bpo::value<bool>(&serving_cell_pdsch_enable)->default_value(true), "Enable simulated PDSCH in serving cell")
("serving_cell_pdsch_rnti", bpo::value<uint16_t >(&serving_cell_pdsch_rnti)->default_value(0x1234), "Simulated PDSCH RNTI")
("serving_cell_pdsch_tm", bpo::value<int>((int*) &serving_cell_pdsch_tm)->default_value(SRSLTE_TM1), "Simulated Transmission mode 0: TM1, 1: TM2, 2: TM3, 3: TM4")
("serving_cell_pdsch_mcs", bpo::value<uint16_t >(&serving_cell_pdsch_mcs)->default_value(20), "Simulated PDSCH MCS")
;
// clang-format on
options.add(common).add(over_the_air).add(simulation).add_options()("help", "Show this message");
options.add(common).add(over_the_air).add(simulation).add_options()
("help", "Show this message")
;
// clang-format on
bpo::variables_map vm;
try {
@ -340,6 +370,8 @@ int main(int argc, char** argv)
return SRSLTE_ERROR;
}
srslte_dft_load();
// Common for simulation and over-the-air
auto baseband_buffer = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
srslte_timestamp_t ts = {};
@ -347,7 +379,6 @@ int main(int argc, char** argv)
srslte::log_filter logger("intra_measure");
dummy_rrc rrc;
srsue::phy_common common(1);
srsue::phy_args_t phy_args;
// Simulation only
std::vector<std::unique_ptr<test_enb> > test_enb_v;
@ -364,8 +395,6 @@ int main(int argc, char** argv)
phy_args.estimator_fil_order = 4;
phy_args.estimator_fil_stddev = 1.0f;
phy_args.sic_pss_enabled = false;
phy_args.intra_freq_meas_len_ms = 20;
phy_args.intra_freq_meas_period_ms = 200;
phy_args.interpolate_subframe_enabled = false;
phy_args.nof_rx_ant = 1;
phy_args.cfo_is_doppler = true;
@ -418,7 +447,6 @@ int main(int argc, char** argv)
intra_measure.init(&common, &rrc, &logger);
intra_measure.set_primay_cell(serving_cell_id, cell_base);
intra_measure.add_cell(serving_cell_id);
if (earfcn_dl >= 0) {
// Create radio log
@ -457,10 +485,40 @@ int main(int argc, char** argv)
channel_args.delay_period_s = (uint32)channel_period_s;
channel_args.delay_init_time_s = (enb_idx * channel_period_s) / nof_enb;
test_enb_v.push_back(std::unique_ptr<test_enb>(new test_enb(cell, channel_args)));
// Add cell to known cells
if (cell_list.empty()) {
intra_measure.add_cell(cell.id);
}
}
}
// Parse cell list
if (cell_list == "all") {
// Add all possible cells
for (int i = 0; i < 504; i++) {
intra_measure.add_cell(i);
}
} else if (cell_list == "none") {
// Do nothing
} else if (!cell_list.empty()) {
// Remove spaces from neightbour cell list
std::size_t p1 = cell_list.find(' ');
while (p1 != std::string::npos) {
cell_list.erase(p1);
p1 = cell_list.find(' ');
}
// Add cell to known cells
std::stringstream ss(cell_list);
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
intra_measure.add_cell((uint32_t)strtoul(substr.c_str(), nullptr, 10));
}
}
// Run Programm
// Run loop
for (uint32_t sf_idx = 0; sf_idx < duration_execution_s * 1000; sf_idx++) {
srslte_dl_sf_cfg_t sf_cfg_dl = {};
sf_cfg_dl.tti = sf_idx % 10240;
@ -553,7 +611,7 @@ int main(int argc, char** argv)
srslte_timestamp_add(&ts, 0, 0.001f);
intra_measure.write(sf_idx % 10240, baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb));
intra_measure.write(sf_idx, baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb));
if (sf_idx % 1000 == 0) {
printf("Done %.1f%%\n", (double)sf_idx * 100.0 / ((double)duration_execution_s * 1000.0));
}
@ -566,4 +624,5 @@ int main(int argc, char** argv)
if (baseband_buffer) {
free(baseband_buffer);
}
srslte_dft_exit();
}
Loading…
Cancel
Save