mirror of https://github.com/PentHertz/srsLTE.git
Fixed PDSCH UE example. Added ue_dl and ue_sync modules. Fixed other minor bugs
This commit is contained in:
parent
09243c7996
commit
7372d3a386
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -31,26 +31,63 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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<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;
|
||||
}
|
||||
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<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_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<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_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<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_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<cuhd_handler*>(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<cuhd_handler*>(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<cuhd_handler*>(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<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;
|
||||
} while(n<nsamples);
|
||||
return nsamples;
|
||||
} else {
|
||||
return handler->rx_stream->recv(data, nsamples, md, 0.0);
|
||||
}
|
||||
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
|
||||
cuhd_handler* handler = static_cast<cuhd_handler*>(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<cuhd_handler*>(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<cuhd_handler*>(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<cuhd_handler*>(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(n<nsamples);
|
||||
return n;
|
||||
} else {
|
||||
p = handler->rx_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<cuhd_handler*>(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<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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -37,83 +37,59 @@
|
|||
#include <signal.h>
|
||||
|
||||
#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<nof_locations && crc_rem != 1234;i++) {
|
||||
if (pdcch_extract_llr(&pdcch, fft_buffer, ce, locations[i], sf_idx, cfi)) {
|
||||
fprintf(stderr, "Error extracting LLRs\n");
|
||||
return -1;
|
||||
}
|
||||
if (pdcch_decode_msg(&pdcch, &dci_msg, Format1, &crc_rem)) {
|
||||
fprintf(stderr, "Error decoding DCI msg\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (crc_rem == 1234) {
|
||||
if (dci_msg_to_ra_dl(&dci_msg, 1234, 1234, cell, cfi, &ra_dl)) {
|
||||
fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &ra_dl.prb_alloc)) {
|
||||
fprintf(stderr, "Error configuring HARQ process\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, &harq_process, ra_dl.rv_idx)) {
|
||||
pkt_errors++;
|
||||
}
|
||||
pkts_total++;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!disable_plots && crc_rem == 1234) {
|
||||
int n_re = 2 * RE_X_RB * CPNORM_NSYMB * cell.nof_prb;
|
||||
for (i = 0; i < n_re; i++) {
|
||||
tmp_plot[i] = 10 * log10f(cabsf(fft_buffer[i]));
|
||||
if (isinf(tmp_plot[i])) {
|
||||
tmp_plot[i] = -80;
|
||||
}
|
||||
}
|
||||
plot_real_setNewData(&poutfft, tmp_plot, n_re);
|
||||
plot_complex_setNewData(&pce, ce[0], n_re);
|
||||
plot_scatter_setNewData(&pscatrecv, pdsch.pdsch_symbols[0], ra_dl.prb_alloc.re_sf[sf_idx]);
|
||||
plot_scatter_setNewData(&pscatequal, pdsch.pdsch_d, ra_dl.prb_alloc.re_sf[sf_idx]);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
|
||||
lte_fft_run_sf(&fft, input, fft_buffer);
|
||||
|
||||
/* Get channel estimates for each port */
|
||||
chest_ce_sf(&chest, fft_buffer, ce, 0);
|
||||
|
||||
DEBUG("Decoding PBCH\n", 0);
|
||||
return pbch_decode(&pbch, fft_buffer, ce, mib);
|
||||
}
|
||||
|
||||
int run_receiver(cf_t *input, uint32_t cell_id, uint32_t sf_idx) {
|
||||
pbch_mib_t mib;
|
||||
|
||||
if (!cell_id_initated) {
|
||||
cell_id_init(sampling_nof_prb, cell_id);
|
||||
}
|
||||
if (!cell.nof_prb || pbch_only) {
|
||||
|
||||
if (!sf_idx) {
|
||||
if (mib_decoder_run(input, &mib)) {
|
||||
INFO("MIB decoded!\n", 0);
|
||||
cell.id = cell_id;
|
||||
cell.cp = CPNORM;
|
||||
cell.nof_ports = mib.nof_ports;
|
||||
cell.nof_prb = mib.nof_prb;
|
||||
frame_number = mib.sfn;
|
||||
|
||||
if (!mib_initiated) {
|
||||
if (mib_init(mib.phich_resources, mib.phich_length)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (VERBOSE_ISINFO() || !frame_cnt) {
|
||||
CLRSTDOUT;
|
||||
printf(" - Phy. CellId:\t %d\n", cell_id);
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
}
|
||||
} else if (pbch_only) {
|
||||
pkt_errors++;
|
||||
}
|
||||
if (pbch_only) {
|
||||
#ifndef DISABLE_GRAPHICS
|
||||
if (!disable_plots) {
|
||||
int i;
|
||||
int n_re = 2 * RE_X_RB * CPNORM_NSYMB * sampling_nof_prb;
|
||||
for (i = 0; i < n_re; i++) {
|
||||
tmp_plot[i] = 10 * log10f(cabsf(fft_buffer[i]));
|
||||
if (isinf(tmp_plot[i])) {
|
||||
tmp_plot[i] = -80;
|
||||
}
|
||||
}
|
||||
plot_real_setNewData(&poutfft, tmp_plot, n_re);
|
||||
plot_complex_setNewData(&pce, ce[0], n_re);
|
||||
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
|
||||
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
|
||||
}
|
||||
#endif
|
||||
pkts_total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cell.nof_prb && !pbch_only) {
|
||||
if (pdsch_run(input, sf_idx)) {
|
||||
fprintf(stderr, "\nError running PDSCH decoder\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sigintHandler(int sig_num) {
|
||||
go_exit = 1;
|
||||
}
|
||||
|
||||
void setup_uhd() {
|
||||
double samp_freq;
|
||||
|
||||
#ifndef DISABLE_UHD
|
||||
/* Get the sampling rate from the number of PRB */
|
||||
samp_freq = lte_sampling_freq_hz(sampling_nof_prb);
|
||||
|
||||
INFO("Setting sampling frequency %.2f MHz\n", (float) samp_freq/MHZ);
|
||||
cuhd_set_rx_srate(uhd, samp_freq);
|
||||
cuhd_set_rx_gain(uhd, uhd_gain);
|
||||
|
||||
/* set uhd_freq */
|
||||
cuhd_set_rx_freq(uhd, (double) uhd_freq);
|
||||
cuhd_rx_wait_lo_locked(uhd);
|
||||
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq);
|
||||
|
||||
DEBUG("Starting receiver...\n", 0);
|
||||
cuhd_start_rx_stream(uhd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void read_io(cf_t *buffer, int nsamples) {
|
||||
int n;
|
||||
DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", nsamples);
|
||||
if (input_file_name) {
|
||||
n = filesource_read(&fsrc, buffer, nsamples);
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
exit(-1);
|
||||
/* wrap file if arrive to end */
|
||||
} else if (n < nsamples) {
|
||||
DEBUG("Read %d from file. Seeking to 0\n",n);
|
||||
filesource_seek(&fsrc, 0);
|
||||
filesource_read(&fsrc, buffer, nsamples);
|
||||
}
|
||||
} else {
|
||||
#ifndef DISABLE_UHD
|
||||
cuhd_recv(uhd, buffer, nsamples, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int ret;
|
||||
uint32_t sf_idx;
|
||||
uint32_t cell_id;
|
||||
cf_t *in_ptr;
|
||||
|
||||
#ifdef DISABLE_UHD
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
parse_args(argc, argv);
|
||||
|
||||
if (base_init(sampling_nof_prb)) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* If input_file_name is NULL, we read from the USRP */
|
||||
if (!input_file_name) {
|
||||
setup_uhd();
|
||||
}
|
||||
|
||||
printf("\n --- Press Ctrl+C to exit --- \n");
|
||||
|
||||
signal(SIGINT, sigintHandler);
|
||||
|
||||
/* Initialize variables */
|
||||
frame_cnt = 0;
|
||||
frame_number = -1;
|
||||
|
||||
/* The number of samples read from the USRP or file corresponds to 1 ms (subframe) */
|
||||
sf_n_samples = 1920 * lte_symbol_sz(sampling_nof_prb)/128;
|
||||
|
||||
sync_frame_set_threshold(&sframe, find_threshold);
|
||||
|
||||
sf_idx = 0;
|
||||
cell_id = cell_id_file;
|
||||
if (input_file_name) {
|
||||
in_ptr = input_buffer;
|
||||
} else {
|
||||
in_ptr = sf_buffer;
|
||||
}
|
||||
|
||||
while (!go_exit && (frame_cnt < nof_frames || nof_frames == -1)) {
|
||||
|
||||
read_io(input_buffer, sf_n_samples);
|
||||
|
||||
if (!input_file_name) {
|
||||
ret = sync_frame_push(&sframe, input_buffer, sf_buffer);
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
switch(ret ) {
|
||||
case 0:
|
||||
/* not yet synched */
|
||||
break;
|
||||
case 1:
|
||||
/* sf_buffer is aligned to the subframe */
|
||||
|
||||
if (!(frame_cnt%10)) {
|
||||
frame_number++;
|
||||
}
|
||||
|
||||
if (!input_file_name) {
|
||||
sf_idx = sync_frame_sfidx(&sframe);
|
||||
cell_id = sync_frame_cell_id(&sframe);
|
||||
}
|
||||
|
||||
/* synch'd and tracking */
|
||||
if (run_receiver(in_ptr, cell_id, sf_idx)) {
|
||||
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (!(frame_cnt % 10)) {
|
||||
printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r",
|
||||
frame_number, sframe.cur_cfo * 15, sframe.timeoffset / 5, sframe.peak_idx,
|
||||
pkt_errors, pkts_total,
|
||||
(float) pkt_errors / pkts_total);
|
||||
fflush(stdout);
|
||||
}
|
||||
if (input_file_name) {
|
||||
sf_idx++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error running automatic synchronization\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
frame_cnt++;
|
||||
if (input_file_name) {
|
||||
usleep(5000);
|
||||
}
|
||||
}
|
||||
|
||||
base_free();
|
||||
|
||||
printf("\nBye\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -162,11 +162,11 @@ int base_init(int frame_length) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
if (sync_init(&ssync, FLEN)) {
|
||||
if (sync_init(&ssync, FLEN, 128, 128)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) {
|
||||
if (chest_init(&chest, CPNORM, 6, MAX_PORTS)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -349,12 +349,14 @@ int main(int argc, char **argv) {
|
|||
int cell_id;
|
||||
float max_peak_to_avg;
|
||||
float sfo;
|
||||
int find_idx, track_idx, last_found;
|
||||
uint32_t track_idx, find_idx;
|
||||
int last_found;
|
||||
enum sync_state state;
|
||||
int n;
|
||||
int mib_attempts;
|
||||
int nslot;
|
||||
pbch_mib_t mib;
|
||||
int ret;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
|
@ -434,14 +436,14 @@ int main(int argc, char **argv) {
|
|||
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
#endif
|
||||
/* set find_threshold and go to FIND state */
|
||||
sync_set_threshold(&ssync, find_threshold);
|
||||
sync_set_threshold(&ssync, find_threshold, find_threshold/2);
|
||||
state = FIND;
|
||||
break;
|
||||
case FIND:
|
||||
/* find peak in all frame */
|
||||
find_idx = sync_find(&ssync, &input_buffer[FLEN]);
|
||||
ret = sync_find(&ssync, &input_buffer[FLEN], &find_idx);
|
||||
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&ssync));
|
||||
if (find_idx != -1) {
|
||||
if (ret == 1) {
|
||||
/* if found peak, go to track and set lower threshold */
|
||||
frame_cnt = -1;
|
||||
last_found = 0;
|
||||
|
@ -462,7 +464,7 @@ int main(int argc, char **argv) {
|
|||
case TRACK:
|
||||
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len);
|
||||
|
||||
track_idx = sync_track(&ssync, &input_buffer[FLEN + find_idx - track_len]);
|
||||
ret = sync_track(&ssync, input_buffer, FLEN + find_idx - track_len, &track_idx);
|
||||
p2a_v[frame_cnt] = sync_get_peak_to_avg(&ssync);
|
||||
|
||||
/* save cell id for the best peak-to-avg */
|
||||
|
@ -470,7 +472,7 @@ int main(int argc, char **argv) {
|
|||
max_peak_to_avg = p2a_v[frame_cnt];
|
||||
cell_id = sync_get_cell_id(&ssync);
|
||||
}
|
||||
if (track_idx != -1) {
|
||||
if (ret == 1) {
|
||||
cfo_v[frame_cnt] = sync_get_cfo(&ssync);
|
||||
last_found = frame_cnt;
|
||||
find_idx += track_idx - track_len;
|
||||
|
@ -506,7 +508,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
// Correct CFO
|
||||
INFO("Correcting CFO=%.4f\n", cfo[freq]);
|
||||
cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128);
|
||||
cfo_correct(&cfocorr, &input_buffer[FLEN], &input_buffer[FLEN], (-cfo[freq])/128);
|
||||
|
||||
if (nslot == 0) {
|
||||
if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) {
|
||||
|
|
|
@ -261,10 +261,12 @@ int main(int argc, char **argv) {
|
|||
sync_t sfind, strack;
|
||||
float max_peak_to_avg;
|
||||
float sfo;
|
||||
int find_idx, track_idx, last_found;
|
||||
uint32_t find_idx, track_idx;
|
||||
int last_found;
|
||||
enum sync_state state;
|
||||
int n;
|
||||
filesink_t fs;
|
||||
int ret;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
|
@ -278,13 +280,13 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (sync_init(&sfind, FLEN)) {
|
||||
if (sync_init(&sfind, FLEN, 128, 128)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
sync_pss_det_peak_to_avg(&sfind);
|
||||
|
||||
if (sync_init(&strack, track_len)) {
|
||||
if (sync_init(&strack, track_len, 128, 128)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -315,6 +317,9 @@ int main(int argc, char **argv) {
|
|||
max_peak_to_avg = 0;
|
||||
last_found = 0;
|
||||
frame_cnt = 0;
|
||||
|
||||
sync_set_threshold(&sfind, find_threshold, track_threshold);
|
||||
|
||||
while(freq<nof_bands) {
|
||||
/* scan only bands above rssi_threshold */
|
||||
if (!IS_SIGNAL(freq)) {
|
||||
|
@ -346,19 +351,16 @@ int main(int argc, char **argv) {
|
|||
/* receive first frame */
|
||||
cuhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
|
||||
/* set find_threshold and go to FIND state */
|
||||
sync_set_threshold(&sfind, find_threshold);
|
||||
state = FIND;
|
||||
break;
|
||||
case FIND:
|
||||
/* find peak in all frame */
|
||||
find_idx = sync_find(&sfind, &input_buffer[FLEN]);
|
||||
ret = sync_find(&sfind, &input_buffer[FLEN], &find_idx);
|
||||
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
|
||||
if (find_idx != -1) {
|
||||
if (ret == 1) {
|
||||
/* if found peak, go to track and set lower threshold */
|
||||
frame_cnt = -1;
|
||||
last_found = 0;
|
||||
sync_set_threshold(&strack, track_threshold);
|
||||
state = TRACK;
|
||||
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
|
||||
channels[freq].id, channels[freq].fd,
|
||||
|
@ -380,7 +382,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len);
|
||||
|
||||
track_idx = sync_find(&strack, &input_buffer[FLEN + find_idx - track_len]);
|
||||
ret = sync_find(&strack, &input_buffer[FLEN + find_idx - track_len], &track_idx);
|
||||
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
|
||||
|
||||
/* save cell id for the best peak-to-avg */
|
||||
|
@ -388,7 +390,7 @@ int main(int argc, char **argv) {
|
|||
max_peak_to_avg = p2a_v[frame_cnt];
|
||||
cell_id = sync_get_cell_id(&strack);
|
||||
}
|
||||
if (track_idx != -1) {
|
||||
if (ret == 1) {
|
||||
cfo_v[frame_cnt] = sync_get_cfo(&strack);
|
||||
last_found = frame_cnt;
|
||||
find_idx += track_idx - track_len;
|
||||
|
|
|
@ -112,10 +112,10 @@ int main(int argc, char **argv) {
|
|||
float mean_value[3];
|
||||
int frame_cnt;
|
||||
cf_t *input;
|
||||
int m0, m1;
|
||||
uint32_t m0, m1;
|
||||
float m0_value, m1_value;
|
||||
int N_id_2;
|
||||
int sss_idx;
|
||||
uint32_t N_id_2;
|
||||
uint32_t sss_idx;
|
||||
struct timeval tdata[3];
|
||||
int *exec_time;
|
||||
|
||||
|
@ -173,7 +173,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error initializing N_id_2\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (sss_synch_init(&sss[N_id_2])) {
|
||||
if (sss_synch_init(&sss[N_id_2], 128)) {
|
||||
fprintf(stderr, "Error initializing SSS object\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ int main(int argc, char **argv) {
|
|||
|
||||
gettimeofday(&tdata[1], NULL);
|
||||
if (force_cfo != CFO_AUTO) {
|
||||
cfo_correct(&cfocorr, input, -force_cfo/128);
|
||||
cfo_correct(&cfocorr, input, input, -force_cfo/128);
|
||||
}
|
||||
|
||||
if (force_N_id_2 != -1) {
|
||||
|
|
|
@ -33,19 +33,19 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,6 +73,7 @@ typedef struct LIBLTE_API {
|
|||
lte_cell_t cell;
|
||||
|
||||
uint32_t max_symbols;
|
||||
bool rnti_is_set;
|
||||
uint16_t rnti;
|
||||
|
||||
/* buffers */
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 <stdbool.h>
|
||||
|
||||
#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_
|
||||
|
|
@ -54,6 +54,10 @@
|
|||
#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
|
||||
|
|
|
@ -26,15 +26,73 @@
|
|||
*/
|
||||
|
||||
#ifndef INTERP_H
|
||||
#define INTERP_H_
|
||||
#define INTERP_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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];
|
||||
|
@ -70,34 +65,67 @@ typedef struct LIBLTE_API {
|
|||
|
||||
dft_plan_t dftp_input;
|
||||
|
||||
float corr_peak_threshold;
|
||||
int symbol_sz;
|
||||
int subframe_sz;
|
||||
int N_id_2;
|
||||
uint32_t fft_size;
|
||||
|
||||
int N_id_1_table[30][30];
|
||||
float corr_peak_threshold;
|
||||
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;
|
||||
|
||||
|
|
|
@ -30,11 +30,15 @@
|
|||
#define SYNC_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <math.h>
|
||||
|
||||
#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_
|
||||
|
||||
|
|
|
@ -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 <stdbool.h>
|
||||
|
||||
#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_
|
||||
|
|
@ -30,19 +30,28 @@
|
|||
#define CEXPTAB_
|
||||
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
#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_
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -30,51 +30,74 @@
|
|||
#define VECTOR_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#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_
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -32,13 +32,14 @@
|
|||
#include <math.h>
|
||||
|
||||
#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;i<r->nsymbols;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;i<q->nof_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;j<r->nsymbols;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;j<MAX_NSYMB;j++) {
|
||||
y[j] = ce[r->symbols_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 &&
|
||||
|
@ -237,11 +249,6 @@ int chest_init(chest_t *q, chest_interp_t interp, uint32_t nof_re, uint32_t nof_
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -65,6 +65,23 @@ bool lte_cell_isvalid(lte_cell_t *cell) {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -205,12 +204,7 @@ 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));
|
||||
/* 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 {
|
||||
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));
|
||||
cb_len = harq_process->cb_segm.K2;
|
||||
}
|
||||
if (harq_process->cb_segm.C > 1) {
|
||||
/* Attach Codeblock CRC */
|
||||
crc_attach(&q->crc_cb, q->cb_in, rlen);
|
||||
rlen = cb_len - 24;
|
||||
} else {
|
||||
rlen = cb_len;
|
||||
}
|
||||
if (VERBOSE_ISDEBUG()) {
|
||||
DEBUG("CB#%d Len=%d: ", i, cb_len);
|
||||
vec_fprint_b(stdout, q->cb_in, cb_len);
|
||||
if (i == 0) {
|
||||
F = harq_process->cb_segm.F;
|
||||
} else {
|
||||
F = 0;
|
||||
}
|
||||
/* Turbo Encoding */
|
||||
tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
|
||||
|
||||
/* Set read/write pointers */
|
||||
rp += (rlen - F);
|
||||
wp += n_e;
|
||||
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,6 +772,7 @@ 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 &&
|
||||
|
@ -768,67 +780,69 @@ int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS], uint32_t s
|
|||
harq_process != NULL)
|
||||
{
|
||||
|
||||
for (i=0;i<q->cell.nof_ports;i++) {
|
||||
if (sf_symbols[i] == NULL) {
|
||||
if (q->rnti_is_set) {
|
||||
for (i=0;i<q->cell.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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (nof_bits > nof_bits_e) {
|
||||
fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
if (harq_process->mcs.tbs == 0) {
|
||||
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_bits > nof_bits_e) {
|
||||
fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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));
|
||||
|
||||
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);
|
||||
if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) {
|
||||
fprintf(stderr, "Error encoding TB\n");
|
||||
return LIBLTE_ERROR;
|
||||
}
|
||||
|
||||
/* 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));
|
||||
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);
|
||||
|
||||
/* 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));
|
||||
}
|
||||
|
||||
scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#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;i<SYNC_PBCH_NOF_PORTS;i++) {
|
||||
q->ce[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;i<SYNC_PBCH_NOF_PORTS;i++) {
|
||||
if (q->ce[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
|
||||
}
|
||||
|
|
@ -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
|
||||
########################################################################
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -27,12 +27,173 @@
|
|||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;i<TABLE_SIZE;i++) {
|
||||
q->cexptable[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;j<off_st;j++) {
|
||||
q->out_mag[j] = mag0 - (j+1)*dmag;
|
||||
q->out_arg[j] = arg0 - (j+1)*darg;
|
||||
}
|
||||
|
||||
for (i=0;i<len1;i++) {
|
||||
mag0 = q->in_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;j<M;j++) {
|
||||
q->out_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;j<off_end;j++) {
|
||||
q->out_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;n<len;n++) {
|
||||
q->out_cexp[n] = q->cexptable[q->table_idx[n]+TABLE_SIZE/2];
|
||||
}
|
||||
#else
|
||||
for (n=0;n<len;n++) {
|
||||
q->out_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;i<len-1;i++) {
|
||||
|
@ -63,14 +224,14 @@ void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st,
|
|||
}
|
||||
|
||||
/* Performs 1st order linear interpolation */
|
||||
void interp_linear_c(cf_t *input, cf_t *output, int M, int len) {
|
||||
interp_linear_offset(input, output, M, len, 0, 0);
|
||||
void interp_linear_c(cf_t *input, cf_t *output, uint32_t M, uint32_t len) {
|
||||
interp_linear_offset(input, output, M, len, 0, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Performs 1st order integer linear interpolation */
|
||||
void interp_linear_f(float *input, float *output, int M, int len) {
|
||||
int i, j;
|
||||
/* Performs 1st order uint32_teger linear interpolation */
|
||||
void interp_linear_f(float *input, float *output, uint32_t M, uint32_t len) {
|
||||
uint32_t i, j;
|
||||
for (i=0;i<len-1;i++) {
|
||||
for (j=0;j<M;j++) {
|
||||
output[i*M+j] = input[i] + j * (input[i+1]-input[i]) / M;
|
||||
|
|
|
@ -31,5 +31,7 @@ TARGET_LINK_LIBRARIES(resample_arb_bench lte_phy)
|
|||
|
||||
ADD_TEST(resample resample_arb_test)
|
||||
|
||||
ADD_EXECUTABLE(interp_test_volk interp_test_volk.c)
|
||||
TARGET_LINK_LIBRARIES(interp_test_volk lte_phy)
|
||||
|
||||
|
||||
|
|
|
@ -34,14 +34,14 @@
|
|||
#include "liblte/phy/utils/vector.h"
|
||||
#include "liblte/phy/utils/debug.h"
|
||||
|
||||
int cfo_init(cfo_t *h, int nsamples) {
|
||||
int ret = -1;
|
||||
int cfo_init(cfo_t *h, uint32_t nsamples) {
|
||||
int ret = LIBLTE_ERROR;
|
||||
bzero(h, sizeof(cfo_t));
|
||||
|
||||
if (cexptab_init(&h->tab, 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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
dft_run_c(&q->dftp_input, input, input_fft);
|
||||
/* 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;
|
||||
|
||||
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];
|
||||
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);
|
||||
|
||||
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];
|
||||
}
|
||||
ret = LIBLTE_SUCCESS;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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];
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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 (N_id_2 < 0 || N_id_2 > 2) {
|
||||
fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2);
|
||||
return -1;
|
||||
if (lte_N_id_2_isvalid(N_id_2) &&
|
||||
fft_size < 2048)
|
||||
{
|
||||
|
||||
pss_generate(pss_signal_time, N_id_2);
|
||||
|
||||
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));
|
||||
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;
|
||||
|
||||
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]) {
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 CONVOLUTION_FFT
|
||||
conv_fft_cc_free(&q->conv_fft);
|
||||
|
||||
#ifdef ENABLE_SF
|
||||
if (q->frame_buffer) {
|
||||
free(q->frame_buffer);
|
||||
#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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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));
|
||||
if (q != NULL &&
|
||||
input != NULL)
|
||||
{
|
||||
|
||||
#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
|
||||
uint32_t corr_peak_pos;
|
||||
uint32_t 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 (!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, 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;
|
||||
}
|
||||
|
||||
ret = (int) 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;
|
||||
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_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);
|
||||
|
||||
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);
|
||||
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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
bzero(q, sizeof(sss_synch_t));
|
||||
if (q != NULL &&
|
||||
fft_size < 2048)
|
||||
{
|
||||
uint32_t N_id_2;
|
||||
struct sss_tables sss_tables;
|
||||
|
||||
if (dft_plan(&q->dftp_input, SSS_DFT_LEN, FORWARD, COMPLEX)) {
|
||||
return -1;
|
||||
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;
|
||||
}
|
||||
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);
|
||||
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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,9 +137,9 @@ 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];
|
||||
|
@ -163,12 +152,12 @@ int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1) {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,43 +25,105 @@
|
|||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#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;
|
||||
|
||||
if (pss_synch_init(&q->pss, frame_size)) {
|
||||
fprintf(stderr, "Error initializing PSS object\n");
|
||||
return -1;
|
||||
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_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);
|
||||
}
|
||||
|
||||
return 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;
|
||||
|
||||
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->sss_en) {
|
||||
if (sync_sss(q, input, q->N_id_2, peak_pos, false)) {
|
||||
return -1;
|
||||
}
|
||||
if (q->pss_mode == ABSOLUTE) {
|
||||
mean_ptr = NULL;
|
||||
} else {
|
||||
mean_ptr = &mean_value;
|
||||
}
|
||||
|
||||
return peak_pos;
|
||||
} else {
|
||||
return -1;
|
||||
peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &peak_value, mean_ptr);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return peak_pos[N_id_2];
|
||||
if (peak_position) {
|
||||
*peak_position = peak_pos[N_id_2];
|
||||
}
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
return LIBLTE_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
# and at http://www.gnu.org/licenses/.
|
||||
#
|
||||
|
||||
|
||||
########################################################################
|
||||
# SYNC TEST
|
||||
########################################################################
|
||||
|
|
|
@ -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;i<num_samples;i++) {
|
||||
|
|
|
@ -78,7 +78,8 @@ int main(int argc, char **argv) {
|
|||
cf_t pss_signal[PSS_LEN];
|
||||
float sss_signal0[SSS_LEN]; // for subframe 0
|
||||
float sss_signal5[SSS_LEN]; // for subframe 5
|
||||
int cid, max_cid, find_idx;
|
||||
int cid, max_cid;
|
||||
uint32_t find_idx;
|
||||
sync_t sync;
|
||||
lte_fft_t ifft;
|
||||
|
||||
|
@ -101,12 +102,12 @@ int main(int argc, char **argv) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (sync_init(&sync, FLEN)) {
|
||||
if (sync_init(&sync, FLEN, 128, 128)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sync_set_threshold(&sync, 20);
|
||||
sync_set_threshold(&sync, 20, 10);
|
||||
|
||||
if (cell_id == -1) {
|
||||
cid = 0;
|
||||
|
@ -131,7 +132,7 @@ int main(int argc, char **argv) {
|
|||
memset(fft_buffer, 0, sizeof(cf_t) * 2 * FLEN);
|
||||
lte_ifft_run_slot(&ifft, buffer, &fft_buffer[offset]);
|
||||
|
||||
find_idx = sync_find(&sync, fft_buffer);
|
||||
sync_find(&sync, fft_buffer, &find_idx);
|
||||
find_ns = sync_get_slot_id(&sync);
|
||||
printf("cell_id: %d find: %d, offset: %d, ns=%d find_ns=%d\n", cid, find_idx, offset,
|
||||
ns, find_ns);
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
|
||||
#include "liblte/phy/utils/cexptab.h"
|
||||
|
||||
int cexptab_init(cexptab_t *h, int size) {
|
||||
int i;
|
||||
int cexptab_init(cexptab_t *h, uint32_t size) {
|
||||
uint32_t i;
|
||||
|
||||
h->size = 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);
|
||||
}
|
||||
|
|
|
@ -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<input_len;i++) {
|
||||
for (j=0;j<filter_len;j++) {
|
||||
output[i+j]+=input[i]*filter[j];
|
||||
|
|
|
@ -26,16 +26,19 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "liblte/phy/utils/vector.h"
|
||||
#include <float.h>
|
||||
#include <complex.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;i<len;i++) {
|
||||
|
@ -44,10 +47,10 @@ int vec_acc_ii(int *x, int len) {
|
|||
return z;
|
||||
}
|
||||
|
||||
float vec_acc_ff(float *x, int len) {
|
||||
float vec_acc_ff(float *x, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_ACC_FUNCTION
|
||||
float result;
|
||||
volk_32f_accumulator_s32f_u(&result,x,(unsigned int) len);
|
||||
volk_32f_accumulator_s32f(&result,x,len);
|
||||
return result;
|
||||
#else
|
||||
int i;
|
||||
|
@ -59,7 +62,7 @@ float vec_acc_ff(float *x, int len) {
|
|||
#endif
|
||||
}
|
||||
|
||||
cf_t vec_acc_cc(cf_t *x, int len) {
|
||||
cf_t vec_acc_cc(cf_t *x, uint32_t len) {
|
||||
int i;
|
||||
cf_t z=0;
|
||||
for (i=0;i<len;i++) {
|
||||
|
@ -68,21 +71,43 @@ cf_t vec_acc_cc(cf_t *x, int len) {
|
|||
return z;
|
||||
}
|
||||
|
||||
void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len) {
|
||||
void vec_sub_fff(float *x, float *y, float *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_SUB_FLOAT_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]-y[i];
|
||||
}
|
||||
#else
|
||||
volk_32f_x2_subtract_32f(z,x,y,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]+y[i];
|
||||
}
|
||||
}
|
||||
|
||||
void vec_sum_bbb(char *z, char *x, char *y, int len) {
|
||||
void vec_sum_bbb(char *x, char *y, char *z, uint32_t len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]+y[i];
|
||||
}
|
||||
}
|
||||
|
||||
void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len) {
|
||||
void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT_FLOAT_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]*h;
|
||||
}
|
||||
#else
|
||||
volk_32f_s32f_multiply_32f(z,x,h,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
|
@ -92,29 +117,50 @@ void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len) {
|
|||
cf_t hh;
|
||||
__real__ hh = h;
|
||||
__imag__ hh = 0;
|
||||
volk_32fc_s32fc_multiply_32fc_u(z,x,hh,(unsigned int) len);
|
||||
volk_32fc_s32fc_multiply_32fc(z,x,hh,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len) {
|
||||
void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]*h;
|
||||
}
|
||||
#else
|
||||
volk_32fc_s32fc_multiply_32fc_u(z,x,h,(unsigned int) len);
|
||||
volk_32fc_s32fc_multiply_32fc(z,x,h,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_CONVERT_FI_FUNCTION
|
||||
volk_32f_s32f_convert_16i(z, x, scale, len);
|
||||
#else
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = (int16_t) (x[i]*scale);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_DEINTERLEAVE_FUNCTION
|
||||
volk_32fc_deinterleave_32f_x2(real, imag, x, len);
|
||||
#else
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
real[i] = __real__ x[i];
|
||||
imag[i] = __imag__ x[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void *vec_malloc(int size) {
|
||||
void *vec_malloc(uint32_t size) {
|
||||
#ifndef HAVE_VOLK
|
||||
return malloc(size);
|
||||
#else
|
||||
void *ptr;
|
||||
if (posix_memalign(&ptr,64,size)) {
|
||||
if (posix_memalign(&ptr,volk_get_alignment(),size)) {
|
||||
return NULL;
|
||||
} else {
|
||||
return ptr;
|
||||
|
@ -122,18 +168,32 @@ void *vec_malloc(int size) {
|
|||
#endif
|
||||
}
|
||||
|
||||
void vec_fprint_c(FILE *stream, cf_t *x, int len) {
|
||||
void *vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size) {
|
||||
#ifndef HAVE_VOLK
|
||||
return realloc(ptr, new_size);
|
||||
#else
|
||||
void *new_ptr;
|
||||
if (posix_memalign(&new_ptr,volk_get_alignment(),new_size)) {
|
||||
return NULL;
|
||||
} else {
|
||||
memcpy(new_ptr, ptr, old_size);
|
||||
free(ptr);
|
||||
return new_ptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void vec_fprint_c(FILE *stream, cf_t *x, uint32_t len) {
|
||||
int i;
|
||||
fprintf(stream, "[");
|
||||
for (i=0;i<len;i++) {
|
||||
fprintf(stream, "%+2.2f%+2.2fi, ", __real__ x[i], __imag__ x[i]);
|
||||
//if (!((i+1)%10))
|
||||
// fprintf(stream, "\n");
|
||||
}
|
||||
fprintf(stream, "];\n");
|
||||
}
|
||||
|
||||
void vec_fprint_f(FILE *stream, float *x, int len) {
|
||||
void vec_fprint_f(FILE *stream, float *x, uint32_t len) {
|
||||
int i;
|
||||
fprintf(stream, "[");
|
||||
for (i=0;i<len;i++) {
|
||||
|
@ -143,7 +203,7 @@ void vec_fprint_f(FILE *stream, float *x, int len) {
|
|||
}
|
||||
|
||||
|
||||
void vec_fprint_b(FILE *stream, char *x, int len) {
|
||||
void vec_fprint_b(FILE *stream, char *x, uint32_t len) {
|
||||
int i;
|
||||
fprintf(stream, "[");
|
||||
for (i=0;i<len;i++) {
|
||||
|
@ -152,7 +212,7 @@ void vec_fprint_b(FILE *stream, char *x, int len) {
|
|||
fprintf(stream, "];\n");
|
||||
}
|
||||
|
||||
void vec_fprint_i(FILE *stream, int *x, int len) {
|
||||
void vec_fprint_i(FILE *stream, int *x, uint32_t len) {
|
||||
int i;
|
||||
fprintf(stream, "[");
|
||||
for (i=0;i<len;i++) {
|
||||
|
@ -161,36 +221,116 @@ void vec_fprint_i(FILE *stream, int *x, int len) {
|
|||
fprintf(stream, "];\n");
|
||||
}
|
||||
|
||||
void vec_conj_cc(cf_t *x, cf_t *y, int len) {
|
||||
void vec_fprint_hex(FILE *stream, char *x, uint32_t len) {
|
||||
uint32_t i, nbytes, byte;
|
||||
nbytes = len/8;
|
||||
fprintf(stream, "[", len);
|
||||
for (i=0;i<nbytes;i++) {
|
||||
byte = bit_unpack(&x, 8);
|
||||
fprintf(stream, "%02x ", byte);
|
||||
}
|
||||
if (len%8) {
|
||||
byte = bit_unpack(&x, len%8);
|
||||
fprintf(stream, "%02x ", byte);
|
||||
}
|
||||
fprintf(stream, "];\n");
|
||||
}
|
||||
|
||||
void vec_save_file(char *filename, void *buffer, uint32_t len) {
|
||||
FILE *f;
|
||||
f = fopen(filename, "w");
|
||||
if (f) {
|
||||
fwrite(buffer, len, 1, f);
|
||||
fclose(f);
|
||||
} else {
|
||||
perror("fopen");
|
||||
}
|
||||
}
|
||||
|
||||
void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_CONJ_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
y[i] = conjf(x[i]);
|
||||
}
|
||||
#else
|
||||
volk_32fc_conjugate_32fc_u(y,x,(unsigned int) len);
|
||||
volk_32fc_conjugate_32fc(y,x,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, int len) {
|
||||
void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT_REAL_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]*y[i];
|
||||
}
|
||||
#else
|
||||
volk_32fc_32f_multiply_32fc(z,x,y,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void vec_prod_ccc(cf_t *x,cf_t *y, cf_t *z, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MULT2_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]*y[i];
|
||||
}
|
||||
#else
|
||||
volk_32fc_x2_multiply_32fc_u(z,x,y,(unsigned int) len);
|
||||
volk_32fc_x2_multiply_32fc(z,x,y,len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len) {
|
||||
void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i] / y[i];
|
||||
}
|
||||
}
|
||||
|
||||
float vec_avg_power_cf(cf_t *x, int len) {
|
||||
void vec_div_fff(float *x, float *y, float *z, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_DIVIDE_FUNCTION
|
||||
volk_32f_x2_divide_32f(z, x, y, len);
|
||||
#else
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i] / y[i];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_DOTPROD_FC_FUNCTION
|
||||
cf_t res;
|
||||
volk_32fc_x2_dot_prod_32fc(&res, x, y, len);
|
||||
return res;
|
||||
#else
|
||||
uint32_t i;
|
||||
cf_t res = 0;
|
||||
for (i=0;i<len;i++) {
|
||||
res += x[i]*y[i];
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
float vec_dot_prod_fff(float *x, float *y, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_DOTPROD_F_FUNCTION
|
||||
float res;
|
||||
volk_32f_x2_dot_prod_32f(&res, x, y, len);
|
||||
return res;
|
||||
#else
|
||||
uint32_t i;
|
||||
float res = 0;
|
||||
for (i=0;i<len;i++) {
|
||||
res += x[i]*y[i];
|
||||
}
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
float vec_avg_power_cf(cf_t *x, uint32_t len) {
|
||||
int j;
|
||||
float power = 0;
|
||||
for (j=0;j<len;j++) {
|
||||
|
@ -200,40 +340,42 @@ float vec_avg_power_cf(cf_t *x, int len) {
|
|||
return power / len;
|
||||
}
|
||||
|
||||
void vec_prod_ccc_unalign(cf_t *x,cf_t *y, cf_t *z, int len) {
|
||||
#ifndef HAVE_VOLK_MULT_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
z[i] = x[i]*y[i];
|
||||
}
|
||||
#else
|
||||
volk_32fc_x2_multiply_32fc_u(z,x,y,(unsigned int) len);
|
||||
#endif
|
||||
}
|
||||
|
||||
void vec_abs_cf(cf_t *x, float *abs, int len) {
|
||||
void vec_abs_cf(cf_t *x, float *abs, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_MAG_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
abs[i] = cabsf(x[i]);
|
||||
}
|
||||
#else
|
||||
volk_32fc_magnitude_32f_u(abs,x,(unsigned int) len);
|
||||
volk_32fc_magnitude_32f(abs,x,len);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
int vec_max_fi(float *x, int len) {
|
||||
void vec_arg_cf(cf_t *x, float *arg, uint32_t len) {
|
||||
#ifndef HAVE_VOLK_ATAN_FUNCTION
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
arg[i] = cargf(x[i]);
|
||||
}
|
||||
#else
|
||||
volk_32fc_s32f_atan2_32f(arg,x,1,len);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
uint32_t vec_max_fi(float *x, uint32_t len) {
|
||||
#ifdef HAVE_VOLK_MAX_FUNCTION
|
||||
unsigned int target=0;
|
||||
volk_32f_index_max_16u_u(&target,x,(unsigned int) len);
|
||||
return (int) target;
|
||||
uint32_t target=0;
|
||||
volk_32f_index_max_16u(&target,x,len);
|
||||
return target;
|
||||
|
||||
#else
|
||||
int i;
|
||||
uint32_t i;
|
||||
float m=-FLT_MAX;
|
||||
int p=0;
|
||||
uint32_t p=0;
|
||||
for (i=0;i<len;i++) {
|
||||
if (x[i]>m) {
|
||||
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<len;i++) {
|
||||
|
|
|
@ -27,17 +27,5 @@ function [ fs eps p_m w2] = find_pss( x, N_id_2, doplot, threshold)
|
|||
mean(abs(w2)), m, 10*log10(m/mean(abs(w2))));
|
||||
end
|
||||
|
||||
% Estimate PSS-aided CFO
|
||||
if (i > 128 && i<length(x)&& p_m > 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
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
%
|
||||
% 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
|
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue