From 6196c096afbdf4174d334431a06964f23d62b091 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 23 Nov 2017 12:36:16 +0100 Subject: [PATCH 01/22] Use CP-based CFO estimation only for DL and UL. Estimate every subframe. Calibrated EMA to 0.3 highest valid for low SNR --- lib/include/srslte/phy/sync/sync.h | 4 ++++ lib/include/srslte/phy/ue/ue_sync.h | 7 +++++- lib/src/phy/sync/sync.c | 24 ++++++++++---------- lib/src/phy/ue/ue_sync.c | 34 +++++++++++++++++++++++++++++ srsue/src/main.cc | 2 +- srsue/src/phy/phch_worker.cc | 1 + srsue/ue.conf.example | 2 +- 7 files changed, 60 insertions(+), 14 deletions(-) diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 1c70b2449..135a19160 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -139,6 +139,10 @@ SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, uint32_t find_offset, uint32_t *peak_position); +SRSLTE_API float srslte_sync_cfo_estimate(srslte_sync_t *q, + cf_t *input, + int find_offset); + /* Estimates the CP length */ SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index e5877dd23..0d12f846c 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -88,7 +88,12 @@ typedef struct SRSLTE_API { bool file_mode; float file_cfo; srslte_cfo_t file_cfo_correct; - + + bool mean_cfo_isunset; + float cfo; + float mean_cfo; + float cfo_ema_alpha; + srslte_ue_sync_state_t state; uint32_t frame_len; diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index ee2ba76d1..849b64b3b 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -587,19 +587,21 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); } } - - if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); - if (q->mean_cfo2_isunset) { - q->mean_cfo2 = cfo2; - q->mean_cfo2_isunset = true; + + if (q->enable_cfo_corr) { + if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { + float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); + if (q->mean_cfo2_isunset) { + q->mean_cfo2 = cfo2; + q->mean_cfo2_isunset = true; + } else { + q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); + } + + ret = SRSLTE_SYNC_FOUND; } else { - q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); + ret = SRSLTE_SYNC_FOUND_NOSPACE; } - - ret = SRSLTE_SYNC_FOUND; - } else { - ret = SRSLTE_SYNC_FOUND_NOSPACE; } } else { ret = SRSLTE_SYNC_NOFOUND; diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index e9c02ca8b..e4caf8e0b 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -47,6 +47,10 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 + +//#define DO_CFO_IN_SYNC + + cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -182,6 +186,9 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; q->sfo_ema = DEFAULT_SFO_EMA_COEFF; + q->mean_cfo_isunset = true; + q->mean_cfo = 0; + q->cfo_ema_alpha = 0.4; q->max_prb = max_prb; if (search_cell) { @@ -218,6 +225,11 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, } } +#ifndef DO_CFO_IN_SYNC + // Disable CFO correction in sync object and do it here every subframe + srslte_sync_set_cfo_enable(&q->strack, false); +#endif + ret = SRSLTE_SUCCESS; } @@ -362,6 +374,7 @@ uint32_t srslte_ue_sync_peak_idx(srslte_ue_sync_t *q) { void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { srslte_sync_set_cfo_ema_alpha(&q->sfind, ema); srslte_sync_set_cfo_ema_alpha(&q->strack, ema); + q->cfo_ema_alpha = ema; } srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q) { @@ -377,7 +390,11 @@ void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, bool enable) { } float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) { +#ifdef DO_CFO_IN_SYNC return 15000 * srslte_sync_get_cfo(&q->strack); +#else + return 15000 * q->mean_cfo; +#endif } void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { @@ -662,6 +679,23 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; +#ifndef DO_CFO_IN_SYNC + /* We found that CP-based correction performs better in low SNR than PSS-based. + * + * Estimate, average and correct here instead of inside sync object + */ + q->cfo = srslte_sync_cfo_estimate(&q->strack, input_buffer[0], 0); + if (q->mean_cfo_isunset) { + q->mean_cfo = q->cfo; + q->mean_cfo_isunset = false; + } else { + /* compute exponential moving average CFO */ + q->mean_cfo = SRSLTE_VEC_EMA(q->cfo, q->mean_cfo, q->cfo_ema_alpha); + } + srslte_cfo_correct(&q->strack.cfocorr2, input_buffer[0], input_buffer[0], -q->mean_cfo / q->fft_size); + +#endif + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ if (q->sf_idx == 0 || q->sf_idx == 5) { diff --git a/srsue/src/main.cc b/srsue/src/main.cc index cc0b07043..d357a8e44 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -208,7 +208,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Tolerance (in Hz) for digial CFO compensation.") ("expert.cfo_ema", - bpo::value(&args->expert.phy.cfo_ema)->default_value(0.4), + bpo::value(&args->expert.phy.cfo_ema)->default_value(0.3), "CFO Exponential Moving Average coefficient. Lower makes it more robust to noise " "but vulnerable to periodic interruptions due to VCO corrections.") diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 7b4ec48bd..54dbb057e 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -128,6 +128,7 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true); + srslte_ue_ul_set_cfo_tol(&ue_ul, phy->args->cfo_correct_tol_hz); mem_initiated = true; diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 867221e87..3373c562f 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -172,7 +172,7 @@ enable = false #attach_enable_64qam = false #nof_phy_threads = 2 #equalizer_mode = mmse -#cfo_ema = 0.4 +#cfo_ema = 0.3 #cfo_integer_enabled = false #cfo_correct_tol_hz = 50 #time_correct_period = 5 From 8b6bd607a720f610b97bd4b5eacf384e68c0f5e8 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 23 Nov 2017 12:38:44 +0100 Subject: [PATCH 02/22] Fixed and tested AGC --- lib/src/phy/agc/agc.c | 12 ++++++------ lib/src/phy/rf/rf_imp.c | 3 ++- lib/src/phy/ue/ue_sync.c | 2 ++ srsue/src/phy/phch_recv.cc | 10 +++++----- srsue/src/ue.cc | 8 +++++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/src/phy/agc/agc.c b/lib/src/phy/agc/agc.c index 3134de729..42a6ef09d 100644 --- a/lib/src/phy/agc/agc.c +++ b/lib/src/phy/agc/agc.c @@ -117,7 +117,7 @@ void srslte_agc_lock(srslte_agc_t *q, bool enable) { void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { if (!q->lock) { float gain_db = 10*log10(q->gain); - float gain_uhd_db = 1.0; + float gain_uhd_db = 50.0; //float gain_uhd = 1.0; float y = 0; // Apply current gain to input signal @@ -125,12 +125,12 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { srslte_vec_sc_prod_cfc(signal, q->gain, signal, len); } else { if (gain_db < 0) { - gain_db = 0.0; + gain_db = 5.0; } if (isinf(gain_db) || isnan(gain_db)) { - gain_db = 10.0; + gain_db = 40.0; } else { - gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db); + gain_uhd_db = q->set_gain_callback(q->uhd_handler, gain_db); q->gain = pow(10, gain_uhd_db/10); } } @@ -166,7 +166,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { } } - double gg = 1.0; + double gg = 1.0; if (q->isfirst) { q->y_out = y; q->isfirst = false; @@ -177,7 +177,7 @@ void srslte_agc_process(srslte_agc_t *q, cf_t *signal, uint32_t len) { gg = expf(-0.5*q->bandwidth*logf(q->y_out/q->target)); q->gain *= gg; } - DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg); + DEBUG("AGC gain: %.2f (%.2f) y_out=%.3f, y=%.3f target=%.1f gg=%.2f\n", gain_db, gain_uhd_db, q->y_out, y, q->target, gg); } } } diff --git a/lib/src/phy/rf/rf_imp.c b/lib/src/phy/rf/rf_imp.c index c1074ebc5..05f064932 100644 --- a/lib/src/phy/rf/rf_imp.c +++ b/lib/src/phy/rf/rf_imp.c @@ -41,7 +41,7 @@ int rf_get_available_devices(char **devnames, int max_strlen) { double srslte_rf_set_rx_gain_th(srslte_rf_t *rf, double gain) { - if (gain > rf->new_rx_gain + 0.5 || gain < rf->new_rx_gain - 0.5) { + if (gain > rf->new_rx_gain + 2 || gain < rf->new_rx_gain - 2) { pthread_mutex_lock(&rf->mutex); rf->new_rx_gain = gain; pthread_cond_signal(&rf->cond); @@ -69,6 +69,7 @@ static void* thread_gain_fcn(void *h) { srslte_rf_set_rx_gain(h, rf->cur_rx_gain); } if (rf->tx_gain_same_rx) { + printf("setting also tx\n"); srslte_rf_set_tx_gain(h, rf->cur_rx_gain+rf->tx_rx_gain_offset); } pthread_mutex_unlock(&rf->mutex); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index e4caf8e0b..d11811cf3 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -122,6 +122,8 @@ int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(voi q->do_agc = n==0?true:false; if (q->do_agc) { srslte_agc_set_gain(&q->agc, init_gain_value); + srslte_agc_set_target(&q->agc, 0.3); + srslte_agc_set_bandwidth(&q->agc, 0.8); } return n; } diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 8a69a7f76..b527f66cf 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -57,8 +57,9 @@ int radio_recv_wrapper_cs(void *obj, cf_t *data[SRSLTE_MAX_PORTS], uint32_t nsam } double callback_set_rx_gain(void *h, double gain) { - srslte::radio_multi *radio_handler = (srslte::radio_multi *) h; - return radio_handler->set_rx_gain_th(gain); + phch_recv *obj = (phch_recv*) h; + srslte::radio_multi *radio_h = obj->radio_h; + return radio_h->set_rx_gain_th(gain); } @@ -100,6 +101,7 @@ void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ // Set options defined in expert section set_ue_sync_opts(&cs.ue_sync); + last_gain = 40; if (do_agc) { srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); } @@ -553,8 +555,6 @@ bool phch_recv::cell_select(uint32_t earfcn, srslte_cell_t cell) { current_earfcn = earfcn; - printf("cell select called set frequency\n"); - if (set_frequency()) { this->cell = cell; log_h->info("Cell Select: Configuring cell...\n"); @@ -670,7 +670,7 @@ void phch_recv::run_thread() { switch (cell_sync_sfn()) { case 1: - srslte_ue_sync_set_agc_period(&ue_sync, 20); + srslte_ue_sync_set_agc_period(&ue_sync, 4); if (!cell_search_in_progress) { phy_state = CELL_CAMP; log_h->info("Sync OK. Camping on cell PCI=%d...\n", cell.id); diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index ca56db556..029ad9255 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -117,7 +117,11 @@ bool ue::init(all_args_t *args_) // Init layers - // PHY initis in background, start before radio + if (args->rf.rx_gain < 0) { + phy.set_agc_enable(true); + } + + // PHY initis in background, start before radio args->expert.phy.nof_rx_ant = args->rf.nof_rx_ant; phy.init(&radio, &mac, &rrc, phy_log, &args->expert.phy); @@ -160,8 +164,6 @@ bool ue::init(all_args_t *args_) if (args->rf.rx_gain < 0) { radio.start_agc(false); - radio.set_tx_rx_gain_offset(10); - phy.set_agc_enable(true); } else { radio.set_rx_gain(args->rf.rx_gain); } From dc65e4243c92dec32504881b2b6c68f7c590dd45 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 23 Nov 2017 13:25:40 +0100 Subject: [PATCH 03/22] print build info to log and on stdout --- CMakeLists.txt | 6 +++ cmake/modules/SRSLTEbuildinfo.cmake.in | 21 ++++++++++ lib/include/srslte/build_info.h.in | 56 ++++++++++++++++++++++++++ lib/src/common/CMakeLists.txt | 4 +- srsue/src/ue.cc | 7 ++++ 5 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 cmake/modules/SRSLTEbuildinfo.cmake.in create mode 100644 lib/include/srslte/build_info.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index bead502f9..855df3a04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,12 @@ if(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") +# Generate CMake to include build information +configure_file( + ${CMAKE_SOURCE_DIR}/cmake/modules/SRSLTEbuildinfo.cmake.in + ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake +) + ######################################################################## # Options ######################################################################## diff --git a/cmake/modules/SRSLTEbuildinfo.cmake.in b/cmake/modules/SRSLTEbuildinfo.cmake.in new file mode 100644 index 000000000..d8715afbc --- /dev/null +++ b/cmake/modules/SRSLTEbuildinfo.cmake.in @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 2.6) + +execute_process( +COMMAND git rev-parse --abbrev-ref HEAD +WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@" +OUTPUT_VARIABLE GIT_BRANCH +OUTPUT_STRIP_TRAILING_WHITESPACE +) + +execute_process( +COMMAND git log -1 --format=%h +WORKING_DIRECTORY "@CMAKE_SOURCE_DIR@" +OUTPUT_VARIABLE GIT_COMMIT_HASH +OUTPUT_STRIP_TRAILING_WHITESPACE +) + +message(STATUS "Generating build_info.h") +configure_file( + @CMAKE_SOURCE_DIR@/lib/include/srslte/build_info.h.in + @CMAKE_BINARY_DIR@/lib/include/srslte/build_info.h +) diff --git a/lib/include/srslte/build_info.h.in b/lib/include/srslte/build_info.h.in new file mode 100644 index 000000000..a8acb306b --- /dev/null +++ b/lib/include/srslte/build_info.h.in @@ -0,0 +1,56 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2015 Software Radio Systems Limited + * + * \section LICENSE + * + * This file is part of the srsLTE library. + * + * srsLTE is free software: you can redistribute it and/or modify + + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef BUILD_INFO_ +#define BUILD_INFO_ + +# ifdef __cplusplus +extern "C" { +# endif + +#ifdef NDEBUG + static char build_mode[] = "Release"; +#else + static char build_mode[] = "Debug"; +#endif + +// the configured build options for srsLTE +static char build_info[] = "commit @GIT_COMMIT_HASH@ on branch @GIT_BRANCH@"; + +SRSLTE_API char* srslte_get_build_info() { + return build_info; +}; + +SRSLTE_API char* srslte_get_build_mode() { + return build_mode; +} + +# ifdef __cplusplus +} +# endif + +#endif // BUILD_INFO_ diff --git a/lib/src/common/CMakeLists.txt b/lib/src/common/CMakeLists.txt index 723085e24..010f8f730 100644 --- a/lib/src/common/CMakeLists.txt +++ b/lib/src/common/CMakeLists.txt @@ -22,7 +22,9 @@ file(GLOB CXX_SOURCES "*.cc") file(GLOB C_SOURCES "*.c") add_library(srslte_common STATIC ${C_SOURCES} ${CXX_SOURCES}) +add_custom_target(gen_build_info COMMAND cmake -P ${CMAKE_BINARY_DIR}/SRSLTEbuildinfo.cmake) +add_dependencies(srslte_common gen_build_info) + target_include_directories(srslte_common PUBLIC ${SEC_INCLUDE_DIRS}) target_link_libraries(srslte_common ${SEC_LIBRARIES}) install(TARGETS srslte_common DESTINATION ${LIBRARY_DIR}) - diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 029ad9255..7cb9ebaa1 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -32,7 +32,9 @@ #include #include #include +#include #include +#include "srslte/build_info.h" using namespace srslte; @@ -51,6 +53,10 @@ ue::~ue() bool ue::init(all_args_t *args_) { + std::stringstream ss; + ss << "Built in " << srslte_get_build_mode() << " mode using " << srslte_get_build_info() << "." << std::endl << std::endl; + std::cout << ss.str(); + args = args_; if (!args->log.filename.compare("stdout")) { @@ -58,6 +64,7 @@ bool ue::init(all_args_t *args_) } else { logger_file.init(args->log.filename); logger_file.log("\n\n"); + logger_file.log(ss.str().c_str()); logger = &logger_file; } From d9b9ae9454d36451c865aa9efcdbd030f72ac4e1 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Thu, 23 Nov 2017 18:42:08 +0000 Subject: [PATCH 04/22] Fix for GUTI pack bug, add support for integrity with attach req --- lib/include/srslte/asn1/liblte_mme.h | 4 ++++ lib/src/asn1/liblte_mme.cc | 26 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h index 15799f7ca..977f309ce 100644 --- a/lib/include/srslte/asn1/liblte_mme.h +++ b/lib/include/srslte/asn1/liblte_mme.h @@ -2721,6 +2721,10 @@ typedef struct{ // Functions LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, LIBLTE_BYTE_MSG_STRUCT *msg); +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg); LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg, LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index 4447b001f..215ffd838 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -1411,9 +1411,9 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_eps_mobile_id_ie(LIBLTE_MME_EPS_MOBILE_ID_STRU **ie_ptr = (((eps_mobile_id->guti.mnc/10) % 10) << 4) | ((eps_mobile_id->guti.mnc/100) % 10); *ie_ptr += 1; } - **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0x0F; + **ie_ptr = (eps_mobile_id->guti.mme_group_id >> 8) & 0xFF; *ie_ptr += 1; - **ie_ptr = eps_mobile_id->guti.mme_group_id & 0x0F; + **ie_ptr = eps_mobile_id->guti.mme_group_id & 0xFF; *ie_ptr += 1; **ie_ptr = eps_mobile_id->guti.mme_code; *ie_ptr += 1; @@ -5518,6 +5518,14 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_attach_reject_msg(LIBLTE_BYTE_MSG_STRUCT *********************************************************************/ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, LIBLTE_BYTE_MSG_STRUCT *msg) +{ + return liblte_mme_pack_attach_request_msg(attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, msg); +} + +LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req, + uint8 sec_hdr_type, + uint32 count, + LIBLTE_BYTE_MSG_STRUCT *msg) { LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; uint8 *msg_ptr = msg->msg; @@ -5525,6 +5533,20 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_attach_request_msg(LIBLTE_MME_ATTACH_REQUEST_M if(attach_req != NULL && msg != NULL) { + if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type) + { + // Protocol Discriminator and Security Header Type + *msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); + msg_ptr++; + + // MAC will be filled in later + msg_ptr += 4; + + // Sequence Number + *msg_ptr = count & 0xFF; + msg_ptr++; + } + // Protocol Discriminator and Security Header Type *msg_ptr = (LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg_ptr++; From 4877c7ab074e0303d72260646323cad014a7fd17 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Thu, 23 Nov 2017 18:42:48 +0000 Subject: [PATCH 05/22] Adding support for GUTI attach --- lib/include/srslte/interfaces/ue_interfaces.h | 18 +- srsue/hdr/upper/nas.h | 62 +- srsue/hdr/upper/rrc.h | 12 - srsue/hdr/upper/usim.h | 30 +- srsue/src/main.cc | 7 +- srsue/src/upper/nas.cc | 691 ++++++++++++++---- srsue/src/upper/rrc.cc | 104 +-- srsue/src/upper/usim.cc | 58 +- 8 files changed, 675 insertions(+), 307 deletions(-) diff --git a/lib/include/srslte/interfaces/ue_interfaces.h b/lib/include/srslte/interfaces/ue_interfaces.h index 88dfd285c..f083c89e2 100644 --- a/lib/include/srslte/interfaces/ue_interfaces.h +++ b/lib/include/srslte/interfaces/ue_interfaces.h @@ -52,16 +52,20 @@ class ue_interface class usim_interface_nas { public: - virtual void get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; - virtual void get_imei_vec(uint8_t* imei_, uint32_t n) = 0; - virtual int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; + virtual std::string get_imsi_str() = 0; + virtual std::string get_imei_str() = 0; + virtual bool get_imsi_vec(uint8_t* imsi_, uint32_t n) = 0; + virtual bool get_imei_vec(uint8_t* imei_, uint32_t n) = 0; + virtual bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) = 0; virtual void generate_authentication_response(uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) = 0; - virtual void generate_nas_keys(uint8_t *k_nas_enc, + uint8_t *res, + uint8_t *k_asme) = 0; + virtual void generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo) = 0; @@ -71,7 +75,8 @@ public: class usim_interface_rrc { public: - virtual void generate_as_keys(uint32_t count_ul, + virtual void generate_as_keys(uint8_t *k_asme, + uint32_t count_ul, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -104,6 +109,7 @@ public: virtual void write_pdu(uint32_t lcid, srslte::byte_buffer_t *pdu) = 0; virtual uint32_t get_ul_count() = 0; virtual bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) = 0; + virtual bool get_k_asme(uint8_t *k_asme_, uint32_t n) = 0; virtual void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) = 0; virtual void plmn_search_end() = 0; }; diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index e743165fb..d79eddea8 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -57,6 +57,9 @@ static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"NULL", "DEREGISTERED INITIATED", "TRACKING AREA UPDATE INITIATED"}; +static const bool eia_caps[8] = {false, true, true, false, false, false, false, false}; +static const bool eea_caps[8] = {true, false, false, false, false, false, false, false}; + typedef enum { PLMN_NOT_SELECTED = 0, PLMN_SELECTED @@ -80,16 +83,12 @@ public: // RRC interface void notify_connection_setup(); - void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - uint32_t get_ul_count(); - bool is_attached(); bool is_attaching(); - bool get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); - + bool get_k_asme(uint8_t *k_asme_, uint32_t n); void plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code); void plmn_search_end(); @@ -115,72 +114,73 @@ private: std::vector known_plmns; - // Save short MAC + LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info; // Identifiers LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; - bool is_guti_set; + bool have_guti; + + // Security context + struct nas_sec_ctxt{ + uint8_t ksi; + uint8_t k_asme[32]; + uint32_t tx_count; + uint32_t rx_count; + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + }; + + bool have_ctxt; + nas_sec_ctxt ctxt; uint32_t ip_addr; uint8_t eps_bearer_id; uint8_t transaction_id; - // NAS counters - incremented for each security-protected message recvd/sent - uint32_t count_ul; - uint32_t count_dl; - // Security - uint8_t ksi; uint8_t k_nas_enc[32]; uint8_t k_nas_int[32]; - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; - - void integrity_generate(uint8_t *key_128, + void integrity_generate(uint8_t integ_algo, + uint8_t *key_128, uint32_t count, uint8_t rb_id, uint8_t direction, uint8_t *msg, uint32_t msg_len, uint8_t *mac); - void integrity_check(); - void cipher_encrypt(); - void cipher_decrypt(); + bool check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps); // Parsers void parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu); - void parse_attach_reject(uint32_t lcid, byte_buffer_t *pdu); - void parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu); - void parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu); - void parse_identity_request(uint32_t lcid, byte_buffer_t *pdu); - void parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu); - void parse_service_reject(uint32_t lcid, byte_buffer_t *pdu); - void parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu); - void parse_emm_information(uint32_t lcid, byte_buffer_t *pdu); // Senders void send_attach_request(); - void send_identity_response(); - void send_service_request(); - void send_esm_information_response(); - void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); + void send_security_mode_reject(uint8_t cause); + + // guti persistence file + bool read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti); + bool write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti); + + // security context persistence file + bool read_ctxt_file(nas_sec_ctxt *ctxt); + bool write_ctxt_file(nas_sec_ctxt ctxt); }; } // namespace srsue diff --git a/srsue/hdr/upper/rrc.h b/srsue/hdr/upper/rrc.h index 37ab941cd..d561b0f1c 100644 --- a/srsue/hdr/upper/rrc.h +++ b/srsue/hdr/upper/rrc.h @@ -40,8 +40,6 @@ #include typedef struct { - bool stmsi_attach; - LIBLTE_RRC_S_TMSI_STRUCT stmsi_value; uint32_t ue_category; uint32_t feature_group; uint8_t supported_bands[LIBLTE_RRC_BAND_N_ITEMS]; @@ -198,21 +196,16 @@ private: // MAC interface void release_pucch_srs(); - void ra_problem(); // GW interface bool is_connected(); - bool have_drb(); // PDCP interface void write_pdu(uint32_t lcid, byte_buffer_t *pdu); - void write_pdu_bcch_bch(byte_buffer_t *pdu); - void write_pdu_bcch_dlsch(byte_buffer_t *pdu); - void write_pdu_pcch(byte_buffer_t *pdu); // Radio bearers @@ -280,11 +273,6 @@ private: void set_mac_default(); void set_rrc_default(); void set_bearers(); - - // s-tmsi persistent file - bool read_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi); - bool write_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi); - }; } // namespace srsue diff --git a/srsue/hdr/upper/usim.h b/srsue/hdr/upper/usim.h index fea15ba68..73acd5594 100644 --- a/srsue/hdr/upper/usim.h +++ b/srsue/hdr/upper/usim.h @@ -1,4 +1,4 @@ -/** +/** * * \section COPYRIGHT * @@ -59,24 +59,30 @@ public: void stop(); // NAS interface - void get_imsi_vec(uint8_t* imsi_, uint32_t n); - void get_imei_vec(uint8_t* imei_, uint32_t n); - int get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); + std::string get_imsi_str(); + std::string get_imei_str(); + + bool get_imsi_vec(uint8_t* imsi_, uint32_t n); + bool get_imei_vec(uint8_t* imei_, uint32_t n); + bool get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id); void generate_authentication_response(uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); - void generate_nas_keys(uint8_t *k_nas_enc, + void generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo, srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo); // RRC interface - void generate_as_keys(uint32_t count_ul, + void generate_as_keys(uint8_t *k_asme, + uint32_t count_ul, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -91,13 +97,15 @@ private: uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); void gen_auth_res_xor( uint8_t *rand, uint8_t *autn_enb, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res); + uint8_t *res, + uint8_t *k_asme); void str_to_hex(std::string str, uint8_t *hex); srslte::log *usim_log; @@ -110,6 +118,9 @@ private: uint64_t imei; uint8_t k[16]; + std::string imsi_str; + std::string imei_str; + // Security variables uint8_t rand[16]; uint8_t ck[16]; @@ -117,7 +128,6 @@ private: uint8_t ak[6]; uint8_t mac[8]; uint8_t autn[16]; - uint8_t k_asme[32]; uint8_t k_enb[32]; bool initiated; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 59d6360c7..b9717d93e 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -77,17 +77,12 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Transmission time advance") ("rf.burst_preamble_us", bpo::value(&args->rf.burst_preamble)->default_value("auto"), "Transmission time advance") - ("rrc.stmsi_attach", bpo::value(&args->rrc.stmsi_attach)->default_value(false),"If enabled, always tries first an S-TMSI attach using the\n" - "S-TMSI value stored in .stimsi file generated in previous run") - ("rrc.mmec_value", bpo::value(&args->rrc.stmsi_value.mmec)->default_value(0), "If defined (non-zero), overwrites the value stored in .stimsi file") - ("rrc.mtmsi_value", bpo::value(&args->rrc.stmsi_value.m_tmsi)->default_value(0), "If defined (non-zero), overwrites the value stored in .stimsi file") - ("rrc.feature_group", bpo::value(&args->rrc.feature_group)->default_value(0xe6041c00), "Hex value of the featureGroupIndicators field in the" "UECapabilityInformation message. Default 0xe6041c00") ("rrc.ue_category", bpo::value(&args->ue_category_str)->default_value("4"), "UE Category (1 to 5)") - ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), + ("pcap.enable", bpo::value(&args->pcap.enable)->default_value(false), "Enable MAC packet captures for wireshark") ("pcap.filename", bpo::value(&args->pcap.filename)->default_value("ue.pcap"), "MAC layer capture filename") diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index d8bd40c6e..2b01efcec 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -25,6 +25,11 @@ */ +#include +#include +#include +#include +#include #include "srslte/asn1/liblte_rrc.h" #include "upper/nas.h" #include "srslte/common/bcd_helpers.h" @@ -33,9 +38,78 @@ using namespace srslte; namespace srsue { +/********************************************************************* + * Conversion helpers + ********************************************************************/ +std::string hex_to_string(uint8_t *hex, int size) +{ + std::stringstream ss; + + ss << std::hex << std::setfill('0'); + for(int i=0; i(hex[i]); + } + return ss.str(); +} + +bool string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len) +{ + static const char* const lut = "0123456789abcdef"; + uint32_t str_len = hex_str.length(); + if(str_len & 1) { + return false; // uneven hex_str length + } + if(str_len > len*2) { + return false; // not enough space in hex buffer + } + + for(uint32_t i=0; ifull_net_name_present) { + ss << info->full_net_name.name; + } + if(info->short_net_name_present) { + ss << " (" << info->short_net_name.name << ")"; + } + if(info->utc_and_local_time_zone_present) { + ss << " " << (int)info->utc_and_local_time_zone.day; + ss << "/" << (int)info->utc_and_local_time_zone.month; + ss << "/" << (int)info->utc_and_local_time_zone.year; + ss << " " << (int)info->utc_and_local_time_zone.hour; + ss << ":" << (int)info->utc_and_local_time_zone.minute; + ss << ":" << (int)info->utc_and_local_time_zone.second; + ss << " TZ:" << (int)info->utc_and_local_time_zone.tz; + } + return ss.str(); +} + + nas::nas() - : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), is_guti_set(false), ip_addr(0), eps_bearer_id(0), - count_ul(0), count_dl(0) {} + : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), ip_addr(0), eps_bearer_id(0) +{ + ctxt.rx_count = 0; + ctxt.tx_count = 0; +} void nas::init(usim_interface_nas *usim_, rrc_interface_nas *rrc_, @@ -51,15 +125,26 @@ void nas::init(usim_interface_nas *usim_, state = EMM_STATE_DEREGISTERED; plmn_selection = PLMN_NOT_SELECTED; - if (usim->get_home_plmn_id(&home_plmn)) { + if (!usim->get_home_plmn_id(&home_plmn)) { nas_log->error("Getting Home PLMN Id from USIM. Defaulting to 001-01\n"); home_plmn.mcc = 61441; // This is 001 home_plmn.mnc = 65281; // This is 01 } cfg = cfg_; + + if((have_guti = read_guti_file(&guti))) { + if((have_ctxt = read_ctxt_file(&ctxt))) { + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, + ctxt.cipher_algo, ctxt.integ_algo); + nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); + nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); + } + } } -void nas::stop() {} +void nas::stop() { + write_ctxt_file(ctxt); +} emm_state_t nas::get_state() { return state; @@ -207,11 +292,11 @@ void nas::write_pdu(uint32_t lcid, byte_buffer_t *pdu) { } uint32_t nas::get_ul_count() { - return count_ul; + return ctxt.tx_count; } bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { - if (is_guti_set) { + if (have_guti) { s_tmsi->mmec = guti.mme_code; s_tmsi->m_tmsi = guti.m_tmsi; return true; @@ -220,11 +305,26 @@ bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { } } +bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { + if(!have_ctxt) { + nas_log->error("K_asme requested before security context established\n"); + return false; + } + if(NULL == k_asme_ || n < 32) { + nas_log->error("Invalid parameters to get_k_asme"); + return false; + } + + memcpy(k_asme_, ctxt.k_asme, 32); + return true; +} + /******************************************************************************* Security *******************************************************************************/ -void nas::integrity_generate(uint8_t *key_128, +void nas::integrity_generate(uint8_t integ_algo, + uint8_t *key_128, uint32_t count, uint8_t rb_id, uint8_t direction, @@ -269,6 +369,16 @@ void nas::cipher_decrypt() { } +bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps) +{ + for(uint32_t i=0; i<8; i++) { + if(caps->eea[i] != eea_caps[i] || caps->eia[i] != eia_caps[i]) { + return false; + } + } + return true; +} + /******************************************************************************* Parsers @@ -289,8 +399,8 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { //FIXME: Handle tai_list if (attach_accept.guti_present) { memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); - is_guti_set = true; - // TODO: log message to console + have_guti = true; + write_guti_file(guti); } if (attach_accept.lai_present) { } @@ -358,10 +468,9 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { state = EMM_STATE_REGISTERED; current_plmn = selecting_plmn; - count_dl++; + ctxt.rx_count++; // Send EPS bearer context accept and attach complete - count_ul++; act_def_eps_bearer_context_accept.eps_bearer_id = eps_bearer_id; act_def_eps_bearer_context_accept.proc_transaction_id = transaction_id; act_def_eps_bearer_context_accept.protocol_cnfg_opts_present = false; @@ -369,10 +478,11 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { &attach_complete.esm_msg); liblte_mme_pack_attach_complete_msg(&attach_complete, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, - count_ul, + ctxt.tx_count, (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(&k_nas_int[16], - count_ul, + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, lcid - 1, SECURITY_DIRECTION_UPLINK, &pdu->msg[5], @@ -384,6 +494,7 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { nas_log->info("Sending Attach Complete\n"); rrc->write_sdu(lcid, pdu); + ctxt.tx_count++; } else { nas_log->info("Not handling attach type %u\n", attach_accept.eps_attach_result); @@ -407,7 +518,7 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_AUTHENTICATION_REQUEST_MSG_STRUCT auth_req; LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_res; - nas_log->info("Received Authentication Request\n");; + nas_log->info("Received Authentication Request\n"); liblte_mme_unpack_authentication_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &auth_req); // Reuse the pdu for the response message @@ -422,7 +533,15 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { bool net_valid; uint8_t res[16]; - usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, &net_valid, res); + usim->generate_authentication_response(auth_req.rand, auth_req.autn, mcc, mnc, + &net_valid, res, ctxt.k_asme); + nas_log->info("Generated k_asme=%s\n", hex_to_string(ctxt.k_asme, 32).c_str()); + if(LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE == auth_req.nas_ksi.tsc_flag) { + ctxt.ksi = auth_req.nas_ksi.nas_ksi; + } else { + nas_log->error("NAS mapped security context not currently supported\n"); + nas_log->console("Warning: NAS mapped security context not currently supported\n"); + } if (net_valid) { nas_log->info("Network authentication successful\n"); @@ -438,9 +557,6 @@ void nas::parse_authentication_request(uint32_t lcid, byte_buffer_t *pdu) { nas_log->console("Warning: Network authentication failure\n"); pool->deallocate(pdu); } - - // Reset DL counter (as per 24.301 5.4.3.2) - count_dl = 0; } void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) { @@ -451,108 +567,154 @@ void nas::parse_authentication_reject(uint32_t lcid, byte_buffer_t *pdu) { } void nas::parse_identity_request(uint32_t lcid, byte_buffer_t *pdu) { - nas_log->error("TODO:parse_identity_request\n"); + LIBLTE_MME_ID_REQUEST_MSG_STRUCT id_req; + LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp; + + liblte_mme_unpack_identity_request_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &id_req); + nas_log->info("Received Identity Request. ID type: %d\n", id_req.id_type); + + switch(id_req.id_type) { + case LIBLTE_MME_MOBILE_ID_TYPE_IMSI: + id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMSI; + usim->get_imsi_vec(id_resp.mobile_id.imsi, 15); + break; + case LIBLTE_MME_MOBILE_ID_TYPE_IMEI: + id_resp.mobile_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEI; + usim->get_imei_vec(id_resp.mobile_id.imei, 15); + break; + default: + nas_log->error("Unhandled ID type: %d\n"); + pool->deallocate(pdu); + return; + } + + pdu->reset(); + liblte_mme_pack_identity_response_msg(&id_resp, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + rrc->write_sdu(lcid, pdu); } -void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) { - bool success; +void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) +{ LIBLTE_MME_SECURITY_MODE_COMMAND_MSG_STRUCT sec_mode_cmd; LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sec_mode_comp; - LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; - nas_log->info("Received Security Mode Command\n"); liblte_mme_unpack_security_mode_command_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &sec_mode_cmd); + nas_log->info("Received Security Mode Command ksi: %d, eea: %s, eia: %s\n", + sec_mode_cmd.nas_ksi.nas_ksi, + ciphering_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eea], + integrity_algorithm_id_text[sec_mode_cmd.selected_nas_sec_algs.type_of_eia]); - ksi = sec_mode_cmd.nas_ksi.nas_ksi; - cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; - integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; - // FIXME: Handle nonce_ue, nonce_mme - // FIXME: Currently only handling ciphering EEA0 (null) and integrity EIA1,EIA2 - // FIXME: Use selected_nas_sec_algs to choose correct algos + if(sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { + nas_log->error("Mapped security context not supported\n"); + pool->deallocate(pdu); + return; + } - nas_log->debug("Security details: ksi=%d, eea=%s, eia=%s\n", - ksi, ciphering_algorithm_id_text[cipher_algo], integrity_algorithm_id_text[integ_algo]); + if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi) + { + nas_log->warning("Sending Security Mode Reject due to key set ID mismatch\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + pool->deallocate(pdu); + return; + } + // MME is setting up security context + // TODO: check nonce (not sent by Amari) - if (CIPHERING_ALGORITHM_ID_EEA0 != cipher_algo || - (INTEGRITY_ALGORITHM_ID_128_EIA2 != integ_algo && - INTEGRITY_ALGORITHM_ID_128_EIA1 != integ_algo) || - sec_mode_cmd.nas_ksi.tsc_flag != LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE) { - sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH; + // Check capabilities replay + if(!check_cap_replay(&sec_mode_cmd.ue_security_cap)) { nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); - nas_log->console("Unsupported Security Mode Command settings: use ciphering algorithm EEA0 and integrity check EIA1 or EIA2.\n"); - success = false; - } else { - // Generate NAS encryption key and integrity protection key - usim->generate_nas_keys(k_nas_enc, k_nas_int, cipher_algo, integ_algo); - nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); - nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); - - // Check incoming MAC - uint8_t *inMAC = &pdu->msg[1]; - uint8_t genMAC[4]; - integrity_generate(&k_nas_int[16], - count_dl, - lcid - 1, - SECURITY_DIRECTION_DOWNLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - genMAC); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH); + pool->deallocate(pdu); + return; + } - nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); - nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); + // Reset counterd (as per 24.301 5.4.3.2) + ctxt.rx_count = 0; + ctxt.tx_count = 0; - bool match = true; - for (int i = 0; i < 4; i++) { - if (inMAC[i] != genMAC[i]) { - match = false; - } - } - if (!match) { - sec_mode_rej.emm_cause = LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED; - nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); - success = false; - } else { + ctxt.cipher_algo = (CIPHERING_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eea; + ctxt.integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) sec_mode_cmd.selected_nas_sec_algs.type_of_eia; - if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) { - sec_mode_comp.imeisv_present = true; - sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; - usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); - sec_mode_comp.imeisv.imeisv[14] = 5; - sec_mode_comp.imeisv.imeisv[15] = 3; - } else { - sec_mode_comp.imeisv_present = false; - } + // Check capabilities + if(!eea_caps[ctxt.cipher_algo] || !eia_caps[ctxt.integ_algo]) { + nas_log->warning("Sending Security Mode Reject due to security capabilities mismatch\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_UE_SECURITY_CAPABILITIES_MISMATCH); + pool->deallocate(pdu); + return; + } - // Reuse pdu for response - pdu->reset(); - liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, - LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, - count_ul, - (LIBLTE_BYTE_MSG_STRUCT *) pdu); - integrity_generate(&k_nas_int[16], - count_ul, - lcid - 1, - SECURITY_DIRECTION_UPLINK, - &pdu->msg[5], - pdu->N_bytes - 5, - &pdu->msg[1]); - nas_log->info("Sending Security Mode Complete nas_count_ul=%d, RB=%s\n", - count_ul, - rrc->get_rb_name(lcid).c_str()); - success = true; + // Generate NAS keys + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, ctxt.cipher_algo, ctxt.integ_algo); + nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); + nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); + + nas_log->debug("Generating integrity check. integ_algo:%d, count_dl:%d, lcid:%d\n", + ctxt.integ_algo, ctxt.rx_count, lcid); + + // Check incoming MAC + uint8_t *inMAC = &pdu->msg[1]; + uint8_t genMAC[4]; + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.rx_count, + lcid - 1, + SECURITY_DIRECTION_DOWNLINK, + &pdu->msg[5], + pdu->N_bytes - 5, + genMAC); + + nas_log->info_hex(inMAC, 4, "Incoming PDU MAC:"); + nas_log->info_hex(genMAC, 4, "Generated PDU MAC:"); + + ctxt.rx_count++; + + bool match = true; + for (int i = 0; i < 4; i++) { + if (inMAC[i] != genMAC[i]) { + match = false; } } + if(!match) { + nas_log->warning("Sending Security Mode Reject due to integrity check failure\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + pool->deallocate(pdu); + return; + } - count_dl++; + // Take security context into use + have_ctxt = true; - if (!success) { - // Reuse pdu for response - pdu->reset(); - liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) pdu); + if (sec_mode_cmd.imeisv_req_present && LIBLTE_MME_IMEISV_REQUESTED == sec_mode_cmd.imeisv_req) { + sec_mode_comp.imeisv_present = true; + sec_mode_comp.imeisv.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_IMEISV; + usim->get_imei_vec(sec_mode_comp.imeisv.imeisv, 15); + sec_mode_comp.imeisv.imeisv[14] = 5; + sec_mode_comp.imeisv.imeisv[15] = 3; + } else { + sec_mode_comp.imeisv_present = false; } - rrc->write_sdu(lcid, pdu); + // Send response + byte_buffer_t *sdu = pool_allocate; + liblte_mme_pack_security_mode_complete_msg(&sec_mode_comp, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) sdu); + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, + lcid - 1, + SECURITY_DIRECTION_UPLINK, + &sdu->msg[5], + sdu->N_bytes - 5, + &sdu->msg[1]); + nas_log->info("Sending Security Mode Complete nas_current_ctxt.tx_count=%d, RB=%s\n", + ctxt.tx_count, + rrc->get_rb_name(lcid).c_str()); + rrc->write_sdu(lcid, sdu); + ctxt.tx_count++; + pool->deallocate(pdu); } void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { @@ -561,10 +723,15 @@ void nas::parse_service_reject(uint32_t lcid, byte_buffer_t *pdu) { void nas::parse_esm_information_request(uint32_t lcid, byte_buffer_t *pdu) { nas_log->error("TODO:parse_esm_information_request\n"); + } void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { - nas_log->error("TODO:parse_emm_information\n"); + liblte_mme_unpack_emm_information_msg((LIBLTE_BYTE_MSG_STRUCT *) pdu, &emm_info); + std::string str = emm_info_str(&emm_info); + nas_log->info("Received EMM Information: %s\n", str.c_str()); + nas_log->console("%s\n", str.c_str()); + ctxt.rx_count++; } /******************************************************************************* @@ -579,25 +746,13 @@ void nas::send_attach_request() { attach_req.eps_attach_type = LIBLTE_MME_EPS_ATTACH_TYPE_EPS_ATTACH; for (i = 0; i < 8; i++) { - attach_req.ue_network_cap.eea[i] = false; - attach_req.ue_network_cap.eia[i] = false; + attach_req.ue_network_cap.eea[i] = eea_caps[i]; + attach_req.ue_network_cap.eia[i] = eia_caps[i]; } - attach_req.ue_network_cap.eea[0] = true; // EEA0 supported - attach_req.ue_network_cap.eia[0] = true; // EIA0 supported - attach_req.ue_network_cap.eia[1] = true; // EIA1 supported - attach_req.ue_network_cap.eia[2] = true; // EIA2 supported - - attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos - attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos - - attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) - - attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; - usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); - - // ESM message (PDN connectivity request) for first default bearer - gen_pdn_connectivity_request(&attach_req.esm_msg); + attach_req.ue_network_cap.uea_present = false; // UMTS encryption algos + attach_req.ue_network_cap.uia_present = false; // UMTS integrity algos + attach_req.ms_network_cap_present = false; // A/Gb mode (2G) or Iu mode (3G) attach_req.old_p_tmsi_signature_present = false; attach_req.additional_guti_present = false; attach_req.last_visited_registered_tai_present = false; @@ -613,11 +768,47 @@ void nas::send_attach_request() { attach_req.device_properties_present = false; attach_req.old_guti_type_present = false; - // Pack the message - liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); + // ESM message (PDN connectivity request) for first default bearer + gen_pdn_connectivity_request(&attach_req.esm_msg); + + // GUTI or IMSI attach + if(have_guti && have_ctxt) { + attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI; + memcpy(&attach_req.eps_mobile_id.guti, &guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + attach_req.old_guti_type = LIBLTE_MME_GUTI_TYPE_NATIVE; + attach_req.old_guti_type_present = true; + attach_req.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE; + attach_req.nas_ksi.nas_ksi = ctxt.ksi; + nas_log->info("Requesting GUTI attach. " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code); + liblte_mme_pack_attach_request_msg(&attach_req, + LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY, + ctxt.tx_count, + (LIBLTE_BYTE_MSG_STRUCT *) msg); + + // Add MAC + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, + cfg.lcid-1, + SECURITY_DIRECTION_UPLINK, + &msg->msg[5], + msg->N_bytes - 5, + &msg->msg[1]); + } else { + attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; + usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); + nas_log->info("Requesting IMSI attach. imsi: %s\n", usim->get_imsi_str()); + liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); + } nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); + + if(have_ctxt) { + ctxt.tx_count++; + } } void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { @@ -641,27 +832,36 @@ void nas::gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg) { liblte_mme_pack_pdn_connectivity_request_msg(&pdn_con_req, msg); } +void nas::send_security_mode_reject(uint8_t cause) { + byte_buffer_t *msg = pool_allocate; + + LIBLTE_MME_SECURITY_MODE_REJECT_MSG_STRUCT sec_mode_rej; + sec_mode_rej.emm_cause = cause; + liblte_mme_pack_security_mode_reject_msg(&sec_mode_rej, (LIBLTE_BYTE_MSG_STRUCT *) msg); + rrc->write_sdu(cfg.lcid, msg); +} + void nas::send_identity_response() {} void nas::send_service_request() { byte_buffer_t *msg = pool_allocate; - count_ul++; // Pack the service request message directly msg->msg[0] = (LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST << 4) | (LIBLTE_MME_PD_EPS_MOBILITY_MANAGEMENT); msg->N_bytes++; - msg->msg[1] = (ksi & 0x07) << 5; - msg->msg[1] |= count_ul & 0x1F; + msg->msg[1] = (ctxt.ksi & 0x07) << 5; + msg->msg[1] |= ctxt.tx_count & 0x1F; msg->N_bytes++; uint8_t mac[4]; - integrity_generate(&k_nas_int[16], - count_ul, - cfg.lcid-1, - SECURITY_DIRECTION_UPLINK, - &msg->msg[0], - 2, - &mac[0]); + integrity_generate(ctxt.integ_algo, + &k_nas_int[16], + ctxt.tx_count, + cfg.lcid-1, + SECURITY_DIRECTION_UPLINK, + &msg->msg[0], + 2, + &mac[0]); // Set the short MAC msg->msg[2] = mac[2]; msg->N_bytes++; @@ -669,8 +869,239 @@ void nas::send_service_request() { msg->N_bytes++; nas_log->info("Sending service request\n"); rrc->write_sdu(cfg.lcid, msg); + ctxt.tx_count++; } void nas::send_esm_information_response() {} +bool nas::read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti) +{ + std::ifstream file; + std::string line; + if (!guti) { + return false; + } + + const char *m_tmsi_str = "m_tmsi="; + size_t m_tmsi_str_len = strlen(m_tmsi_str); + const char *mcc_str = "mcc="; + size_t mcc_str_len = strlen(mcc_str); + const char *mnc_str = "mnc="; + size_t mnc_str_len = strlen(mnc_str); + const char *mme_group_id_str = "mme_group_id="; + size_t mme_group_id_str_len = strlen(mme_group_id_str); + const char *mme_code_str = "mme_code="; + size_t mme_code_str_len = strlen(mme_code_str); + + file.open(".guti", std::ios::in); + if (file.is_open()) { + bool read_ok = true; + if (std::getline(file, line)) { + if (!line.substr(0,m_tmsi_str_len).compare(m_tmsi_str)) { + guti->m_tmsi = atoi(line.substr(m_tmsi_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,mcc_str_len).compare(mcc_str)) { + guti->mcc = atoi(line.substr(mcc_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,mnc_str_len).compare(mnc_str)) { + guti->mnc = atoi(line.substr(mnc_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,mme_group_id_str_len).compare(mme_group_id_str)) { + guti->mme_group_id = atoi(line.substr(mme_group_id_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,mme_code_str_len).compare(mme_code_str)) { + guti->mme_code = atoi(line.substr(mme_code_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + file.close(); + if (read_ok) { + nas_log->info("Read GUTI from file .guti. " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + guti->m_tmsi, guti->mcc, guti->mnc, guti->mme_group_id, guti->mme_code); + return true; + } else { + nas_log->error("Invalid GUTI file format\n"); + return false; + } + } else { + return false; + } +} + +bool nas::write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti) { + std::ofstream file; + if (!have_guti) { + return false; + } + file.open(".guti", std::ios::out | std::ios::trunc); + if (file.is_open()) { + file << "m_tmsi=" << (int) guti.m_tmsi << std::endl; + file << "mcc=" << (int) guti.mcc << std::endl; + file << "mnc=" << (int) guti.mnc << std::endl; + file << "mme_group_id=" << (int) guti.mme_group_id << std::endl; + file << "mme_code=" << (int) guti.mme_code << std::endl; + nas_log->info("Saved GUTI to file .guti. " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code); + file.close(); + return true; + } else { + return false; + } +} + +bool nas::read_ctxt_file(nas_sec_ctxt *ctxt) +{ + std::ifstream file; + std::string line; + if (!ctxt) { + return false; + } + + const char *ksi_str = "ksi="; + size_t ksi_str_len = strlen(ksi_str); + const char *k_asme_str = "k_asme="; + size_t k_asme_str_len = strlen(k_asme_str); + const char *tx_count_str = "tx_count="; + size_t tx_count_str_len = strlen(tx_count_str); + const char *rx_count_str = "rx_count="; + size_t rx_count_str_len = strlen(rx_count_str); + const char *int_alg_str = "int_alg="; + size_t int_alg_str_len = strlen(int_alg_str); + const char *enc_alg_str = "enc_alg="; + size_t enc_alg_str_len = strlen(enc_alg_str); + + file.open(".ctxt", std::ios::in); + if (file.is_open()) { + bool read_ok = true; + if (std::getline(file, line)) { + if (!line.substr(0,ksi_str_len).compare(ksi_str)) { + ctxt->ksi = atoi(line.substr(ksi_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,k_asme_str_len).compare(k_asme_str)) { + std::string tmp = line.substr(k_asme_str_len); + if(!string_to_hex(tmp, ctxt->k_asme, 32)) { + read_ok = false; + } + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,tx_count_str_len).compare(tx_count_str)) { + ctxt->tx_count = atoi(line.substr(tx_count_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,rx_count_str_len).compare(rx_count_str)) { + ctxt->rx_count = atoi(line.substr(rx_count_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,int_alg_str_len).compare(int_alg_str)) { + ctxt->integ_algo = (srslte::INTEGRITY_ALGORITHM_ID_ENUM)atoi(line.substr(int_alg_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + if (std::getline(file, line)) { + if (!line.substr(0,enc_alg_str_len).compare(enc_alg_str)) { + ctxt->cipher_algo = (srslte::CIPHERING_ALGORITHM_ID_ENUM)atoi(line.substr(enc_alg_str_len).c_str()); + } else { + read_ok = false; + } + } else { + read_ok = false; + } + file.close(); + if (read_ok) { + nas_log->info("Read security ctxt from file .ctxt. " + "ksi: %x, k_asme: %s, " + "tx_count: %x, rx_count: %x, " + "int_alg: %d, enc_alg: %d\n", + ctxt->ksi, hex_to_string(ctxt->k_asme,32).c_str(), + ctxt->tx_count, ctxt->rx_count, + ctxt->integ_algo, ctxt->cipher_algo); + return true; + } else { + nas_log->error("Invalid security ctxt file format\n"); + return false; + } + } else { + return false; + } +} + +bool nas::write_ctxt_file(nas_sec_ctxt ctxt) +{ + std::ofstream file; + file.open(".ctxt", std::ios::out | std::ios::trunc); + if (file.is_open()) { + file << "ksi=" << (int) ctxt.ksi << std::endl; + file << "k_asme=" << hex_to_string(ctxt.k_asme, 32) << std::endl; + file << "tx_count=" << (int) ctxt.tx_count << std::endl; + file << "rx_count=" << (int) ctxt.rx_count << std::endl; + file << "int_alg=" << (int) ctxt.integ_algo << std::endl; + file << "enc_alg=" << (int) ctxt.cipher_algo << std::endl; + nas_log->info("Saved security ctxt to file .ctxt. " + "ksi: %x, k_asme: %s, " + "tx_count: %x, rx_count: %x, " + "int_alg: %d, enc_alg: %d\n", + ctxt.ksi, hex_to_string(ctxt.k_asme,32).c_str(), + ctxt.tx_count, ctxt.rx_count, + ctxt.integ_algo, ctxt.cipher_algo); + file.close(); + return true; + } else { + return false; + } +} + + } // namespace srsue diff --git a/srsue/src/upper/rrc.cc b/srsue/src/upper/rrc.cc index b33332f1d..665761a04 100644 --- a/srsue/src/upper/rrc.cc +++ b/srsue/src/upper/rrc.cc @@ -27,8 +27,9 @@ #include #include -#include #include +#include +#include #include "upper/rrc.h" #include "srslte/asn1/liblte_rrc.h" #include "srslte/common/security.h" @@ -99,7 +100,6 @@ void rrc::init(phy_interface_rrc *phy_, args.supported_bands[0] = 7; args.nof_supported_bands = 1; args.feature_group = 0xe6041c00; - args.stmsi_attach = false; t301 = mac_timers->timer_get_unique_id(); t310 = mac_timers->timer_get_unique_id(); @@ -117,6 +117,9 @@ void rrc::init(phy_interface_rrc *phy_, set_rrc_default(); set_phy_default(); set_mac_default(); + + // set seed for rand (used in attach) + srand(time(NULL)); } void rrc::stop() { @@ -592,66 +595,6 @@ void rrc::timer_expired(uint32_t timeout_id) { * *******************************************************************************/ -bool rrc::read_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { - std::ifstream file; - std::string line; - if (!s_tmsi) { - return false; - } - - const char *mmec_str = "mmec="; - size_t mmec_str_len = strlen(mmec_str); - const char *mtmsi_str = "mtmsi="; - size_t mtmsi_str_len = strlen(mtmsi_str); - - file.open(".stmsi", std::ios::in); - if (file.is_open()) { - bool read_ok = true; - if (std::getline(file, line)) { - if (!line.substr(0,mmec_str_len).compare(mmec_str)) { - s_tmsi->mmec = atoi(line.substr(5).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,mtmsi_str_len).compare(mtmsi_str)) { - s_tmsi->m_tmsi = atoi(line.substr(mtmsi_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - file.close(); - if (read_ok) { - rrc_log->info("Read S-TMSI value: %x:%x\n", s_tmsi->mmec, s_tmsi->m_tmsi); - return true; - } else { - rrc_log->error("Invalid s-tmsi persistent file format\n"); - return false; - } - } else { - return false; - } -} - -bool rrc::write_stimsi_file(LIBLTE_RRC_S_TMSI_STRUCT s_tmsi) { - std::ofstream file; - file.open(".stmsi", std::ios::out | std::ios::trunc); - if (file.is_open()) { - file << "mmec=" << (int) s_tmsi.mmec << std::endl; - file << "mtmsi=" << (int) s_tmsi.m_tmsi << std::endl; - rrc_log->info("Saved S-TMSI in persistent file: %x:%x\n", s_tmsi.mmec, s_tmsi.m_tmsi); - file.close(); - return true; - } else { - return false; - } -} - void rrc::send_con_request() { rrc_log->debug("Preparing RRC Connection Request\n"); LIBLTE_RRC_UL_CCCH_MSG_STRUCT ul_ccch_msg; @@ -659,30 +602,13 @@ void rrc::send_con_request() { // Prepare ConnectionRequest packet ul_ccch_msg.msg_type = LIBLTE_RRC_UL_CCCH_MSG_TYPE_RRC_CON_REQ; - bool valid_stmsi = false; - if (nas->get_s_tmsi(&s_tmsi) || (args.stmsi_attach && !first_stimsi_attempt)) { + if (nas->get_s_tmsi(&s_tmsi)) { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_S_TMSI; - if (nas->get_s_tmsi(&s_tmsi)) { - ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; - valid_stmsi = true; - } else { - first_stimsi_attempt = true; - if (args.stmsi_value.m_tmsi) { - ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = args.stmsi_value; - valid_stmsi = true; - } else { - if (!read_stimsi_file(&ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi)) { - rrc_log->warning("Could not read S-TMSI from persistent file. Trying normal attach.\n"); - } else { - valid_stmsi = true; - } - } - } - } - if (!valid_stmsi) { + ul_ccch_msg.msg.rrc_con_req.ue_id.s_tmsi = s_tmsi; + } else { ul_ccch_msg.msg.rrc_con_req.ue_id_type = LIBLTE_RRC_CON_REQ_UE_ID_TYPE_RANDOM_VALUE; - ul_ccch_msg.msg.rrc_con_req.ue_id.random = 1000; + ul_ccch_msg.msg.rrc_con_req.ue_id.random = rand() % 2^40; } ul_ccch_msg.msg.rrc_con_req.cause = LIBLTE_RRC_CON_REQ_EST_CAUSE_MO_SIGNALLING; @@ -956,14 +882,6 @@ void rrc::handle_rrc_con_reconfig(uint32_t lcid, LIBLTE_RRC_CONNECTION_RECONFIGU nas_sdu->N_bytes = reconfig->ded_info_nas_list[i].N_bytes; nas->write_pdu(lcid, nas_sdu); } - - // Get S-TMSI from NAS and store it in persistent file - LIBLTE_RRC_S_TMSI_STRUCT s_tmsi; - if (nas->get_s_tmsi(&s_tmsi)) { - if (!write_stimsi_file(s_tmsi)) { - rrc_log->warning("Could not store S-TMSI in persistent file\n"); - } - } } /* Actions upon reception of RRCConnectionRelease 5.3.8.3 */ @@ -1247,7 +1165,9 @@ void rrc::parse_dl_dcch(uint32_t lcid, byte_buffer_t *pdu) { integ_algo = (INTEGRITY_ALGORITHM_ID_ENUM) dl_dcch_msg.msg.security_mode_cmd.sec_algs.int_alg; // Configure PDCP for security - usim->generate_as_keys(nas->get_ul_count(), k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); + uint8_t k_asme[32]; + nas->get_k_asme(k_asme, 32); + usim->generate_as_keys(k_asme, nas->get_ul_count()-1, k_rrc_enc, k_rrc_int, k_up_enc, k_up_int, cipher_algo, integ_algo); pdcp->config_security(lcid, k_rrc_enc, k_rrc_int, cipher_algo, integ_algo); send_security_mode_complete(lcid, pdu); break; diff --git a/srsue/src/upper/usim.cc b/srsue/src/upper/usim.cc index e1d2c204f..7ae53988b 100644 --- a/srsue/src/upper/usim.cc +++ b/srsue/src/upper/usim.cc @@ -39,9 +39,11 @@ usim::usim() : initiated(false) void usim::init(usim_args_t *args, srslte::log *usim_log_) { usim_log = usim_log_; + imsi_str = args->imsi; + imei_str = args->imei; - const char *imsi_str = args->imsi.c_str(); - const char *imei_str = args->imei.c_str(); + const char *imsi_c = args->imsi.c_str(); + const char *imei_c = args->imei.c_str(); uint32_t i; if(32 == args->op.length()) { @@ -63,7 +65,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_) for(i=0; i<15; i++) { imsi *= 10; - imsi += imsi_str[i] - '0'; + imsi += imsi_c[i] - '0'; } } else { usim_log->error("Invalid length for ISMI: %d should be %d", args->imsi.length(), 15); @@ -75,7 +77,7 @@ void usim::init(usim_args_t *args, srslte::log *usim_log_) for(i=0; i<15; i++) { imei *= 10; - imei += imei_str[i] - '0'; + imei += imei_c[i] - '0'; } } else { usim_log->error("Invalid length for IMEI: %d should be %d", args->imei.length(), 15); @@ -103,16 +105,25 @@ void usim::stop() NAS interface *******************************************************************************/ -void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) +std::string usim::get_imsi_str() +{ + return imsi_str; +} +std::string usim::get_imei_str() +{ + return imei_str; +} + +bool usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) { if (!initiated) { fprintf(stderr, "USIM not initiated!\n"); - return; + return false; } if(NULL == imsi_ || n < 15) { usim_log->error("Invalid parameters to get_imsi_vec"); - return; + return false; } uint64_t temp = imsi; @@ -120,18 +131,19 @@ void usim::get_imsi_vec(uint8_t* imsi_, uint32_t n) imsi_[i] = temp % 10; temp /= 10; } + return true; } -void usim::get_imei_vec(uint8_t* imei_, uint32_t n) +bool usim::get_imei_vec(uint8_t* imei_, uint32_t n) { if (!initiated) { fprintf(stderr, "USIM not initiated!\n"); - return; + return false; } if(NULL == imei_ || n < 15) { usim_log->error("Invalid parameters to get_imei_vec"); - return; + return false; } uint64 temp = imei; @@ -140,13 +152,14 @@ void usim::get_imei_vec(uint8_t* imei_, uint32_t n) imei_[i] = temp % 10; temp /= 10; } + return true; } -int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) +bool usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) { if (!initiated) { fprintf(stderr, "USIM not initiated!\n"); - return -1; + return false; } int mcc_len = 3; @@ -180,7 +193,7 @@ int usim::get_home_plmn_id(LIBLTE_RRC_PLMN_IDENTITY_STRUCT *home_plmn_id) usim_log->info("Read Home PLMN Id=%s\n", plmn_id_to_string(*home_plmn_id).c_str()); - return 0; + return true; } void usim::generate_authentication_response(uint8_t *rand, @@ -188,16 +201,18 @@ void usim::generate_authentication_response(uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { if(auth_algo_xor == auth_algo) { - gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res); + gen_auth_res_xor(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); } else { - gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res); + gen_auth_res_milenage(rand, autn_enb, mcc, mnc, net_valid, res, k_asme); } } -void usim::generate_nas_keys(uint8_t *k_nas_enc, +void usim::generate_nas_keys(uint8_t *k_asme, + uint8_t *k_nas_enc, uint8_t *k_nas_int, CIPHERING_ALGORITHM_ID_ENUM cipher_algo, INTEGRITY_ALGORITHM_ID_ENUM integ_algo) @@ -214,7 +229,8 @@ void usim::generate_nas_keys(uint8_t *k_nas_enc, RRC interface *******************************************************************************/ -void usim::generate_as_keys(uint32_t count_ul, +void usim::generate_as_keys(uint8_t *k_asme, + uint32_t count_ul, uint8_t *k_rrc_enc, uint8_t *k_rrc_int, uint8_t *k_up_enc, @@ -251,7 +267,8 @@ void usim::gen_auth_res_milenage( uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { uint32_t i; uint8_t sqn[6]; @@ -320,7 +337,8 @@ void usim::gen_auth_res_xor(uint8_t *rand, uint16_t mcc, uint16_t mnc, bool *net_valid, - uint8_t *res) + uint8_t *res, + uint8_t *k_asme) { uint32_t i; uint8_t sqn[6]; From d562a70261512ccf0096d638bffe7649a1ed499c Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 23 Nov 2017 21:55:49 +0100 Subject: [PATCH 06/22] fix USIM test --- srsue/test/upper/usim_test.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc index c8a248184..00003bc28 100644 --- a/srsue/test/upper/usim_test.cc +++ b/srsue/test/upper/usim_test.cc @@ -61,6 +61,7 @@ KASME : a8.27.57.5e.ea.1a.10.17.3a.a1.bf.ce.4b.0c.21.85.e0.51.ef.bd.91.7f.fe.f uint8_t rand_enb[] = {0x88, 0x38, 0xc3, 0x55, 0xc8, 0x78, 0xaa, 0x57, 0x21, 0x49, 0xfe, 0x69, 0xdb, 0x68, 0x6b, 0x5a}; uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1}; +uint8_t kasme[] = {0xa8, 0x27, 0x57, 0x5e, 0xea, 0x1a, 0x10, 0x17, 0x3a, 0xa1, 0xbf, 0xce, 0x4b, 0x0c, 0x21, 0x85, 0xe0, 0x51, 0xef, 0xbd, 0x91, 0x7f, 0xfe, 0xf5, 0x1f, 0x74, 0x29, 0x61, 0xf9, 0x03, 0x7a, 0x35}; uint16 mcc = 208; uint16 mnc = 93; @@ -74,14 +75,14 @@ int main(int argc, char **argv) usim_args_t args; args.algo = "milenage"; args.amf = "8000"; - args.imei = "35609204079301"; + args.imei = "356092040793011"; args.imsi = "208930000000001"; args.k = "8BAF473F2F8FD09487CCCBD7097C6862"; args.op = "11111111111111111111111111111111"; srsue::usim usim; usim.init(&args, &usim_log); - usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res); + usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res, kasme); assert(net_valid == true); } From 3ebda405801f87a466ce4003a4976d3dce8d9c80 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Thu, 23 Nov 2017 21:56:41 +0100 Subject: [PATCH 07/22] move build info to UE base class --- srsue/hdr/ue_base.h | 4 ++++ srsue/src/ue.cc | 9 +-------- srsue/src/ue_base.cc | 23 ++++++++++++++++++++++- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/srsue/hdr/ue_base.h b/srsue/hdr/ue_base.h index 13e2e4660..e23adf3d2 100644 --- a/srsue/hdr/ue_base.h +++ b/srsue/hdr/ue_base.h @@ -163,6 +163,10 @@ public: srslte::log_filter rf_log; rf_metrics_t rf_metrics; srslte::LOG_LEVEL_ENUM level(std::string l); + + std::string get_build_mode(); + std::string get_build_info(); + std::string get_build_string(); }; } // namespace srsue diff --git a/srsue/src/ue.cc b/srsue/src/ue.cc index 7cb9ebaa1..b7e744bd8 100644 --- a/srsue/src/ue.cc +++ b/srsue/src/ue.cc @@ -32,9 +32,6 @@ #include #include #include -#include -#include -#include "srslte/build_info.h" using namespace srslte; @@ -53,10 +50,6 @@ ue::~ue() bool ue::init(all_args_t *args_) { - std::stringstream ss; - ss << "Built in " << srslte_get_build_mode() << " mode using " << srslte_get_build_info() << "." << std::endl << std::endl; - std::cout << ss.str(); - args = args_; if (!args->log.filename.compare("stdout")) { @@ -64,7 +57,7 @@ bool ue::init(all_args_t *args_) } else { logger_file.init(args->log.filename); logger_file.log("\n\n"); - logger_file.log(ss.str().c_str()); + logger_file.log(get_build_string().c_str()); logger = &logger_file; } diff --git a/srsue/src/ue_base.cc b/srsue/src/ue_base.cc index 94b9b5155..4b2c372ae 100644 --- a/srsue/src/ue_base.cc +++ b/srsue/src/ue_base.cc @@ -24,13 +24,14 @@ * */ - #include "ue_base.h" #include "ue.h" #include "srslte/srslte.h" +#include "srslte/build_info.h" #include #include #include +#include #include #include @@ -58,6 +59,9 @@ ue_base* ue_base::get_instance(srsue_instance_type_t type) } ue_base::ue_base() { + // print build info + std::cout << std::endl << get_build_string() << std::endl; + // load FFTW wisdom srslte_dft_load(); } @@ -116,4 +120,21 @@ srslte::LOG_LEVEL_ENUM ue_base::level(std::string l) } } +std::string ue_base::get_build_mode() +{ + return std::string(srslte_get_build_mode()); +} + +std::string ue_base::get_build_info() +{ + return std::string(srslte_get_build_info()); +} + +std::string ue_base::get_build_string() +{ + std::stringstream ss; + ss << "Built in " << get_build_mode() << " mode using " << get_build_info() << "." << std::endl; + return ss.str(); +} + } // namespace srsue From e035e248b822ee67847fd1c66149ad9d6e1a75c5 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Sat, 25 Nov 2017 23:01:11 +0100 Subject: [PATCH 08/22] Fix bug in sync when not correcting CFO --- lib/src/phy/sync/sync.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 849b64b3b..78e9ca383 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -539,7 +539,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t /* Correct CFO with the averaged CFO estimation */ srslte_cfo_correct(&q->cfocorr2, input, q->temp, -q->mean_cfo / q->fft_size); - input_cfo = q->temp; + input_cfo = q->temp; } /* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */ @@ -549,20 +549,21 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t srslte_vec_prod_ccc(input_cfo, q->cfo_i_corr[q->cfo_i<0?0:1], input_cfo, q->frame_size); INFO("Compensating cfo_i=%d\n", q->cfo_i); } - } else { - srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value); - // this compensates for the constant time shift caused by the low pass filter - if(q->decimate && peak_pos < 0) - { - peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; - } - if (peak_pos < 0) { - fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); - return SRSLTE_ERROR; - } } - + + srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); + peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value); + + // this compensates for the constant time shift caused by the low pass filter + if(q->decimate && peak_pos < 0) + { + peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; + } + if (peak_pos < 0) { + fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); + return SRSLTE_ERROR; + } + if (peak_position) { *peak_position = (uint32_t) peak_pos; } @@ -579,12 +580,15 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t /* If peak is over threshold, compute CFO and SSS */ if (q->peak_value >= q->threshold) { - + + ret = SRSLTE_SYNC_FOUND; + if (q->detect_cp) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_cfo, peak_pos + find_offset)); } else { DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); + ret = SRSLTE_SYNC_FOUND_NOSPACE; } } @@ -597,8 +601,6 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t } else { q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); } - - ret = SRSLTE_SYNC_FOUND; } else { ret = SRSLTE_SYNC_FOUND_NOSPACE; } From 38903de07cc64a29300bda06fb1593deba1f5b85 Mon Sep 17 00:00:00 2001 From: yagoda Date: Mon, 27 Nov 2017 11:10:50 +0000 Subject: [PATCH 09/22] adding simd xor functionality --- lib/include/srslte/phy/utils/simd.h | 115 +++++++++++++++++++++ lib/include/srslte/phy/utils/vector.h | 4 + lib/include/srslte/phy/utils/vector_simd.h | 4 + lib/src/phy/scrambling/scrambling.c | 6 +- lib/src/phy/utils/test/vector_test.c | 34 +++++- lib/src/phy/utils/vector.c | 4 + lib/src/phy/utils/vector_simd.c | 29 ++++++ 7 files changed, 190 insertions(+), 6 deletions(-) diff --git a/lib/include/srslte/phy/utils/simd.h b/lib/include/srslte/phy/utils/simd.h index a9a79c486..cec003886 100644 --- a/lib/include/srslte/phy/utils/simd.h +++ b/lib/include/srslte/phy/utils/simd.h @@ -1506,4 +1506,119 @@ static inline simd_s_t srslte_simd_convert_2f_s(simd_f_t a, simd_f_t b) { #endif /* SRSLTE_SIMD_F_SIZE && SRSLTE_SIMD_C16_SIZE */ +#if SRSLTE_SIMD_B_SIZE +/* Data types */ +#ifdef LV_HAVE_AVX512 +typedef __m512i simd_b_t; +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 +typedef __m256i simd_b_t; +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE +typedef __m128i simd_b_t; +#else /* HAVE_NEON */ +#ifdef HAVE_NEON +typedef int8x16_t simd_b_t; +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ + + + +static inline simd_b_t srslte_simd_b_load(int8_t *ptr){ +#ifdef LV_HAVE_AVX512 + return _mm512_load_si512(ptr); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_load_si256((__m256i*) ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_load_si128((__m128i*) ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_s8(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline simd_b_t srslte_simd_b_loadu(int8_t *ptr){ +#ifdef LV_HAVE_AVX512 + return _mm512_loadu_si512(ptr); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_loadu_si256((__m256i*) ptr); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_loadu_si128((__m128i*) ptr); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return vld1q_s8(ptr); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_b_store(int8_t *ptr, simd_b_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_store_si512(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_store_si256((__m256i*) ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_store_si128((__m128i*) ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_s8( ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +static inline void srslte_simd_b_storeu(int8_t *ptr, simd_b_t simdreg) { +#ifdef LV_HAVE_AVX512 + _mm512_storeu_si512(ptr, simdreg); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + _mm256_storeu_si256((__m256i*) ptr, simdreg); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + _mm_storeu_si128((__m128i*) ptr, simdreg); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + vst1q_s8(ptr, simdreg); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + + +static inline simd_b_t srslte_simd_b_xor(simd_b_t a, simd_b_t b) { + +#ifdef LV_HAVE_AVX512 + return _mm512_xor_epi32(a, b); +#else /* LV_HAVE_AVX512 */ +#ifdef LV_HAVE_AVX2 + return _mm256_xor_si256(a, b); +#else /* LV_HAVE_AVX2 */ +#ifdef LV_HAVE_SSE + return _mm_xor_si128 (a, b); +#else /* LV_HAVE_SSE */ +#ifdef HAVE_NEON + return veorq_s8(a, b); +#endif /* HAVE_NEON */ +#endif /* LV_HAVE_SSE */ +#endif /* LV_HAVE_AVX2 */ +#endif /* LV_HAVE_AVX512 */ +} + +#endif /*SRSLTE_SIMD_B_SIZE */ + + #endif //SRSLTE_SIMD_H_H diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 4a5daefb3..7dad585a0 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -53,6 +53,10 @@ extern "C" { // Exponential moving average #define SRSLTE_VEC_EMA(data, average, alpha) ((alpha)*(data)+(1-alpha)*(average)) + +/*logical operations */ +SRSLTE_API void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, uint32_t len); + /** Return the sum of all the elements */ SRSLTE_API float srslte_vec_acc_ff(float *x, uint32_t len); SRSLTE_API cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len); diff --git a/lib/include/srslte/phy/utils/vector_simd.h b/lib/include/srslte/phy/utils/vector_simd.h index 294cff50f..468c5e11a 100644 --- a/lib/include/srslte/phy/utils/vector_simd.h +++ b/lib/include/srslte/phy/utils/vector_simd.h @@ -53,6 +53,10 @@ extern "C" { #endif /* LV_HAVE_AVX */ #endif /* LV_HAVE_AVX512 */ + +/*SIMD Logical operations*/ +SRSLTE_API void srslte_vec_xor_bbb_simd(int8_t *x, int8_t *y, int8_t *z, int len); + /* SIMD Basic vector math */ SRSLTE_API void srslte_vec_sum_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len); diff --git a/lib/src/phy/scrambling/scrambling.c b/lib/src/phy/scrambling/scrambling.c index 42f16d1e8..ca0342905 100644 --- a/lib/src/phy/scrambling/scrambling.c +++ b/lib/src/phy/scrambling/scrambling.c @@ -60,10 +60,8 @@ void srslte_scrambling_c_offset(srslte_sequence_t *s, cf_t *data, int offset, in } void scrambling_b(uint8_t *c, uint8_t *data, int len) { - int i; - for (i = 0; i < len; i++) { - data[i] = (data[i] ^ c[i]); - } + + srslte_vec_xor_bbb((int8_t*)c,(int8_t*)data,(int8_t*)data,len); } void scrambling_b_word(uint8_t *c, uint8_t *data, int len) { diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c index 9058e8813..a717a7537 100644 --- a/lib/src/phy/utils/test/vector_test.c +++ b/lib/src/phy/utils/test/vector_test.c @@ -47,8 +47,10 @@ bool verbose = false; #define MAX_FUNCTIONS (64) #define MAX_BLOCKS (16) + #define RANDOM_F() ((float)rand())/((float)RAND_MAX) #define RANDOM_S() ((int16_t)(rand() && 0x800F)) +#define RANDOM_B() ((int8_t)(rand() && 0x8008)) #define RANDOM_CF() (RANDOM_F() + _Complex_I*RANDOM_F()) #define TEST_CALL(TEST_CODE) gettimeofday(&start, NULL);\ @@ -87,6 +89,29 @@ float squared_error (cf_t a, cf_t b) { return diff_re*diff_re + diff_im*diff_im; } + TEST(srslte_vec_xor_bbb, + MALLOC(int8_t, x); + MALLOC(int8_t, y); + MALLOC(int8_t, z); + + cf_t gold = 0.0f; + for (int i = 0; i < block_size; i++) { + x[i] = RANDOM_B(); + y[i] = RANDOM_B(); + } + + TEST_CALL(srslte_vec_xor_bbb(x, y, z, block_size)) + + for (int i = 0; i < block_size; i++) { + gold = x[i] ^ y[i]; + mse += cabsf(gold - z[i]); + } + + free(x); + free(y); + free(z); +) + TEST(srslte_vec_acc_ff, MALLOC(float, x); float z; @@ -613,8 +638,8 @@ TEST(srslte_vec_div_fff, cf_t gold; for (int i = 0; i < block_size; i++) { - x[i] = RANDOM_F(); - y[i] = RANDOM_F(); + x[i] = RANDOM_F() + 0.0001; + y[i] = RANDOM_F()+ 0.0001; } TEST_CALL(srslte_vec_div_fff(x, y, z, block_size)) @@ -690,6 +715,11 @@ int main(int argc, char **argv) { for (uint32_t block_size = 1; block_size <= 1024*8; block_size *= 2) { func_count = 0; + + passed[func_count][size_count] = test_srslte_vec_xor_bbb(func_names[func_count], &timmings[func_count][size_count], block_size); + func_count++; + + passed[func_count][size_count] = test_srslte_vec_acc_ff(func_names[func_count], &timmings[func_count][size_count], block_size); func_count++; diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 3bb7fb08f..5d5b6747a 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -37,6 +37,10 @@ +void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, uint32_t len) { + srslte_vec_xor_bbb_simd(x, y, z, len); +} + // Used in PRACH detector, AGC and chest_dl for noise averaging float srslte_vec_acc_ff(float *x, uint32_t len) { return srslte_vec_acc_ff_simd(x, len); diff --git a/lib/src/phy/utils/vector_simd.c b/lib/src/phy/utils/vector_simd.c index 23c58cfce..c7bb7b1fc 100644 --- a/lib/src/phy/utils/vector_simd.c +++ b/lib/src/phy/utils/vector_simd.c @@ -37,6 +37,35 @@ #include "srslte/phy/utils/simd.h" +void srslte_vec_xor_bbb_simd(int8_t *x, int8_t *y, int8_t *z, int len) { + int i = 0; +#if SRSLTE_SIMD_B_SIZE + if (SRSLTE_IS_ALIGNED(x) && SRSLTE_IS_ALIGNED(y) && SRSLTE_IS_ALIGNED(z)) { + for (; i < len - SRSLTE_SIMD_B_SIZE + 1; i += SRSLTE_SIMD_B_SIZE) { + simd_b_t a = srslte_simd_b_load(&x[i]); + simd_b_t b = srslte_simd_b_load(&y[i]); + + simd_b_t r = srslte_simd_b_xor(a, b); + + srslte_simd_b_store(&z[i], r); + } + } else { + for (; i < len - SRSLTE_SIMD_B_SIZE + 1; i += SRSLTE_SIMD_B_SIZE) { + simd_b_t a = srslte_simd_b_loadu(&x[i]); + simd_b_t b = srslte_simd_b_loadu(&y[i]); + + simd_s_t r = srslte_simd_b_xor(a, b); + + srslte_simd_b_storeu(&z[i], r); + } + } +#endif /* SRSLTE_SIMD_B_SIZE */ + + for(; i < len; i++){ + z[i] = x[i] ^ y[i]; + } +} + int srslte_vec_dot_prod_sss_simd(int16_t *x, int16_t *y, int len) { int i = 0; int result = 0; From aacd9e1e5b0f2af65c114809e0459c4a394539fc Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Mon, 27 Nov 2017 18:27:48 +0100 Subject: [PATCH 10/22] Revert "Use CP-based CFO estimation only for DL and UL. Estimate every subframe. Calibrated EMA to 0.3 highest valid for low SNR" This reverts commit 6196c096afbdf4174d334431a06964f23d62b091. --- lib/include/srslte/phy/sync/sync.h | 4 ---- lib/include/srslte/phy/ue/ue_sync.h | 7 +----- lib/src/phy/sync/sync.c | 24 +++++++++----------- lib/src/phy/ue/ue_sync.c | 34 ----------------------------- srsue/src/main.cc | 2 +- srsue/src/phy/phch_worker.cc | 1 - srsue/ue.conf.example | 2 +- 7 files changed, 13 insertions(+), 61 deletions(-) diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 135a19160..1c70b2449 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -139,10 +139,6 @@ SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, uint32_t find_offset, uint32_t *peak_position); -SRSLTE_API float srslte_sync_cfo_estimate(srslte_sync_t *q, - cf_t *input, - int find_offset); - /* Estimates the CP length */ SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index 0d12f846c..e5877dd23 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -88,12 +88,7 @@ typedef struct SRSLTE_API { bool file_mode; float file_cfo; srslte_cfo_t file_cfo_correct; - - bool mean_cfo_isunset; - float cfo; - float mean_cfo; - float cfo_ema_alpha; - + srslte_ue_sync_state_t state; uint32_t frame_len; diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index 78e9ca383..d1a477046 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -581,29 +581,25 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t /* If peak is over threshold, compute CFO and SSS */ if (q->peak_value >= q->threshold) { - ret = SRSLTE_SYNC_FOUND; - if (q->detect_cp) { if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_cfo, peak_pos + find_offset)); } else { DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); - ret = SRSLTE_SYNC_FOUND_NOSPACE; } } - - if (q->enable_cfo_corr) { - if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); - if (q->mean_cfo2_isunset) { - q->mean_cfo2 = cfo2; - q->mean_cfo2_isunset = true; - } else { - q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); - } + if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { + float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); + if (q->mean_cfo2_isunset) { + q->mean_cfo2 = cfo2; + q->mean_cfo2_isunset = true; } else { - ret = SRSLTE_SYNC_FOUND_NOSPACE; + q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); } + + ret = SRSLTE_SYNC_FOUND; + } else { + ret = SRSLTE_SYNC_FOUND_NOSPACE; } } else { ret = SRSLTE_SYNC_NOFOUND; diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index d11811cf3..960d1de66 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -47,10 +47,6 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 - -//#define DO_CFO_IN_SYNC - - cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -188,9 +184,6 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; q->sfo_ema = DEFAULT_SFO_EMA_COEFF; - q->mean_cfo_isunset = true; - q->mean_cfo = 0; - q->cfo_ema_alpha = 0.4; q->max_prb = max_prb; if (search_cell) { @@ -227,11 +220,6 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, } } -#ifndef DO_CFO_IN_SYNC - // Disable CFO correction in sync object and do it here every subframe - srslte_sync_set_cfo_enable(&q->strack, false); -#endif - ret = SRSLTE_SUCCESS; } @@ -376,7 +364,6 @@ uint32_t srslte_ue_sync_peak_idx(srslte_ue_sync_t *q) { void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { srslte_sync_set_cfo_ema_alpha(&q->sfind, ema); srslte_sync_set_cfo_ema_alpha(&q->strack, ema); - q->cfo_ema_alpha = ema; } srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q) { @@ -392,11 +379,7 @@ void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, bool enable) { } float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) { -#ifdef DO_CFO_IN_SYNC return 15000 * srslte_sync_get_cfo(&q->strack); -#else - return 15000 * q->mean_cfo; -#endif } void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { @@ -681,23 +664,6 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; -#ifndef DO_CFO_IN_SYNC - /* We found that CP-based correction performs better in low SNR than PSS-based. - * - * Estimate, average and correct here instead of inside sync object - */ - q->cfo = srslte_sync_cfo_estimate(&q->strack, input_buffer[0], 0); - if (q->mean_cfo_isunset) { - q->mean_cfo = q->cfo; - q->mean_cfo_isunset = false; - } else { - /* compute exponential moving average CFO */ - q->mean_cfo = SRSLTE_VEC_EMA(q->cfo, q->mean_cfo, q->cfo_ema_alpha); - } - srslte_cfo_correct(&q->strack.cfocorr2, input_buffer[0], input_buffer[0], -q->mean_cfo / q->fft_size); - -#endif - /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ if (q->sf_idx == 0 || q->sf_idx == 5) { diff --git a/srsue/src/main.cc b/srsue/src/main.cc index b9717d93e..1c9b6edc6 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -203,7 +203,7 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Tolerance (in Hz) for digial CFO compensation.") ("expert.cfo_ema", - bpo::value(&args->expert.phy.cfo_ema)->default_value(0.3), + bpo::value(&args->expert.phy.cfo_ema)->default_value(0.4), "CFO Exponential Moving Average coefficient. Lower makes it more robust to noise " "but vulnerable to periodic interruptions due to VCO corrections.") diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 54dbb057e..7b4ec48bd 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -128,7 +128,6 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true); - srslte_ue_ul_set_cfo_tol(&ue_ul, phy->args->cfo_correct_tol_hz); mem_initiated = true; diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 3373c562f..867221e87 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -172,7 +172,7 @@ enable = false #attach_enable_64qam = false #nof_phy_threads = 2 #equalizer_mode = mmse -#cfo_ema = 0.3 +#cfo_ema = 0.4 #cfo_integer_enabled = false #cfo_correct_tol_hz = 50 #time_correct_period = 5 From d34ce7441904e58987a1b68aa2b944eab2b0bbf4 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Tue, 28 Nov 2017 13:01:38 +0000 Subject: [PATCH 11/22] NAS security context file tidy-up, usim_test minor edit --- srsue/hdr/upper/nas.h | 47 +++- srsue/src/upper/nas.cc | 433 ++++++++++++---------------------- srsue/test/upper/usim_test.cc | 6 +- 3 files changed, 189 insertions(+), 297 deletions(-) diff --git a/srsue/hdr/upper/nas.h b/srsue/hdr/upper/nas.h index d79eddea8..2e795098e 100644 --- a/srsue/hdr/upper/nas.h +++ b/srsue/hdr/upper/nas.h @@ -116,20 +116,18 @@ private: LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info; - // Identifiers - LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; - bool have_guti; - // Security context struct nas_sec_ctxt{ uint8_t ksi; uint8_t k_asme[32]; uint32_t tx_count; uint32_t rx_count; - srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; - srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo; + srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; + LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti; }; + bool have_guti; bool have_ctxt; nas_sec_ctxt ctxt; @@ -174,13 +172,42 @@ private: void gen_pdn_connectivity_request(LIBLTE_BYTE_MSG_STRUCT *msg); void send_security_mode_reject(uint8_t cause); - // guti persistence file - bool read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti); - bool write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti); - // security context persistence file bool read_ctxt_file(nas_sec_ctxt *ctxt); bool write_ctxt_file(nas_sec_ctxt ctxt); + + // ctxt file helpers + std::string hex_to_string(uint8_t *hex, int size); + bool string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len); + std::string emm_info_str(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *info); + + template + bool readvar(std::istream &file, const char *key, T *var) + { + std::string line; + size_t len = strlen(key); + std::getline(file, line); + if(line.substr(0,len).compare(key)) { + return false; + } + *var = (T)atoi(line.substr(len).c_str()); + return true; + } + + bool readvar(std::istream &file, const char *key, uint8_t *var, int varlen) + { + std::string line; + size_t len = strlen(key); + std::getline(file, line); + if(line.substr(0,len).compare(key)) { + return false; + } + std::string tmp = line.substr(len); + if(!string_to_hex(tmp, var, varlen)) { + return false; + } + return true; + } }; } // namespace srsue diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 2b01efcec..9c24cbf2e 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -38,71 +38,10 @@ using namespace srslte; namespace srsue { + /********************************************************************* - * Conversion helpers + * NAS ********************************************************************/ -std::string hex_to_string(uint8_t *hex, int size) -{ - std::stringstream ss; - - ss << std::hex << std::setfill('0'); - for(int i=0; i(hex[i]); - } - return ss.str(); -} - -bool string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len) -{ - static const char* const lut = "0123456789abcdef"; - uint32_t str_len = hex_str.length(); - if(str_len & 1) { - return false; // uneven hex_str length - } - if(str_len > len*2) { - return false; // not enough space in hex buffer - } - - for(uint32_t i=0; ifull_net_name_present) { - ss << info->full_net_name.name; - } - if(info->short_net_name_present) { - ss << " (" << info->short_net_name.name << ")"; - } - if(info->utc_and_local_time_zone_present) { - ss << " " << (int)info->utc_and_local_time_zone.day; - ss << "/" << (int)info->utc_and_local_time_zone.month; - ss << "/" << (int)info->utc_and_local_time_zone.year; - ss << " " << (int)info->utc_and_local_time_zone.hour; - ss << ":" << (int)info->utc_and_local_time_zone.minute; - ss << ":" << (int)info->utc_and_local_time_zone.second; - ss << " TZ:" << (int)info->utc_and_local_time_zone.tz; - } - return ss.str(); -} - nas::nas() : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), ip_addr(0), eps_bearer_id(0) @@ -132,13 +71,13 @@ void nas::init(usim_interface_nas *usim_, } cfg = cfg_; - if((have_guti = read_guti_file(&guti))) { - if((have_ctxt = read_ctxt_file(&ctxt))) { - usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, - ctxt.cipher_algo, ctxt.integ_algo); - nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); - nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); - } + if((read_ctxt_file(&ctxt))) { + usim->generate_nas_keys(ctxt.k_asme, k_nas_enc, k_nas_int, + ctxt.cipher_algo, ctxt.integ_algo); + nas_log->debug_hex(k_nas_enc, 32, "NAS encryption key - k_nas_enc"); + nas_log->debug_hex(k_nas_int, 32, "NAS integrity key - k_nas_int"); + have_guti = true; + have_ctxt = true; } } @@ -151,8 +90,8 @@ emm_state_t nas::get_state() { } /******************************************************************************* -UE interface -*******************************************************************************/ + * UE interface + ******************************************************************************/ void nas::attach_request() { nas_log->info("Attach Request\n"); @@ -181,8 +120,8 @@ void nas::deattach_request() { } /******************************************************************************* -RRC interface -*******************************************************************************/ + * RRC interface + ******************************************************************************/ void nas::plmn_found(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id, uint16_t tracking_area_code) { @@ -297,8 +236,8 @@ uint32_t nas::get_ul_count() { bool nas::get_s_tmsi(LIBLTE_RRC_S_TMSI_STRUCT *s_tmsi) { if (have_guti) { - s_tmsi->mmec = guti.mme_code; - s_tmsi->m_tmsi = guti.m_tmsi; + s_tmsi->mmec = ctxt.guti.mme_code; + s_tmsi->m_tmsi = ctxt.guti.m_tmsi; return true; } else { return false; @@ -320,8 +259,8 @@ bool nas::get_k_asme(uint8_t *k_asme_, uint32_t n) { } /******************************************************************************* -Security -*******************************************************************************/ + * Security + ******************************************************************************/ void nas::integrity_generate(uint8_t integ_algo, uint8_t *key_128, @@ -381,8 +320,8 @@ bool nas::check_cap_replay(LIBLTE_MME_UE_SECURITY_CAPABILITIES_STRUCT *caps) /******************************************************************************* -Parsers -*******************************************************************************/ + * Parsers + ******************************************************************************/ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; @@ -398,21 +337,19 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { //FIXME: Handle t3412.unit //FIXME: Handle tai_list if (attach_accept.guti_present) { - memcpy(&guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + memcpy(&ctxt.guti, &attach_accept.guti.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); have_guti = true; - write_guti_file(guti); - } - if (attach_accept.lai_present) { } + if (attach_accept.lai_present) {} if (attach_accept.ms_id_present) {} if (attach_accept.emm_cause_present) {} if (attach_accept.t3402_present) {} + if (attach_accept.t3412_ext_present) {} if (attach_accept.t3423_present) {} if (attach_accept.equivalent_plmns_present) {} if (attach_accept.emerg_num_list_present) {} if (attach_accept.eps_network_feature_support_present) {} if (attach_accept.additional_update_result_present) {} - if (attach_accept.t3412_ext_present) {} liblte_mme_unpack_activate_default_eps_bearer_context_request_msg(&attach_accept.esm_msg, &act_def_eps_bearer_context_req); @@ -735,8 +672,8 @@ void nas::parse_emm_information(uint32_t lcid, byte_buffer_t *pdu) { } /******************************************************************************* -Senders -*******************************************************************************/ + * Senders + ******************************************************************************/ void nas::send_attach_request() { LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; @@ -774,14 +711,14 @@ void nas::send_attach_request() { // GUTI or IMSI attach if(have_guti && have_ctxt) { attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI; - memcpy(&attach_req.eps_mobile_id.guti, &guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); + memcpy(&attach_req.eps_mobile_id.guti, &ctxt.guti, sizeof(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT)); attach_req.old_guti_type = LIBLTE_MME_GUTI_TYPE_NATIVE; attach_req.old_guti_type_present = true; attach_req.nas_ksi.tsc_flag = LIBLTE_MME_TYPE_OF_SECURITY_CONTEXT_FLAG_NATIVE; attach_req.nas_ksi.nas_ksi = ctxt.ksi; nas_log->info("Requesting GUTI attach. " "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", - guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code); + ctxt.guti.m_tmsi, ctxt.guti.mcc, ctxt.guti.mnc, ctxt.guti.mme_group_id, ctxt.guti.mme_code); liblte_mme_pack_attach_request_msg(&attach_req, LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY, ctxt.tx_count, @@ -874,103 +811,94 @@ void nas::send_service_request() { void nas::send_esm_information_response() {} -bool nas::read_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT *guti) + +/******************************************************************************* + * Security context persistence file + ******************************************************************************/ + +bool nas::read_ctxt_file(nas_sec_ctxt *ctxt) { std::ifstream file; - std::string line; - if (!guti) { + if(!ctxt) { return false; } - const char *m_tmsi_str = "m_tmsi="; - size_t m_tmsi_str_len = strlen(m_tmsi_str); - const char *mcc_str = "mcc="; - size_t mcc_str_len = strlen(mcc_str); - const char *mnc_str = "mnc="; - size_t mnc_str_len = strlen(mnc_str); - const char *mme_group_id_str = "mme_group_id="; - size_t mme_group_id_str_len = strlen(mme_group_id_str); - const char *mme_code_str = "mme_code="; - size_t mme_code_str_len = strlen(mme_code_str); - - file.open(".guti", std::ios::in); - if (file.is_open()) { - bool read_ok = true; - if (std::getline(file, line)) { - if (!line.substr(0,m_tmsi_str_len).compare(m_tmsi_str)) { - guti->m_tmsi = atoi(line.substr(m_tmsi_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,mcc_str_len).compare(mcc_str)) { - guti->mcc = atoi(line.substr(mcc_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,mnc_str_len).compare(mnc_str)) { - guti->mnc = atoi(line.substr(mnc_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,mme_group_id_str_len).compare(mme_group_id_str)) { - guti->mme_group_id = atoi(line.substr(mme_group_id_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,mme_code_str_len).compare(mme_code_str)) { - guti->mme_code = atoi(line.substr(mme_code_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } + file.open(".ctxt", std::ios::in); + if(file.is_open()) { + if(!readvar(file, "m_tmsi=", &ctxt->guti.m_tmsi)) {return false;} + if(!readvar(file, "mcc=", &ctxt->guti.mcc)) {return false;} + if(!readvar(file, "mnc=", &ctxt->guti.mnc)) {return false;} + if(!readvar(file, "mme_group_id=", &ctxt->guti.mme_group_id)) {return false;} + if(!readvar(file, "mme_code=", &ctxt->guti.mme_code)) {return false;} + if(!readvar(file, "tx_count=", &ctxt->tx_count)) {return false;} + if(!readvar(file, "rx_count=", &ctxt->rx_count)) {return false;} + if(!readvar(file, "int_alg=", &ctxt->integ_algo)) {return false;} + if(!readvar(file, "enc_alg=", &ctxt->cipher_algo)) {return false;} + if(!readvar(file, "ksi=", &ctxt->ksi)) {return false;} + + if(!readvar(file, "k_asme=", ctxt->k_asme, 32)) {return false;} + file.close(); - if (read_ok) { - nas_log->info("Read GUTI from file .guti. " - "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", - guti->m_tmsi, guti->mcc, guti->mnc, guti->mme_group_id, guti->mme_code); - return true; - } else { - nas_log->error("Invalid GUTI file format\n"); - return false; - } + have_guti = true; + nas_log->info("Read GUTI from file " + "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", + ctxt->guti.m_tmsi, + ctxt->guti.mcc, + ctxt->guti.mnc, + ctxt->guti.mme_group_id, + ctxt->guti.mme_code); + have_ctxt = true; + nas_log->info("Read security ctxt from file .ctxt. " + "ksi: %x, k_asme: %s, tx_count: %x, rx_count: %x, int_alg: %d, enc_alg: %d\n", + ctxt->ksi, + hex_to_string(ctxt->k_asme,32).c_str(), + ctxt->tx_count, + ctxt->rx_count, + ctxt->integ_algo, + ctxt->cipher_algo); + return true; + } else { return false; } } -bool nas::write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti) { - std::ofstream file; - if (!have_guti) { +bool nas::write_ctxt_file(nas_sec_ctxt ctxt) +{ + if (!have_guti || !have_ctxt) { return false; } - file.open(".guti", std::ios::out | std::ios::trunc); + std::ofstream file; + file.open(".ctxt", std::ios::out | std::ios::trunc); if (file.is_open()) { - file << "m_tmsi=" << (int) guti.m_tmsi << std::endl; - file << "mcc=" << (int) guti.mcc << std::endl; - file << "mnc=" << (int) guti.mnc << std::endl; - file << "mme_group_id=" << (int) guti.mme_group_id << std::endl; - file << "mme_code=" << (int) guti.mme_code << std::endl; - nas_log->info("Saved GUTI to file .guti. " + file << "m_tmsi=" << (int) ctxt.guti.m_tmsi << std::endl; + file << "mcc=" << (int) ctxt.guti.mcc << std::endl; + file << "mnc=" << (int) ctxt.guti.mnc << std::endl; + file << "mme_group_id=" << (int) ctxt.guti.mme_group_id << std::endl; + file << "mme_code=" << (int) ctxt.guti.mme_code << std::endl; + file << "tx_count=" << (int) ctxt.tx_count << std::endl; + file << "rx_count=" << (int) ctxt.rx_count << std::endl; + file << "int_alg=" << (int) ctxt.integ_algo << std::endl; + file << "enc_alg=" << (int) ctxt.cipher_algo << std::endl; + file << "ksi=" << (int) ctxt.ksi << std::endl; + + file << "k_asme=" << hex_to_string(ctxt.k_asme, 32) << std::endl; + + nas_log->info("Saved GUTI to file " "m_tmsi: %x, mcc: %x, mnc: %x, mme_group_id: %x, mme_code: %x\n", - guti.m_tmsi, guti.mcc, guti.mnc, guti.mme_group_id, guti.mme_code); + ctxt.guti.m_tmsi, + ctxt.guti.mcc, + ctxt.guti.mnc, + ctxt.guti.mme_group_id, + ctxt.guti.mme_code); + nas_log->info("Saved security ctxt to file .ctxt. " + "ksi: %x, k_asme: %s, tx_count: %x, rx_count: %x, int_alg: %d, enc_alg: %d\n", + ctxt.ksi, + hex_to_string(ctxt.k_asme,32).c_str(), + ctxt.tx_count, + ctxt.rx_count, + ctxt.integ_algo, + ctxt.cipher_algo); file.close(); return true; } else { @@ -978,129 +906,66 @@ bool nas::write_guti_file(LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti) { } } -bool nas::read_ctxt_file(nas_sec_ctxt *ctxt) +/********************************************************************* + * Conversion helpers + ********************************************************************/ +std::string nas::hex_to_string(uint8_t *hex, int size) { - std::ifstream file; - std::string line; - if (!ctxt) { - return false; - } + std::stringstream ss; - const char *ksi_str = "ksi="; - size_t ksi_str_len = strlen(ksi_str); - const char *k_asme_str = "k_asme="; - size_t k_asme_str_len = strlen(k_asme_str); - const char *tx_count_str = "tx_count="; - size_t tx_count_str_len = strlen(tx_count_str); - const char *rx_count_str = "rx_count="; - size_t rx_count_str_len = strlen(rx_count_str); - const char *int_alg_str = "int_alg="; - size_t int_alg_str_len = strlen(int_alg_str); - const char *enc_alg_str = "enc_alg="; - size_t enc_alg_str_len = strlen(enc_alg_str); + ss << std::hex << std::setfill('0'); + for(int i=0; i(hex[i]); + } + return ss.str(); +} - file.open(".ctxt", std::ios::in); - if (file.is_open()) { - bool read_ok = true; - if (std::getline(file, line)) { - if (!line.substr(0,ksi_str_len).compare(ksi_str)) { - ctxt->ksi = atoi(line.substr(ksi_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,k_asme_str_len).compare(k_asme_str)) { - std::string tmp = line.substr(k_asme_str_len); - if(!string_to_hex(tmp, ctxt->k_asme, 32)) { - read_ok = false; - } - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,tx_count_str_len).compare(tx_count_str)) { - ctxt->tx_count = atoi(line.substr(tx_count_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,rx_count_str_len).compare(rx_count_str)) { - ctxt->rx_count = atoi(line.substr(rx_count_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,int_alg_str_len).compare(int_alg_str)) { - ctxt->integ_algo = (srslte::INTEGRITY_ALGORITHM_ID_ENUM)atoi(line.substr(int_alg_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; - } - if (std::getline(file, line)) { - if (!line.substr(0,enc_alg_str_len).compare(enc_alg_str)) { - ctxt->cipher_algo = (srslte::CIPHERING_ALGORITHM_ID_ENUM)atoi(line.substr(enc_alg_str_len).c_str()); - } else { - read_ok = false; - } - } else { - read_ok = false; +bool nas::string_to_hex(std::string hex_str, uint8_t *hex, uint32_t len) +{ + static const char* const lut = "0123456789abcdef"; + uint32_t str_len = hex_str.length(); + if(str_len & 1) { + return false; // uneven hex_str length + } + if(str_len > len*2) { + return false; // not enough space in hex buffer + } + for(uint32_t i=0; iinfo("Read security ctxt from file .ctxt. " - "ksi: %x, k_asme: %s, " - "tx_count: %x, rx_count: %x, " - "int_alg: %d, enc_alg: %d\n", - ctxt->ksi, hex_to_string(ctxt->k_asme,32).c_str(), - ctxt->tx_count, ctxt->rx_count, - ctxt->integ_algo, ctxt->cipher_algo); - return true; - } else { - nas_log->error("Invalid security ctxt file format\n"); - return false; + char b = hex_str[i+1]; + const char* q = std::lower_bound(lut, lut + 16, b); + if (*q != b) { + return false; // invalid char } - } else { - return false; + hex[i/2] = ((p - lut) << 4) | (q - lut); } + return true; } -bool nas::write_ctxt_file(nas_sec_ctxt ctxt) +std::string nas::emm_info_str(LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT *info) { - std::ofstream file; - file.open(".ctxt", std::ios::out | std::ios::trunc); - if (file.is_open()) { - file << "ksi=" << (int) ctxt.ksi << std::endl; - file << "k_asme=" << hex_to_string(ctxt.k_asme, 32) << std::endl; - file << "tx_count=" << (int) ctxt.tx_count << std::endl; - file << "rx_count=" << (int) ctxt.rx_count << std::endl; - file << "int_alg=" << (int) ctxt.integ_algo << std::endl; - file << "enc_alg=" << (int) ctxt.cipher_algo << std::endl; - nas_log->info("Saved security ctxt to file .ctxt. " - "ksi: %x, k_asme: %s, " - "tx_count: %x, rx_count: %x, " - "int_alg: %d, enc_alg: %d\n", - ctxt.ksi, hex_to_string(ctxt.k_asme,32).c_str(), - ctxt.tx_count, ctxt.rx_count, - ctxt.integ_algo, ctxt.cipher_algo); - file.close(); - return true; - } else { - return false; + std::stringstream ss; + if(info->full_net_name_present) { + ss << info->full_net_name.name; + } + if(info->short_net_name_present) { + ss << " (" << info->short_net_name.name << ")"; } + if(info->utc_and_local_time_zone_present) { + ss << " " << (int)info->utc_and_local_time_zone.day; + ss << "/" << (int)info->utc_and_local_time_zone.month; + ss << "/" << (int)info->utc_and_local_time_zone.year; + ss << " " << (int)info->utc_and_local_time_zone.hour; + ss << ":" << (int)info->utc_and_local_time_zone.minute; + ss << ":" << (int)info->utc_and_local_time_zone.second; + ss << " TZ:" << (int)info->utc_and_local_time_zone.tz; + } + return ss.str(); } diff --git a/srsue/test/upper/usim_test.cc b/srsue/test/upper/usim_test.cc index 00003bc28..4ac468673 100644 --- a/srsue/test/upper/usim_test.cc +++ b/srsue/test/upper/usim_test.cc @@ -61,7 +61,6 @@ KASME : a8.27.57.5e.ea.1a.10.17.3a.a1.bf.ce.4b.0c.21.85.e0.51.ef.bd.91.7f.fe.f uint8_t rand_enb[] = {0x88, 0x38, 0xc3, 0x55, 0xc8, 0x78, 0xaa, 0x57, 0x21, 0x49, 0xfe, 0x69, 0xdb, 0x68, 0x6b, 0x5a}; uint8_t autn_enb[] = {0xd7, 0x44, 0x51, 0x9b, 0x25, 0xaa, 0x80, 0x00, 0x84, 0xba, 0x37, 0xb0, 0xf6, 0x73, 0x4d, 0xd1}; -uint8_t kasme[] = {0xa8, 0x27, 0x57, 0x5e, 0xea, 0x1a, 0x10, 0x17, 0x3a, 0xa1, 0xbf, 0xce, 0x4b, 0x0c, 0x21, 0x85, 0xe0, 0x51, 0xef, 0xbd, 0x91, 0x7f, 0xfe, 0xf5, 0x1f, 0x74, 0x29, 0x61, 0xf9, 0x03, 0x7a, 0x35}; uint16 mcc = 208; uint16 mnc = 93; @@ -71,18 +70,19 @@ int main(int argc, char **argv) srslte::log_filter usim_log("USIM"); bool net_valid; uint8_t res[16]; + uint8_t k_asme[32]; usim_args_t args; args.algo = "milenage"; args.amf = "8000"; - args.imei = "356092040793011"; + args.imei = "35609204079301"; args.imsi = "208930000000001"; args.k = "8BAF473F2F8FD09487CCCBD7097C6862"; args.op = "11111111111111111111111111111111"; srsue::usim usim; usim.init(&args, &usim_log); - usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res, kasme); + usim.generate_authentication_response(rand_enb, autn_enb, mcc, mnc, &net_valid, res, k_asme); assert(net_valid == true); } From 0d7af888222b2c6cd5fed406875ca082b7d457e5 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 28 Nov 2017 15:51:40 +0100 Subject: [PATCH 12/22] Add noise reduction in PSS before estimating CFO --- lib/include/srslte/phy/sync/pss.h | 16 ++-- lib/src/phy/sync/pss.c | 146 +++++++++++++++++------------- 2 files changed, 94 insertions(+), 68 deletions(-) diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index 9760a178c..d590cf2e6 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -70,9 +70,7 @@ /* Low-level API */ typedef struct SRSLTE_API { - - srslte_dft_plan_t dftp_input; - + #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_t conv_fft; srslte_filt_cc_t filter; @@ -87,16 +85,22 @@ typedef struct SRSLTE_API { uint32_t N_id_2; uint32_t fft_size; cf_t *pss_signal_freq_full[3]; - + cf_t *pss_signal_time[3]; - + cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; cf_t *conv_output; float *conv_output_abs; - float ema_alpha; + float ema_alpha; float *conv_output_avg; float peak_value; + + srslte_dft_plan_t dftp_input; + srslte_dft_plan_t idftp_input; + cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; + cf_t yr[SRSLTE_PSS_LEN]; + }srslte_pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index f7b35071d..9333567ff 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -137,9 +137,15 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } srslte_dft_plan_set_mirror(&q->dftp_input, true); srslte_dft_plan_set_dc(&q->dftp_input, true); - srslte_dft_plan_set_norm(&q->dftp_input, true); - q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); + if (srslte_dft_plan(&q->idftp_input, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { + fprintf(stderr, "Error creating DFT plan \n"); + goto clean_and_exit; + } + srslte_dft_plan_set_mirror(&q->idftp_input, true); + srslte_dft_plan_set_dc(&q->idftp_input, true); + + q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; @@ -167,7 +173,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } bzero(q->conv_output_abs, sizeof(float) * buffer_size); #endif - + for (N_id_2=0;N_id_2<3;N_id_2++) { q->pss_signal_time[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (!q->pss_signal_time[N_id_2]) { @@ -178,14 +184,14 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; - } + } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); - } + } #ifdef CONVOLUTION_FFT for(N_id_2=0; N_id_2<3; N_id_2++) - q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); @@ -194,15 +200,15 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, for(int i=0; i<3; i++) { srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); } - + #endif - + srslte_pss_synch_reset(q); - + ret = SRSLTE_SUCCESS; } -clean_and_exit: +clean_and_exit: if (ret == SRSLTE_ERROR) { srslte_pss_synch_free(q); } @@ -298,7 +304,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_free(&q->conv_fft); - + #endif if (q->tmp_input) { free(q->tmp_input); @@ -312,9 +318,10 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { if (q->conv_output_avg) { free(q->conv_output_avg); } - + srslte_dft_plan_free(&q->dftp_input); - + srslte_dft_plan_free(&q->idftp_input); + if(q->decimate > 1) { srslte_filt_decim_cc_free(&q->filter); @@ -323,7 +330,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_synch_t)); } } @@ -379,7 +386,7 @@ void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, srslte_ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp) { int k; k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; - memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); + memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); } @@ -398,34 +405,34 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output */ void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { - q->ema_alpha = alpha; + q->ema_alpha = alpha; } -/** Performs time-domain PSS correlation. +/** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) +int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && + + if (q != NULL && input != NULL) { uint32_t corr_peak_pos; uint32_t conv_output_len; - + if (!srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } /* Correlate input with PSS sequence - * + * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. * The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 * This is why we can use FFT-based convolution @@ -442,7 +449,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe { conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); } - + #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif @@ -450,19 +457,19 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe for (int i=0;iframe_size;i++) { q->conv_output[i] = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], &input[i], q->fft_size); } - conv_output_len = q->frame_size; + conv_output_len = q->frame_size; } - + #ifdef SRSLTE_PSS_ABS_SQUARE srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #else srslte_vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #endif - + if (q->ema_alpha < 1.0 && q->ema_alpha > 0.0) { - srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); - srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); srslte_vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); } else { @@ -470,43 +477,43 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe } /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); - - // save absolute value + + // save absolute value q->peak_value = q->conv_output_avg[corr_peak_pos]; - -#ifdef SRSLTE_PSS_RETURN_PSR + +#ifdef SRSLTE_PSS_RETURN_PSR // Find second side lobe - + // Find end of peak lobe to the right int pl_ub = corr_peak_pos+1; while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { - pl_ub ++; + pl_ub ++; } // Find end of peak lobe to the left - int pl_lb; + int pl_lb; if (corr_peak_pos > 2) { pl_lb = corr_peak_pos-1; while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { - pl_lb --; - } + pl_lb --; + } } else { - pl_lb = 0; + pl_lb = 0; } - int sl_distance_right = conv_output_len-1-pl_ub; + int sl_distance_right = conv_output_len-1-pl_ub; if (sl_distance_right < 0) { - sl_distance_right = 0; + sl_distance_right = 0; } - int sl_distance_left = pl_lb; - + int sl_distance_left = pl_lb; + int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); - int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); - float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); + int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); + float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; - + if (*corr_peak_value < 10) - DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, + DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); } #else @@ -514,7 +521,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif - + if(q->decimate >1) { int decimation_correction = (q->filter.num_taps - 2); @@ -524,23 +531,23 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe if (q->frame_size >= q->fft_size) { - ret = (int) corr_peak_pos; + ret = (int) corr_peak_pos; } else { ret = (int) corr_peak_pos + q->fft_size; } - } + } return ret; } -/* Computes frequency-domain channel estimation of the PSS symbol - * input signal is in the time-domain. - * ce is the returned frequency-domain channel estimates. +/* Computes frequency-domain channel estimation of the PSS symbol + * input signal is in the time-domain. + * ce is the returned frequency-domain channel estimates. */ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; - if (q != NULL && + if (q != NULL && input != NULL) { @@ -548,31 +555,46 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } - + /* Transform to frequency-domain */ srslte_dft_run_c(&q->dftp_input, input, input_fft); - + /* Compute channel estimate taking the PSS sequence as reference */ srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); - + ret = SRSLTE_SUCCESS; } - return ret; + return ret; } +#define CLEAN_NOISE_DFT +//#define PSS_CFO_FREQ /* Returns the CFO estimation given a PSS received sequence * * Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Feng Wang and Yu Zhu */ float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, cf_t *pss_recv) { - cf_t y0, y1, yr; + cf_t y0, y1; + +#ifdef PSS_CFO_FREQ + + srslte_vec_prod_conj_ccc(&q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss_signal_freq[q->N_id_2], q->yr, SRSLTE_PSS_LEN); + y0 = srslte_vec_acc_cc(q->yr, SRSLTE_PSS_LEN/2); + y1 = srslte_vec_acc_cc(&q->yr[SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN/2); + +#else +#ifdef CLEAN_NOISE_DFT + // Eliminate noise + srslte_dft_run_c(&q->dftp_input, pss_recv, q->tmp_fft); + bzero(q->tmp_fft, sizeof(cf_t)*(q->fft_size/2-SRSLTE_PSS_LEN/2)); + bzero(&q->tmp_fft[q->fft_size/2+SRSLTE_PSS_LEN/2], sizeof(cf_t)*(q->fft_size/2-SRSLTE_PSS_LEN/2)); + srslte_dft_run_c(&q->idftp_input, q->tmp_fft, pss_recv); +#endif y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_recv, q->fft_size/2); y1 = srslte_vec_dot_prod_ccc(&q->pss_signal_time[q->N_id_2][q->fft_size/2], &pss_recv[q->fft_size/2], q->fft_size/2); - - yr = conjf(y0) * y1; - - return atan2f(__imag__ yr, __real__ yr) / M_PI; +#endif + return carg(conjf(y0) * y1)/M_PI; } From 15a13043951a34402c3cc70d56af1c01b3691a64 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Tue, 28 Nov 2017 16:20:40 +0100 Subject: [PATCH 13/22] Revert "Add noise reduction in PSS before estimating CFO" This reverts commit 0d7af888222b2c6cd5fed406875ca082b7d457e5. --- lib/include/srslte/phy/sync/pss.h | 16 ++-- lib/src/phy/sync/pss.c | 146 +++++++++++++----------------- 2 files changed, 68 insertions(+), 94 deletions(-) diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index d590cf2e6..9760a178c 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -70,7 +70,9 @@ /* Low-level API */ typedef struct SRSLTE_API { - + + srslte_dft_plan_t dftp_input; + #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_t conv_fft; srslte_filt_cc_t filter; @@ -85,22 +87,16 @@ typedef struct SRSLTE_API { uint32_t N_id_2; uint32_t fft_size; cf_t *pss_signal_freq_full[3]; - + cf_t *pss_signal_time[3]; - + cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; cf_t *conv_output; float *conv_output_abs; - float ema_alpha; + float ema_alpha; float *conv_output_avg; float peak_value; - - srslte_dft_plan_t dftp_input; - srslte_dft_plan_t idftp_input; - cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; - cf_t yr[SRSLTE_PSS_LEN]; - }srslte_pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index 9333567ff..f7b35071d 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -137,15 +137,9 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } srslte_dft_plan_set_mirror(&q->dftp_input, true); srslte_dft_plan_set_dc(&q->dftp_input, true); + srslte_dft_plan_set_norm(&q->dftp_input, true); - if (srslte_dft_plan(&q->idftp_input, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { - fprintf(stderr, "Error creating DFT plan \n"); - goto clean_and_exit; - } - srslte_dft_plan_set_mirror(&q->idftp_input, true); - srslte_dft_plan_set_dc(&q->idftp_input, true); - - q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); + q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; @@ -173,7 +167,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } bzero(q->conv_output_abs, sizeof(float) * buffer_size); #endif - + for (N_id_2=0;N_id_2<3;N_id_2++) { q->pss_signal_time[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (!q->pss_signal_time[N_id_2]) { @@ -184,14 +178,14 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; - } + } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); - } + } #ifdef CONVOLUTION_FFT for(N_id_2=0; N_id_2<3; N_id_2++) - q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); @@ -200,15 +194,15 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, for(int i=0; i<3; i++) { srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); } - + #endif - + srslte_pss_synch_reset(q); - + ret = SRSLTE_SUCCESS; } -clean_and_exit: +clean_and_exit: if (ret == SRSLTE_ERROR) { srslte_pss_synch_free(q); } @@ -304,7 +298,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_free(&q->conv_fft); - + #endif if (q->tmp_input) { free(q->tmp_input); @@ -318,10 +312,9 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { if (q->conv_output_avg) { free(q->conv_output_avg); } - + srslte_dft_plan_free(&q->dftp_input); - srslte_dft_plan_free(&q->idftp_input); - + if(q->decimate > 1) { srslte_filt_decim_cc_free(&q->filter); @@ -330,7 +323,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_synch_t)); } } @@ -386,7 +379,7 @@ void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, srslte_ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp) { int k; k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; - memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); + memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); } @@ -405,34 +398,34 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output */ void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { - q->ema_alpha = alpha; + q->ema_alpha = alpha; } -/** Performs time-domain PSS correlation. +/** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) +int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && + + if (q != NULL && input != NULL) { uint32_t corr_peak_pos; uint32_t conv_output_len; - + if (!srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } /* Correlate input with PSS sequence - * + * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. * The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 * This is why we can use FFT-based convolution @@ -449,7 +442,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe { conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); } - + #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif @@ -457,19 +450,19 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe for (int i=0;iframe_size;i++) { q->conv_output[i] = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], &input[i], q->fft_size); } - conv_output_len = q->frame_size; + conv_output_len = q->frame_size; } - + #ifdef SRSLTE_PSS_ABS_SQUARE srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #else srslte_vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #endif - + if (q->ema_alpha < 1.0 && q->ema_alpha > 0.0) { - srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); - srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); srslte_vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); } else { @@ -477,43 +470,43 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe } /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); - - // save absolute value + + // save absolute value q->peak_value = q->conv_output_avg[corr_peak_pos]; - -#ifdef SRSLTE_PSS_RETURN_PSR + +#ifdef SRSLTE_PSS_RETURN_PSR // Find second side lobe - + // Find end of peak lobe to the right int pl_ub = corr_peak_pos+1; while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { - pl_ub ++; + pl_ub ++; } // Find end of peak lobe to the left - int pl_lb; + int pl_lb; if (corr_peak_pos > 2) { pl_lb = corr_peak_pos-1; while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { - pl_lb --; - } + pl_lb --; + } } else { - pl_lb = 0; + pl_lb = 0; } - int sl_distance_right = conv_output_len-1-pl_ub; + int sl_distance_right = conv_output_len-1-pl_ub; if (sl_distance_right < 0) { - sl_distance_right = 0; + sl_distance_right = 0; } - int sl_distance_left = pl_lb; - + int sl_distance_left = pl_lb; + int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); - int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); - float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); + int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); + float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; - + if (*corr_peak_value < 10) - DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, + DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); } #else @@ -521,7 +514,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif - + if(q->decimate >1) { int decimation_correction = (q->filter.num_taps - 2); @@ -531,23 +524,23 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe if (q->frame_size >= q->fft_size) { - ret = (int) corr_peak_pos; + ret = (int) corr_peak_pos; } else { ret = (int) corr_peak_pos + q->fft_size; } - } + } return ret; } -/* Computes frequency-domain channel estimation of the PSS symbol - * input signal is in the time-domain. - * ce is the returned frequency-domain channel estimates. +/* Computes frequency-domain channel estimation of the PSS symbol + * input signal is in the time-domain. + * ce is the returned frequency-domain channel estimates. */ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; - if (q != NULL && + if (q != NULL && input != NULL) { @@ -555,46 +548,31 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } - + /* Transform to frequency-domain */ srslte_dft_run_c(&q->dftp_input, input, input_fft); - + /* Compute channel estimate taking the PSS sequence as reference */ srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); - + ret = SRSLTE_SUCCESS; } - return ret; + return ret; } -#define CLEAN_NOISE_DFT -//#define PSS_CFO_FREQ /* Returns the CFO estimation given a PSS received sequence * * Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Feng Wang and Yu Zhu */ float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, cf_t *pss_recv) { - cf_t y0, y1; - -#ifdef PSS_CFO_FREQ - - srslte_vec_prod_conj_ccc(&q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], q->pss_signal_freq[q->N_id_2], q->yr, SRSLTE_PSS_LEN); - y0 = srslte_vec_acc_cc(q->yr, SRSLTE_PSS_LEN/2); - y1 = srslte_vec_acc_cc(&q->yr[SRSLTE_PSS_LEN/2], SRSLTE_PSS_LEN/2); - -#else -#ifdef CLEAN_NOISE_DFT - // Eliminate noise - srslte_dft_run_c(&q->dftp_input, pss_recv, q->tmp_fft); - bzero(q->tmp_fft, sizeof(cf_t)*(q->fft_size/2-SRSLTE_PSS_LEN/2)); - bzero(&q->tmp_fft[q->fft_size/2+SRSLTE_PSS_LEN/2], sizeof(cf_t)*(q->fft_size/2-SRSLTE_PSS_LEN/2)); - srslte_dft_run_c(&q->idftp_input, q->tmp_fft, pss_recv); -#endif + cf_t y0, y1, yr; y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_recv, q->fft_size/2); y1 = srslte_vec_dot_prod_ccc(&q->pss_signal_time[q->N_id_2][q->fft_size/2], &pss_recv[q->fft_size/2], q->fft_size/2); -#endif - return carg(conjf(y0) * y1)/M_PI; + + yr = conjf(y0) * y1; + + return atan2f(__imag__ yr, __real__ yr) / M_PI; } From 2fd2f151576c4ff19afb3c6ea2e8d9973aec070b Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 29 Nov 2017 11:30:10 +0100 Subject: [PATCH 14/22] Cell RS based CFO estimation --- .../srslte/phy/ch_estimation/chest_dl.h | 10 ++++- lib/src/phy/ch_estimation/chest_dl.c | 43 ++++++++++++++++--- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index 0e43d113c..229495a9b 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -82,7 +82,11 @@ typedef struct { float rssi[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float rsrp[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; - + float cfo; + + bool cfo_estimate_enable; + uint32_t cfo_estimate_sf_mask; + /* Use PSS for noise estimation in LS linear interpolation mode */ cf_t pss_signal[SRSLTE_PSS_LEN]; cf_t tmp_pss[SRSLTE_PSS_LEN]; @@ -144,8 +148,12 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, uint32_t port_id, uint32_t rxant_id); +SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask); + SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); +SRSLTE_API float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q); + SRSLTE_API float srslte_chest_dl_get_snr(srslte_chest_dl_t *q); SRSLTE_API float srslte_chest_dl_get_rssi(srslte_chest_dl_t *q); diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 0f8ae8074..60d62a004 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -410,6 +410,30 @@ float srslte_chest_dl_rssi(srslte_chest_dl_t *q, cf_t *input, uint32_t port_id) return rssi/nsymbols; } +// CFO estimation algorithm taken from "Carrier Frequency Synchronization in the +// Downlink of 3GPP LTE", Qi Wang, C. Mehlfuhrer, M. Rupp +float chest_estimate_cfo(srslte_chest_dl_t *q) +{ + float n = (float) srslte_symbol_sz(q->cell.nof_prb); + float ns = (float) SRSLTE_CP_NSYMB(q->cell.cp); + float ng = (float) SRSLTE_CP_LEN_NORM(1, n); + + uint32_t npilots = SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, 0); + + // Compute angles between slots + for (int i=0;i<2;i++) { + srslte_vec_prod_conj_ccc(&q->pilot_estimates[i*npilots/4], + &q->pilot_estimates[(i+2)*npilots/4], + &q->tmp_noise[i*npilots/4], + npilots/4); + } + // Average all angles + cf_t sum = srslte_vec_acc_cc(q->tmp_noise, npilots/2); + + // Compute CFO + return -cargf(sum)*n/(ns*(n+ng))/2/M_PI; +} + void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, srslte_sf_t ch_mode){ if (ce != NULL) { /* Smooth estimates (if applicable) and interpolate */ @@ -433,6 +457,10 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui } } } + + if (q->cfo_estimate_enable && ((1<cfo_estimate_sf_mask)) { + q->cfo = chest_estimate_cfo(q); + } /* Compute RSRP for the channel estimates in this port */ q->rsrp[rxant_id][port_id] = srslte_vec_avg_power_cf(q->pilot_recv_signal, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); @@ -451,8 +479,9 @@ int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, u srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->csr_refs.pilots[port_id/2][sf_idx], q->pilot_estimates, SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + chest_interpolate_noise_est(q, input, ce, sf_idx, port_id, rxant_id, SRSLTE_SF_NORM); - + return 0; } int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id, uint32_t rxant_id, uint16_t mbsfn_area_id) @@ -474,10 +503,6 @@ int srslte_chest_dl_estimate_port_mbsfn(srslte_chest_dl_t *q, cf_t *input, cf_t return 0; } - - - - int srslte_chest_dl_estimate_multi(srslte_chest_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], cf_t *ce[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t nof_rx_antennas) { for (uint32_t rxant_id=0;rxant_idcfo_estimate_enable = enable; + q->cfo_estimate_sf_mask = mask; +} +float srslte_chest_dl_get_cfo(srslte_chest_dl_t *q) { + return q->cfo; +} float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q) { float n = 0; From 2772471e41692f3893a3856b7205a035da3ff027 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 29 Nov 2017 11:58:18 +0100 Subject: [PATCH 15/22] Added filtering function to PSS --- lib/include/srslte/phy/sync/pss.h | 24 +++-- lib/src/phy/sync/pss.c | 168 ++++++++++++++++++------------ 2 files changed, 118 insertions(+), 74 deletions(-) diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index 9760a178c..f94b2deba 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -70,9 +70,7 @@ /* Low-level API */ typedef struct SRSLTE_API { - - srslte_dft_plan_t dftp_input; - + #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_t conv_fft; srslte_filt_cc_t filter; @@ -87,16 +85,23 @@ typedef struct SRSLTE_API { uint32_t N_id_2; uint32_t fft_size; cf_t *pss_signal_freq_full[3]; - + cf_t *pss_signal_time[3]; - + cf_t pss_signal_freq[3][SRSLTE_PSS_LEN]; // One sequence for each N_id_2 cf_t *tmp_input; cf_t *conv_output; float *conv_output_abs; - float ema_alpha; + float ema_alpha; float *conv_output_avg; float peak_value; + + bool filter_pss_enable; + srslte_dft_plan_t dftp_input; + srslte_dft_plan_t idftp_input; + cf_t tmp_fft[SRSLTE_SYMBOL_SZ_MAX]; + cf_t tmp_fft2[SRSLTE_SYMBOL_SZ_MAX]; + }srslte_pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; @@ -128,6 +133,13 @@ SRSLTE_API void srslte_pss_synch_free(srslte_pss_synch_t *q); SRSLTE_API void srslte_pss_synch_reset(srslte_pss_synch_t *q); +SRSLTE_API void srslte_pss_synch_filter_enable(srslte_pss_synch_t *q, + bool enable); + +SRSLTE_API void srslte_pss_synch_filter(srslte_pss_synch_t *q, + cf_t *input, + cf_t *output); + SRSLTE_API int srslte_pss_generate(cf_t *signal, uint32_t N_id_2); diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index f7b35071d..411579d7c 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -30,12 +30,8 @@ #include #include #include -#include #include "srslte/phy/sync/pss.h" -#include "srslte/phy/dft/dft.h" -#include "srslte/phy/utils/vector.h" -#include "srslte/phy/utils/convolution.h" #include "srslte/phy/utils/debug.h" @@ -69,7 +65,7 @@ int srslte_pss_synch_init_N_id_2(cf_t *pss_signal_freq, cf_t *pss_signal_time, srslte_vec_sc_prod_cfc(pss_signal_time, 1.0/SRSLTE_PSS_LEN, pss_signal_time, fft_size); srslte_dft_plan_free(&plan); - + ret = SRSLTE_SUCCESS; } return ret; @@ -123,6 +119,8 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, buffer_size = fft_size + frame_size + 1; + q->filter_pss_enable = true; + if(q->decimate > 1) { int filter_order = 3; srslte_filt_decim_cc_init(&q->filter,q->decimate,filter_order); @@ -137,9 +135,19 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } srslte_dft_plan_set_mirror(&q->dftp_input, true); srslte_dft_plan_set_dc(&q->dftp_input, true); - srslte_dft_plan_set_norm(&q->dftp_input, true); + srslte_dft_plan_set_norm(&q->dftp_input, false); - q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); + if (srslte_dft_plan(&q->idftp_input, fft_size, SRSLTE_DFT_BACKWARD, SRSLTE_DFT_COMPLEX)) { + fprintf(stderr, "Error creating DFT plan \n"); + goto clean_and_exit; + } + srslte_dft_plan_set_mirror(&q->idftp_input, true); + srslte_dft_plan_set_dc(&q->idftp_input, true); + srslte_dft_plan_set_norm(&q->idftp_input, true); + + bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); + + q->tmp_input = srslte_vec_malloc((buffer_size + frame_size*(q->decimate - 1)) * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; @@ -167,7 +175,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, } bzero(q->conv_output_abs, sizeof(float) * buffer_size); #endif - + for (N_id_2=0;N_id_2<3;N_id_2++) { q->pss_signal_time[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (!q->pss_signal_time[N_id_2]) { @@ -178,14 +186,14 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, if (srslte_pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], q->pss_signal_time[N_id_2], N_id_2, fft_size, offset)) { fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); goto clean_and_exit; - } + } bzero(&q->pss_signal_time[N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); - } + } #ifdef CONVOLUTION_FFT for(N_id_2=0; N_id_2<3; N_id_2++) - q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); + q->pss_signal_freq_full[N_id_2] = srslte_vec_malloc(buffer_size * sizeof(cf_t)); if (srslte_conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { fprintf(stderr, "Error initiating convolution FFT\n"); @@ -194,15 +202,15 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, for(int i=0; i<3; i++) { srslte_dft_run_c(&q->conv_fft.filter_plan, q->pss_signal_time[i], q->pss_signal_freq_full[i]); } - + #endif - + srslte_pss_synch_reset(q); - + ret = SRSLTE_SUCCESS; } -clean_and_exit: +clean_and_exit: if (ret == SRSLTE_ERROR) { srslte_pss_synch_free(q); } @@ -248,6 +256,13 @@ int srslte_pss_synch_resize(srslte_pss_synch_t *q, uint32_t frame_size, uint32_t return SRSLTE_ERROR; } + if (srslte_dft_replan(&q->idftp_input, fft_size)) { + fprintf(stderr, "Error creating DFT plan \n"); + return SRSLTE_ERROR; + } + + bzero(q->tmp_fft2, sizeof(cf_t)*SRSLTE_SYMBOL_SZ_MAX); + bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); bzero(q->conv_output, sizeof(cf_t) * buffer_size); bzero(q->conv_output_avg, sizeof(float) * buffer_size); @@ -298,7 +313,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } #ifdef CONVOLUTION_FFT srslte_conv_fft_cc_free(&q->conv_fft); - + #endif if (q->tmp_input) { free(q->tmp_input); @@ -312,9 +327,10 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { if (q->conv_output_avg) { free(q->conv_output_avg); } - + srslte_dft_plan_free(&q->dftp_input); - + srslte_dft_plan_free(&q->idftp_input); + if(q->decimate > 1) { srslte_filt_decim_cc_free(&q->filter); @@ -323,7 +339,7 @@ void srslte_pss_synch_free(srslte_pss_synch_t *q) { } - bzero(q, sizeof(srslte_pss_synch_t)); + bzero(q, sizeof(srslte_pss_synch_t)); } } @@ -379,7 +395,7 @@ void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, srslte_ void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp) { int k; k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; - memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); + memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); } @@ -398,34 +414,34 @@ int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2) { /* Sets the weight factor alpha for the exponential moving average of the PSS correlation output */ void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { - q->ema_alpha = alpha; + q->ema_alpha = alpha; } -/** Performs time-domain PSS correlation. +/** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. * The value of the correlation is stored in corr_peak_value. * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) +int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && + + if (q != NULL && input != NULL) { uint32_t corr_peak_pos; uint32_t conv_output_len; - + if (!srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } /* Correlate input with PSS sequence - * + * * We do not reverse time-domain PSS signal because it's conjugate is symmetric. * The conjugate operation on pss_signal_time has been done in srslte_pss_synch_init_N_id_2 * This is why we can use FFT-based convolution @@ -442,7 +458,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe { conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); } - + #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif @@ -450,19 +466,19 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe for (int i=0;iframe_size;i++) { q->conv_output[i] = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], &input[i], q->fft_size); } - conv_output_len = q->frame_size; + conv_output_len = q->frame_size; } - + #ifdef SRSLTE_PSS_ABS_SQUARE srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #else srslte_vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); #endif - + if (q->ema_alpha < 1.0 && q->ema_alpha > 0.0) { - srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); - srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); + srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); srslte_vec_sum_fff(q->conv_output_abs, q->conv_output_avg, q->conv_output_avg, conv_output_len-1); } else { @@ -470,43 +486,43 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe } /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); - - // save absolute value + + // save absolute value q->peak_value = q->conv_output_avg[corr_peak_pos]; - -#ifdef SRSLTE_PSS_RETURN_PSR + +#ifdef SRSLTE_PSS_RETURN_PSR // Find second side lobe - + // Find end of peak lobe to the right int pl_ub = corr_peak_pos+1; while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { - pl_ub ++; + pl_ub ++; } // Find end of peak lobe to the left - int pl_lb; + int pl_lb; if (corr_peak_pos > 2) { pl_lb = corr_peak_pos-1; while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { - pl_lb --; - } + pl_lb --; + } } else { - pl_lb = 0; + pl_lb = 0; } - int sl_distance_right = conv_output_len-1-pl_ub; + int sl_distance_right = conv_output_len-1-pl_ub; if (sl_distance_right < 0) { - sl_distance_right = 0; + sl_distance_right = 0; } - int sl_distance_left = pl_lb; - + int sl_distance_left = pl_lb; + int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); - int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); - float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); + int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); + float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); if (corr_peak_value) { *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; - + if (*corr_peak_value < 10) - DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, + DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); } #else @@ -514,7 +530,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe *corr_peak_value = q->conv_output_avg[corr_peak_pos]; } #endif - + if(q->decimate >1) { int decimation_correction = (q->filter.num_taps - 2); @@ -524,23 +540,23 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe if (q->frame_size >= q->fft_size) { - ret = (int) corr_peak_pos; + ret = (int) corr_peak_pos; } else { ret = (int) corr_peak_pos + q->fft_size; } - } + } return ret; } -/* Computes frequency-domain channel estimation of the PSS symbol - * input signal is in the time-domain. - * ce is the returned frequency-domain channel estimates. +/* Computes frequency-domain channel estimation of the PSS symbol + * input signal is in the time-domain. + * ce is the returned frequency-domain channel estimates. */ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; - if (q != NULL && + if (q != NULL && input != NULL) { @@ -548,16 +564,28 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return SRSLTE_ERROR; } - + /* Transform to frequency-domain */ srslte_dft_run_c(&q->dftp_input, input, input_fft); - + /* Compute channel estimate taking the PSS sequence as reference */ srslte_vec_prod_conj_ccc(&input_fft[(q->fft_size-SRSLTE_PSS_LEN)/2], q->pss_signal_freq[q->N_id_2], ce, SRSLTE_PSS_LEN); - + ret = SRSLTE_SUCCESS; } - return ret; + return ret; +} + +// Frequency-domain filtering of the central 64 sub-carriers +void srslte_pss_synch_filter(srslte_pss_synch_t *q, cf_t *input, cf_t *output) +{ + srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); + + memcpy(&q->tmp_fft2[q->fft_size/2-SRSLTE_PSS_LEN/2], + &q->tmp_fft[q->fft_size/2-SRSLTE_PSS_LEN/2], + sizeof(cf_t)*SRSLTE_PSS_LEN); + + srslte_dft_run_c(&q->idftp_input, q->tmp_fft2, output); } /* Returns the CFO estimation given a PSS received sequence @@ -566,13 +594,17 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS * Feng Wang and Yu Zhu */ float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, cf_t *pss_recv) { - cf_t y0, y1, yr; + cf_t y0, y1; - y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_recv, q->fft_size/2); - y1 = srslte_vec_dot_prod_ccc(&q->pss_signal_time[q->N_id_2][q->fft_size/2], &pss_recv[q->fft_size/2], q->fft_size/2); - - yr = conjf(y0) * y1; + cf_t *pss_ptr = pss_recv; + + if (q->filter_pss_enable) { + srslte_pss_synch_filter(q, pss_recv, q->tmp_fft); + pss_ptr = q->tmp_fft; + } - return atan2f(__imag__ yr, __real__ yr) / M_PI; + y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_ptr, q->fft_size/2); + y1 = srslte_vec_dot_prod_ccc(&q->pss_signal_time[q->N_id_2][q->fft_size/2], &pss_ptr[q->fft_size/2], q->fft_size/2); + return carg(conjf(y0) * y1)/M_PI; } From 5292137b3a5d863dc0e33edc49a213558bdac517 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Wed, 29 Nov 2017 11:51:12 +0000 Subject: [PATCH 16/22] Adding APN info to log output --- srsue/src/upper/nas.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 9c24cbf2e..62e23d852 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -360,13 +360,14 @@ void nas::parse_attach_accept(uint32_t lcid, byte_buffer_t *pdu) { ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[2] << 8; ip_addr |= act_def_eps_bearer_context_req.pdn_addr.addr[3]; - nas_log->info("IP allocated by network %u.%u.%u.%u\n", + nas_log->info("Network attach successful. APN: %s, IP: %u.%u.%u.%u\n", + act_def_eps_bearer_context_req.apn.apn.c_str(), act_def_eps_bearer_context_req.pdn_addr.addr[0], act_def_eps_bearer_context_req.pdn_addr.addr[1], act_def_eps_bearer_context_req.pdn_addr.addr[2], act_def_eps_bearer_context_req.pdn_addr.addr[3]); - nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n", + nas_log->console("Network attach successful. IP: %u.%u.%u.%u\n", act_def_eps_bearer_context_req.pdn_addr.addr[0], act_def_eps_bearer_context_req.pdn_addr.addr[1], act_def_eps_bearer_context_req.pdn_addr.addr[2], From a3a1d268b7ac81446c364a5466a5220b41881fec Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 29 Nov 2017 18:30:21 +0100 Subject: [PATCH 17/22] Improved CFO estimation/correction by filtering central 6 PRB. Cleaned ue_sync/sync/pss objects. Used const attr in vector and other objects --- lib/examples/cell_measurement.c | 3 - lib/examples/pdsch_ue.c | 9 +- lib/include/srslte/phy/dft/dft.h | 14 +- lib/include/srslte/phy/sync/cfo.h | 2 +- lib/include/srslte/phy/sync/cp.h | 2 +- lib/include/srslte/phy/sync/pss.h | 12 +- lib/include/srslte/phy/sync/sss.h | 10 +- lib/include/srslte/phy/sync/sync.h | 84 ++-- lib/include/srslte/phy/ue/ue_sync.h | 37 +- lib/include/srslte/phy/utils/convolution.h | 16 +- lib/include/srslte/phy/utils/simd.h | 22 +- lib/include/srslte/phy/utils/vector.h | 98 ++-- lib/include/srslte/phy/utils/vector_simd.h | 65 +-- lib/src/phy/dft/dft_fftw.c | 10 +- lib/src/phy/modem/demod_soft.c | 4 +- .../phy/resampling/test/resample_arb_bench.c | 2 +- lib/src/phy/rf/rf_blade_imp.c | 4 +- lib/src/phy/rf/rf_utils.c | 7 +- lib/src/phy/sync/cfo.c | 2 +- lib/src/phy/sync/cp.c | 4 +- lib/src/phy/sync/find_sss.c | 8 +- lib/src/phy/sync/pss.c | 115 +++-- lib/src/phy/sync/sync.c | 431 ++++++++++-------- lib/src/phy/sync/test/pss_usrp.c | 18 +- lib/src/phy/sync/test/sync_test.c | 3 +- lib/src/phy/ue/ue_cell_search.c | 4 +- lib/src/phy/ue/ue_sync.c | 242 +++++----- lib/src/phy/utils/convolution.c | 6 +- lib/src/phy/utils/test/vector_test.c | 2 +- lib/src/phy/utils/vector.c | 107 +++-- lib/src/phy/utils/vector_simd.c | 67 +-- srsue/src/phy/phch_recv.cc | 6 +- 32 files changed, 749 insertions(+), 667 deletions(-) diff --git a/lib/examples/cell_measurement.c b/lib/examples/cell_measurement.c index 6415257f0..573cab255 100644 --- a/lib/examples/cell_measurement.c +++ b/lib/examples/cell_measurement.c @@ -299,9 +299,6 @@ int main(int argc, char **argv) { float rx_gain_offset = 0; - // Set initial CFO for ue_sync - srslte_ue_sync_set_cfo(&ue_sync, cfo); - /* Main loop */ while ((sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) && !go_exit) { diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index e8d4b1d00..e15aa473f 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -579,11 +579,8 @@ int main(int argc, char **argv) { srslte_ra_dl_dci_t old_dl_dci; bzero(&old_dl_dci, sizeof(srslte_ra_dl_dci_t)); #endif - - ue_sync.correct_cfo = !prog_args.disable_cfo; - - // Set initial CFO for ue_sync - srslte_ue_sync_set_cfo(&ue_sync, cfo); + + ue_sync.cfo_correct_enable = !prog_args.disable_cfo; srslte_pbch_decode_reset(&ue_mib.pbch); @@ -776,7 +773,7 @@ int main(int argc, char **argv) { /* Print basic Parameters */ PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); - PRINT_LINE(" CFO: %+5.2f kHz", srslte_ue_sync_get_cfo(&ue_sync) / 1000); + PRINT_LINE(" CFO: %+7.2f kHz", srslte_ue_sync_get_cfo(&ue_sync)); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); diff --git a/lib/include/srslte/phy/dft/dft.h b/lib/include/srslte/phy/dft/dft.h index b3dd4378b..afe8024d2 100644 --- a/lib/include/srslte/phy/dft/dft.h +++ b/lib/include/srslte/phy/dft/dft.h @@ -139,22 +139,22 @@ SRSLTE_API void srslte_dft_plan_set_dc(srslte_dft_plan_t *plan, /* Compute DFT */ -SRSLTE_API void srslte_dft_run(srslte_dft_plan_t *plan, - void *in, +SRSLTE_API void srslte_dft_run(srslte_dft_plan_t *plan, + const void *in, void *out); -SRSLTE_API void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, - cf_t *in, +SRSLTE_API void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, + const cf_t *in, cf_t *out); -SRSLTE_API void srslte_dft_run_c(srslte_dft_plan_t *plan, - cf_t *in, +SRSLTE_API void srslte_dft_run_c(srslte_dft_plan_t *plan, + const cf_t *in, cf_t *out); SRSLTE_API void srslte_dft_run_guru_c(srslte_dft_plan_t *plan); SRSLTE_API void srslte_dft_run_r(srslte_dft_plan_t *plan, - float *in, + const float *in, float *out); #endif // DFT_H_ diff --git a/lib/include/srslte/phy/sync/cfo.h b/lib/include/srslte/phy/sync/cfo.h index fd2ab4d83..5b9b3c0dd 100644 --- a/lib/include/srslte/phy/sync/cfo.h +++ b/lib/include/srslte/phy/sync/cfo.h @@ -66,7 +66,7 @@ SRSLTE_API void srslte_cfo_set_tol(srslte_cfo_t *h, float tol); SRSLTE_API void srslte_cfo_correct(srslte_cfo_t *h, - cf_t *input, + const cf_t *input, cf_t *output, float freq); diff --git a/lib/include/srslte/phy/sync/cp.h b/lib/include/srslte/phy/sync/cp.h index 9daf7d4f6..d9da03722 100644 --- a/lib/include/srslte/phy/sync/cp.h +++ b/lib/include/srslte/phy/sync/cp.h @@ -47,7 +47,7 @@ SRSLTE_API int srslte_cp_synch_resize(srslte_cp_synch_t *q, uint32_t symbol_sz); SRSLTE_API uint32_t srslte_cp_synch(srslte_cp_synch_t *q, - cf_t *input, + const cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len); diff --git a/lib/include/srslte/phy/sync/pss.h b/lib/include/srslte/phy/sync/pss.h index f94b2deba..aba84f5cd 100644 --- a/lib/include/srslte/phy/sync/pss.h +++ b/lib/include/srslte/phy/sync/pss.h @@ -63,8 +63,6 @@ #define SRSLTE_PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to srslte_pss_synch_find_pss -#define SRSLTE_PSS_ABS_SQUARE // If enabled, compute abs square, otherwise computes absolute value only - #define SRSLTE_PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value @@ -137,7 +135,7 @@ SRSLTE_API void srslte_pss_synch_filter_enable(srslte_pss_synch_t *q, bool enable); SRSLTE_API void srslte_pss_synch_filter(srslte_pss_synch_t *q, - cf_t *input, + const cf_t *input, cf_t *output); SRSLTE_API int srslte_pss_generate(cf_t *signal, @@ -160,14 +158,14 @@ SRSLTE_API int srslte_pss_synch_set_N_id_2(srslte_pss_synch_t *q, uint32_t N_id_2); SRSLTE_API int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, - cf_t *input, + const cf_t *input, float *corr_peak_value); SRSLTE_API int srslte_pss_synch_chest(srslte_pss_synch_t *q, - cf_t *input, + const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]); -SRSLTE_API float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, - cf_t *pss_recv); +SRSLTE_API float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, + const cf_t *pss_recv); #endif // PSS_ diff --git a/lib/include/srslte/phy/sync/sss.h b/lib/include/srslte/phy/sync/sss.h index 35eedac8f..4a0942d61 100644 --- a/lib/include/srslte/phy/sync/sss.h +++ b/lib/include/srslte/phy/sync/sss.h @@ -107,8 +107,8 @@ SRSLTE_API void srslte_sss_put_slot(float *sss, SRSLTE_API int srslte_sss_synch_set_N_id_2(srslte_sss_synch_t *q, uint32_t N_id_2); -SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, + const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, @@ -117,15 +117,15 @@ SRSLTE_API int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, float *m1_value); SRSLTE_API int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, - cf_t *input, + const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value); -SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, - cf_t *input, +SRSLTE_API int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, + const cf_t *input, uint32_t *m0, float *m0_value, uint32_t *m1, diff --git a/lib/include/srslte/phy/sync/sync.h b/lib/include/srslte/phy/sync/sync.h index 1c70b2449..151c530b1 100644 --- a/lib/include/srslte/phy/sync/sync.h +++ b/lib/include/srslte/phy/sync/sync.h @@ -74,19 +74,8 @@ typedef struct SRSLTE_API { uint32_t fft_size; uint32_t frame_size; uint32_t max_offset; - bool enable_cfo_corr; - bool mean_cfo2_isunset; - bool mean_cfo_isunset; - float mean_cfo; - float mean_cfo2; - int cfo_i; - bool find_cfo_i; - bool find_cfo_i_initiated; - float cfo_ema_alpha; uint32_t nof_symbols; uint32_t cp_len; - srslte_cfo_t cfocorr; - srslte_cfo_t cfocorr2; float current_cfo_tol; sss_alg_t sss_alg; bool detect_cp; @@ -102,6 +91,30 @@ typedef struct SRSLTE_API { uint32_t max_frame_size; + + // variables for various CFO estimation methods + bool cfo_cp_enable; + bool cfo_pss_enable; + bool cfo_i_enable; + + bool cfo_cp_is_set; + bool cfo_pss_is_set; + bool cfo_i_initiated; + + float cfo_cp_mean; + float cfo_pss_mean; + int cfo_i_value; + + float cfo_ema_alpha; + + srslte_cfo_t cfo_corr_frame; + srslte_cfo_t cfo_corr_symbol; + + bool sss_filtering_enabled; + bool pss_filtering_enabled; + cf_t sss_filt[SRSLTE_SYMBOL_SZ_MAX]; + cf_t pss_filt[SRSLTE_SYMBOL_SZ_MAX]; + }srslte_sync_t; typedef enum { @@ -135,29 +148,23 @@ SRSLTE_API void srslte_sync_reset(srslte_sync_t *q); /* Finds a correlation peak in the input signal around position find_offset */ SRSLTE_API srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, - cf_t *input, + const cf_t *input, uint32_t find_offset, uint32_t *peak_position); /* Estimates the CP length */ SRSLTE_API srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, - cf_t *input, + const cf_t *input, uint32_t peak_pos); /* Sets the threshold for peak comparison */ SRSLTE_API void srslte_sync_set_threshold(srslte_sync_t *q, float threshold); -SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q, - float tol); - /* Gets the subframe idx (0 or 5) */ SRSLTE_API uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q); -/* Gets the last peak value */ -SRSLTE_API float srslte_sync_get_last_peak_value(srslte_sync_t *q); - -/* Gets the mean peak value */ +/* Gets the peak value */ SRSLTE_API float srslte_sync_get_peak_value(srslte_sync_t *q); /* Choose SSS detection algorithm */ @@ -175,23 +182,40 @@ SRSLTE_API int srslte_sync_set_N_id_2(srslte_sync_t *q, /* Gets the Physical CellId from the last call to synch_run() */ SRSLTE_API int srslte_sync_get_cell_id(srslte_sync_t *q); +/* Enables/disables filtering of the central PRBs before PSS CFO estimation or SSS correlation*/ +SRSLTE_API void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, + bool enable); + +SRSLTE_API void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, + bool enable); + /* Gets the CFO estimation from the last call to synch_run() */ SRSLTE_API float srslte_sync_get_cfo(srslte_sync_t *q); -/* Sets known CFO to avoid long transients due to average */ -SRSLTE_API void srslte_sync_set_cfo(srslte_sync_t *q, float cfo); +/* Resets internal CFO state */ +SRSLTE_API void srslte_sync_cfo_reset(srslte_sync_t *q); + +/* Copies CFO internal state from another object to avoid long transients */ +SRSLTE_API void srslte_sync_copy_cfo(srslte_sync_t *q, + srslte_sync_t *src_obj); -/* Set integer CFO */ -SRSLTE_API void srslte_sync_set_cfo_i(srslte_sync_t *q, - int cfo_i); +/* Enable different CFO estimation stages */ +SRSLTE_API void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, + bool enable); +SRSLTE_API void srslte_sync_set_cfo_cp_enable(srslte_sync_t *q, + bool enable); +SRSLTE_API void srslte_sync_set_cfo_pss_enable(srslte_sync_t *q, + bool enable); -SRSLTE_API void srslte_sync_set_cfo_enable(srslte_sync_t *q, - bool enable); +/* Sets CFO correctors tolerance (in Hz) */ +SRSLTE_API void srslte_sync_set_cfo_tol(srslte_sync_t *q, + float tol); /* Sets the exponential moving average coefficient for CFO averaging */ SRSLTE_API void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, float alpha); + /* Gets the CP length estimation from the last call to synch_run() */ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); @@ -199,10 +223,6 @@ SRSLTE_API srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q); SRSLTE_API void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp); -/* Enable integer CFO detection */ -SRSLTE_API void srslte_sync_cfo_i_detec_en(srslte_sync_t *q, - bool enabled); - /* Enables/Disables SSS detection */ SRSLTE_API void srslte_sync_sss_en(srslte_sync_t *q, bool enabled); @@ -211,8 +231,6 @@ SRSLTE_API srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q); SRSLTE_API bool srslte_sync_sss_detected(srslte_sync_t *q); -SRSLTE_API bool srslte_sync_sss_is_en(srslte_sync_t *q); - /* Enables/Disables CP detection */ SRSLTE_API void srslte_sync_cp_en(srslte_sync_t *q, bool enabled); diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index e5877dd23..11d7893c8 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -110,8 +110,12 @@ typedef struct SRSLTE_API { uint32_t sf_idx; bool decode_sss_on_track; - bool correct_cfo; - + + bool cfo_correct_enable; + float cfo_current_value; + float cfo_loop_bw; + float cfo_pss_tol; + uint32_t peak_idx; int next_rf_sample_offset; int last_sample_offset; @@ -165,6 +169,10 @@ SRSLTE_API void srslte_ue_sync_free(srslte_ue_sync_t *q); SRSLTE_API int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell); +SRSLTE_API void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q); + +SRSLTE_API void srslte_ue_sync_reset(srslte_ue_sync_t *q); + SRSLTE_API int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value); @@ -175,34 +183,34 @@ SRSLTE_API void srslte_ue_sync_set_agc_period(srslte_ue_sync_t *q, uint32_t period); /* CAUTION: input_buffer MUST have space for 2 subframes */ -SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, +SRSLTE_API int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer); -SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, +SRSLTE_API int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS]); SRSLTE_API void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float tol); -SRSLTE_API void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, - float cfo); +SRSLTE_API void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, + srslte_ue_sync_t *src_obj); + +SRSLTE_API void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, + float bw, + float pss_tol); SRSLTE_API void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema); -SRSLTE_API void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, - bool enable); +SRSLTE_API void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q, + bool enable); -SRSLTE_API void srslte_ue_sync_reset(srslte_ue_sync_t *q); - -SRSLTE_API void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, +SRSLTE_API void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2); SRSLTE_API void srslte_ue_sync_decode_sss_on_track(srslte_ue_sync_t *q, bool enabled); -SRSLTE_API srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q); - SRSLTE_API uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q); SRSLTE_API float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q); @@ -218,8 +226,5 @@ SRSLTE_API void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t *timestamp); - - - #endif // SYNC_FRAME_ diff --git a/lib/include/srslte/phy/utils/convolution.h b/lib/include/srslte/phy/utils/convolution.h index fcb321ce5..a93dfb955 100644 --- a/lib/include/srslte/phy/utils/convolution.h +++ b/lib/include/srslte/phy/utils/convolution.h @@ -66,18 +66,18 @@ SRSLTE_API int srslte_conv_fft_cc_replan(srslte_conv_fft_cc_t *q, SRSLTE_API void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q); -SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, - cf_t *input, - cf_t *filter, +SRSLTE_API uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, + const cf_t *input, + const cf_t *filter, cf_t *output); -SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, - cf_t *input, - cf_t *filter_freq, +SRSLTE_API uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, + const cf_t *input, + const cf_t *filter_freq, cf_t *output); -SRSLTE_API uint32_t srslte_conv_cc(cf_t *input, - cf_t *filter, +SRSLTE_API uint32_t srslte_conv_cc(const cf_t *input, + const cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len); diff --git a/lib/include/srslte/phy/utils/simd.h b/lib/include/srslte/phy/utils/simd.h index cec003886..226e2ecae 100644 --- a/lib/include/srslte/phy/utils/simd.h +++ b/lib/include/srslte/phy/utils/simd.h @@ -172,7 +172,7 @@ typedef float32x4_t simd_f_t; #endif /* LV_HAVE_AVX512 */ /* Single precision Floating point functions */ -static inline simd_f_t srslte_simd_f_load(float *ptr) { +static inline simd_f_t srslte_simd_f_load(const float *ptr) { #ifdef LV_HAVE_AVX512 return _mm512_load_ps(ptr); #else /* LV_HAVE_AVX512 */ @@ -190,7 +190,7 @@ static inline simd_f_t srslte_simd_f_load(float *ptr) { #endif /* LV_HAVE_AVX512 */ } -static inline simd_f_t srslte_simd_f_loadu(float *ptr) { +static inline simd_f_t srslte_simd_f_loadu(const float *ptr) { #ifdef LV_HAVE_AVX512 return _mm512_loadu_ps(ptr); #else /* LV_HAVE_AVX512 */ @@ -477,7 +477,7 @@ typedef struct { #endif /* Complex Single precission Floating point functions */ -static inline simd_cf_t srslte_simd_cfi_load(cf_t *ptr) { +static inline simd_cf_t srslte_simd_cfi_load(const cf_t *ptr) { simd_cf_t ret; #ifdef LV_HAVE_AVX512 __m512 in1 = _mm512_load_ps((float*)(ptr)); @@ -513,7 +513,7 @@ static inline simd_cf_t srslte_simd_cfi_load(cf_t *ptr) { } /* Complex Single precission Floating point functions */ -static inline simd_cf_t srslte_simd_cfi_loadu(cf_t *ptr) { +static inline simd_cf_t srslte_simd_cfi_loadu(const cf_t *ptr) { simd_cf_t ret; #ifdef LV_HAVE_AVX512 __m512 in1 = _mm512_loadu_ps((float*)(ptr)); @@ -548,7 +548,7 @@ static inline simd_cf_t srslte_simd_cfi_loadu(cf_t *ptr) { return ret; } -static inline simd_cf_t srslte_simd_cf_load(float *re, float *im) { +static inline simd_cf_t srslte_simd_cf_load(const float *re, const float *im) { simd_cf_t ret; #ifdef LV_HAVE_AVX512 ret.re = _mm512_load_ps(re); @@ -572,7 +572,7 @@ static inline simd_cf_t srslte_simd_cf_load(float *re, float *im) { return ret; } -static inline simd_cf_t srslte_simd_cf_loadu(float *re, float *im) { +static inline simd_cf_t srslte_simd_cf_loadu(const float *re, const float *im) { simd_cf_t ret; #ifdef LV_HAVE_AVX512 ret.re = _mm512_loadu_ps(re); @@ -1074,7 +1074,7 @@ typedef int16x8_t simd_s_t; #endif /* LV_HAVE_AVX2 */ #endif /* LV_HAVE_AVX512 */ -static inline simd_s_t srslte_simd_s_load(int16_t *ptr) { +static inline simd_s_t srslte_simd_s_load(const int16_t *ptr) { #ifdef LV_HAVE_AVX512 return _mm512_load_si512(ptr); #else /* LV_HAVE_AVX512 */ @@ -1092,7 +1092,7 @@ static inline simd_s_t srslte_simd_s_load(int16_t *ptr) { #endif /* LV_HAVE_AVX512 */ } -static inline simd_s_t srslte_simd_s_loadu(int16_t *ptr) { +static inline simd_s_t srslte_simd_s_loadu(const int16_t *ptr) { #ifdef LV_HAVE_AVX512 return _mm512_loadu_si512(ptr); #else /* LV_HAVE_AVX512 */ @@ -1267,7 +1267,7 @@ typedef } simd_c16_t; /* Fixed point precision (16-bit) functions */ -static inline simd_c16_t srslte_simd_c16i_load(c16_t *ptr) { +static inline simd_c16_t srslte_simd_c16i_load(const c16_t *ptr) { simd_c16_t ret; #ifdef LV_HAVE_AVX512 __m512i in1 = _mm512_load_si512((__m512i*)(ptr)); @@ -1296,7 +1296,7 @@ static inline simd_c16_t srslte_simd_c16i_load(c16_t *ptr) { return ret; } -static inline simd_c16_t srslte_simd_c16_load(int16_t *re, int16_t *im) { +static inline simd_c16_t srslte_simd_c16_load(const int16_t *re, const int16_t *im) { simd_c16_t ret; #ifdef LV_HAVE_AVX2 ret.re.m256 = _mm256_load_si256((__m256i*)(re)); @@ -1315,7 +1315,7 @@ static inline simd_c16_t srslte_simd_c16_load(int16_t *re, int16_t *im) { return ret; } -static inline simd_c16_t srslte_simd_c16_loadu(int16_t *re, int16_t *im) { +static inline simd_c16_t srslte_simd_c16_loadu(const int16_t *re, const int16_t *im) { simd_c16_t ret; #ifdef LV_HAVE_AVX2 ret.re.m256 = _mm256_loadu_si256((__m256i*)(re)); diff --git a/lib/include/srslte/phy/utils/vector.h b/lib/include/srslte/phy/utils/vector.h index 7dad585a0..a4028e495 100644 --- a/lib/include/srslte/phy/utils/vector.h +++ b/lib/include/srslte/phy/utils/vector.h @@ -55,100 +55,100 @@ extern "C" { /*logical operations */ -SRSLTE_API void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, uint32_t len); +SRSLTE_API void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, const uint32_t len); /** Return the sum of all the elements */ -SRSLTE_API float srslte_vec_acc_ff(float *x, uint32_t len); -SRSLTE_API cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len); +SRSLTE_API float srslte_vec_acc_ff(const float *x, const uint32_t len); +SRSLTE_API cf_t srslte_vec_acc_cc(const cf_t *x, const uint32_t len); SRSLTE_API void *srslte_vec_malloc(uint32_t size); SRSLTE_API void *srslte_vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size); /* print vectors */ -SRSLTE_API void srslte_vec_fprint_c(FILE *stream, cf_t *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_f(FILE *stream, float *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_b(FILE *stream, uint8_t *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, uint32_t len); -SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, uint32_t len); -SRSLTE_API void srslte_vec_sprint_hex(char *str, uint8_t *x, uint32_t len); +SRSLTE_API void srslte_vec_fprint_c(FILE *stream, cf_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_f(FILE *stream, float *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_b(FILE *stream, uint8_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_byte(FILE *stream, uint8_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_i(FILE *stream, int *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_s(FILE *stream, short *x, const uint32_t len); +SRSLTE_API void srslte_vec_fprint_hex(FILE *stream, uint8_t *x, const uint32_t len); +SRSLTE_API void srslte_vec_sprint_hex(char *str, uint8_t *x, const uint32_t len); /* Saves/loads a vector to a file */ -SRSLTE_API void srslte_vec_save_file(char *filename, void *buffer, uint32_t len); -SRSLTE_API void srslte_vec_load_file(char *filename, void *buffer, uint32_t len); +SRSLTE_API void srslte_vec_save_file(char *filename, const void *buffer, const uint32_t len); +SRSLTE_API void srslte_vec_load_file(char *filename, void *buffer, const uint32_t len); /* sum two vectors */ -SRSLTE_API void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len); -SRSLTE_API void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sub_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sum_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len); +SRSLTE_API void srslte_vec_sum_fff(const float *x, const float *y, float *z, const uint32_t len); +SRSLTE_API void srslte_vec_sum_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sub_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sum_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len); /* substract two vectors z=x-y */ -SRSLTE_API void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len); -SRSLTE_API void srslte_vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_sub_fff(const float *x, const float *y, float *z, const uint32_t len); +SRSLTE_API void srslte_vec_sub_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); /* scalar product */ -SRSLTE_API void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); +SRSLTE_API void srslte_vec_sc_prod_cfc(const cf_t *x, const float h, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sc_prod_ccc(const cf_t *x, const cf_t h, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_sc_prod_fff(const float *x, const float h, float *z, const uint32_t len); -SRSLTE_API void srslte_vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); -SRSLTE_API void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len); +SRSLTE_API void srslte_vec_convert_fi(const float *x, const float scale, int16_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len); -SRSLTE_API void srslte_vec_lut_sss(short *x, unsigned short *lut, short *y, uint32_t len); +SRSLTE_API void srslte_vec_lut_sss(const short *x, const unsigned short *lut, short *y, const uint32_t len); /* vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_prod_ccc_split(float *x_re, float *x_im, float *y_re, float *y_im, float *z_re, float *z_im, uint32_t len); +SRSLTE_API void srslte_vec_prod_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_prod_ccc_split(const float *x_re, const float *x_im, const float *y_re, const float *y_im, float *z_re, float *z_im, const uint32_t len); /* vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_cfc(const cf_t *x, const float *y, cf_t *z, const uint32_t len); /* conjugate vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_conj_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); /* real vector product (element-wise) */ -SRSLTE_API void srslte_vec_prod_fff(float *x, float *y, float *z, uint32_t len); -SRSLTE_API void srslte_vec_prod_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len); +SRSLTE_API void srslte_vec_prod_fff(const float *x, const float *y, float *z, const uint32_t len); +SRSLTE_API void srslte_vec_prod_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len); /* Dot-product */ -SRSLTE_API cf_t srslte_vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len); -SRSLTE_API cf_t srslte_vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); -SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len); -SRSLTE_API float srslte_vec_dot_prod_fff(float *x, float *y, uint32_t len); -SRSLTE_API int32_t srslte_vec_dot_prod_sss(int16_t *x, int16_t *y, uint32_t len); +SRSLTE_API cf_t srslte_vec_dot_prod_cfc(const cf_t *x, const float *y, const uint32_t len); +SRSLTE_API cf_t srslte_vec_dot_prod_ccc(const cf_t *x, const cf_t *y, const uint32_t len); +SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc(const cf_t *x, const cf_t *y, const uint32_t len); +SRSLTE_API float srslte_vec_dot_prod_fff(const float *x, const float *y, const uint32_t len); +SRSLTE_API int32_t srslte_vec_dot_prod_sss(const int16_t *x, const int16_t *y, const uint32_t len); /* z=x/y vector division (element-wise) */ -SRSLTE_API void srslte_vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_div_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); -SRSLTE_API void srslte_vec_div_fff(float *x, float *y, float *z, uint32_t len); +SRSLTE_API void srslte_vec_div_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_div_cfc(const cf_t *x, const float *y, cf_t *z, const uint32_t len); +SRSLTE_API void srslte_vec_div_fff(const float *x, const float *y, float *z, const uint32_t len); /* conjugate */ -SRSLTE_API void srslte_vec_conj_cc(cf_t *x, cf_t *y, uint32_t len); +SRSLTE_API void srslte_vec_conj_cc(const cf_t *x, cf_t *y, const uint32_t len); /* average vector power */ -SRSLTE_API float srslte_vec_avg_power_cf(cf_t *x, uint32_t len); +SRSLTE_API float srslte_vec_avg_power_cf(const cf_t *x, const uint32_t len); /* Correlation between complex vectors x and y */ -SRSLTE_API float srslte_vec_corr_ccc(cf_t *x, cf_t *y, uint32_t len); +SRSLTE_API float srslte_vec_corr_ccc(const cf_t *x, cf_t *y, const uint32_t len); /* return the index of the maximum value in the vector */ -SRSLTE_API uint32_t srslte_vec_max_fi(float *x, uint32_t len); -SRSLTE_API uint32_t srslte_vec_max_abs_ci(cf_t *x, uint32_t len); +SRSLTE_API uint32_t srslte_vec_max_fi(const float *x, const uint32_t len); +SRSLTE_API uint32_t srslte_vec_max_abs_ci(const cf_t *x, const uint32_t len); /* quantify vector of floats or int16 and convert to uint8_t */ -SRSLTE_API void srslte_vec_quant_fuc(float *in, uint8_t *out, float gain, float offset, float clip, uint32_t len); -SRSLTE_API void srslte_vec_quant_suc(int16_t *in, uint8_t *out, float gain, int16_t offset, int16_t clip, uint32_t len); +SRSLTE_API void srslte_vec_quant_fuc(const float *in, uint8_t *out, const float gain, const float offset, const float clip, const uint32_t len); +SRSLTE_API void srslte_vec_quant_suc(const int16_t *in, uint8_t *out, const float gain, const int16_t offset, const int16_t clip, const uint32_t len); /* magnitude of each vector element */ -SRSLTE_API void srslte_vec_abs_cf(cf_t *x, float *abs, uint32_t len); -SRSLTE_API void srslte_vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len); +SRSLTE_API void srslte_vec_abs_cf(const cf_t *x, float *abs, const uint32_t len); +SRSLTE_API void srslte_vec_abs_square_cf(const cf_t *x, float *abs_square, const uint32_t len); /* Copy 256 bit aligned vector */ -SRSLTE_API void srs_vec_cf_cpy(cf_t *src, cf_t *dst, int len); +SRSLTE_API void srs_vec_cf_cpy(const cf_t *src, cf_t *dst, const int len); #ifdef __cplusplus } diff --git a/lib/include/srslte/phy/utils/vector_simd.h b/lib/include/srslte/phy/utils/vector_simd.h index 468c5e11a..54ac55f98 100644 --- a/lib/include/srslte/phy/utils/vector_simd.h +++ b/lib/include/srslte/phy/utils/vector_simd.h @@ -55,77 +55,78 @@ extern "C" { /*SIMD Logical operations*/ -SRSLTE_API void srslte_vec_xor_bbb_simd(int8_t *x, int8_t *y, int8_t *z, int len); +SRSLTE_API void srslte_vec_xor_bbb_simd(const int8_t *x, const int8_t *y, int8_t *z, int len); /* SIMD Basic vector math */ -SRSLTE_API void srslte_vec_sum_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len); +SRSLTE_API void srslte_vec_sum_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, int len); -SRSLTE_API void srslte_vec_sub_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len); +SRSLTE_API void srslte_vec_sub_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, int len); -SRSLTE_API float srslte_vec_acc_ff_simd(float *x, int len); +SRSLTE_API float srslte_vec_acc_ff_simd(const float *x, int len); -SRSLTE_API cf_t srslte_vec_acc_cc_simd(cf_t *x, int len); +SRSLTE_API cf_t srslte_vec_acc_cc_simd(const cf_t *x, int len); -SRSLTE_API void srslte_vec_add_fff_simd(float *x, float *y, float *z, int len); +SRSLTE_API void srslte_vec_add_fff_simd(const float *x, const float *y, float *z, int len); -SRSLTE_API void srslte_vec_sub_fff_simd(float *x, float *y, float *z, int len); +SRSLTE_API void srslte_vec_sub_fff_simd(const float *x, const float *y, float *z, int len); /* SIMD Vector Scalar Product */ -SRSLTE_API void srslte_vec_sc_prod_cfc_simd(const cf_t *x,const float h,cf_t *y,const int len); +SRSLTE_API void srslte_vec_sc_prod_cfc_simd(const cf_t *x, const float h,cf_t *y, const int len); -SRSLTE_API void srslte_vec_sc_prod_fff_simd(float *x, float h, float *z, int len); +SRSLTE_API void srslte_vec_sc_prod_fff_simd(const float *x, const float h, float *z, const int len); -SRSLTE_API void srslte_vec_sc_prod_ccc_simd(cf_t *x, cf_t h, cf_t *z, int len); +SRSLTE_API void srslte_vec_sc_prod_ccc_simd(const cf_t *x, const cf_t h, cf_t *z, const int len); /* SIMD Vector Product */ -SRSLTE_API void srslte_vec_prod_ccc_split_simd(float *a_re, float *a_im, float *b_re, float *b_im, float *r_re, float *r_im, int len); +SRSLTE_API void srslte_vec_prod_ccc_split_simd(const float *a_re, const float *a_im, const float *b_re, const float *b_im, + float *r_re, float *r_im, const int len); -SRSLTE_API void srslte_vec_prod_ccc_c16_simd(int16_t *a_re, int16_t *a_im, int16_t *b_re, int16_t *b_im, int16_t *r_re, - int16_t *r_im, int len); +SRSLTE_API void srslte_vec_prod_ccc_c16_simd(const int16_t *a_re, const int16_t *a_im, const int16_t *b_re, const int16_t *b_im, + int16_t *r_re, int16_t *r_im, const int len); -SRSLTE_API void srslte_vec_prod_sss_simd(int16_t *x, int16_t *y, int16_t *z, int len); +SRSLTE_API void srslte_vec_prod_sss_simd(const int16_t *x, const int16_t *y, int16_t *z, const int len); -SRSLTE_API void srslte_vec_prod_cfc_simd(cf_t *x, float *y, cf_t *z, int len); +SRSLTE_API void srslte_vec_prod_cfc_simd(const cf_t *x, const float *y, cf_t *z, const int len); -SRSLTE_API void srslte_vec_prod_fff_simd(float *x, float *y, float *z, int len); +SRSLTE_API void srslte_vec_prod_fff_simd(const float *x, const float *y, float *z, const int len); -SRSLTE_API void srslte_vec_prod_ccc_simd(cf_t *x,cf_t *y, cf_t *z, int len); +SRSLTE_API void srslte_vec_prod_ccc_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); -SRSLTE_API void srslte_vec_prod_conj_ccc_simd(cf_t *x,cf_t *y, cf_t *z, int len); +SRSLTE_API void srslte_vec_prod_conj_ccc_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); /* SIMD Division */ -SRSLTE_API void srslte_vec_div_ccc_simd(cf_t *x,cf_t *y, cf_t *z, int len); +SRSLTE_API void srslte_vec_div_ccc_simd(const cf_t *x, const cf_t *y, cf_t *z, const int len); -SRSLTE_API void srslte_vec_div_cfc_simd(cf_t *x, float *y, cf_t *z, int len); +SRSLTE_API void srslte_vec_div_cfc_simd(const cf_t *x, const float *y, cf_t *z, const int len); -SRSLTE_API void srslte_vec_div_fff_simd(float *x, float *y, float *z, int len); +SRSLTE_API void srslte_vec_div_fff_simd(const float *x, const float *y, float *z, const int len); /* SIMD Dot product */ -SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc_simd(cf_t *x, cf_t *y, int len); +SRSLTE_API cf_t srslte_vec_dot_prod_conj_ccc_simd(const cf_t *x, const cf_t *y, const int len); -SRSLTE_API cf_t srslte_vec_dot_prod_ccc_simd(cf_t *x, cf_t *y, int len); +SRSLTE_API cf_t srslte_vec_dot_prod_ccc_simd(const cf_t *x, const cf_t *y, const int len); -SRSLTE_API c16_t srslte_vec_dot_prod_ccc_c16i_simd(c16_t *x, c16_t *y, int len); +SRSLTE_API c16_t srslte_vec_dot_prod_ccc_c16i_simd(const c16_t *x, const c16_t *y, const int len); -SRSLTE_API int srslte_vec_dot_prod_sss_simd(int16_t *x, int16_t *y, int len); +SRSLTE_API int srslte_vec_dot_prod_sss_simd(const int16_t *x, const int16_t *y, const int len); /* SIMD Modulus functions */ -SRSLTE_API void srslte_vec_abs_cf_simd(cf_t *x, float *z, int len); +SRSLTE_API void srslte_vec_abs_cf_simd(const cf_t *x, float *z, const int len); -SRSLTE_API void srslte_vec_abs_square_cf_simd(cf_t *x, float *z, int len); +SRSLTE_API void srslte_vec_abs_square_cf_simd(const cf_t *x, float *z, const int len); /* Other Functions */ -SRSLTE_API void srslte_vec_lut_sss_simd(short *x, unsigned short *lut, short *y, int len); +SRSLTE_API void srslte_vec_lut_sss_simd(const short *x, const unsigned short *lut, short *y, const int len); -SRSLTE_API void srslte_vec_convert_fi_simd(float *x, int16_t *z, float scale, int len); +SRSLTE_API void srslte_vec_convert_fi_simd(const float *x, int16_t *z, const float scale, const int len); -SRSLTE_API void srslte_vec_cp_simd(cf_t *src, cf_t *dst, int len); +SRSLTE_API void srslte_vec_cp_simd(const cf_t *src, cf_t *dst, int len); /* SIMD Find Max functions */ -SRSLTE_API uint32_t srslte_vec_max_fi_simd(float *x, int len); +SRSLTE_API uint32_t srslte_vec_max_fi_simd(const float *x, const int len); -SRSLTE_API uint32_t srslte_vec_max_ci_simd(cf_t *x, int len); +SRSLTE_API uint32_t srslte_vec_max_ci_simd(const cf_t *x, const int len); #ifdef __cplusplus } diff --git a/lib/src/phy/dft/dft_fftw.c b/lib/src/phy/dft/dft_fftw.c index 9d6898117..e6eb70ecf 100644 --- a/lib/src/phy/dft/dft_fftw.c +++ b/lib/src/phy/dft/dft_fftw.c @@ -245,7 +245,7 @@ static void copy_post(uint8_t *dst, uint8_t *src, int size_d, int len, } } -void srslte_dft_run(srslte_dft_plan_t *plan, void *in, void *out) { +void srslte_dft_run(srslte_dft_plan_t *plan, const void *in, void *out) { if(plan->mode == SRSLTE_DFT_COMPLEX) { srslte_dft_run_c(plan,in,out); } else { @@ -253,11 +253,11 @@ void srslte_dft_run(srslte_dft_plan_t *plan, void *in, void *out) { } } -void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, cf_t *in, cf_t *out) { - fftwf_execute_dft(plan->p, in, out); +void srslte_dft_run_c_zerocopy(srslte_dft_plan_t *plan, const cf_t *in, cf_t *out) { + fftwf_execute_dft(plan->p, (cf_t*) in, out); } -void srslte_dft_run_c(srslte_dft_plan_t *plan, cf_t *in, cf_t *out) { +void srslte_dft_run_c(srslte_dft_plan_t *plan, const cf_t *in, cf_t *out) { float norm; int i; fftwf_complex *f_out = plan->out; @@ -286,7 +286,7 @@ void srslte_dft_run_guru_c(srslte_dft_plan_t *plan) { } } -void srslte_dft_run_r(srslte_dft_plan_t *plan, float *in, float *out) { +void srslte_dft_run_r(srslte_dft_plan_t *plan, const float *in, float *out) { float norm; int i; int len = plan->size; diff --git a/lib/src/phy/modem/demod_soft.c b/lib/src/phy/modem/demod_soft.c index 259a12271..0ea3ce938 100644 --- a/lib/src/phy/modem/demod_soft.c +++ b/lib/src/phy/modem/demod_soft.c @@ -57,11 +57,11 @@ void demod_bpsk_lte(const cf_t *symbols, float *llr, int nsymbols) { } void demod_qpsk_lte_s(const cf_t *symbols, short *llr, int nsymbols) { - srslte_vec_convert_fi((float*) symbols, llr, -SCALE_SHORT_CONV_QPSK*sqrt(2), nsymbols*2); + srslte_vec_convert_fi((const float*) symbols, -SCALE_SHORT_CONV_QPSK*sqrt(2), llr, nsymbols*2); } void demod_qpsk_lte(const cf_t *symbols, float *llr, int nsymbols) { - srslte_vec_sc_prod_fff((float*) symbols, -sqrt(2), llr, nsymbols*2); + srslte_vec_sc_prod_fff((const float*) symbols, -sqrt(2), llr, nsymbols*2); } void demod_16qam_lte(const cf_t *symbols, float *llr, int nsymbols) { diff --git a/lib/src/phy/resampling/test/resample_arb_bench.c b/lib/src/phy/resampling/test/resample_arb_bench.c index 773291913..e9ef3c442 100644 --- a/lib/src/phy/resampling/test/resample_arb_bench.c +++ b/lib/src/phy/resampling/test/resample_arb_bench.c @@ -50,7 +50,7 @@ int main(int argc, char **argv) { clock_t start = clock(), diff; for(int xx = 0; xxrx_rate, meta.timestamp, secs, frac_secs); - srslte_vec_convert_if(handler->rx_buffer, data, 2048, 2*nsamples); + srslte_vec_convert_if(handler->rx_buffer, 2048, data, 2*nsamples); return nsamples; } @@ -506,7 +506,7 @@ int rf_blade_send_timed(void *h, return -1; } - srslte_vec_convert_fi(data, handler->tx_buffer, 2048, 2*nsamples); + srslte_vec_convert_fi(data, 2048, handler->tx_buffer, 2*nsamples); memset(&meta, 0, sizeof(meta)); if (is_start_of_burst) { diff --git a/lib/src/phy/rf/rf_utils.c b/lib/src/phy/rf/rf_utils.c index ce288b5c5..f97784305 100644 --- a/lib/src/phy/rf/rf_utils.c +++ b/lib/src/phy/rf/rf_utils.c @@ -123,12 +123,7 @@ int rf_mib_decoder(srslte_rf_t *rf, uint32_t nof_rx_antennas,cell_search_cfg_t * INFO("Starting receiver...\n", 0); srslte_rf_start_rx_stream(rf); - - // Set CFO if available - if (cfo) { - srslte_ue_sync_set_cfo(&ue_mib.ue_sync, *cfo); - } - + /* Find and decody MIB */ ret = srslte_ue_mib_sync_decode(&ue_mib, config->max_frames_pbch, bch_payload, &cell->nof_ports, NULL); if (ret < 0) { diff --git a/lib/src/phy/sync/cfo.c b/lib/src/phy/sync/cfo.c index 34498ce58..44c795c19 100644 --- a/lib/src/phy/sync/cfo.c +++ b/lib/src/phy/sync/cfo.c @@ -83,7 +83,7 @@ int srslte_cfo_resize(srslte_cfo_t *h, uint32_t samples) { return SRSLTE_SUCCESS; } -void srslte_cfo_correct(srslte_cfo_t *h, cf_t *input, cf_t *output, float freq) { +void srslte_cfo_correct(srslte_cfo_t *h, const cf_t *input, cf_t *output, float freq) { if (fabs(h->last_freq - freq) > h->tol) { h->last_freq = freq; srslte_cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); diff --git a/lib/src/phy/sync/cp.c b/lib/src/phy/sync/cp.c index a282f6dfd..80d0a2179 100644 --- a/lib/src/phy/sync/cp.c +++ b/lib/src/phy/sync/cp.c @@ -63,14 +63,14 @@ int srslte_cp_synch_resize(srslte_cp_synch_t *q, uint32_t symbol_sz) } -uint32_t srslte_cp_synch(srslte_cp_synch_t *q, cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) +uint32_t srslte_cp_synch(srslte_cp_synch_t *q, const cf_t *input, uint32_t max_offset, uint32_t nof_symbols, uint32_t cp_len) { if (max_offset > q->symbol_sz) { max_offset = q->symbol_sz; } for (int i=0;icorr[i] = 0; - cf_t *inputPtr = input; + const cf_t *inputPtr = input; for (int n=0;ncorr[i] += srslte_vec_dot_prod_conj_ccc(&inputPtr[i], &inputPtr[i+q->symbol_sz], cplen)/nof_symbols; diff --git a/lib/src/phy/sync/find_sss.c b/lib/src/phy/sync/find_sss.c index 082aee52a..70b300bd3 100644 --- a/lib/src/phy/sync/find_sss.c +++ b/lib/src/phy/sync/find_sss.c @@ -68,7 +68,7 @@ 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_synch_t *q, cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { +static void extract_pair_sss(srslte_sss_synch_t *q, const cf_t *input, cf_t *ce, cf_t y[2][SRSLTE_SSS_N]) { cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; srslte_dft_run_c(&q->dftp_input, input, input_fft); @@ -88,7 +88,7 @@ static void extract_pair_sss(srslte_sss_synch_t *q, cf_t *input, cf_t *ce, cf_t } -int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value, +int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, const cf_t *input, uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { return srslte_sss_synch_m0m1_diff_coh(q, input, NULL, m0, m0_value, m1, m1_value); @@ -102,7 +102,7 @@ int srslte_sss_synch_m0m1_diff(srslte_sss_synch_t *q, cf_t *input, uint32_t *m0, * */ -int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, const cf_t *input, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { @@ -145,7 +145,7 @@ int srslte_sss_synch_m0m1_diff_coh(srslte_sss_synch_t *q, cf_t *input, cf_t ce[2 * Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi */ -int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, +int srslte_sss_synch_m0m1_partial(srslte_sss_synch_t *q, const cf_t *input, uint32_t M, cf_t ce[2*SRSLTE_SSS_N], uint32_t *m0, float *m0_value, uint32_t *m1, float *m1_value) { diff --git a/lib/src/phy/sync/pss.c b/lib/src/phy/sync/pss.c index 411579d7c..d93fe0896 100644 --- a/lib/src/phy/sync/pss.c +++ b/lib/src/phy/sync/pss.c @@ -119,7 +119,7 @@ int srslte_pss_synch_init_fft_offset_decim(srslte_pss_synch_t *q, buffer_size = fft_size + frame_size + 1; - q->filter_pss_enable = true; + q->filter_pss_enable = false; if(q->decimate > 1) { int filter_order = 3; @@ -417,6 +417,37 @@ void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { q->ema_alpha = alpha; } +float compute_peak_sidelobe(srslte_pss_synch_t *q, uint32_t corr_peak_pos, uint32_t conv_output_len) +{ + // Find end of peak lobe to the right + int pl_ub = corr_peak_pos+1; + while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { + pl_ub ++; + } + // Find end of peak lobe to the left + int pl_lb; + if (corr_peak_pos > 2) { + pl_lb = corr_peak_pos-1; + while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { + pl_lb --; + } + } else { + pl_lb = 0; + } + + int sl_distance_right = conv_output_len-1-pl_ub; + if (sl_distance_right < 0) { + sl_distance_right = 0; + } + int sl_distance_left = pl_lb; + + int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); + int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); + float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); + + return q->conv_output_avg[corr_peak_pos]/side_lobe_value; +} + /** Performs time-domain PSS correlation. * Returns the index of the PSS correlation peak in a subframe. * The frame starts at corr_peak_pos-subframe_size/2. @@ -424,7 +455,7 @@ void srslte_pss_synch_set_ema_alpha(srslte_pss_synch_t *q, float alpha) { * * Input buffer must be subframe_size long. */ -int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_peak_value) +int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, const cf_t *input, float *corr_peak_value) { int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -448,16 +479,13 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe */ if (q->frame_size >= q->fft_size) { #ifdef CONVOLUTION_FFT - memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t)); - if(q->decimate > 1) - { - srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate)); - conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output); - } - else - { - conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); - } + memcpy(q->tmp_input, input, (q->frame_size * q->decimate) * sizeof(cf_t)); + if(q->decimate > 1) { + srslte_filt_decim_cc_execute(&(q->filter), q->tmp_input, q->filter.downsampled_input, q->filter.filter_output , (q->frame_size * q->decimate)); + conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->filter.filter_output,q->pss_signal_freq_full[q->N_id_2], q->conv_output); + } else { + conv_output_len = srslte_conv_fft_cc_run_opt(&q->conv_fft, q->tmp_input, q->pss_signal_freq_full[q->N_id_2], q->conv_output); + } #else conv_output_len = srslte_conv_cc(input, q->pss_signal_time[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); @@ -469,13 +497,10 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe conv_output_len = q->frame_size; } + // Compute modulus square + srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); - #ifdef SRSLTE_PSS_ABS_SQUARE - srslte_vec_abs_square_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); - #else - srslte_vec_abs_cf(q->conv_output, q->conv_output_abs, conv_output_len-1); - #endif - + // If enabled, average the absolute value from previous calls if (q->ema_alpha < 1.0 && q->ema_alpha > 0.0) { srslte_vec_sc_prod_fff(q->conv_output_abs, q->ema_alpha, q->conv_output_abs, conv_output_len-1); srslte_vec_sc_prod_fff(q->conv_output_avg, 1-q->ema_alpha, q->conv_output_avg, conv_output_len-1); @@ -484,6 +509,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe } else { memcpy(q->conv_output_avg, q->conv_output_abs, sizeof(float)*(conv_output_len-1)); } + /* Find maximum of the absolute value of the correlation */ corr_peak_pos = srslte_vec_max_fi(q->conv_output_avg, conv_output_len-1); @@ -491,39 +517,8 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe q->peak_value = q->conv_output_avg[corr_peak_pos]; #ifdef SRSLTE_PSS_RETURN_PSR - // Find second side lobe - - // Find end of peak lobe to the right - int pl_ub = corr_peak_pos+1; - while(q->conv_output_avg[pl_ub+1] <= q->conv_output_avg[pl_ub] && pl_ub < conv_output_len) { - pl_ub ++; - } - // Find end of peak lobe to the left - int pl_lb; - if (corr_peak_pos > 2) { - pl_lb = corr_peak_pos-1; - while(q->conv_output_avg[pl_lb-1] <= q->conv_output_avg[pl_lb] && pl_lb > 1) { - pl_lb --; - } - } else { - pl_lb = 0; - } - - int sl_distance_right = conv_output_len-1-pl_ub; - if (sl_distance_right < 0) { - sl_distance_right = 0; - } - int sl_distance_left = pl_lb; - - int sl_right = pl_ub+srslte_vec_max_fi(&q->conv_output_avg[pl_ub], sl_distance_right); - int sl_left = srslte_vec_max_fi(q->conv_output_avg, sl_distance_left); - float side_lobe_value = SRSLTE_MAX(q->conv_output_avg[sl_right], q->conv_output_avg[sl_left]); if (corr_peak_value) { - *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; - - if (*corr_peak_value < 10) - DEBUG("peak_pos=%2d, pl_ub=%2d, pl_lb=%2d, sl_right: %2d, sl_left: %2d, PSR: %.2f/%.2f=%.2f\n", corr_peak_pos, pl_ub, pl_lb, - sl_right,sl_left, q->conv_output_avg[corr_peak_pos], side_lobe_value,*corr_peak_value); + *corr_peak_value = compute_peak_sidelobe(q, corr_peak_pos, conv_output_len); } #else if (corr_peak_value) { @@ -531,14 +526,12 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe } #endif - if(q->decimate >1) - { - int decimation_correction = (q->filter.num_taps - 2); - corr_peak_pos = corr_peak_pos - decimation_correction; - corr_peak_pos = corr_peak_pos*q->decimate; + if(q->decimate >1) { + int decimation_correction = (q->filter.num_taps - 2); + corr_peak_pos = corr_peak_pos - decimation_correction; + corr_peak_pos = corr_peak_pos*q->decimate; } - if (q->frame_size >= q->fft_size) { ret = (int) corr_peak_pos; } else { @@ -552,7 +545,7 @@ int srslte_pss_synch_find_pss(srslte_pss_synch_t *q, cf_t *input, float *corr_pe * input signal is in the time-domain. * ce is the returned frequency-domain channel estimates. */ -int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { +int srslte_pss_synch_chest(srslte_pss_synch_t *q, const cf_t *input, cf_t ce[SRSLTE_PSS_LEN]) { int ret = SRSLTE_ERROR_INVALID_INPUTS; cf_t input_fft[SRSLTE_SYMBOL_SZ_MAX]; @@ -577,7 +570,7 @@ int srslte_pss_synch_chest(srslte_pss_synch_t *q, cf_t *input, cf_t ce[SRSLTE_PS } // Frequency-domain filtering of the central 64 sub-carriers -void srslte_pss_synch_filter(srslte_pss_synch_t *q, cf_t *input, cf_t *output) +void srslte_pss_synch_filter(srslte_pss_synch_t *q, const cf_t *input, cf_t *output) { srslte_dft_run_c(&q->dftp_input, input, q->tmp_fft); @@ -593,14 +586,14 @@ void srslte_pss_synch_filter(srslte_pss_synch_t *q, cf_t *input, cf_t *output) * Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE * Feng Wang and Yu Zhu */ -float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, cf_t *pss_recv) { +float srslte_pss_synch_cfo_compute(srslte_pss_synch_t* q, const cf_t *pss_recv) { cf_t y0, y1; - cf_t *pss_ptr = pss_recv; + const cf_t *pss_ptr = pss_recv; if (q->filter_pss_enable) { srslte_pss_synch_filter(q, pss_recv, q->tmp_fft); - pss_ptr = q->tmp_fft; + pss_ptr = (const cf_t*) q->tmp_fft; } y0 = srslte_vec_dot_prod_ccc(q->pss_signal_time[q->N_id_2], pss_ptr, q->fft_size/2); diff --git a/lib/src/phy/sync/sync.c b/lib/src/phy/sync/sync.c index d1a477046..d14419965 100644 --- a/lib/src/phy/sync/sync.c +++ b/lib/src/phy/sync/sync.c @@ -37,11 +37,10 @@ #include "srslte/phy/utils/vector.h" #include "srslte/phy/sync/cfo.h" -#define MEANPEAK_EMA_ALPHA 0.1 -#define CFO_EMA_ALPHA 0.1 -#define CP_EMA_ALPHA 0.1 +#define CFO_EMA_ALPHA 0.1 +#define CP_EMA_ALPHA 0.1 -#define DEFAULT_CFO_TOL 50.0 // Hz +#define DEFAULT_CFO_TOL 50.0 // Hz static bool fft_size_isvalid(uint32_t fft_size) { if (fft_size >= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { @@ -51,13 +50,12 @@ static bool fft_size_isvalid(uint32_t fft_size) { } } - - int srslte_sync_init(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size) { return srslte_sync_init_decim(q, frame_size, max_offset, fft_size, 1); } -int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size, int decimate) { +int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offset, uint32_t fft_size, int decimate) +{ int ret = SRSLTE_ERROR_INVALID_INPUTS; @@ -67,31 +65,34 @@ int srslte_sync_init_decim(srslte_sync_t *q, uint32_t frame_size, uint32_t max_o { ret = SRSLTE_ERROR; bzero(q, sizeof(srslte_sync_t)); - q->detect_cp = true; - q->sss_en = true; - q->mean_cfo = 0; - q->mean_cfo2 = 0; - q->N_id_2 = 1000; + + q->N_id_2 = 1000; q->N_id_1 = 1000; - q->cfo_i = 0; - q->find_cfo_i = false; - q->find_cfo_i_initiated = false; + q->cfo_ema_alpha = CFO_EMA_ALPHA; + q->sss_alg = SSS_FULL; + + q->detect_cp = true; + q->sss_en = true; + q->cfo_pss_enable = false; + q->cfo_cp_enable = false; + q->cfo_i_initiated = false; + q->pss_filtering_enabled = false; + q->sss_filtering_enabled = false; + q->fft_size = fft_size; q->frame_size = frame_size; q->max_offset = max_offset; - q->sss_alg = SSS_FULL; q->max_frame_size = frame_size; - q->mean_cfo_isunset = true; - q->mean_cfo2_isunset = true; - q->enable_cfo_corr = true; - if (srslte_cfo_init(&q->cfocorr, q->frame_size)) { + srslte_sync_cfo_reset(q); + + if (srslte_cfo_init(&q->cfo_corr_frame, q->frame_size)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; } - if (srslte_cfo_init(&q->cfocorr2, q->frame_size)) { + if (srslte_cfo_init(&q->cfo_corr_symbol, q->fft_size)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; } @@ -147,18 +148,23 @@ clean_exit: return ret; } -void srslte_sync_free(srslte_sync_t *q) { +void srslte_sync_free(srslte_sync_t *q) +{ if (q) { + srslte_pss_synch_free(&q->pss); srslte_sss_synch_free(&q->sss); - srslte_cfo_free(&q->cfocorr); - srslte_cfo_free(&q->cfocorr2); + srslte_cfo_free(&q->cfo_corr_frame); + srslte_cfo_free(&q->cfo_corr_symbol); srslte_cp_synch_free(&q->cp_synch); - for (int i=0;i<2;i++) { - if (q->cfo_i_corr[i]) { - free(q->cfo_i_corr[i]); + + if (q->cfo_i_initiated) { + for (int i=0;i<2;i++) { + if (q->cfo_i_corr[i]) { + free(q->cfo_i_corr[i]); + } + srslte_pss_synch_free(&q->pss_i[i]); } - srslte_pss_synch_free(&q->pss_i[i]); } if (q->temp) { free(q->temp); @@ -174,53 +180,51 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse frame_size <= 307200 && fft_size_isvalid(fft_size)) { - ret = SRSLTE_ERROR; - if (frame_size > q->max_frame_size) { fprintf(stderr, "Error in sync_resize(): frame_size must be lower than initialized\n"); return SRSLTE_ERROR; } - q->detect_cp = true; - q->sss_en = true; - q->mean_cfo = 0; - q->mean_cfo2 = 0; - q->N_id_2 = 1000; - q->N_id_1 = 1000; - q->cfo_i = 0; - q->find_cfo_i = false; - q->find_cfo_i_initiated = false; - q->cfo_ema_alpha = CFO_EMA_ALPHA; - q->fft_size = fft_size; + + q->fft_size = fft_size; q->frame_size = frame_size; q->max_offset = max_offset; - q->sss_alg = SSS_FULL; - q->enable_cfo_corr = true; - - if (srslte_pss_synch_resize(&q->pss, max_offset, fft_size, 0)) { + if (srslte_pss_synch_resize(&q->pss, q->max_offset, q->fft_size, 0)) { fprintf(stderr, "Error resizing PSS object\n"); return SRSLTE_ERROR; } - if (srslte_sss_synch_resize(&q->sss, fft_size)) { + if (srslte_sss_synch_resize(&q->sss, q->fft_size)) { fprintf(stderr, "Error resizing SSS object\n"); return SRSLTE_ERROR; } - if (srslte_cp_synch_resize(&q->cp_synch, fft_size)) { + if (srslte_cp_synch_resize(&q->cp_synch, q->fft_size)) { fprintf(stderr, "Error resizing CFO\n"); return SRSLTE_ERROR; } - if (srslte_cfo_resize(&q->cfocorr, q->frame_size)) { + if (srslte_cfo_resize(&q->cfo_corr_frame, q->frame_size)) { fprintf(stderr, "Error resizing CFO\n"); return SRSLTE_ERROR; } - if (srslte_cfo_resize(&q->cfocorr2, q->frame_size)) { + if (srslte_cfo_resize(&q->cfo_corr_symbol, q->fft_size)) { fprintf(stderr, "Error resizing CFO\n"); return SRSLTE_ERROR; } + if (q->cfo_i_initiated) { + for (int i=0;i<2;i++) { + int offset=(i==0)?-1:1; + if (srslte_pss_synch_resize(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + fprintf(stderr, "Error initializing PSS object\n"); + } + for (int t=0;tframe_size;t++) { + q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); + } + } + } + // Update CFO tolerance srslte_sync_set_cfo_tol(q, q->current_cfo_tol); @@ -236,30 +240,14 @@ int srslte_sync_resize(srslte_sync_t *q, uint32_t frame_size, uint32_t max_offse void srslte_sync_set_cfo_tol(srslte_sync_t *q, float tol) { q->current_cfo_tol = tol; - srslte_cfo_set_tol(&q->cfocorr, tol/(15000.0*q->fft_size)); - srslte_cfo_set_tol(&q->cfocorr2, tol/(15000.0*q->fft_size)); + srslte_cfo_set_tol(&q->cfo_corr_frame, tol/(15000.0*q->fft_size)); + srslte_cfo_set_tol(&q->cfo_corr_symbol, tol/(15000.0*q->fft_size)); } void srslte_sync_set_threshold(srslte_sync_t *q, float threshold) { q->threshold = threshold; } -void srslte_sync_cfo_i_detec_en(srslte_sync_t *q, bool enabled) { - q->find_cfo_i = enabled; - if (enabled && !q->find_cfo_i_initiated) { - for (int i=0;i<2;i++) { - int offset=(i==0)?-1:1; - if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { - fprintf(stderr, "Error initializing PSS object\n"); - } - for (int t=0;tframe_size;t++) { - q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); - } - } - q->find_cfo_i_initiated = true; - } -} - void srslte_sync_sss_en(srslte_sync_t *q, bool enabled) { q->sss_en = enabled; } @@ -291,30 +279,59 @@ uint32_t srslte_sync_get_sf_idx(srslte_sync_t *q) { } float srslte_sync_get_cfo(srslte_sync_t *q) { - return q->mean_cfo2 + q->cfo_i; + return q->cfo_cp_mean + q->cfo_pss_mean + q->cfo_i_value; } -void srslte_sync_set_cfo(srslte_sync_t *q, float cfo) { - q->mean_cfo = cfo; - q->mean_cfo2 = cfo; - q->mean_cfo2_isunset = false; - q->mean_cfo_isunset = false; +void srslte_sync_cfo_reset(srslte_sync_t *q) +{ + q->cfo_cp_mean = 0; + q->cfo_cp_is_set = false; + q->cfo_pss_mean = 0; + q->cfo_pss_is_set = false; } -void srslte_sync_set_cfo_i(srslte_sync_t *q, int cfo_i) { - q->cfo_i = cfo_i; +void srslte_sync_copy_cfo(srslte_sync_t *q, srslte_sync_t *src_obj) { + q->cfo_cp_mean = src_obj->cfo_cp_mean; + q->cfo_pss_mean = src_obj->cfo_pss_mean; + q->cfo_i_value = src_obj->cfo_i_value; + q->cfo_cp_is_set = false; + q->cfo_pss_is_set = false; } -void srslte_sync_set_cfo_enable(srslte_sync_t *q, bool enable) { - q->enable_cfo_corr = enable; +void srslte_sync_set_cfo_i_enable(srslte_sync_t *q, bool enable) { + q->cfo_i_enable = enable; + if (q->cfo_i_enable && !q->cfo_i_initiated) { + for (int i=0;i<2;i++) { + int offset=(i==0)?-1:1; + if (srslte_pss_synch_init_fft_offset(&q->pss_i[i], q->max_offset, q->fft_size, offset)) { + fprintf(stderr, "Error initializing PSS object\n"); + } + for (int t=0;tframe_size;t++) { + q->cfo_i_corr[i][t] = cexpf(-2*_Complex_I*M_PI*offset*(float) t/q->fft_size); + } + } + q->cfo_i_initiated = true; + } } -void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, float alpha) { - q->cfo_ema_alpha = alpha; +void srslte_sync_set_sss_filt_enable(srslte_sync_t *q, bool enable) { + q->sss_filtering_enabled = enable; } -float srslte_sync_get_last_peak_value(srslte_sync_t *q) { - return q->peak_value; +void srslte_sync_set_pss_filt_enable(srslte_sync_t *q, bool enable) { + q->pss_filtering_enabled = enable; +} + +void srslte_sync_set_cfo_cp_enable(srslte_sync_t *q, bool enable) { + q->cfo_cp_enable = enable; +} + +void srslte_sync_set_cfo_pss_enable(srslte_sync_t *q, bool enable) { + q->cfo_pss_enable = enable; +} + +void srslte_sync_set_cfo_ema_alpha(srslte_sync_t *q, float alpha) { + q->cfo_ema_alpha = alpha; } float srslte_sync_get_peak_value(srslte_sync_t *q) { @@ -325,18 +342,17 @@ void srslte_sync_cp_en(srslte_sync_t *q, bool enabled) { q->detect_cp = enabled; } -bool srslte_sync_sss_is_en(srslte_sync_t *q) { - return q->sss_en; -} - -void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) { +void srslte_sync_set_em_alpha(srslte_sync_t *q, float alpha) +{ srslte_pss_synch_set_ema_alpha(&q->pss, alpha); } -srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) { +srslte_cp_t srslte_sync_get_cp(srslte_sync_t *q) +{ return q->cp; } -void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) { +void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) +{ q->cp = cp; q->cp_len = SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_LEN_NORM(1,q->fft_size):SRSLTE_CP_LEN_EXT(q->fft_size); if (q->frame_size < q->fft_size) { @@ -346,7 +362,8 @@ void srslte_sync_set_cp(srslte_sync_t *q, srslte_cp_t cp) { } } -void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) { +void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) +{ q->sss_alg = alg; } @@ -354,7 +371,7 @@ void srslte_sync_set_sss_algorithm(srslte_sync_t *q, sss_alg_t alg) { * "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver" * by Jung-In Kim et al. */ -srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_pos) +srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, const cf_t *input, uint32_t peak_pos) { float R_norm=0, R_ext=0, C_norm=0, C_ext=0; float M_norm=0, M_ext=0; @@ -370,8 +387,8 @@ srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_p if (nof_symbols > 0) { - cf_t *input_cp_norm = &input[peak_pos-nof_symbols*(q->fft_size+cp_norm_len)]; - cf_t *input_cp_ext = &input[peak_pos-nof_symbols*(q->fft_size+cp_ext_len)]; + const cf_t *input_cp_norm = &input[peak_pos-nof_symbols*(q->fft_size+cp_norm_len)]; + const cf_t *input_cp_ext = &input[peak_pos-nof_symbols*(q->fft_size+cp_ext_len)]; for (int i=0;ifft_size], input_cp_norm, cp_norm_len)); @@ -414,28 +431,21 @@ srslte_cp_t srslte_sync_detect_cp(srslte_sync_t *q, cf_t *input, uint32_t peak_p /* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space * to correlate */ -int sync_sss(srslte_sync_t *q, cf_t *input, uint32_t peak_pos, srslte_cp_t cp) { - int sss_idx, ret; +int sync_sss_symbol(srslte_sync_t *q, const cf_t *input) +{ + int ret; srslte_sss_synch_set_N_id_2(&q->sss, q->N_id_2); - /* Make sure we have enough room to find SSS sequence */ - sss_idx = (int) peak_pos-2*q->fft_size-SRSLTE_CP_LEN(q->fft_size, (SRSLTE_CP_ISNORM(q->cp)?SRSLTE_CP_NORM_LEN:SRSLTE_CP_EXT_LEN)); - if (sss_idx < 0) { - DEBUG("Not enough room to decode SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos); - return SRSLTE_ERROR; - } - DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos); - switch(q->sss_alg) { case SSS_DIFF: - srslte_sss_synch_m0m1_diff(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_synch_m0m1_diff(&q->sss, input, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_PARTIAL_3: - srslte_sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_synch_m0m1_partial(&q->sss, input, 3, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; case SSS_FULL: - srslte_sss_synch_m0m1_partial(&q->sss, &input[sss_idx], 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); + srslte_sss_synch_m0m1_partial(&q->sss, input, 1, NULL, &q->m0, &q->m0_value, &q->m1, &q->m1_value); break; } @@ -452,20 +462,23 @@ int sync_sss(srslte_sync_t *q, cf_t *input, uint32_t peak_pos, srslte_cp_t cp) { } } -srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) { +srslte_pss_synch_t* srslte_sync_get_cur_pss_obj(srslte_sync_t *q) +{ srslte_pss_synch_t *pss_obj[3] = {&q->pss_i[0], &q->pss, &q->pss_i[1]}; - return pss_obj[q->cfo_i+1]; + return pss_obj[q->cfo_i_value+1]; } -static float cfo_estimate(srslte_sync_t *q, cf_t *input) { +static float cfo_cp_estimate(srslte_sync_t *q, const cf_t *input) +{ uint32_t cp_offset = 0; - cp_offset = srslte_cp_synch(&q->cp_synch, input, q->max_offset, 2, SRSLTE_CP_LEN_NORM(1,q->fft_size)); + cp_offset = srslte_cp_synch(&q->cp_synch, input, q->max_offset, 7, SRSLTE_CP_LEN_NORM(1,q->fft_size)); cf_t cp_corr_max = srslte_cp_synch_corr_output(&q->cp_synch, cp_offset); float cfo = -carg(cp_corr_max) / M_PI / 2; return cfo; } -static int cfo_i_estimate(srslte_sync_t *q, cf_t *input, int find_offset, int *peak_pos) { +static int cfo_i_estimate(srslte_sync_t *q, const cf_t *input, int find_offset, int *peak_pos, int *cfo_i) +{ float peak_value; float max_peak_value = -99; int max_cfo_i = 0; @@ -473,6 +486,9 @@ static int cfo_i_estimate(srslte_sync_t *q, cf_t *input, int find_offset, int *p for (int cfo_i=0;cfo_i<3;cfo_i++) { srslte_pss_synch_set_N_id_2(pss_obj[cfo_i], q->N_id_2); int p = srslte_pss_synch_find_pss(pss_obj[cfo_i], &input[find_offset], &peak_value); + if (p < 0) { + return -1; + } if (peak_value > max_peak_value) { max_peak_value = peak_value; if (peak_pos) { @@ -481,125 +497,172 @@ static int cfo_i_estimate(srslte_sync_t *q, cf_t *input, int find_offset, int *p q->peak_value = peak_value; max_cfo_i = cfo_i-1; } - } - return max_cfo_i; -} - -float srslte_sync_cfo_estimate(srslte_sync_t *q, cf_t *input, int find_offset) { - float cfo_f = cfo_estimate(q, input); - - int cfo_i = 0; - if (q->find_cfo_i) { - cfo_i = cfo_i_estimate(q, input, find_offset, NULL); } - return (float) cfo_i + cfo_f; + if (cfo_i) { + *cfo_i = max_cfo_i; + } + return 0; } /** Finds the PSS sequence previously defined by a call to srslte_sync_set_N_id_2() - * around the position find_offset in the buffer input. + * around the position find_offset in the buffer input. + * * Returns 1 if the correlation peak exceeds the threshold set by srslte_sync_set_threshold() * or 0 otherwise. Returns a negative number on error (if N_id_2 has not been set) - * + * + * The input signal is not modified. Any CFO correction is done in internal buffers + * * The maximum of the correlation peak is always stored in *peak_position */ -srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_position) +srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, const cf_t *input, uint32_t find_offset, uint32_t *peak_position) { - - srslte_sync_find_ret_t ret = SRSLTE_SYNC_ERROR; - + srslte_sync_find_ret_t ret = SRSLTE_SYNC_ERROR; + int peak_pos = 0; + if (!q) { return SRSLTE_ERROR_INVALID_INPUTS; } - if (input != NULL && + if (input != NULL && srslte_N_id_2_isvalid(q->N_id_2) && fft_size_isvalid(q->fft_size)) { - int peak_pos = 0; - - ret = SRSLTE_SUCCESS; - + if (peak_position) { *peak_position = 0; } - cf_t *input_cfo = input; + const cf_t *input_ptr = input; + + /* First CFO estimation stage is integer. + * Finds max PSS correlation for shifted +1/0/-1 integer versions. + * This should only used once N_id_2 is set + */ + if (q->cfo_i_enable) { + if (cfo_i_estimate(q, input_ptr, find_offset, &peak_pos, &q->cfo_i_value) < 0) { + fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); + return SRSLTE_ERROR; + } + // Correct it using precomputed signal and store in buffer (don't modify input signal) + if (q->cfo_i_value != 0) { + srslte_vec_prod_ccc((cf_t*) input_ptr, q->cfo_i_corr[q->cfo_i_value<0?0:1], q->temp, q->frame_size); + INFO("Compensating cfo_i=%d\n", q->cfo_i_value); + input_ptr = q->temp; + } + } - if (q->enable_cfo_corr) { - float cfo = cfo_estimate(q, input); + /* Second stage is coarse fractional CFO estimation using CP. + * In case of multi-cell, this can lead to incorrect estimations if CFO from different cells is different + */ + if (q->cfo_cp_enable) { + float cfo_cp = cfo_cp_estimate(q, input_ptr); - if (q->mean_cfo_isunset) { - q->mean_cfo = cfo; - q->mean_cfo_isunset = false; + if (!q->cfo_cp_is_set) { + q->cfo_cp_mean = cfo_cp; + q->cfo_cp_is_set = true; } else { /* compute exponential moving average CFO */ - q->mean_cfo = SRSLTE_VEC_EMA(cfo, q->mean_cfo, q->cfo_ema_alpha); + q->cfo_cp_mean = SRSLTE_VEC_EMA(cfo_cp, q->cfo_cp_mean, q->cfo_ema_alpha); } + INFO("CP-CFO: estimated=%f, mean=%f\n", cfo_cp, q->cfo_cp_mean); + /* Correct CFO with the averaged CFO estimation */ - srslte_cfo_correct(&q->cfocorr2, input, q->temp, -q->mean_cfo / q->fft_size); - - input_cfo = q->temp; + srslte_cfo_correct(&q->cfo_corr_frame, input_ptr, q->temp, -q->cfo_cp_mean / q->fft_size); + input_ptr = q->temp; } - - /* If integer CFO is enabled, find max PSS correlation for shifted +1/0/-1 integer versions */ - if (q->find_cfo_i && q->enable_cfo_corr) { - q->cfo_i = cfo_i_estimate(q, input_cfo, find_offset, &peak_pos); - if (q->cfo_i != 0) { - srslte_vec_prod_ccc(input_cfo, q->cfo_i_corr[q->cfo_i<0?0:1], input_cfo, q->frame_size); - INFO("Compensating cfo_i=%d\n", q->cfo_i); + + /* Find maximum of PSS correlation. If Integer CFO is enabled, correlation is already done + */ + if (!q->cfo_i_enable) { + srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); + peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_ptr[find_offset], q->threshold>0?&q->peak_value:NULL); + if (peak_pos < 0) { + fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); + return SRSLTE_ERROR; } } - srslte_pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = srslte_pss_synch_find_pss(&q->pss, &input_cfo[find_offset], &q->peak_value); - - // this compensates for the constant time shift caused by the low pass filter - if(q->decimate && peak_pos < 0) - { - peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; - } - if (peak_pos < 0) { - fprintf(stderr, "Error calling finding PSS sequence at : %d \n", peak_pos); - return SRSLTE_ERROR; - } + INFO("PSS: id=%d, peak_pos=%d, peak_value=%f\n", q->N_id_2, peak_pos, q->peak_value); + // Save peak position if (peak_position) { *peak_position = (uint32_t) peak_pos; } - - // Try to detect SSS - if (q->sss_en) { - // Set an invalid N_id_1 indicating SSS is yet to be detected - q->N_id_1 = 1000; - - if (sync_sss(q, input_cfo, find_offset + peak_pos, q->cp) < 0) { - DEBUG("No space for SSS processing. Frame starts at %d\n", peak_pos); - } + + // In case of decimation, this compensates for the constant time shift caused by the low pass filter + if(q->decimate && peak_pos < 0) { + peak_pos = 0 ;//peak_pos + q->decimate*(2);// replace 2 with q->filter_size -2; } - + /* If peak is over threshold, compute CFO and SSS */ - if (q->peak_value >= q->threshold) { + if (q->peak_value >= q->threshold || q->threshold == 0) { + + if (q->cfo_pss_enable && peak_pos >= q->fft_size) { + + // Filter central bands before PSS-based CFO estimation + const cf_t *pss_ptr = &input_ptr[find_offset + peak_pos - q->fft_size]; + if (q->pss_filtering_enabled) { + srslte_pss_synch_filter(&q->pss, pss_ptr, q->pss_filt); + pss_ptr = q->pss_filt; + } - if (q->detect_cp) { - if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_cfo, peak_pos + find_offset)); + // PSS-based CFO estimation + float cfo_pss = srslte_pss_synch_cfo_compute(&q->pss, pss_ptr); + if (!q->cfo_pss_is_set) { + q->cfo_pss_mean = cfo_pss; + q->cfo_pss_is_set = true; } else { - DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); + q->cfo_pss_mean = SRSLTE_VEC_EMA(cfo_pss, q->cfo_pss_mean, q->cfo_ema_alpha); } + + INFO("PSS-CFO: filter=%s, estimated=%f, mean=%f\n", + q->pss_filtering_enabled?"yes":"no", cfo_pss, q->cfo_pss_mean); + } - if (peak_pos + find_offset >= 2*(q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { - float cfo2 = srslte_pss_synch_cfo_compute(&q->pss, &input[find_offset + peak_pos - q->fft_size]); - if (q->mean_cfo2_isunset) { - q->mean_cfo2 = cfo2; - q->mean_cfo2_isunset = true; + + // If there is enough space for CP and PSS-based CFO estimation + if (peak_pos + find_offset >= 2 * (q->fft_size + SRSLTE_CP_LEN_EXT(q->fft_size))) { + + // If SSS search is enabled, correlate SSS sequence + if (q->sss_en) { + + // Set an invalid N_id_1 indicating SSS is yet to be detected + q->N_id_1 = 1000; + + int sss_idx = find_offset + peak_pos - 2 * q->fft_size - + SRSLTE_CP_LEN(q->fft_size, (SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_NORM_LEN : SRSLTE_CP_EXT_LEN)); + + const cf_t *sss_ptr = &input_ptr[sss_idx]; + + // Correct CFO if detected in PSS + if (q->cfo_pss_enable) { + srslte_cfo_correct(&q->cfo_corr_symbol, sss_ptr, q->sss_filt, -q->cfo_pss_mean / q->fft_size); + sss_ptr = q->sss_filt; + } + + // Filter central bands before SSS estimation + if (q->sss_filtering_enabled) { + srslte_pss_synch_filter(&q->pss, sss_ptr, q->sss_filt); + sss_ptr = q->sss_filt; + } + + if (sync_sss_symbol(q, sss_ptr) < 0) { + fprintf(stderr, "Error correlating SSS\n"); + return -1; + } + } + + // Detect CP length + if (q->detect_cp) { + srslte_sync_set_cp(q, srslte_sync_detect_cp(q, input_ptr, peak_pos + find_offset)); } else { - q->mean_cfo2 = SRSLTE_VEC_EMA(cfo2, q->mean_cfo2, q->cfo_ema_alpha); + DEBUG("Not enough room to detect CP length. Peak position: %d\n", peak_pos); } ret = SRSLTE_SYNC_FOUND; } else { - ret = SRSLTE_SYNC_FOUND_NOSPACE; + ret = SRSLTE_SYNC_FOUND_NOSPACE; } } else { ret = SRSLTE_SYNC_NOFOUND; @@ -607,7 +670,7 @@ srslte_sync_find_ret_t srslte_sync_find(srslte_sync_t *q, cf_t *input, uint32_t DEBUG("SYNC ret=%d N_id_2=%d find_offset=%d frame_len=%d, pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f kHz\n", ret, q->N_id_2, find_offset, q->frame_size, peak_pos, q->peak_value, - q->threshold, q->sf_idx, 15*(q->cfo_i+q->mean_cfo)); + q->threshold, q->sf_idx, 15*(srslte_sync_get_cfo(q))); } else if (srslte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Must call srslte_sync_set_N_id_2() first!\n"); diff --git a/lib/src/phy/sync/test/pss_usrp.c b/lib/src/phy/sync/test/pss_usrp.c index 8e8377b83..7c22652f7 100644 --- a/lib/src/phy/sync/test/pss_usrp.c +++ b/lib/src/phy/sync/test/pss_usrp.c @@ -221,7 +221,9 @@ int main(int argc, char **argv) { uint32_t max_peak = 0; uint32_t max_peak_ = 0; uint32_t min_peak = fft_size; - uint32_t min_peak_ = fft_size; + uint32_t min_peak_ = fft_size; + + pss.filter_pss_enable = true; while(frame_cnt < nof_frames || nof_frames == -1) { n = srslte_rf_recv(&rf, buffer, flen - peak_offset, 1); @@ -243,7 +245,7 @@ int main(int argc, char **argv) { if (peak_idx >= fft_size) { - // Estimate CFO + // Estimate CFO cfo = srslte_pss_synch_cfo_compute(&pss, &buffer[peak_idx-fft_size]); mean_cfo = SRSLTE_VEC_CMA(cfo, mean_cfo, frame_cnt); @@ -255,10 +257,14 @@ int main(int argc, char **argv) { fprintf(stderr, "Error computing channel estimation\n"); exit(-1); } - - // Find SSS + + // Find SSS 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) { + + // Filter SSS + srslte_pss_synch_filter(&pss, &buffer[sss_idx], &buffer[sss_idx]); + INFO("Full N_id_1: %d\n", srslte_sss_synch_N_id_1(&sss, m0, m1)); srslte_sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, ce, &m0, &m0_value, &m1, &m1_value); if (srslte_sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { @@ -301,12 +307,12 @@ int main(int argc, char **argv) { } printf("[%5d]: Pos: %5d (%d-%d), PSR: %4.1f (~%4.1f) Pdet: %4.2f, " - "FA: %4.2f, CFO: %+4.1f kHz, SFO: %+.2f Hz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f%%\r", + "FA: %4.2f, CFO: %+7.1f Hz, SFO: %+.2f Hz SSSmiss: %4.2f/%4.2f/%4.2f CPNorm: %.0f%%\r", frame_cnt, peak_idx, min_peak_, max_peak_, peak_value, mean_peak, (float) nof_det/frame_cnt, - (float) nof_nopeakdet/frame_cnt, mean_cfo*15, sfo, + (float) nof_nopeakdet/frame_cnt, mean_cfo*15000, sfo, (float) sss_error1/nof_det,(float) sss_error2/nof_det,(float) sss_error3/nof_det, (float) cp_is_norm/nof_det * 100); diff --git a/lib/src/phy/sync/test/sync_test.c b/lib/src/phy/sync/test/sync_test.c index 1e3951884..9016c1baa 100644 --- a/lib/src/phy/sync/test/sync_test.c +++ b/lib/src/phy/sync/test/sync_test.c @@ -124,8 +124,7 @@ int main(int argc, char **argv) { /* Set a very high threshold to make sure the correlation is ok */ srslte_sync_set_threshold(&syncobj, 5.0); srslte_sync_set_sss_algorithm(&syncobj, SSS_PARTIAL_3); - srslte_sync_set_cfo_enable(&syncobj, false); - + if (cell_id == -1) { cid = 0; max_cid = 49; diff --git a/lib/src/phy/ue/ue_cell_search.c b/lib/src/phy/ue/ue_cell_search.c index dc35fb48c..133aad144 100644 --- a/lib/src/phy/ue/ue_cell_search.c +++ b/lib/src/phy/ue/ue_cell_search.c @@ -116,7 +116,7 @@ int srslte_ue_cellsearch_init_multi(srslte_ue_cellsearch_t * q, uint32_t max_fra goto clean_exit; } if (srslte_ue_sync_set_cell(&q->ue_sync, cell)) { - fprintf(stderr, "Error initiating ue_sync\n"); + fprintf(stderr, "Error setting cell in ue_sync\n"); goto clean_exit; } @@ -292,6 +292,8 @@ int srslte_ue_cellsearch_scan_N_id_2(srslte_ue_cellsearch_t * q, srslte_ue_sync_set_N_id_2(&q->ue_sync, N_id_2); srslte_ue_sync_reset(&q->ue_sync); + srslte_ue_sync_cfo_reset(&q->ue_sync); + do { ret = srslte_ue_sync_zerocopy_multi(&q->ue_sync, q->sf_buffer); diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 960d1de66..b6e0bd589 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -47,6 +47,9 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 +#define DEFAULT_CFO_BW 0.2 +#define DEFAULT_CFO_PSS_TOL 100 // typical accuracy of PSS estimation + cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -70,9 +73,10 @@ int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char * q->file_mode = true; q->sf_len = SRSLTE_SF_LEN(srslte_symbol_sz(nof_prb)); q->file_cfo = -offset_freq; - q->correct_cfo = true; q->fft_size = srslte_symbol_sz(nof_prb); q->nof_rx_antennas = nof_rx_ant; + + q->cfo_correct_enable = true; if (srslte_cfo_init(&q->file_cfo_correct, 2*q->sf_len)) { fprintf(stderr, "Error initiating CFO\n"); @@ -96,6 +100,7 @@ int srslte_ue_sync_init_file_multi(srslte_ue_sync_t *q, uint32_t nof_prb, char * free(file_offset_buffer); } + srslte_ue_sync_cfo_reset(q); srslte_ue_sync_reset(q); ret = SRSLTE_SUCCESS; @@ -107,6 +112,31 @@ clean_exit: return ret; } +void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q) +{ + q->cfo_current_value = 0; + srslte_sync_cfo_reset(&q->strack); + srslte_sync_cfo_reset(&q->sfind); +} + +void srslte_ue_sync_reset(srslte_ue_sync_t *q) { + + if (!q->file_mode) { + srslte_sync_reset(&q->sfind); + srslte_sync_reset(&q->strack); + } else { + q->sf_idx = 9; + } + q->state = SF_FIND; + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->mean_sample_offset = 0.0; + q->next_rf_sample_offset = 0; + q->frame_find_cnt = 0; +} + + int srslte_ue_sync_start_agc(srslte_ue_sync_t *q, double (set_gain_callback)(void*, double), float init_gain_value) { uint32_t nframes; if (q->nof_recv_sf == 1) { @@ -179,13 +209,16 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->fft_size = srslte_symbol_sz(max_prb); q->sf_len = SRSLTE_SF_LEN(q->fft_size); q->file_mode = false; - q->correct_cfo = true; - q->agc_period = 0; + q->agc_period = 0; q->sample_offset_correct_period = DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD; q->sfo_ema = DEFAULT_SFO_EMA_COEFF; q->max_prb = max_prb; + q->cfo_pss_tol = DEFAULT_CFO_PSS_TOL; + q->cfo_loop_bw = DEFAULT_CFO_BW; + q->cfo_correct_enable = true; + if (search_cell) { /* If the cell is unkown, we search PSS/SSS in 5 ms */ @@ -220,6 +253,29 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, } } + // Configure FIND and TRACK sync objects behaviour (this configuration is always the same) + srslte_sync_set_cfo_i_enable(&q->sfind, false); + srslte_sync_set_cfo_cp_enable(&q->sfind, true); + srslte_sync_set_cfo_pss_enable(&q->sfind, true); + srslte_sync_set_pss_filt_enable(&q->sfind, true); + srslte_sync_set_sss_filt_enable(&q->sfind, true); + + // During track, we do CFO correction outside the sync object + srslte_sync_set_cfo_i_enable(&q->strack, false); + srslte_sync_set_cfo_cp_enable(&q->strack, false); + srslte_sync_set_cfo_pss_enable(&q->strack, true); + srslte_sync_set_pss_filt_enable(&q->strack, true); + srslte_sync_set_sss_filt_enable(&q->strack, true); + + // FIXME: CP detection not working very well. Not supporting Extended CP right now + srslte_sync_cp_en(&q->strack, false); + srslte_sync_cp_en(&q->sfind, false); + + + srslte_sync_sss_en(&q->strack, true); + q->decode_sss_on_track = true; + + ret = SRSLTE_SUCCESS; } @@ -255,8 +311,6 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) if (q != NULL && srslte_nofprb_isvalid(cell.nof_prb)) { - ret = SRSLTE_ERROR; - if (cell.nof_prb > q->max_prb) { fprintf(stderr, "Error in ue_sync_set_cell(): cell.nof_prb must be lower than initialized\n"); return SRSLTE_ERROR; @@ -271,15 +325,10 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) /* If the cell is unkown, we search PSS/SSS in 5 ms */ q->nof_recv_sf = 5; - - q->decode_sss_on_track = true; - } else { /* If the cell is known, we work on a 1ms basis */ q->nof_recv_sf = 1; - - q->decode_sss_on_track = true; } q->frame_len = q->nof_recv_sf*q->sf_len; @@ -289,59 +338,51 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) } if(srslte_sync_resize(&q->sfind, q->frame_len, q->frame_len, q->fft_size)) { - fprintf(stderr, "Error initiating sync find\n"); + fprintf(stderr, "Error setting cell sync find\n"); return SRSLTE_ERROR; } if (cell.id == 1000) { if(srslte_sync_resize(&q->strack, q->frame_len, TRACK_FRAME_SIZE, q->fft_size)) { - fprintf(stderr, "Error initiating sync track\n"); + fprintf(stderr, "Error setting cell sync track\n"); return SRSLTE_ERROR; } } else { if(srslte_sync_resize(&q->strack, q->frame_len, SRSLTE_CP_LEN_NORM(1,q->fft_size), q->fft_size)) { - fprintf(stderr, "Error initiating sync track\n"); + fprintf(stderr, "Error setting cell sync track\n"); return SRSLTE_ERROR; } } if (cell.id == 1000) { - /* If the cell id is unknown, enable CP detection on find */ - // FIXME: CP detection not working very well. Not supporting Extended CP right now - srslte_sync_cp_en(&q->sfind, false); - srslte_sync_cp_en(&q->strack, false); + q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; - srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.8); + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.8); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); - srslte_sync_cfo_i_detec_en(&q->sfind, false); + srslte_sync_set_em_alpha(&q->sfind, 1); - q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; - srslte_sync_set_threshold(&q->sfind, 2.0); + srslte_sync_set_threshold(&q->sfind, 2.0); srslte_sync_set_threshold(&q->strack, 1.2); } else { - srslte_sync_set_N_id_2(&q->sfind, cell.id%3); - srslte_sync_set_N_id_2(&q->strack, cell.id%3); - q->sfind.cp = cell.cp; + q->sfind.cp = cell.cp; q->strack.cp = cell.cp; - srslte_sync_cp_en(&q->sfind, false); - srslte_sync_cp_en(&q->strack, false); - srslte_sync_cfo_i_detec_en(&q->sfind, false); + srslte_sync_set_N_id_2(&q->sfind, cell.id%3); + srslte_sync_set_N_id_2(&q->strack, cell.id%3); - srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); /* In find phase and if the cell is known, do not average pss correlation * because we only capture 1 subframe and do not know where the peak is. */ q->nof_avg_find_frames = 1; - srslte_sync_set_em_alpha(&q->sfind, 1); - srslte_sync_set_threshold(&q->sfind, 3.0); + srslte_sync_set_em_alpha(&q->sfind, 1); + srslte_sync_set_threshold(&q->sfind, 3.0); - srslte_sync_set_em_alpha(&q->strack, 0.2); + srslte_sync_set_em_alpha(&q->strack, 0.2); srslte_sync_set_threshold(&q->strack, 1.2); - } srslte_ue_sync_reset(q); @@ -357,34 +398,35 @@ void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t * memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t)); } -uint32_t srslte_ue_sync_peak_idx(srslte_ue_sync_t *q) { - return q->peak_idx; +void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw, float pss_tol) { + q->cfo_loop_bw = bw; + q->cfo_pss_tol = pss_tol; } void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { - srslte_sync_set_cfo_ema_alpha(&q->sfind, ema); + srslte_sync_set_cfo_ema_alpha(&q->sfind, ema); srslte_sync_set_cfo_ema_alpha(&q->strack, ema); } -srslte_ue_sync_state_t srslte_ue_sync_get_state(srslte_ue_sync_t *q) { - return q->state; -} uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q) { return q->sf_idx; } -void srslte_ue_sync_cfo_i_detec_en(srslte_ue_sync_t *q, bool enable) { - srslte_sync_cfo_i_detec_en(&q->strack, enable); - srslte_sync_cfo_i_detec_en(&q->sfind, enable); +void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q, bool enable) { + printf("Warning: Setting integer CFO detection/correction. This is experimental!\n"); + srslte_sync_set_cfo_i_enable(&q->strack, enable); + srslte_sync_set_cfo_i_enable(&q->sfind, enable); } float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) { - return 15000 * srslte_sync_get_cfo(&q->strack); + return 15000 * q->cfo_current_value; } -void srslte_ue_sync_set_cfo(srslte_ue_sync_t *q, float cfo) { - srslte_sync_set_cfo(&q->sfind, cfo/15000); - srslte_sync_set_cfo(&q->strack, cfo/15000); +void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, srslte_ue_sync_t *src_obj) { + // Copy find object internal CFO averages + srslte_sync_copy_cfo(&q->sfind, &src_obj->sfind); + // Current CFO is tracking-phase CFO of previous object + q->cfo_current_value = srslte_ue_sync_get_cfo(src_obj); } void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) {} @@ -406,7 +448,8 @@ void srslte_ue_sync_set_sfo_ema(srslte_ue_sync_t *q, float ema_coefficient) { } void srslte_ue_sync_decode_sss_on_track(srslte_ue_sync_t *q, bool enabled) { - q->decode_sss_on_track = enabled; + q->decode_sss_on_track = enabled; + srslte_sync_sss_en(&q->strack, q->decode_sss_on_track); } void srslte_ue_sync_set_N_id_2(srslte_ue_sync_t *q, uint32_t N_id_2) { @@ -434,7 +477,7 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS q->frame_find_cnt++; DEBUG("Found peak %d at %d, value %.3f, Cell_id: %d CP: %s\n", q->frame_find_cnt, q->peak_idx, - srslte_sync_get_last_peak_value(&q->sfind), q->cell.id, srslte_cp_string(q->cell.cp)); + srslte_sync_get_peak_value(&q->sfind), q->cell.id, srslte_cp_string(q->cell.cp)); if (q->frame_find_cnt >= q->nof_avg_find_frames || q->peak_idx < 2*q->fft_size) { INFO("Realigning frame, reading %d samples\n", q->peak_idx+q->sf_len/2); @@ -453,9 +496,9 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS /* Goto Tracking state */ q->state = SF_TRACK; - /* Initialize track state CFO */ - q->strack.mean_cfo = q->sfind.mean_cfo; - q->strack.cfo_i = q->sfind.cfo_i; + /* Set CFO values. Since we correct before track, the initial track state is CFO=0 Hz */ + q->cfo_current_value = srslte_sync_get_cfo(&q->sfind); + srslte_sync_cfo_reset(&q->strack); } return 0; @@ -491,6 +534,14 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { q->mean_sample_offset = q->last_sample_offset; } + /* Adjust current CFO estimation with PSS + * Since sync track has enabled only PSS-based correlation, get_cfo() returns that value only, already filtered. + */ + INFO("TRACK: cfo_current: %f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack)); + if (abs(srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw) > q->cfo_pss_tol) { + q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw; + } + // Compute cumulative moving average time offset */ if (!frame_idx) { // Adjust RF sampling time based on the mean sampling offset @@ -543,13 +594,7 @@ static int track_peak_no(srslte_ue_sync_t *q) { return 0; } else { INFO("Tracking peak not found. Peak %.3f, %d lost\n", - srslte_sync_get_last_peak_value(&q->strack), (int) q->frame_no_cnt); - /* - printf("Saving files: pss_corr (%d), input (%d)\n", q->strack.pss.frame_size, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); - srslte_vec_save_file("pss_corr", q->strack.pss.conv_output_avg, q->strack.pss.frame_size*sizeof(float)); - srslte_vec_save_file("input", q->input_buffer, SRSLTE_SF_LEN_PRB(q->cell.nof_prb)*sizeof(cf_t)); - exit(-1); - */ + srslte_sync_get_peak_value(&q->strack), (int) q->frame_no_cnt); return 1; } @@ -578,12 +623,10 @@ static int receive_samples(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PO return SRSLTE_SUCCESS; } -bool first_track = true; - int srslte_ue_sync_zerocopy(srslte_ue_sync_t *q, cf_t *input_buffer) { - cf_t *_input_buffer[SRSLTE_MAX_PORTS]; - _input_buffer[0] = input_buffer; - return srslte_ue_sync_zerocopy_multi(q, _input_buffer); + cf_t *_input_buffer[SRSLTE_MAX_PORTS]; + _input_buffer[0] = input_buffer; + return srslte_ue_sync_zerocopy_multi(q, _input_buffer); } /* Returns 1 if the subframe is synchronized in time, 0 otherwise */ @@ -610,7 +653,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE return SRSLTE_ERROR; } } - if (q->correct_cfo) { + if (q->cfo_correct_enable) { for (int i = 0; i < q->nof_rx_antennas; i++) { srslte_cfo_correct(&q->file_cfo_correct, input_buffer[i], @@ -625,13 +668,14 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE INFO("Reading %d samples. sf_idx = %d\n", q->sf_len, q->sf_idx); ret = 1; } else { + if (receive_samples(q, input_buffer)) { fprintf(stderr, "Error receiving samples\n"); return SRSLTE_ERROR; } switch (q->state) { - case SF_FIND: + case SF_FIND: switch(srslte_sync_find(&q->sfind, input_buffer[0], 0, &q->peak_idx)) { case SRSLTE_SYNC_ERROR: ret = SRSLTE_ERROR; @@ -659,37 +703,39 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE case SF_TRACK: ret = 1; - - srslte_sync_sss_en(&q->strack, q->decode_sss_on_track); - + + // Increase subframe counter q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; - /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ - if (q->sf_idx == 0 || q->sf_idx == 5) { + // Correct CFO before PSS/SSS tracking using the sync object corrector (initialized for 1 ms) + if (q->cfo_correct_enable) { + for (int i=0;inof_rx_antennas;i++) { + srslte_cfo_correct(&q->strack.cfo_corr_frame, + input_buffer[i], + input_buffer[i], + -q->cfo_current_value/q->fft_size); + } + } + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx == 0 || q->sf_idx == 5) + { + // Process AGC every period if (q->do_agc && (q->agc_period == 0 || (q->agc_period && (q->frame_total_cnt%q->agc_period) == 0))) { srslte_agc_process(&q->agc, input_buffer[0], q->sf_len); } - #ifdef MEASURE_EXEC_TIME - struct timeval t[3]; - gettimeofday(&t[1], NULL); - #endif - - track_idx = 0; - - /* Track PSS/SSS around the expected PSS position + /* Track PSS/SSS around the expected PSS position * In tracking phase, the subframe carrying the PSS is always the last one of the frame */ - + track_idx = 0; switch(srslte_sync_find(&q->strack, input_buffer[0], q->frame_len - q->sf_len/2 - q->fft_size - q->strack.max_offset/2, &track_idx)) { case SRSLTE_SYNC_ERROR: - ret = SRSLTE_ERROR; fprintf(stderr, "Error tracking correlation peak\n"); return SRSLTE_ERROR; case SRSLTE_SYNC_FOUND: @@ -699,19 +745,13 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE // It's very very unlikely that we fall here because this event should happen at FIND phase only ret = 0; q->state = SF_FIND; - printf("Warning: No space for SSS/CP while in tracking phase\n"); + INFO("Warning: No space for SSS/CP while in tracking phase\n"); break; case SRSLTE_SYNC_NOFOUND: ret = track_peak_no(q); break; } - #ifdef MEASURE_EXEC_TIME - gettimeofday(&t[2], NULL); - get_time_interval(t); - q->mean_exec_time = (float) SRSLTE_VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); - #endif - if (ret == SRSLTE_ERROR) { fprintf(stderr, "Error processing tracking peak\n"); q->state = SF_FIND; @@ -719,40 +759,12 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE } q->frame_total_cnt++; - } - if (q->correct_cfo) { - for (int i=0;inof_rx_antennas;i++) { - srslte_cfo_correct(&q->strack.cfocorr, - input_buffer[i], - input_buffer[i], - -srslte_sync_get_cfo(&q->strack) / q->fft_size); - } - } + } break; } - } } return ret; } -void srslte_ue_sync_reset(srslte_ue_sync_t *q) { - - if (!q->file_mode) { - srslte_sync_reset(&q->sfind); - srslte_sync_reset(&q->strack); - } else { - q->sf_idx = 9; - } - q->state = SF_FIND; - q->frame_ok_cnt = 0; - q->frame_no_cnt = 0; - q->frame_total_cnt = 0; - q->mean_sample_offset = 0.0; - q->next_rf_sample_offset = 0; - q->frame_find_cnt = 0; - #ifdef MEASURE_EXEC_TIME - q->mean_exec_time = 0; - #endif -} diff --git a/lib/src/phy/utils/convolution.c b/lib/src/phy/utils/convolution.c index f96bdd4a2..59807ad5b 100644 --- a/lib/src/phy/utils/convolution.c +++ b/lib/src/phy/utils/convolution.c @@ -115,7 +115,7 @@ void srslte_conv_fft_cc_free(srslte_conv_fft_cc_t *q) { } -uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter_freq, cf_t *output) +uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, const cf_t *input, const cf_t *filter_freq, cf_t *output) { srslte_dft_run_c(&q->input_plan, input, q->input_fft); srslte_vec_prod_ccc(q->input_fft, filter_freq, q->output_fft, q->output_len); @@ -125,7 +125,7 @@ uint32_t srslte_conv_fft_cc_run_opt(srslte_conv_fft_cc_t *q, cf_t *input, cf_t * } -uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { +uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, const cf_t *input, const cf_t *filter, cf_t *output) { srslte_dft_run_c(&q->filter_plan, filter, q->filter_fft); @@ -133,7 +133,7 @@ uint32_t srslte_conv_fft_cc_run(srslte_conv_fft_cc_t *q, cf_t *input, cf_t *filt } -uint32_t srslte_conv_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { +uint32_t srslte_conv_cc(const cf_t *input, const cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { uint32_t i; uint32_t M = filter_len; uint32_t N = input_len; diff --git a/lib/src/phy/utils/test/vector_test.c b/lib/src/phy/utils/test/vector_test.c index a717a7537..cb7eff480 100644 --- a/lib/src/phy/utils/test/vector_test.c +++ b/lib/src/phy/utils/test/vector_test.c @@ -441,7 +441,7 @@ TEST(srslte_vec_convert_fi, x[i] = (float) RANDOM_F(); } - TEST_CALL(srslte_vec_convert_fi(x, z, scale, block_size)) + TEST_CALL(srslte_vec_convert_fi(x, scale, z, block_size)) for (int i = 0; i < block_size; i++) { gold = (short) ((x[i] * scale)); diff --git a/lib/src/phy/utils/vector.c b/lib/src/phy/utils/vector.c index 5d5b6747a..35457fcb5 100644 --- a/lib/src/phy/utils/vector.c +++ b/lib/src/phy/utils/vector.c @@ -37,79 +37,73 @@ -void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, uint32_t len) { +void srslte_vec_xor_bbb(int8_t *x,int8_t *y,int8_t *z, const uint32_t len) { srslte_vec_xor_bbb_simd(x, y, z, len); } // Used in PRACH detector, AGC and chest_dl for noise averaging -float srslte_vec_acc_ff(float *x, uint32_t len) { +float srslte_vec_acc_ff(const float *x, const uint32_t len) { return srslte_vec_acc_ff_simd(x, len); } -void srslte_vec_ema_filter(cf_t *new_data, cf_t *average, cf_t *output, float coeff, uint32_t len) { - srslte_vec_sc_prod_cfc(new_data, coeff, new_data, len); - srslte_vec_sc_prod_cfc(average, 1-coeff, output, len); - srslte_vec_sum_ccc(output, new_data, output, len); -} - -cf_t srslte_vec_acc_cc(cf_t *x, uint32_t len) { +cf_t srslte_vec_acc_cc(const cf_t *x, const uint32_t len) { return srslte_vec_acc_cc_simd(x, len); } -void srslte_vec_sub_fff(float *x, float *y, float *z, uint32_t len) { +void srslte_vec_sub_fff(const float *x, const float *y, float *z, const uint32_t len) { srslte_vec_sub_fff_simd(x, y, z, len); } -void srslte_vec_sub_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len) { +void srslte_vec_sub_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len) { srslte_vec_sub_sss_simd(x, y, z, len); } // Noise estimation in chest_dl, interpolation -void srslte_vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) { - return srslte_vec_sub_fff((float*) x,(float*) y,(float*) z, 2*len); +void srslte_vec_sub_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) { + return srslte_vec_sub_fff((const float*) x,(const float*) y,(float*) z, 2*len); } // Used in PSS/SSS and sum_ccc -void srslte_vec_sum_fff(float *x, float *y, float *z, uint32_t len) { +void srslte_vec_sum_fff(const float *x, const float *y, float *z, const uint32_t len) { srslte_vec_add_fff_simd(x, y, z, len); } -void srslte_vec_sum_sss(int16_t *x, int16_t *y, int16_t *z, uint32_t len) { +void srslte_vec_sum_sss(const int16_t *x, const int16_t *y, int16_t *z, const uint32_t len) { srslte_vec_sum_sss_simd(x, y, z, len); } -void srslte_vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) { +void srslte_vec_sum_ccc(const cf_t *x, const cf_t *y, cf_t *z, const uint32_t len) { srslte_vec_sum_fff((float*) x,(float*) y,(float*) z,2*len); } // PSS, PBCH, DEMOD, FFTW, etc. -void srslte_vec_sc_prod_fff(float *x, float h, float *z, uint32_t len) { +void srslte_vec_sc_prod_fff(const float *x, const float h, float *z, const uint32_t len) { srslte_vec_sc_prod_fff_simd(x, h, z, len); } // Used throughout -void srslte_vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len) { +void srslte_vec_sc_prod_cfc(const const cf_t *x, const float h, cf_t *z, const uint32_t len) { srslte_vec_sc_prod_cfc_simd(x,h,z,len); } // Chest UL -void srslte_vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) { +void srslte_vec_sc_prod_ccc(const cf_t *x, const cf_t h, cf_t *z, const uint32_t len) { srslte_vec_sc_prod_ccc_simd(x,h,z,len); } // Used in turbo decoder -void srslte_vec_convert_if(int16_t *x, float *z, float scale, uint32_t len) { +void srslte_vec_convert_if(const int16_t *x, const float scale, float *z, const uint32_t len) { int i; for (i=0;iargs->cfo_integer_enabled) { - srslte_ue_sync_cfo_i_detec_en(q, true); + srslte_ue_sync_set_cfo_i_enable(q, true); } srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_ema); @@ -328,7 +328,7 @@ int phch_recv::cell_search(int force_N_id_2) { } srslte_ue_sync_reset(&ue_mib_sync.ue_sync); - srslte_ue_sync_set_cfo(&ue_mib_sync.ue_sync, cellsearch_cfo); + srslte_ue_sync_copy_cfo(&ue_mib_sync.ue_sync, &cs.ue_sync); /* Find and decode MIB */ int sfn_offset; @@ -340,7 +340,7 @@ int phch_recv::cell_search(int force_N_id_2) { cellsearch_cfo = srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync); srslte_ue_sync_reset(&ue_sync); - srslte_ue_sync_set_cfo(&ue_sync, cellsearch_cfo); + srslte_ue_sync_copy_cfo(&ue_sync, &ue_mib_sync.ue_sync); if (ret == 1) { srslte_pbch_mib_unpack(bch_payload, &cell, NULL); From 6e0c24c7eed9c8ccfc24aecdf329c0e5aebf8367 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 29 Nov 2017 18:54:45 +0100 Subject: [PATCH 18/22] Fixed feedback loop in CFO correction --- lib/src/phy/ue/ue_sync.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index b6e0bd589..dfd609e8f 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -47,8 +47,8 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 -#define DEFAULT_CFO_BW 0.2 -#define DEFAULT_CFO_PSS_TOL 100 // typical accuracy of PSS estimation +#define DEFAULT_CFO_BW 0.7 +#define DEFAULT_CFO_PSS_TOL 80 // typical accuracy of PSS estimation cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -538,7 +538,7 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { * Since sync track has enabled only PSS-based correlation, get_cfo() returns that value only, already filtered. */ INFO("TRACK: cfo_current: %f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack)); - if (abs(srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw) > q->cfo_pss_tol) { + if (15000*fabsf(srslte_sync_get_cfo(&q->strack)) > q->cfo_pss_tol) { q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw; } From 46f15c19e62c5458c5eddd01307b79f50f4207b5 Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Wed, 29 Nov 2017 20:28:04 +0100 Subject: [PATCH 19/22] Added subframe averaging option in chest_dl. Optional in pdsch_ue --- lib/examples/pdsch_ue.c | 34 +++++- .../srslte/phy/ch_estimation/chest_dl.h | 15 ++- lib/include/srslte/phy/ue/ue_sync.h | 8 +- lib/src/phy/ch_estimation/chest_dl.c | 112 ++++++++++++------ lib/src/phy/ue/ue_sync.c | 17 ++- 5 files changed, 137 insertions(+), 49 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index e15aa473f..acc598296 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -90,6 +90,8 @@ typedef struct { uint32_t file_nof_prb; uint32_t file_nof_ports; uint32_t file_cell_id; + bool enable_cfo_ref; + bool average_subframe; char *rf_args; uint32_t rf_nof_rx_ant; double rf_freq; @@ -120,7 +122,9 @@ void args_default(prog_args_t *args) { args->file_offset_freq = 0; args->rf_args = ""; args->rf_freq = -1.0; - args->rf_nof_rx_ant = 1; + args->rf_nof_rx_ant = 1; + args->enable_cfo_ref = false; + args->average_subframe = false; #ifdef ENABLE_AGC_DEFAULT args->rf_gain = -1.0; #else @@ -137,7 +141,7 @@ void args_default(prog_args_t *args) { } void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [agpPoOcildDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); + printf("Usage: %s [agpPoOcildFRDnruMNv] -f rx_frequency (in Hz) | -i input_file\n", prog); #ifndef DISABLE_RF printf("\t-a RF args [Default %s]\n", args->rf_args); printf("\t-A Number of RX antennas [Default %d]\n", args->rf_nof_rx_ant); @@ -158,6 +162,8 @@ void usage(prog_args_t *args, char *prog) { printf("\t-r RNTI in Hex [Default 0x%x]\n",args->rnti); printf("\t-l Force N_id_2 [Default best]\n"); printf("\t-C Disable CFO correction [Default %s]\n", args->disable_cfo?"Disabled":"Enabled"); + printf("\t-F Enable RS-based CFO correction [Default %s]\n", args->enable_cfo_ref?"Disabled":"Enabled"); + printf("\t-R Average channel estimates on 1 ms [Default %s]\n", args->average_subframe?"Disabled":"Enabled"); printf("\t-t Add time offset [Default %d]\n", args->time_offset); #ifndef DISABLE_GRAPHICS printf("\t-d disable plots [Default enabled]\n"); @@ -179,7 +185,7 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "aAoglipPcOCtdDnvrfuUsSZyWMN")) != -1) { + while ((opt = getopt(argc, argv, "aAoglipPcOCtdDFRnvrfuUsSZyWMN")) != -1) { switch (opt) { case 'i': args->input_file_name = argv[optind]; @@ -211,6 +217,12 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'C': args->disable_cfo = true; break; + case 'F': + args->enable_cfo_ref = true; + break; + case 'R': + args->average_subframe = true; + break; case 't': args->time_offset = atoi(argv[optind]); break; @@ -533,7 +545,10 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating UE downlink processing module\n"); exit(-1); } - + + srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 0xff, 0.1); + srslte_chest_dl_average_subframe(&ue_dl.chest, prog_args.average_subframe); + /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ srslte_ue_dl_set_rnti(&ue_dl, prog_args.rnti); @@ -655,6 +670,7 @@ int main(int argc, char **argv) { decode_pdsch = false; } } + gettimeofday(&t[1], NULL); if (decode_pdsch) { if(sfidx != 1 || prog_args.mbsfn_area_id < 0){ // Not an MBSFN subframe @@ -677,6 +693,12 @@ int main(int argc, char **argv) { } } } + + // Feed-back ue_sync with chest_dl CFO estimation + if (sfidx == 5 && prog_args.enable_cfo_ref) { + srslte_ue_sync_set_cfo_ref(&ue_sync, srslte_chest_dl_get_cfo(&ue_dl.chest)); + } + }else{ // MBSFN subframe n = srslte_ue_dl_decode_mbsfn(&ue_dl, sf_buffer, @@ -773,7 +795,7 @@ int main(int argc, char **argv) { /* Print basic Parameters */ PRINT_LINE(" nof layers: %d", ue_dl.pdsch_cfg.nof_layers); PRINT_LINE("nof codewords: %d", SRSLTE_RA_DL_GRANT_NOF_TB(&ue_dl.pdsch_cfg.grant)); - PRINT_LINE(" CFO: %+7.2f kHz", srslte_ue_sync_get_cfo(&ue_sync)); + PRINT_LINE(" CFO: %+7.2f Hz", srslte_ue_sync_get_cfo(&ue_sync)); PRINT_LINE(" SNR: %+5.1f dB | %+5.1f dB", 10 * log10(rsrp0 / noise), 10 * log10(rsrp1 / noise)); PRINT_LINE(" Rb: %6.2f / %6.2f / %6.2f Mbps (net/maximum/processing)", uerate, enodebrate, procrate); PRINT_LINE(" PDCCH-Miss: %5.2f%%", 100 * (1 - (float) ue_dl.nof_detected / nof_trials)); @@ -973,7 +995,7 @@ void *plot_thread_run(void *arg) { tmp_plot2[g+i] = -80; } } - plot_real_setNewData(&pce, tmp_plot2, sz); + plot_real_setNewData(&pce, tmp_plot2, sz); if (!prog_args.input_file_name) { if (plot_track) { diff --git a/lib/include/srslte/phy/ch_estimation/chest_dl.h b/lib/include/srslte/phy/ch_estimation/chest_dl.h index 229495a9b..91fda41e4 100644 --- a/lib/include/srslte/phy/ch_estimation/chest_dl.h +++ b/lib/include/srslte/phy/ch_estimation/chest_dl.h @@ -68,7 +68,8 @@ typedef struct { cf_t *pilot_estimates_average; cf_t *pilot_recv_signal; cf_t *tmp_noise; - + cf_t *tmp_cfo_estimate; + #ifdef FREQ_SEL_SNR float snr_vector[12000]; float pilot_power[12000]; @@ -84,8 +85,9 @@ typedef struct { float noise_estimate[SRSLTE_MAX_PORTS][SRSLTE_MAX_PORTS]; float cfo; - bool cfo_estimate_enable; + bool cfo_estimate_enable; uint32_t cfo_estimate_sf_mask; + float cfo_ema; /* Use PSS for noise estimation in LS linear interpolation mode */ cf_t pss_signal[SRSLTE_PSS_LEN]; @@ -95,6 +97,7 @@ typedef struct { srslte_chest_dl_noise_alg_t noise_alg; int last_nof_antennas; + bool average_subframe; } srslte_chest_dl_t; @@ -148,7 +151,13 @@ SRSLTE_API int srslte_chest_dl_estimate_port(srslte_chest_dl_t *q, uint32_t port_id, uint32_t rxant_id); -SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask); +SRSLTE_API void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, + bool enable, + uint32_t mask, + float ema); + +SRSLTE_API void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, + bool enable); SRSLTE_API float srslte_chest_dl_get_noise_estimate(srslte_chest_dl_t *q); diff --git a/lib/include/srslte/phy/ue/ue_sync.h b/lib/include/srslte/phy/ue/ue_sync.h index 11d7893c8..3619156f7 100644 --- a/lib/include/srslte/phy/ue/ue_sync.h +++ b/lib/include/srslte/phy/ue/ue_sync.h @@ -115,6 +115,8 @@ typedef struct SRSLTE_API { float cfo_current_value; float cfo_loop_bw; float cfo_pss_tol; + float cfo_ref_tol; + float cfo_ref_max; uint32_t peak_idx; int next_rf_sample_offset; @@ -197,11 +199,15 @@ SRSLTE_API void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, SRSLTE_API void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw, - float pss_tol); + float pss_tol, + float ref_tol, + float ref_max); SRSLTE_API void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema); +SRSLTE_API void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float res_cfo); + SRSLTE_API void srslte_ue_sync_set_cfo_i_enable(srslte_ue_sync_t *q, bool enable); diff --git a/lib/src/phy/ch_estimation/chest_dl.c b/lib/src/phy/ch_estimation/chest_dl.c index 60d62a004..e04d30e69 100644 --- a/lib/src/phy/ch_estimation/chest_dl.c +++ b/lib/src/phy/ch_estimation/chest_dl.c @@ -102,25 +102,30 @@ int srslte_chest_dl_init(srslte_chest_dl_t *q, uint32_t max_prb) } q->tmp_noise = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); - - if (!q->tmp_noise) { perror("malloc"); goto clean_exit; } - q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + q->tmp_cfo_estimate = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + if (!q->tmp_cfo_estimate) { + perror("malloc"); + goto clean_exit; + } + + q->pilot_estimates = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_estimates) { perror("malloc"); goto clean_exit; } + q->pilot_estimates_average = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_estimates_average) { perror("malloc"); goto clean_exit; - } - q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); + } + q->pilot_recv_signal = srslte_vec_malloc(sizeof(cf_t) * pilot_vec_size); if (!q->pilot_recv_signal) { perror("malloc"); goto clean_exit; @@ -175,6 +180,9 @@ void srslte_chest_dl_free(srslte_chest_dl_t *q) if (q->tmp_noise) { free(q->tmp_noise); } + if (q->tmp_cfo_estimate) { + free(q->tmp_cfo_estimate); + } srslte_interp_linear_vector_free(&q->srslte_interp_linvec); srslte_interp_linear_free(&q->srslte_interp_lin); srslte_interp_linear_free(&q->srslte_interp_lin_mbsfn); @@ -241,6 +249,10 @@ static float estimate_noise_pilots(srslte_chest_dl_t *q, uint32_t port_id) { int nref=SRSLTE_REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); + if (q->average_subframe) { + nref /= 4; + } + /* Substract noisy pilot estimates */ srslte_vec_sub_ccc(q->pilot_estimates_average, q->pilot_estimates, q->tmp_noise, nref); @@ -305,9 +317,13 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t uint32_t nsymbols = (ch_mode == SRSLTE_SF_MBSFN ) ? srslte_refsignal_mbsfn_nof_symbols() + 1 : srslte_refsignal_cs_nof_symbols(port_id); uint32_t fidx_offset = 0; /* Interpolate in the frequency domain */ - + + if (q->average_subframe) { + nsymbols = 1; + } + // we add one to nsymbols to allow for inclusion of the non-mbms references in the channel estimation - for (l=0;l<(nsymbols);l++) { + for (l=0;lcell, l, port_id, 0); @@ -329,34 +345,41 @@ static void interpolate_pilots(srslte_chest_dl_t *q, cf_t *pilot_estimates, cf_t } /* Now interpolate in the time domain between symbols */ - if (ch_mode == SRSLTE_SF_MBSFN) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); - } else { - if (SRSLTE_CP_ISNORM(q->cell.cp)) { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); - } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); - } + if (q->average_subframe) { + // If we average per subframe, just copy the estimates in the time domain + for (l=0;l<2*SRSLTE_CP_NSYMB(q->cell.cp);l++) { + memcpy(&ce[l*SRSLTE_NRE*q->cell.nof_prb], ce, sizeof(cf_t)*SRSLTE_NRE*q->cell.nof_prb); + } + } else { + if (ch_mode == SRSLTE_SF_MBSFN) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(2), &cesymb(1), 2, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(2), &cesymb(6), &cesymb(3), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(7), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(10), &cesymb(10), &cesymb(11), 4, 1); } else { - if (nsymbols == 4) { - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + if (SRSLTE_CP_ISNORM(q->cell.cp)) { + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 4, 3); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 4, 3); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(11), &cesymb(11), &cesymb(12), 4, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(8), &cesymb(1), &cesymb(1), &cesymb(0), 7, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 7, 6); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 7, 5); + } } else { - srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); - srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); - } + if (nsymbols == 4) { + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 3, 2); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 3, 2); + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), &cesymb(10), 3, 2); + } else { + srslte_interp_linear_vector2(&q->srslte_interp_linvec, &cesymb(7), &cesymb(1), &cesymb(1), &cesymb(0), 6, 1); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 6, 5); + srslte_interp_linear_vector(&q->srslte_interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 6, 4); + } + } } } } @@ -392,6 +415,15 @@ static void average_pilots(srslte_chest_dl_t *q, cf_t *input, cf_t *output, uint 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; + // Average in the time domain if enabled + if (q->average_subframe) { + for (int l=1;lsmooth_filter, &output[l*nref], nref, q->smooth_filter_len); @@ -424,11 +456,11 @@ float chest_estimate_cfo(srslte_chest_dl_t *q) for (int i=0;i<2;i++) { srslte_vec_prod_conj_ccc(&q->pilot_estimates[i*npilots/4], &q->pilot_estimates[(i+2)*npilots/4], - &q->tmp_noise[i*npilots/4], + &q->tmp_cfo_estimate[i*npilots/4], npilots/4); } // Average all angles - cf_t sum = srslte_vec_acc_cc(q->tmp_noise, npilots/2); + cf_t sum = srslte_vec_acc_cc(q->tmp_cfo_estimate, npilots/2); // Compute CFO return -cargf(sum)*n/(ns*(n+ng))/2/M_PI; @@ -459,7 +491,7 @@ void chest_interpolate_noise_est(srslte_chest_dl_t *q, cf_t *input, cf_t *ce, ui } if (q->cfo_estimate_enable && ((1<cfo_estimate_sf_mask)) { - q->cfo = chest_estimate_cfo(q); + q->cfo = SRSLTE_VEC_EMA(chest_estimate_cfo(q), q->cfo, q->cfo_ema); } /* Compute RSRP for the channel estimates in this port */ @@ -542,8 +574,14 @@ int srslte_chest_dl_estimate_multi_mbsfn(srslte_chest_dl_t *q, cf_t *input[SRSLT return SRSLTE_SUCCESS; } -void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask) +void srslte_chest_dl_average_subframe(srslte_chest_dl_t *q, bool enable) +{ + q->average_subframe = enable; +} + +void srslte_chest_dl_cfo_estimate_enable(srslte_chest_dl_t *q, bool enable, uint32_t mask, float ema) { + q->cfo_ema = ema; q->cfo_estimate_enable = enable; q->cfo_estimate_sf_mask = mask; } diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index dfd609e8f..58489b92b 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -48,7 +48,9 @@ #define DEFAULT_SFO_EMA_COEFF 0.1 #define DEFAULT_CFO_BW 0.7 -#define DEFAULT_CFO_PSS_TOL 80 // typical accuracy of PSS estimation +#define DEFAULT_CFO_PSS_TOL 80 // typical accuracy of PSS estimation. Avoids ping-pong effect +#define DEFAULT_CFO_REF_TOL 5 // typical accuracy of REF estimation +#define DEFAULT_CFO_REF_MAX 300 // Maximum detection offset of REF based estimation cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -215,6 +217,8 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->max_prb = max_prb; + q->cfo_ref_max = DEFAULT_CFO_REF_MAX; + q->cfo_ref_tol = DEFAULT_CFO_REF_TOL; q->cfo_pss_tol = DEFAULT_CFO_PSS_TOL; q->cfo_loop_bw = DEFAULT_CFO_BW; q->cfo_correct_enable = true; @@ -398,9 +402,11 @@ void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t * memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t)); } -void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw, float pss_tol) { +void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw, float pss_tol, float ref_tol, float ref_max) { q->cfo_loop_bw = bw; q->cfo_pss_tol = pss_tol; + q->cfo_ref_tol = ref_tol; + q->cfo_ref_max = ref_max; } void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { @@ -408,6 +414,13 @@ void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { srslte_sync_set_cfo_ema_alpha(&q->strack, ema); } +void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float ref_cfo) +{ + if (fabsf(ref_cfo)*15000 > q->cfo_ref_tol && fabsf(ref_cfo)*15000 < q->cfo_ref_max) { + q->cfo_current_value += ref_cfo*q->cfo_loop_bw; + } +} + uint32_t srslte_ue_sync_get_sfidx(srslte_ue_sync_t *q) { return q->sf_idx; } From dd8bacf46683e853830fac5d2e0692a0cd5e243d Mon Sep 17 00:00:00 2001 From: Ismael Gomez Date: Thu, 30 Nov 2017 20:01:35 +0100 Subject: [PATCH 20/22] Calibrated CFO loop default values --- lib/examples/pdsch_ue.c | 10 +- lib/include/srslte/interfaces/ue_interfaces.h | 10 +- lib/include/srslte/phy/ue/ue_sync.h | 18 +- lib/src/phy/sync/sync.c | 2 +- lib/src/phy/ue/ue_sync.c | 97 ++++--- lib/src/phy/ue/ue_ul.c | 2 +- srsue/hdr/phy/phch_common.h | 255 +++++++++--------- srsue/hdr/phy/phch_recv.h | 5 +- srsue/hdr/phy/phch_worker.h | 5 +- srsue/src/main.cc | 45 +++- srsue/src/phy/phch_recv.cc | 23 +- srsue/src/phy/phch_worker.cc | 39 ++- srsue/src/phy/phy.cc | 3 +- srsue/ue.conf.example | 42 ++- 14 files changed, 353 insertions(+), 203 deletions(-) diff --git a/lib/examples/pdsch_ue.c b/lib/examples/pdsch_ue.c index acc598296..b62ae263e 100644 --- a/lib/examples/pdsch_ue.c +++ b/lib/examples/pdsch_ue.c @@ -546,7 +546,7 @@ int main(int argc, char **argv) { exit(-1); } - srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 0xff, 0.1); + srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, prog_args.enable_cfo_ref, 0xff, 0.005); srslte_chest_dl_average_subframe(&ue_dl.chest, prog_args.average_subframe); /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ @@ -959,7 +959,7 @@ void *plot_thread_run(void *arg) { plot_real_init(&pce); plot_real_setTitle(&pce, "Channel Response - Magnitude"); plot_real_setLabels(&pce, "Index", "dB"); - plot_real_setYAxisScale(&pce, -40, 40); + plot_real_setYAxisScale(&pce, -M_PI, M_PI); plot_real_init(&p_sync); plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value"); @@ -995,7 +995,11 @@ void *plot_thread_run(void *arg) { tmp_plot2[g+i] = -80; } } - plot_real_setNewData(&pce, tmp_plot2, sz); + uint32_t nrefs = 2*ue_dl.cell.nof_prb; + for (i=0;i= SRSLTE_SYNC_FFT_SZ_MIN && fft_size <= SRSLTE_SYNC_FFT_SZ_MAX && (fft_size%64) == 0) { diff --git a/lib/src/phy/ue/ue_sync.c b/lib/src/phy/ue/ue_sync.c index 58489b92b..b5d89743f 100644 --- a/lib/src/phy/ue/ue_sync.c +++ b/lib/src/phy/ue/ue_sync.c @@ -47,10 +47,14 @@ #define DEFAULT_SAMPLE_OFFSET_CORRECT_PERIOD 0 #define DEFAULT_SFO_EMA_COEFF 0.1 -#define DEFAULT_CFO_BW 0.7 -#define DEFAULT_CFO_PSS_TOL 80 // typical accuracy of PSS estimation. Avoids ping-pong effect -#define DEFAULT_CFO_REF_TOL 5 // typical accuracy of REF estimation -#define DEFAULT_CFO_REF_MAX 300 // Maximum detection offset of REF based estimation +#define DEFAULT_CFO_BW 0.2 +#define DEFAULT_CFO_PSS_MIN 500 // typical bias of PSS estimation. +#define DEFAULT_CFO_REF_MIN 0 // typical bias of REF estimation +#define DEFAULT_CFO_REF_MAX 500 // Maximum detection offset of REF based estimation + +#define DEFAULT_PSS_STABLE_TIMEOUT 100 // Time after which the PSS is considered to be stable and we accept REF-CFO + +#define DEFAULT_CFO_EMA_TRACK 0.1 cf_t dummy_buffer0[15*2048/2]; cf_t dummy_buffer1[15*2048/2]; @@ -116,6 +120,7 @@ clean_exit: void srslte_ue_sync_cfo_reset(srslte_ue_sync_t *q) { + q->cfo_is_copied = false; q->cfo_current_value = 0; srslte_sync_cfo_reset(&q->strack); srslte_sync_cfo_reset(&q->sfind); @@ -129,6 +134,7 @@ void srslte_ue_sync_reset(srslte_ue_sync_t *q) { } else { q->sf_idx = 9; } + q->pss_stable_timeout = false; q->state = SF_FIND; q->frame_ok_cnt = 0; q->frame_no_cnt = 0; @@ -218,11 +224,15 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, q->max_prb = max_prb; q->cfo_ref_max = DEFAULT_CFO_REF_MAX; - q->cfo_ref_tol = DEFAULT_CFO_REF_TOL; - q->cfo_pss_tol = DEFAULT_CFO_PSS_TOL; - q->cfo_loop_bw = DEFAULT_CFO_BW; + q->cfo_ref_min = DEFAULT_CFO_REF_MIN; + q->cfo_pss_min = DEFAULT_CFO_PSS_MIN; + q->cfo_loop_bw_pss = DEFAULT_CFO_BW; + q->cfo_loop_bw_ref = DEFAULT_CFO_BW; q->cfo_correct_enable = true; + q->pss_stable_cnt = 0; + q->pss_stable_timeout = DEFAULT_PSS_STABLE_TIMEOUT; + if (search_cell) { /* If the cell is unkown, we search PSS/SSS in 5 ms */ @@ -269,11 +279,11 @@ int srslte_ue_sync_init_multi_decim(srslte_ue_sync_t *q, srslte_sync_set_cfo_cp_enable(&q->strack, false); srslte_sync_set_cfo_pss_enable(&q->strack, true); srslte_sync_set_pss_filt_enable(&q->strack, true); - srslte_sync_set_sss_filt_enable(&q->strack, true); + srslte_sync_set_sss_filt_enable(&q->strack, false); // FIXME: CP detection not working very well. Not supporting Extended CP right now srslte_sync_cp_en(&q->strack, false); - srslte_sync_cp_en(&q->sfind, false); + srslte_sync_cp_en(&q->sfind, false); srslte_sync_sss_en(&q->strack, true); @@ -368,6 +378,9 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) srslte_sync_set_threshold(&q->sfind, 2.0); srslte_sync_set_threshold(&q->strack, 1.2); + srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); + srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); + } else { q->sfind.cp = cell.cp; q->strack.cp = cell.cp; @@ -376,7 +389,7 @@ int srslte_ue_sync_set_cell(srslte_ue_sync_t *q, srslte_cell_t cell) srslte_sync_set_N_id_2(&q->strack, cell.id%3); srslte_sync_set_cfo_ema_alpha(&q->sfind, 0.1); - srslte_sync_set_cfo_ema_alpha(&q->strack, 0.1); + srslte_sync_set_cfo_ema_alpha(&q->strack, DEFAULT_CFO_EMA_TRACK); /* In find phase and if the cell is known, do not average pss correlation * because we only capture 1 subframe and do not know where the peak is. @@ -402,22 +415,31 @@ void srslte_ue_sync_get_last_timestamp(srslte_ue_sync_t *q, srslte_timestamp_t * memcpy(timestamp, &q->last_timestamp, sizeof(srslte_timestamp_t)); } -void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw, float pss_tol, float ref_tol, float ref_max) { - q->cfo_loop_bw = bw; - q->cfo_pss_tol = pss_tol; - q->cfo_ref_tol = ref_tol; +void srslte_ue_sync_set_cfo_loop_bw(srslte_ue_sync_t *q, float bw_pss, float bw_ref, + float pss_tol, float ref_tol, float ref_max, + uint32_t pss_stable_conv_time) { + q->cfo_loop_bw_pss = bw_pss; + q->cfo_loop_bw_ref = bw_ref; + q->cfo_pss_min = pss_tol; + q->cfo_ref_min = ref_tol; q->cfo_ref_max = ref_max; + q->pss_stable_timeout = pss_stable_conv_time; } void srslte_ue_sync_set_cfo_ema(srslte_ue_sync_t *q, float ema) { - srslte_sync_set_cfo_ema_alpha(&q->sfind, ema); srslte_sync_set_cfo_ema_alpha(&q->strack, ema); } void srslte_ue_sync_set_cfo_ref(srslte_ue_sync_t *q, float ref_cfo) { - if (fabsf(ref_cfo)*15000 > q->cfo_ref_tol && fabsf(ref_cfo)*15000 < q->cfo_ref_max) { - q->cfo_current_value += ref_cfo*q->cfo_loop_bw; + // Accept REF-based CFO adjustments only after PSS CFO is stable + if (q->pss_is_stable) { + if (fabsf(ref_cfo)*15000 > q->cfo_ref_min) { + if (fabsf(ref_cfo)*15000 > q->cfo_ref_max) { + ref_cfo = (ref_cfo>0?q->cfo_ref_max:-q->cfo_ref_max)/15000; + } + q->cfo_current_value += ref_cfo*q->cfo_loop_bw_ref; + } } } @@ -437,12 +459,16 @@ float srslte_ue_sync_get_cfo(srslte_ue_sync_t *q) { void srslte_ue_sync_copy_cfo(srslte_ue_sync_t *q, srslte_ue_sync_t *src_obj) { // Copy find object internal CFO averages - srslte_sync_copy_cfo(&q->sfind, &src_obj->sfind); + srslte_sync_copy_cfo(&q->sfind, &src_obj->sfind); // Current CFO is tracking-phase CFO of previous object - q->cfo_current_value = srslte_ue_sync_get_cfo(src_obj); + q->cfo_current_value = src_obj->cfo_current_value; + q->cfo_is_copied = true; } -void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) {} +void srslte_ue_sync_set_cfo_tol(srslte_ue_sync_t *q, float cfo_tol) { + srslte_sync_set_cfo_tol(&q->strack, cfo_tol); + srslte_sync_set_cfo_tol(&q->sfind, cfo_tol); +} float srslte_ue_sync_get_sfo(srslte_ue_sync_t *q) { return q->mean_sfo/5e-3; @@ -507,10 +533,12 @@ static int find_peak_ok(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE_MAX_PORTS q->mean_sample_offset = 0; /* Goto Tracking state */ - q->state = SF_TRACK; - + q->state = SF_TRACK; + /* Set CFO values. Since we correct before track, the initial track state is CFO=0 Hz */ - q->cfo_current_value = srslte_sync_get_cfo(&q->sfind); + if (!q->cfo_is_copied) { + q->cfo_current_value = srslte_sync_get_cfo(&q->sfind); + } srslte_sync_cfo_reset(&q->strack); } @@ -550,9 +578,18 @@ static int track_peak_ok(srslte_ue_sync_t *q, uint32_t track_idx) { /* Adjust current CFO estimation with PSS * Since sync track has enabled only PSS-based correlation, get_cfo() returns that value only, already filtered. */ - INFO("TRACK: cfo_current: %f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack)); - if (15000*fabsf(srslte_sync_get_cfo(&q->strack)) > q->cfo_pss_tol) { - q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw; + INFO("TRACK: cfo_current=%f, cfo_strack=%f\n", 15000*q->cfo_current_value, 15000*srslte_sync_get_cfo(&q->strack)); + if (15000*fabsf(srslte_sync_get_cfo(&q->strack)) > q->cfo_pss_min) { + q->cfo_current_value += srslte_sync_get_cfo(&q->strack)*q->cfo_loop_bw_pss; + q->pss_stable_cnt = 0; + q->pss_is_stable = false; + } else { + if (!q->pss_is_stable) { + q->pss_stable_cnt++; + if (q->pss_stable_cnt >= q->pss_stable_timeout) { + q->pss_is_stable = true; + } + } } // Compute cumulative moving average time offset */ @@ -694,7 +731,7 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE ret = SRSLTE_ERROR; fprintf(stderr, "Error finding correlation peak (%d)\n", ret); return SRSLTE_ERROR; - case SRSLTE_SYNC_FOUND: + case SRSLTE_SYNC_FOUND: ret = find_peak_ok(q, input_buffer); break; case SRSLTE_SYNC_FOUND_NOSPACE: @@ -769,9 +806,9 @@ int srslte_ue_sync_zerocopy_multi(srslte_ue_sync_t *q, cf_t *input_buffer[SRSLTE fprintf(stderr, "Error processing tracking peak\n"); q->state = SF_FIND; return SRSLTE_SUCCESS; - } - - q->frame_total_cnt++; + } + + q->frame_total_cnt++; } break; } diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index ec2809dfe..e50be05a6 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -38,7 +38,7 @@ #define MAX_SFLEN SRSLTE_SF_LEN(srslte_symbol_sz(max_prb)) -#define DEFAULT_CFO_TOL 50.0 // Hz +#define DEFAULT_CFO_TOL 0.0 // Hz int srslte_ue_ul_init(srslte_ue_ul_t *q, cf_t *out_buffer, diff --git a/srsue/hdr/phy/phch_common.h b/srsue/hdr/phy/phch_common.h index 0fe8529da..963f146dc 100644 --- a/srsue/hdr/phy/phch_common.h +++ b/srsue/hdr/phy/phch_common.h @@ -42,131 +42,138 @@ namespace srsue { + +class chest_feedback_itf +{ +public: + virtual void set_cfo(float cfo) = 0; +}; + /* Subclass that manages variables common to all workers */ - class phch_common { - public: - - /* Common variables used by all phy workers */ - phy_interface_rrc::phy_cfg_t *config; - phy_args_t *args; - rrc_interface_phy *rrc; - mac_interface_phy *mac; - srslte_ue_ul_t ue_ul; - - /* Power control variables */ - float pathloss; - float cur_pathloss; - float p0_preamble; - float cur_radio_power; - float cur_pusch_power; - float avg_rsrp_db; - float avg_rsrq_db; - float rx_gain_offset; - float avg_snr_db; - float avg_noise; - float avg_rsrp; - - // Save last TBS for mcs>28 cases - int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; - uint32_t last_dl_tti[2*HARQ_DELAY_MS]; - - int last_ul_tbs[2*HARQ_DELAY_MS]; - uint32_t last_ul_tti[2*HARQ_DELAY_MS]; - srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; - - phch_common(uint32_t max_mutex = 3); - void init(phy_interface_rrc::phy_cfg_t *config, - phy_args_t *args, - srslte::log *_log, - srslte::radio *_radio, - rrc_interface_phy *rrc, - mac_interface_phy *_mac); - - /* For RNTI searches, -1 means now or forever */ - void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); - uint16_t get_ul_rnti(uint32_t tti); - srslte_rnti_type_t get_ul_rnti_type(); - - void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); - uint16_t get_dl_rnti(uint32_t tti); - srslte_rnti_type_t get_dl_rnti_type(); - - void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); - bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); - - void reset_pending_ack(uint32_t tti); - void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); - bool get_pending_ack(uint32_t tti); - bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); - - void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); - - void set_nof_mutex(uint32_t nof_mutex); - - bool sr_enabled; - int sr_last_tx_tti; - - srslte::radio* get_radio(); - - void set_cell(const srslte_cell_t &c); - uint32_t get_nof_prb(); - void set_dl_metrics(const dl_metrics_t &m); - void get_dl_metrics(dl_metrics_t &m); - void set_ul_metrics(const ul_metrics_t &m); - void get_ul_metrics(ul_metrics_t &m); - void set_sync_metrics(const sync_metrics_t &m); - void get_sync_metrics(sync_metrics_t &m); - - void reset_ul(); - - private: - - std::vector tx_mutex; - - bool is_first_of_burst; - srslte::radio *radio_h; - float cfo; - srslte::log *log_h; - - - bool ul_rnti_active(uint32_t tti); - bool dl_rnti_active(uint32_t tti); - uint16_t ul_rnti, dl_rnti; - srslte_rnti_type_t ul_rnti_type, dl_rnti_type; - int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; - - float time_adv_sec; - - srslte_dci_rar_grant_t rar_grant; - bool rar_grant_pending; - uint32_t rar_grant_tti; - - typedef struct { - bool enabled; - uint32_t I_lowest; - uint32_t n_dmrs; - } pending_ack_t; - pending_ack_t pending_ack[TTIMOD_SZ]; - - bool is_first_tx; - - uint32_t nof_workers; - uint32_t nof_mutex; - uint32_t max_mutex; - - srslte_cell_t cell; - - dl_metrics_t dl_metrics; - uint32_t dl_metrics_count; - bool dl_metrics_read; - ul_metrics_t ul_metrics; - uint32_t ul_metrics_count; - bool ul_metrics_read; - sync_metrics_t sync_metrics; - uint32_t sync_metrics_count; - bool sync_metrics_read; - }; - +class phch_common { +public: + + /* Common variables used by all phy workers */ + phy_interface_rrc::phy_cfg_t *config; + phy_args_t *args; + rrc_interface_phy *rrc; + mac_interface_phy *mac; + srslte_ue_ul_t ue_ul; + + /* Power control variables */ + float pathloss; + float cur_pathloss; + float p0_preamble; + float cur_radio_power; + float cur_pusch_power; + float avg_rsrp_db; + float avg_rsrq_db; + float rx_gain_offset; + float avg_snr_db; + float avg_noise; + float avg_rsrp; + + // Save last TBS for mcs>28 cases + int last_dl_tbs[2*HARQ_DELAY_MS][SRSLTE_MAX_CODEWORDS]; + uint32_t last_dl_tti[2*HARQ_DELAY_MS]; + + int last_ul_tbs[2*HARQ_DELAY_MS]; + uint32_t last_ul_tti[2*HARQ_DELAY_MS]; + srslte_mod_t last_ul_mod[2*HARQ_DELAY_MS]; + + phch_common(uint32_t max_mutex = 3); + void init(phy_interface_rrc::phy_cfg_t *config, + phy_args_t *args, + srslte::log *_log, + srslte::radio *_radio, + rrc_interface_phy *rrc, + mac_interface_phy *_mac); + + /* For RNTI searches, -1 means now or forever */ + void set_ul_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_ul_rnti(uint32_t tti); + srslte_rnti_type_t get_ul_rnti_type(); + + void set_dl_rnti(srslte_rnti_type_t type, uint16_t rnti_value, int tti_start = -1, int tti_end = -1); + uint16_t get_dl_rnti(uint32_t tti); + srslte_rnti_type_t get_dl_rnti_type(); + + void set_rar_grant(uint32_t tti, uint8_t grant_payload[SRSLTE_RAR_GRANT_LEN]); + bool get_pending_rar(uint32_t tti, srslte_dci_rar_grant_t *rar_grant = NULL); + + void reset_pending_ack(uint32_t tti); + void set_pending_ack(uint32_t tti, uint32_t I_lowest, uint32_t n_dmrs); + bool get_pending_ack(uint32_t tti); + bool get_pending_ack(uint32_t tti, uint32_t *I_lowest, uint32_t *n_dmrs); + + void worker_end(uint32_t tti, bool tx_enable, cf_t *buffer, uint32_t nof_samples, srslte_timestamp_t tx_time); + + void set_nof_mutex(uint32_t nof_mutex); + + bool sr_enabled; + int sr_last_tx_tti; + + srslte::radio* get_radio(); + + void set_cell(const srslte_cell_t &c); + uint32_t get_nof_prb(); + void set_dl_metrics(const dl_metrics_t &m); + void get_dl_metrics(dl_metrics_t &m); + void set_ul_metrics(const ul_metrics_t &m); + void get_ul_metrics(ul_metrics_t &m); + void set_sync_metrics(const sync_metrics_t &m); + void get_sync_metrics(sync_metrics_t &m); + + void reset_ul(); + +private: + + std::vector tx_mutex; + + bool is_first_of_burst; + srslte::radio *radio_h; + float cfo; + srslte::log *log_h; + + + bool ul_rnti_active(uint32_t tti); + bool dl_rnti_active(uint32_t tti); + uint16_t ul_rnti, dl_rnti; + srslte_rnti_type_t ul_rnti_type, dl_rnti_type; + int ul_rnti_start, ul_rnti_end, dl_rnti_start, dl_rnti_end; + + float time_adv_sec; + + srslte_dci_rar_grant_t rar_grant; + bool rar_grant_pending; + uint32_t rar_grant_tti; + + typedef struct { + bool enabled; + uint32_t I_lowest; + uint32_t n_dmrs; + } pending_ack_t; + pending_ack_t pending_ack[TTIMOD_SZ]; + + bool is_first_tx; + + uint32_t nof_workers; + uint32_t nof_mutex; + uint32_t max_mutex; + + srslte_cell_t cell; + + dl_metrics_t dl_metrics; + uint32_t dl_metrics_count; + bool dl_metrics_read; + ul_metrics_t ul_metrics; + uint32_t ul_metrics_count; + bool ul_metrics_read; + sync_metrics_t sync_metrics; + uint32_t sync_metrics_count; + bool sync_metrics_read; +}; + } // namespace srsue #endif // UEPHYWORKERCOMMON_H diff --git a/srsue/hdr/phy/phch_recv.h b/srsue/hdr/phy/phch_recv.h index 01a296094..a5f290887 100644 --- a/srsue/hdr/phy/phch_recv.h +++ b/srsue/hdr/phy/phch_recv.h @@ -41,7 +41,7 @@ namespace srsue { typedef _Complex float cf_t; -class phch_recv : public thread +class phch_recv : public thread, public chest_feedback_itf { public: phch_recv(); @@ -65,6 +65,9 @@ public: bool status_is_sync(); + // from chest_feedback_itf + void set_cfo(float cfo); + void set_time_adv_sec(float time_adv_sec); void get_current_cell(srslte_cell_t *cell); diff --git a/srsue/hdr/phy/phch_worker.h b/srsue/hdr/phy/phch_worker.h index e7030d777..570d3d0c2 100644 --- a/srsue/hdr/phy/phch_worker.h +++ b/srsue/hdr/phy/phch_worker.h @@ -45,7 +45,7 @@ public: ~phch_worker(); void reset(); void set_common(phch_common *phy); - bool init(uint32_t max_prb, srslte::log *log); + bool init(uint32_t max_prb, srslte::log *log, chest_feedback_itf *chest_loop); bool set_cell(srslte_cell_t cell); @@ -66,6 +66,8 @@ public: int read_ce_abs(float *ce_abs); int read_pdsch_d(cf_t *pdsch_d); void start_plot(); + + float get_ref_cfo(); private: /* Inherited from thread_pool::worker. Function called every subframe to run the DL/UL processing */ @@ -114,6 +116,7 @@ private: /* Common objects */ phch_common *phy; srslte::log *log_h; + chest_feedback_itf *chest_loop; srslte_cell_t cell; bool mem_initiated; bool cell_initiated; diff --git a/srsue/src/main.cc b/srsue/src/main.cc index 1c9b6edc6..201af1b14 100644 --- a/srsue/src/main.cc +++ b/srsue/src/main.cc @@ -199,13 +199,46 @@ void parse_args(all_args_t *args, int argc, char *argv[]) { "Enables integer CFO estimation and correction.") ("expert.cfo_correct_tol_hz", - bpo::value(&args->expert.phy.cfo_correct_tol_hz)->default_value(50.0), - "Tolerance (in Hz) for digial CFO compensation.") + bpo::value(&args->expert.phy.cfo_correct_tol_hz)->default_value(0.0), + "Tolerance (in Hz) for digital CFO compensation (needs to be low if average_subframe_enabled=true.") - ("expert.cfo_ema", - bpo::value(&args->expert.phy.cfo_ema)->default_value(0.4), - "CFO Exponential Moving Average coefficient. Lower makes it more robust to noise " - "but vulnerable to periodic interruptions due to VCO corrections.") + ("expert.cfo_pss_ema", + bpo::value(&args->expert.phy.cfo_pss_ema)->default_value(0.1), + "CFO Exponential Moving Average coefficient for PSS estimation during TRACK.") + + ("expert.cfo_ref_ema", + bpo::value(&args->expert.phy.cfo_ref_ema)->default_value(0.01), + "CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition") + + ("expert.cfo_ref_mask", + bpo::value(&args->expert.phy.cfo_ref_mask)->default_value(1023), + "Bitmask for subframes on which to run RS estimation (set to 0 to disable, default all sf)") + + ("expert.cfo_loop_bw_pss", + bpo::value(&args->expert.phy.cfo_loop_bw_pss)->default_value(0.05), + "CFO feedback loop bandwidth for samples from PSS") + + ("expert.cfo_loop_bw_ref", + bpo::value(&args->expert.phy.cfo_loop_bw_ref)->default_value(0.01), + "CFO feedback loop bandwidth for samples from RS") + + ("expert.cfo_loop_pss_tol", + bpo::value(&args->expert.phy.cfo_loop_pss_tol)->default_value(300), + "Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop" + "and RS estimations are used instead (when available)") + + ("expert.cfo_loop_ref_min", + bpo::value(&args->expert.phy.cfo_loop_ref_min)->default_value(0), + "Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop") + + + ("expert.cfo_loop_pss_conv", + bpo::value(&args->expert.phy.cfo_loop_pss_conv)->default_value(50), + "After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, RS adjustments are allowed.") + + ("expert.average_subframe_enabled", + 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.time_correct_period", bpo::value(&args->expert.phy.time_correct_period)->default_value(5), diff --git a/srsue/src/phy/phch_recv.cc b/srsue/src/phy/phch_recv.cc index 37f7970ee..652a848bd 100644 --- a/srsue/src/phy/phch_recv.cc +++ b/srsue/src/phy/phch_recv.cc @@ -98,9 +98,6 @@ void phch_recv:: init(srslte::radio_multi *_radio_handler, mac_interface_phy *_ srslte_ue_cellsearch_set_nof_valid_frames(&cs, 2); - // Set options defined in expert section - set_ue_sync_opts(&cs.ue_sync); - last_gain = 40; if (do_agc) { srslte_ue_sync_start_agc(&cs.ue_sync, callback_set_rx_gain, last_gain); @@ -184,6 +181,11 @@ void phch_recv::radio_error() { radio_is_resetting=false; } +void phch_recv::set_cfo(float cfo) { + Debug("set_ref_cfo=%f\n",cfo*15000); + srslte_ue_sync_set_cfo_ref(&ue_sync, cfo); +} + bool phch_recv::wait_radio_reset() { int cnt=0; while(cnt < 20 && radio_is_resetting) { @@ -211,8 +213,13 @@ void phch_recv::set_ue_sync_opts(srslte_ue_sync_t *q) { srslte_ue_sync_set_cfo_i_enable(q, true); } - srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_ema); + srslte_ue_sync_set_cfo_ema(q, worker_com->args->cfo_pss_ema); srslte_ue_sync_set_cfo_tol(q, worker_com->args->cfo_correct_tol_hz); + srslte_ue_sync_set_cfo_loop_bw(q, worker_com->args->cfo_loop_bw_pss, worker_com->args->cfo_loop_bw_ref, + worker_com->args->cfo_loop_pss_tol, + worker_com->args->cfo_loop_ref_min, + worker_com->args->cfo_loop_pss_tol, + worker_com->args->cfo_loop_pss_conv); int time_correct_period = worker_com->args->time_correct_period; if (time_correct_period > 0) { @@ -320,15 +327,13 @@ int phch_recv::cell_search(int force_N_id_2) { return false; } - // Set options defined in expert section - set_ue_sync_opts(&ue_mib_sync.ue_sync); - if (do_agc) { srslte_ue_sync_start_agc(&ue_mib_sync.ue_sync, callback_set_rx_gain, last_gain); } srslte_ue_sync_reset(&ue_mib_sync.ue_sync); srslte_ue_sync_copy_cfo(&ue_mib_sync.ue_sync, &cs.ue_sync); + Info("Copied cfo=%f Hz from cs_sync to ue_mib\n", srslte_ue_sync_get_cfo(&ue_mib_sync.ue_sync)); /* Find and decode MIB */ int sfn_offset; @@ -341,6 +346,7 @@ int phch_recv::cell_search(int force_N_id_2) { srslte_ue_sync_reset(&ue_sync); srslte_ue_sync_copy_cfo(&ue_sync, &ue_mib_sync.ue_sync); + Info("Copied cfo=%f Hz from ue_mib_sync to ue_sync\n", srslte_ue_sync_get_cfo(&ue_sync)); if (ret == 1) { srslte_pbch_mib_unpack(bch_payload, &cell, NULL); @@ -731,6 +737,9 @@ void phch_recv::run_thread() { worker->set_cfo(ul_dl_factor * metrics.cfo / 15000); worker_com->set_sync_metrics(metrics); + Debug("current_cfo=%f, pss_stable_cnt=%d, cfo_pss=%f Hz\n", + metrics.cfo, ue_sync.pss_stable_cnt, srslte_sync_get_cfo(&ue_sync.strack)*15000); + worker->set_sample_offset(srslte_ue_sync_get_sfo(&ue_sync)/1000); /* Compute TX time: Any transmission happens in TTI+4 thus advance 4 ms the reception time */ diff --git a/srsue/src/phy/phch_worker.cc b/srsue/src/phy/phch_worker.cc index 7b4ec48bd..fefa7d250 100644 --- a/srsue/src/phy/phch_worker.cc +++ b/srsue/src/phy/phch_worker.cc @@ -57,7 +57,9 @@ namespace srsue { phch_worker::phch_worker() : tr_exec(10240) { - phy = NULL; + phy = NULL; + chest_loop = NULL; + bzero(signal_buffer, sizeof(cf_t*)*SRSLTE_MAX_PORTS); mem_initiated = false; @@ -104,9 +106,11 @@ void phch_worker::set_common(phch_common* phy_) phy = phy_; } -bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) +bool phch_worker::init(uint32_t max_prb, srslte::log *log_h, chest_feedback_itf *chest_loop) { this->log_h = log_h; + this->chest_loop = chest_loop; + // ue_sync in phy.cc requires a buffer for 3 subframes for (uint32_t i=0;iargs->nof_rx_ant;i++) { signal_buffer[i] = (cf_t*) srslte_vec_malloc(3 * sizeof(cf_t) * SRSLTE_SF_LEN_PRB(max_prb)); @@ -126,6 +130,8 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) return false; } + srslte_chest_dl_average_subframe(&ue_dl.chest, phy->args->average_subframe_enabled); + srslte_chest_dl_cfo_estimate_enable(&ue_dl.chest, phy->args->cfo_ref_mask!=0, phy->args->cfo_ref_mask, phy->args->cfo_ref_ema); srslte_ue_ul_set_normalization(&ue_ul, true); srslte_ue_ul_set_cfo_enable(&ue_ul, true); @@ -134,6 +140,10 @@ bool phch_worker::init(uint32_t max_prb, srslte::log *log_h) return true; } +float phch_worker::get_ref_cfo() { + return srslte_chest_dl_get_cfo(&ue_dl.chest); +} + bool phch_worker::set_cell(srslte_cell_t cell_) { if (cell.id != cell_.id || !cell_initiated) { @@ -221,6 +231,11 @@ void phch_worker::work_imp() bool snr_th_ok = 10*log10(srslte_chest_dl_get_snr(&ue_dl.chest))>1.0; + // Call feedback loop for chest + if (chest_loop && ((1<<(tti%10)) & phy->args->cfo_ref_mask)) { + chest_loop->set_cfo(srslte_chest_dl_get_cfo(&ue_dl.chest)); + } + if (chest_ok && snr_th_ok) { /***** Downlink Processing *******/ @@ -394,11 +409,8 @@ void phch_worker::work_imp() bool phch_worker::extract_fft_and_pdcch_llr() { - bool decode_pdcch = false; - if (phy->get_ul_rnti(tti) || phy->get_dl_rnti(tti) || phy->get_pending_rar(tti)) { - decode_pdcch = true; - } - + bool decode_pdcch = true; + /* Without a grant, we might need to do fft processing if need to decode PHICH */ if (phy->get_pending_ack(tti) || decode_pdcch) { @@ -1213,13 +1225,18 @@ int phch_worker::read_ce_abs(float *ce_abs) { int sz = srslte_symbol_sz(cell.nof_prb); bzero(ce_abs, sizeof(float)*sz); int g = (sz - 12*cell.nof_prb)/2; - for (i = 0; i < 12*cell.nof_prb; i++) { +/* for (i = 0; i < 12*cell.nof_prb; i++) { ce_abs[g+i] = 20 * log10f(cabsf(ue_dl.ce_m[0][0][i])); if (isinf(ce_abs[g+i])) { ce_abs[g+i] = -80; } } - return sz; +*/ + uint32_t nrefs = 2*ue_dl.cell.nof_prb; + for (i=0;iavg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise); + phy->avg_snr_db = 10*log10(phy->avg_rsrp/phy->avg_noise); // Store metrics dl_metrics.n = phy->avg_noise; @@ -1371,7 +1388,7 @@ void *plot_thread_run(void *arg) { plot_real_init(&pce); plot_real_setTitle(&pce, (char*) "Channel Response - Magnitude"); plot_real_setLabels(&pce, (char*) "Index", (char*) "dB"); - plot_real_setYAxisScale(&pce, -40, 40); + plot_real_setYAxisScale(&pce, -1000, 1000); plot_scatter_init(&pconst); plot_scatter_setTitle(&pconst, (char*) "PDSCH - Equalized Symbols"); diff --git a/srsue/src/phy/phy.cc b/srsue/src/phy/phy.cc index 6dfb2c6d7..0daecf0de 100644 --- a/srsue/src/phy/phy.cc +++ b/srsue/src/phy/phy.cc @@ -37,7 +37,6 @@ #include "srslte/common/threads.h" #include "srslte/common/log.h" #include "phy/phy.h" -#include "phy/phch_worker.h" #define Error(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->error_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) #define Warning(fmt, ...) if (SRSLTE_DEBUG_ENABLED) log_h->warning_line(__FILE__, __LINE__, fmt, ##__VA_ARGS__) @@ -134,7 +133,7 @@ void phy::run_thread() { // Add workers to workers pool and start threads for (uint32_t i=0;iworker_cpu_mask); } diff --git a/srsue/ue.conf.example b/srsue/ue.conf.example index 867221e87..7bd6fae18 100644 --- a/srsue/ue.conf.example +++ b/srsue/ue.conf.example @@ -137,13 +137,7 @@ enable = false # equalizer_mode: Selects equalizer mode. Valid modes are: "mmse", "zf" or any # non-negative real number to indicate a regularized zf coefficient. # Default is MMSE. -# cfo_ema: CFO Exponential Moving Average coefficient. Lower makes it more robust to noise -# but vulnerable to periodic interruptions due to VCO corrections. -# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement -# and may lead to incorrect synchronization. Use with caution. -# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that -# a new table will be generated more often. -# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c), +# time_correct_period: Period for sampling time offset correction. Default is 10 (ue_sync.c), # good for long channels. For best performance at highest SNR reduce it to 1. # sfo_correct_disable: Disables phase correction before channel estimation to compensate for # sampling frequency offset. Default is enabled. @@ -155,10 +149,28 @@ enable = false # # pregenerate_signals: Pregenerate uplink signals after attach. Improves CPU performance. # +# average_subframe_enabled: Averages in the time domain the channel estimates within 1 subframe. +# Needs accurate CFO correction. +# # metrics_csv_enable: Write UE metrics to CSV file. # # metrics_csv_filename: File path to use for CSV metrics. # +# cfo_integer_enabled: Enables integer CFO estimation and correction. This needs improvement +# and may lead to incorrect synchronization. Use with caution. +# cfo_correct_tol_hz: Tolerance (in Hz) for digial CFO compensation. Lower tolerance means that +# a new table will be generated more often. +# +# cfo_pss_ema: CFO Exponential Moving Average coefficient for PSS estimation during TRACK. +# cfo_ref_ema: CFO Exponential Moving Average coefficient for RS estimation after PSS acquisition +# cfo_ref_mask: Bitmask for subframes on which to run RS estimation (set to 0 to disable, default sf=[1, 5]) +# cfo_loop_bw: CFO feedback loop bandwidth for samples from PSS or RS +# cfo_loop_pss_tol: Tolerance (in Hz) of the PSS estimation method. Below this value, PSS estimation does not feeds back the loop +# and RS estimations are used instead (when available) +# cfo_loop_ref_min: Tolerance (in Hz) of the RS estimation method. Below this value, RS estimation does not feeds back the loop +# cfo_loop_pss_timeout: After the PSS estimation is below cfo_loop_pss_tol for cfo_loop_pss_timeout times consecutively, +# RS adjustments are allowed. +# ##################################################################### [expert] #ip_netmask = 255.255.255.0 @@ -172,17 +184,27 @@ enable = false #attach_enable_64qam = false #nof_phy_threads = 2 #equalizer_mode = mmse -#cfo_ema = 0.4 -#cfo_integer_enabled = false -#cfo_correct_tol_hz = 50 #time_correct_period = 5 #sfo_correct_disable = false #sss_algorithm = full #estimator_fil_w = 0.1 +#average_subframe_enabled = true #pregenerate_signals = false #metrics_csv_enable = false #metrics_csv_filename = /tmp/ue_metrics.csv +# CFO related values +#cfo_integer_enabled = false +#cfo_correct_tol_hz = 0 +#cfo_pss_ema = 0.1 +#cfo_ref_ema = 0.01 +#cfo_ref_mask = 1023 +#cfo_loop_bw_pss = 0.05 +#cfo_loop_bw_ref = 0.01 +#cfo_loop_pss_tol = 300 +#cfo_loop_ref_min = 0 +#cfo_loop_pss_conv = 50 + ##################################################################### # Manual RF calibration # From 3705baddc3c25800d9f45b1e095843956f10a902 Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 5 Dec 2017 22:06:30 +0100 Subject: [PATCH 21/22] nas: initialize ctxt variable and only check ksi if ctxt is present --- srsue/src/upper/nas.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 62e23d852..5927c3c64 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -44,7 +44,7 @@ namespace srsue { ********************************************************************/ nas::nas() - : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), ip_addr(0), eps_bearer_id(0) + : state(EMM_STATE_DEREGISTERED), plmn_selection(PLMN_SELECTED), have_guti(false), have_ctxt(false), ip_addr(0), eps_bearer_id(0) { ctxt.rx_count = 0; ctxt.tx_count = 0; @@ -548,13 +548,15 @@ void nas::parse_security_mode_command(uint32_t lcid, byte_buffer_t *pdu) return; } - if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi) - { - nas_log->warning("Sending Security Mode Reject due to key set ID mismatch\n"); - send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); - pool->deallocate(pdu); - return; + if (have_ctxt) { + if(sec_mode_cmd.nas_ksi.nas_ksi != ctxt.ksi) { + nas_log->warning("Sending Security Mode Reject due to key set ID mismatch\n"); + send_security_mode_reject(LIBLTE_MME_EMM_CAUSE_SECURITY_MODE_REJECTED_UNSPECIFIED); + pool->deallocate(pdu); + return; + } } + // MME is setting up security context // TODO: check nonce (not sent by Amari) @@ -744,7 +746,7 @@ void nas::send_attach_request() { nas_log->info("Sending attach request\n"); rrc->write_sdu(cfg.lcid, msg); - if(have_ctxt) { + if (have_ctxt) { ctxt.tx_count++; } } From 0641fee20b0422bec5837eecde0cf32a9ae3472b Mon Sep 17 00:00:00 2001 From: Andre Puschmann Date: Tue, 5 Dec 2017 22:15:57 +0100 Subject: [PATCH 22/22] nas: fix IMSI print --- srsue/src/upper/nas.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/srsue/src/upper/nas.cc b/srsue/src/upper/nas.cc index 5927c3c64..801cab581 100644 --- a/srsue/src/upper/nas.cc +++ b/srsue/src/upper/nas.cc @@ -697,7 +697,6 @@ void nas::send_attach_request() { attach_req.additional_guti_present = false; attach_req.last_visited_registered_tai_present = false; attach_req.drx_param_present = false; - attach_req.ms_network_cap_present = false; attach_req.old_lai_present = false; attach_req.tmsi_status_present = false; attach_req.ms_cm2_present = false; @@ -739,7 +738,7 @@ void nas::send_attach_request() { } else { attach_req.eps_mobile_id.type_of_id = LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI; usim->get_imsi_vec(attach_req.eps_mobile_id.imsi, 15); - nas_log->info("Requesting IMSI attach. imsi: %s\n", usim->get_imsi_str()); + nas_log->info("Requesting IMSI attach (IMSI=%s)\n", usim->get_imsi_str().c_str()); liblte_mme_pack_attach_request_msg(&attach_req, (LIBLTE_BYTE_MSG_STRUCT *) msg); }