Improved SSS decoding and improved scell_search_test

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

@ -220,10 +220,15 @@ int main(int argc, char **argv) {
cfo[frame_cnt] = srslte_pss_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);
printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n",
frame_cnt,N_id_2, srslte_sss_N_id_1(&sss[N_id_2], m0, m1),
srslte_sss_subframe(m0, m1), peak_value[N_id_2],
peak_pos[N_id_2], m0, m1,
cfo[frame_cnt]);
frame_cnt,
N_id_2,
srslte_sss_N_id_1(&sss[N_id_2], m0, m1, m1_value + m0_value),
srslte_sss_subframe(m0, m1),
peak_value[N_id_2],
peak_pos[N_id_2],
m0,
m1,
cfo[frame_cnt]);
}
}
gettimeofday(&tdata[2], NULL);

@ -131,9 +131,7 @@ SRSLTE_API int srslte_sss_m0m1_diff(srslte_sss_t *q,
SRSLTE_API uint32_t srslte_sss_subframe(uint32_t m0,
uint32_t m1);
SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t *q,
uint32_t m0,
uint32_t m1);
SRSLTE_API int srslte_sss_N_id_1(srslte_sss_t* q, uint32_t m0, uint32_t m1, float corr);
SRSLTE_API int srslte_sss_frame(srslte_sss_t *q,
cf_t *input,

@ -118,6 +118,7 @@ typedef struct SRSLTE_API {
bool sss_generated;
bool sss_detected;
bool sss_available;
float sss_corr;
srslte_dft_plan_t idftp_sss;
cf_t sss_recv[SRSLTE_SYMBOL_SZ_MAX];
cf_t sss_signal[2][SRSLTE_SYMBOL_SZ_MAX];
@ -242,6 +243,8 @@ SRSLTE_API srslte_pss_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q);
SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q);
SRSLTE_API float srslte_sync_sss_correlation_peak(srslte_sync_t* q);
SRSLTE_API bool srslte_sync_sss_available(srslte_sync_t* q);
/* Enables/Disables CP detection */

@ -65,18 +65,30 @@ static void corr_all_sz_partial(cf_t z[SRSLTE_SSS_N], float s[SRSLTE_SSS_N][SRSL
static void extract_pair_sss(srslte_sss_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) {
cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX];
// Run FFT
srslte_dft_run_c(&q->dftp_input, input, input_fft);
// Equalize if available channel estimate
if (ce) {
srslte_vec_div_ccc(&input_fft[q->fft_size/2-SRSLTE_SSS_N], ce,
&input_fft[q->fft_size/2-SRSLTE_SSS_N], 2*SRSLTE_SSS_N);
}
// Extract FFT Data
for (int i = 0; i < SRSLTE_SSS_N; i++) {
y[0][i] = input_fft[q->fft_size/2-SRSLTE_SSS_N + 2 * i];
y[1][i] = input_fft[q->fft_size/2-SRSLTE_SSS_N + 2 * i + 1];
}
// Normalize
for (int i = 0; i < 2; i++) {
float avg_pow = srslte_vec_avg_power_cf(y[i], SRSLTE_SSS_N);
float rms = (avg_pow != 0.0f) ? sqrtf(avg_pow) : 1.0f;
srslte_vec_sc_prod_cfc(y[i], 1.0 / rms, y[i], SRSLTE_SSS_N);
}
// Unmask signal with sequence generated from NID2
srslte_vec_prod_cfc(y[0], q->fc_tables[q->N_id_2].c[0], y[0], SRSLTE_SSS_N);
srslte_vec_prod_cfc(y[1], q->fc_tables[q->N_id_2].c[1], y[1], SRSLTE_SSS_N);

@ -133,16 +133,22 @@ uint32_t srslte_sss_subframe(uint32_t m0, uint32_t m1) {
}
/** Returns the N_id_1 value based on the m0 and m1 values */
int srslte_sss_N_id_1(srslte_sss_t *q, uint32_t m0, uint32_t m1) {
int N_id_1 = -1;
if (m1 > m0) {
if (m0 < 30 && m1 - 1 < 30) {
N_id_1 = q->N_id_1_table[m0][m1 - 1];
}
} else {
if (m1 < 30 && m0 - 1 < 30) {
N_id_1 = q->N_id_1_table[m1][m0 - 1];
int srslte_sss_N_id_1(srslte_sss_t* q, uint32_t m0, uint32_t m1, float corr)
{
int N_id_1 = SRSLTE_ERROR;
// Check threshold, consider not found (error) if the correlation is not above the threshold
if (corr > q->corr_peak_threshold) {
if (m1 > m0) {
if (m0 < 30 && m1 - 1 < 30) {
N_id_1 = q->N_id_1_table[m0][m1 - 1];
}
} else {
if (m1 < 30 && m0 - 1 < 30) {
N_id_1 = q->N_id_1_table[m1][m0 - 1];
}
}
}
}
return N_id_1;
}

@ -271,6 +271,11 @@ bool srslte_sync_sss_detected(srslte_sync_t* q)
return q->sss_detected;
}
float srslte_sync_sss_correlation_peak(srslte_sync_t* q)
{
return q->sss_corr;
}
bool srslte_sync_sss_available(srslte_sync_t* q)
{
return q->sss_available;
@ -544,11 +549,12 @@ static bool sync_sss_symbol(srslte_sync_t* q, const cf_t* input, uint32_t* sf_id
*corr = q->m0_value + q->m1_value;
*sf_idx = srslte_sss_subframe(q->m0, q->m1);
ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1);
ret = srslte_sss_N_id_1(&q->sss, q->m0, q->m1, *corr);
if (ret >= 0) {
*N_id_1 = (uint32_t)ret;
INFO("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n",
INFO("SSS detected N_id_1=%d (corr=%7.1f), sf_idx=%d, %s CP\n",
*N_id_1,
*corr,
*sf_idx,
SRSLTE_CP_ISNORM(q->cp) ? "Normal" : "Extended");
return true;
@ -741,6 +747,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
}
q->sss_available = true;
q->sss_detected = false;
for (uint32_t f = 0; f < nof_frame_type_trials; f++) {
if (frame_type_trials[f] == SRSLTE_FDD) {
sss_idx = (int)find_offset + peak_pos - 2 * SRSLTE_SYMBOL_SZ(q->fft_size, q->cp) +
@ -766,7 +773,9 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
}
sss_ptr = q->sss_filt;
}
q->sss_detected = sync_sss_symbol(q, sss_ptr, &sf_idx[f], &N_id_1[f], &sss_corr[f]);
// Consider SSS detected if at least one trial found the SSS
q->sss_detected |= sync_sss_symbol(q, sss_ptr, &sf_idx[f], &N_id_1[f], &sss_corr[f]);
} else {
q->sss_available = false;
}
@ -777,10 +786,12 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
q->frame_type = SRSLTE_FDD;
q->sf_idx = sf_idx[0];
q->N_id_1 = N_id_1[0];
q->sss_corr = sss_corr[0];
} else {
q->frame_type = SRSLTE_TDD;
q->sf_idx = sf_idx[1] + 1;
q->N_id_1 = N_id_1[1];
q->sss_corr = sss_corr[1];
}
DEBUG("SYNC: Detected SSS %s, corr=%.2f/%.2f\n",
q->frame_type == SRSLTE_FDD ? "FDD" : "TDD",
@ -793,6 +804,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uin
q->sf_idx = sf_idx[0] + 1;
}
q->N_id_1 = N_id_1[0];
q->sss_corr = sss_corr[0];
}
}

@ -233,21 +233,21 @@ int main(int argc, char **argv) {
int sss_idx = peak_idx-2*fft_size-(SRSLTE_CP_ISNORM(cp)?SRSLTE_CP_LEN(fft_size, SRSLTE_CP_NORM_LEN):SRSLTE_CP_LEN(fft_size, SRSLTE_CP_EXT_LEN));
if (sss_idx >= 0 && sss_idx < flen-fft_size) {
srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 3, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
if (srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value) != N_id_1) {
sss_error2++;
}
INFO("sf_idx = %d\n", srslte_sss_subframe(m0, m1));
INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value));
srslte_sss_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
if (srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value) != N_id_1) {
sss_error3++;
}
INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value));
srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
if (srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value) != N_id_1) {
sss_error1++;
}
INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value));
}
// Estimate CP

@ -265,20 +265,20 @@ int main(int argc, char **argv) {
// Filter SSS
srslte_pss_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]);
INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
INFO("Full N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value));
srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
if (srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value) != N_id_1) {
sss_error2++;
}
INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
INFO("Partial N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value));
srslte_sss_m0m1_diff_coh(&sss, &buffer[sss_idx], ce, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
if (srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value) != N_id_1) {
sss_error3++;
}
INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1));
INFO("Diff N_id_1: %d\n", srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value));
}
srslte_sss_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value);
if (srslte_sss_N_id_1(&sss, m0, m1) != N_id_1) {
if (srslte_sss_N_id_1(&sss, m0, m1, m1_value + m0_value) != N_id_1) {
sss_error1++;
}

@ -51,6 +51,7 @@ public:
float rsrp();
float rsrq();
float snr();
float cfo();
uint32_t frame_st_idx();
void set_rx_gain_offset(float rx_gain_offset);
@ -63,7 +64,7 @@ private:
uint32_t nof_subframes;
uint32_t current_prb;
float rx_gain_offset;
float mean_rsrp, mean_rsrq, mean_snr, mean_rssi;
float mean_rsrp, mean_rsrq, mean_snr, mean_rssi, mean_cfo;
uint32_t final_offset;
const static int RSRP_MEASURE_NOF_FRAMES = 5;
};

@ -70,6 +70,7 @@ void measure::reset()
mean_rsrq = 0;
mean_snr = 0;
mean_rssi = 0;
mean_cfo = 0;
}
void measure::set_cell(srslte_cell_t cell)
@ -101,6 +102,11 @@ float measure::snr()
return mean_snr;
}
float measure::cfo()
{
return mean_cfo;
}
uint32_t measure::frame_st_idx()
{
return final_offset;
@ -196,6 +202,7 @@ measure::ret_code measure::run_subframe(uint32_t sf_idx)
float rsrp = ue_dl.chest_res.rsrp_neigh;
float rsrq = ue_dl.chest_res.rsrq;
float snr = ue_dl.chest_res.snr_db;
float cfo = ue_dl.chest_res.cfo;
float rssi = srslte_vec_avg_power_cf(buffer[0], (uint32_t)SRSLTE_SF_LEN_PRB(current_prb));
if (cnt == 0) {
@ -203,11 +210,13 @@ measure::ret_code measure::run_subframe(uint32_t sf_idx)
mean_rsrq = rsrq;
mean_snr = snr;
mean_rssi = rssi;
mean_cfo = cfo;
} else {
mean_rsrp = SRSLTE_VEC_CMA(rsrp, mean_rsrp, cnt);
mean_rsrq = SRSLTE_VEC_CMA(rsrq, mean_rsrq, cnt);
mean_snr = SRSLTE_VEC_CMA(snr, mean_snr, cnt);
mean_rssi = SRSLTE_VEC_CMA(rssi, mean_rssi, cnt);
mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, cnt);
}
cnt++;

@ -64,15 +64,16 @@ void scell_recv::init(srslte::log* _log_h, bool _sic_pss_enabled, uint32_t max_s
return;
}
srslte_sync_set_sss_algorithm(&sync_find, SSS_FULL);
srslte_sync_set_cfo_cp_enable(&sync_find, false, 0);
srslte_sync_cp_en(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_threshold(&sync_find, 1.7);
srslte_sync_set_em_alpha(&sync_find, 0.3);
srslte_sync_set_cfo_pss_enable(&sync_find, false);
srslte_sync_set_threshold(&sync_find, 2.0f); // The highest the best for avoiding ghost cells
srslte_sync_set_em_alpha(&sync_find, 0.3f);
srslte_sss_set_threshold(&sync_find.sss, 300.0); // A higher value will avoid false alarms but reduce detection
// Configure FIND object behaviour (this configuration is always the same)
srslte_sync_set_cfo_ema_alpha(&sync_find, 1.0);
srslte_sync_set_cfo_i_enable(&sync_find, false);
srslte_sync_set_cfo_pss_enable(&sync_find, true);
srslte_sync_set_pss_filt_enable(&sync_find, true);
srslte_sync_set_sss_eq_enable(&sync_find, true);
@ -132,29 +133,48 @@ int scell_recv::find_cells(
srslte_sync_cfo_reset(&sync_find);
sync_res = SRSLTE_SYNC_NOFOUND;
bool sss_detected = false;
cell_id = 0;
float max_peak = -1;
uint32_t max_sf5 = 0;
uint32_t max_sf_idx = 0;
float sss_correlation_peak_max = 0.0f;
for (uint32_t sf5_cnt = 0; sf5_cnt < nof_sf / 5; sf5_cnt++) {
sync_res = srslte_sync_find(&sync_find, input_buffer, sf5_cnt * 5 * sf_len, &peak_idx);
Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f\n",
Debug("INTRA: n_id_2=%d, cnt=%d/%d, sync_res=%d, sf_idx=%d, peak_idx=%d, peak_value=%f, sss_detected=%d\n",
n_id_2,
sf5_cnt,
nof_sf / 5,
sync_res,
srslte_sync_get_sf_idx(&sync_find),
peak_idx,
sync_find.peak_value);
sync_find.peak_value,
srslte_sync_sss_detected(&sync_find));
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND) {
if (sync_find.peak_value > max_peak && sync_res == SRSLTE_SYNC_FOUND &&
srslte_sync_sss_detected(&sync_find)) {
max_sf5 = sf5_cnt;
max_sf_idx = srslte_sync_get_sf_idx(&sync_find);
cell_id = srslte_sync_get_cell_id(&sync_find);
// Uses the cell ID from the highest SSS correlation peak
if (sss_correlation_peak_max < srslte_sync_sss_correlation_peak(&sync_find)) {
// Set the cell ID
cell_id = srslte_sync_get_cell_id(&sync_find);
// Update the maximum value
sss_correlation_peak_max = srslte_sync_sss_correlation_peak(&sync_find);
}
sss_detected = true;
}
}
// If the SSS was not detected, the cell id is not reliable. So, consider no sync found
if (!sss_detected) {
sync_res = SRSLTE_SYNC_NOFOUND;
}
switch (sync_res) {
case SRSLTE_SYNC_ERROR:
return SRSLTE_ERROR;
@ -196,17 +216,20 @@ int scell_recv::find_cells(
cells[nof_cells].rsrq = measure_p.rsrq();
cells[nof_cells].offset = measure_p.frame_st_idx();
Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, peak_idx=%5d, peak_value=%3.2f, "
"sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f Hz\n",
Info("INTRA: Found neighbour cell %d: PCI=%03d, RSRP=%5.1f dBm, SNR=%5.1f dB, peak_idx=%5d, "
"peak_value=%3.2f, "
"sf=%d, max_sf=%d, n_id_2=%d, CFO=%6.1f/%6.1fHz\n",
nof_cells,
cell_id,
measure_p.rsrp(),
measure_p.snr(),
measure_p.frame_st_idx(),
sync_find.peak_value,
sf_idx,
max_sf5,
n_id_2,
15000 * srslte_sync_get_cfo(&sync_find));
15000 * srslte_sync_get_cfo(&sync_find),
15000 * measure_p.cfo());
nof_cells++;

@ -18,17 +18,22 @@
# and at http://www.gnu.org/licenses/.
#
include_directories(
${Boost_INCLUDE_DIRS}
${SEC_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}
)
link_directories(
${Boost_LIBRARY_DIRS}
${SEC_LIBRARY_DIRS}
)
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
target_link_libraries(scell_search_test
srsue_phy
srslte_common
srslte_phy
srslte_radio
srslte_upper
rrc_asn1
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES})
add_test(scell_search_test scell_search_test)

@ -19,100 +19,97 @@
*
*/
#include <boost/program_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <iostream>
#include <map>
#include <memory>
#include <srslte/phy/channel/channel.h>
#include <srslte/phy/utils/random.h>
#include <srslte/srslte.h>
#include <srsue/hdr/phy/scell/intra_measure.h>
#include <vector>
// Simulation parameters
static uint16_t pdsch_rnti = 0x1234;
static srslte_cell_t cell_base = {.nof_prb = 6,
// Common execution parameters
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 uint32_t nof_enb = 3;
static uint16_t cell_id_start = 0;
static uint16_t cell_id_step = 1;
static float channel_period_s = 7.2f;
static uint32_t sim_time_periods = 10;
static uint32_t cfi = 1;
static srslte::channel::args_t channel_args_base;
// Constant
static const srslte_tm_t transmission_mode = SRSLTE_TM1;
int work_enb(srslte_enb_dl_t* enb_dl,
srslte_dl_sf_cfg_t* dl_sf,
srslte_dci_cfg_t* dci_cfg,
srslte_dci_dl_t* dci,
srslte_softbuffer_tx_t** softbuffer_tx,
uint8_t** data_tx)
{
int ret = SRSLTE_ERROR;
srslte_enb_dl_put_base(enb_dl, dl_sf);
// Put PDSCH only if required
if (dci && dci_cfg && data_tx && softbuffer_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;
}
// Create pdsch config
srslte_pdsch_cfg_t pdsch_cfg;
if (srslte_ra_dl_dci_to_grant(&enb_dl->cell, dl_sf, transmission_mode, false, dci, &pdsch_cfg.grant)) {
ERROR("Computing DL grant sf_idx=%d\n", dl_sf->tti);
goto quit;
}
char str[512];
srslte_dci_dl_info(dci, str, 512);
INFO("eNb PDCCH: rnti=0x%x, %s\n", pdsch_rnti, str);
static std::string intra_meas_log_level;
static int phy_lib_log_level;
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
pdsch_cfg.softbuffers.tx[i] = softbuffer_tx[i];
}
// On the Fly parameters
static int earfcn_dl;
static std::string radio_device_args;
static std::string radio_device_name;
static std::string radio_log_level;
static float rx_gain;
// Enable power allocation
pdsch_cfg.power_scale = true;
pdsch_cfg.p_a = 0.0f; // 0 dB
pdsch_cfg.p_b = (transmission_mode > SRSLTE_TM1) ? 1 : 0; // 0 dB
pdsch_cfg.rnti = pdsch_rnti;
pdsch_cfg.meas_time_en = false;
// 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;
static float channel_hst_fd_hz;
static float channel_delay_max_us;
static std::string channel_log_level;
// Simulation Serving cell PDSCH parameters
static bool serving_cell_pdsch_enable;
static uint16_t serving_cell_pdsch_rnti;
static srslte_tm_t serving_cell_pdsch_tm;
static uint16_t serving_cell_pdsch_mcs;
// PRB allocation helpers
static uint32_t prbset_num = 1, last_prbset_num = 1;
static uint32_t prbset_orig = 0;
unsigned int reverse(unsigned int x)
{
x = (((x & (uint32_t)0xaaaaaaaa) >> (uint32_t)1) | ((x & (uint32_t)0x55555555) << (uint32_t)1));
x = (((x & (uint32_t)0xcccccccc) >> (uint32_t)2) | ((x & (uint32_t)0x33333333) << (uint32_t)2));
x = (((x & (uint32_t)0xf0f0f0f0) >> (uint32_t)4) | ((x & (uint32_t)0x0f0f0f0f) << (uint32_t)4));
x = (((x & (uint32_t)0xff00ff00) >> (uint32_t)8) | ((x & (uint32_t)0x00ff00ff) << (uint32_t)8));
return ((x >> (uint32_t)16) | (x << (uint32_t)16));
}
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;
uint32_t prbset_to_bitmask()
{
uint32_t mask = 0;
auto nb = (uint32_t)ceilf((float)cell_base.nof_prb / srslte_ra_type0_P(cell_base.nof_prb));
for (uint32_t i = 0; i < nb; i++) {
if (i >= prbset_orig && i < prbset_orig + prbset_num) {
mask = mask | ((uint32_t)0x1 << i);
}
srslte_pdsch_tx_info(&pdsch_cfg, str, 512);
INFO("eNb PDSCH: rnti=0x%x, %s\n", pdsch_rnti, str);
}
srslte_enb_dl_gen_signal(enb_dl);
ret = SRSLTE_SUCCESS;
quit:
return ret;
return reverse(mask) >> (uint32_t)(32 - nb);
}
// Test eNb class
class test_enb
{
private:
srslte_enb_dl_t enb_dl;
srslte::channel_ptr channel;
cf_t* signal_buffer[SRSLTE_MAX_PORTS] = {};
srslte::log_filter channel_log;
public:
test_enb(const srslte_cell_t& cell, const srslte::channel::args_t& channel_args)
test_enb(const srslte_cell_t& cell, const srslte::channel::args_t& channel_args) :
enb_dl(),
channel_log("Channel pci=" + std::to_string(cell.id))
{
channel_log.set_level(channel_log_level);
channel = srslte::channel_ptr(new srslte::channel(channel_args, cell_base.nof_ports));
channel->set_srate(srslte_sampling_freq_hz(cell.nof_prb));
channel->set_logger(&channel_log);
// Allocate buffer for eNb
for (uint32_t i = 0; i < cell_base.nof_ports; i++) {
@ -130,7 +127,7 @@ public:
ERROR("Error setting eNb DL cell\n");
}
if (srslte_enb_dl_add_rnti(&enb_dl, pdsch_rnti)) {
if (srslte_enb_dl_add_rnti(&enb_dl, serving_cell_pdsch_rnti)) {
ERROR("Error adding RNTI\n");
}
}
@ -158,13 +155,13 @@ public:
// Create pdsch config
srslte_pdsch_cfg_t pdsch_cfg;
if (srslte_ra_dl_dci_to_grant(&enb_dl.cell, dl_sf, transmission_mode, false, dci, &pdsch_cfg.grant)) {
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;
}
char str[512];
srslte_dci_dl_info(dci, str, 512);
INFO("eNb PDCCH: rnti=0x%x, %s\n", pdsch_rnti, str);
INFO("eNb PDCCH: rnti=0x%x, %s\n", serving_cell_pdsch_rnti, str);
for (uint32_t i = 0; i < SRSLTE_MAX_CODEWORDS; i++) {
pdsch_cfg.softbuffers.tx[i] = softbuffer_tx[i];
@ -173,8 +170,8 @@ public:
// Enable power allocation
pdsch_cfg.power_scale = true;
pdsch_cfg.p_a = 0.0f; // 0 dB
pdsch_cfg.p_b = (transmission_mode > SRSLTE_TM1) ? 1 : 0; // 0 dB
pdsch_cfg.rnti = pdsch_rnti;
pdsch_cfg.p_b = (serving_cell_pdsch_tm > SRSLTE_TM1) ? 1 : 0; // 0 dB
pdsch_cfg.rnti = serving_cell_pdsch_rnti;
pdsch_cfg.meas_time_en = false;
if (srslte_enb_dl_put_pdsch(&enb_dl, &pdsch_cfg, data_tx) < 0) {
@ -182,7 +179,7 @@ public:
goto quit;
}
srslte_pdsch_tx_info(&pdsch_cfg, str, 512);
INFO("eNb PDSCH: rnti=0x%x, %s\n", pdsch_rnti, str);
INFO("eNb PDSCH: rnti=0x%x, %s\n", serving_cell_pdsch_rnti, str);
}
srslte_enb_dl_gen_signal(&enb_dl);
@ -194,6 +191,13 @@ public:
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);
}
srslte_vec_sum_ccc(signal_buffer[0], baseband_buffer, baseband_buffer, sf_len);
ret = SRSLTE_SUCCESS;
@ -218,78 +222,348 @@ public:
class dummy_rrc : public srsue::rrc_interface_phy_lte
{
public:
typedef struct {
float rsrp;
float rsrq;
uint32_t count;
} cell_meas_t;
std::map<uint32_t, cell_meas_t> cells;
void in_sync() override {}
void out_of_sync() override {}
void new_phy_meas(float rsrp, float rsrq, uint32_t tti, int earfcn, int pci) override
{
printf("[new_phy_meas] tti=%d earfcn=%d; pci=%d; rsrp=%+.1f; rsrq=%+.1f;\n", tti, earfcn, pci, rsrp, rsrq);
if (!cells.count(pci)) {
cells[pci].rsrp = rsrp;
cells[pci].rsrq = 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].count++;
}
}
void print_stats()
{
printf("\n-- Statistics:\n");
for (auto& e : cells) {
bool false_alarm = true;
for (uint32_t i = 0; false_alarm && (i < nof_enb); i++) {
if (e.first == cell_id_start + cell_id_step * i) {
false_alarm = false;
}
}
printf(" pci=%03d; count=%3d; false=%s; rsrp=%+.1f\n",
e.first,
e.second.count,
false_alarm ? "y" : "n",
e.second.rsrp);
}
}
};
// shorten boost program options namespace
namespace bpo = boost::program_options;
int parse_args(int argc, char** argv)
{
int ret = SRSLTE_SUCCESS;
bpo::options_description options;
bpo::options_description common("Common execution options");
bpo::options_description over_the_air("Over the air execution options");
bpo::options_description simulation("Over the air execution options");
// 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)")
;
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")
;
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")
;
// clang-format on
options.add(common).add(over_the_air).add(simulation).add_options()("help", "Show this message");
bpo::variables_map vm;
try {
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
bpo::notify(vm);
} catch (bpo::error& e) {
std::cerr << e.what() << std::endl;
ret = SRSLTE_ERROR;
}
// help option was given or error - print usage and exit
if (vm.count("help") || ret) {
std::cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << std::endl << std::endl;
std::cout << options << std::endl << std::endl;
ret = SRSLTE_ERROR;
}
return ret;
}
int main(int argc, char** argv)
{
auto baseband_buffer = (cf_t*)srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
// Parse 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 = {};
srsue::scell::intra_measure intra_measure;
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;
srslte_timestamp_t ts = {};
srsue::scell::intra_measure intra_measure;
srslte::log_filter logger("intra_measure");
dummy_rrc rrc;
srsue::phy_common common(1);
srsue::phy_args_t phy_args;
common.args = &phy_args;
phy_args.estimator_fil_auto = false;
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;
uint8_t* data_tx[SRSLTE_MAX_TB] = {};
srslte_softbuffer_tx_t* softbuffer_tx[SRSLTE_MAX_TB] = {};
// Over-the-air only
std::unique_ptr<srslte::radio> radio = nullptr;
std::unique_ptr<srslte::log_filter> radio_log = nullptr;
// Set Receiver args
common.args = &phy_args;
phy_args.estimator_fil_auto = false;
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;
phy_args.cfo_integer_enabled = false;
phy_args.cfo_correct_tol_hz = 1.0f;
phy_args.cfo_pss_ema = DEFAULT_CFO_EMA_TRACK;
phy_args.cfo_ref_mask = 1023;
phy_args.cfo_loop_bw_pss = DEFAULT_CFO_BW_PSS;
phy_args.cfo_loop_bw_ref = DEFAULT_CFO_BW_REF;
phy_args.cfo_loop_pss_tol = DEFAULT_CFO_PSS_MIN;
phy_args.cfo_loop_ref_min = DEFAULT_CFO_REF_MIN;
phy_args.cfo_loop_pss_conv = DEFAULT_PSS_STABLE_TIMEOUT;
phy_args.snr_estim_alg = "refs";
phy_args.snr_ema_coeff = 0.1f;
// Set phy-lib logging level
srslte_verbose = phy_lib_log_level;
// Allocate PDSCH data and tx-soft-buffers only if pdsch is enabled and radio is not available
for (int i = 0; i < SRSLTE_MAX_TB && serving_cell_pdsch_enable && radio == nullptr; i++) {
srslte_random_t random_gen = srslte_random_init(serving_cell_pdsch_rnti);
const size_t nof_bytes = (6144 * 16 * 3 / 8);
softbuffer_tx[i] = (srslte_softbuffer_tx_t*)calloc(sizeof(srslte_softbuffer_tx_t), 1);
if (!softbuffer_tx[i]) {
ERROR("Error allocating softbuffer_tx\n");
}
if (srslte_softbuffer_tx_init(softbuffer_tx[i], cell_base.nof_prb)) {
ERROR("Error initiating softbuffer_tx\n");
}
data_tx[i] = (uint8_t*)srslte_vec_malloc(sizeof(uint8_t) * nof_bytes);
if (!data_tx[i]) {
ERROR("Error allocating data tx\n");
}
for (uint32_t j = 0; j < nof_bytes; j++) {
data_tx[i][j] = (uint8_t)srslte_random_uniform_int_dist(random_gen, 0, 255);
}
srslte_random_free(random_gen);
}
// 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;
cell_base.id = serving_cell_id;
logger.set_level(intra_meas_log_level);
intra_measure.init(&common, &rrc, &logger);
intra_measure.set_primay_cell(0, cell_base);
intra_measure.add_cell(cell_id_start);
for (uint32_t enb_idx = 0; enb_idx < nof_enb; enb_idx++) {
// Initialise cell
srslte_cell_t cell = cell_base;
cell.id = cell_id_start + enb_idx * cell_id_step;
// Initialise channel and push back
srslte::channel::args_t channel_args;
channel_args.enable = true;
channel_args.hst_enable = true;
channel_args.hst_init_time_s = 0.0f; //(float) channel_period_s / (float) nof_enb * enb_idx;
channel_args.hst_period_s = 7.2f; //(float) channel_period_s;
channel_args.hst_fd_hz = 750.0f;
channel_args.delay_enable = enb_idx != 0;
channel_args.delay_min_us = 10.0;
channel_args.delay_max_us = 300.0;
channel_args.delay_period_s = channel_period_s;
test_enb_v.push_back(std::unique_ptr<test_enb>(new test_enb(cell, channel_args)));
intra_measure.set_primay_cell(serving_cell_id, cell_base);
intra_measure.add_cell(serving_cell_id);
if (earfcn_dl >= 0) {
// Create radio log
radio_log = std::unique_ptr<srslte::log_filter>(new srslte::log_filter("Radio"));
radio_log->set_level(radio_log_level);
// Create radio
radio = std::unique_ptr<srslte::radio>(new srslte::radio());
// Init radio
radio->init(radio_log.get(), (char*)radio_device_args.c_str(), (char*)radio_device_name.c_str(), 1);
// Set sampling rate
radio->set_rx_srate(srslte_sampling_freq_hz(cell_base.nof_prb));
// Set frequency
radio->set_rx_freq(0, srslte_band_fd(earfcn_dl) * 1e6);
} else {
// Create test eNb's if radio is not available
for (uint32_t enb_idx = 0; enb_idx < nof_enb; enb_idx++) {
// Initialise cell
srslte_cell_t cell = cell_base;
cell.id = (cell_id_start + enb_idx * cell_id_step) % 504;
// Initialise channel and push back
srslte::channel::args_t channel_args;
channel_args.enable = true;
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_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_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)));
}
}
for (uint32_t period = 0; period < sim_time_periods; period++) {
for (uint32_t k = 0, sf_idx = 0; k < channel_period_s * 1000; k++, sf_idx++) {
srslte_dl_sf_cfg_t sf_cfg_dl = {};
sf_cfg_dl.tti = sf_idx % 10;
sf_cfg_dl.cfi = cfi;
sf_cfg_dl.sf_type = SRSLTE_SF_NORM;
// Run Programm
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;
sf_cfg_dl.cfi = cfi;
sf_cfg_dl.sf_type = SRSLTE_SF_NORM;
// Clean buffer
bzero(baseband_buffer, sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
// Clean buffer
bzero(baseband_buffer, sizeof(cf_t) * SRSLTE_SF_LEN_MAX);
if (radio) {
// Receive radio
radio->rx_now(&baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb), &ts);
} else {
// Run eNb simulator
bool put_pdsch = serving_cell_pdsch_enable;
for (auto& enb : test_enb_v) {
enb->work(&sf_cfg_dl, nullptr, nullptr, nullptr, nullptr, baseband_buffer, ts);
if (put_pdsch) {
// Reset pdsch put flag
put_pdsch = false;
// DCI Configuration
srslte_dci_dl_t dci;
srslte_dci_cfg_t dci_cfg;
dci_cfg.srs_request_enabled = false;
dci_cfg.ra_format_enabled = false;
dci_cfg.multiple_csi_request_enabled = false;
// DCI Fixed values
dci.pid = 0;
dci.pinfo = 0;
dci.rnti = serving_cell_pdsch_rnti;
dci.is_tdd = false;
dci.is_dwpts = false;
dci.is_ra_order = false;
dci.tb_cw_swap = false;
dci.pconf = false;
dci.power_offset = false;
dci.tpc_pucch = false;
dci.ra_preamble = false;
dci.ra_mask_idx = false;
dci.srs_request = false;
dci.srs_request_present = false;
dci.cif_present = false;
dci_cfg.cif_enabled = false;
// Set PRB Allocation type
dci.alloc_type = SRSLTE_RA_ALLOC_TYPE0;
prbset_num = (int)ceilf((float)cell_base.nof_prb / srslte_ra_type0_P(cell_base.nof_prb));
last_prbset_num = prbset_num;
dci.type0_alloc.rbg_bitmask = prbset_to_bitmask();
dci.location.L = 0;
dci.location.ncce = 0;
// Set TB
if (serving_cell_pdsch_tm < SRSLTE_TM3) {
dci.format = SRSLTE_DCI_FORMAT1;
dci.tb[0].mcs_idx = serving_cell_pdsch_mcs;
dci.tb[0].rv = 0;
dci.tb[0].ndi = false;
dci.tb[0].cw_idx = 0;
dci.tb[1].mcs_idx = 0;
dci.tb[1].rv = 1;
} else if (serving_cell_pdsch_tm == SRSLTE_TM3) {
dci.format = SRSLTE_DCI_FORMAT2A;
for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) {
dci.tb[i].mcs_idx = serving_cell_pdsch_mcs;
dci.tb[i].rv = 0;
dci.tb[i].ndi = false;
dci.tb[i].cw_idx = i;
}
} else if (serving_cell_pdsch_tm == SRSLTE_TM4) {
dci.format = SRSLTE_DCI_FORMAT2;
dci.pinfo = 0;
for (uint32_t i = 0; i < SRSLTE_MAX_TB; i++) {
dci.tb[i].mcs_idx = serving_cell_pdsch_mcs;
dci.tb[i].rv = 0;
dci.tb[i].ndi = false;
dci.tb[i].cw_idx = i;
}
} else {
ERROR("Wrong transmission mode (%d)\n", serving_cell_pdsch_tm);
}
enb->work(&sf_cfg_dl, &dci_cfg, &dci, softbuffer_tx, data_tx, baseband_buffer, ts);
} else {
enb->work(&sf_cfg_dl, nullptr, nullptr, nullptr, nullptr, baseband_buffer, ts);
}
}
}
srslte_timestamp_add(&ts, 0, 0.001f);
srslte_timestamp_add(&ts, 0, 0.001f);
intra_measure.write(k, baseband_buffer, SRSLTE_SF_LEN_PRB(cell_base.nof_prb));
if (k % 1000 == 0) {
printf("Done %.1f%%\n", (double)k * 100.0 / ((double)sim_time_periods * channel_period_s * 1000.0));
}
intra_measure.write(sf_idx % 10240, 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));
}
}
// Stop
intra_measure.stop();
srslte_dft_exit();
rrc.print_stats();
if (baseband_buffer) {
free(baseband_buffer);
}
}
Loading…
Cancel
Save