diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index ce0810cca..f0384a532 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -494,8 +494,10 @@ typedef struct { uint32_t cfo_loop_pss_conv; uint32_t cfo_ref_mask; bool average_subframe_enabled; + bool estimator_fil_auto; + float estimator_fil_stddev; + uint32_t estimator_fil_order; std::string sss_algorithm; - float estimator_fil_w; bool rssi_sensor_enabled; bool sic_pss_enabled; float rx_gain_offset; diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index a521d653e..5f7731305 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -74,6 +74,7 @@ typedef struct { float snr_vector[12000]; float pilot_power[12000]; #endif + bool smooth_filter_auto; uint32_t smooth_filter_len; float smooth_filter[SRSLTE_CHEST_MAX_SMOOTH_FIL_LEN]; @@ -123,6 +124,13 @@ SRSLTE_API void srslte_chest_dl_set_smooth_filter(srslte_chest_dl_t *q, SRSLTE_API void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w); +SRSLTE_API void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, + uint32_t order, + float std_dev); + +SRSLTE_API void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t* q, + bool enable); + SRSLTE_API void srslte_chest_dl_set_noise_alg(srslte_chest_dl_t *q, srslte_chest_dl_noise_alg_t noise_estimation_alg); diff --git a/lib/src/common/log_filter.cc b/lib/src/common/log_filter.cc index a86a36f1e..9602e202a 100644 --- a/lib/src/common/log_filter.cc +++ b/lib/src/common/log_filter.cc @@ -136,7 +136,7 @@ void log_filter::all_log(srslte::LOG_LEVEL_ENUM level, } void log_filter::console(const char * message, ...) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -147,7 +147,7 @@ void log_filter::console(const char * message, ...) { void log_filter::error(const char * message, ...) { if (level >= LOG_LEVEL_ERROR) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -158,7 +158,7 @@ void log_filter::error(const char * message, ...) { } void log_filter::warning(const char * message, ...) { if (level >= LOG_LEVEL_WARNING) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -169,7 +169,7 @@ void log_filter::warning(const char * message, ...) { } void log_filter::info(const char * message, ...) { if (level >= LOG_LEVEL_INFO) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -180,7 +180,7 @@ void log_filter::info(const char * message, ...) { } void log_filter::debug(const char * message, ...) { if (level >= LOG_LEVEL_DEBUG) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -192,7 +192,7 @@ void log_filter::debug(const char * message, ...) { void log_filter::error_hex(const uint8_t *hex, int size, const char * message, ...) { if (level >= LOG_LEVEL_ERROR) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -203,7 +203,7 @@ void log_filter::error_hex(const uint8_t *hex, int size, const char * message, . } void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, ...) { if (level >= LOG_LEVEL_WARNING) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -214,7 +214,7 @@ void log_filter::warning_hex(const uint8_t *hex, int size, const char * message, } void log_filter::info_hex(const uint8_t *hex, int size, const char * message, ...) { if (level >= LOG_LEVEL_INFO) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) @@ -225,7 +225,7 @@ void log_filter::info_hex(const uint8_t *hex, int size, const char * message, .. } void log_filter::debug_hex(const uint8_t *hex, int size, const char * message, ...) { if (level >= LOG_LEVEL_DEBUG) { - char *args_msg; + char *args_msg = NULL; va_list args; va_start(args, message); if(vasprintf(&args_msg, message, args) > 0) diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index e719b22c0..238cd1a18 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -155,6 +155,7 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) q->rsrp_neighbour = false; + q->smooth_filter_auto = false; q->smooth_filter_len = 3; srslte_chest_dl_set_smooth_filter3_coeff(q, 0.1); @@ -263,41 +264,66 @@ int srslte_chest_dl_set_cell(srslte_chest_dl_t *q, srslte_cell_t cell) /* Uses the difference between the averaged and non-averaged pilot estimates */ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id, srslte_sf_t ch_mode) { - int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + const float weight = 1.0f; + float sum_power = 0.0f; + uint32_t count = 0; + uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + uint32_t nsymbols = + (ch_mode == SRSLTE_SF_MBSFN) ? srslte_refsignal_mbsfn_nof_symbols() : srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nref = npilots / nsymbols; + uint32_t fidx = srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0); - if (q->average_subframe) { - if (ch_mode == SRSLTE_SF_MBSFN) { - nref /= 4; - } else { - nref /= 2; - } + cf_t *input2d[nsymbols + 2]; + cf_t *tmp_noise = q->tmp_noise; + + for (int i = 0; i < nsymbols; i++) { + input2d[i + 1] = &q->pilot_estimates[i * nref]; } - /* Substract noisy pilot estimates */ - srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); - -#ifdef FREQ_SEL_SNR - /* Compute frequency-selective SNR */ - srslte_vec_abs_square_cf(q->tmp_noise, q->snr_vector, nref); - srslte_vec_abs_square_cf(q->pilot_estimates, q->pilot_power, nref); - srslte_vec_div_fff(q->pilot_power, q->snr_vector, q->snr_vector, nref); - - srslte_vec_fprint_f(stdout, q->snr_vector, nref); -#endif - - /* Compute average power. Normalized for filter len 3 using matlab */ - float norm = 1; - if (q->average_subframe) { - norm = 32; + input2d[0] = &q->tmp_noise[0]; + if (nsymbols > 3) { + srslte_vec_sc_prod_cfc(input2d[2], 2.0f, input2d[0], nref); + srslte_vec_sub_ccc(input2d[0], input2d[4], input2d[0], nref); } else { - if (q->smooth_filter_len == 3) { - float a = q->smooth_filter[0]; - float norm3 = 6.143*a*a+0.04859*a-0.002774; - norm /= norm3; + srslte_vec_sc_prod_cfc(input2d[2], 1.0f, input2d[0], nref); + } + + input2d[nsymbols + 1] = &q->tmp_noise[nref]; + if (nsymbols > 3) { + srslte_vec_sc_prod_cfc(input2d[nsymbols - 1], 2.0f, input2d[nsymbols + 1], nref); + srslte_vec_sub_ccc(input2d[nsymbols + 1], input2d[nsymbols - 3], input2d[nsymbols + 1], nref); + } else { + srslte_vec_sc_prod_cfc(input2d[nsymbols - 1], 1.0f, input2d[nsymbols + 1], nref); + } + + for (int i = 1; i < nsymbols + 1; i++) { + uint32_t offset = ((fidx < 3) ^ (i & 1)) ? 0 : 1; + srslte_vec_sc_prod_cfc(input2d[i], weight, tmp_noise, nref); + + srslte_vec_sum_ccc(&input2d[i - 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset); + srslte_vec_sum_ccc(&input2d[i - 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1); + if (offset) { + tmp_noise[0] += 2.0f * input2d[i - 1][0] - input2d[i - 1][1]; + } else { + tmp_noise[nref - 1] += 2.0f * input2d[i - 1][nref - 2] - input2d[i - 1][nref - 1]; } + + srslte_vec_sum_ccc(&input2d[i + 1][0], &tmp_noise[offset], &tmp_noise[offset], nref - offset); + srslte_vec_sum_ccc(&input2d[i + 1][1 - offset], &tmp_noise[0], &tmp_noise[0], nref + offset - 1); + if (offset) { + tmp_noise[0] += 2.0f * input2d[i + 1][0] - input2d[i + 1][1]; + } else { + tmp_noise[nref - 1] += 2.0f * input2d[i + 1][nref - 2] - input2d[i + 1][nref - 1]; + } + + srslte_vec_sc_prod_cfc(tmp_noise, 1.0f / (weight + 4.0f), tmp_noise, nref); + + srslte_vec_sub_ccc(input2d[i], tmp_noise, tmp_noise, nref); + sum_power = srslte_vec_avg_power_cf(tmp_noise, nref); + count++; } - float power = norm*srslte_vec_avg_power_cf(q->tmp_noise, nref); - return power; + + return sum_power / (float) count * sqrtf(weight + 4.0f); } static float estimate_noise_pss(srslte_chest_dl_t *q, cf_t *input, cf_t *ce) @@ -443,6 +469,53 @@ void srslte_chest_dl_set_smooth_filter3_coeff(srslte_chest_dl_t* q, float w) q->smooth_filter[1] = 1-2*w; } +void srslte_chest_dl_set_smooth_filter_gauss(srslte_chest_dl_t* q, uint32_t order, float std_dev) +{ + const uint32_t filterlen = order + 1; + const int center = (filterlen - 1) / 2; + float *filter = q->smooth_filter; + float norm_p = 0.0f; + + if (filterlen) { + + for (int i = 0; i < filterlen; i++) { + filter[i] = expf(-powf(i - center, 2) / (2.0f * powf(std_dev, 2))); + norm_p += powf(filter[i], 2); + } + + const float norm = srslte_vec_acc_ff(filter, filterlen); + + srslte_vec_sc_prod_fff(filter, 1.0f / norm, filter, filterlen); + q->smooth_filter_len = filterlen; + } +} + +void srslte_chest_dl_set_smooth_filter_auto(srslte_chest_dl_t *q, bool enable) { + q->smooth_filter_auto = enable; +} + +uint32_t srslte_chest_dl_interleave_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *tmp, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) { + uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); + uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; + + if (srslte_refsignal_cs_fidx(q->cell, 0, port_id, 0) < 3) { + srslte_vec_interleave(input, &input[nref], tmp, nref); + for (int l = 2; l < nsymbols - 1; l += 2) { + srslte_vec_interleave_add(&input[l * nref], &input[(l + 1) * nref], tmp, nref); + } + } else { + srslte_vec_interleave(&input[nref], input, tmp, nref); + for (int l = 2; l < nsymbols - 1; l += 2) { + srslte_vec_interleave_add(&input[(l + 1) * nref], &input[l * nref], tmp, nref); + } + } + + nref *= 2; + srslte_vec_sc_prod_cfc(tmp, 2.0f / nsymbols, output, nref); + + return nref; +} + static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint32_t port_id, srslte_sf_t ch_mode) { uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN)?srslte_refsignal_mbsfn_nof_symbols(port_id):srslte_refsignal_cs_nof_symbols(port_id); uint32_t nref = (ch_mode == SRSLTE_SF_MBSFN)?6*q->cell.nof_prb:2*q->cell.nof_prb; @@ -523,7 +596,16 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui q->cfo = chest_estimate_cfo(q); } + /* Estimate noise */ + if (q->noise_alg == SRSLTE_NOISE_ALG_REFS) { + q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode); + } + if (ce != NULL) { + if (q->smooth_filter_auto) { + srslte_chest_dl_set_smooth_filter_gauss(q, 4, q->noise_estimate[rxant_id][port_id] * 200.0f); + } + /* Smooth estimates (if applicable) and interpolate */ if (q->smooth_filter_len == 0 || (q->smooth_filter_len == 3 && q->smooth_filter[0] == 0)) { interpolate_pilots(q, q->pilot_estimates, ce, port_id, ch_mode); @@ -533,13 +615,11 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui } /* Estimate noise power */ - if (q->noise_alg == SRSLTE_NOISE_ALG_REFS && q->smooth_filter_len > 0) { - q->noise_estimate[rxant_id][port_id] = estimate_noise_pilots(q, port_id, ch_mode); - } else if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) { + if (q->noise_alg == SRSLTE_NOISE_ALG_PSS) { if (sf_idx == 0 || sf_idx == 5) { q->noise_estimate[rxant_id][port_id] = estimate_noise_pss(q, input, ce); } - } else { + } else if (q->noise_alg != SRSLTE_NOISE_ALG_REFS) { if (sf_idx == 0 || sf_idx == 5) { q->noise_estimate[rxant_id][port_id] = estimate_noise_empty_sc(q, input); } diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index b66cf5b53..38355af92 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -41,7 +41,7 @@ #define MAX_TIME_OFFSET 128 -#define TRACK_MAX_LOST 4 +#define TRACK_MAX_LOST 100 #define TRACK_FRAME_SIZE 32 #define FIND_NOF_AVG_FRAMES 4 #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 diff --git a/lib/src/radio/radio.cc b/lib/src/radio/radio.cc index 7ef925f60..d4cc2aa6c 100644 --- a/lib/src/radio/radio.cc +++ b/lib/src/radio/radio.cc @@ -176,7 +176,7 @@ float radio::set_tx_power(float power) float radio::get_max_tx_power() { - return 10; + return 40; } float radio::get_rssi() diff --git a/srsenb/src/upper/rrc.cc b/srsenb/src/upper/rrc.cc index f47656c6d..93b9f8499 100644 --- a/srsenb/src/upper/rrc.cc +++ b/srsenb/src/upper/rrc.cc @@ -1447,6 +1447,8 @@ void rrc::ue::send_connection_reconf(srslte::byte_buffer_t *pdu) // Get DRB1 configuration if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[0], 1)) { parent->rrc_log->error("Getting DRB1 configuration\n"); + printf("The QCI %d for DRB1 is invalid or not configured.\n", erabs[5].qos_params.qCI.QCI); + return; } else { conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size = 1; } @@ -1524,8 +1526,10 @@ void rrc::ue::send_connection_reconf_new_bearer(LIBLTE_S1AP_E_RABTOBESETUPLISTBE uint8_t lcid = id - 2; // Map e.g. E-RAB 5 to LCID 3 (==DRB1) // Get DRB configuration - if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid)) { - parent->rrc_log->error("Getting DRB configuration\n"); + if (get_drbid_config(&conn_reconf->rr_cnfg_ded.drb_to_add_mod_list[i], lcid-2)) { + parent->rrc_log->error("Getting DRB configuration\n"); + printf("ERROR: The QCI %d is invalid or not configured.\n", erabs[lcid+4].qos_params.qCI.QCI); + return; } else { conn_reconf->rr_cnfg_ded.drb_to_add_mod_list_size++; } diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 5209c44d7..602ebd55b 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -134,7 +134,7 @@ class cell_t } void set_rsrp(float rsrp) { - if (~isnan(rsrp)) { + if (!isnan(rsrp)) { this->rsrp = rsrp; } in_sync = true; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index f0c733172..dd03541f8 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -261,14 +261,22 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { bpo::value(&args->expert.phy.average_subframe_enabled)->default_value(true), "Averages in the time domain the channel estimates within 1 subframe. Needs accurate CFO correction.") + ("expert.estimator_fil_auto", + bpo::value(&args->expert.phy.estimator_fil_auto)->default_value(false), + "The channel estimator smooths the channel estimate with an adaptative filter.") + + ("expert.estimator_fil_stddev", + bpo::value(&args->expert.phy.estimator_fil_stddev)->default_value(1.0f), + "Sets the channel estimator smooth gaussian filter standard deviation.") + + ("expert.estimator_fil_order", + bpo::value(&args->expert.phy.estimator_fil_order)->default_value(4), + "Sets the channel estimator smooth gaussian filter order (even values perform better).") + ("expert.sss_algorithm", bpo::value(&args->expert.phy.sss_algorithm)->default_value("full"), "Selects the SSS estimation algorithm.") - ("expert.estimator_fil_w", - bpo::value(&args->expert.phy.estimator_fil_w)->default_value(0.1), - "Chooses the coefficients for the 3-tap channel estimator centered filter.") - ("expert.pdsch_csi_enabled", bpo::value(&args->expert.phy.pdsch_csi_enabled)->default_value(false), "Stores the Channel State Information and uses it for weightening the softbits. It is only compatible with TM1.") diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 627bddaa1..663cb52db 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -444,12 +444,10 @@ bool phch_worker::extract_fft_and_pdcch_llr() { // Do always channel estimation to keep track of out-of-sync and send measurements to RRC // Setup estimator filter - float w_coeff = phy->args->estimator_fil_w; - if (w_coeff > 0.0) { - srslte_chest_dl_set_smooth_filter3_coeff(&ue_dl.chest, w_coeff); - } else if (w_coeff == 0.0) { - srslte_chest_dl_set_smooth_filter(&ue_dl.chest, NULL, 0); - } + srslte_chest_dl_set_smooth_filter_gauss(&ue_dl.chest, + phy->args->estimator_fil_order, + phy->args->estimator_fil_stddev); + srslte_chest_dl_set_smooth_filter_auto(&ue_dl.chest, phy->args->estimator_fil_auto); if (!phy->args->snr_estim_alg.compare("refs")) { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_REFS); @@ -459,6 +457,12 @@ bool phch_worker::extract_fft_and_pdcch_llr() { srslte_chest_dl_set_noise_alg(&ue_dl.chest, SRSLTE_NOISE_ALG_PSS); } + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { + Error("Getting PDCCH FFT estimate\n"); + return false; + } + chest_done = true; + if (srslte_ue_dl_decode_fft_estimate(&ue_dl, tti%10, &cfi) < 0) { Error("Getting PDCCH FFT estimate\n"); return false; diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index f0187b3f6..875fc483c 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -97,7 +97,9 @@ void phy::set_default_args(phy_args_t *args) args->cfo_integer_enabled = false; args->cfo_correct_tol_hz = 50; args->sss_algorithm = "full"; - args->estimator_fil_w = 0.1; + args->estimator_fil_auto = false; + args->estimator_fil_stddev = 1.0f; + args->estimator_fil_order = 4; } bool phy::check_args(phy_args_t *args) @@ -106,10 +108,6 @@ bool phy::check_args(phy_args_t *args) log_h->console("Error in PHY args: nof_phy_threads must be 1, 2 or 3\n"); return false; } - if (args->estimator_fil_w > 1.0) { - log_h->console("Error in PHY args: estimator_fil_w must be 0<=w<=1\n"); - return false; - } if (args->snr_ema_coeff > 1.0) { log_h->console("Error in PHY args: snr_ema_coeff must be 0<=w<=1\n"); return false; diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index a3de1a678..531381431 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -150,7 +150,9 @@ enable = false # sampling frequency offset. Default is enabled. # sss_algorithm: Selects the SSS estimation algorithm. Can choose between # {full, partial, diff}. -# estimator_fil_w: Chooses the coefficients for the 3-tap channel estimator centered filter. +# estimator_fil_auto: The channel estimator smooths the channel estimate with an adaptative filter. +# estimator_fil_stddev: Sets the channel estimator smooth gaussian filter standard deviation. +# estimator_fil_order: Sets the channel estimator smooth gaussian filter order (even values perform better). # The taps are [w, 1-2w, w] # metrics_period_secs: Sets the period at which metrics are requested from the UE. # @@ -204,7 +206,9 @@ enable = false #time_correct_period = 5 #sfo_correct_disable = false #sss_algorithm = full -#estimator_fil_w = 0.1 +#estimator_fil_auto = false +#estimator_fil_stddev = 1.0 +#estimator_fil_order = 4 #average_subframe_enabled = true #sic_pss_enabled = true #pregenerate_signals = false