SRSUE: neighbour cell measurement test defined

This commit is contained in:
Xavier Arteaga 2020-01-22 16:07:14 +01:00 committed by Xavier Arteaga
parent 385102fa2d
commit 8f6dd184be
2 changed files with 374 additions and 113 deletions

View File

@ -26,38 +26,154 @@
#include <srslte/phy/utils/vector.h>
#include <srslte/srslte.h>
/*
* Constants
* --------------
* These constants have been optimized for passing scell_search_test for a number of scenarios.
* - 6 PRB. 6 cells distributed uniformly 10ms delay
* srsue/test/phy/scell_search_test --duration=5 --cell.nof_prb=6 --active_cell_list=all
* --simulation_cell_list=1,2,3,4,5,6 --channel_period_s=30 --channel.hst.fd=750 --channel.delay_max=1000
*
* - 6 PRB. 6 cells distributed uniformly 10ms delay
* srsue/test/phy/scell_search_test --duration=30 --cell.nof_prb=6 --active_cell_list=2,3,4,5,6
* --simulation_cell_list=1,2,3,4,5,6 --channel_period_s=30 --channel.hst.fd=750 --channel.delay_max=10000
*
* - 6 PRB. 6 cell PSS, SSS overlapped:
* srsue/test/phy/scell_search_test --duration=30 --cell.nof_prb=6 --active_cell_list=all
* --simulation_cell_list=1,2,3,4,5,6 --channel_period_s=30 --channel.hst.fd=750 --channel.delay_max=0
*
* - 100 PRB, 6 cell, distributed around 1ms
* srsue/test/phy/scell_search_test --duration=30 --cell.nof_prb=100 --active_cell_list=2,3,4,5,6
* --simulation_cell_list=1,2,3,4,5,6 --channel_period_s=30 --channel.hst.fd=750 --channel.delay_max=1000
*/
#define REFSIGNAL_DL_SYNC_CORRELATION_THR (4.0f) /* Correlation threashold normalised in Peak / RMS */
#define REFSIGNAL_DL_CFO_MIN_MAX_MILD (1000.0f) /* Maximum difference between sub-frame CFO estimation in Hz */
#define REFSIGNAL_DL_CFO_MIN_MAX_SEVERE (2000.0f)
#define REFSIGNAL_DL_RSRP_MIN_MAX_MILD (6.0f) /* Maximum difference between sub-frame RSRP estimation in dB */
#define REFSIGNAL_DL_RSRP_MIN_MAX_SEVERE (10.0f)
#define REFSIGNAL_DL_RSRP_FALSE_RATIO_MILD (4.0f) /* Minimum RSRP ratio between real and false in dB */
#define REFSIGNAL_DL_RSRP_FALSE_RATIO_SEVERE (3.0f)
#define REFSIGNAL_DL_SSS_FALSE_RATIO_MILD (15.0f) /* Minimum SSS strength between real and false (linear) */
#define REFSIGNAL_DL_SSS_FALSE_RATIO_SEVERE (1.5f)
#define REFSIGNAL_DL_MAX_FAULT_CHECK (1) /* Number of mild faults without declaring false */
#define REFSIGNAL_DL_CFO_LOW_WEIGHT (0.5f) /* Weight for low CFO estimation (2 kHz) */
#define REFSIGNAL_DL_CFO_MEDIUM_WEIGHT (0.3f) /* Weight for medium CFO estimation (3.5 kHz) */
#define REFSIGNAL_DL_CFO_HIGH_WEIGHT (0.2f) /* Weight for high CFO estimation (4.66 kHz) */
/*
* Local Helpers
*/
static inline void refsignal_set_results_not_found(srslte_refsignal_dl_sync_t* q)
{
q->found = false;
q->rsrp_dBfs = NAN;
q->rssi_dBfs = NAN;
q->rsrq_dB = NAN;
q->cfo_Hz = NAN;
q->peak_index = UINT32_MAX;
}
static inline void refsignal_sf_prepare_correlation(srslte_refsignal_dl_sync_t* q)
{
uint32_t sf_len = q->ifft.sf_sz;
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);
}
static inline void
refsignal_sf_correlate(srslte_refsignal_dl_sync_t* q, cf_t* ptr_in, float* peak_value, uint32_t* peak_idx, float* rms)
{
// Correlate
srslte_corr_fft_cc_run_opt(&q->conv_fft_cc, ptr_in, q->conv_fft_cc.filter_fft, q->correlation);
// Find maximum, calculate RMS and peak
uint32_t imax = srslte_vec_max_abs_ci(q->correlation, q->ifft.sf_sz);
if (peak_idx) {
*peak_idx = imax;
}
if (peak_value) {
*peak_value = cabsf(q->correlation[imax]);
}
if (rms) {
*rms = sqrtf(srslte_vec_avg_power_cf(q->correlation, q->ifft.sf_sz));
}
}
static inline void refsignal_dl_pss_sss_strength(srslte_refsignal_dl_sync_t* q,
cf_t* buffer,
uint32_t sf_idx,
float* pss_strength,
float* sss_strength,
float* sss_strength_false)
{
uint32_t symbol_sz = q->ifft.symbol_sz;
uint32_t cp_len0 = SRSLTE_CP_LEN_NORM(0, symbol_sz);
uint32_t cp_len1 = SRSLTE_CP_LEN_NORM(1, symbol_sz);
uint32_t pss_n = cp_len0 + cp_len1 * 6 + symbol_sz * 6;
uint32_t sss_n = cp_len0 + cp_len1 * 5 + symbol_sz * 5;
sf_idx %= SRSLTE_NOF_SF_X_FRAME;
srslte_dl_sf_cfg_t dl_sf_cfg = {};
dl_sf_cfg.tti = sf_idx;
float k = (float)(srslte_refsignal_cs_nof_re(&q->refsignal, &dl_sf_cfg, 0)) / (float)SRSLTE_PSS_LEN;
if (pss_strength) {
cf_t corr = srslte_vec_dot_prod_conj_ccc(&buffer[pss_n], &q->sequences[sf_idx][pss_n], symbol_sz);
*pss_strength = k * __real__(corr * conjf(corr));
}
if (sss_strength) {
cf_t corr = srslte_vec_dot_prod_conj_ccc(&buffer[sss_n], &q->sequences[sf_idx][sss_n], symbol_sz);
*sss_strength = k * __real__(corr * conjf(corr));
}
if (sss_strength_false) {
uint32_t sf_idx2 = (sf_idx + SRSLTE_NOF_SF_X_FRAME / 2) % SRSLTE_NOF_SF_X_FRAME;
cf_t corr = srslte_vec_dot_prod_conj_ccc(&buffer[sss_n], &q->sequences[sf_idx2][sss_n], symbol_sz);
*sss_strength_false = k * __real__(corr * conjf(corr));
}
}
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));
memset(q, 0, 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);
q->sequences[i] = srslte_vec_cf_malloc(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);
q->ifft_buffer_in = srslte_vec_cf_malloc(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);
q->ifft_buffer_out = srslte_vec_cf_malloc(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);
q->correlation = srslte_vec_cf_malloc(SRSLTE_SF_LEN_MAX * 2);
if (!q->correlation) {
perror("Allocating correlation\n");
}
@ -76,6 +192,9 @@ int srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q)
if (!ret) {
ret = srslte_conv_fft_cc_init(&q->conv_fft_cc, q->ifft.sf_sz, q->ifft.sf_sz);
}
// Set default results to not found
refsignal_set_results_not_found(q);
}
return ret;
@ -125,9 +244,6 @@ int srslte_refsignal_dl_sync_set_cell(srslte_refsignal_dl_sync_t* q, srslte_cell
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);
@ -185,33 +301,25 @@ void srslte_refsignal_dl_sync_free(srslte_refsignal_dl_sync_t* q)
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);
refsignal_sf_prepare_correlation(q);
// 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, find maximum, calculate RMS and peak
uint32_t imax = 0;
float peak = 0.0f;
float rms = 0.0f;
refsignal_sf_correlate(q, &buffer[n], &peak, &imax, &rms);
// 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
@ -223,10 +331,27 @@ int srslte_refsignal_dl_sync_find_peak(srslte_refsignal_dl_sync_t* q, cf_t* buff
// Condition of peak detection
rms_avg /= floorf((float)nsamples / sf_len);
if (peak_value > rms_avg * thr) {
if (peak_value > rms_avg * REFSIGNAL_DL_SYNC_CORRELATION_THR) {
ret = peak_idx;
}
// Double check sub-frame selection failure due to high PSS
if (ret > 0) {
float sss_strength = 0.0f;
float sss_strength_false = 0.0f;
refsignal_dl_pss_sss_strength(q, &buffer[peak_idx], 0, NULL, &sss_strength, &sss_strength_false);
float rsrp_lin = 0.0f;
float rsrp_lin_false = 0.0f;
srslte_refsignal_dl_sync_measure_sf(q, &buffer[peak_idx], 0, &rsrp_lin, NULL, NULL);
srslte_refsignal_dl_sync_measure_sf(q, &buffer[peak_idx], 5, &rsrp_lin_false, NULL, NULL);
// Change base sub-frame
if (sss_strength_false > sss_strength && rsrp_lin_false > rsrp_lin) {
ret += (q->ifft.sf_sz * SRSLTE_NOF_SF_X_FRAME) / 2;
}
}
INFO("pci=%03d; sf_len=%d; imax=%d; peak=%.3f; rms=%.3f; peak/rms=%.3f\n",
q->refsignal.cell.id,
sf_len,
@ -242,11 +367,19 @@ int srslte_refsignal_dl_sync_find_peak(srslte_refsignal_dl_sync_t* q, cf_t* buff
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;
uint32_t sf_len = q->ifft.sf_sz;
uint32_t sf_count = 0;
float rsrp_lin = 0.0f;
float rsrp_lin_min = +INFINITY;
float rsrp_lin_max = -INFINITY;
float rssi_lin = 0.0f;
float cfo_acc = 0.0f;
float cfo_min = +INFINITY;
float cfo_max = -INFINITY;
float sss_strength_avg = 0.0f;
float sss_strength_false_avg = 0.0f;
float rsrp_false_avg = 0.0f;
bool false_alarm = false;
// Stage 1: find peak
int peak_idx = srslte_refsignal_dl_sync_find_peak(q, buffer, nsamples);
@ -264,9 +397,33 @@ void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, u
// Measure subframe rsrp, rssi and accumulate
float rsrp = 0.0f, rssi = 0.0f, cfo = 0.0f;
srslte_refsignal_dl_sync_measure_sf(q, buf, sf_idx, &rsrp, &rssi, &cfo);
// Update measurements
rsrp_lin += rsrp;
rsrp_lin_min = SRSLTE_MIN(rsrp_lin_min, rsrp);
rsrp_lin_max = SRSLTE_MAX(rsrp_lin_max, rsrp);
rssi_lin += rssi;
cfo_acc += cfo;
cfo_min = SRSLTE_MIN(cfo_min, cfo);
cfo_max = SRSLTE_MAX(cfo_max, cfo);
// Compute PSS/SSS strength
if (sf_idx % (SRSLTE_NOF_SF_X_FRAME / 2) == 0) {
float sss_strength = 0.0f;
float sss_strength_false = 0.0f;
refsignal_dl_pss_sss_strength(q, buf, sf_idx, NULL, &sss_strength, &sss_strength_false);
float rsrp_false = 0.0f;
srslte_refsignal_dl_sync_measure_sf(q, buf, sf_idx + 1, &rsrp_false, NULL, NULL);
sss_strength_avg += sss_strength;
sss_strength_false_avg += sss_strength_false;
rsrp_false_avg += rsrp_false;
}
// Increment counter
sf_count++;
}
@ -275,27 +432,82 @@ void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, u
rsrp_lin /= sf_count;
rssi_lin /= sf_count;
cfo_acc /= sf_count;
sss_strength_avg /= (2.0f * sf_count / SRSLTE_NOF_SF_X_FRAME);
sss_strength_false_avg /= (2.0f * sf_count / SRSLTE_NOF_SF_X_FRAME);
rsrp_false_avg /= (2.0f * sf_count / SRSLTE_NOF_SF_X_FRAME);
}
// Calculate in dBm
q->rsrp_dBfs = srslte_convert_power_to_dBm(rsrp_lin);
// RSRP conversion to dB
float rsrp_dB_min = srslte_convert_power_to_dBm(rsrp_lin_min);
float rsrp_dB_max = srslte_convert_power_to_dBm(rsrp_lin_max);
float rsrp_dB = srslte_convert_power_to_dBm(rsrp_lin);
float rsrp_false_dB = srslte_convert_power_to_dBm(rsrp_false_avg);
// Calculate RSSI in dBm
q->rssi_dBfs = srslte_convert_power_to_dBm(rssi_lin);
// Stage 3: Final false alarm decision
uint32_t false_count = 0;
if (sss_strength_avg < sss_strength_false_avg * REFSIGNAL_DL_SSS_FALSE_RATIO_SEVERE) {
false_alarm = true;
} else if (sss_strength_avg < sss_strength_false_avg * REFSIGNAL_DL_SSS_FALSE_RATIO_MILD) {
false_count++;
}
// Calculate RSRQ
q->rsrq_dB = srslte_convert_power_to_dB(q->refsignal.cell.nof_prb) + q->rsrp_dBfs - q->rssi_dBfs;
if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_SEVERE) {
false_alarm = true;
} else if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_MILD) {
false_count++;
}
q->found = true;
q->cfo_Hz = cfo_acc;
q->peak_index = peak_idx;
if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_SEVERE) {
false_alarm = true;
} else if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_MILD) {
false_count++;
}
if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_SEVERE) {
false_alarm = true;
} else if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_MILD) {
false_count++;
}
// Allow only one check fail
if (false_count > REFSIGNAL_DL_MAX_FAULT_CHECK) {
false_alarm = true;
}
INFO("-- pci=%03d; rsrp_dB=(%+.1f|%+.1f|%+.1f); rsrp_max-min=%.1f; rsrp_false_ratio=%.1f; "
"cfo=(%.1f|%.1f|%.1f); cfo_max-min=%.1f; sss_ratio=%f; false_count=%d;\n",
q->refsignal.cell.id,
rsrp_dB_min,
rsrp_dB,
rsrp_dB_max,
rsrp_dB_max - rsrp_dB_min,
rsrp_dB - rsrp_false_dB,
cfo_min,
cfo_acc,
cfo_max,
cfo_max - cfo_min,
sss_strength_avg / sss_strength_false_avg,
false_count);
if (!false_alarm) {
// Calculate in dBm
q->rsrp_dBfs = rsrp_dB;
// Calculate RSSI in dBm
q->rssi_dBfs = srslte_convert_power_to_dBm(rssi_lin);
// Calculate RSRQ
q->rsrq_dB = srslte_convert_power_to_dB(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 {
refsignal_set_results_not_found(q);
}
} 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;
refsignal_set_results_not_found(q);
}
}
}
@ -337,7 +549,9 @@ void srslte_refsignal_dl_sync_measure_sf(srslte_refsignal_dl_sync_t* q,
rsrp_lin += __real__(corr[l] * conjf(corr[l]));
// Calculate RSSI
rssi_lin += srslte_vec_dot_prod_conj_ccc(&buffer[offset], &buffer[offset], symbol_sz);
if (rssi) {
rssi_lin += srslte_vec_dot_prod_conj_ccc(&buffer[offset], &buffer[offset], symbol_sz);
}
}
// Return measurements
@ -350,10 +564,30 @@ void srslte_refsignal_dl_sync_measure_sf(srslte_refsignal_dl_sync_t* q,
}
if (cfo) {
// Distances between symbols
float distance_1 = (cp_len1 + symbol_sz) * 4.0f; // Number of samples between first and second symbol
float distance_2 =
(cp_len1 + symbol_sz) * 3.0f + (cp_len0 - cp_len1); // Number of samples between second and third symbol
// Averaging weights, all of them must be 1.0f
float low_w = REFSIGNAL_DL_CFO_LOW_WEIGHT / 2.0f; // Two of them
float medium_w = REFSIGNAL_DL_CFO_MEDIUM_WEIGHT / 2.0f; // Two of them
float high_w = REFSIGNAL_DL_CFO_HIGH_WEIGHT; // One of them
// Initialise average
*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;
// Low doppler (2 kHz)
*cfo += cargf(corr[2] * conjf(corr[0])) / (2.0f * M_PI * 7.5f) * 15000.0f * low_w;
*cfo += cargf(corr[3] * conjf(corr[1])) / (2.0f * M_PI * 7.5f) * 15000.0f * low_w;
// Medium Doppler (3.5 kHz)
*cfo += cargf(corr[1] * conjf(corr[0])) / (2.0f * M_PI * distance_1) * (15000.0f * symbol_sz) * medium_w;
*cfo += cargf(corr[3] * conjf(corr[2])) / (2.0f * M_PI * distance_1) * (15000.0f * symbol_sz) * medium_w;
// High doppler (4.66 kHz)
*cfo += cargf(corr[2] * conjf(corr[1])) / (2.0f * M_PI * distance_2) * (15000.0f * symbol_sz) * high_w;
}
}
}

View File

@ -31,17 +31,19 @@
#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 std::string cell_list;
static int phy_lib_log_level;
static std::string intra_meas_log_level;
static std::string active_cell_list;
static std::string simulation_cell_list;
static int phy_lib_log_level;
static srsue::phy_args_t phy_args;
// On the Fly parameters
static int earfcn_dl;
@ -51,9 +53,6 @@ static std::string radio_log_level;
static float rx_gain;
// Simulation parameters
static uint32_t nof_enb;
static uint16_t cell_id_start;
static uint16_t cell_id_step;
static float channel_period_s;
static uint32_t cfi;
static float ncell_attenuation_dB;
@ -67,6 +66,10 @@ static uint16_t serving_cell_pdsch_rnti;
static srslte_tm_t serving_cell_pdsch_tm;
static uint16_t serving_cell_pdsch_mcs;
// Parsed PCI lists
static std::set<uint32_t> pcis_to_meas = {};
static std::set<uint32_t> pcis_to_simulate = {};
// PRB allocation helpers
static uint32_t prbset_num = 1, last_prbset_num = 1;
static uint32_t prbset_orig = 0;
@ -197,7 +200,7 @@ public:
float scale = sqrtf(cell_base.nof_prb) / 0.05f / enb_dl.ifft->symbol_sz;
// Apply Neighbour cell attenuation
if (enb_dl.cell.id != cell_id_start) {
if (enb_dl.cell.id != *pcis_to_simulate.begin()) {
scale *= srslte_convert_dB_to_amplitude(-ncell_attenuation_dB);
}
@ -265,16 +268,22 @@ public:
}
}
void print_stats()
bool print_stats()
{
printf("\n-- Statistics:\n");
for (auto& e : cells) {
bool false_alarm = true;
uint32_t true_counts = 0;
uint32_t false_counts = 0;
uint32_t tti_count = (1000 * duration_execution_s) / phy_args.intra_freq_meas_period_ms;
uint32_t ideal_true_counts = (pcis_to_simulate.size() - 1) * tti_count;
uint32_t ideal_false_counts = tti_count * cells.size() - ideal_true_counts;
for (uint32_t i = 0; false_alarm && (i < nof_enb); i++) {
if (e.first == cell_id_start + cell_id_step * i) {
false_alarm = false;
}
for (auto& e : cells) {
bool false_alarm = pcis_to_simulate.find(e.first) == pcis_to_simulate.end();
if (false_alarm) {
false_counts += e.second.count;
} else {
true_counts += e.second.count;
}
printf(" pci=%03d; count=%3d; false=%s; rsrp=%+.1f|%+.1f|%+.1fdBfs; rsrq=%+.1f|%+.1f|%+.1fdB;\n",
@ -288,13 +297,21 @@ public:
e.second.rsrq_avg,
e.second.rsrq_max);
}
float prob_detection = (ideal_true_counts) ? (float)true_counts / (float)ideal_true_counts : 0.0f;
float prob_false_alarm = (ideal_false_counts) ? (float)false_counts / (float)ideal_false_counts : 0.0f;
printf("\n");
printf(" Probability of detection: %.6f\n", prob_detection);
printf(" Probability of false alarm: %.6f\n", prob_false_alarm);
return (prob_detection >= 0.9f && prob_false_alarm <= 0.1f);
}
};
// shorten boost program options namespace
namespace bpo = boost::program_options;
int parse_args(int argc, char** argv, srsue::phy_args_t* phy_args)
int parse_args(int argc, char** argv)
{
int ret = SRSLTE_SUCCESS;
@ -308,10 +325,10 @@ int parse_args(int argc, char** argv, srsue::phy_args_t* phy_args)
("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")
("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")
("active_cell_list", bpo::value<std::string>(&active_cell_list)->default_value("10,17,24,31,38,45,52"), "Comma separated neighbour PCI cell list")
;
over_the_air.add_options()
@ -324,9 +341,7 @@ int parse_args(int argc, char** argv, srsue::phy_args_t* phy_args)
;
simulation.add_options()
("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")
("simulation_cell_list", bpo::value<std::string>(&simulation_cell_list)->default_value("10,17,24,31,38,45,52"), "Comma separated neighbour PCI cell list")
("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")
@ -363,17 +378,42 @@ int parse_args(int argc, char** argv, srsue::phy_args_t* phy_args)
return ret;
}
static void pci_list_parse_helper(std::string& list_str, std::set<uint32_t>& list)
{
if (list_str == "all") {
// Add all possible cells
for (int i = 0; i < 504; i++) {
list.insert(i);
}
} else if (list_str == "none") {
// Do nothing
} else if (!list_str.empty()) {
// Remove spaces from neightbour cell list
std::size_t p1 = list_str.find(' ');
while (p1 != std::string::npos) {
list_str.erase(p1);
p1 = list_str.find(' ');
}
// Add cell to known cells
std::stringstream ss(list_str);
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
list.insert((uint32_t)strtoul(substr.c_str(), nullptr, 10));
}
}
}
int main(int argc, char** argv)
{
int ret = SRSLTE_SUCCESS;
srsue::phy_args_t phy_args = {};
int ret;
// Parse args
if (parse_args(argc, argv, &phy_args)) {
if (parse_args(argc, argv)) {
return SRSLTE_ERROR;
}
// 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 = {};
@ -422,18 +462,15 @@ int main(int argc, char** argv)
softbuffer_tx[i] = (srslte_softbuffer_tx_t*)calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffer_tx[i]) {
ERROR("Error allocating softbuffer_tx\n");
ret = SRSLTE_ERROR;
}
if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell_base.nof_prb)) {
ERROR("Error initiating softbuffer_tx\n");
ret = SRSLTE_ERROR;
}
data_tx[i] = (uint8_t*)srslte_vec_malloc(sizeof(uint8_t) * nof_bytes);
if (!data_tx[i]) {
ERROR("Error allocating data tx\n");
ret = SRSLTE_ERROR;
} else {
for (uint32_t j = 0; j < nof_bytes; j++) {
data_tx[i][j] = (uint8_t)srslte_random_uniform_int_dist(random_gen, 0, 255);
@ -443,8 +480,11 @@ int main(int argc, char** argv)
srslte_random_free(random_gen);
}
pci_list_parse_helper(active_cell_list, pcis_to_meas);
pci_list_parse_helper(simulation_cell_list, pcis_to_simulate);
// Set cell_base id with the serving cell
uint32_t serving_cell_id = (nof_enb == 1) ? (cell_id_start + cell_id_step) : cell_id_start;
uint32_t serving_cell_id = *pcis_to_simulate.begin();
cell_base.id = serving_cell_id;
logger.set_level(intra_meas_log_level);
@ -452,8 +492,6 @@ int main(int argc, char** argv)
intra_measure.init(&common, &rrc, &logger);
intra_measure.set_primary_cell(serving_cell_id, cell_base);
std::set<uint32_t> pcis_to_meas = {};
if (earfcn_dl >= 0) {
// Create radio log
radio_log = std::unique_ptr<srslte::log_filter>(new srslte::log_filter("Radio"));
@ -473,58 +511,40 @@ int main(int argc, char** argv)
} else {
// Create test eNb's if radio is not available
for (uint32_t enb_idx = 0; enb_idx < nof_enb; enb_idx++) {
float channel_init_time_s = 0;
float channel_delay_us = 0;
for (auto& pci : pcis_to_simulate) {
// Initialise cell
srslte_cell_t cell = cell_base;
cell.id = (cell_id_start + enb_idx * cell_id_step) % 504;
cell.id = pci;
// Initialise channel and push back
srslte::channel::args_t channel_args;
channel_args.enable = true;
channel_args.enable = (channel_period_s != 0);
channel_args.hst_enable = (channel_hst_fd_hz != 0.0f);
channel_args.hst_init_time_s = (float)(enb_idx * channel_period_s) / (float)nof_enb;
channel_args.hst_init_time_s = channel_init_time_s;
channel_args.hst_period_s = (float)channel_period_s;
channel_args.hst_fd_hz = channel_hst_fd_hz;
channel_args.delay_enable = (channel_delay_max_us != 0.0f);
channel_args.delay_min_us = 0;
channel_args.delay_max_us = channel_delay_max_us;
channel_args.delay_min_us = channel_delay_us;
channel_args.delay_max_us = channel_delay_us;
channel_args.delay_period_s = (uint32)channel_period_s;
channel_args.delay_init_time_s = (enb_idx * channel_period_s) / nof_enb;
channel_args.delay_init_time_s = channel_init_time_s;
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()) {
if (active_cell_list.empty()) {
pcis_to_meas.insert(cell.id);
}
}
}
// Parse cell list
if (cell_list == "all") {
// Add all possible cells
for (int i = 0; i < 504; i++) {
pcis_to_meas.insert(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, ',');
pcis_to_meas.insert((uint32_t)strtoul(substr.c_str(), nullptr, 10));
// Increase init time
channel_init_time_s += channel_period_s / (float)pcis_to_simulate.size();
channel_delay_us += channel_delay_max_us / (float)pcis_to_simulate.size();
}
}
// pass cells to measure to intra_measure object
intra_measure.set_cells_to_meas(pcis_to_meas);
// Run loop
@ -620,6 +640,12 @@ int main(int argc, char** argv)
srslte_timestamp_add(&ts, 0, 0.001f);
if (sf_idx > phy_args.intra_freq_meas_period_ms) {
if (sf_idx % phy_args.intra_freq_meas_period_ms == 0) {
intra_measure.wait_meas();
}
}
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));
@ -629,7 +655,8 @@ int main(int argc, char** argv)
// Stop
intra_measure.stop();
rrc.print_stats();
ret = rrc.print_stats() ? SRSLTE_SUCCESS : SRSLTE_ERROR;
if (baseband_buffer) {
free(baseband_buffer);
}