diff --git a/CMakeLists.txt b/CMakeLists.txt index 73195b1d5..8abc0c063 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ PROJECT (LIBLTE) LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") -INCLUDE(libLTEPackage) #setup cpack +INCLUDE(libLTEPackage) #setup cpack include(CTest) set( CTEST_MEMORYCHECK_COMMAND valgrind ) @@ -77,7 +77,10 @@ IF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + # IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") + # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=implicit-function-declaration -Wno-error=unused-but-set-variable") + # ENDIF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") IF(NOT WIN32) ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) ENDIF(NOT WIN32) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 7a9cb5349..d9e90e9e4 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -5,7 +5,7 @@ FIND_PATH( VOLK_INCLUDE_DIRS NAMES volk.h HINTS $ENV{VOLK_DIR}/include/volk - ${CMAKE_INSTALL_PREFIX}/include/volk + ${CMAKE_INSTALL_PREFIX}/include/volk ${PC_VOLK_INCLUDE_DIR} PATHS /usr/local/include/volk /usr/include/volk @@ -15,9 +15,9 @@ FIND_LIBRARY( VOLK_LIBRARIES NAMES volk HINTS $ENV{VOLK_DIR}/lib - ${CMAKE_INSTALL_PREFIX}/lib - ${CMAKE_INSTALL_PREFIX}/lib64 - ${PC_VOLK_LIBDIR} + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 + ${PC_VOLK_LIBDIR} PATHS /usr/local/lib /usr/local/lib64 /usr/lib @@ -25,35 +25,71 @@ FIND_LIBRARY( ) # Some functions are not defined in old volk versions -SET(CMAKE_REQUIRED_LIBRARIES volk m) +SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m) CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION) + +CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) SET(VOLK_DEFINITIONS "HAVE_VOLK") +IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_CONVERT_FI_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION") +ENDIF() IF(${HAVE_VOLK_MAX_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION") ENDIF() IF(${HAVE_VOLK_ACC_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION") ENDIF() IF(${HAVE_VOLK_MULT_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION") ENDIF() IF(${HAVE_VOLK_CONJ_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION") ENDIF() IF(${HAVE_VOLK_MULT2_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_MULT_REAL_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION") ENDIF() IF(${HAVE_VOLK_MAG_FUNCTION}) - SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION") + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DIVIDE_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_DOTPROD_F_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION") +ENDIF() +IF(${HAVE_VOLK_ATAN_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION") ENDIF() - INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS) MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS) diff --git a/cuhd/include/liblte/cuhd/cuhd.h b/cuhd/include/liblte/cuhd/cuhd.h index d67c2eba1..48da5883d 100644 --- a/cuhd/include/liblte/cuhd/cuhd.h +++ b/cuhd/include/liblte/cuhd/cuhd.h @@ -31,26 +31,63 @@ extern "C" { #endif #include - +#include + #include "liblte/config.h" #include "liblte/cuhd/cuhd_utils.h" -LIBLTE_API int cuhd_open(char *args, void **handler); +LIBLTE_API int cuhd_open(char *args, + void **handler); + LIBLTE_API int cuhd_close(void *h); LIBLTE_API int cuhd_start_rx_stream(void *h); -LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, int nsamples); -LIBLTE_API int cuhd_stop_rx_stream(void *h); -LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h); -LIBLTE_API double cuhd_set_rx_srate(void *h, double freq); -LIBLTE_API double cuhd_set_rx_gain(void *h, double gain); -LIBLTE_API double cuhd_set_rx_freq(void *h, double freq); -LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking); -LIBLTE_API double cuhd_set_tx_srate(void *h, double freq); -LIBLTE_API double cuhd_set_tx_gain(void *h, double gain); -LIBLTE_API double cuhd_set_tx_freq(void *h, double freq); -LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking); +LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, + uint32_t nsamples); + +LIBLTE_API int cuhd_stop_rx_stream(void *h); + +LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h); + +LIBLTE_API double cuhd_set_rx_srate(void *h, + double freq); + +LIBLTE_API double cuhd_set_rx_gain(void *h, + double gain); + +LIBLTE_API double cuhd_set_rx_freq(void *h, + double freq); + +LIBLTE_API double cuhd_set_rx_freq_offset(void *h, + double freq, + double off); + +LIBLTE_API int cuhd_recv(void *h, + void *data, + uint32_t nsamples, + bool blocking); + +LIBLTE_API int cuhd_recv_timed(void *h, + void *data, + uint32_t nsamples, + bool blocking, + time_t *secs, + double *frac_secs); + +LIBLTE_API double cuhd_set_tx_srate(void *h, + double freq); + +LIBLTE_API double cuhd_set_tx_gain(void *h, + double gain); + +LIBLTE_API double cuhd_set_tx_freq(void *h, + double freq); + +LIBLTE_API int cuhd_send(void *h, + void *data, + uint32_t nsamples, + bool blocking); #ifdef __cplusplus diff --git a/cuhd/lib/cuhd_handler.hpp b/cuhd/lib/cuhd_handler.hpp index 349117a88..8e3ecedd6 100644 --- a/cuhd/lib/cuhd_handler.hpp +++ b/cuhd/lib/cuhd_handler.hpp @@ -30,9 +30,9 @@ class cuhd_handler { public: - uhd::usrp::multi_usrp::sptr usrp; - uhd::rx_streamer::sptr rx_stream; - bool rx_stream_enable; - uhd::tx_streamer::sptr tx_stream; + uhd::usrp::multi_usrp::sptr usrp; + uhd::rx_streamer::sptr rx_stream; + bool rx_stream_enable; + uhd::tx_streamer::sptr tx_stream; }; diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp index 626415f7e..ca98b9e2e 100644 --- a/cuhd/lib/cuhd_imp.cpp +++ b/cuhd/lib/cuhd_imp.cpp @@ -35,8 +35,9 @@ #include "liblte/cuhd/cuhd.h" -void my_handler(uhd::msg::type_t type, const std::string &msg){ - //handle the message... +void my_handler(uhd::msg::type_t type, const std::string & msg) +{ + //handle the message... } typedef _Complex float complex_t; @@ -45,161 +46,216 @@ typedef _Complex float complex_t; bool isLocked(void *h) { - cuhd_handler* handler = static_cast(h); - std::vector mb_sensors = handler->usrp->get_mboard_sensor_names(); - std::vector rx_sensors = handler->usrp->get_rx_sensor_names(0); - if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) { - return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); - } - else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) { - return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); - } - else { - usleep(500); - return true; - } + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + std::vector < std::string > mb_sensors = + handler->usrp->get_mboard_sensor_names(); + std::vector < std::string > rx_sensors = + handler->usrp->get_rx_sensor_names(0); + if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != + rx_sensors.end()) { + return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool(); + } else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != + mb_sensors.end()) { + return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool(); + } else { + usleep(500); + return true; + } } bool cuhd_rx_wait_lo_locked(void *h) { - double report = 0.0; - while(isLocked(h) && report < 3.0) - { - report += 0.1; - usleep(1000); - } - return isLocked(h); + double report = 0.0; + while (isLocked(h) && report < 3.0) { + report += 0.1; + usleep(1000); + } + return isLocked(h); } -int cuhd_start_rx_stream(void *h) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; +int cuhd_start_rx_stream(void *h) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; } -int cuhd_stop_rx_stream(void *h) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - handler->usrp->issue_stream_cmd(cmd); - return 0; +int cuhd_stop_rx_stream(void *h) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + handler->usrp->issue_stream_cmd(cmd); + return 0; } -int cuhd_start_rx_stream_nsamples(void *h, int nsamples) { - cuhd_handler* handler = static_cast(h); - uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); - cmd.time_spec = handler->usrp->get_time_now(); - cmd.stream_now = true; - cmd.num_samps = nsamples; - handler->usrp->issue_stream_cmd(cmd); - return 0; +int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE); + cmd.time_spec = handler->usrp->get_time_now(); + cmd.stream_now = true; + cmd.num_samps = nsamples; + handler->usrp->issue_stream_cmd(cmd); + return 0; } -int cuhd_open(char *args, void **h) { - cuhd_handler* handler = new cuhd_handler(); - std::string _args=std::string(args); - handler->usrp = uhd::usrp::multi_usrp::make(_args); +int cuhd_open(char *args, void **h) +{ + cuhd_handler *handler = new cuhd_handler(); + std::string _args = std::string(args); + handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000"); - // Try to set LTE clock - handler->usrp->set_master_clock_rate(30720000); + handler->usrp->set_clock_source("internal"); - handler->usrp->set_clock_source("internal"); + std::string otw, cpu; + otw = "sc16"; + cpu = "fc32"; + uhd::stream_args_t stream_args(cpu, otw); + handler->rx_stream = handler->usrp->get_rx_stream(stream_args); + handler->tx_stream = handler->usrp->get_tx_stream(stream_args); - std::string otw, cpu; - otw="sc16"; - cpu="fc32"; - uhd::stream_args_t stream_args(cpu, otw); - handler->rx_stream = handler->usrp->get_rx_stream(stream_args); - handler->tx_stream = handler->usrp->get_tx_stream(stream_args); + *h = handler; - *h = handler; - - return 0; + return 0; } -int cuhd_close(void *h) { - cuhd_stop_rx_stream(h); - /** Something else to close the USRP?? */ - return 0; +int cuhd_close(void *h) +{ + cuhd_stop_rx_stream(h); + /** Something else to close the USRP?? */ + return 0; } -double cuhd_set_rx_srate(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_rate(freq); - double ret = handler->usrp->get_rx_rate(); - return ret; +double cuhd_set_rx_srate(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_rate(freq); + double ret = handler->usrp->get_rx_rate(); + return ret; } -double cuhd_set_rx_gain(void *h, double gain) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_gain(gain); - return handler->usrp->get_rx_gain(); +double cuhd_set_rx_gain(void *h, double gain) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_gain(gain); + return handler->usrp->get_rx_gain(); } -double cuhd_set_rx_freq(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_rx_freq(freq); - return handler->usrp->get_rx_freq(); +double cuhd_set_rx_freq(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_rx_freq(freq); + return handler->usrp->get_rx_freq(); } -int cuhd_recv(void *h, void *data, int nsamples, int blocking) { - cuhd_handler* handler = static_cast(h); - uhd::rx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(nrx_stream->recv(data, nsamples, md, 0.0); - } +double cuhd_set_rx_freq_offset(void *h, double freq, double off) { + cuhd_handler* handler = static_cast(h); + handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off)); + return handler->usrp->get_rx_freq(); } -double cuhd_set_tx_gain(void *h, double gain) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_gain(gain); - return handler->usrp->get_tx_gain(); +int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::rx_metadata_t md; + if (blocking) { + int n = 0, p; + complex_t *data_c = (complex_t *) data; + do { + p = handler->rx_stream->recv(&data_c[n], nsamples - n, md); + if (p == -1) { + return -1; + } + n += p; + if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) { + std::cout << "\nError code: " << md.to_pp_string() << "\n\n"; + } + } while (n < nsamples); + return nsamples; + } else { + return handler->rx_stream->recv(data, nsamples, md, 0.0); + } } -double cuhd_set_tx_srate(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_rate(freq); - return handler->usrp->get_tx_rate(); +int cuhd_recv_timed(void *h, + void *data, + uint32_t nsamples, + int blocking, + time_t *secs, + double *frac_secs) { + cuhd_handler* handler = static_cast(h); + uhd::rx_metadata_t md; + *secs = -1; + *frac_secs = -1; + int p; + if (blocking) { + int n=0; + complex_t *data_c = (complex_t*) data; + do { + p=handler->rx_stream->recv(&data_c[n], nsamples-n, md); + if (p == -1) { + return -1; + } + if(*secs < 0){ + *secs = md.time_spec.get_full_secs(); + *frac_secs = md.time_spec.get_frac_secs(); + } + n+=p; + } while(nrx_stream->recv(data, nsamples, md, 0.0); + *secs = md.time_spec.get_full_secs(); + *frac_secs = md.time_spec.get_frac_secs(); + return p; + } } -double cuhd_set_tx_freq(void *h, double freq) { - cuhd_handler* handler = static_cast(h); - handler->usrp->set_tx_freq(freq); - return handler->usrp->get_tx_freq(); + +double cuhd_set_tx_gain(void *h, double gain) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_gain(gain); + return handler->usrp->get_tx_gain(); } -int cuhd_send(void *h, void *data, int nsamples, int blocking) { - cuhd_handler* handler = static_cast(h); - uhd::tx_metadata_t md; - if (blocking) { - int n=0,p; - complex_t *data_c = (complex_t*) data; - do { - p=handler->tx_stream->send(&data_c[n], nsamples-n, md); - if (p == -1) { - return -1; - } - n+=p; - } while(ntx_stream->send(data, nsamples, md, 0.0); - } +double cuhd_set_tx_srate(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_rate(freq); + return handler->usrp->get_tx_rate(); +} + +double cuhd_set_tx_freq(void *h, double freq) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + handler->usrp->set_tx_freq(freq); + return handler->usrp->get_tx_freq(); +} + +int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking) +{ + cuhd_handler *handler = static_cast < cuhd_handler * >(h); + uhd::tx_metadata_t md; + if (blocking) { + int n = 0, p; + complex_t *data_c = (complex_t *) data; + do { + p = handler->tx_stream->send(&data_c[n], nsamples - n, md); + if (p == -1) { + return -1; + } + n += p; + } while (n < nsamples); + return nsamples; + } else { + return handler->tx_stream->send(data, nsamples, md, 0.0); + } } diff --git a/lte/phy/CMakeLists.txt b/lte/phy/CMakeLists.txt index 77373e308..886b9d311 100644 --- a/lte/phy/CMakeLists.txt +++ b/lte/phy/CMakeLists.txt @@ -34,10 +34,10 @@ INSTALL(DIRECTORY include/ SET(HEADERS_ALL "") FILE(GLOB headers *) FOREACH (_header ${headers}) - IF(IS_DIRECTORY ${_header}) - FILE(GLOB_RECURSE tmp "${_header}/*.h") - LIST(APPEND HEADERS_ALL ${tmp}) - ENDIF(IS_DIRECTORY ${_header}) + IF(IS_DIRECTORY ${_header}) + FILE(GLOB_RECURSE tmp "${_header}/*.h") + LIST(APPEND HEADERS_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_header}) ENDFOREACH() ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL}) diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index a599920ec..b14924cc7 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -51,7 +51,7 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) # These two can be compiled without UHD or graphics support ################################################################# -add_executable(pdsch_ue pdsch_ue.c) +add_executable(pdsch_ue pdsch_ue.c iodev.c) target_link_libraries(pdsch_ue lte_phy) add_executable(pdsch_enodeb pdsch_enodeb.c) diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 78633c6b4..7aeb435f2 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -189,11 +189,13 @@ void base_init() { exit(-1); } - if (pdsch_init(&pdsch, 1234, cell)) { + if (pdsch_init(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } + pdsch_set_rnti(&pdsch, 1234); + if (pdsch_harq_init(&harq_process, &pdsch)) { fprintf(stderr, "Error initiating HARQ process\n"); exit(-1); @@ -365,7 +367,7 @@ int main(int argc, char **argv) { } else { #ifndef DISABLE_UHD vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples); - cuhd_send(uhd, output_buffer, sf_n_samples, 1); + cuhd_send(uhd, output_buffer, sf_n_samples, true); #endif } nf++; diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 9ec8c8885..70b6cb121 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -37,83 +37,59 @@ #include #include "liblte/phy/phy.h" - -#ifndef DISABLE_UHD -#include "liblte/cuhd/cuhd.h" -void *uhd; -#endif +#include "iodev.h" #ifndef DISABLE_GRAPHICS -#include "liblte/graphics/plot.h" -plot_real_t poutfft; -plot_complex_t pce; -plot_scatter_t pscatrecv, pscatequal; +void init_plots(); +void do_plots(ue_dl_t *q, uint32_t sf_idx); #endif -#define MHZ 1000000 -#define SAMP_FREQ 1920000 - -#define NOF_PORTS 2 - -float find_threshold = 9.0; -int nof_frames = -1; -int pkt_errors = 0, pkts_total = 0; -int frame_cnt; -char *input_file_name = NULL; -int disable_plots = 0; - -/* These are the number of PRBs used during the SYNC procedure */ -int sampling_nof_prb = 6; - -/* Number of samples in a subframe */ -int sf_n_samples; - -lte_cell_t cell; - -uint32_t cell_id_file = 1; - -int cell_id_initated = 0, mib_initiated = 0; -int frame_number; - -bool pbch_only = false; - int go_exit = 0; -float uhd_freq = 2600000000.0, uhd_gain = 20.0; -char *uhd_args = ""; +/* Local function definitions */ +void init_plots(); -filesource_t fsrc; -cf_t *input_buffer, *sf_buffer, *fft_buffer, *input_decim_buffer, *ce[MAX_PORTS]; -float *tmp_plot; -pbch_t pbch; -pcfich_t pcfich; -pdcch_t pdcch; -pdsch_t pdsch; -pdsch_harq_t harq_process; -regs_t regs; -lte_fft_t fft; -chest_t chest; -sync_frame_t sframe; +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + uint32_t cell_id_file; + uint32_t nof_prb_file; + uint16_t rnti; + int nof_subframes; + bool disable_plots; + bool pbch_only; + iodev_cfg_t io_config; +}prog_args_t; -#define CLRSTDOUT printf("\r\n"); fflush(stdout); printf("\r\n") +void args_default(prog_args_t *args) { + args->cell_id_file = 1; + args->nof_prb_file = 6; + args->rnti = SIRNTI; + args->nof_subframes = -1; + args->disable_plots = false; + args->pbch_only = false; + args->io_config.find_threshold = -1.0; + args->io_config.input_file_name = NULL; + args->io_config.uhd_args = ""; + args->io_config.uhd_freq = -1.0; + args->io_config.uhd_gain = 20.0; +} -#define DOWNSAMPLE_FACTOR(x, y) lte_symbol_sz(x) / lte_symbol_sz(y) - -void usage(char *prog) { - printf("Usage: %s [icagfndvtpb]\n", prog); - printf("\t-i input_file [Default use USRP]\n"); - printf("\t-c cell_id if reading from file [Default %d]\n", cell_id_file); +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog); + printf("\t-c cell_id if reading from file [Default %d]\n", args->cell_id_file); + printf("\t-p nof_prb if reading from file [Default %d]\n", args->nof_prb_file); + printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti); #ifndef DISABLE_UHD - printf("\t-a UHD args [Default %s]\n", uhd_args); - printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); - printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq / 1000000); + printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", args->io_config.uhd_gain); #else printf("\t UHD is disabled. CUHD library not available\n"); #endif - printf("\t-b Decode PBCH only [Default All]\n"); - printf("\t-p sampling_nof_prb [Default %d]\n", sampling_nof_prb); - printf("\t-n nof_frames [Default %d]\n", nof_frames); - printf("\t-t PSS threshold [Default %f]\n", find_threshold); + printf("\t-b Decode PBCH only [Default All channels]\n"); + printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); + printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold); #ifndef DISABLE_GRAPHICS printf("\t-d disable plots [Default enabled]\n"); #else @@ -122,59 +98,186 @@ void usage(char *prog) { printf("\t-v [set verbose to debug, default none]\n"); } -void parse_args(int argc, char **argv) { +void parse_args(prog_args_t *args, int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "icagfndvtpb")) != -1) { + args_default(args); + while ((opt = getopt(argc, argv, "icagfndvtbp")) != -1) { switch (opt) { case 'i': - input_file_name = argv[optind]; + args->io_config.input_file_name = argv[optind]; break; case 'c': - cell_id_file = atoi(argv[optind]); - break; - case 'a': - uhd_args = argv[optind]; - break; - case 'g': - uhd_gain = atof(argv[optind]); - break; - case 'f': - uhd_freq = atof(argv[optind]); - break; - case 'b': - pbch_only = true; - break; - case 't': - find_threshold = atof(argv[optind]); + args->cell_id_file = atoi(argv[optind]); break; case 'p': - sampling_nof_prb = atof(argv[optind]); + args->nof_prb_file = atoi(argv[optind]); + break; + case 'a': + args->io_config.uhd_args = argv[optind]; + break; + case 'g': + args->io_config.uhd_gain = atof(argv[optind]); + break; + case 'f': + args->io_config.uhd_freq = atof(argv[optind]); + break; + case 'b': + args->pbch_only = true; + break; + case 't': + args->io_config.find_threshold = atof(argv[optind]); break; case 'n': - nof_frames = atoi(argv[optind]); + args->nof_subframes = atoi(argv[optind]); break; case 'd': - disable_plots = 1; + args->disable_plots = true; break; case 'v': verbose++; break; default: - usage(argv[0]); + usage(args, argv[0]); exit(-1); } } + if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) { + usage(args, argv[0]); + } +} +/**********************************************************************/ + +void sigintHandler(int x) { + go_exit = 1; } +int main(int argc, char **argv) { + int ret; + cf_t *sf_buffer; + iodev_t iodev; + prog_args_t prog_args; + lte_cell_t cell; + ue_dl_t ue_dl; + bool ue_dl_initiated = false; + int64_t sf_cnt; + uint32_t sf_idx; + pbch_mib_t mib; + + parse_args(&prog_args, argc, argv); + + if (iodev_init(&iodev, &prog_args.io_config)) { + fprintf(stderr, "Error initiating input device\n"); + exit(-1); + } + + if (!prog_args.disable_plots) { + init_plots(); + } + + /* Setup SIGINT handler */ + printf("\n --- Press Ctrl+C to exit --- \n"); + signal(SIGINT, sigintHandler); + + /* Initialize frame and subframe counters */ + sf_cnt = 0; + sf_idx = 0; + + /* Main loop */ + while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { + + ret = iodev_receive(&iodev, &sf_buffer); + if (ret < 0) { + fprintf(stderr, "Error reading from input device (%d)\n", ret); + break; + } + + /* iodev_receive returns 1 if successfully read 1 aligned subframe */ + if (ret == 1) { + if (!ue_dl_initiated) { + if (iodev_isUSRP(&iodev)) { + cell = ue_sync_get_cell(&iodev.sframe); + mib = ue_sync_get_mib(&iodev.sframe); + } else { + cell.id = prog_args.cell_id_file; + cell.cp = CPNORM; + cell.nof_ports = 1; // TODO: Use prog_args + cell.nof_prb = prog_args.nof_prb_file; + mib.phich_resources = R_1; + mib.phich_length = PHICH_NORM; + } + if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti); + ue_dl_initiated = true; + } else { + if (iodev_isUSRP(&iodev)) { + sf_idx = ue_sync_get_sfidx(&iodev.sframe); + } + if (ue_dl_process(&ue_dl, sf_buffer, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti)) { + fprintf(stderr, "\nError running receiver\n");fflush(stdout); + exit(-1); + } + if (!(sf_cnt % 10)) { + printf("Cell ID: %3d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d/%d, BLER: %.1e\r", + cell.id, iodev.sframe.cur_cfo * 15, iodev.sframe.mean_time_offset / 5, iodev.sframe.peak_idx, + (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (int) ue_dl.nof_trials, (float) ue_dl.pkt_errors / ue_dl.pkts_total); + fflush(stdout); + if (VERBOSE_ISINFO()) { + printf("\n"); + } + } + if (!prog_args.disable_plots && sf_idx == 5) { + do_plots(&ue_dl, sf_idx); + } + } + if (iodev_isfile(&iodev)) { + sf_idx++; + if (sf_idx == NSUBFRAMES_X_FRAME) { + sf_idx = 0; + } + } + } + if (prog_args.nof_subframes > 0) { + sf_cnt++; + } + if (iodev_isfile(&iodev)) { + usleep(5000); + } + } + + if (ue_dl_initiated) { + ue_dl_free(&ue_dl); + } + iodev_free(&iodev); + + printf("\nBye\n"); + exit(0); +} + + + + +/********************************************************************** + * Plotting Functions + ***********************************************************************/ #ifndef DISABLE_GRAPHICS + +#include "liblte/graphics/plot.h" +plot_real_t poutfft; +plot_complex_t pce; +plot_scatter_t pscatrecv, pscatequal; + +float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)]; + void init_plots() { plot_init(); plot_real_init(&poutfft); plot_real_setTitle(&poutfft, "Output FFT - Magnitude"); plot_real_setLabels(&poutfft, "Index", "dB"); plot_real_setYAxisScale(&poutfft, -60, 0); - plot_real_setXAxisScale(&poutfft, 1, 504); plot_complex_init(&pce); plot_complex_setTitle(&pce, "Channel Estimates"); @@ -194,513 +297,20 @@ void init_plots() { plot_scatter_setYAxisScale(&pscatequal, -1, 1); } -#endif - - -/* This function initializes the objects defined as global variables */ -int base_init(int nof_prb) { +void do_plots(ue_dl_t *q, uint32_t sf_idx) { int i; - - int sf_n_re = 2 * CPNORM_NSYMB * nof_prb * RE_X_RB; - int sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb)); - - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) { - tmp_plot = malloc(sizeof(cf_t) * sf_n_re); - if (!tmp_plot) { - perror("malloc"); - return -1; + uint32_t nof_re = SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp); + uint32_t nof_symbols = q->harq_process[0].prb_alloc.re_sf[sf_idx]; + for (i = 0; i < nof_re; i++) { + tmp_plot[i] = 10 * log10f(cabsf(q->sf_symbols[i])); + if (isinf(tmp_plot[i])) { + tmp_plot[i] = -80; } - init_plots(); } -#else - printf("-- PLOTS are disabled. Graphics library not available --\n\n"); + plot_real_setNewData(&poutfft, tmp_plot, nof_re); + plot_complex_setNewData(&pce, q->ce[0], nof_re); + plot_scatter_setNewData(&pscatrecv, q->pdsch.pdsch_symbols[0], nof_symbols); + plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols); +} + #endif - - if (input_file_name) { - if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) { - return -1; - } - } else { - /* open UHD device */ -#ifndef DISABLE_UHD - printf("Opening UHD device...\n"); - if (cuhd_open(uhd_args, &uhd)) { - fprintf(stderr, "Error opening uhd\n"); - return -1; - } -#else - printf("Error UHD not available. Select an input file\n"); - return -1; -#endif - } - - /* For the input buffer, we allocate space for 1 ms of samples */ - input_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); - if (!input_buffer) { - perror("malloc"); - return -1; - } - - input_decim_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); - if (!input_decim_buffer) { - perror("malloc"); - return -1; - } - - /* This buffer is the aligned version of input_buffer */ - sf_buffer = (cf_t*) malloc(sf_n_samples * sizeof(cf_t)); - if (!sf_buffer) { - perror("malloc"); - return -1; - } - - /* For the rest of the buffers, we allocate for the number of RE in one subframe */ - fft_buffer = (cf_t*) malloc(sf_n_re * sizeof(cf_t)); - if (!fft_buffer) { - perror("malloc"); - return -1; - } - - for (i = 0; i < MAX_PORTS; i++) { - ce[i] = (cf_t*) malloc(sf_n_re * sizeof(cf_t)); - if (!ce[i]) { - perror("malloc"); - return -1; - } - } - - if (sync_frame_init(&sframe, DOWNSAMPLE_FACTOR(nof_prb,6))) { - fprintf(stderr, "Error initiating PSS/SSS\n"); - return -1; - } - - if (chest_init(&chest, LINEAR, nof_prb * RE_X_RB, CPNORM_NSYMB, NOF_PORTS)) { - fprintf(stderr, "Error initializing equalizer\n"); - return -1; - } - - if (lte_fft_init(&fft, CPNORM, nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); - return -1; - } - - return 0; -} - -void base_free() { - int i; - - if (input_file_name) { - filesource_free(&fsrc); - } else { -#ifndef DISABLE_UHD - cuhd_close(uhd); -#endif - } - -#ifndef DISABLE_GRAPHICS - if (!disable_plots) { - if (tmp_plot) { - free(tmp_plot); - } - plot_exit(); - } -#endif - - pbch_free(&pbch); - pdsch_free(&pdsch); - pdcch_free(&pdcch); - regs_free(®s); - sync_frame_free(&sframe); - lte_fft_free(&fft); - chest_free(&chest); - - free(input_buffer); - free(input_decim_buffer); - free(fft_buffer); - for (i = 0; i < MAX_PORTS; i++) { - free(ce[i]); - } -} - -int mib_init(phich_resources_t phich_resources, phich_length_t phich_length) { - - if (!lte_cell_isvalid(&cell)) { - fprintf(stderr, "Invalid cell properties: Id=%d, Ports=%d, PRBs=%d\n", - cell.id, cell.nof_ports, cell.nof_prb); - return -1; - } - if (cell.nof_prb > sampling_nof_prb) { - fprintf(stderr, "Error sampling frequency is %.2f Mhz but captured signal has %d PRB\n", - (float) lte_sampling_freq_hz(sampling_nof_prb)/MHZ, cell.nof_prb); - return -1; - } - if (regs_init(®s, phich_resources, phich_length, cell)) { - fprintf(stderr, "Error initiating REGs\n"); - return -1; - } - - if (pcfich_init(&pcfich, ®s, cell)) { - fprintf(stderr, "Error creating PCFICH object\n"); - return -1; - } - - if (pdcch_init(&pdcch, ®s, cell)) { - fprintf(stderr, "Error creating PDCCH object\n"); - return -1; - } - - if (pdsch_init(&pdsch, 1234, cell)) { - fprintf(stderr, "Error creating PDSCH object\n"); - return -1; - } - - if (pdsch_harq_init(&harq_process, &pdsch)) { - fprintf(stderr, "Error initiating HARQ process\n"); - return -1; - } - - chest_set_nof_ports(&chest, cell.nof_ports); - - mib_initiated = 1; - - DEBUG("Receiver initiated cell.id=%d nof_prb=%d\n", cell.id, cell.nof_prb); - - return 0; -} - -int cell_id_init(int nof_prb, int cell_id) { - - lte_cell_t cell; - - cell.id = cell_id; - cell.nof_prb = nof_prb; - cell.nof_ports = 2; - cell.cp = CPNORM; - - if (chest_ref_LTEDL(&chest, cell)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - - if (pbch_init(&pbch, cell)) { - fprintf(stderr, "Error initiating PBCH\n"); - return -1; - } - - cell_id_initated = 1; - DEBUG("PBCH initiated cell_id=%d\n", cell_id); - - return 0; -} - -char data[10000]; - -int pdsch_run(cf_t *input, uint32_t sf_idx) { - uint32_t cfi, cfi_distance, i; - cf_t *input_decim; - ra_pdsch_t ra_dl; - dci_location_t locations[10]; - dci_msg_t dci_msg; - uint32_t nof_locations; - - /* Downsample if the signal bandwith is shorter */ - if (sampling_nof_prb > cell.nof_prb) { - decim_c(input, input_decim_buffer, sf_n_samples, DOWNSAMPLE_FACTOR(sampling_nof_prb, cell.nof_prb)); - input_decim = input_decim_buffer; - } else { - input_decim = input; - } - - lte_fft_run_sf(&fft, input_decim, fft_buffer); - - /* Get channel estimates for each port */ - chest_ce_sf(&chest, fft_buffer, ce, sf_idx); - - /* First decode PCFICH and obtain CFI */ - if (pcfich_decode(&pcfich, fft_buffer, ce, sf_idx, &cfi, &cfi_distance)<0) { - fprintf(stderr, "Error decoding PCFICH\n"); - return -1; - } - - INFO("Decoded CFI=%d with distance %d\n", cfi, cfi_distance); - - if (regs_set_cfi(®s, cfi)) { - fprintf(stderr, "Error setting CFI\n"); - return -1; - } - - /* Search only UE-specific locations */ - nof_locations = pdcch_ue_locations(&pdcch, locations, 10, sf_idx, cfi, 1234); - - uint16_t crc_rem = 0; - for (i=0;i #include "liblte/config.h" + +#include "liblte/phy/resampling/interp.h" #include "liblte/phy/ch_estimation/refsignal.h" -#include "liblte/phy/filter/filter2d.h" #include "liblte/phy/common/phy_common.h" typedef _Complex float cf_t; /* this is only a shortcut */ -typedef enum {LINEAR} chest_interp_t; typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, - int M, - int len, - int off_st, - int off_end); + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); /** This is an OFDM channel estimator. * It works with any reference signal pattern, provided by the object @@ -61,11 +61,12 @@ typedef struct LIBLTE_API { uint32_t nof_symbols; refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; - interpolate_fnc_t interp; + interp_t interp_time[MAX_PORTS]; + interp_t interp_freq[MAX_PORTS]; + }chest_t; LIBLTE_API int chest_init(chest_t *q, - chest_interp_t interp, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports); @@ -76,7 +77,6 @@ LIBLTE_API int chest_set_nof_ports(chest_t *q, uint32_t nof_ports); LIBLTE_API int chest_init_LTEDL(chest_t *q, - chest_interp_t interp, lte_cell_t cell); LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 422fe8699..29e8c233e 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -59,6 +59,11 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define MAX_NSYMB 7 +#define MAX_PRB 110 +#define RE_X_RB 12 + +#define SYMBOL_SZ_MAX 2048 + #define CPNORM_NSYMB 7 #define CPNORM_SF_NSYMB 2*CPNORM_NSYMB #define CPNORM_0_LEN 160 @@ -79,20 +84,21 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN))) #define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) -#define SLOT_LEN(symbol_sz, cp) CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz) +#define SLOT_LEN(symbol_sz, cp) (CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz)) -#define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz) -#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz) +#define SF_LEN_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz)) +#define SF_LEN_CPEXT(symbol_sz) (2*SLOT_LEN_CPEXT(symbol_sz)) #define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp)) +#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX, CPNORM) + +#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp)) +#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp)) #define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) #define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx) -#define MAX_PRB 110 -#define RE_X_RB 12 - #define RS_VSHIFT(cell_id) (cell_id%6) #define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2) @@ -136,8 +142,15 @@ LIBLTE_API enum band_geographical_area { LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell); +LIBLTE_API bool lte_N_id_2_isvalid(uint32_t N_id_2); + +LIBLTE_API bool lte_N_id_1_isvalid(uint32_t N_id_1); + +LIBLTE_API bool lte_symbol_sz_isvalid(uint32_t symbol_sz); + LIBLTE_API int lte_symbol_sz(uint32_t nof_prb); + LIBLTE_API int lte_sampling_freq_hz(uint32_t nof_prb); LIBLTE_API uint32_t lte_re_x_prb(uint32_t ns, @@ -151,6 +164,8 @@ LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id, LIBLTE_API int lte_cb_size(uint32_t index); +LIBLTE_API char *lte_cp_string(lte_cp_t cp); + LIBLTE_API char *lte_mod_string(lte_mod_t mod); LIBLTE_API uint32_t lte_mod_bits_x_symbol(lte_mod_t mod); diff --git a/lte/phy/include/liblte/phy/phch/pdcch.h b/lte/phy/include/liblte/phy/phch/pdcch.h index 87aa91eb8..f15dd1519 100644 --- a/lte/phy/include/liblte/phy/phch/pdcch.h +++ b/lte/phy/include/liblte/phy/phch/pdcch.h @@ -44,12 +44,6 @@ typedef _Complex float cf_t; -#define NOF_COMMON_FORMATS 2 -const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C }; - -#define NOF_UE_FORMATS 2 -const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0 - typedef enum LIBLTE_API { SEARCH_UE, SEARCH_COMMON diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index 6800e1707..44717689b 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -43,7 +43,7 @@ #include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/regs.h" -#define TDEC_ITERATIONS 1 +#define TDEC_ITERATIONS 6 typedef _Complex float cf_t; @@ -73,8 +73,9 @@ typedef struct LIBLTE_API { lte_cell_t cell; uint32_t max_symbols; - uint16_t rnti; - + bool rnti_is_set; + uint16_t rnti; + /* buffers */ // void buffers are shared for tx and rx cf_t *ce[MAX_PORTS]; @@ -96,11 +97,13 @@ typedef struct LIBLTE_API { }pdsch_t; LIBLTE_API int pdsch_init(pdsch_t *q, - uint16_t user_rnti, lte_cell_t cell); LIBLTE_API void pdsch_free(pdsch_t *q); +LIBLTE_API int pdsch_set_rnti(pdsch_t *q, + uint16_t rnti); + LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p, pdsch_t *pdsch); diff --git a/lte/phy/include/liblte/phy/phch/ue_sync.h b/lte/phy/include/liblte/phy/phch/ue_sync.h new file mode 100644 index 000000000..cf1e2f7a2 --- /dev/null +++ b/lte/phy/include/liblte/phy/phch/ue_sync.h @@ -0,0 +1,168 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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 UE_SYNC_ +#define UE_SYNC_ + +#include + +#include "liblte/config.h" +#include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/cfo.h" +#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/common/fft.h" + +/************************************************************** + * + * This object automatically manages the cell association and + * synchronization procedure. By default, it associates with the + * CELL whose correlation peak to average ratio is the highest. + * + * TODO: Associate with arbitrary CELL ID + * + * The main function is ue_sync_get_buffer(), which returns a pointer + * to the aligned subframe of samples (before FFT). This function + * should be called regularly, returning every 1 ms. It reads from the + * USRP, aligns the samples to the subframe and performs time/freq synch. + * + * The function returns 0 during the cell association procedure, which includes + * PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency + * adjustment (according to signal bandwidth) and resynchronization. + * + * The function returns 1 when the signal is correctly acquired and the + * returned buffer is aligned with the subframe. + * + * + *************************************************************/ + +typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t; + +#define SYNC_PBCH_NOF_PRB 6 +#define SYNC_PBCH_NOF_PORTS 2 + +#define TRACK_MAX_LOST 10 +#define PAR_THRESHOLD_FIND 20 + +#define NOF_MIB_DECODES 10 + +#define MEASURE_EXEC_TIME + +typedef struct LIBLTE_API { + sync_t s; + + void *stream; + double (*set_rate_callback)(void*, double); + int (*recv_callback)(void*, void*, uint32_t); + + ue_sync_state_t state; + + cf_t *input_buffer; + cf_t *sf_symbols; + cf_t *ce[SYNC_PBCH_NOF_PORTS]; + + /* These count half frames (5ms) */ + uint64_t frame_ok_cnt; + uint32_t frame_no_cnt; + uint32_t frame_total_cnt; + + /* this is the system frame number (SFN) */ + uint32_t frame_number; + + lte_cell_t cell; + uint32_t sf_idx; + + cfo_t cfocorr; + float cur_cfo; + + /* Variables for PBCH decoding */ + pbch_mib_t mib; + lte_fft_t fft; + chest_t chest; + pbch_t pbch; + bool pbch_initialized; + uint32_t pbch_decoded; + bool pbch_decode_always; + bool pbch_decoder_enabled; + uint32_t pbch_last_trial; + + bool decode_sss_on_track; + + uint32_t peak_idx; + int time_offset; + float mean_time_offset; + #ifdef MEASURE_EXEC_TIME + float mean_exec_time; + #endif +} ue_sync_t; + + +LIBLTE_API int ue_sync_init(ue_sync_t *q, + double (set_rate_callback)(void*, double), + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); + +LIBLTE_API void ue_sync_free(ue_sync_t *q); + +LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q, + cf_t **sf_symbols); + + +LIBLTE_API void ue_sync_reset(ue_sync_t *q); + +LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q, bool enabled); + +LIBLTE_API void ue_sync_set_threshold(ue_sync_t *q, + float threshold); + +LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q); + +LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q); + +LIBLTE_API uint32_t ue_sync_get_peak_idx(ue_sync_t *q); + +LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q); + +LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q); + +LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q); + +LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q); + +LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q); + + + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index 0b5ba19d2..3de436895 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -50,10 +50,14 @@ #include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/fft.h" - + #include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/ch_estimation/refsignal.h" +#include "liblte/phy/resampling/interp.h" +#include "liblte/phy/resampling/decim.h" +#include "liblte/phy/resampling/resample_arb.h" + #include "liblte/phy/channel/ch_awgn.h" #include "liblte/phy/fec/viterbi.h" @@ -88,18 +92,15 @@ #include "liblte/phy/phch/pbch.h" #include "liblte/phy/phch/pcfich.h" #include "liblte/phy/phch/phich.h" +#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/phch/ue_dl.h" #include "liblte/phy/scrambling/scrambling.h" -#include "liblte/phy/resampling/interp.h" -#include "liblte/phy/resampling/decim.h" -#include "liblte/phy/resampling/resample_arb.h" - #include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/sfo.h" #include "liblte/phy/sync/sss.h" #include "liblte/phy/sync/sync.h" -#include "liblte/phy/sync/sync_frame.h" #include "liblte/phy/sync/cfo.h" #ifdef __cplusplus diff --git a/lte/phy/include/liblte/phy/resampling/interp.h b/lte/phy/include/liblte/phy/resampling/interp.h index 3c0a652e7..c39c83602 100644 --- a/lte/phy/include/liblte/phy/resampling/interp.h +++ b/lte/phy/include/liblte/phy/resampling/interp.h @@ -26,15 +26,73 @@ */ #ifndef INTERP_H -#define INTERP_H_ +#define INTERP_H + +#include #include "liblte/config.h" typedef _Complex float cf_t; +typedef enum LIBLTE_API {LINEAR} interp_type_t; -LIBLTE_API void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end); -LIBLTE_API void interp_linear_c(cf_t *input, cf_t *output, int M, int len); -LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len); +typedef struct LIBLTE_API { + interp_type_t type; + + float *in_mag; + float *in_arg; + float *in_mag0; + float *in_arg0; + float *in_mag1; + float *in_arg1; + + float *out_mag; + float *out_arg; + float *out_arg2; + int16_t *table_idx; + + cf_t *out_cexp; + cf_t *out_prod; + + cf_t *cexptable; + + uint32_t len; + uint32_t M; + +}interp_t; + +LIBLTE_API int interp_init(interp_t *q, + interp_type_t type, + uint32_t len, + uint32_t M); + +LIBLTE_API void interp_free(interp_t *q); + +LIBLTE_API void interp_run(interp_t *q, + cf_t *input, + cf_t *output); + +LIBLTE_API void interp_run_offset(interp_t *q, + cf_t *input, + cf_t *output, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_offset(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_c(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len); + +LIBLTE_API void interp_linear_f(float *input, + float *output, + uint32_t M, + uint32_t len); #endif // INTERP_H diff --git a/lte/phy/include/liblte/phy/sync/cfo.h b/lte/phy/include/liblte/phy/sync/cfo.h index b3f282fe0..b88683ad1 100644 --- a/lte/phy/include/liblte/phy/sync/cfo.h +++ b/lte/phy/include/liblte/phy/sync/cfo.h @@ -49,10 +49,20 @@ typedef struct LIBLTE_API { cf_t *cur_cexp; }cfo_t; -LIBLTE_API int cfo_init(cfo_t *h, int nsamples); +LIBLTE_API int cfo_init(cfo_t *h, + uint32_t nsamples); + LIBLTE_API void cfo_free(cfo_t *h); -LIBLTE_API void cfo_set_tol(cfo_t *h, float tol); -LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq); +LIBLTE_API int cfo_realloc(cfo_t *h, + uint32_t samples); + +LIBLTE_API void cfo_set_tol(cfo_t *h, + float tol); + +LIBLTE_API void cfo_correct(cfo_t *h, + cf_t *input, + cf_t *output, + float freq); #endif // CFO_ diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index 9e0e87727..a27f92f6b 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -42,8 +42,7 @@ typedef _Complex float cf_t; /* this is only a shortcut */ #define DEFAULT_CORRELATION_TH 10000 #define DEFAULT_NOSYNC_TIMEOUT 5 -#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128 -#define PSS_LEN 62 +#define PSS_LEN 62 #define PSS_RE 6*12 @@ -67,50 +66,47 @@ typedef struct LIBLTE_API { conv_fft_cc_t conv_fft; #endif - int frame_size; - int N_id_2; + uint32_t frame_size; + uint32_t N_id_2; + uint32_t fft_size; cf_t *pss_signal_freq[3]; // One sequence for each N_id_2 cf_t *tmp_input; float *conv_abs; cf_t *conv_output; - -#ifdef ENABLE_HL - cf_t *frame_buffer; - cf_t *tmp_nco; - float current_cfo; - bool cfo_auto; - int nof_nosync_frames; - int nosync_timeout_frames; - float correlation_threshold; - int frame_start_idx; - int fb_wp; -#endif - - + }pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; /* Basic functionality */ -LIBLTE_API int pss_synch_init(pss_synch_t *q, int frame_size); +LIBLTE_API int pss_synch_init_fft(pss_synch_t *q, + uint32_t frame_size, + uint32_t fft_size); + +LIBLTE_API int pss_synch_init(pss_synch_t *q, + uint32_t frame_size); + LIBLTE_API void pss_synch_free(pss_synch_t *q); -LIBLTE_API int pss_generate(cf_t *signal, int N_id_2); -LIBLTE_API void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp); -LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2); -LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value); -LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv); +LIBLTE_API int pss_generate(cf_t *signal, + uint32_t N_id_2); +LIBLTE_API void pss_put_slot(cf_t *pss_signal, + cf_t *slot, + uint32_t nof_prb, + lte_cp_t cp); -/* Automatic frame management functions (for periodic calling) */ -LIBLTE_API int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples); -LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames); -LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold); -LIBLTE_API void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto); -LIBLTE_API float pss_synch_get_cfo(pss_synch_t *q); -LIBLTE_API int pss_synch_get_frame_start_idx(pss_synch_t *q); +LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, + uint32_t N_id_2); +LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, + cf_t *input, + float *corr_peak_value, + float *corr_mean_value); + +LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, + cf_t *pss_recv); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/sync/sss.h b/lte/phy/include/liblte/phy/sync/sss.h index 48c78add4..bdc219542 100644 --- a/lte/phy/include/liblte/phy/sync/sss.h +++ b/lte/phy/include/liblte/phy/sync/sss.h @@ -38,17 +38,12 @@ typedef _Complex float cf_t; /* this is only a shortcut */ -/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1). - * subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz - * symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz - */ -#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz) -#define SSS_POS_SYMBOL 33 -#define SSS_DFT_LEN 128 -#define N_SSS 31 +#define N_SSS 31 #define SSS_LEN 2*N_SSS +#define SSS_MAX_FFT_LEN 2048 + struct sss_tables{ int z1[N_SSS][N_SSS]; int c[2][N_SSS]; @@ -56,7 +51,7 @@ struct sss_tables{ }; /* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement. - * Should use vect_malloc() to make it platform agnostic. + * Should use vec_malloc() to make it platform agnostic. */ struct fc_tables{ cf_t z1[N_SSS+1][N_SSS+1]; @@ -69,35 +64,68 @@ struct fc_tables{ typedef struct LIBLTE_API { dft_plan_t dftp_input; + + uint32_t fft_size; float corr_peak_threshold; - int symbol_sz; - int subframe_sz; - int N_id_2; - - int N_id_1_table[30][30]; + uint32_t symbol_sz; + uint32_t subframe_sz; + uint32_t N_id_2; + + uint32_t N_id_1_table[30][30]; struct fc_tables fc_tables[3]; // one for each N_id_2 }sss_synch_t; /* Basic functionality */ -LIBLTE_API int sss_synch_init(sss_synch_t *q); +LIBLTE_API int sss_synch_init(sss_synch_t *q, + uint32_t fft_size); + +LIBLTE_API int sss_synch_realloc(sss_synch_t *q, + uint32_t fft_size); + LIBLTE_API void sss_synch_free(sss_synch_t *q); -LIBLTE_API void sss_generate(float *signal0, float *signal5, int cell_id); -LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp); -LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2); +LIBLTE_API void sss_generate(float *signal0, + float *signal5, + uint32_t cell_id); -LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, - int *m1, float *m1_value); -LIBLTE_API int sss_synch_subframe(int m0, int m1); -LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1); +LIBLTE_API void sss_put_slot(float *sss, + cf_t *symbol, + uint32_t nof_prb, + lte_cp_t cp); -LIBLTE_API int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1); -LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold); -LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz); -LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz); +LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, + uint32_t N_id_2); + +LIBLTE_API int sss_synch_m0m1(sss_synch_t *q, + cf_t *input, + uint32_t *m0, + float *m0_value, + uint32_t *m1, + float *m1_value); + +LIBLTE_API uint32_t sss_synch_subframe(uint32_t m0, + uint32_t m1); + +LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q, + uint32_t m0, + uint32_t m1); + +LIBLTE_API int sss_synch_frame(sss_synch_t *q, + cf_t *input, + uint32_t *subframe_idx, + uint32_t *N_id_1); + +LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, + float threshold); + +LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, + uint32_t symbol_sz); + +LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, + uint32_t subframe_sz); /* High-level API */ @@ -105,18 +133,18 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz); typedef struct LIBLTE_API { sss_synch_t obj; struct sss_synch_init { - int N_id_2; + uint32_t N_id_2; } init; cf_t *input; - int in_len; + uint32_t in_len; struct sss_synch_ctrl_in { - int symbol_sz; - int subframe_sz; - int correlation_threshold; + uint32_t symbol_sz; + uint32_t subframe_sz; + uint32_t correlation_threshold; } ctrl_in; struct sss_synch_ctrl_out { - int subframe_idx; - int N_id_1; + uint32_t subframe_idx; + uint32_t N_id_1; } ctrl_out; }sss_synch_hl; diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index 0288b29d6..6f40777dd 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -30,11 +30,15 @@ #define SYNC_ #include +#include #include "liblte/config.h" #include "liblte/phy/sync/pss.h" #include "liblte/phy/sync/sss.h" +#define FFT_SIZE_MIN 64 +#define FFT_SIZE_MAX 2048 + /** * * This object performs time and frequency synchronization using the PSS and SSS signals. @@ -49,19 +53,19 @@ enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; -#define TRACK_THRESHOLD 10.0 -#define TRACK_LEN 300 - typedef struct LIBLTE_API { - pss_synch_t pss; + pss_synch_t pss_find; pss_synch_t pss_track; sss_synch_t sss; enum sync_pss_det pss_mode; - float threshold; + float find_threshold; + float track_threshold; float peak_to_avg; - int N_id_2; - int N_id_1; - int slot_id; + uint32_t N_id_2; + uint32_t N_id_1; + uint32_t slot_id; + uint32_t fft_size; + uint32_t find_frame_size; float cfo; bool detect_cp; bool sss_en; @@ -69,42 +73,72 @@ typedef struct LIBLTE_API { }sync_t; -LIBLTE_API int sync_init(sync_t *q, int frame_size); +LIBLTE_API int sync_init(sync_t *q, + uint32_t find_frame_size, + uint32_t track_frame_size, + uint32_t fft_size); + LIBLTE_API void sync_free(sync_t *q); +LIBLTE_API int sync_realloc(sync_t *q, + uint32_t find_frame_size, + uint32_t track_frame_size, + uint32_t fft_size); + /* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be subframe_size long at least */ -LIBLTE_API int sync_find(sync_t *q, cf_t *input); +LIBLTE_API int sync_find(sync_t *q, + cf_t *input, + uint32_t *peak_position); /* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be TRACK_LEN long at least */ -LIBLTE_API int sync_track(sync_t *q, cf_t *input); +LIBLTE_API int sync_track(sync_t *q, + cf_t *input, + uint32_t offset, + uint32_t *peak_position); /* Sets the threshold for peak comparison */ -LIBLTE_API void sync_set_threshold(sync_t *q, float threshold); +LIBLTE_API void sync_set_threshold(sync_t *q, + float find_threshold, + float track_threshold); + /* Set peak comparison to absolute value */ LIBLTE_API void sync_pss_det_absolute(sync_t *q); + /* Set peak comparison to relative to the mean */ LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); /* Gets the slot id (0 or 10) */ -LIBLTE_API int sync_get_slot_id(sync_t *q); +LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); + /* Gets the last peak-to-average ratio */ LIBLTE_API float sync_get_peak_to_avg(sync_t *q); + /* Gets the N_id_2 from the last call to synch_run() */ -LIBLTE_API int sync_get_N_id_2(sync_t *q); +LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q); + /* Gets the N_id_1 from the last call to synch_run() */ -LIBLTE_API int sync_get_N_id_1(sync_t *q); +LIBLTE_API uint32_t sync_get_N_id_1(sync_t *q); + /* Gets the Physical CellId from the last call to synch_run() */ LIBLTE_API int sync_get_cell_id(sync_t *q); + /* Gets the CFO estimation from the last call to synch_run() */ LIBLTE_API float sync_get_cfo(sync_t *q); + /* Gets the CP length estimation from the last call to synch_run() */ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q); + /* Enables/Disables SSS detection */ -LIBLTE_API void sync_sss_en(sync_t *q, bool enabled); +LIBLTE_API void sync_sss_en(sync_t *q, + bool enabled); + +LIBLTE_API bool sync_sss_detected(sync_t *q); + /* Enables/Disables CP detection */ -LIBLTE_API void sync_cp_en(sync_t *q, bool enabled); +LIBLTE_API void sync_cp_en(sync_t *q, + bool enabled); #endif // SYNC_ diff --git a/lte/phy/include/liblte/phy/sync/sync_frame.h b/lte/phy/include/liblte/phy/sync/sync_frame.h deleted file mode 100644 index afe73c375..000000000 --- a/lte/phy/include/liblte/phy/sync/sync_frame.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE 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 Lesser General Public License for more details. - * - * A copy of the GNU Lesser 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 SYNC_FRAME_ -#define SYNC_FRAME_ - -#include - -#include "liblte/config.h" -#include "liblte/phy/sync/sync.h" -#include "liblte/phy/sync/cfo.h" - -/** - * - * Uses sync object to automatically manage the FIND and TRACKING states. - * It is suposed to work on a subframe basis. The input signal must be sampled at - * a frequency integer multiple of 1.92 MHz. The signal is internally downsampled - * and fed to the sync object. - * - * This object also deals with frame alignment and CFO correction, returning an - * output signal aligned both in time and frequency. - */ - -enum sync_frame_state { SF_FIND, SF_TRACK }; - -#define SYNC_SF_LEN 1920 // 1ms at 1.92 MHz - -#define TRACK_MAX_LOST 10 - - -typedef struct LIBLTE_API { - sync_t s; - enum sync_frame_state state; - uint32_t downsampling; - resample_arb_t resample; - unsigned long frame_cnt; - bool fb_wp; - uint32_t frame_size; - cf_t *input_buffer; - cf_t *input_downsampled; - cfo_t cfocorr; - float cur_cfo; - uint32_t peak_idx; - uint32_t cell_id; - float timeoffset; - uint32_t last_found; - uint32_t sf_idx; -}sync_frame_t; - - -/* Initializes the automatic tracker, setting the downsampling ratio for the input signal. - * downsampling is the ratio of the provided signal sampling frequency to 1.92 Mhz. E.g. if input is sampled at 3.84 Mhz, - * downsampling should be 2. -*/ -LIBLTE_API int sync_frame_init(sync_frame_t *q, - uint32_t downsampling); - -LIBLTE_API void sync_frame_free(sync_frame_t *q); - -LIBLTE_API void sync_frame_set_threshold(sync_frame_t *q, - float threshold); - -LIBLTE_API uint32_t sync_frame_cell_id(sync_frame_t *q); - -LIBLTE_API uint32_t sync_frame_sfidx(sync_frame_t *q); - -/* Automatically time/freq synchronizes the input signal. Returns 1 if the signal is synched and locked, - * and fills the output buffer with the time and frequency aligned version of the signal. - * If 0 is returned, the PSS was not found. -1 is returned in case of error. - * - * The provided signal can be sampled at an integer multiple of 1.92 Mhz. - * The sampling ratio is provided when calling the sync_auto_reset() function. - * - * The buffer input must have subframe_size samples (used in sync_init) - */ -LIBLTE_API int sync_frame_push(sync_frame_t *q, - cf_t *input, - cf_t *output); - -/* Resets the automatic tracker */ -LIBLTE_API void sync_frame_reset(sync_frame_t *q); - - - - -#endif // SYNC_FRAME_ - diff --git a/lte/phy/include/liblte/phy/utils/cexptab.h b/lte/phy/include/liblte/phy/utils/cexptab.h index 058ea81c4..6922eff32 100644 --- a/lte/phy/include/liblte/phy/utils/cexptab.h +++ b/lte/phy/include/liblte/phy/utils/cexptab.h @@ -30,19 +30,28 @@ #define CEXPTAB_ #include +#include #include "liblte/config.h" typedef _Complex float cf_t; typedef struct LIBLTE_API { - int size; + uint32_t size; cf_t *tab; }cexptab_t; -LIBLTE_API int cexptab_init(cexptab_t *nco, int size); +LIBLTE_API int cexptab_init(cexptab_t *nco, + uint32_t size); + LIBLTE_API void cexptab_free(cexptab_t *nco); -LIBLTE_API void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len); -LIBLTE_API void cexptab_gen_direct(cf_t *x, float freq, int len); +LIBLTE_API void cexptab_gen(cexptab_t *nco, + cf_t *x, + float freq, + uint32_t len); + +LIBLTE_API void cexptab_gen_direct(cf_t *x, + float freq, + uint32_t len); #endif // CEXPTAB_ diff --git a/lte/phy/include/liblte/phy/utils/convolution.h b/lte/phy/include/liblte/phy/utils/convolution.h index 99c058f02..ed9404738 100644 --- a/lte/phy/include/liblte/phy/utils/convolution.h +++ b/lte/phy/include/liblte/phy/utils/convolution.h @@ -32,23 +32,36 @@ #include "liblte/config.h" #include "liblte/phy/utils/dft.h" +typedef _Complex float cf_t; + typedef struct LIBLTE_API { - _Complex float *input_fft; - _Complex float *filter_fft; - _Complex float *output_fft; - _Complex float *output_fft2; - int input_len; - int filter_len; - int output_len; + cf_t *input_fft; + cf_t *filter_fft; + cf_t *output_fft; + cf_t *output_fft2; + uint32_t input_len; + uint32_t filter_len; + uint32_t output_len; dft_plan_t input_plan; dft_plan_t filter_plan; dft_plan_t output_plan; }conv_fft_cc_t; -LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len); -LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *state); -LIBLTE_API int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output); +LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *q, + uint32_t input_len, + uint32_t filter_len); -LIBLTE_API int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len); +LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *q); + +LIBLTE_API uint32_t conv_fft_cc_run(conv_fft_cc_t *q, + cf_t *input, + cf_t *filter, + cf_t *output); + +LIBLTE_API uint32_t conv_cc(cf_t *input, + cf_t *filter, + cf_t *output, + uint32_t input_len, + uint32_t filter_len); #endif // CONVOLUTION_H_ diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 4456f8036..1b0547cb9 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -30,51 +30,74 @@ #define VECTOR_ #include +#include #include "liblte/config.h" typedef _Complex float cf_t; /** Return the sum of all the elements */ -LIBLTE_API int vec_acc_ii(int *x, int len); -LIBLTE_API float vec_acc_ff(float *x, int len); -LIBLTE_API cf_t vec_acc_cc(cf_t *x, int len); +LIBLTE_API int vec_acc_ii(int *x, uint32_t len); +LIBLTE_API float vec_acc_ff(float *x, uint32_t len); +LIBLTE_API cf_t vec_acc_cc(cf_t *x, uint32_t len); -LIBLTE_API void *vec_malloc(int size); +LIBLTE_API void *vec_malloc(uint32_t size); + +LIBLTE_API void *vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size); /* print vectors */ -LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, int len); -LIBLTE_API void vec_fprint_f(FILE *stream, float *x, int len); -LIBLTE_API void vec_fprint_b(FILE *stream, char *x, int len); -LIBLTE_API void vec_fprint_i(FILE *stream, int *x, int len); +LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, uint32_t len); +LIBLTE_API void vec_fprint_f(FILE *stream, float *x, uint32_t len); +LIBLTE_API void vec_fprint_b(FILE *stream, char *x, uint32_t len); +LIBLTE_API void vec_fprint_i(FILE *stream, int *x, uint32_t len); +LIBLTE_API void vec_fprint_hex(FILE *stream, char *x, uint32_t len); + +/* Saves a vector to a file */ +LIBLTE_API void vec_save_file(char *filename, void *buffer, uint32_t len); /* sum two vectors */ -LIBLTE_API void vec_sum_ch(char *z, char *x, char *y, int len); -LIBLTE_API void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len); +LIBLTE_API void vec_sum_ch(char *x, char *y, char *z, uint32_t len); +LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* substract two vectors z=x-y */ +LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len); /* scalar product */ -LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len); -LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len); +LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len); +LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len); +LIBLTE_API void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); + +LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); + +LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len); /* vector product (element-wise) */ -LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len); -LIBLTE_API void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len); +LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); + +/* vector product (element-wise) */ +LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); + +LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); +LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len); /* z=x/y vector division (element-wise) */ -LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len); +LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* conjugate */ -LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, int len); +LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len); /* average vector power */ -LIBLTE_API float vec_avg_power_cf(cf_t *x, int len); +LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len); /* return the index of the maximum value in the vector */ -LIBLTE_API int vec_max_fi(float *x, int len); +LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len); /* quantify vector of floats and convert to unsigned char */ -LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len); +LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len); /* magnitude of each vector element */ -LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, int len); +LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, uint32_t len); + +/* argument of each vector element */ +LIBLTE_API void vec_arg_cf(cf_t *x, float *arg, uint32_t len); #endif // VECTOR_ diff --git a/lte/phy/lib/CMakeLists.txt b/lte/phy/lib/CMakeLists.txt index ec06db805..bbb80299c 100644 --- a/lte/phy/lib/CMakeLists.txt +++ b/lte/phy/lib/CMakeLists.txt @@ -29,13 +29,13 @@ FIND_PACKAGE(FFTW3F REQUIRED) # TODO: distribute kissfft instead INCLUDE_DIRECTORIES(${FFTW3F_INCLUDE_DIRS}) IF(${DISABLE_VOLK}) - IF(${DISABLE_VOLK} EQUAL 0) - FIND_PACKAGE(Volk) - ELSE(${DISABLE_VOLK} EQUAL 0) - MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") - ENDIF(${DISABLE_VOLK} EQUAL 0) + IF(${DISABLE_VOLK} EQUAL 0) + FIND_PACKAGE(Volk) + ELSE(${DISABLE_VOLK} EQUAL 0) + MESSAGE(STATUS "VOLK library disabled (DISABLE_VOLK=1)") + ENDIF(${DISABLE_VOLK} EQUAL 0) ELSE(${DISABLE_VOLK}) - FIND_PACKAGE(Volk) + FIND_PACKAGE(Volk) ENDIF(${DISABLE_VOLK}) ######################################################################## @@ -44,10 +44,10 @@ ENDIF(${DISABLE_VOLK}) FILE(GLOB modules *) SET(SOURCES_ALL "") FOREACH (_module ${modules}) - IF(IS_DIRECTORY ${_module}) - FILE(GLOB_RECURSE tmp "${_module}/src/*.c") - LIST(APPEND SOURCES_ALL ${tmp}) - ENDIF(IS_DIRECTORY ${_module}) + IF(IS_DIRECTORY ${_module}) + FILE(GLOB_RECURSE tmp "${_module}/src/*.c") + LIST(APPEND SOURCES_ALL ${tmp}) + ENDIF(IS_DIRECTORY ${_module}) ENDFOREACH() ADD_LIBRARY(lte_phy SHARED ${SOURCES_ALL}) @@ -56,12 +56,12 @@ INSTALL(TARGETS lte_phy DESTINATION ${LIBRARY_DIR}) LIBLTE_SET_PIC(lte_phy) IF(VOLK_FOUND) - INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) - SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") - TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) - MESSAGE(STATUS " Compiling with VOLK SIMD library.") + INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS}) + SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}") + TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES}) + MESSAGE(STATUS " Compiling with VOLK SIMD library.") ELSE(VOLK_FOUND) - MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") + MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.") ENDIF(VOLK_FOUND) @@ -70,10 +70,10 @@ ENDIF(VOLK_FOUND) ######################################################################## FILE(GLOB_RECURSE cmakefiles CMakeLists.txt) FOREACH (_file ${cmakefiles}) - GET_FILENAME_COMPONENT(dir ${_file} PATH) - IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) - ADD_SUBDIRECTORY(${dir}) - ENDIF () + GET_FILENAME_COMPONENT(dir ${_file} PATH) + IF (NOT ${dir} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + ADD_SUBDIRECTORY(${dir}) + ENDIF () ENDFOREACH() diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 31332eb8f..843266d7f 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -32,13 +32,14 @@ #include #include "liblte/phy/ch_estimation/chest.h" -#include "liblte/phy/resampling/interp.h" #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) +//#define VOLK_INTERP + void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { chest_ref_fprint(q, stream, nslot, port_id); chest_recvsig_fprint(q, stream, nslot, port_id); @@ -102,6 +103,7 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint port_id < q->nof_ports) { if (nref < q->refsignal[port_id][nslot].nof_refs) { + fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index @@ -153,10 +155,15 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32 /* interpolate the symbols with references * in the freq domain */ for (i=0;insymbols;i++) { +#ifdef VOLK_INTERP + interp_run_offset(&q->interp_freq[port_id], + &r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re], + r->voffset, RE_X_RB/2-r->voffset); +#else interp_linear_offset(&r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2, r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); - +#endif } /* now interpolate in the time domain */ for (i=0;inof_re; i++) { @@ -164,8 +171,13 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32 for (j=0;jnsymbols;j++) { x[j] = ce[r->symbols_ref[j] * q->nof_re + i]; } +#ifdef VOLK_INTERP + interp_run_offset(&q->interp_time[port_id], x, y, + r->symbols_ref[0], 3); +#else interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], 2, r->symbols_ref[0], 3); +#endif } else { for (j=0;jsymbols_ref[0] * q->nof_re + i]; @@ -225,7 +237,7 @@ int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) { return LIBLTE_SUCCESS; } -int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { +int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -236,12 +248,7 @@ int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_ q->nof_ports = nof_ports; q->nof_symbols = nof_symbols; q->nof_re = nof_re; - - switch(interp) { - case LINEAR: - q->interp = interp_linear_offset; - } - + INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", q->nof_symbols, q->nof_re, nof_ports); @@ -250,9 +257,9 @@ int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_ return ret; } -int chest_init_LTEDL(chest_t *q, chest_interp_t interp, lte_cell_t cell) { +int chest_init_LTEDL(chest_t *q, lte_cell_t cell) { int ret; - ret = chest_init(q, interp, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); + ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); if (ret != LIBLTE_SUCCESS) { return ret; } else { @@ -268,6 +275,16 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ nslot < NSLOTS_X_FRAME) { ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell); + + if (ret == LIBLTE_SUCCESS) { + if (nslot == 0) { + ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2); + if (ret == LIBLTE_SUCCESS) { + ret = interp_init(&q->interp_time[port_id], LINEAR, 2, + q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]); + } + } + } } return ret; } @@ -339,7 +356,7 @@ int chest_initialize(chest_hl* h) { cell.nof_prb = h->init.nof_prb; cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT; - if (chest_init_LTEDL(&h->obj, LINEAR, cell)) { + if (chest_init_LTEDL(&h->obj, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test.c index 3f97e149d..b0328b4ba 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test.c +++ b/lte/phy/lib/ch_estimation/test/chest_test.c @@ -162,7 +162,7 @@ int main(int argc, char **argv) { while(cid <= max_cid) { cell.id = cid; - if (chest_init_LTEDL(&eq, LINEAR, cell)) { + if (chest_init_LTEDL(&eq, cell)) { fprintf(stderr, "Error initializing equalizer\n"); goto do_exit; } diff --git a/lte/phy/lib/common/src/phy_common.c b/lte/phy/lib/common/src/phy_common.c index a4b9a314d..223d2e299 100644 --- a/lte/phy/lib/common/src/phy_common.c +++ b/lte/phy/lib/common/src/phy_common.c @@ -64,7 +64,24 @@ bool lte_cell_isvalid(lte_cell_t *cell) { return false; } } - + +bool lte_N_id_2_isvalid(uint32_t N_id_2) { + if (N_id_2 < 3) { + return true; + } else { + return false; + } +} + +bool lte_N_id_1_isvalid(uint32_t N_id_1) { + if (N_id_1 < 169) { + return true; + } else { + return false; + } +} + + /* * Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index */ @@ -106,6 +123,14 @@ uint32_t lte_mod_bits_x_symbol(lte_mod_t mod) { } } +char *lte_cp_string(lte_cp_t cp) { + if (cp == CPNORM) { + return "Normal"; + } else { + return "Extended"; + } +} + /* * Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212 */ @@ -130,6 +155,7 @@ int lte_sampling_freq_hz(uint32_t nof_prb) { return 15000 * n; } } + int lte_symbol_sz(uint32_t nof_prb) { if (nof_prb<=0) { return LIBLTE_ERROR; @@ -150,6 +176,18 @@ int lte_symbol_sz(uint32_t nof_prb) { return LIBLTE_ERROR; } +bool lte_symbol_sz_isvalid(uint32_t symbol_sz) { + if (symbol_sz == 128 || + symbol_sz == 256 || + symbol_sz == 512 || + symbol_sz == 1024 || + symbol_sz == 2048) { + return true; + } else { + return false; + } +} + uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) { if (nof_ports == 1 && symbol_id==0) { return (cell_id+3) % 6; diff --git a/lte/phy/lib/phch/src/dci.c b/lte/phy/lib/phch/src/dci.c index df278efa3..5d57a28ab 100644 --- a/lte/phy/lib/phch/src/dci.c +++ b/lte/phy/lib/phch/src/dci.c @@ -61,7 +61,7 @@ int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti, return ret; } - if (VERBOSE_ISINFO()) { + if (VERBOSE_ISDEBUG()) { dci_msg_type_fprint(stdout, type); } if (type.type == PDSCH_SCHED) { @@ -72,7 +72,7 @@ int dci_msg_to_ra_dl(dci_msg_t *msg, uint16_t msg_rnti, uint16_t c_rnti, return ret; } - if (VERBOSE_ISINFO()) { + if (VERBOSE_ISDEBUG()) { ra_pdsch_fprint(stdout, ra_dl, cell.nof_prb); } diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 111420be4..99d49b4aa 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -50,6 +50,13 @@ #define MIN(a,b) ((a>b)?b:a) +#define NOF_COMMON_FORMATS 2 +const dci_format_t common_formats[NOF_COMMON_FORMATS] = { Format1A, Format1C }; + +#define NOF_UE_FORMATS 2 +const dci_format_t ue_formats[NOF_UE_FORMATS] = { Format0, Format1 }; // 1A has the same payload as 0 + + static void set_cfi(pdcch_t *q, uint32_t cfi) { if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; @@ -228,7 +235,8 @@ uint32_t pdcch_ue_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidat * Returns the number of candidates saved in the array c. */ uint32_t pdcch_common_locations(pdcch_t *q, dci_location_t *c, uint32_t max_candidates, - uint32_t cfi) { + uint32_t cfi) +{ uint32_t i, l, L, k; set_cfi(q, cfi); @@ -271,8 +279,8 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof if (q != NULL && data != NULL && - E < q->max_bits && - nof_bits < DCI_MAX_BITS) + E <= q->max_bits && + nof_bits <= DCI_MAX_BITS) { /* unrate matching */ @@ -301,6 +309,7 @@ static int dci_decode(pdcch_t *q, float *e, char *data, uint32_t E, uint32_t nof } return LIBLTE_SUCCESS; } else { + fprintf(stderr, "Invalid parameters: E: %d, max_bits: %d, nof_bits: %d\n", E, q->max_bits, nof_bits); return LIBLTE_ERROR_INVALID_INPUTS; } } diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 6b92c4e0b..0f5a508d4 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -171,7 +171,7 @@ int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, } /** Initializes the PDCCH transmitter and receiver */ -int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { +int pdsch_init(pdsch_t *q, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; int i; @@ -183,7 +183,6 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { ret = LIBLTE_ERROR; q->cell = cell; - q->rnti = user_rnti; q->max_symbols = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); @@ -204,13 +203,8 @@ int pdsch_init(pdsch_t *q, uint16_t user_rnti, lte_cell_t cell) { demod_soft_init(&q->demod); demod_soft_alg_set(&q->demod, APPROX); - - for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { - if (sequence_pdsch(&q->seq_pdsch[i], q->rnti, 0, 2 * i, q->cell.id, - q->max_symbols * q->mod[3].nbits_x_symbol)) { - goto clean; - } - } + + q->rnti_is_set = false; if (tcod_init(&q->encoder, MAX_LONG_CB)) { goto clean; @@ -304,8 +298,20 @@ void pdsch_free(pdsch_t *q) { } +int pdsch_set_rnti(pdsch_t *q, uint16_t rnti) { + uint32_t i; + for (i = 0; i < NSUBFRAMES_X_FRAME; i++) { + if (sequence_pdsch(&q->seq_pdsch[i], rnti, 0, 2 * i, q->cell.id, + q->max_symbols * q->mod[3].nbits_x_symbol)) { + return LIBLTE_ERROR; + } + } + q->rnti_is_set = true; + q->rnti = rnti; + return LIBLTE_SUCCESS; +} /* Calculate Codeblock Segmentation as in Section 5.1.2 of 36.212 */ -int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) { +static int codeblock_segmentation(struct cb_segm *s, uint32_t tbs) { uint32_t Bp, B, idx1; int ret; @@ -499,7 +505,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, n_e = nb_e - rp; } - INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, + DEBUG("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, cb_len, rlen - F, wp, rp, F, n_e); /* Rate Unmatching */ @@ -526,7 +532,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, if (i < harq_process->cb_segm.C - 1) { memcpy(&data[wp], &q->cb_in[F], (rlen - F) * sizeof(char)); } else { - INFO("Last CB, appending parity: %d to %d from %d and 24 from %d\n", + DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n", rlen - F - 24, wp, F, rlen - 24); /* Append Transport Block parity bits to the last CB */ memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(char)); @@ -538,7 +544,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, rp += n_e; } - INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + DEBUG("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); // Compute transport block CRC par_rx = crc_checksum(&q->crc_tb, data, tbs); @@ -573,11 +579,12 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, cf_t *x[MAX_LAYERS]; uint32_t nof_symbols, nof_bits, nof_bits_e; - if (q != NULL && - sf_symbols != NULL && - data != NULL && - subframe < 10 && - harq_process != NULL) + if (q != NULL && + sf_symbols != NULL && + data != NULL && + subframe < 10 && + harq_process != NULL && + harq_process->mcs.mod > 0) { nof_bits = harq_process->mcs.tbs; @@ -585,8 +592,8 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d\n", - subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e); + INFO("Decoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { @@ -651,105 +658,109 @@ int pdsch_encode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, uint32_t i; uint32_t cb_len, rp, wp, rlen, F, n_e; char *e_bits = q->pdsch_e; + int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && data != NULL && nb_e < q->max_symbols * q->mod[3].nbits_x_symbol) { - if (rv_idx == 0) { - /* Compute transport block CRC */ - par = crc_checksum(&q->crc_tb, data, tbs); - - /* parity bits will be appended later */ - bit_pack(par, &p_parity, 24); - - if (VERBOSE_ISDEBUG()) { - DEBUG("DATA: ", 0); - vec_fprint_b(stdout, data, tbs); - DEBUG("PARITY: ", 0); - vec_fprint_b(stdout, parity, 24); - } - - /* Add filler bits to the new data buffer */ - for (i = 0; i < harq_process->cb_segm.F; i++) { - q->cb_in[i] = LTE_NULL_BIT; - } - } - - wp = 0; - rp = 0; - for (i = 0; i < harq_process->cb_segm.C; i++) { - - /* Get read lengths */ - if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { - cb_len = harq_process->cb_segm.K1; - } else { - cb_len = harq_process->cb_segm.K2; - } - if (harq_process->cb_segm.C > 1) { - rlen = cb_len - 24; - } else { - rlen = cb_len; - } - if (i == 0) { - F = harq_process->cb_segm.F; - } else { - F = 0; - } - - if (i < harq_process->cb_segm.C - 1) { - n_e = nb_e / harq_process->cb_segm.C; - } else { - n_e = nb_e - wp; - } - - INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, - cb_len, rlen - F, wp, rp, F, n_e); - + if (q->rnti_is_set) { if (rv_idx == 0) { - /* Copy data to another buffer, making space for the Codeblock CRC */ - if (i < harq_process->cb_segm.C - 1) { - memcpy(&q->cb_in[F], &data[rp], (rlen - F) * sizeof(char)); - } else { - INFO("Last CB, appending parity: %d from %d and 24 to %d\n", - rlen - F - 24, rp, rlen - 24); - /* Append Transport Block parity bits to the last CB */ - memcpy(&q->cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); - memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(char)); - } - if (harq_process->cb_segm.C > 1) { - /* Attach Codeblock CRC */ - crc_attach(&q->crc_cb, q->cb_in, rlen); - } + /* Compute transport block CRC */ + par = crc_checksum(&q->crc_tb, data, tbs); + + /* parity bits will be appended later */ + bit_pack(par, &p_parity, 24); + if (VERBOSE_ISDEBUG()) { - DEBUG("CB#%d Len=%d: ", i, cb_len); - vec_fprint_b(stdout, q->cb_in, cb_len); + DEBUG("DATA: ", 0); + vec_fprint_b(stdout, data, tbs); + DEBUG("PARITY: ", 0); + vec_fprint_b(stdout, parity, 24); + } + + /* Add filler bits to the new data buffer */ + for (i = 0; i < harq_process->cb_segm.F; i++) { + q->cb_in[i] = LTE_NULL_BIT; } - /* Turbo Encoding */ - tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len); } - /* Rate matching */ - if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, - (char*) q->cb_out, 3 * cb_len + 12, - &e_bits[wp], n_e, rv_idx)) - { - fprintf(stderr, "Error in rate matching\n"); - return LIBLTE_ERROR; + wp = 0; + rp = 0; + for (i = 0; i < harq_process->cb_segm.C; i++) { + + /* Get read lengths */ + if (i < harq_process->cb_segm.C - harq_process->cb_segm.C2) { + cb_len = harq_process->cb_segm.K1; + } else { + cb_len = harq_process->cb_segm.K2; + } + if (harq_process->cb_segm.C > 1) { + rlen = cb_len - 24; + } else { + rlen = cb_len; + } + if (i == 0) { + F = harq_process->cb_segm.F; + } else { + F = 0; + } + + if (i < harq_process->cb_segm.C - 1) { + n_e = nb_e / harq_process->cb_segm.C; + } else { + n_e = nb_e - wp; + } + + INFO("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, + cb_len, rlen - F, wp, rp, F, n_e); + + if (rv_idx == 0) { + /* Copy data to another buffer, making space for the Codeblock CRC */ + if (i < harq_process->cb_segm.C - 1) { + memcpy(&q->cb_in[F], &data[rp], (rlen - F) * sizeof(char)); + } else { + INFO("Last CB, appending parity: %d from %d and 24 to %d\n", + rlen - F - 24, rp, rlen - 24); + /* Append Transport Block parity bits to the last CB */ + memcpy(&q->cb_in[F], &data[rp], (rlen - F - 24) * sizeof(char)); + memcpy(&q->cb_in[rlen - 24], parity, 24 * sizeof(char)); + } + if (harq_process->cb_segm.C > 1) { + /* Attach Codeblock CRC */ + crc_attach(&q->crc_cb, q->cb_in, rlen); + } + if (VERBOSE_ISDEBUG()) { + DEBUG("CB#%d Len=%d: ", i, cb_len); + vec_fprint_b(stdout, q->cb_in, cb_len); + } + /* Turbo Encoding */ + tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len); + } + + /* Rate matching */ + if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size, + (char*) q->cb_out, 3 * cb_len + 12, + &e_bits[wp], n_e, rv_idx)) + { + fprintf(stderr, "Error in rate matching\n"); + return LIBLTE_ERROR; + } + + /* Set read/write pointers */ + rp += (rlen - F); + wp += n_e; } - /* Set read/write pointers */ - rp += (rlen - F); - wp += n_e; + INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); + + ret = LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n"); } - - INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp); - - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } + } + return ret; } /** Converts the PDSCH data bits to symbols mapped to the slot ready for transmission @@ -761,74 +772,77 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t s uint32_t nof_symbols, nof_bits, nof_bits_e; /* Set pointers for layermapping & precoding */ cf_t *x[MAX_LAYERS]; - + int ret = LIBLTE_ERROR_INVALID_INPUTS; + if (q != NULL && data != NULL && subframe < 10 && harq_process != NULL) { - for (i=0;icell.nof_ports;i++) { - if (sf_symbols[i] == NULL) { + if (q->rnti_is_set) { + for (i=0;icell.nof_ports;i++) { + if (sf_symbols[i] == NULL) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + } + + nof_bits = harq_process->mcs.tbs; + nof_symbols = harq_process->prb_alloc.re_sf[subframe]; + nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; + + if (harq_process->mcs.tbs == 0) { + return LIBLTE_ERROR_INVALID_INPUTS; + } + + if (nof_bits > nof_bits_e) { + fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); return LIBLTE_ERROR_INVALID_INPUTS; } - } - - nof_bits = harq_process->mcs.tbs; - nof_symbols = harq_process->prb_alloc.re_sf[subframe]; - nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol; - if (harq_process->mcs.tbs == 0) { - return LIBLTE_ERROR_INVALID_INPUTS; - } - - if (nof_bits > nof_bits_e) { - fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e); - return LIBLTE_ERROR_INVALID_INPUTS; - } + if (nof_symbols > q->max_symbols) { + fprintf(stderr, + "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", + nof_symbols, q->max_symbols, q->cell.nof_prb); + return LIBLTE_ERROR_INVALID_INPUTS; + } - if (nof_symbols > q->max_symbols) { - fprintf(stderr, - "Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n", - nof_symbols, q->max_symbols, q->cell.nof_prb); - return LIBLTE_ERROR_INVALID_INPUTS; - } + INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", + subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); - INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n", - subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx); + /* number of layers equals number of ports */ + for (i = 0; i < q->cell.nof_ports; i++) { + x[i] = q->pdsch_x[i]; + } + memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); - /* number of layers equals number of ports */ - for (i = 0; i < q->cell.nof_ports; i++) { - x[i] = q->pdsch_x[i]; - } - memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports)); + if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) { + fprintf(stderr, "Error encoding TB\n"); + return LIBLTE_ERROR; + } + + scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); - if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) { - fprintf(stderr, "Error encoding TB\n"); - return LIBLTE_ERROR; - } - + mod_modulate(&q->mod[harq_process->mcs.mod - 1], (char*) q->pdsch_e, q->pdsch_d, nof_bits_e); - scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e); + /* TODO: only diversity supported */ + if (q->cell.nof_ports > 1) { + layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols); + precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports, + nof_symbols / q->cell.nof_ports); + } else { + memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); + } - mod_modulate(&q->mod[harq_process->mcs.mod - 1], (char*) q->pdsch_e, q->pdsch_d, nof_bits_e); - - /* TODO: only diversity supported */ - if (q->cell.nof_ports > 1) { - layermap_diversity(q->pdsch_d, x, q->cell.nof_ports, nof_symbols); - precoding_diversity(x, q->pdsch_symbols, q->cell.nof_ports, - nof_symbols / q->cell.nof_ports); + /* mapping to resource elements */ + for (i = 0; i < q->cell.nof_ports; i++) { + pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe); + } + ret = LIBLTE_SUCCESS; } else { - memcpy(q->pdsch_symbols[0], q->pdsch_d, nof_symbols * sizeof(cf_t)); + fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n"); } - - /* mapping to resource elements */ - for (i = 0; i < q->cell.nof_ports; i++) { - pdsch_put(q, q->pdsch_symbols[i], sf_symbols[i], &harq_process->prb_alloc, subframe); - } - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } + } + return ret; } - + \ No newline at end of file diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c new file mode 100644 index 000000000..7a73da125 --- /dev/null +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -0,0 +1,555 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE 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 Lesser General Public License for more details. + * + * A copy of the GNU Lesser 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/. + * + */ + +#include +#include +#include +#include +#include + + +#include "liblte/phy/phch/ue_sync.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#define MAX_TIME_OFFSET 128 +cf_t dummy[MAX_TIME_OFFSET]; + +#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) + +#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) + +#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) + +#define MAXIMUM_SFLEN SF_LEN(2048, CPNORM) +#define MAXIMUM_SFLEN_RE SF_LEN_RE(110, CPNORM) + +static int mib_decoder_initialize(ue_sync_t *q); +static void mib_decoder_free(ue_sync_t *q); + +int ue_sync_init(ue_sync_t *q, + double (set_rate_callback)(void*, double), + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + stream_handler != NULL) + { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(ue_sync_t)); + + ue_sync_reset(q); + + q->cell.nof_prb = SYNC_PBCH_NOF_PRB; + q->cell.nof_ports = SYNC_PBCH_NOF_PORTS; + q->cell.id = 0; + q->cell.cp = CPNORM; + + q->pbch_decoded = false; + q->pbch_initialized = false; + q->pbch_decoder_enabled = true; + q->pbch_decode_always = false; + q->decode_sss_on_track = false; + + q->stream = stream_handler; + q->recv_callback = recv_callback; + q->set_rate_callback = set_rate_callback; + + INFO("Setting sampling frequency 1.92 MHz\n",0); + q->set_rate_callback(q->stream, 1920000.0); + + if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + goto clean_exit; + } + + sync_pss_det_peak_to_avg(&q->s); + + if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) { + fprintf(stderr, "Error initiating CFO\n"); + goto clean_exit; + } + + q->input_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); + if (!q->input_buffer) { + perror("malloc"); + goto clean_exit; + } + + q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); + if (!q->sf_symbols) { + perror("malloc"); + goto clean_exit; + } + for (int i=0;ice[i] = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); + if (!q->ce[i]) { + perror("malloc"); + goto clean_exit; + } + } + + //float th = PAR_THRESHOLD_FIND * (1+(float) CURRENT_FFTSIZE/128/10); + sync_set_threshold(&q->s, PAR_THRESHOLD_FIND, PAR_THRESHOLD_FIND/4); + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_sync_free(q); + } + return ret; +} + +void ue_sync_free(ue_sync_t *q) { + if (q->input_buffer) { + free(q->input_buffer); + } + if (q->sf_symbols) { + free(q->sf_symbols); + } + for (int i=0;ice[i]) { + free(q->ce[i]); + } + } + mib_decoder_free(q); + cfo_free(&q->cfocorr); + sync_free(&q->s); +} + +void ue_sync_set_threshold(ue_sync_t *q, float threshold) { + sync_set_threshold(&q->s, threshold, threshold/2); +} + +lte_cell_t ue_sync_get_cell(ue_sync_t *q) { + return q->cell; +} + +pbch_mib_t ue_sync_get_mib(ue_sync_t *q) { + return q->mib; +} + +uint32_t ue_sync_peak_idx(ue_sync_t *q) { + return q->peak_idx; +} + +ue_sync_state_t ue_sync_get_state(ue_sync_t *q) { + return q->state; +} + +static int update_srate(ue_sync_t *q) { + struct timeval t[3]; + + gettimeofday(&t[1], NULL); + if (sync_realloc(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + fprintf(stderr, "Error realloc'ing SYNC\n"); + return LIBLTE_ERROR; + } + gettimeofday(&t[2], NULL); + get_time_interval(t); + + if (NOF_MIB_DECODES > 1) { + mib_decoder_free(q); + if (mib_decoder_initialize(q)) { + fprintf(stderr, "Error reinitializing MIB decoder\n"); + return LIBLTE_ERROR; + } + } + + // Finally set the new sampling rate + q->set_rate_callback(q->stream, (float) lte_sampling_freq_hz(q->cell.nof_prb)); + + ue_sync_reset(q); + printf("Set sampling rate %.2f MHz, fft_size=%d, sf_len=%d Texec=%d us\n", + (float) lte_sampling_freq_hz(q->cell.nof_prb)/1000000, + CURRENT_FFTSIZE, CURRENT_SFLEN, (int) t[0].tv_usec); + + return LIBLTE_SUCCESS; +} + +uint32_t ue_sync_get_sfidx(ue_sync_t *q) { + return q->sf_idx; +} + +float ue_sync_get_cfo(ue_sync_t *q) { + return 15000 * q->cur_cfo; +} + +float ue_sync_get_sfo(ue_sync_t *q) { + return 1000*q->mean_time_offset/5; +} + +bool ue_sync_is_mib_decoded(ue_sync_t *q) { + return q->pbch_decoded; +} + +void ue_sync_pbch_enable(ue_sync_t *q, bool enabled) { + q->pbch_decoder_enabled = enabled; +} + +void ue_sync_pbch_always(ue_sync_t *q, bool enabled) { + q->pbch_decode_always = enabled; +} + +void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { + q->decode_sss_on_track = enabled; +} + +static int mib_decoder_initialize(ue_sync_t *q) { + + if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + return -1; + } + if (chest_init_LTEDL(&q->chest, q->cell)) { + fprintf(stderr, "Error initializing reference signal\n"); + return -1; + } + if (pbch_init(&q->pbch, q->cell)) { + fprintf(stderr, "Error initiating PBCH\n"); + return -1; + } + q->pbch_initialized = 1; + DEBUG("PBCH initiated cell_id=%d\n", q->cell.id); + + return 0; +} + +static void mib_decoder_free(ue_sync_t *q) { + chest_free(&q->chest); + pbch_free(&q->pbch); + lte_fft_free(&q->fft); +} + +static int mib_decoder_run(ue_sync_t *q) { + int ret; + + /* Run FFT for the second slot */ + lte_fft_run_sf(&q->fft, q->input_buffer, q->sf_symbols); + + /* Get channel estimates of slot #1 for each port */ + chest_ce_sf(&q->chest, q->sf_symbols, q->ce, 0); + + if (q->pbch_last_trial && + (q->frame_total_cnt - q->pbch_last_trial > 2)) + { + pbch_decode_reset(&q->pbch); + INFO("Resetting PBCH decoder: last trial %d, now is %d\n", + q->pbch_last_trial, q->frame_total_cnt); + q->pbch_last_trial = 0; + } + + if (pbch_decode(&q->pbch, q->sf_symbols, q->ce, &q->mib) == 1) { + q->frame_number = q->mib.sfn; + q->cell.nof_ports = q->mib.nof_ports; + q->cell.nof_prb = q->mib.nof_prb; + + if (!q->pbch_decoded) { + printf("MIB decoded:\n"); + pbch_mib_fprint(stdout, &q->mib); + ret = update_srate(q); + } else { + INFO("MIB decoded #%d SFN: %d\n", q->pbch_decoded, q->mib.sfn); + } + q->pbch_decoded++; + + pbch_decode_reset(&q->pbch); + + } else { + INFO("MIB not decoded: %d\n", q->frame_total_cnt); + q->pbch_last_trial = q->frame_total_cnt; + } + + return ret; +} + +static int find_peak_ok(ue_sync_t *q) { + int ret; + + if (q->peak_idx < CURRENT_SFLEN) { + /* Receive the rest of the next subframe */ + if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) { + return LIBLTE_ERROR; + } + } + + if (sync_sss_detected(&q->s)) { + ret = sync_get_cell_id(&q->s); + if (ret >= 0) { + q->cell.id = (uint32_t) ret; + q->cell.cp = sync_get_cp(&q->s); + } + + /* Get the subframe index (0 or 5) */ + q->sf_idx = sync_get_slot_id(&q->s)/2; + + /* Reset variables */ + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + + /* Goto Tracking state */ + q->state = SF_TRACK; + ret = LIBLTE_SUCCESS; + + INFO("Found peak %d, SF_idx: %d, Cell_id: %d CP: %s\n", + q->peak_idx, q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); + + if (q->peak_idx < CURRENT_SFLEN) { + q->sf_idx++; + } + + return ret; + } else { + INFO("Found peak at %d, SSS not detected\n", q->peak_idx); + return 0; + } +} + +int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { + int ret = LIBLTE_SUCCESS; + + /* Make sure subframe idx is what we expect */ + if ((q->sf_idx != sync_get_slot_id(&q->s)/2) && q->decode_sss_on_track) { + printf("\nWarning: Expected SF idx %d but got %d!\n", + q->sf_idx, sync_get_slot_id(&q->s)/2); + q->sf_idx = sync_get_slot_id(&q->s)/2; + } else { + q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); + + /* If the PSS peak is beyond the frame (we sample too slowly), + discard the offseted samples to align next frame */ + if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { + ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); + } else { + ret = LIBLTE_SUCCESS; + } + + /* compute cumulative moving average CFO */ + q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->s), q->cur_cfo, q->frame_ok_cnt); + + /* compute cumulative moving average time offset */ + q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt); + + q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; + q->frame_ok_cnt++; + q->frame_no_cnt = 0; + + + if (ret >= LIBLTE_SUCCESS) { + ret = LIBLTE_SUCCESS; + } + } + + return ret; +} + +int track_peak_no(ue_sync_t *q) { + + /* if we missed too many PSS go back to FIND */ + q->frame_no_cnt++; + if (q->frame_no_cnt >= TRACK_MAX_LOST) { + printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); + q->state = SF_FIND; + } else { + INFO("Tracking peak not found, %d lost\n", (int) q->frame_no_cnt); + } + + return LIBLTE_SUCCESS; +} + +static int receive_samples(ue_sync_t *q) { + + /* A negative time offset means there are samples in our buffer for the next subframe, + because we are sampling too fast. + */ + if (q->time_offset < 0) { + q->time_offset = -q->time_offset; + } + /* copy last part of the last subframe (use move since there could be overlapping) */ + memmove(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); + + /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ + if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { + return LIBLTE_ERROR; + } + + /* reset time offset */ + q->time_offset = 0; + + return LIBLTE_SUCCESS; +} + +int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t track_idx; + struct timeval t[3]; + + if (q != NULL && + sf_symbols != NULL && + q->input_buffer != NULL) + { + + if (receive_samples(q)) { + fprintf(stderr, "Error receiving samples\n"); + return -1; + } + + switch (q->state) { + case SF_FIND: + q->s.sss_en = true; + + /* Find peak and cell id */ + ret = sync_find(&q->s, q->input_buffer, &q->peak_idx); + if (ret < 0) { + fprintf(stderr, "Error finding correlation peak (%d)\n", ret); + return -1; + } + + DEBUG("Find PAR=%.2f\n", sync_get_peak_to_avg(&q->s)); + + if (ret == 1) { + ret = find_peak_ok(q); + /* Initialize PBCH decoder */ + if (ret == LIBLTE_SUCCESS) { + if (!q->pbch_initialized && q->pbch_decoder_enabled) { + ret = mib_decoder_initialize(q); + if (ret < 0) { + fprintf(stderr, "Error initializing MIB decoder\n"); + } + } + } else if (ret < 0) { + if (ret < 0) { + fprintf(stderr, "Error processing find peak \n"); + } + } + } + break; + case SF_TRACK: + ret = LIBLTE_SUCCESS; + + q->s.sss_en = q->decode_sss_on_track; + + q->sf_idx = (q->sf_idx + 1) % 10; + + DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt); + + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx == 0 || q->sf_idx == 5) { + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[1], NULL); + #endif + + track_idx = 0; + + /* track pss around the middle of the subframe, where the PSS is */ + ret = sync_track(&q->s, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx); + if (ret < 0) { + fprintf(stderr, "Error tracking correlation peak\n"); + return -1; + } + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[2], NULL); + get_time_interval(t); + q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); + #endif + + if (ret == 1) { + ret = track_peak_ok(q, track_idx); + } else { + ret = track_peak_no(q); + } + + INFO("TRACK %3d: SF=%d Track_idx=%d Offset=%d CFO: %f\n", + (int) q->frame_total_cnt, q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->s)); + + q->frame_total_cnt++; + + if (ret == LIBLTE_ERROR) { + fprintf(stderr, "Error processing tracking peak\n"); + ue_sync_reset(q); + return LIBLTE_SUCCESS; + } + } + + /* Do CFO Correction and deliver the frame */ + cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); + *sf_symbols = q->input_buffer; + + /* At subframe 0, try to decode PBCH if not yet decoded */ + if (q->sf_idx == 0) { + if(q->pbch_decoder_enabled && + (q->pbch_decoded < NOF_MIB_DECODES || q->pbch_decode_always)) + { + mib_decoder_run(q); + } else { + q->mib.sfn = (q->mib.sfn + 1) % 1024; + } + } + + if (ret == LIBLTE_SUCCESS) { + if (q->pbch_decoder_enabled) { + if (q->pbch_decoded >= NOF_MIB_DECODES) { + ret = 1; + } else { + ret = 0; + } + } else { + ret = 1; + } + } + break; + } + } + DEBUG("UE SYNC returns %d\n", ret); + return ret; +} + +void ue_sync_reset(ue_sync_t *q) { + q->state = SF_FIND; + + q->pbch_last_trial = 0; + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->cur_cfo = 0; + q->mean_time_offset = 0; + q->time_offset = 0; + #ifdef MEASURE_EXEC_TIME + q->mean_exec_time = 0; + #endif +} + diff --git a/lte/phy/lib/phch/test/CMakeLists.txt b/lte/phy/lib/phch/test/CMakeLists.txt index 328d8128a..eb8b8dd1e 100644 --- a/lte/phy/lib/phch/test/CMakeLists.txt +++ b/lte/phy/lib/phch/test/CMakeLists.txt @@ -19,6 +19,23 @@ # and at http://www.gnu.org/licenses/. # +######################################################################## +# UE SYNC TEST (Only compiled if CUHD is available) +######################################################################## +LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND) +LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) +IF(${CUHD_FIND} GREATER -1) + ADD_EXECUTABLE(ue_sync_usrp ue_sync_usrp.c) + TARGET_LINK_LIBRARIES(ue_sync_usrp lte_phy cuhd) +ENDIF(${CUHD_FIND} GREATER -1) + +IF(${GRAPHICS_FIND} EQUAL -1) + SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") +ELSE(${GRAPHICS_FIND} EQUAL -1) + target_link_libraries(ue_sync_usrp graphics) +ENDIF(${GRAPHICS_FIND} EQUAL -1) + + ######################################################################## # PBCH TEST ######################################################################## diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index 09ed88980..92b2d8621 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -136,7 +136,7 @@ int base_init() { return -1; } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/phch/test/pcfich_file_test.c b/lte/phy/lib/phch/test/pcfich_file_test.c index f6b5770d1..7c54203e2 100644 --- a/lte/phy/lib/phch/test/pcfich_file_test.c +++ b/lte/phy/lib/phch/test/pcfich_file_test.c @@ -141,7 +141,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/phch/test/pdcch_file_test.c b/lte/phy/lib/phch/test/pdcch_file_test.c index 3f400b662..189adc871 100644 --- a/lte/phy/lib/phch/test/pdcch_file_test.c +++ b/lte/phy/lib/phch/test/pdcch_file_test.c @@ -155,7 +155,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/phch/test/pdsch_file_test.c b/lte/phy/lib/phch/test/pdsch_file_test.c index ac2185471..d180167f2 100644 --- a/lte/phy/lib/phch/test/pdsch_file_test.c +++ b/lte/phy/lib/phch/test/pdsch_file_test.c @@ -158,7 +158,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } @@ -183,10 +183,11 @@ int base_init() { exit(-1); } - if (pdsch_init(&pdsch, rnti, cell)) { + if (pdsch_init(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); exit(-1); } + pdsch_set_rnti(&pdsch, rnti); if (pdsch_harq_init(&harq_process, &pdsch)) { fprintf(stderr, "Error initiating HARQ process\n"); diff --git a/lte/phy/lib/phch/test/pdsch_re_test.c b/lte/phy/lib/phch/test/pdsch_re_test.c index 0f772a264..2ba2c75fd 100644 --- a/lte/phy/lib/phch/test/pdsch_re_test.c +++ b/lte/phy/lib/phch/test/pdsch_re_test.c @@ -78,7 +78,8 @@ int main(int argc, char **argv) { cell.nof_ports = test_re_ports[i]; cell.cp = test_re_cp[i]; - pdsch_init(&pdsch, 0, cell); + pdsch_init(&pdsch, cell); + pdsch_set_rnti(&pdsch, 0); memset(prb_alloc.re_sf, 0, sizeof(uint32_t) * 10); prb_alloc.slot[0].nof_prb = test_re_prb[i]; diff --git a/lte/phy/lib/phch/test/pdsch_test.c b/lte/phy/lib/phch/test/pdsch_test.c index 97c54308d..271b3c471 100644 --- a/lte/phy/lib/phch/test/pdsch_test.c +++ b/lte/phy/lib/phch/test/pdsch_test.c @@ -166,11 +166,13 @@ int main(int argc, char **argv) { goto quit; } - if (pdsch_init(&pdsch, 1234, cell)) { + if (pdsch_init(&pdsch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } + pdsch_set_rnti(&pdsch, 1234); + if (pdsch_harq_init(&harq_process, &pdsch)) { fprintf(stderr, "Error initiating HARQ process\n"); goto quit; diff --git a/lte/phy/lib/phch/test/phich_file_test.c b/lte/phy/lib/phch/test/phich_file_test.c index 897d4172a..bf031c834 100644 --- a/lte/phy/lib/phch/test/phich_file_test.c +++ b/lte/phy/lib/phch/test/phich_file_test.c @@ -166,7 +166,7 @@ int base_init() { } } - if (chest_init_LTEDL(&chest, LINEAR, cell)) { + if (chest_init_LTEDL(&chest, cell)) { fprintf(stderr, "Error initializing equalizer\n"); return -1; } diff --git a/lte/phy/lib/resampling/src/interp.c b/lte/phy/lib/resampling/src/interp.c index 35946c5f6..f6f0f10da 100644 --- a/lte/phy/lib/resampling/src/interp.c +++ b/lte/phy/lib/resampling/src/interp.c @@ -27,12 +27,173 @@ #include #include +#include + #include "liblte/phy/resampling/interp.h" +#include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" +#define TABLE_SIZE 1024 + + +#ifdef TABLE_SIZE + #define ARG2IDX(arg) ((uint32_t) ((1+(arg)/M_PI)*TABLE_SIZE/2)) + #define MYCEXP(arg) q->cexptable[ARG2IDX(arg)] +#else + #define MYCEXP(arg) (cosf(arg) + I*sinf(arg)) +#endif + +#define MAX_OFFSET 64 + +int interp_init(interp_t *q, interp_type_t type, uint32_t len, uint32_t M) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = LIBLTE_ERROR; + + q->in_arg = vec_malloc(len * sizeof(float)); + if (!q->in_arg) { + goto clean_and_exit; + } + q->in_mag = vec_malloc(len * sizeof(float)); + if (!q->in_mag) { + goto clean_and_exit; + } + q->out_arg = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_arg) { + goto clean_and_exit; + } + q->out_arg2 = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_arg2) { + goto clean_and_exit; + } + q->table_idx = vec_malloc((MAX_OFFSET + M * len) * sizeof(int16_t)); + if (!q->table_idx) { + goto clean_and_exit; + } + q->out_mag = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); + if (!q->out_mag) { + goto clean_and_exit; + } + q->out_cexp = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); + if (!q->out_cexp) { + goto clean_and_exit; + } + q->out_prod = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); + if (!q->out_prod) { + goto clean_and_exit; + } +#ifdef TABLE_SIZE + q->cexptable = vec_malloc(TABLE_SIZE * sizeof(cf_t)); + uint32_t i; + for (i=0;icexptable[i] = cexpf(I*M_PI*(2*((float) i/TABLE_SIZE) - 1)); + } +#endif + q->M = M; + q->len = len; + ret = LIBLTE_SUCCESS; + } + +clean_and_exit: + if (ret == LIBLTE_ERROR) { + interp_free(q); + } + return ret; +} + +void interp_free(interp_t *q) { + if (q) { + if (q->in_arg) { + free(q->in_arg); + } + if (q->in_mag) { + free(q->in_mag); + } + if (q->out_arg) { + free(q->out_arg); + } + if (q->out_cexp) { + free(q->out_cexp); + } + if (q->out_mag) { + free(q->out_mag); + } + + if (q->out_prod) { + free(q->out_prod); + } +#ifdef TABLE_SIZE + if (q->cexptable) { + free(q->cexptable); + } +#endif + } +} + +void interp_run_offset(interp_t *q, cf_t *input, cf_t *output, uint32_t off_st, uint32_t off_end) { + uint32_t i, j, n; + float mag0=0, mag1=0, arg0=0, arg1=0; + float dmag, darg; + uint32_t M = q->M; + uint32_t len1 = q->len-1; + + if (off_st + off_end < MAX_OFFSET) { + vec_abs_cf(input, q->in_mag, q->len); + vec_arg_cf(input, q->in_arg, q->len); + + mag0 = q->in_mag[0]; + mag1 = q->in_mag[1]; + arg0 = q->in_arg[0]; + arg1 = q->in_arg[1]; + dmag=(mag1-mag0)/M; + darg=(arg1-arg0)/M; + for (j=0;jout_mag[j] = mag0 - (j+1)*dmag; + q->out_arg[j] = arg0 - (j+1)*darg; + } + + for (i=0;iin_mag[i]; + mag1 = q->in_mag[i+1]; + arg0 = q->in_arg[i]; + arg1 = q->in_arg[i+1]; + dmag=(mag1-mag0)/M; + darg=(arg1-arg0)/M; + for (j=0;jout_mag[i*M+j+off_st] = mag0 + j*dmag; + q->out_arg[i*M+j+off_st] = arg0 + j*darg; + } + } + if (q->len > 1) { + for (j=0;jout_mag[i*M+j+off_st] = mag1 + j*dmag; + q->out_arg[i*M+j+off_st] = arg1 + j*darg; + } + } + uint32_t len=i*M+j+off_st; +#ifdef TABLE_SIZE + vec_convert_fi(q->out_arg, q->table_idx, (float) TABLE_SIZE/2/M_PI, len); + for (n=0;nout_cexp[n] = q->cexptable[q->table_idx[n]+TABLE_SIZE/2]; + } +#else + for (n=0;nout_cexp[n] = MYCEXP(q->out_arg[n]); + } +#endif + vec_prod_cfc(q->out_cexp, q->out_mag, output, len); + } + +} + +void interp_run(interp_t *q, cf_t *input, cf_t *output) { + interp_run_offset(q, input, output, 0, 1); +} + /* Performs 1st order linear interpolation with out-of-bound interpolation */ -void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end) { - int i, j; +void interp_linear_offset(cf_t *input, cf_t *output, uint32_t M, uint32_t len, uint32_t off_st, uint32_t off_end) { + uint32_t i, j; float mag0=0, mag1=0, arg0=0, arg1=0, mag=0, arg=0; for (i=0;itab, CFO_CEXPTAB_SIZE)) { goto clean; } - h->cur_cexp = malloc(sizeof(cf_t) * nsamples); + h->cur_cexp = vec_malloc(sizeof(cf_t) * nsamples); if (!h->cur_cexp) { goto clean; } @@ -50,9 +50,9 @@ int cfo_init(cfo_t *h, int nsamples) { h->nsamples = nsamples; cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); - ret = 0; + ret = LIBLTE_SUCCESS; clean: - if (ret == -1) { + if (ret == LIBLTE_ERROR) { cfo_free(h); } return ret; @@ -70,11 +70,23 @@ void cfo_set_tol(cfo_t *h, float tol) { h->tol = tol; } -void cfo_correct(cfo_t *h, cf_t *x, float freq) { +int cfo_realloc(cfo_t *h, uint32_t samples) { + h->cur_cexp = realloc(h->cur_cexp, sizeof(cf_t) * samples); + if (!h->cur_cexp) { + perror("realloc"); + return LIBLTE_ERROR; + } + cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, samples); + h->nsamples = samples; + + return LIBLTE_SUCCESS; +} + +void cfo_correct(cfo_t *h, cf_t *input, cf_t *output, float freq) { if (fabs(h->last_freq - freq) > h->tol) { h->last_freq = freq; cexptab_gen(&h->tab, h->cur_cexp, h->last_freq, h->nsamples); - INFO("CFO generating new table for frequency %.4f\n", freq); + DEBUG("CFO generating new table for frequency %.4f\n", freq); } - vec_prod_ccc(h->cur_cexp, x, x, h->nsamples); + vec_prod_ccc(h->cur_cexp, input, output, h->nsamples); } diff --git a/lte/phy/lib/sync/src/find_sss.c b/lte/phy/lib/sync/src/find_sss.c index 7fd47a752..7bc52d558 100644 --- a/lte/phy/lib/sync/src/find_sss.c +++ b/lte/phy/lib/sync/src/find_sss.c @@ -31,18 +31,10 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/sync/sss.h" -cf_t corr_sz(cf_t *z, cf_t *s) { - cf_t sum; - cf_t zsprod[32]; - vec_prod_ccc(z, s, zsprod, N_SSS - 1); - sum = vec_acc_cc(zsprod, N_SSS - 1); - - return sum; -} -void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) { - int m; +void corr_all_zs(cf_t *z, cf_t s[N_SSS+1][N_SSS+1], cf_t *output) { + uint32_t m; for (m = 0; m < N_SSS; m++) { - output[m] = corr_sz(z, s[m]); + output[m] = vec_dot_prod_ccc(z, s[m], N_SSS - 1); } } @@ -58,54 +50,64 @@ void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) { * */ -void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value, - int *m1, float *m1_value) { +int sss_synch_m0m1(sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value, + uint32_t *m1, float *m1_value) +{ - /* This is aprox 3-4 kbytes of stack. Consider moving to sss_synch_t?? */ - cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1]; - cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1]; - float tmp_real[N_SSS+1]; - cf_t input_fft[SSS_DFT_LEN]; + int ret = LIBLTE_ERROR_INVALID_INPUTS; - int i; + if (q != NULL && + input != NULL && + m0 != NULL && + m1 != NULL) + { + + /* Consider moving to sss_synch_t?? */ + cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1]; + cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1]; + float tmp_real[N_SSS+1]; + cf_t input_fft[SSS_MAX_FFT_LEN]; + uint32_t i; - dft_run_c(&q->dftp_input, input, input_fft); + dft_run_c(&q->dftp_input, input, input_fft); + + for (i = 0; i < N_SSS; i++) { + y[0][i] = input_fft[q->fft_size/2-N_SSS + 2 * i]; + y[1][i] = input_fft[q->fft_size/2-N_SSS + 2 * i + 1]; + } + + vec_prod_ccc(y[0], q->fc_tables[q->N_id_2].c[0], z, N_SSS); + memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); + vec_conj_cc(z, zconj, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - for (i = 0; i < N_SSS; i++) { - y[0][i] = input_fft[SSS_POS_SYMBOL + 2 * i]; - y[1][i] = input_fft[SSS_POS_SYMBOL + 2 * i + 1]; - } + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); + vec_abs_cf(tmp, tmp_real, N_SSS); + *m0 = vec_max_fi(tmp_real, N_SSS); + if (m0_value) { + *m0_value = tmp_real[*m0]; + } - vec_prod_ccc(y[0], q->fc_tables[q->N_id_2].c[0], z, N_SSS); - memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); - vec_conj_cc(z, zconj, N_SSS - 1); - vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - - corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); - vec_abs_cf(tmp, tmp_real, N_SSS); - *m0 = vec_max_fi(tmp_real, N_SSS); - if (m0_value) { - *m0_value = tmp_real[*m0]; - } - - vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS); - vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS); - memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); - vec_conj_cc(z, zconj, N_SSS - 1); - vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); - - corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); - vec_abs_cf(tmp, tmp_real, N_SSS); - *m1 = vec_max_fi(tmp_real, N_SSS); - if (m1_value) { - *m1_value = tmp_real[*m1]; - } + vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS); + vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS); + memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t)); + vec_conj_cc(z, zconj, N_SSS - 1); + vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1); + corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp); + vec_abs_cf(tmp, tmp_real, N_SSS); + *m1 = vec_max_fi(tmp_real, N_SSS); + if (m1_value) { + *m1_value = tmp_real[*m1]; + } + ret = LIBLTE_SUCCESS; + } + return ret; } void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in) { - int i, j; - bzero(fc_tables, sizeof(struct fc_tables)); + uint32_t i, j; + for (i = 0; i < N_SSS; i++) { for (j = 0; j < N_SSS; j++) { __real__ fc_tables->z1[i][j] = (float) in->z1[i][j]; diff --git a/lte/phy/lib/sync/src/gen_sss.c b/lte/phy/lib/sync/src/gen_sss.c index e68407f45..da3e895b2 100644 --- a/lte/phy/lib/sync/src/gen_sss.c +++ b/lte/phy/lib/sync/src/gen_sss.c @@ -58,19 +58,19 @@ void generate_zsc_tilde(int *z_tilde, int *s_tilde, int *c_tilde) { z_tilde[i] = 1 - 2 * x[i]; } -void generate_m0m1(int N_id_1, int *m0, int *m1) { - int q_prime = N_id_1 / (N_SSS - 1); - int q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1); - int m_prime = N_id_1 + (q * (q + 1) / 2); +void generate_m0m1(uint32_t N_id_1, uint32_t *m0, uint32_t *m1) { + uint32_t q_prime = N_id_1 / (N_SSS - 1); + uint32_t q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1); + uint32_t m_prime = N_id_1 + (q * (q + 1) / 2); *m0 = m_prime % N_SSS; *m1 = (*m0 + m_prime / N_SSS + 1) % N_SSS; } /* table[m0][m1-1]=N_id_1 */ -void generate_N_id_1_table(int table[30][30]) { - int m0, m1; - int N_id_1; +void generate_N_id_1_table(uint32_t table[30][30]) { + uint32_t m0, m1; + uint32_t N_id_1; for (N_id_1=0;N_id_1<168;N_id_1++) { generate_m0m1(N_id_1, &m0, &m1); table[m0][m1-1] = N_id_1; @@ -78,60 +78,60 @@ void generate_N_id_1_table(int table[30][30]) { } -void generate_s(int *s, int *s_tilde, int m0_m1) { - int i; +void generate_s(int *s, int *s_tilde, uint32_t m0_m1) { + uint32_t i; for (i = 0; i < N_SSS; i++) { s[i] = s_tilde[(i + m0_m1) % N_SSS]; } } void generate_s_all(int s[N_SSS][N_SSS], int *s_tilde) { - int i; + uint32_t i; for (i = 0; i < N_SSS; i++) { generate_s(s[i], s_tilde, i); } } -void generate_c(int *c, int *c_tilde, int N_id_2, int is_c0) { - int i; +void generate_c(int *c, int *c_tilde, uint32_t N_id_2, bool is_c0) { + uint32_t i; for (i = 0; i < N_SSS; i++) { - c[i] = c_tilde[(i + N_id_2 + (is_c0 > 0 ? 3 : 0)) % N_SSS]; + c[i] = c_tilde[(i + N_id_2 + (is_c0 ? 3 : 0)) % N_SSS]; } } -void generate_z(int *z, int *z_tilde, int m0_m1) { - int i; +void generate_z(int *z, int *z_tilde, uint32_t m0_m1) { + uint32_t i; for (i = 0; i < N_SSS; i++) { z[i] = z_tilde[(i + (m0_m1 % 8)) % N_SSS]; } } void generate_z_all(int z[N_SSS][N_SSS], int *z_tilde) { - int i; + uint32_t i; for (i = 0; i < N_SSS; i++) { generate_z(z[i], z_tilde, i); } } -void generate_sss_all_tables(struct sss_tables *tables, int N_id_2) { - int i; +void generate_sss_all_tables(struct sss_tables *tables, uint32_t N_id_2) { + uint32_t i; int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS]; generate_zsc_tilde(z_t, s_t, c_t); generate_s_all(tables->s, s_t); generate_z_all(tables->z1, z_t); for (i = 0; i < 2; i++) { - generate_c(tables->c[i], c_t, N_id_2, i); + generate_c(tables->c[i], c_t, N_id_2, i > 0); } } -void sss_generate(float *signal0, float *signal5, int cell_id) { +void sss_generate(float *signal0, float *signal5, uint32_t cell_id) { - int i; - int id1 = cell_id / 3; - int id2 = cell_id % 3; - int m0; - int m1; + uint32_t i; + uint32_t id1 = cell_id / 3; + uint32_t id2 = cell_id % 3; + uint32_t m0; + uint32_t m1; int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS]; int s0[N_SSS], s1[N_SSS], c0[N_SSS], c1[N_SSS], z1_0[N_SSS], z1_1[N_SSS]; diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index fd5f6c522..4c8da1a26 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -37,144 +37,142 @@ #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/convolution.h" -#define NOT_SYNC 0xF0F0F0F0 - - -int pss_synch_init_N_id_2(pss_synch_t *q, int N_id_2) { - q->N_id_2 = N_id_2; +int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_size) { dft_plan_t plan; - cf_t pss_signal_pad[PSS_LEN_FREQ]; + cf_t pss_signal_pad[2048]; cf_t pss_signal_time[PSS_LEN]; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (lte_N_id_2_isvalid(N_id_2) && + fft_size < 2048) + { + + pss_generate(pss_signal_time, N_id_2); - if (N_id_2 < 0 || N_id_2 > 2) { - fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); - return -1; + bzero(pss_signal_pad, fft_size * sizeof(cf_t)); + bzero(pss_signal_freq, fft_size * sizeof(cf_t)); + memcpy(&pss_signal_pad[(fft_size-PSS_LEN)/2], pss_signal_time, PSS_LEN * sizeof(cf_t)); + + if (dft_plan(&plan, fft_size, BACKWARD, COMPLEX)) { + return LIBLTE_ERROR; + } + + dft_plan_set_mirror(&plan, true); + dft_plan_set_dc(&plan, true); + dft_run_c(&plan, pss_signal_pad, pss_signal_freq); + + vec_sc_prod_cfc(pss_signal_freq, (float) 1 / (fft_size), pss_signal_pad, fft_size); + vec_conj_cc(pss_signal_pad, pss_signal_freq, fft_size); + + dft_plan_free(&plan); + + ret = LIBLTE_SUCCESS; } - - pss_generate(pss_signal_time, N_id_2); - - memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t)); - memset(q->pss_signal_freq[N_id_2], 0, PSS_LEN_FREQ * sizeof(cf_t)); - memcpy(&pss_signal_pad[33], pss_signal_time, PSS_LEN * sizeof(cf_t)); - - if (dft_plan(&plan, PSS_LEN_FREQ - 1, BACKWARD, COMPLEX)) { - return -1; - } - dft_plan_set_mirror(&plan, true); - dft_plan_set_dc(&plan, true); - dft_run_c(&plan, pss_signal_pad, q->pss_signal_freq[q->N_id_2]); - - vec_sc_prod_cfc(q->pss_signal_freq[q->N_id_2], (float) 1 / (PSS_LEN_FREQ - 1), - pss_signal_pad, PSS_LEN_FREQ); - - vec_conj_cc(pss_signal_pad, q->pss_signal_freq[q->N_id_2], PSS_LEN_FREQ); - - dft_plan_free(&plan); - - return 0; + return ret; } -/* Initializes the object. subframe_size is the size, in samples, of the 1ms subframe - * +/* Initializes the PSS synchronization object with fft_size=128 */ -int pss_synch_init(pss_synch_t *q, int frame_size) { - int ret = -1; - int N_id_2; - bzero(q, sizeof(pss_synch_t)); - - q->conv_abs = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(float)); - if (!q->conv_abs) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->tmp_input = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->tmp_input) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->conv_output) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - for (N_id_2=0;N_id_2<3;N_id_2++) { - q->pss_signal_freq[N_id_2] = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t)); - if (!q->pss_signal_freq[N_id_2]) { +int pss_synch_init(pss_synch_t *q, uint32_t frame_size) { + return pss_synch_init_fft(q, frame_size, 128); +} +/* Initializes the PSS synchronization object. + * + * It correlates a signal of frame_size samples with the PSS sequence in the frequency + * domain. The PSS sequence is transformed using fft_size samples. + */ +int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + + uint32_t N_id_2; + uint32_t buffer_size; + bzero(q, sizeof(pss_synch_t)); + + q->N_id_2 = 10; + q->fft_size = fft_size; + q->frame_size = frame_size; + + buffer_size = fft_size + frame_size + 1; + + q->conv_abs = vec_malloc(buffer_size * sizeof(float)); + if (!q->conv_abs) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } - if (pss_synch_init_N_id_2(q, N_id_2)) { - fprintf(stderr, "Error initiating PSS detector for N_id_2=%d\n", N_id_2); + q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->tmp_input) { + fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } + q->conv_output = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->conv_output) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + for (N_id_2=0;N_id_2<3;N_id_2++) { + q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t)); + if (!q->pss_signal_freq[N_id_2]) { + fprintf(stderr, "Error allocating memory\n"); + goto clean_and_exit; + } + /* The PSS is translated into the frequency domain for each N_id_2 */ + if (pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], N_id_2, fft_size)) { + fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size); + goto clean_and_exit; + } + } + #ifdef CONVOLUTION_FFT + if (conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) { + fprintf(stderr, "Error initiating convolution FFT\n"); + goto clean_and_exit; + } + #endif + + ret = LIBLTE_SUCCESS; } -#ifdef ENABLE_SF - q->frame_buffer = vec_malloc(4 * frame_size * sizeof(cf_t)); - if (!q->frame_buffer) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } - q->correlation_threshold = DEFAULT_CORRELATION_TH; - q->nosync_timeout_frames = DEFAULT_NOSYNC_TIMEOUT; - q->cfo_auto = true; - q->frame_start_idx = NOT_SYNC; - q->fb_wp = 0; -#endif - -#ifdef CONVOLUTION_FFT - if (conv_fft_cc_init(&q->conv_fft, frame_size, PSS_LEN_FREQ)) { - fprintf(stderr, "Error initiating convolution FFT\n"); - goto clean_and_exit; - } -#endif - - q->N_id_2 = -1; - q->frame_size = frame_size; - - ret = 0; - clean_and_exit: if (ret == -1) { +clean_and_exit: + if (ret == LIBLTE_ERROR) { pss_synch_free(q); } return ret; } void pss_synch_free(pss_synch_t *q) { - int i; - for (i=0;i<3;i++) { - if (q->pss_signal_freq[i]) { - free(q->pss_signal_freq[i]); + uint32_t i; + + if (q) { + for (i=0;i<3;i++) { + if (q->pss_signal_freq[i]) { + free(q->pss_signal_freq[i]); + } + } + #ifdef CONVOLUTION_FFT + conv_fft_cc_free(&q->conv_fft); + + #endif + if (q->tmp_input) { + free(q->tmp_input); + } + if (q->conv_output) { + free(q->conv_output); + } + if (q->conv_abs) { + free(q->conv_abs); } - } - if (q->conv_abs) { - free(q->conv_abs); - } - if (q->tmp_input) { - free(q->tmp_input); - } - if (q->conv_output) { - free(q->conv_output); - } -#ifdef ENABLE_SF - if (q->frame_buffer) { - free(q->frame_buffer); + bzero(q, sizeof(pss_synch_t)); } -#endif - -#ifdef CONVOLUTION_FFT - conv_fft_cc_free(&q->conv_fft); -#endif - - bzero(q, sizeof(pss_synch_t)); } /** * This function calculates the Zadoff-Chu sequence. * @param signal Output array. */ -int pss_generate(cf_t *signal, int N_id_2) { +int pss_generate(cf_t *signal, uint32_t N_id_2) { int i; float arg; const float root_value[] = { 25.0, 29.0, 34.0 }; @@ -182,7 +180,7 @@ int pss_generate(cf_t *signal, int N_id_2) { int sign = -1; - if (N_id_2 < 0 || N_id_2 > 2) { + if (N_id_2 > 2) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; } @@ -206,7 +204,7 @@ int pss_generate(cf_t *signal, int N_id_2) { /** 36.211 10.3 section 6.11.1.2 */ -void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { +void pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, lte_cp_t cp) { int k; k = (CP_NSYMB(cp) - 1) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); @@ -217,8 +215,8 @@ void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp) { /** Sets the current N_id_2 value. Returns -1 on error, 0 otherwise */ -int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { - if (N_id_2 < 0 || N_id_2 > 2) { +int pss_synch_set_N_id_2(pss_synch_t *q, uint32_t N_id_2) { + if (!lte_N_id_2_isvalid((N_id_2))) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); return -1; } else { @@ -227,40 +225,53 @@ int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) { } } - /** 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 pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, - float *corr_mean_value) { - int corr_peak_pos; - int conv_output_len; +int pss_synch_find_pss(pss_synch_t *q, cf_t *input, + float *corr_peak_value, float *corr_mean_value) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + input != NULL) + { - memset(&q->pss_signal_freq[q->N_id_2][PSS_LEN_FREQ], 0, q->frame_size * sizeof(cf_t)); - memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); - memset(&q->tmp_input[q->frame_size], 0, PSS_LEN_FREQ * sizeof(cf_t)); + uint32_t corr_peak_pos; + uint32_t conv_output_len; + + if (!lte_N_id_2_isvalid(q->N_id_2)) { + fprintf(stderr, "Error finding PSS peak, N_id_2 not set\n"); + return LIBLTE_ERROR; + } + + bzero(&q->pss_signal_freq[q->N_id_2][q->fft_size], q->frame_size * sizeof(cf_t)); + memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); + bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); -#ifdef CONVOLUTION_FFT - conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, - q->pss_signal_freq[q->N_id_2], q->conv_output); -#else - conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, PSS_LEN_FREQ); -#endif + #ifdef CONVOLUTION_FFT + conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, + q->pss_signal_freq[q->N_id_2], q->conv_output); + #else + conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); + #endif - vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); - corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); - if (corr_peak_value) { - *corr_peak_value = q->conv_abs[corr_peak_pos]; - } - if (corr_mean_value) { - *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) - / conv_output_len; - } + vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); + corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); + if (corr_peak_value) { + *corr_peak_value = q->conv_abs[corr_peak_pos]; + } + if (corr_mean_value) { + *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) + / conv_output_len; + } - return (int) corr_peak_pos; + ret = (int) corr_peak_pos; + } + return ret; } /* Returns the CFO estimation given a PSS received sequence @@ -270,159 +281,12 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, */ float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) { cf_t y0, y1, yr; - cf_t y[PSS_LEN_FREQ - 1]; - vec_prod_ccc_unalign(q->pss_signal_freq[q->N_id_2], pss_recv, y, PSS_LEN_FREQ - 1); - - y0 = vec_acc_cc(y, (PSS_LEN_FREQ - 1) / 2); - y1 = vec_acc_cc(&y[(PSS_LEN_FREQ - 1) / 2], (PSS_LEN_FREQ - 1) / 2); + y0 = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], pss_recv, q->fft_size/2); + y1 = vec_dot_prod_ccc(&q->pss_signal_freq[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; } -#ifdef ENABLE_SF - -void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) { - q->nosync_timeout_frames = nof_frames; -} - -void pss_synch_set_threshold(pss_synch_t *q, float threshold) { - q->correlation_threshold = threshold; -} - -void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto) { - q->cfo_auto = cfo_auto; -} - -float pss_synch_get_cfo(pss_synch_t *q) { - return q->current_cfo; -} - -int pss_synch_get_frame_start_idx(pss_synch_t *q) { - return q->frame_start_idx; -} - -/** This function is designed to be called periodically on a subframe basis. - * The function finds the PSS correlation peak and computes (does not adjust) CFO automatically as defined by - * pss_synch_set_cfo_mode(). - * - * If the PSS sequence is not found, returns 0 writes nothing to the output buffer. - * If the PSS sequence is found, aligns the beginning of the subframe to the output buffer and returns the number of samples - * written to the output buffer. - * If synchronized, subsequent calls to this function align the input buffer to the subframe beginning. - */ -int pss_synch_frame(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples) { - int max_idx, tmp_start_idx; - int retval; - float max_value; - - if (nsamples != q->frame_size) { - fprintf(stderr, "Configured for frame size %d but got %d samples\n", - q->frame_size, nsamples); - return -1; - } - - if (q->N_id_2 < 0) { - fprintf(stderr, - "N_id_2 must be configured before calling pss_synch()\n"); - return -1; - } - - max_idx = pss_synch_find_pss(q, input, &max_value, NULL); - if (max_value > q->correlation_threshold) { - tmp_start_idx = max_idx - nsamples / 2; - if (q->frame_start_idx != tmp_start_idx) { - printf("Re-synchronizing: new index is %d, old was %d\n", - tmp_start_idx, q->frame_start_idx); - } - q->frame_start_idx = tmp_start_idx; - } else { - if (q->nosync_timeout_frames > 0) { - q->nof_nosync_frames++; - if (q->nof_nosync_frames >= q->nosync_timeout_frames) { - q->frame_start_idx = NOT_SYNC; - } - } - } - - if (q->frame_start_idx == NOT_SYNC) { - - memcpy(q->frame_buffer, input, nsamples * sizeof(cf_t)); - retval = 0; - - } else if (q->frame_start_idx > 0) { - - if (q->fb_wp) { - memcpy(&q->frame_buffer[(nsamples - q->frame_start_idx)], input, - q->frame_start_idx * sizeof(cf_t)); - memcpy(output, q->frame_buffer, nsamples * sizeof(cf_t)); - retval = nsamples; - } else { - retval = 0; - } - memcpy(q->frame_buffer, &input[q->frame_start_idx], - (nsamples - q->frame_start_idx) * sizeof(cf_t)); - q->fb_wp = 1; - - } else { - - memcpy(output, &q->frame_buffer[nsamples + q->frame_start_idx], - (-q->frame_start_idx) * sizeof(cf_t)); - memcpy(&output[-q->frame_start_idx], input, - (nsamples + q->frame_start_idx) * sizeof(cf_t)); - memcpy(&q->frame_buffer[nsamples + q->frame_start_idx], - &input[nsamples + q->frame_start_idx], - (-q->frame_start_idx) * sizeof(cf_t)); - retval = nsamples; - } - - if (q->frame_start_idx != NOT_SYNC && q->cfo_auto && retval) { - q->current_cfo = pss_synch_cfo_compute(q, - &output[q->frame_size / 2 - PSS_LEN_FREQ + 1]); - } - - return retval; -} - -/** High-level API */ - -int pss_synch_initialize(pss_synch_hl* h) { - int fs = h->init.frame_size; - if (!fs) { - fs = DEFAULT_FRAME_SIZE; - } - if (pss_synch_init(&h->obj, fs)) { - return -1; - } - if (h->init.unsync_nof_pkts) { - pss_synch_set_timeout(&h->obj, h->init.unsync_nof_pkts); - } - - pss_synch_set_N_id_2(&h->obj, h->init.N_id_2); - if (h->init.do_cfo) { - pss_synch_set_cfo_mode(&h->obj, true); - } else { - pss_synch_set_cfo_mode(&h->obj, false); - } - return 0; -} - -int pss_synch_work(pss_synch_hl* hl) { - - if (hl->ctrl_in.correlation_threshold) { - pss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold); - } - - hl->out_len = pss_synch_frame(&hl->obj, hl->input, hl->output, hl->in_len); - - return 0; -} - -int pss_synch_stop(pss_synch_hl* hl) { - pss_synch_free(&hl->obj); - return 0; -} - -#endif - diff --git a/lte/phy/lib/sync/src/sss.c b/lte/phy/lib/sync/src/sss.c index 9d4525e83..6feef89da 100644 --- a/lte/phy/lib/sync/src/sss.c +++ b/lte/phy/lib/sync/src/sss.c @@ -35,29 +35,58 @@ #include "liblte/phy/sync/sss.h" #include "liblte/phy/utils/dft.h" #include "liblte/phy/utils/convolution.h" +#include "liblte/phy/utils/vector.h" -void generate_sss_all_tables(struct sss_tables *tables, int N_id_2); +void generate_sss_all_tables(struct sss_tables *tables, uint32_t N_id_2); void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in); -void generate_N_id_1_table(int table[30][30]); +void generate_N_id_1_table(uint32_t table[30][30]); -int sss_synch_init(sss_synch_t *q) { - int N_id_2; - struct sss_tables sss_tables; +int sss_synch_init(sss_synch_t *q, uint32_t fft_size) { + + if (q != NULL && + fft_size < 2048) + { + uint32_t N_id_2; + struct sss_tables sss_tables; - bzero(q, sizeof(sss_synch_t)); + bzero(q, sizeof(sss_synch_t)); + + if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { + sss_synch_free(q); + return LIBLTE_ERROR; + } + q->fft_size = fft_size; + + generate_N_id_1_table(q->N_id_1_table); + dft_plan_set_mirror(&q->dftp_input, true); + dft_plan_set_dc(&q->dftp_input, true); + + for (N_id_2=0;N_id_2<3;N_id_2++) { + generate_sss_all_tables(&sss_tables, N_id_2); + convert_tables(&q->fc_tables[N_id_2], &sss_tables); + } + q->N_id_2 = 0; + return LIBLTE_SUCCESS; + } + return LIBLTE_ERROR_INVALID_INPUTS; +} - if (dft_plan(&q->dftp_input, SSS_DFT_LEN, FORWARD, COMPLEX)) { - return -1; +int sss_synch_realloc(sss_synch_t *q, uint32_t fft_size) { + if (q != NULL && + fft_size < 2048) + { + dft_plan_free(&q->dftp_input); + if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { + sss_synch_free(q); + return LIBLTE_ERROR; + } + dft_plan_set_mirror(&q->dftp_input, true); + dft_plan_set_dc(&q->dftp_input, true); + + q->fft_size = fft_size; + return LIBLTE_SUCCESS; } - generate_N_id_1_table(q->N_id_1_table); - dft_plan_set_mirror(&q->dftp_input, true); - dft_plan_set_dc(&q->dftp_input, true); - for (N_id_2=0;N_id_2<3;N_id_2++) { - generate_sss_all_tables(&sss_tables, N_id_2); - convert_tables(&q->fc_tables[N_id_2], &sss_tables); - } - q->N_id_2 = 0; - return 0; + return LIBLTE_ERROR_INVALID_INPUTS; } void sss_synch_free(sss_synch_t *q) { @@ -66,80 +95,40 @@ void sss_synch_free(sss_synch_t *q) { } /** Sets the N_id_2 to search for */ -int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) { - if (N_id_2 < 0 || N_id_2 > 2) { +int sss_synch_set_N_id_2(sss_synch_t *q, uint32_t N_id_2) { + if (!lte_N_id_2_isvalid(N_id_2)) { fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2); - return -1; + return LIBLTE_ERROR; } else { q->N_id_2 = N_id_2; - return 0; + return LIBLTE_SUCCESS; } } /** 36.211 10.3 section 6.11.2.2 */ -void sss_put_slot(float *sss, cf_t *slot, int nof_prb, lte_cp_t cp) { - int i, k; +void sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, lte_cp_t cp) { + uint32_t i, k; k = (CP_NSYMB(cp) - 2) * nof_prb * RE_X_RB + nof_prb * RE_X_RB / 2 - 31; - memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); - for (i = 0; i < SSS_LEN; i++) { - __real__ slot[k + i] = sss[i]; - __imag__ slot[k + i] = 0; - } - memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); -} - -/* In this function, input points to the beginning of the subframe. Saves result in subframe_idx and N_id_1 - * Return 1 if the sequence was found, 0 if the peak is not found, -1 if the subframe_sz or symbol_sz are - * invalid or not configured. - * Before calling this function, the correlation threshold and symbol size duration need to be set - * using sss_synch_set_threshold() and sss_synch_set_symbol_sz(). - */ -int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1) { - int m0, m1; - float m0_value, m1_value; - - if (q->subframe_sz <= 0 || q->symbol_sz <= 0) { - return -1; - } - - sss_synch_m0m1(q, &input[SSS_SYMBOL_ST(q->subframe_sz, q->symbol_sz)], &m0, - &m0_value, &m1, &m1_value); - - if (m0_value > q->corr_peak_threshold - && m1_value > q->corr_peak_threshold) { - if (subframe_idx) { - *subframe_idx = sss_synch_subframe(m0, m1); + + if (k > 5) { + memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); + for (i = 0; i < SSS_LEN; i++) { + __real__ slot[k + i] = sss[i]; + __imag__ slot[k + i] = 0; } - if (N_id_1) { - *N_id_1 = sss_synch_N_id_1(q, m0, m1); - } - return 1; - } else { - return 0; + memset(&slot[k + SSS_LEN], 0, 5 * sizeof(cf_t)); } } -/** Used by sss_synch_frame() to compute the beginning of the SSS symbol - * symbol_sz MUST INCLUDE THE CYCLIC PREFIX SIZE - */ -void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz) { - q->symbol_sz = symbol_sz; -} - -/** Used by sss_synch_frame() to compute the beginning of the SSS symbol */ -void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz) { - q->subframe_sz = subframe_sz; -} - /** Sets the SSS correlation peak detection threshold */ void sss_synch_set_threshold(sss_synch_t *q, float threshold) { q->corr_peak_threshold = threshold; } /** Returns the subframe index based on the m0 and m1 values */ -int sss_synch_subframe(int m0, int m1) { +uint32_t sss_synch_subframe(uint32_t m0, uint32_t m1) { if (m1 > m0) { return 0; } else { @@ -148,27 +137,27 @@ int sss_synch_subframe(int m0, int m1) { } /** Returns the N_id_1 value based on the m0 and m1 values */ -int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1) { - if (m0 < 0 || m0 > 29 || m1 < 0 || m1 > 29) { - return -1; +int sss_synch_N_id_1(sss_synch_t *q, uint32_t m0, uint32_t m1) { + if (m0==m1 || m0 > 29 || m1 > 29) { + return LIBLTE_ERROR; } if (m1 > m0) { return q->N_id_1_table[m0][m1 - 1]; } else { return q->N_id_1_table[m1][m0 - 1]; - } + } } /** High-level API */ int sss_synch_initialize(sss_synch_hl* h) { - if (sss_synch_init(&h->obj)) { - return -1; + if (sss_synch_init(&h->obj, 128)) { + return LIBLTE_ERROR; } sss_synch_set_N_id_2(&h->obj, h->init.N_id_2); - return 0; + return LIBLTE_SUCCESS; } int sss_synch_work(sss_synch_hl* hl) { @@ -176,20 +165,12 @@ int sss_synch_work(sss_synch_hl* hl) { if (hl->ctrl_in.correlation_threshold) { sss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold); } - if (hl->ctrl_in.subframe_sz) { - sss_synch_set_subframe_sz(&hl->obj, hl->ctrl_in.subframe_sz); - } - if (hl->ctrl_in.symbol_sz) { - sss_synch_set_symbol_sz(&hl->obj, hl->ctrl_in.symbol_sz); - } - sss_synch_frame(&hl->obj, hl->input, &hl->ctrl_out.subframe_idx, - &hl->ctrl_out.N_id_1); - - return 0; + + return LIBLTE_SUCCESS; } int sss_synch_stop(sss_synch_hl* hl) { sss_synch_free(&hl->obj); - return 0; + return LIBLTE_SUCCESS; } diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 083922d99..28333e06a 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -25,43 +25,105 @@ * */ - - #include #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/phy_common.h" #include "liblte/phy/sync/sync.h" +#include "liblte/phy/utils/vector.h" -int sync_init(sync_t *q, int frame_size) { - bzero(q, sizeof(sync_t)); - q->threshold = 1.5; - q->pss_mode = PEAK_MEAN; - q->detect_cp = true; - q->sss_en = true; +static bool fft_size_isvalid(uint32_t fft_size) { + if (fft_size >= FFT_SIZE_MIN && fft_size <= FFT_SIZE_MAX && (fft_size%64) == 0) { + return true; + } else { + return false; + } +} - if (pss_synch_init(&q->pss, frame_size)) { - fprintf(stderr, "Error initializing PSS object\n"); - return -1; - } - if (pss_synch_init(&q->pss_track, TRACK_LEN)) { - fprintf(stderr, "Error initializing PSS track object\n"); - return -1; - } - if (sss_synch_init(&q->sss)) { - fprintf(stderr, "Error initializing SSS object\n"); - return -1; - } - DEBUG("PSS and SSS initiated\n",0); +int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, uint32_t fft_size) { + + int ret = LIBLTE_ERROR_INVALID_INPUTS; - return 0; + if (q != NULL && + find_frame_size > fft_size && + find_frame_size < 307200 && + fft_size_isvalid(fft_size)) + { + bzero(q, sizeof(sync_t)); + q->pss_mode = PEAK_MEAN; + q->detect_cp = true; + q->sss_en = true; + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->fft_size = fft_size; + q->find_frame_size = find_frame_size; + + if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return LIBLTE_ERROR; + } + if (sss_synch_init(&q->sss, fft_size)) { + fprintf(stderr, "Error initializing SSS object\n"); + return LIBLTE_ERROR; + } + if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return LIBLTE_ERROR; + } + + DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + + ret = LIBLTE_SUCCESS; + } + return ret; +} + +int sync_realloc(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, + uint32_t fft_size) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + find_frame_size > fft_size && + find_frame_size < 307200 && + fft_size_isvalid(fft_size)) + { + q->N_id_2 = 1000; + q->N_id_1 = 1000; + q->fft_size = fft_size; + q->find_frame_size = find_frame_size; + + pss_synch_free(&q->pss_find); + if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS object\n"); + return LIBLTE_ERROR; + } + + pss_synch_free(&q->pss_track); + if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { + fprintf(stderr, "Error initializing PSS track object\n"); + return LIBLTE_ERROR; + } + + if (sss_synch_realloc(&q->sss, fft_size)) { + fprintf(stderr, "Error realloc'ing SSS object\n"); + return LIBLTE_ERROR; + } + + DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + + ret = LIBLTE_SUCCESS; + } + return ret; } void sync_free(sync_t *q) { - pss_synch_free(&q->pss); - pss_synch_free(&q->pss_track); - sss_synch_free(&q->sss); + if (q) { + pss_synch_free(&q->pss_track); + pss_synch_free(&q->pss_find); + sss_synch_free(&q->sss); + } } void sync_pss_det_absolute(sync_t *q) { @@ -71,31 +133,42 @@ void sync_pss_det_peak_to_avg(sync_t *q) { q->pss_mode = PEAK_MEAN; } -void sync_set_threshold(sync_t *q, float threshold) { - q->threshold = threshold; +void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold) { + q->find_threshold = find_threshold; + q->track_threshold = track_threshold; } void sync_sss_en(sync_t *q, bool enabled) { q->sss_en = enabled; } +bool sync_sss_detected(sync_t *q) { + return lte_N_id_1_isvalid(q->N_id_1); +} + int sync_get_cell_id(sync_t *q) { - if (q->N_id_1 >=0 && q->N_id_2 >= 0) { - return q->N_id_1*3 + q->N_id_2; + if (q->N_id_2 != 10) { + if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { + return q->N_id_1*3 + q->N_id_2; + } else { + fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); + return LIBLTE_ERROR; + } } else { - return -1; + fprintf(stderr, "Error getting cell_id, N_id_2 not set\n"); + return LIBLTE_ERROR; } } -int sync_get_N_id_1(sync_t *q) { +uint32_t sync_get_N_id_1(sync_t *q) { return q->N_id_1; } -int sync_get_N_id_2(sync_t *q) { +uint32_t sync_get_N_id_2(sync_t *q) { return q->N_id_2; } -int sync_get_slot_id(sync_t *q) { +uint32_t sync_get_slot_id(sync_t *q) { return q->slot_id; } @@ -115,57 +188,66 @@ lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } -int sync_sss(sync_t *q, cf_t *input, int N_id_2, int peak_pos, bool en_cp) { - int m0, m1, sss_idx_n, sss_idx_e; +int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { + uint32_t m0, m1; + int sss_idx_n, sss_idx_e, ret; float m0_value_e, m1_value_e,m0_value_n, m1_value_n; - int slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + uint32_t slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; - sss_synch_set_N_id_2(&q->sss, N_id_2); + sss_synch_set_N_id_2(&q->sss, q->N_id_2); /* Make sure we have enough room to find SSS sequence */ - sss_idx_n = peak_pos-2*(128+CP(128,CPNORM_LEN)); - sss_idx_e = peak_pos-2*(128+CP(128,CPEXT_LEN)); + sss_idx_n = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPNORM_LEN)); + sss_idx_e = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPEXT_LEN)); if (en_cp) { if (sss_idx_n < 0 || sss_idx_e < 0) { INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); - return -1; + return LIBLTE_SUCCESS; } } else { if (CP_ISNORM(q->cp)) { if (sss_idx_n < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_n); - return -1; + INFO("Not enough room to decode normal CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_n, peak_pos); + return LIBLTE_SUCCESS; } } else { if (sss_idx_e < 0) { - INFO("Not enough room to decode SSS (%d)\n", sss_idx_e); - return -1; + INFO("Not enough room to decode extended CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_e, peak_pos); + return LIBLTE_SUCCESS; } } } - - N_id_1_e = -1; - N_id_1_n = -1; - slot_id_e = -1; - slot_id_n = -1; + + slot_id_n = 0; + slot_id_e = 0; + N_id_1_n = 0; + N_id_1_e = 0; /* try Normal CP length */ if (en_cp || CP_ISNORM(q->cp)) { - sss_synch_m0m1(&q->sss, &input[sss_idx_n], - &m0, &m0_value_n, &m1, &m1_value_n); + sss_synch_m0m1(&q->sss, &input[sss_idx_n], &m0, &m0_value_n, &m1, &m1_value_n); slot_id_n = 2 * sss_synch_subframe(m0, m1); - N_id_1_n = sss_synch_N_id_1(&q->sss, m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + N_id_1_n = (uint32_t) ret; + } else { + N_id_1_n = 1000; + } } if (en_cp || CP_ISEXT(q->cp)) { /* Now try Extended CP length */ - sss_synch_m0m1(&q->sss, &input[sss_idx_e], - &m0, &m0_value_e, &m1, &m1_value_e); + sss_synch_m0m1(&q->sss, &input[sss_idx_e], &m0, &m0_value_e, &m1, &m1_value_e); slot_id_e = 2 * sss_synch_subframe(m0, m1); - N_id_1_e = sss_synch_N_id_1(&q->sss, m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + N_id_1_e = (uint32_t) ret; + } else { + N_id_1_e = 1000; + } } /* Correlation with extended CP hypoteshis is greater than with normal? */ @@ -174,56 +256,93 @@ int sync_sss(sync_t *q, cf_t *input, int N_id_2, int peak_pos, bool en_cp) { q->cp = CPEXT; q->slot_id = slot_id_e; q->N_id_1 = N_id_1_e; - /* then is normal CP */ + /* otherwise is normal CP */ } else { q->cp = CPNORM; q->slot_id = slot_id_n; q->N_id_1 = N_id_1_n; } - INFO("SSS detected N_id_1=%d, slot_idx=%d, %s CP\n", - q->N_id_1, q->slot_id, CP_ISNORM(q->cp)?"Normal":"Extended"); + DEBUG("SSS detected N_id_1=%d, slot_idx=%d, position=%d/%d %s CP\n", + q->N_id_1, q->slot_id, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended"); - return 0; + return 1; } -int sync_track(sync_t *q, cf_t *input) { - float peak_value, mean_value; - int peak_detected = 0; - pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); +int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) { - int peak_pos = pss_synch_find_pss(&q->pss, input, &peak_value, &mean_value); + int ret = LIBLTE_ERROR_INVALID_INPUTS; - if (q->peak_to_avg > TRACK_THRESHOLD) { - peak_detected = 1; - } - if (peak_detected) { + if (q != NULL && + input != NULL && + fft_size_isvalid(q->fft_size)) + { + float peak_value, mean_value, *mean_ptr; + bool peak_detected; + uint32_t peak_pos; - q->cfo = pss_synch_cfo_compute(&q->pss, &input[peak_pos-128]); + pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); + + if (q->pss_mode == ABSOLUTE) { + mean_ptr = NULL; + } else { + mean_ptr = &mean_value; + } + + peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &peak_value, mean_ptr); - if (q->sss_en) { - if (sync_sss(q, input, q->N_id_2, peak_pos, false)) { - return -1; + peak_detected = false; + if (q->pss_mode == ABSOLUTE) { + if (peak_value > q->track_threshold) { + peak_detected = true; + } + } else { + q->peak_to_avg = peak_value / mean_value; + if (q->peak_to_avg > q->track_threshold) { + peak_detected = true; } } - - return peak_pos; - } else { - return -1; + DEBUG("PSS possible tracking peak pos=%d peak=%.2f par=%.2f threshold=%.2f\n", + peak_pos, peak_value, q->peak_to_avg, q->track_threshold); + if (peak_detected) { + q->cfo = pss_synch_cfo_compute(&q->pss_track, &input[offset+peak_pos-q->fft_size]); + + if (q->sss_en) { + if (sync_sss(q, input, offset + peak_pos, false) < 0) { + fprintf(stderr, "Error synchronizing with SSS\n"); + return LIBLTE_ERROR; + } + } + + if (peak_position) { + *peak_position = peak_pos; + } + ret = 1; + } else { + ret = LIBLTE_SUCCESS; + } } + return ret; } -int sync_find(sync_t *q, cf_t *input) { - int N_id_2, peak_pos[3]; +int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { + uint32_t N_id_2, peak_pos[3]; float peak_value[3]; float mean_value[3]; float max=-999; - int i; - int peak_detected; + uint32_t i; + int ret; + bool peak_detected; for (N_id_2=0;N_id_2<3;N_id_2++) { - pss_synch_set_N_id_2(&q->pss, N_id_2); - peak_pos[N_id_2] = pss_synch_find_pss(&q->pss, input, &peak_value[N_id_2], &mean_value[N_id_2]); + pss_synch_set_N_id_2(&q->pss_find, N_id_2); + ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2], &mean_value[N_id_2]); + if (ret < 0) { + fprintf(stderr, "Error finding PSS for N_id_2=%d\n", N_id_2); + return LIBLTE_ERROR; + } + peak_pos[N_id_2] = (uint32_t) ret; + } for (i=0;i<3;i++) { if (peak_value[i] > max) { @@ -235,38 +354,43 @@ int sync_find(sync_t *q, cf_t *input) { q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2]; DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f par=%.2f threshold=%.2f\n", - N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold); + N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->find_threshold); /* If peak detected */ - peak_detected = 0; - if (peak_pos[N_id_2] - 128 >= 0) { + peak_detected = false; + if (peak_pos[N_id_2] > q->fft_size) { if (q->pss_mode == ABSOLUTE) { - if (peak_value[N_id_2] > q->threshold) { - peak_detected = 1; + if (peak_value[N_id_2] > q->find_threshold) { + peak_detected = true; } } else { - if (q->peak_to_avg > q->threshold) { - peak_detected = 1; + if (q->peak_to_avg > q->find_threshold) { + peak_detected = true; } } } + if (peak_detected) { q->N_id_2 = N_id_2; - pss_synch_set_N_id_2(&q->pss, q->N_id_2); - q->cfo = pss_synch_cfo_compute(&q->pss, &input[peak_pos[q->N_id_2]-128]); + pss_synch_set_N_id_2(&q->pss_find, q->N_id_2); + q->cfo = pss_synch_cfo_compute(&q->pss_find, &input[peak_pos[N_id_2]-q->fft_size]); - INFO("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->threshold, q->cfo); + DEBUG("PSS peak detected N_id_2=%d, pos=%d peak=%.2f par=%.2f th=%.2f cfo=%.4f\n", N_id_2, + peak_pos[N_id_2], peak_value[N_id_2], q->peak_to_avg, q->find_threshold, q->cfo); if (q->sss_en) { - if (sync_sss(q, input, q->N_id_2, peak_pos[q->N_id_2], q->detect_cp)) { - return -1; + if (sync_sss(q, input, peak_pos[q->N_id_2], q->detect_cp) < 0) { + fprintf(stderr, "Error synchronizing with SSS\n"); + return LIBLTE_ERROR; } } + + if (peak_position) { + *peak_position = peak_pos[N_id_2]; + } - return peak_pos[N_id_2]; - + return 1; } else { - return -1; + return LIBLTE_SUCCESS; } } diff --git a/lte/phy/lib/sync/src/sync_frame.c b/lte/phy/lib/sync/src/sync_frame.c deleted file mode 100644 index 56b9de863..000000000 --- a/lte/phy/lib/sync/src/sync_frame.c +++ /dev/null @@ -1,244 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE 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 Lesser General Public License for more details. - * - * A copy of the GNU Lesser 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/. - * - */ - -#include -#include -#include -#include - -#include "liblte/phy/resampling/decim.h" -#include "liblte/phy/resampling/resample_arb.h" -#include "liblte/phy/utils/debug.h" -#include "liblte/phy/sync/sync_frame.h" - - -int sync_frame_init(sync_frame_t *q, uint32_t downsampling) { - int ret = -1; - bzero(q, sizeof(sync_frame_t)); - - if(sync_init(&q->s, SYNC_SF_LEN)) { - goto clean_exit; - } - sync_pss_det_peak_to_avg(&q->s); - - if (cfo_init(&q->cfocorr, SYNC_SF_LEN * downsampling)) { - fprintf(stderr, "Error initiating CFO\n"); - goto clean_exit; - } - - q->input_buffer = malloc(2 * SYNC_SF_LEN * downsampling * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - - q->input_downsampled = malloc(SYNC_SF_LEN * sizeof(cf_t)); - if (!q->input_downsampled) { - perror("malloc"); - goto clean_exit; - } - - resample_arb_init(&q->resample, (float) 1/downsampling); - - q->downsampling = downsampling; - sync_frame_reset(q); - ret = 0; - -clean_exit: - if (ret == -1) { - sync_frame_free(q); - } - return ret; -} - -void sync_frame_free(sync_frame_t *q) { - if (q->input_buffer) { - free(q->input_buffer); - } - if (q->input_downsampled) { - free(q->input_downsampled); - } - - cfo_free(&q->cfocorr); - sync_free(&q->s); -} - -void sync_frame_run(sync_frame_t *q, cf_t *input) { - uint32_t track_idx; - - switch (q->state) { - - case SF_FIND: - q->peak_idx = sync_find(&q->s, input); - q->cell_id = sync_get_cell_id(&q->s); - - INFO("FIND %3d:\tPAR=%.2f\n", (int) q->frame_cnt, sync_get_peak_to_avg(&q->s)); - - if (q->peak_idx != -1 && q->cell_id != -1) { - - /* Get the subframe index (0 or 5) */ - q->sf_idx = sync_get_slot_id(&q->s)/2; - - /* Reset variables */ - q->last_found = 0; - q->timeoffset = 0; - q->frame_cnt = 0; - - /* Goto Tracking state */ - q->state = SF_TRACK; - } - break; - case SF_TRACK: - - q->sf_idx = (q->sf_idx + 1) % 10; - - /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ - if (q->sf_idx != 0 && q->sf_idx != 5) { - break; - } - - assert(q->peak_idx < TRACK_LEN); - - track_idx = sync_track(&q->s, &input[q->peak_idx - TRACK_LEN]); - - INFO("TRACK %3d: SF=%d. Previous idx is %d New Offset is %d\n", - (int) q->frame_cnt, q->sf_idx, q->peak_idx, track_idx - TRACK_LEN); - - if (track_idx != -1) { - INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx, - sync_get_slot_id(&q->s)/2); - - /* Make sure subframe idx is what we expect */ - if (q->sf_idx != sync_get_slot_id(&q->s)/2) { - INFO("Expected SF idx %d but got %d. Going back to FIND\n", q->sf_idx, - sync_get_slot_id(&q->s)/2); - q->state = SF_FIND; - } - - /* compute cumulative moving average CFO */ - q->cur_cfo = (sync_get_cfo(&q->s) + q->frame_cnt * q->cur_cfo) / (q->frame_cnt + 1); - - /* compute cumulative moving average time offset */ - q->timeoffset = (float) ((float) track_idx - TRACK_LEN + q->timeoffset * q->frame_cnt) - / (q->frame_cnt + 1); - - q->last_found = q->frame_cnt; - q->peak_idx = (q->peak_idx + track_idx - TRACK_LEN) % SYNC_SF_LEN; - - if (q->peak_idx < 0) { - INFO("PSS lost (peak_idx=%d). Going back to FIND\n", q->peak_idx); - q->state = SF_FIND; - } - } else { - /* if sync not found, adjust time offset with the averaged value */ - q->peak_idx = (q->peak_idx + (uint32_t) q->timeoffset) % SYNC_SF_LEN; - - /* if we missed too many PSS go back to FIND */ - if (q->frame_cnt - q->last_found > TRACK_MAX_LOST) { - INFO("%d frames lost. Going back to FIND", (int) q->frame_cnt - q->last_found); - q->state = SF_FIND; - } - } - q->frame_cnt++; - break; - } -} - -void sync_frame_set_threshold(sync_frame_t *q, float threshold) { - sync_set_threshold(&q->s, threshold); -} - -uint32_t sync_frame_cell_id(sync_frame_t *q) { - return q->cell_id; -} - -uint32_t sync_frame_sfidx(sync_frame_t *q) { - return q->sf_idx; -} - - -int sync_frame_push(sync_frame_t *q, cf_t *input, cf_t *output) { - int retval = 0; - int frame_start; - cf_t *input_ds; - uint32_t sf_len; - - if (q->downsampling == 1) { - input_ds = input; - } else { - //resample_arb_compute(&q->resample, input, q->input_downsampled, SYNC_SF_LEN * q->downsampling); - decim_c(input, q->input_downsampled, q->downsampling, SYNC_SF_LEN * q->downsampling); - input_ds = q->input_downsampled; - } - - sync_frame_run(q, input_ds); - - sf_len = q->downsampling * SYNC_SF_LEN; - - if (q->state == SF_FIND) { - memcpy(q->input_buffer, input, sf_len * sizeof(cf_t)); - } else { - frame_start = q->downsampling * q->peak_idx - sf_len/2; - - DEBUG("Peak_idx=%d, frame_start=%d cfo=%.3f\n",q->peak_idx, - frame_start, q->cur_cfo); - - if (frame_start > 0) { - if (q->fb_wp) { - memcpy(&q->input_buffer[(sf_len - frame_start)], input, frame_start * sizeof(cf_t)); - memcpy(output, q->input_buffer, sf_len * sizeof(cf_t)); - retval = 1; - } - memcpy(q->input_buffer, &input[frame_start], (sf_len - frame_start) * sizeof(cf_t)); - q->fb_wp = true; - } else { - memcpy(output, &q->input_buffer[sf_len + frame_start], (-frame_start) * sizeof(cf_t)); - memcpy(&output[-frame_start], input, (sf_len + frame_start) * sizeof(cf_t)); - memcpy(&q->input_buffer[sf_len + frame_start], &input[sf_len + frame_start], (-frame_start) * sizeof(cf_t)); - retval = 1; - } - } - - /* Frequency Synchronization */ - if (retval) { - cfo_correct(&q->cfocorr, output, -q->cur_cfo / 128); - } - - if (!retval) { - DEBUG("Frame Buffered\n",0); - } - - return retval; -} - -void sync_frame_reset(sync_frame_t *q) { - q->state = SF_FIND; - q->frame_cnt = 0; - q->fb_wp = false; - q->cur_cfo = 0; -} - diff --git a/lte/phy/lib/sync/test/CMakeLists.txt b/lte/phy/lib/sync/test/CMakeLists.txt index 2c5b29c3b..72b2ccb6a 100644 --- a/lte/phy/lib/sync/test/CMakeLists.txt +++ b/lte/phy/lib/sync/test/CMakeLists.txt @@ -19,6 +19,7 @@ # and at http://www.gnu.org/licenses/. # + ######################################################################## # SYNC TEST ######################################################################## diff --git a/lte/phy/lib/sync/test/cfo_test.c b/lte/phy/lib/sync/test/cfo_test.c index 1ccb17cc2..5c6086c15 100644 --- a/lte/phy/lib/sync/test/cfo_test.c +++ b/lte/phy/lib/sync/test/cfo_test.c @@ -96,8 +96,8 @@ int main(int argc, char **argv) { return -1; } - cfo_correct(&cfocorr, output, freq); - cfo_correct(&cfocorr, output, -freq); + cfo_correct(&cfocorr, output, output, freq); + cfo_correct(&cfocorr, output, output, -freq); mse = 0; for (i=0;isize = size; h->tab = malloc(sizeof(cf_t) * size); @@ -42,9 +42,9 @@ int cexptab_init(cexptab_t *h, int size) { for (i = 0; i < size; i++) { h->tab[i] = cexpf(_Complex_I * 2 * M_PI * (float) i / size); } - return 0; + return LIBLTE_SUCCESS; } else { - return -1; + return LIBLTE_ERROR; } } @@ -55,9 +55,9 @@ void cexptab_free(cexptab_t *h) { bzero(h, sizeof(cexptab_t)); } -void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { - int i; - unsigned int idx; +void cexptab_gen(cexptab_t *h, cf_t *x, float freq, uint32_t len) { + uint32_t i; + uint32_t idx; float phase_inc = freq * h->size; float phase=0; @@ -68,15 +68,15 @@ void cexptab_gen(cexptab_t *h, cf_t *x, float freq, int len) { while (phase < 0) { phase += (float) h->size; } - idx = (unsigned int) phase; + idx = (uint32_t) phase; x[i] = h->tab[idx]; phase += phase_inc; } } -void cexptab_gen_direct(cf_t *x, float freq, int len) { - int i; +void cexptab_gen_direct(cf_t *x, float freq, uint32_t len) { + uint32_t i; for (i = 0; i < len; i++) { x[i] = cexpf(_Complex_I * 2 * M_PI * freq * i); } diff --git a/lte/phy/lib/utils/src/convolution.c b/lte/phy/lib/utils/src/convolution.c index 2ab27e041..721595f80 100644 --- a/lte/phy/lib/utils/src/convolution.c +++ b/lte/phy/lib/utils/src/convolution.c @@ -34,61 +34,61 @@ #include "liblte/phy/utils/convolution.h" -int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len) { - state->input_len = input_len; - state->filter_len = filter_len; - state->output_len = input_len+filter_len-1; - state->input_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - state->filter_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - state->output_fft = vec_malloc(sizeof(_Complex float)*state->output_len); - if (!state->input_fft || !state->filter_fft || !state->output_fft) { - return -1; +int conv_fft_cc_init(conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) { + q->input_len = input_len; + q->filter_len = filter_len; + q->output_len = input_len+filter_len; + q->input_fft = vec_malloc(sizeof(cf_t)*q->output_len); + q->filter_fft = vec_malloc(sizeof(cf_t)*q->output_len); + q->output_fft = vec_malloc(sizeof(cf_t)*q->output_len); + if (!q->input_fft || !q->filter_fft || !q->output_fft) { + return LIBLTE_ERROR; } - if (dft_plan(&state->input_plan,state->output_len,FORWARD,COMPLEX)) { - return -2; + if (dft_plan(&q->input_plan,q->output_len,FORWARD,COMPLEX)) { + return LIBLTE_ERROR; } - if (dft_plan(&state->filter_plan,state->output_len,FORWARD,COMPLEX)) { - return -3; + if (dft_plan(&q->filter_plan,q->output_len,FORWARD,COMPLEX)) { + return LIBLTE_ERROR; } - if (dft_plan(&state->output_plan,state->output_len,BACKWARD,COMPLEX)) { - return -4; + if (dft_plan(&q->output_plan,q->output_len,BACKWARD,COMPLEX)) { + return LIBLTE_ERROR; } - return 0; + return LIBLTE_SUCCESS; } -void conv_fft_cc_free(conv_fft_cc_t *state) { - if (state->input_fft) { - free(state->input_fft); +void conv_fft_cc_free(conv_fft_cc_t *q) { + if (q->input_fft) { + free(q->input_fft); } - if (state->filter_fft) { - free(state->filter_fft); + if (q->filter_fft) { + free(q->filter_fft); } - if (state->output_fft) { - free(state->output_fft); + if (q->output_fft) { + free(q->output_fft); } - dft_plan_free(&state->input_plan); - dft_plan_free(&state->filter_plan); - dft_plan_free(&state->output_plan); + dft_plan_free(&q->input_plan); + dft_plan_free(&q->filter_plan); + dft_plan_free(&q->output_plan); } -int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output) { +uint32_t conv_fft_cc_run(conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *output) { - dft_run_c(&state->input_plan, input, state->input_fft); - dft_run_c(&state->filter_plan, filter, state->filter_fft); + dft_run_c(&q->input_plan, input, q->input_fft); + dft_run_c(&q->filter_plan, filter, q->filter_fft); - vec_prod_ccc(state->input_fft,state->filter_fft,state->output_fft,state->output_len); + vec_prod_ccc(q->input_fft,q->filter_fft,q->output_fft,q->output_len); - dft_run_c(&state->output_plan, state->output_fft, output); + dft_run_c(&q->output_plan, q->output_fft, output); - return state->output_len; + return q->output_len; } -int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len) { - int i,j; - int output_len; +uint32_t conv_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t input_len, uint32_t filter_len) { + uint32_t i,j; + uint32_t output_len; output_len=input_len+filter_len-1; - memset(output,0,output_len*sizeof(_Complex float)); + memset(output,0,output_len*sizeof(cf_t)); for (i=0;i #include #include +#include + +#include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/bit.h" #ifdef HAVE_VOLK #include "volk/volk.h" #endif -int vec_acc_ii(int *x, int len) { +int vec_acc_ii(int *x, uint32_t len) { int i; int z=0; for (i=0;im) { m=x[i]; @@ -244,7 +386,7 @@ int vec_max_fi(float *x, int len) { #endif } -void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len) { +void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len) { int i; int tmp; for (i=0;i 128 && i threshold) - y=ccf.*x(i-128:i-1); - - y0=y(1:64); - y1=y(65:length(y)); - - eps=angle(conj(sum(y0))*sum(y1))/pi; - else - eps = NaN; - fs = NaN; - end end diff --git a/matlab/sync/lte_generate_sss.m b/matlab/sync/lte_generate_sss.m deleted file mode 100644 index d8b45e914..000000000 --- a/matlab/sync/lte_generate_sss.m +++ /dev/null @@ -1,123 +0,0 @@ -% -% Copyright 2011-2012 Ben Wojtowicz -% -% This program 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. -% -% This program 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. -% -% You should have received a copy of the GNU Affero General Public License -% along with this program. If not, see . -% -% Function: lte_generate_sss -% Description: Generates LTE secondary synchronization signals -% Inputs: N_id_1 - Physical layer cell identity group -% N_id_2 - Physical layer identity -% Outputs: sss_d_u_0 - The sequence d(n) used for the secondary -% synchronization signal, an interleaved -% concatenation of two length-31 binary -% sequences for subframe 0 -% Outputs: sss_d_u_5 - The sequence d(n) used for the secondary -% synchronization signal, an interleaved -% concatenation of two length-31 binary -% sequences for subframe 5 -% Spec: 3GPP TS 36.211 section 6.11.2.1 v10.1.0 -% Notes: None -% Rev History: Ben Wojtowicz 10/28/2011 Created -% Ben Wojtowicz 01/29/2012 Fixed license statement -% -function [sss_d_u_0, sss_d_u_5 c0 c1 m0 m1] = lte_generate_sss(N_id_1, N_id_2) - % Validate N_id_1 - if(~(N_id_1 >= 0 && N_id_1 <= 167)) - fprintf('ERROR: Invalid N_id_1 (%u)\n', N_id_1); - sss_d_u_0 = 0; - sss_d_u_5 = 0; - return; - end - - % Validate N_id_2 - if(~(N_id_2 >= 0 && N_id_2 <= 2)) - fprintf('ERROR: Invalid N_id_2 (%u)\n', N_id_2); - sss_d_u_0 = 0; - sss_d_u_5 = 0; - return; - end - - % Generate m0 and m1 - q_prime = floor(N_id_1/30); - q = floor((N_id_1 + (q_prime*(q_prime+1)/2))/30); - m_prime = N_id_1 + (q*(q+1)/2); - m0 = mod(m_prime, 31); - m1 = mod((m0 + floor(m_prime/31) + 1), 31); - - % Generate s_tilda - x_s_tilda(0+1) = 0; - x_s_tilda(1+1) = 0; - x_s_tilda(2+1) = 0; - x_s_tilda(3+1) = 0; - x_s_tilda(4+1) = 1; - for(i_hat=0:25) - x_s_tilda(i_hat+5+1) = mod((x_s_tilda(i_hat+2+1) + x_s_tilda(i_hat+1)), 2); - end - for(idx=0:30) - s_tilda(idx+1) = 1 - 2*x_s_tilda(idx+1); - end - - % Generate c_tilda - x_c_tilda(0+1) = 0; - x_c_tilda(1+1) = 0; - x_c_tilda(2+1) = 0; - x_c_tilda(3+1) = 0; - x_c_tilda(4+1) = 1; - for(i_hat=0:25) - x_c_tilda(i_hat+5+1) = mod((x_c_tilda(i_hat+3+1) + x_c_tilda(i_hat+1)), 2); - end - for(idx=0:30) - c_tilda(idx+1) = 1 - 2*x_c_tilda(idx+1); - end - - % Generate z_tilda - x_z_tilda(0+1) = 0; - x_z_tilda(1+1) = 0; - x_z_tilda(2+1) = 0; - x_z_tilda(3+1) = 0; - x_z_tilda(4+1) = 1; - for(i_hat=0:25) - x_z_tilda(i_hat+5+1) = mod((x_z_tilda(i_hat+4+1) + x_z_tilda(i_hat+2+1) + x_z_tilda(i_hat+1+1) + x_z_tilda(i_hat+1)), 2); - end - for(idx=0:30) - z_tilda(idx+1) = 1 - 2*x_z_tilda(idx+1); - end - - % Generate s0_m0 and s1_m1 - for(n=0:30) - s0_m0(n+1) = s_tilda(mod(n + m0, 31)+1); - s1_m1(n+1) = s_tilda(mod(n + m1, 31)+1); - end - - % Generate c0 and c1 - for(n=0:30) - c0(n+1) = c_tilda(mod(n + N_id_2, 31)+1); - c1(n+1) = c_tilda(mod(n + N_id_2 + 3, 31)+1); - end - - % Generate z1_m0 and z1_m1 - for(n=0:30) - z1_m0(n+1) = z_tilda(mod(n + mod(m0, 8), 31)+1); - z1_m1(n+1) = z_tilda(mod(n + mod(m1, 8), 31)+1); - end - - % Generate SSS - for(n=0:30) - sss_d_u_0(2*n+1) = s0_m0(n+1) * c0(n+1); - sss_d_u_5(2*n+1) = s1_m1(n+1) * c0(n+1); - - sss_d_u_0(2*n+1+1) = s1_m1(n+1) * c1(n+1) * z1_m0(n+1); - sss_d_u_5(2*n+1+1) = s0_m0(n+1) * c1(n+1) * z1_m1(n+1); - end -end diff --git a/matlab/sync/test.m b/matlab/sync/test.m deleted file mode 100644 index 33d3d6e92..000000000 --- a/matlab/sync/test.m +++ /dev/null @@ -1,35 +0,0 @@ -N=128; %128 subcarries -M=16; %QAM order -cp=9; %length of the cyclic prefix... Is increasing the cyclic prefix size gonna increase the efficiency? -scale = 1/sqrt(10); -hMod = modem.qammod(M); %QAM Modulator -hDemod = modem.qamdemod(hMod); %QAM demodulator -loops = 10; -SNR =0:5:35; -t1= cputime ; -% transmited signal. Contains N data points ranging from 0 to M-1 -ber=zeros(5,length(SNR)); -%% Creating the Rayleigh Multipath Channels -Ch = rayleighchan(1/1000,10); -Ch.ResetBeforeFiltering = 0; -sig = 1i*ones(loops,1); -h1 = filter(Ch,sig); -h2 = 0.1072*filter(Ch,sig); -h3 = 0.0120*filter(Ch,sig); -h4 = 0.0052*filter(Ch,sig); -% Delay Values -l1 = 4; -l2 = 7; -l3= 16; -%% -ofdm_cp=[]; - %tx=transmited_data; - for ik=1:loops%number of loops - tx = randi([0 M-1],1,N); % generate random data - sig=modulate(hMod, tx)*scale; % Modulate QAM modulated signal, devide by the square root of 10 to bring the average power of the signal to 1 - ofdm=sqrt(N).*ifft(sig,N); % generate OFDM signal IFFT on the parrellel data,multiply by sqrt(N) to adjust to the matlab computation , - ofdm_cp = [ofdm_cp ofdm(N-cp+1:N) ofdm]; % Add cyclic prefix - - end - - \ No newline at end of file