SRSUE: neighbour cell measurement test defined

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent 385102fa2d
commit 8f6dd184be

@ -26,38 +26,154 @@
#include <srslte/phy/utils/vector.h> #include <srslte/phy/utils/vector.h>
#include <srslte/srslte.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 srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q)
{ {
int ret = SRSLTE_ERROR_INVALID_INPUTS; int ret = SRSLTE_ERROR_INVALID_INPUTS;
if (q) { if (q) {
// Initialise internals // Initialise internals
bzero(q, sizeof(srslte_refsignal_dl_sync_t)); memset(q, 0, sizeof(srslte_refsignal_dl_sync_t));
// Initialise Reference signals // Initialise Reference signals
ret = srslte_refsignal_cs_init(&q->refsignal, SRSLTE_MAX_PRB); ret = srslte_refsignal_cs_init(&q->refsignal, SRSLTE_MAX_PRB);
// Allocate time buffers // Allocate time buffers
for (int i = 0; i < SRSLTE_NOF_SF_X_FRAME; i++) { 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]) { if (!q->sequences[i]) {
perror("Allocating sequence\n"); perror("Allocating sequence\n");
} }
} }
// Allocate Temporal OFDM buffer // 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) { if (!q->ifft_buffer_in) {
perror("Allocating ifft_buffer_in\n"); 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) { if (!q->ifft_buffer_out) {
perror("Allocating ifft_buffer_out\n"); perror("Allocating ifft_buffer_out\n");
} }
// Allocate correlation // 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) { if (!q->correlation) {
perror("Allocating correlation\n"); perror("Allocating correlation\n");
} }
@ -76,6 +192,9 @@ int srslte_refsignal_dl_sync_init(srslte_refsignal_dl_sync_t* q)
if (!ret) { if (!ret) {
ret = srslte_conv_fft_cc_init(&q->conv_fft_cc, q->ifft.sf_sz, q->ifft.sf_sz); 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; 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); 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 // Put Reference signals
for (int p = 0; p < cell.nof_ports; p++) { 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); 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 srslte_refsignal_dl_sync_find_peak(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples)
{ {
int ret = SRSLTE_ERROR; int ret = SRSLTE_ERROR;
float thr = 5.5f;
float peak_value = 0.0f; float peak_value = 0.0f;
int peak_idx = 0; int peak_idx = 0;
float rms_avg = 0; float rms_avg = 0;
uint32_t sf_len = q->ifft.sf_sz; uint32_t sf_len = q->ifft.sf_sz;
// Load correlation sequence and convert to frequency domain // Load correlation sequence and convert to frequency domain
cf_t* ptr_filt = q->conv_fft_cc.filter_fft; refsignal_sf_prepare_correlation(q);
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 // Limit correlate for a frame or less
nsamples = SRSLTE_MIN(nsamples - sf_len, SRSLTE_NOF_SF_X_FRAME * sf_len); nsamples = SRSLTE_MIN(nsamples - sf_len, SRSLTE_NOF_SF_X_FRAME * sf_len);
// Correlation // Correlation
for (int n = 0; n < nsamples; n += sf_len) { for (int n = 0; n < nsamples; n += sf_len) {
// Set input data, two subframes // Correlate, find maximum, calculate RMS and peak
cf_t* ptr_in = &buffer[n]; uint32_t imax = 0;
float peak = 0.0f;
// Correlate float rms = 0.0f;
srslte_corr_fft_cc_run_opt(&q->conv_fft_cc, ptr_in, ptr_filt, q->correlation); refsignal_sf_correlate(q, &buffer[n], &peak, &imax, &rms);
// 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; rms_avg += rms;
// Found bigger peak // 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 // Condition of peak detection
rms_avg /= floorf((float)nsamples / sf_len); 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; 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", INFO("pci=%03d; sf_len=%d; imax=%d; peak=%.3f; rms=%.3f; peak/rms=%.3f\n",
q->refsignal.cell.id, q->refsignal.cell.id,
sf_len, 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) void srslte_refsignal_dl_sync_run(srslte_refsignal_dl_sync_t* q, cf_t* buffer, uint32_t nsamples)
{ {
if (q) { if (q) {
uint32_t sf_len = q->ifft.sf_sz; uint32_t sf_len = q->ifft.sf_sz;
uint32_t sf_count = 0; uint32_t sf_count = 0;
float rsrp_lin = 0.0f; float rsrp_lin = 0.0f;
float rssi_lin = 0.0f; float rsrp_lin_min = +INFINITY;
float cfo_acc = 0.0f; 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 // Stage 1: find peak
int peak_idx = srslte_refsignal_dl_sync_find_peak(q, buffer, nsamples); 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 // Measure subframe rsrp, rssi and accumulate
float rsrp = 0.0f, rssi = 0.0f, cfo = 0.0f; float rsrp = 0.0f, rssi = 0.0f, cfo = 0.0f;
srslte_refsignal_dl_sync_measure_sf(q, buf, sf_idx, &rsrp, &rssi, &cfo); srslte_refsignal_dl_sync_measure_sf(q, buf, sf_idx, &rsrp, &rssi, &cfo);
// Update measurements
rsrp_lin += rsrp; rsrp_lin += rsrp;
rsrp_lin_min = SRSLTE_MIN(rsrp_lin_min, rsrp);
rsrp_lin_max = SRSLTE_MAX(rsrp_lin_max, rsrp);
rssi_lin += rssi; rssi_lin += rssi;
cfo_acc += cfo; 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++; 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; rsrp_lin /= sf_count;
rssi_lin /= sf_count; rssi_lin /= sf_count;
cfo_acc /= 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);
}
// 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);
// 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 in dBm if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_SEVERE) {
q->rsrp_dBfs = srslte_convert_power_to_dBm(rsrp_lin); false_alarm = true;
} else if (cfo_max - cfo_min > REFSIGNAL_DL_CFO_MIN_MAX_MILD) {
false_count++;
}
// Calculate RSSI in dBm if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_SEVERE) {
q->rssi_dBfs = srslte_convert_power_to_dBm(rssi_lin); false_alarm = true;
} else if (rsrp_dB_max - rsrp_dB_min > REFSIGNAL_DL_RSRP_MIN_MAX_MILD) {
false_count++;
}
// Calculate RSRQ if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_SEVERE) {
q->rsrq_dB = srslte_convert_power_to_dB(q->refsignal.cell.nof_prb) + q->rsrp_dBfs - q->rssi_dBfs; false_alarm = true;
} else if (rsrp_dB - rsrp_false_dB < REFSIGNAL_DL_RSRP_FALSE_RATIO_MILD) {
false_count++;
}
q->found = true; // Allow only one check fail
q->cfo_Hz = cfo_acc; if (false_count > REFSIGNAL_DL_MAX_FAULT_CHECK) {
q->peak_index = peak_idx; 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 { } else {
q->found = false; refsignal_set_results_not_found(q);
q->rsrp_dBfs = NAN;
q->rssi_dBfs = NAN;
q->rsrq_dB = NAN;
q->cfo_Hz = NAN;
q->peak_index = UINT32_MAX;
} }
} }
} }
@ -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])); rsrp_lin += __real__(corr[l] * conjf(corr[l]));
// Calculate RSSI // 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 // Return measurements
@ -350,10 +564,30 @@ void srslte_refsignal_dl_sync_measure_sf(srslte_refsignal_dl_sync_t* q,
} }
if (cfo) { 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 = 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; // Low doppler (2 kHz)
*cfo /= 2; *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;
} }
} }
} }

@ -31,17 +31,19 @@
#include <vector> #include <vector>
// Common execution parameters // Common execution parameters
static uint32_t duration_execution_s; static uint32_t duration_execution_s;
static srslte_cell_t cell_base = {.nof_prb = 6, static srslte_cell_t cell_base = {.nof_prb = 6,
.nof_ports = 1, .nof_ports = 1,
.id = 0, .id = 0,
.cp = SRSLTE_CP_NORM, .cp = SRSLTE_CP_NORM,
.phich_length = SRSLTE_PHICH_NORM, .phich_length = SRSLTE_PHICH_NORM,
.phich_resources = SRSLTE_PHICH_R_1_6, .phich_resources = SRSLTE_PHICH_R_1_6,
.frame_type = SRSLTE_FDD}; .frame_type = SRSLTE_FDD};
static std::string intra_meas_log_level; static std::string intra_meas_log_level;
static std::string cell_list; static std::string active_cell_list;
static int phy_lib_log_level; static std::string simulation_cell_list;
static int phy_lib_log_level;
static srsue::phy_args_t phy_args;
// On the Fly parameters // On the Fly parameters
static int earfcn_dl; static int earfcn_dl;
@ -51,9 +53,6 @@ static std::string radio_log_level;
static float rx_gain; static float rx_gain;
// Simulation parameters // 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 float channel_period_s;
static uint32_t cfi; static uint32_t cfi;
static float ncell_attenuation_dB; 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 srslte_tm_t serving_cell_pdsch_tm;
static uint16_t serving_cell_pdsch_mcs; 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 // PRB allocation helpers
static uint32_t prbset_num = 1, last_prbset_num = 1; static uint32_t prbset_num = 1, last_prbset_num = 1;
static uint32_t prbset_orig = 0; 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; float scale = sqrtf(cell_base.nof_prb) / 0.05f / enb_dl.ifft->symbol_sz;
// Apply Neighbour cell attenuation // 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); scale *= srslte_convert_dB_to_amplitude(-ncell_attenuation_dB);
} }
@ -265,16 +268,22 @@ public:
} }
} }
void print_stats() bool print_stats()
{ {
printf("\n-- Statistics:\n"); printf("\n-- Statistics:\n");
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 (auto& e : cells) { for (auto& e : cells) {
bool false_alarm = true; bool false_alarm = pcis_to_simulate.find(e.first) == pcis_to_simulate.end();
for (uint32_t i = 0; false_alarm && (i < nof_enb); i++) { if (false_alarm) {
if (e.first == cell_id_start + cell_id_step * i) { false_counts += e.second.count;
false_alarm = false; } else {
} true_counts += e.second.count;
} }
printf(" pci=%03d; count=%3d; false=%s; rsrp=%+.1f|%+.1f|%+.1fdBfs; rsrq=%+.1f|%+.1f|%+.1fdB;\n", 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_avg,
e.second.rsrq_max); 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 // shorten boost program options namespace
namespace bpo = boost::program_options; 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; 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") ("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") ("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_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_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_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)") ("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() 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() simulation.add_options()
("nof_enb", bpo::value<uint32_t >(&nof_enb)->default_value(4), "Number of eNb") ("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_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") ("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") ("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") ("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; 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 main(int argc, char** argv)
{ {
int ret = SRSLTE_SUCCESS; int ret;
srsue::phy_args_t phy_args = {};
// Parse args // Parse args
if (parse_args(argc, argv, &phy_args)) { if (parse_args(argc, argv)) {
return SRSLTE_ERROR; return SRSLTE_ERROR;
} }
// Common for simulation and over-the-air // Common for simulation and over-the-air
auto baseband_buffer = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX); auto baseband_buffer = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
srslte_timestamp_t ts = {}; 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); softbuffer_tx[i] = (srslte_softbuffer_tx_t*)calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffer_tx[i]) { if (!softbuffer_tx[i]) {
ERROR("Error allocating softbuffer_tx\n"); ERROR("Error allocating softbuffer_tx\n");
ret = SRSLTE_ERROR;
} }
if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell_base.nof_prb)) { if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell_base.nof_prb)) {
ERROR("Error initiating softbuffer_tx\n"); ERROR("Error initiating softbuffer_tx\n");
ret = SRSLTE_ERROR;
} }
data_tx[i] = (uint8_t*)srslte_vec_malloc(sizeof(uint8_t) * nof_bytes); data_tx[i] = (uint8_t*)srslte_vec_malloc(sizeof(uint8_t) * nof_bytes);
if (!data_tx[i]) { if (!data_tx[i]) {
ERROR("Error allocating data tx\n"); ERROR("Error allocating data tx\n");
ret = SRSLTE_ERROR;
} else { } else {
for (uint32_t j = 0; j < nof_bytes; j++) { for (uint32_t j = 0; j < nof_bytes; j++) {
data_tx[i][j] = (uint8_t)srslte_random_uniform_int_dist(random_gen, 0, 255); 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); 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 // 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; cell_base.id = serving_cell_id;
logger.set_level(intra_meas_log_level); 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.init(&common, &rrc, &logger);
intra_measure.set_primary_cell(serving_cell_id, cell_base); intra_measure.set_primary_cell(serving_cell_id, cell_base);
std::set<uint32_t> pcis_to_meas = {};
if (earfcn_dl >= 0) { if (earfcn_dl >= 0) {
// Create radio log // Create radio log
radio_log = std::unique_ptr<srslte::log_filter>(new srslte::log_filter("Radio")); radio_log = std::unique_ptr<srslte::log_filter>(new srslte::log_filter("Radio"));
@ -473,58 +511,40 @@ int main(int argc, char** argv)
} else { } else {
// Create test eNb's if radio is not available // 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 // Initialise cell
srslte_cell_t cell = cell_base; 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 // Initialise channel and push back
srslte::channel::args_t channel_args; 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_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_period_s = (float)channel_period_s;
channel_args.hst_fd_hz = channel_hst_fd_hz; channel_args.hst_fd_hz = channel_hst_fd_hz;
channel_args.delay_enable = (channel_delay_max_us != 0.0f); channel_args.delay_enable = (channel_delay_max_us != 0.0f);
channel_args.delay_min_us = 0; channel_args.delay_min_us = channel_delay_us;
channel_args.delay_max_us = channel_delay_max_us; channel_args.delay_max_us = channel_delay_us;
channel_args.delay_period_s = (uint32)channel_period_s; 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))); test_enb_v.push_back(std::unique_ptr<test_enb>(new test_enb(cell, channel_args)));
// Add cell to known cells // Add cell to known cells
if (cell_list.empty()) { if (active_cell_list.empty()) {
pcis_to_meas.insert(cell.id); 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 // Increase init time
std::stringstream ss(cell_list); channel_init_time_s += channel_period_s / (float)pcis_to_simulate.size();
while (ss.good()) { channel_delay_us += channel_delay_max_us / (float)pcis_to_simulate.size();
std::string substr;
getline(ss, substr, ',');
pcis_to_meas.insert((uint32_t)strtoul(substr.c_str(), nullptr, 10));
} }
} }
// pass cells to measure to intra_measure object // pass cells to measure to intra_measure object
intra_measure.set_cells_to_meas(pcis_to_meas); intra_measure.set_cells_to_meas(pcis_to_meas);
// Run loop // Run loop
@ -620,6 +640,12 @@ int main(int argc, char** argv)
srslte_timestamp_add(&ts, 0, 0.001f); 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)); intra_measure.write(sf_idx, baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb));
if (sf_idx % 1000 == 0) { if (sf_idx % 1000 == 0) {
printf("Done %.1f%%\n", (double)sf_idx * 100.0 / ((double)duration_execution_s * 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 // Stop
intra_measure.stop(); intra_measure.stop();
rrc.print_stats(); ret = rrc.print_stats() ? SRSLTE_SUCCESS : SRSLTE_ERROR;
if (baseband_buffer) { if (baseband_buffer) {
free(baseband_buffer); free(baseband_buffer);
} }

Loading…
Cancel
Save