Fixed PDSCH UE example. Added ue_dl and ue_sync modules. Fixed other minor bugs

master
ismagom 11 years ago
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_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 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 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_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, 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 + ", master_clock_rate=30720000");
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);
*h = handler;
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;
}
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;
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();
}
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;
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_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;
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();
}
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);
// Try to set LTE clock
handler->usrp->set_master_clock_rate(30720000);
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);
*h = handler;
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_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();
}
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_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();
}
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, 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);
}
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);
}
}
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_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();
}
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 = "";
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;
#define CLRSTDOUT printf("\r\n"); fflush(stdout); printf("\r\n")
#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);
/* Local function definitions */
void init_plots();
/**********************************************************************
* 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;
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;
}
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,585 +98,219 @@ 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]);
args->cell_id_file = atoi(argv[optind]);
break;
case 'p':
args->nof_prb_file = atoi(argv[optind]);
break;
case 'a':
uhd_args = argv[optind];
args->io_config.uhd_args = argv[optind];
break;
case 'g':
uhd_gain = atof(argv[optind]);
args->io_config.uhd_gain = atof(argv[optind]);
break;
case 'f':
uhd_freq = atof(argv[optind]);
args->io_config.uhd_freq = atof(argv[optind]);
break;
case 'b':
pbch_only = true;
args->pbch_only = true;
break;
case 't':
find_threshold = atof(argv[optind]);
break;
case 'p':
sampling_nof_prb = atof(argv[optind]);
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);
}
}
}
#ifndef DISABLE_GRAPHICS
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");
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -1, 1);
plot_scatter_setYAxisScale(&pscatequal, -1, 1);
}
#endif
/* This function initializes the objects defined as global variables */
int base_init(int nof_prb) {
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;
}
init_plots();
if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) {
usage(args, argv[0]);
}
#else
printf("-- PLOTS are disabled. Graphics library not available --\n\n");
#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(&regs);
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(&regs, phich_resources, phich_length, cell)) {
fprintf(stderr, "Error initiating REGs\n");
return -1;
}
if (pcfich_init(&pcfich, &regs, cell)) {
fprintf(stderr, "Error creating PCFICH object\n");
return -1;
}
if (pdcch_init(&pdcch, &regs, 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;
void sigintHandler(int x) {
go_exit = 1;
}
int cell_id_init(int nof_prb, int cell_id) {
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;
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);
parse_args(&prog_args, argc, argv);
if (regs_set_cfi(&regs, cfi)) {
fprintf(stderr, "Error setting CFI\n");
return -1;
if (iodev_init(&iodev, &prog_args.io_config)) {
fprintf(stderr, "Error initiating input device\n");
exit(-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 (!prog_args.disable_plots) {
init_plots();
}
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;
}
/* Setup SIGINT handler */
printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler);
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &ra_dl.prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n");
return -1;
}
/* Initialize frame and subframe counters */
sf_cnt = 0;
sf_idx = 0;
if (pdsch_decode(&pdsch, fft_buffer, ce, data, sf_idx, &harq_process, ra_dl.rv_idx)) {
pkt_errors++;
}
pkts_total++;
}
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
#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;
}
ret = iodev_receive(&iodev, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error reading from input device (%d)\n", ret);
break;
}
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;
/* 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 (VERBOSE_ISINFO() || !frame_cnt) {
CLRSTDOUT;
printf(" - Phy. CellId:\t %d\n", cell_id);
pbch_mib_fprint(stdout, &mib);
if (!prog_args.disable_plots && sf_idx == 5) {
do_plots(&ue_dl, sf_idx);
}
} 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);
if (iodev_isfile(&iodev)) {
sf_idx++;
if (sf_idx == NSUBFRAMES_X_FRAME) {
sf_idx = 0;
}
#endif
pkts_total++;
}
}
}
if (cell.nof_prb && !pbch_only) {
if (pdsch_run(input, sf_idx)) {
fprintf(stderr, "\nError running PDSCH decoder\n");
return -1;
if (prog_args.nof_subframes > 0) {
sf_cnt++;
}
}
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);
if (iodev_isfile(&iodev)) {
usleep(5000);
}
} 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();
if (ue_dl_initiated) {
ue_dl_free(&ue_dl);
}
iodev_free(&iodev);
printf("\n --- Press Ctrl+C to exit --- \n");
printf("\nBye\n");
exit(0);
}
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);
/**********************************************************************
* Plotting Functions
***********************************************************************/
#ifndef DISABLE_GRAPHICS
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)) {
#include "liblte/graphics/plot.h"
plot_real_t poutfft;
plot_complex_t pce;
plot_scatter_t pscatrecv, pscatequal;
read_io(input_buffer, sf_n_samples);
float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)];
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++;
}
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);
if (!input_file_name) {
sf_idx = sync_frame_sfidx(&sframe);
cell_id = sync_frame_cell_id(&sframe);
}
plot_complex_init(&pce);
plot_complex_setTitle(&pce, "Channel Estimates");
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
/* synch'd and tracking */
if (run_receiver(in_ptr, cell_id, sf_idx)) {
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
exit(-1);
}
plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
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);
}
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -1, 1);
plot_scatter_setYAxisScale(&pscatequal, -1, 1);
}
frame_cnt++;
if (input_file_name) {
usleep(5000);
void do_plots(ue_dl_t *q, uint32_t sf_idx) {
int i;
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;
}
}
base_free();
printf("\nBye\n");
exit(0);
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

@ -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;
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_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);
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);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q,
uint32_t N_id_2);
/* 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_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;
uint32_t fft_size;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
int N_id_2;
uint32_t symbol_sz;
uint32_t subframe_sz;
uint32_t N_id_2;
int N_id_1_table[30][30];
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_put_slot(float *sss,
cf_t *symbol,
uint32_t nof_prb,
lte_cp_t cp);
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_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_synch_set_symbol_sz(sss_synch_t *q,
uint32_t symbol_sz);
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 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 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 int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len);
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 (q->rnti_is_set) {
if (rv_idx == 0) {
/* Compute transport block CRC */
par = crc_checksum(&q->crc_tb, data, tbs);
if (VERBOSE_ISDEBUG()) {
DEBUG("DATA: ", 0);
vec_fprint_b(stdout, data, tbs);
DEBUG("PARITY: ", 0);
vec_fprint_b(stdout, parity, 24);
}
/* parity bits will be appended later */
bit_pack(par, &p_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++) {
if (VERBOSE_ISDEBUG()) {
DEBUG("DATA: ", 0);
vec_fprint_b(stdout, data, tbs);
DEBUG("PARITY: ", 0);
vec_fprint_b(stdout, parity, 24);
}
/* 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;
/* 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;
}
}
if (i < harq_process->cb_segm.C - 1) {
n_e = nb_e / harq_process->cb_segm.C;
} else {
n_e = nb_e - wp;
}
wp = 0;
rp = 0;
for (i = 0; i < harq_process->cb_segm.C; i++) {
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);
/* 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 (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));
n_e = nb_e / harq_process->cb_segm.C;
} 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));
n_e = nb_e - wp;
}
if (harq_process->cb_segm.C > 1) {
/* Attach Codeblock CRC */
crc_attach(&q->crc_cb, q->cb_in, rlen);
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);
}
if (VERBOSE_ISDEBUG()) {
DEBUG("CB#%d Len=%d: ", i, cb_len);
vec_fprint_b(stdout, q->cb_in, 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;
}
/* Turbo Encoding */
tcod_encode(&q->encoder, q->cb_in, (char*) q->cb_out, cb_len);
}
/* Rate matching */
if (rm_turbo_tx(harq_process->pdsch_w_buff_c[i], harq_process->w_buff_size,
(char*) q->cb_out, 3 * cb_len + 12,
&e_bits[wp], n_e, rv_idx))
{
fprintf(stderr, "Error in rate matching\n");
return LIBLTE_ERROR;
/* Set read/write pointers */
rp += (rlen - F);
wp += n_e;
}
/* Set read/write pointers */
rp += (rlen - F);
wp += n_e;
}
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
INFO("END CB#%d: wp: %d, rp: %d\n", i, wp, rp);
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
ret = LIBLTE_SUCCESS;
} else {
fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n");
}
}
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) {
return LIBLTE_ERROR_INVALID_INPUTS;
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;
nof_bits = harq_process->mcs.tbs;
nof_symbols = harq_process->prb_alloc.re_sf[subframe];
nof_bits_e = nof_symbols * q->mod[harq_process->mcs.mod - 1].nbits_x_symbol;
if (harq_process->mcs.tbs == 0) {
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (harq_process->mcs.tbs == 0) {
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (nof_bits > nof_bits_e) {
fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e);
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (nof_bits > nof_bits_e) {
fprintf(stderr, "Invalid code rate %.2f\n", (float) nof_bits / nof_bits_e);
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (nof_symbols > q->max_symbols) {
fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
nof_symbols, q->max_symbols, q->cell.nof_prb);
return LIBLTE_ERROR_INVALID_INPUTS;
}
if (nof_symbols > q->max_symbols) {
fprintf(stderr,
"Error too many RE per subframe (%d). PDSCH configured for %d RE (%d PRB)\n",
nof_symbols, q->max_symbols, q->cell.nof_prb);
return LIBLTE_ERROR_INVALID_INPUTS;
}
INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx);
INFO("Encoding PDSCH SF: %d, Mod %d, NofBits: %d, NofSymbols: %d, NofBitsE: %d, rv_idx: %d\n",
subframe, harq_process->mcs.mod, nof_bits, nof_symbols, nof_bits_e, rv_idx);
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pdsch_x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
/* number of layers equals number of ports */
for (i = 0; i < q->cell.nof_ports; i++) {
x[i] = q->pdsch_x[i];
}
memset(&x[q->cell.nof_ports], 0, sizeof(cf_t*) * (MAX_LAYERS - q->cell.nof_ports));
if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) {
fprintf(stderr, "Error encoding TB\n");
return LIBLTE_ERROR;
}
if (pdsch_encode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx)) {
fprintf(stderr, "Error encoding TB\n");
return LIBLTE_ERROR;
}
scrambling_b_offset(&q->seq_pdsch[subframe], (char*) q->pdsch_e, 0, nof_bits_e);
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);
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));
}
/* 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));
}
/* 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);
fprintf(stderr, "Must call pdsch_set_rnti() to set the encoder/decoder RNTI\n");
}
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) {
/* 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 i;
dft_run_c(&q->dftp_input, input, input_fft);
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];
}
int sss_synch_m0m1(sss_synch_t *q, cf_t *input, uint32_t *m0, float *m0_value,
uint32_t *m1, float *m1_value)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
m0 != NULL &&
m1 != NULL)
{
/* Consider moving to sss_synch_t?? */
cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1];
cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1];
float tmp_real[N_SSS+1];
cf_t input_fft[SSS_MAX_FFT_LEN];
uint32_t i;
dft_run_c(&q->dftp_input, input, input_fft);
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);
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];
}
corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp);
vec_abs_cf(tmp, tmp_real, N_SSS);
*m0 = vec_max_fi(tmp_real, N_SSS);
if (m0_value) {
*m0_value = tmp_real[*m0];
}
vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS);
vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS);
memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t));
vec_conj_cc(z, zconj, N_SSS - 1);
vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1);
corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp);
vec_abs_cf(tmp, tmp_real, N_SSS);
*m1 = vec_max_fi(tmp_real, N_SSS);
if (m1_value) {
*m1_value = tmp_real[*m1];
vec_prod_ccc(y[1], q->fc_tables[q->N_id_2].c[1], tmp, N_SSS);
vec_prod_ccc(tmp, q->fc_tables[q->N_id_2].z1[*m0], z, N_SSS);
memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t));
vec_conj_cc(z, zconj, N_SSS - 1);
vec_prod_ccc(zdelay, zconj, zprod, N_SSS - 1);
corr_all_zs(zprod, q->fc_tables[q->N_id_2].s, tmp);
vec_abs_cf(tmp, tmp_real, N_SSS);
*m1 = vec_max_fi(tmp_real, N_SSS);
if (m1_value) {
*m1_value = tmp_real[*m1];
}
ret = LIBLTE_SUCCESS;
}
return ret;
}
void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in) {
int i, j;
bzero(fc_tables, sizeof(struct fc_tables));
uint32_t i, j;
for (i = 0; i < N_SSS; i++) {
for (j = 0; j < N_SSS; j++) {
__real__ fc_tables->z1[i][j] = (float) in->z1[i][j];

@ -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);
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));
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, 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]);
if (dft_plan(&plan, fft_size, BACKWARD, COMPLEX)) {
return LIBLTE_ERROR;
}
vec_sc_prod_cfc(q->pss_signal_freq[q->N_id_2], (float) 1 / (PSS_LEN_FREQ - 1),
pss_signal_pad, PSS_LEN_FREQ);
dft_plan_set_mirror(&plan, true);
dft_plan_set_dc(&plan, true);
dft_run_c(&plan, pss_signal_pad, pss_signal_freq);
vec_conj_cc(pss_signal_pad, q->pss_signal_freq[q->N_id_2], PSS_LEN_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);
dft_plan_free(&plan);
return 0;
ret = LIBLTE_SUCCESS;
}
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, 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(pss_synch_t *q, int frame_size) {
int ret = -1;
int N_id_2;
bzero(q, sizeof(pss_synch_t));
q->conv_abs = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(float));
if (!q->conv_abs) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
q->tmp_input = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t));
if (!q->tmp_input) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
q->conv_output = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t));
if (!q->conv_output) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
for (N_id_2=0;N_id_2<3;N_id_2++) {
q->pss_signal_freq[N_id_2] = vec_malloc((PSS_LEN_FREQ + frame_size) * sizeof(cf_t));
if (!q->pss_signal_freq[N_id_2]) {
int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL) {
uint32_t N_id_2;
uint32_t buffer_size;
bzero(q, sizeof(pss_synch_t));
q->N_id_2 = 10;
q->fft_size = fft_size;
q->frame_size = frame_size;
buffer_size = fft_size + frame_size + 1;
q->conv_abs = vec_malloc(buffer_size * sizeof(float));
if (!q->conv_abs) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
if (pss_synch_init_N_id_2(q, N_id_2)) {
fprintf(stderr, "Error initiating PSS detector for N_id_2=%d\n", N_id_2);
q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t));
if (!q->tmp_input) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
}
q->conv_output = vec_malloc(buffer_size * sizeof(cf_t));
if (!q->conv_output) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
for (N_id_2=0;N_id_2<3;N_id_2++) {
q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t));
if (!q->pss_signal_freq[N_id_2]) {
fprintf(stderr, "Error allocating memory\n");
goto clean_and_exit;
}
/* The PSS is translated into the frequency domain for each N_id_2 */
if (pss_synch_init_N_id_2(q->pss_signal_freq[N_id_2], N_id_2, fft_size)) {
fprintf(stderr, "Error initiating PSS detector for N_id_2=%d fft_size=%d\n", N_id_2, fft_size);
goto clean_and_exit;
}
}
#ifdef CONVOLUTION_FFT
if (conv_fft_cc_init(&q->conv_fft, frame_size, fft_size)) {
fprintf(stderr, "Error initiating convolution FFT\n");
goto clean_and_exit;
}
#endif
#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;
ret = LIBLTE_SUCCESS;
}
#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]);
}
}
if (q->conv_abs) {
free(q->conv_abs);
}
if (q->tmp_input) {
free(q->tmp_input);
}
if (q->conv_output) {
free(q->conv_output);
}
uint32_t i;
#ifdef ENABLE_SF
if (q->frame_buffer) {
free(q->frame_buffer);
}
#endif
if (q) {
for (i=0;i<3;i++) {
if (q->pss_signal_freq[i]) {
free(q->pss_signal_freq[i]);
}
}
#ifdef CONVOLUTION_FFT
conv_fft_cc_free(&q->conv_fft);
#ifdef CONVOLUTION_FFT
conv_fft_cc_free(&q->conv_fft);
#endif
#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));
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;
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));
#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
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;
}
int pss_synch_find_pss(pss_synch_t *q, cf_t *input,
float *corr_peak_value, float *corr_mean_value)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL)
{
uint32_t corr_peak_pos;
uint32_t conv_output_len;
if (!lte_N_id_2_isvalid(q->N_id_2)) {
fprintf(stderr, "Error finding PSS peak, N_id_2 not set\n");
return LIBLTE_ERROR;
}
bzero(&q->pss_signal_freq[q->N_id_2][q->fft_size], q->frame_size * sizeof(cf_t));
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t));
#ifdef CONVOLUTION_FFT
conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input,
q->pss_signal_freq[q->N_id_2], q->conv_output);
#else
conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, 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;
}
return (int) corr_peak_pos;
ret = (int) corr_peak_pos;
}
return ret;
}
/* Returns the CFO estimation given a PSS received sequence
@ -270,159 +281,12 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value,
*/
float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) {
cf_t y0, y1, yr;
cf_t y[PSS_LEN_FREQ - 1];
vec_prod_ccc_unalign(q->pss_signal_freq[q->N_id_2], pss_recv, y, PSS_LEN_FREQ - 1);
y0 = vec_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;
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;
if (dft_plan(&q->dftp_input, SSS_DFT_LEN, FORWARD, COMPLEX)) {
return -1;
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;
}
if (pss_synch_init(&q->pss_track, TRACK_LEN)) {
fprintf(stderr, "Error initializing PSS track 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 (sss_synch_init(&q->sss)) {
fprintf(stderr, "Error initializing SSS object\n");
return -1;
}
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;
}
DEBUG("PSS and SSS initiated\n",0);
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;
}
return 0;
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;
}
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;
}
}
return peak_pos;
} else {
return -1;
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_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, int len) {
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
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++) {
z[i] = x[i]*y[i];
abs[i] = cabsf(x[i]);
}
#else
volk_32fc_x2_multiply_32fc_u(z,x,y,(unsigned int) len);
volk_32fc_magnitude_32f(abs,x,len);
#endif
}
void vec_abs_cf(cf_t *x, float *abs, int len) {
#ifndef HAVE_VOLK_MAG_FUNCTION
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++) {
abs[i] = cabsf(x[i]);
arg[i] = cargf(x[i]);
}
#else
volk_32fc_magnitude_32f_u(abs,x,(unsigned int) len);
volk_32fc_s32f_atan2_32f(arg,x,1,len);
#endif
}
int vec_max_fi(float *x, int len) {
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…
Cancel
Save