diff --git a/CMakeLists.txt b/CMakeLists.txt index 5da6ac51bc..d2654b2709 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,7 @@ option(FORCE_32BIT "Add flags to force 32 bit compilation" OFF) option(ENABLE_SRSLOG_TRACING "Enable event tracing using srslog" OFF) option(ASSERTS_ENABLED "Enable srsRAN asserts" ON) option(STOP_ON_WARNING "Interrupt application on warning" OFF) +option(ENABLE_WERROR "Stop compilation on errors" ON) option(ENABLE_ALL_TEST "Enable all unit/component test" OFF) @@ -537,7 +538,7 @@ if("Ninja" STREQUAL ${CMAKE_GENERATOR}) endif() # Add -Werror to C/C++ flags for newer compilers -if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) +if(ENABLE_WERROR AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") endif() diff --git a/lib/include/srsran/phy/ch_estimation/cedron_freq_estimator.h b/lib/include/srsran/phy/ch_estimation/cedron_freq_estimator.h new file mode 100644 index 0000000000..865b0555aa --- /dev/null +++ b/lib/include/srsran/phy/ch_estimation/cedron_freq_estimator.h @@ -0,0 +1,39 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2023 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_CEDRON_FREQ_ESTIMATOR_H +#define SRSRAN_CEDRON_FREQ_ESTIMATOR_H + +#include "srsran/config.h" +#include "srsran/phy/common/phy_common.h" +#include + +typedef struct { + // DFT + void* in; // Input buffer + void* out; // Output buffer + void* p; // DFT plan + cf_t* X; // Output buffer as cf_t* + int init_size; + int fft_size; // Currently used FFT size + +} srsran_cedron_freq_est_t; + +SRSRAN_API int srsran_cedron_freq_est_init(srsran_cedron_freq_est_t* q, uint32_t nof_prbs); + +SRSRAN_API void srsran_cedron_freq_est_free(srsran_cedron_freq_est_t* q); + +SRSRAN_API int srsran_cedron_freq_est_replan_c(srsran_cedron_freq_est_t* q, int new_dft_points); + +SRSRAN_API float srsran_cedron_freq_estimate(srsran_cedron_freq_est_t* q, const cf_t* x, int len); + +#endif // SRSRAN_CEDRON_FREQ_ESTIMATOR_H diff --git a/lib/include/srsran/phy/ch_estimation/chest_ul.h b/lib/include/srsran/phy/ch_estimation/chest_ul.h index ddd1cb6b61..476a0ee05b 100644 --- a/lib/include/srsran/phy/ch_estimation/chest_ul.h +++ b/lib/include/srsran/phy/ch_estimation/chest_ul.h @@ -38,6 +38,7 @@ #include "srsran/config.h" +#include "srsran/phy/ch_estimation/cedron_freq_estimator.h" #include "srsran/phy/ch_estimation/chest_common.h" #include "srsran/phy/ch_estimation/refsignal_ul.h" #include "srsran/phy/common/phy_common.h" @@ -85,6 +86,7 @@ typedef struct { srsran_interp_linsrsran_vec_t srsran_interp_linvec; + srsran_cedron_freq_est_t srsran_cedron_freq_est; } srsran_chest_ul_t; SRSRAN_API int srsran_chest_ul_init(srsran_chest_ul_t* q, uint32_t max_prb); diff --git a/lib/include/srsran/phy/phch/pucch_cfg.h b/lib/include/srsran/phy/phch/pucch_cfg.h index af42cc2582..5d4f3dfb69 100644 --- a/lib/include/srsran/phy/phch/pucch_cfg.h +++ b/lib/include/srsran/phy/phch/pucch_cfg.h @@ -78,6 +78,7 @@ typedef struct SRSRAN_API { float threshold_data_valid_format3; float threshold_dmrs_detection; bool meas_ta_en; + bool use_cedron_alg; // PUCCH configuration generated during a call to encode/decode srsran_pucch_format_t format; diff --git a/lib/include/srsran/phy/phch/pusch_cfg.h b/lib/include/srsran/phy/phch/pusch_cfg.h index 6daebd68e2..3ece1024f1 100644 --- a/lib/include/srsran/phy/phch/pusch_cfg.h +++ b/lib/include/srsran/phy/phch/pusch_cfg.h @@ -81,6 +81,7 @@ typedef struct SRSRAN_API { bool meas_epre_en; bool meas_ta_en; + bool use_cedron_alg; bool meas_evm_en; } srsran_pusch_cfg_t; diff --git a/lib/include/srsran/radio/channel_mapping.h b/lib/include/srsran/radio/channel_mapping.h index 3e1fe5f3ff..05a480d0ee 100644 --- a/lib/include/srsran/radio/channel_mapping.h +++ b/lib/include/srsran/radio/channel_mapping.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace srsran { diff --git a/lib/include/srsran/srsran.h b/lib/include/srsran/srsran.h index 04d636083d..55e3f93043 100644 --- a/lib/include/srsran/srsran.h +++ b/lib/include/srsran/srsran.h @@ -46,6 +46,7 @@ extern "C" { #include "srsran/phy/common/timestamp.h" #include "srsran/phy/utils/phy_logger.h" +#include "srsran/phy/ch_estimation/cedron_freq_estimator.h" #include "srsran/phy/ch_estimation/chest_dl.h" #include "srsran/phy/ch_estimation/chest_ul.h" #include "srsran/phy/ch_estimation/csi_rs.h" diff --git a/lib/src/common/band_helper.cc b/lib/src/common/band_helper.cc index 2e00797d77..5ee7abfeb2 100644 --- a/lib/src/common/band_helper.cc +++ b/lib/src/common/band_helper.cc @@ -124,7 +124,7 @@ double srsran_band_helper::get_center_freq_from_abs_freq_point_a(uint32_t nof_pr // TODO: add offset_to_carrier double abs_freq_point_a_freq = nr_arfcn_to_freq(freq_point_a_arfcn); return abs_freq_point_a_freq + - (nof_prb / 2 * SRSRAN_SUBC_SPACING_NR(srsran_subcarrier_spacing_t::srsran_subcarrier_spacing_15kHz) * + (1.0 * nof_prb / 2 * SRSRAN_SUBC_SPACING_NR(srsran_subcarrier_spacing_t::srsran_subcarrier_spacing_15kHz) * SRSRAN_NRE); } diff --git a/lib/src/phy/ch_estimation/cedron_freq_estimator.c b/lib/src/phy/ch_estimation/cedron_freq_estimator.c new file mode 100644 index 0000000000..92c26794ab --- /dev/null +++ b/lib/src/phy/ch_estimation/cedron_freq_estimator.c @@ -0,0 +1,154 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2023 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include +#include +#include + +#include "srsran/config.h" +#include "srsran/phy/ch_estimation/cedron_freq_estimator.h" +#include "srsran/phy/utils/vector_simd.h" +#include "srsran/srsran.h" +#include + +static pthread_mutex_t freq_est_fft_mutex = PTHREAD_MUTEX_INITIALIZER; + +int srsran_cedron_freq_est_init(srsran_cedron_freq_est_t* q, uint32_t nof_prbs) +{ + int ret = SRSRAN_ERROR_INVALID_INPUTS; + int N = SRSRAN_MAX_PRB * SRSRAN_NRE; + if (q != NULL) { + bzero(q, sizeof(srsran_cedron_freq_est_t)); + + q->init_size = N; + q->fft_size = nof_prbs * SRSRAN_NRE; + q->in = fftwf_malloc(sizeof(fftwf_complex) * N); + if (!q->in) { + perror("fftwf_malloc"); + goto clean_exit; + } + q->out = fftwf_malloc(sizeof(fftwf_complex) * N); + if (!q->out) { + perror("fftwf_malloc"); + goto clean_exit; + } + + pthread_mutex_lock(&freq_est_fft_mutex); + q->p = fftwf_plan_dft_1d(q->fft_size, q->in, q->out, FFTW_FORWARD, 0U); + pthread_mutex_unlock(&freq_est_fft_mutex); + + if (!q->p) { + perror("fftwf_plan_dft_1d"); + goto clean_exit; + } + q->X = q->out; + } + + ret = SRSRAN_SUCCESS; + +clean_exit: + if (ret != SRSRAN_SUCCESS) { + srsran_cedron_freq_est_free(q); + } + return ret; +} + +void srsran_cedron_freq_est_free(srsran_cedron_freq_est_t* q) +{ + if (!q) { + return; + } + pthread_mutex_lock(&freq_est_fft_mutex); + if (q->in) { + fftwf_free(q->in); + } + if (q->out) { + fftwf_free(q->out); + } + if (q->p) { + fftwf_destroy_plan(q->p); + q->p = NULL; + } + q->X = NULL; + pthread_mutex_unlock(&freq_est_fft_mutex); + bzero(q, sizeof(srsran_cedron_freq_est_t)); +} + +int srsran_cedron_freq_est_replan_c(srsran_cedron_freq_est_t* q, int new_dft_points) +{ + // No change in size, skip re-planning + if (q->fft_size == new_dft_points) { + return 0; + } + + pthread_mutex_lock(&freq_est_fft_mutex); + if (q->p) { + fftwf_destroy_plan(q->p); + q->p = NULL; + } + q->p = fftwf_plan_dft_1d(new_dft_points, q->in, q->out, FFTW_FORWARD, FFTW_MEASURE); + pthread_mutex_unlock(&freq_est_fft_mutex); + + if (!q->p) { + return -1; + } + q->fft_size = new_dft_points; + return 0; +} + +float srsran_cedron_freq_estimate(srsran_cedron_freq_est_t* q, const cf_t* x, int N) +{ + /* + * Three Bin Exact Frequency Formulas for a Pure Complex Tone in a DFT + * Cedron Dawg + * https://www.dsprelated.com/showarticle/1043.php + */ + const float TWOPI = 2.0f * (float)M_PI; + cf_t Z[3], R1, num, den, ratio; + float alpha, f_est; + int32_t k_max; + + if (N != q->fft_size) { + srsran_cedron_freq_est_replan_c(q, N); + } + + memcpy(q->in, x, sizeof(cf_t) * N); + fftwf_execute(q->p); + + k_max = srsran_vec_max_ci_simd(q->X, N); + if (k_max == 0) { + Z[0] = q->X[N - 1]; + Z[1] = q->X[0]; + Z[2] = q->X[1]; + } else if (k_max == N - 1) { + Z[0] = q->X[N - 2]; + Z[1] = q->X[N - 1]; + Z[2] = q->X[0]; + } else { + Z[0] = q->X[k_max - 1]; + Z[1] = q->X[k_max]; + Z[2] = q->X[k_max + 1]; + } + + R1 = cexpf(-1.0 * _Complex_I * TWOPI / N); + num = -R1 * Z[0] + (1 + R1) * Z[1] - Z[2]; + den = -Z[0] + (1 + R1) * Z[1] - R1 * Z[2]; + srsran_vec_div_ccc_simd(&num, &den, &ratio, 1); + alpha = atan2f(__imag__(ratio), __real__(ratio)); + + if (k_max > floor(N / 2)) { + k_max = -(N - k_max); + } + f_est = 1.0 * k_max / N + alpha * M_1_PI * 0.5f; + + return -f_est; +} \ No newline at end of file diff --git a/lib/src/phy/ch_estimation/chest_ul.c b/lib/src/phy/ch_estimation/chest_ul.c index d266761668..43217b54fe 100644 --- a/lib/src/phy/ch_estimation/chest_ul.c +++ b/lib/src/phy/ch_estimation/chest_ul.c @@ -28,6 +28,7 @@ #include #include "srsran/config.h" +#include "srsran/phy/ch_estimation/cedron_freq_estimator.h" #include "srsran/phy/ch_estimation/chest_ul.h" #include "srsran/phy/dft/dft_precoding.h" #include "srsran/phy/utils/convolution.h" @@ -98,6 +99,11 @@ int srsran_chest_ul_init(srsran_chest_ul_t* q, uint32_t max_prb) ERROR("Error allocating memory for pregenerated signals"); goto clean_exit; } + + if (srsran_cedron_freq_est_init(&q->srsran_cedron_freq_est, max_prb)) { + ERROR("Error initializing cedron freq estimation algorithm."); + goto clean_exit; + } } ret = SRSRAN_SUCCESS; @@ -117,6 +123,7 @@ void srsran_chest_ul_free(srsran_chest_ul_t* q) free(q->tmp_noise); } srsran_interp_linear_vector_free(&q->srsran_interp_linvec); + srsran_cedron_freq_est_free(&q->srsran_cedron_freq_est); if (q->pilot_estimates) { free(q->pilot_estimates); @@ -293,6 +300,7 @@ static void chest_ul_estimate(srsran_chest_ul_t* q, uint32_t nrefs_sym, uint32_t stride, bool meas_ta_en, + bool use_cedron_alg, bool write_estimates, uint32_t n_prb[SRSRAN_NOF_SLOTS_PER_SF], srsran_chest_ul_res_t* res) @@ -310,7 +318,13 @@ static void chest_ul_estimate(srsran_chest_ul_t* q, float ta_err = 0.0f; if (meas_ta_en) { for (int i = 0; i < nslots; i++) { - ta_err += srsran_vec_estimate_frequency(&q->pilot_estimates[i * nrefs_sym], nrefs_sym) / nslots; + if (use_cedron_alg) { + ta_err += + srsran_cedron_freq_estimate(&q->srsran_cedron_freq_est, &q->pilot_estimates[i * nrefs_sym], nrefs_sym) / + nslots; + } else { + ta_err += srsran_vec_estimate_frequency(&q->pilot_estimates[i * nrefs_sym], nrefs_sym) / nslots; + } } } @@ -412,7 +426,8 @@ int srsran_chest_ul_estimate_pusch(srsran_chest_ul_t* q, nrefs_sf); // Estimate - chest_ul_estimate(q, SRSRAN_NOF_SLOTS_PER_SF, nrefs_sym, 1, cfg->meas_ta_en, true, cfg->grant.n_prb, res); + chest_ul_estimate( + q, SRSRAN_NOF_SLOTS_PER_SF, nrefs_sym, 1, cfg->meas_ta_en, cfg->use_cedron_alg, true, cfg->grant.n_prb, res); return 0; } @@ -515,8 +530,14 @@ int srsran_chest_ul_estimate_pucch(srsran_chest_ul_t* q, float ta_err = 0.0f; for (int ns = 0; ns < SRSRAN_NOF_SLOTS_PER_SF; ns++) { for (int i = 0; i < n_rs; i++) { - ta_err += srsran_vec_estimate_frequency(&q->pilot_estimates[(i + ns * n_rs) * SRSRAN_NRE], SRSRAN_NRE) / - (float)(SRSRAN_NOF_SLOTS_PER_SF * n_rs); + if (cfg->use_cedron_alg) { + ta_err += srsran_cedron_freq_estimate( + &q->srsran_cedron_freq_est, &q->pilot_estimates[(i + ns * n_rs) * SRSRAN_NRE], SRSRAN_NRE) / + (float)(SRSRAN_NOF_SLOTS_PER_SF * n_rs); + } else { + ta_err += srsran_vec_estimate_frequency(&q->pilot_estimates[(i + ns * n_rs) * SRSRAN_NRE], SRSRAN_NRE) / + (float)(SRSRAN_NOF_SLOTS_PER_SF * n_rs); + } } } @@ -620,7 +641,7 @@ int srsran_chest_ul_estimate_srs(srsran_chest_ul_t* q, // Estimate uint32_t n_prb[2] = {}; - chest_ul_estimate(q, 1, n_srs_re, 1, true, false, n_prb, res); + chest_ul_estimate(q, 1, n_srs_re, 1, true, false, false, n_prb, res); return SRSRAN_SUCCESS; } diff --git a/lib/src/phy/fec/convolutional/viterbi37_avx2.c b/lib/src/phy/fec/convolutional/viterbi37_avx2.c index 0749bfdf42..48e0698315 100644 --- a/lib/src/phy/fec/convolutional/viterbi37_avx2.c +++ b/lib/src/phy/fec/convolutional/viterbi37_avx2.c @@ -11,6 +11,7 @@ #include #include #include +#include //#define DEBUG diff --git a/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c b/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c index 6d143dbb1f..56c182d9ff 100644 --- a/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c +++ b/lib/src/phy/fec/convolutional/viterbi37_avx2_16bit.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include //#define DEBUG diff --git a/lib/src/phy/fec/convolutional/viterbi37_port.c b/lib/src/phy/fec/convolutional/viterbi37_port.c index 122dfd1884..b1698df20e 100644 --- a/lib/src/phy/fec/convolutional/viterbi37_port.c +++ b/lib/src/phy/fec/convolutional/viterbi37_port.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "parity.h" #include "viterbi37.h" diff --git a/lib/src/phy/fec/convolutional/viterbi37_sse.c b/lib/src/phy/fec/convolutional/viterbi37_sse.c index 2730c8c017..3e49ad0929 100644 --- a/lib/src/phy/fec/convolutional/viterbi37_sse.c +++ b/lib/src/phy/fec/convolutional/viterbi37_sse.c @@ -11,6 +11,7 @@ #include #include #include +#include //#define DEBUG diff --git a/lib/src/phy/fec/polar/polar_interleaver.c b/lib/src/phy/fec/polar/polar_interleaver.c index 41106736b3..bbb48212f8 100644 --- a/lib/src/phy/fec/polar/polar_interleaver.c +++ b/lib/src/phy/fec/polar/polar_interleaver.c @@ -23,6 +23,7 @@ #include "srsran/phy/utils/vector.h" #include #include +#include // Table 5.3.1.1-1: Interleaving pattern static const uint16_t polar_interleaver_pattern[SRSRAN_POLAR_INTERLEAVER_K_MAX_IL] = { diff --git a/lib/src/phy/utils/mat.c b/lib/src/phy/utils/mat.c index a2ee0b9a04..4d03508004 100644 --- a/lib/src/phy/utils/mat.c +++ b/lib/src/phy/utils/mat.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "srsran/phy/utils/mat.h" diff --git a/lib/src/phy/utils/test/CMakeLists.txt b/lib/src/phy/utils/test/CMakeLists.txt index f33cd17a79..7953180169 100644 --- a/lib/src/phy/utils/test/CMakeLists.txt +++ b/lib/src/phy/utils/test/CMakeLists.txt @@ -33,6 +33,9 @@ add_test(dft_dc dft_test -b -d) # Backwards first & handle dc internally add_test(dft_odd dft_test -N 255) # Odd-length add_test(dft_odd_dc dft_test -N 255 -b -d) # Odd-length, backwards first, handle dc +add_executable(freq_est_test freq_est_test.c) +target_link_libraries(freq_est_test srsran_phy) + ######################################################################## # Algebra TEST ######################################################################## diff --git a/lib/src/phy/utils/test/freq_est_test.c b/lib/src/phy/utils/test/freq_est_test.c new file mode 100644 index 0000000000..331afbe210 --- /dev/null +++ b/lib/src/phy/utils/test/freq_est_test.c @@ -0,0 +1,154 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/phy/utils/debug.h" +#include "srsran/phy/utils/random.h" +#include +#include +#include +#include +#include +#include +#include + +#include "srsran/phy/ch_estimation/cedron_freq_estimator.h" +#include "srsran/phy/dft/dft.h" +#include "srsran/phy/utils/vector.h" + +static bool verbose = false; +#define MAXIMUM_ERROR (1e-6f) + +double elapsed_us(struct timeval* ts_start, struct timeval* ts_end) +{ + if (ts_end->tv_usec > ts_start->tv_usec) { + return ((double)ts_end->tv_sec - (double)ts_start->tv_sec) * 1000000 + (double)ts_end->tv_usec - + (double)ts_start->tv_usec; + } else { + return ((double)ts_end->tv_sec - (double)ts_start->tv_sec - 1) * 1000000 + ((double)ts_end->tv_usec + 1000000) - + (double)ts_start->tv_usec; + } +} + +#define RUN_TEST(FUNCTION) \ + do { \ + int nof_prb; \ + struct timeval start, end; \ + gettimeofday(&start, NULL); \ + bool passed_ = true; \ + for (nof_prb = 1; nof_prb < SRSRAN_MAX_PRB; nof_prb++) { \ + passed_ &= FUNCTION(nof_prb); \ + } \ + gettimeofday(&end, NULL); \ + if (verbose) \ + printf("%32s: %s ... %6.2f us/call\n", \ + #FUNCTION, \ + (passed_) ? "Pass" : "Fail", \ + elapsed_us(&start, &end) / SRSRAN_MAX_PRB); \ + passed &= passed_; \ + } while (false) + +static bool test_cedron_estimate_frequency(int nof_prbs) +{ + srsran_cedron_freq_est_t srsran_cedron_freq_est; + float freq_gold = 0.2f; + float freq = 0.0f; + float mse = 0.0f; + uint32_t nof_sym = nof_prbs * SRSRAN_NRE; + + cf_t* x = srsran_vec_malloc(sizeof(cf_t) * nof_sym); + if (srsran_cedron_freq_est_init(&srsran_cedron_freq_est, nof_prbs)) { + ERROR("Error initializing cedron freq estimation algorithm."); + return false; + } + + for (int i = 0; i < nof_sym; i++) { + x[i] = cexpf(-I * 2.0f * M_PI * (float)i * freq_gold); + } + + freq = srsran_cedron_freq_estimate(&srsran_cedron_freq_est, x, nof_sym); + mse = fabsf(freq - freq_gold); + free(x); + srsran_cedron_freq_est_free(&srsran_cedron_freq_est); + if (verbose) + printf("Nof PRBs %i, mse %f\n", nof_prbs, mse); + + return (mse < MAXIMUM_ERROR); +} + +bool test_real_signal(void) +{ + uint32_t nof_prbs = 4; + uint32_t nrefs_sym = nof_prbs * SRSRAN_NRE; + float ta_err_cedron = 0; + float ta_err_srs = 0; + srsran_cedron_freq_est_t srsran_cedron_freq_est; + + // Sniffed UL REF signal with low SNR. + cf_t cp_pilots[48] = {22.162853 - 26.839521 * 1i, -12.896494 + 3.750004 * 1i, 43.889961 + 7.452690 * 1i, + 36.788181 + 3.699238 * 1i, 19.841988 + 2.327892 * 1i, -8.030174 + 15.597110 * 1i, + 23.685257 + 9.359170 * 1i, -0.184066 + 14.776085 * 1i, 54.138931 + 14.602448 * 1i, + 33.998699 + 11.438558 * 1i, 8.634534 + 23.158798 * 1i, 11.593168 + 14.001324 * 1i, + -4.070977 - 28.250189 * 1i, 18.821701 + 1.274709 * 1i, -2.113699 - 2.322813 * 1i, + -1.980798 - 2.809317 * 1i, -16.248312 + 16.282543 * 1i, 4.916372 - 8.317366 * 1i, + 19.537739 + 5.440768 * 1i, 19.273443 + 21.419304 * 1i, 9.158796 - 14.670293 * 1i, + 12.963399 + 16.209164 * 1i, -10.091204 - 0.774263 * 1i, 52.113579 - 62.882523 * 1i, + -45.814278 - 3.351721 * 1i, 16.937546 + 32.659332 * 1i, -2.446608 + 2.216692 * 1i, + -13.836332 + 19.213146 * 1i, -21.508173 + 43.013851 * 1i, -21.323523 + 21.740101 * 1i, + -2.203827 - 12.458035 * 1i, 0.313410 - 8.307796 * 1i, -15.429630 + 14.476921 * 1i, + -8.512527 + 34.065918 * 1i, -16.693293 + 31.356386 * 1i, -34.033825 + 5.859118 * 1i, + -11.836067 + 20.825031 * 1i, -24.690987 + 41.358925 * 1i, -11.794442 + 3.393625 * 1i, + -18.838444 + 9.678068 * 1i, 7.530683 + 42.732479 * 1i, -17.050388 + 32.361870 * 1i, + -3.941456 + 13.747462 * 1i, -19.360886 + 11.063116 * 1i, -16.969175 + 30.928513 * 1i, + -14.056345 - 35.506645 * 1i, -23.354206 - 9.430195 * 1i, 3.566646 - 14.499187 * 1i}; + + if (srsran_cedron_freq_est_init(&srsran_cedron_freq_est, nof_prbs)) { + ERROR("Error initializing cedron freq estimation algorithm."); + return false; + } + + ta_err_cedron = srsran_cedron_freq_estimate(&srsran_cedron_freq_est, cp_pilots, nrefs_sym); + ta_err_srs = srsran_vec_estimate_frequency(cp_pilots, nrefs_sym); + if (verbose) { + printf("Cedron ta_err = %f \n", ta_err_cedron); + printf("SRS ta_err = %f \n", ta_err_srs); + } + + ta_err_cedron /= 15e3f; // Convert from normalized frequency to seconds + ta_err_cedron *= 1e6f; // Convert to micro-seconds + ta_err_srs /= 15e3f; // Convert from normalized frequency to seconds + ta_err_srs *= 1e6f; // Convert to micro-seconds + + if (verbose) { + printf("Cedron TA_err %.1f \n", ta_err_srs); + printf("SRS TA_err %.1f \n", ta_err_srs); + } + + srsran_cedron_freq_est_free(&srsran_cedron_freq_est); + return true; +} + +int main(int argc, char** argv) +{ + bool passed = true; + int ret = SRSRAN_SUCCESS; + + RUN_TEST(test_cedron_estimate_frequency); + passed &= test_real_signal(); + + printf("%s!\n", (passed) ? "Ok" : "Failed"); + + if (!passed) { + ret = SRSRAN_ERROR; + } + + return ret; +} diff --git a/srsenb/enb.conf.example b/srsenb/enb.conf.example index 51f7b58062..432e923b2e 100644 --- a/srsenb/enb.conf.example +++ b/srsenb/enb.conf.example @@ -424,6 +424,7 @@ enable = false # s1_setup_max_retries: Maximum amount of retries to setup the S1AP connection. If this value is exceeded, an alarm is written to the log. -1 means infinity. # s1_connect_timer: Connection Retry Timer for S1 connection (seconds) # rx_gain_offset: RX Gain offset to add to rx_gain to calibrate RSRP readings +# use_cedron_f_est_alg: Whether to use Cedron algorithm for TA estimation or not (Default: false) ##################################################################### [expert] #pusch_max_its = 8 # These are half iterations @@ -462,3 +463,4 @@ enable = false #s1_connect_timer = 10 #rx_gain_offset = 62 #mac_prach_bi = 0 +#use_cedron_f_est_alg = false diff --git a/srsenb/hdr/phy/phy_interfaces.h b/srsenb/hdr/phy/phy_interfaces.h index 4a03f16632..0fa6969739 100644 --- a/srsenb/hdr/phy/phy_interfaces.h +++ b/srsenb/hdr/phy/phy_interfaces.h @@ -72,6 +72,7 @@ struct phy_args_t { bool pusch_meas_evm = false; bool pusch_meas_ta = true; bool pucch_meas_ta = true; + bool use_cedron_alg = false; uint32_t nof_prach_threads = 1; bool extended_cp = false; srsran::channel::args_t dl_channel_args; diff --git a/srsenb/src/main.cc b/srsenb/src/main.cc index 2c7d19e24c..4f405c2d92 100644 --- a/srsenb/src/main.cc +++ b/srsenb/src/main.cc @@ -292,6 +292,7 @@ void parse_args(all_args_t* args, int argc, char* argv[]) ("expert.sctp_max_init_timeo)", bpo::value(&args->stack.s1ap.sctp_max_init_timeo)->default_value(5000), "Maximum SCTP init timeout.") ("expert.rx_gain_offset", bpo::value(&args->phy.rx_gain_offset)->default_value(62), "RX Gain offset to add to rx_gain to calibrate RSRP readings") ("expert.mac_prach_bi", bpo::value(&args->stack.mac.prach_bi)->default_value(0), "Backoff Indicator to reduce contention in the PRACH channel") + ("expert.use_cedron_f_est_alg", bpo::value(&args->phy.use_cedron_alg)->default_value(false), "Whether to use Cedron freq estimation algorithm or not") // eMBMS section ("embms.enable", bpo::value(&args->stack.embms.enable)->default_value(false), "Enables MBMS in the eNB") diff --git a/srsenb/src/phy/phy_ue_db.cc b/srsenb/src/phy/phy_ue_db.cc index 93b64bfd4c..0e95aa2e61 100644 --- a/srsenb/src/phy/phy_ue_db.cc +++ b/srsenb/src/phy/phy_ue_db.cc @@ -99,6 +99,7 @@ inline void phy_ue_db::_set_common_config_rnti(uint16_t rnti, srsran::phy_cfg_t& phy_cfg.ul_cfg.pusch.meas_time_en = true; phy_cfg.ul_cfg.pusch.meas_epre_en = phy_args->pusch_meas_epre; phy_cfg.ul_cfg.pusch.meas_ta_en = phy_args->pusch_meas_ta; + phy_cfg.ul_cfg.pusch.use_cedron_alg = phy_args->use_cedron_alg; phy_cfg.ul_cfg.pusch.meas_evm_en = phy_args->pusch_meas_evm; phy_cfg.ul_cfg.pusch.max_nof_iterations = phy_args->pusch_max_its; phy_cfg.ul_cfg.pucch.threshold_format1 = SRSRAN_PUCCH_DEFAULT_THRESHOLD_FORMAT1; @@ -107,6 +108,7 @@ inline void phy_ue_db::_set_common_config_rnti(uint16_t rnti, srsran::phy_cfg_t& phy_cfg.ul_cfg.pucch.threshold_data_valid_format3 = SRSRAN_PUCCH_DEFAULT_THRESHOLD_FORMAT3; phy_cfg.ul_cfg.pucch.threshold_dmrs_detection = SRSRAN_PUCCH_DEFAULT_THRESHOLD_DMRS; phy_cfg.ul_cfg.pucch.meas_ta_en = phy_args->pucch_meas_ta; + phy_cfg.ul_cfg.pucch.use_cedron_alg = phy_args->use_cedron_alg; } inline uint32_t phy_ue_db::_get_ue_cc_idx(uint16_t rnti, uint32_t enb_cc_idx) const diff --git a/srsue/src/stack/mac_nr/proc_bsr_nr.cc b/srsue/src/stack/mac_nr/proc_bsr_nr.cc index 7355b0fe6b..3c778e5dec 100644 --- a/srsue/src/stack/mac_nr/proc_bsr_nr.cc +++ b/srsue/src/stack/mac_nr/proc_bsr_nr.cc @@ -256,13 +256,14 @@ int proc_bsr_nr::setup_lcid(uint32_t lcid, uint32_t new_lcg, uint32_t priority) std::lock_guard lock(mutex); // Check that the new priority doesn't not already exist - if (lcg_priorities.find(priority) != lcg_priorities.end()) { + auto it = lcg_priorities.find(priority); + if (it != lcg_priorities.end() and it->second != new_lcg) { logger.error( - "BSR: Invalid config. Priority=%d already configured for lcg=%d", priority, lcg_priorities.at(priority)); + "BSR: Invalid config. Priority=%d already configured for lcg=%d", priority, it->second); return SRSRAN_ERROR; } - lcg_priorities[priority] = new_lcg; + it->second = new_lcg; return SRSRAN_SUCCESS; }