Merge branch 'scanner_average_pss'

master
ismagom 10 years ago
commit fe948dc9e8

@ -37,6 +37,7 @@ PROJECT (LIBLTE)
LIST(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules")
INCLUDE(libLTEPackage) #setup cpack
INCLUDE(BuildMex)
include(CTest)
set( CTEST_MEMORYCHECK_COMMAND valgrind )
@ -51,6 +52,7 @@ CONFIGURE_FILE(
SET(RUNTIME_DIR bin)
SET(LIBRARY_DIR lib)
SET(INCLUDE_DIR include)
SET(MEX_DIR mex)
SET(DOC_DIR "share/doc/${CPACK_PACKAGE_NAME}")
SET(DATA_DIR share/${CPACK_PACKAGE_NAME})
@ -77,7 +79,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -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 -g")
# 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")
@ -140,7 +142,6 @@ MACRO (APPEND_INTERNAL_LIST LIST_NAME VALUE)
ENDIF (${LIST_NAME})
ENDMACRO (APPEND_INTERNAL_LIST)
########################################################################
# Print summary
########################################################################
@ -152,7 +153,10 @@ MESSAGE(STATUS "Building for version: ${VERSION}")
########################################################################
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/common/include)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/lte/phy/include/)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/lte/rrc/include/)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/lte/rrc/include/liblte/rrc/asn)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cuhd/include)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/mex/include)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/graphics/include)
########################################################################
@ -162,4 +166,4 @@ ADD_SUBDIRECTORY(common)
ADD_SUBDIRECTORY(cuhd)
ADD_SUBDIRECTORY(graphics)
ADD_SUBDIRECTORY(lte)
add_subdirectory(mex)

@ -0,0 +1,60 @@
# BuildMex.cmake
# Author: Kent Williams norman-k-williams at uiowa.edu
# Modified by Ismael Gomez, 2014
include(CMakeParseArguments)
if(NOT MATLAB_FOUND)
find_package(MATLAB)
endif()
if(NOT OCTAVE_FOUND)
find_package(OCTAVE)
endif()
# CMake 2.8.12 & earlier apparently don't define the
# Mex script path, so find it.
if(NOT MATLAB_MEX_PATH)
find_program( MATLAB_MEX_PATH mex
HINTS ${MATLAB_ROOT}/bin
PATHS ${MATLAB_ROOT}/bin
DOC "The mex program path"
)
endif()
#
# BuildMex -- arguments
# MEXNAME = root of mex library name
# SOURCE = list of source files
# LIBRARIES = libraries needed to link mex library
FUNCTION(BuildMex)
set(oneValueArgs MEXNAME)
set(multiValueArgs SOURCES LIBRARIES)
cmake_parse_arguments(BuildMex "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (MATLAB_FOUND)
add_library(${BuildMex_MEXNAME}-mat SHARED ${BuildMex_SOURCES})
target_include_directories(${BuildMex_MEXNAME}-mat PUBLIC ${MATLAB_INCLUDE_DIR})
set_target_properties(${BuildMex_MEXNAME}-mat PROPERTIES
SUFFIX "${MATLAB_MEX_EXTENSION}"
PREFIX "liblte_"
OUTPUT_NAME "${BuildMex_MEXNAME}"
COMPILE_FLAGS "-fvisibility=default ${MATLAB_MEX_CFLAGS}"
)
target_link_libraries(${BuildMex_MEXNAME}-mat ${BuildMex_LIBRARIES} ${MATLAB_MEX_LIBRARY})
install(TARGETS ${BuildMex_MEXNAME}-mat DESTINATION "${MEX_DIR}/liblte/")
endif(MATLAB_FOUND)
if (OCTAVE_FOUND)
add_library(${BuildMex_MEXNAME}-oct SHARED ${BuildMex_SOURCES})
target_include_directories(${BuildMex_MEXNAME}-oct PUBLIC ${OCTAVE_INCLUDE_DIR})
set_target_properties(${BuildMex_MEXNAME}-oct PROPERTIES
SUFFIX ".${OCTAVE_MEXFILE_EXT}"
PREFIX "liblte_"
OUTPUT_NAME "${BuildMex_MEXNAME}"
COMPILE_FLAGS "-fvisibility=default ${OCTAVE_MEX_CFLAGS} -DUNDEF_BOOL"
)
target_link_libraries(${BuildMex_MEXNAME}-oct ${BuildMex_LIBRARIES} ${OCTAVE_LIBRARIES})
install(TARGETS ${BuildMex_MEXNAME}-oct DESTINATION "${MEX_DIR}/liblte/")
endif (OCTAVE_FOUND)
ENDFUNCTION(BuildMex)

@ -0,0 +1,212 @@
# - this module looks for Matlab
# Defines:
# MATLAB_INCLUDE_DIR: include path for mex.h, engine.h
# MATLAB_LIBRARIES: required libraries: libmex, etc
# MATLAB_MEX_LIBRARY: path to libmex.lib
# MATLAB_MX_LIBRARY: path to libmx.lib
# MATLAB_MAT_LIBRARY: path to libmat.lib # added
# MATLAB_ENG_LIBRARY: path to libeng.lib
# MATLAB_ROOT: path to Matlab's root directory
# This file is part of Gerardus
#
# This is a derivative work of file FindMatlab.cmake released with
# CMake v2.8, because the original seems to be a bit outdated and
# doesn't work with my Windows XP and Visual Studio 10 install
#
# (Note that the original file does work for Ubuntu Natty)
#
# Author: Ramon Casero <rcasero at gmail.com>, Tom Doel
# Version: 0.2.3
# $Rev$
# $Date$
#
# The original file was copied from an Ubuntu Linux install
# /usr/share/cmake-2.8/Modules/FindMatlab.cmake
set(MATLAB_FOUND 0)
if(WIN32)
# Search for a version of Matlab available, starting from the most modern one to older versions
foreach(MATVER "7.14" "7.11" "7.10" "7.9" "7.8" "7.7" "7.6" "7.5" "7.4")
if((NOT DEFINED MATLAB_ROOT)
OR ("${MATLAB_ROOT}" STREQUAL "")
OR ("${MATLAB_ROOT}" STREQUAL "/registry"))
get_filename_component(MATLAB_ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${MATVER};MATLABROOT]"
ABSOLUTE)
set(MATLAB_VERSION ${MATVER})
endif()
endforeach()
# Directory name depending on whether the Windows architecture is 32
# bit or 64 bit
set(CMAKE_SIZEOF_VOID_P 8) # Note: For some wierd reason this variable is undefined in my system...
if(CMAKE_SIZEOF_VOID_P MATCHES "4")
set(WINDIR "win32")
elseif(CMAKE_SIZEOF_VOID_P MATCHES "8")
set(WINDIR "win64")
else()
message(FATAL_ERROR "CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) doesn't indicate a valid platform")
endif()
# Folder where the MEX libraries are, depending of the Windows compiler
if(${CMAKE_GENERATOR} MATCHES "Visual Studio 6")
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/msvc60")
elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio 7")
# Assume people are generally using Visual Studio 7.1,
# if using 7.0 need to link to: ../extern/lib/${WINDIR}/microsoft/msvc70
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/msvc71")
# set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/msvc70")
elseif(${CMAKE_GENERATOR} MATCHES "Borland")
# Assume people are generally using Borland 5.4,
# if using 7.0 need to link to ../extern/lib/${WINDIR}/microsoft/msvc70
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/bcc54")
# set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/bcc50")
# set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/bcc51")
elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio*")
# If the compiler is Visual Studio, but not any of the specific
# versions above, we try our luck with the microsoft directory
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/")
else()
message(FATAL_ERROR "Generator not compatible: ${CMAKE_GENERATOR}")
endif()
# Get paths to the Matlab MEX libraries
find_library(MATLAB_MEX_LIBRARY libmex ${MATLAB_LIBRARIES_DIR} )
find_library(MATLAB_MX_LIBRARY libm ${MATLAB_LIBRARIES_DIR} )
find_library(MATLAB_MAT_LIBRARY libmat ${MATLAB_LIBRARIES_DIR} )
find_library(MATLAB_ENG_LIBRARY libeng ${MATLAB_LIBRARIES_DIR} )
# Get path to the include directory
find_path(MATLAB_INCLUDE_DIR "mex.h" "${MATLAB_ROOT}/extern/include" )
else()
if((NOT DEFINED MATLAB_ROOT)
OR ("${MATLAB_ROOT}" STREQUAL ""))
# get path to the Matlab root directory
execute_process(
COMMAND which matlab
COMMAND xargs readlink
COMMAND xargs dirname
COMMAND xargs dirname
COMMAND xargs echo -n
OUTPUT_VARIABLE MATLAB_ROOT
)
endif()
# Check if this is a Mac
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LIBRARY_EXTENSION .dylib)
# If this is a Mac and the attempts to find MATLAB_ROOT have so far failed,
# we look in the applications folder
if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
# Search for a version of Matlab available, starting from the most modern one to older versions
foreach(MATVER "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a" "R2010b" "R2010a" "R2009b" "R2009a" "R2008b")
if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
if(EXISTS /Applications/MATLAB_${MATVER}.app)
set(MATLAB_ROOT /Applications/MATLAB_${MATVER}.app)
endif()
endif()
endforeach()
endif()
else()
set(LIBRARY_EXTENSION .so)
endif()
# Get path to the MEX libraries
execute_process(
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libmex${LIBRARY_EXTENSION} # Peter
COMMAND find "${MATLAB_ROOT}/bin" -name libmex${LIBRARY_EXTENSION} # standard
COMMAND xargs echo -n
OUTPUT_VARIABLE MATLAB_MEX_LIBRARY
)
execute_process(
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libmx${LIBRARY_EXTENSION} # Peter
COMMAND find "${MATLAB_ROOT}/bin" -name libmx${LIBRARY_EXTENSION} # Standard
COMMAND xargs echo -n
OUTPUT_VARIABLE MATLAB_MX_LIBRARY
)
execute_process(
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libmat${LIBRARY_EXTENSION} # Peter
COMMAND find "${MATLAB_ROOT}/bin" -name libmat${LIBRARY_EXTENSION} # Standard
COMMAND xargs echo -n
OUTPUT_VARIABLE MATLAB_MAT_LIBRARY
)
execute_process(
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libeng${LIBRARY_EXTENSION} # Peter
COMMAND find "${MATLAB_ROOT}/bin" -name libeng${LIBRARY_EXTENSION} # Standard
COMMAND xargs echo -n
OUTPUT_VARIABLE MATLAB_ENG_LIBRARY
)
# Get path to the include directory
find_path(MATLAB_INCLUDE_DIR
"mex.h"
PATHS "${MATLAB_ROOT}/extern/include"
)
find_program( MATLAB_MEX_PATH mex
HINTS ${MATLAB_ROOT}/bin
PATHS ${MATLAB_ROOT}/bin
DOC "The mex program path"
)
find_program( MATLAB_MEXEXT_PATH mexext
HINTS ${MATLAB_ROOT}/bin
PATHS ${MATLAB_ROOT}/bin
DOC "The mexext program path"
)
execute_process(
COMMAND ${MATLAB_MEXEXT_PATH}
OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE MATLAB_MEX_EXT
)
endif()
# This is common to UNIX and Win32:
set(MATLAB_LIBRARIES
${MATLAB_MEX_LIBRARY}
${MATLAB_MX_LIBRARY}
${MATLAB_ENG_LIBRARY}
)
if(MATLAB_INCLUDE_DIR AND MATLAB_LIBRARIES)
set(MATLAB_FOUND 1)
endif()
# 32-bit or 64-bit mex
if(WIN32)
if (CMAKE_CL_64)
SET(MATLAB_MEX_EXTENSION .mexw64)
else(CMAKE_CL_64)
SET(MATLAB_MEX_EXTENSION .mexw32)
endif(CMAKE_CL_64)
else(WIN32)
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
SET(MATLAB_MEX_EXTENSION .mexa64)
else(CMAKE_SIZEOF_VOID_P MATCHES "8")
SET(MATLAB_MEX_EXTENSION .mexglx)
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
endif(WIN32)
SET(MATLAB_MEX_CFLAGS "-DMATLAB_MEX_FILE -DMX_COMPAT_32")
mark_as_advanced(
MATLAB_LIBRARIES
MATLAB_MEX_LIBRARY
MATLAB_MX_LIBRARY
MATLAB_ENG_LIBRARY
MATLAB_INCLUDE_DIR
MATLAB_FOUND
MATLAB_ROOT
MATLAB_MEX_PATH
MATLAB_MEXEXT_PATH
MATLAB_MEX_EXT
)

@ -0,0 +1,138 @@
# - Try to find a version of Octave and headers/library required by the
# used compiler. It determines the right MEX-File extension and add
# a macro to help the build of MEX-functions.
#
# This module defines:
# OCTAVE_INCLUDE_DIR: include path for mex.h, mexproto.h
# OCTAVE_OCTINTERP_LIBRARY: path to the library octinterp
# OCTAVE_OCTAVE_LIBRARY: path to the library octave
# OCTAVE_CRUFT_LIBRARY: path to the library cruft
# OCTAVE_LIBRARIES: required libraries: octinterp, octave, cruft
# OCTAVE_CREATE_MEX: macro to build a MEX-file
#
# The macro OCTAVE_CREATE_MEX requires in this order:
# - function's name which will be called in Octave;
# - C/C++ source files;
# - third libraries required.
# Copyright (c) 2009-2013 Arnaud Barré <arnaud.barre@gmail.com>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
IF(OCTAVE_ROOT AND OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES)
STRING(COMPARE NOTEQUAL "${OCTAVE_ROOT}" "${OCTAVE_ROOT_LAST}" OCTAVE_CHANGED)
IF(OCTAVE_CHANGED)
SET(OCTAVE_USE_MINGW32 OCTAVE_USE_MINGW32-NOTFOUND CACHE INTERNAL "")
SET(OCTAVE_OCTAVE_LIBRARY OCTAVE_OCTAVE_LIBRARY-NOTFOUND CACHE INTERNAL "")
SET(OCTAVE_INCLUDE_DIR OCTAVE_INCLUDE_DIR-NOTFOUND CACHE INTERNAL "")
ELSE(OCTAVE_CHANGED)
# in cache already
SET(Octave_FIND_QUIETLY TRUE)
ENDIF(OCTAVE_CHANGED)
ENDIF(OCTAVE_ROOT AND OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES)
SET(OCTAVE_MEXFILE_EXT mex)
IF(WIN32)
SET(OCTAVE_PATHS_L1 )
SET(OCTAVE_PATHS_L2 )
# Level 0
FILE(GLOB OCTAVE_PATHS_L0 "c:/Octave*")
# Level 1
FOREACH(_file_ ${OCTAVE_PATHS_L0})
FILE(GLOB OCTAVE_PATHS_TEMP "${_file_}/*")
SET(OCTAVE_PATHS_L1 ${OCTAVE_PATHS_L1};${OCTAVE_PATHS_TEMP})
ENDFOREACH(_file_ OCTAVE_PATHS_L0)
# Level 2
FOREACH(_file_ ${OCTAVE_PATHS_L1})
FILE(GLOB OCTAVE_PATHS_TEMP "${_file_}/*")
SET(OCTAVE_PATHS_L2 ${OCTAVE_PATHS_L2};${OCTAVE_PATHS_TEMP})
ENDFOREACH(_file_ OCTAVE_PATHS_L1)
# Merge levels
SET(OCTAVE_PATHS ${OCTAVE_PATHS_L0} ${OCTAVE_PATHS_L1} ${OCTAVE_PATHS_L2})
FIND_PATH(OCTAVE_ROOT "bin/octave.exe" ${OCTAVE_PATHS})
FIND_PATH(OCTAVE_USE_MINGW32 "bin/mingw32-make.exe" "${OCTAVE_ROOT}/mingw32")
IF(MSVC AND OCTAVE_USE_MINGW32)
MESSAGE(FATAL_ERROR
"You must use the generator \"MinGW Makefiles\" as the "
"version of Octave installed on your computer was compiled "
"with MinGW. You should also specify the native compiler "
"(GCC, G++ and GFortan) and add the path of MinGW in the "
"environment variable PATH. Contact the developers of the "
"project for more details")
ENDIF(MSVC AND OCTAVE_USE_MINGW32)
FILE(GLOB OCTAVE_INCLUDE_PATHS "${OCTAVE_ROOT}/include/octave-*/octave")
FILE(GLOB OCTAVE_LIBRARIES_PATHS "${OCTAVE_ROOT}/lib/octave-*")
IF (NOT OCTAVE_LIBRARIES_PATHS)
FILE(GLOB OCTAVE_LIBRARIES_PATHS "${OCTAVE_ROOT}/lib/octave/*")
ENDIF (NOT OCTAVE_LIBRARIES_PATHS)
# LIBOCTINTERP, LIBOCTAVE, LIBCRUFT names
SET(LIBOCTAVE "liboctave")
ELSE(WIN32)
IF(APPLE)
FILE(GLOB OCTAVE_PATHS "/Applications/Octave*")
FIND_PATH(OCTAVE_ROOT "Contents/Resources/bin/octave" ${OCTAVE_PATHS})
FILE(GLOB OCTAVE_INCLUDE_PATHS "${OCTAVE_ROOT}/Contents/Resources/include/octave-*/octave")
FILE(GLOB OCTAVE_LIBRARIES_PATHS "${OCTAVE_ROOT}/Contents/Resources/lib/octave-*")
SET(LIBOCTAVE "liboctave.dylib")
ELSE(APPLE)
FILE(GLOB OCTAVE_LOCAL_PATHS "/usr/local/lib/octave-*")
FILE(GLOB OCTAVE_USR_PATHS "/usr/lib/octave-*")
FILE(GLOB OCTAVE_INCLUDE_PATHS "/usr/include/octave-*")
SET (OCTAVE_INCLUDE_PATHS
"/usr/local/include"
"/usr/local/include/octave"
"/usr/include"
"${OCTAVE_INCLUDE_PATHS}"
"${OCTAVE_INCLUDE_PATHS}/octave")
SET (OCTAVE_LIBRARIES_PATHS
"/usr/local/lib"
"/usr/local/lib/octave"
${OCTAVE_LOCAL_PATHS}
"/usr/lib"
"/usr/lib/octave"
${OCTAVE_USR_PATHS})
SET (LIBOCTAVE "octave")
ENDIF(APPLE)
ENDIF(WIN32)
FIND_LIBRARY(OCTAVE_OCTAVE_LIBRARY
${LIBOCTAVE}
${OCTAVE_LIBRARIES_PATHS}
)
FIND_PATH(OCTAVE_INCLUDE_DIR
"mex.h"
${OCTAVE_INCLUDE_PATHS}
)
SET(OCTAVE_ROOT_LAST "${OCTAVE_ROOT}" CACHE INTERNAL "" FORCE)
# This is common to UNIX and Win32:
SET(OCTAVE_LIBRARIES
${OCTAVE_OCTAVE_LIBRARY}
CACHE INTERNAL "Octave libraries" FORCE
)
INCLUDE(FindPackageHandleStandardArgs)
# The variable OCTAVE_ROOT is only relevant for WIN32
IF(WIN32)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Octave DEFAULT_MSG OCTAVE_ROOT OCTAVE_INCLUDE_DIR OCTAVE_OCTAVE_LIBRARY )
ELSE(WIN32)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Octave DEFAULT_MSG OCTAVE_INCLUDE_DIR OCTAVE_OCTAVE_LIBRARY )
ENDIF(WIN32)
MARK_AS_ADVANCED(
OCTAVE_OCTAVE_LIBRARY
OCTAVE_LIBRARIES
OCTAVE_INCLUDE_DIR
)

@ -25,6 +25,9 @@ FIND_LIBRARY(
)
# Some functions are not defined in old volk versions
IF(${VOLK_FOUND})
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)
@ -35,14 +38,18 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_
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_32fc_magnitude_squared_32f HAVE_VOLK_MAG_SQUARE_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_32fc_x2_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_CFC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_conjugate_dot_prod_32fc HAVE_VOLK_DOTPROD_CONJ_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_interleave_32fc HAVE_VOLK_INTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_add_32f HAVE_VOLK_ADD_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION)
@ -56,15 +63,24 @@ ENDIF()
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAG_SQUARE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_SQUARE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_SQUARE_DIST_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SQUARE_DIST_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_INTERLEAVE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_INTERLEAVE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_ADD_FLOAT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ADD_FLOAT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION")
ENDIF()
@ -113,3 +129,4 @@ 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)
ENDIF(${VOLK_FOUND})

@ -68,7 +68,7 @@ bool cuhd_rx_wait_lo_locked(void *h)
{
double report = 0.0;
while (isLocked(h) && report < 3.0) {
while (isLocked(h) && report < 3000.0) {
report += 0.1;
usleep(1000);
}
@ -147,9 +147,17 @@ int cuhd_close(void *h)
double cuhd_set_rx_srate(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
printf("Changing sampling freq now to %.2f MHz\n", freq/1000000);
handler->usrp->set_rx_rate(freq);
double ret = handler->usrp->get_rx_rate();
return ret;
printf("Done\n");
/*
if ((int) ret != (int) freq) {
printf("Got %f!=%f. setting master clock rate to %f\n",ret, freq, freq);
handler->usrp->set_master_clock_rate(freq);
handler->usrp->set_rx_rate(freq);
}
*/
return freq;
}
double cuhd_set_rx_gain(void *h, double gain)
@ -162,8 +170,10 @@ double cuhd_set_rx_gain(void *h, double gain)
double cuhd_set_rx_freq(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
printf("Tunning receiver to %.3f MHz\n", (double ) freq/1000000);
handler->usrp->set_rx_freq(freq);
return handler->usrp->get_rx_freq();
printf("Done\n");
return freq;
}
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
@ -176,6 +186,7 @@ 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;
uint32_t nof_packets = 0;
if (blocking) {
int n = 0, p;
complex_t *data_c = (complex_t *) data;
@ -190,7 +201,10 @@ int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
}
#endif
} while (n < nsamples);
nof_packets++;
} while (n < nsamples &&
md.error_code == uhd::rx_metadata_t::ERROR_CODE_NONE &&
nof_packets < 10);
return nsamples;
} else {
return handler->rx_stream->recv(data, nsamples, md, 0.0);

@ -25,4 +25,6 @@
ADD_SUBDIRECTORY(phy)
ADD_SUBDIRECTORY(mac)
ADD_SUBDIRECTORY(rlc)
ADD_SUBDIRECTORY(rrc)
ADD_SUBDIRECTORY(pdcp)
ADD_SUBDIRECTORY(examples)

@ -51,19 +51,14 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
# These two can be compiled without UHD or graphics support
#################################################################
add_executable(pdsch_ue pdsch_ue.c iodev.c cell_search_utils.c)
target_link_libraries(pdsch_ue lte_phy)
add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb lte_phy)
IF(${CUHD_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
ELSE(${CUHD_FIND} EQUAL -1)
target_link_libraries(pdsch_ue cuhd)
target_link_libraries(pdsch_enodeb cuhd)
ENDIF(${CUHD_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1)
add_executable(pdsch_ue pdsch_ue.c cuhd_utils.c)
target_link_libraries(pdsch_ue lte_rrc lte_phy cuhd)
add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb lte_rrc lte_phy cuhd)
IF(${GRAPHICS_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
@ -73,6 +68,8 @@ ELSE(${GRAPHICS_FIND} EQUAL -1)
target_link_libraries(pdsch_enodeb graphics)
ENDIF(${GRAPHICS_FIND} EQUAL -1)
ENDIF(${CUHD_FIND} GREATER -1)
#################################################################
@ -81,11 +78,11 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1)
add_executable(cell_search cell_search.c cell_search_utils.c)
target_link_libraries(cell_search lte_phy cuhd )
add_executable(cell_search cell_search.c cuhd_utils.c)
target_link_libraries(cell_search lte_rrc lte_phy cuhd )
add_executable(cell_measurement cell_measurement.c cell_search_utils.c)
target_link_libraries(cell_measurement cuhd lte_phy)
add_executable(cell_measurement cell_measurement.c cuhd_utils.c)
target_link_libraries(cell_measurement cuhd lte_rrc lte_phy)
MESSAGE(STATUS " UHD examples will be installed.")

@ -0,0 +1,344 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/rrc/rrc.h"
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "cuhd_utils.h"
#define B210_DEFAULT_GAIN 40.0
#define B210_DEFAULT_GAIN_CORREC 110.0 // Gain of the Rx chain when the gain is set to 40
float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_search_cfg_t cell_detect_config = {
5000, // maximum number of frames to receive for MIB decoding
50, // maximum number of frames to receive for PSS correlation
16.0 // early-stops cell detection if mean PSR is above this value
};
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
int nof_subframes;
bool disable_plots;
int force_N_id_2;
char *uhd_args;
float uhd_freq;
float uhd_gain;
}prog_args_t;
void args_default(prog_args_t *args) {
args->nof_subframes = -1;
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
args->uhd_gain = B210_DEFAULT_GAIN;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [aglnv] -f rx_frequency (in Hz)\n", prog);
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-v [set verbose to debug, default none]\n");
}
int parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aglnvf")) != -1) {
switch (opt) {
case 'a':
args->uhd_args = argv[optind];
break;
case 'g':
args->uhd_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->force_N_id_2 = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
return -1;
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
return -1;
}
return 0;
}
/**********************************************************************/
/* TODO: Do something with the output data */
uint8_t data[10000], data_unpacked[1000];
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
extern float mean_exec_time;
enum receiver_state { DECODE_MIB, DECODE_SIB, MEASURE} state;
#define MAX_SINFO 10
#define MAX_NEIGHBOUR_CELLS 128
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
prog_args_t prog_args;
lte_cell_t cell;
int64_t sf_cnt;
ue_sync_t ue_sync;
ue_mib_t ue_mib;
void *uhd;
ue_dl_t ue_dl;
lte_fft_t fft;
chest_dl_t chest;
uint32_t nframes=0;
uint32_t nof_trials = 0;
uint32_t sfn = 0; // system frame number
int n;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
uint32_t sfn_offset;
float rssi_utra=0,rssi=0, rsrp=0, rsrq=0, snr=0;
cf_t *ce[MAX_PORTS];
if (parse_args(&prog_args, argc, argv)) {
exit(-1);
}
printf("Opening UHD device...\n");
if (cuhd_open(prog_args.uhd_args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
/* Set receiver gain */
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
return -1;
} else if (ret == 0) {
printf("Cell not found\n");
exit(0);
}
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
return LIBLTE_ERROR;
}
INFO("Stopping UHD and flushing buffer...\n",0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
return -1;
}
if (ue_dl_init(&ue_dl, cell, 1234)) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
return -1;
}
if (ue_mib_init(&ue_mib, cell)) {
fprintf(stderr, "Error initaiting UE MIB decoder\n");
return -1;
}
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
ue_dl_set_rnti(&ue_dl, SIRNTI);
/* Initialize subframe counter */
sf_cnt = 0;
if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n");
return -1;
}
if (chest_dl_init(&chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n");
return -1;
}
int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t));
for (int i=0;i<MAX_PORTS;i++) {
ce[i] = vec_malloc(sizeof(cf_t) * sf_re);
}
cuhd_start_rx_stream(uhd);
/* Main loop */
while (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
/* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
switch (state) {
case DECODE_MIB:
if (ue_sync_get_sfidx(&ue_sync) == 0) {
pbch_decode_reset(&ue_mib.pbch);
n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n");
return -1;
} else if (n == MIB_FOUND) {
bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn);
printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset);
sfn = (sfn + sfn_offset)%1024;
state = DECODE_SIB;
}
}
break;
case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */
if ((ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync),
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
return -1;
} else if (n == 0) {
printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, ExecTime: %5.1f us, NOI: %.2f, PDCCH-Det: %.3f\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
mean_exec_time, pdsch_average_noi(&ue_dl.pdsch),
(float) ue_dl.nof_pdcch_detected/nof_trials);
nof_trials++;
} else {
bit_unpack_vector(data, data_unpacked, n);
void *dlsch_msg = bcch_dlsch_unpack(data_unpacked, n);
if (dlsch_msg) {
printf("\n");fflush(stdout);
cell_access_info_t cell_info;
bcch_dlsch_sib1_get_cell_access_info(dlsch_msg, &cell_info);
printf("Decoded SIB1. Cell ID: 0x%x\n", cell_info.cell_id);
bcch_dlsch_fprint(dlsch_msg, stdout);
state = MEASURE;
}
}
}
break;
case MEASURE:
if (ue_sync_get_sfidx(&ue_sync) == 5) {
/* Run FFT for all subframe data */
lte_fft_run_sf(&fft, sf_buffer, sf_symbols);
chest_dl_estimate(&chest, sf_symbols, ce, ue_sync_get_sfidx(&ue_sync));
rssi = VEC_CMA(vec_avg_power_cf(sf_buffer,SF_LEN(lte_symbol_sz(cell.nof_prb))),rssi,nframes);
rssi_utra = VEC_CMA(chest_dl_get_rssi(&chest),rssi_utra,nframes);
rsrq = VEC_EMA(chest_dl_get_rsrq(&chest),rsrq,0.05);
rsrp = VEC_EMA(chest_dl_get_rsrp(&chest),rsrp,0.05);
snr = VEC_EMA(chest_dl_get_snr(&chest),snr,0.05);
nframes++;
}
// Plot and Printf
if ((nframes%10) == 0) {
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, RSSI: %5.1f dBm, RSSI/ref-symbol: %+5.1f dBm, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rssi*1000)-gain_offset,
10*log10(rssi_utra*1000)-gain_offset,
10*log10(rsrp*1000)-gain_offset,
10*log10(rsrq), 10*log10(snr));
if (verbose != VERBOSE_NONE) {
printf("\n");
}
}
break;
}
if (ue_sync_get_sfidx(&ue_sync) == 9) {
sfn++;
if (sfn == 1024) {
sfn = 0;
}
}
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&ue_sync.sfind),
ue_sync.frame_total_cnt, ue_sync.state);
}
sf_cnt++;
} // Main loop
ue_sync_free(&ue_sync);
cuhd_close(uhd);
printf("\nBye\n");
exit(0);
}

@ -37,7 +37,7 @@
#include "liblte/phy/phy.h"
#include "cell_search_utils.h"
#include "cuhd_utils.h"
#ifndef DISABLE_UHD
@ -54,9 +54,8 @@
int band = -1;
int earfcn_start=-1, earfcn_end = -1;
int nof_frames_total = 50;
int nof_frames_detected = 10;
float threshold = CS_FIND_THRESHOLD;
cell_search_cfg_t config = {500, 50, 1.1};
float uhd_gain = 60.0;
@ -69,8 +68,7 @@ void usage(char *prog) {
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-n nof_frames_total [Default 100]\n");
printf("\t-d nof_frames_detected [Default 10]\n");
printf("\t-t threshold [Default %.2f]\n",threshold);
printf("\t-t threshold [Default %.2f]\n",config.threshold);
printf("\t-v [set verbose to debug, default none]\n");
}
@ -91,13 +89,10 @@ void parse_args(int argc, char **argv) {
earfcn_end = atoi(argv[optind]);
break;
case 'n':
nof_frames_total = atoi(argv[optind]);
break;
case 'd':
nof_frames_detected = atoi(argv[optind]);
config.max_frames_pss = atoi(argv[optind]);
break;
case 't':
threshold = atof(argv[optind]);
config.threshold = atof(argv[optind]);
break;
case 'g':
uhd_gain = atof(argv[optind]);
@ -116,15 +111,19 @@ void parse_args(int argc, char **argv) {
}
}
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
int main(int argc, char **argv) {
int n;
void *uhd;
ue_celldetect_t s;
ue_celldetect_result_t found_cells[3];
ue_cell_search_t cs;
ue_cell_search_result_t found_cells[3];
int nof_freqs;
lte_earfcn_t channels[MAX_EARFCN];
uint32_t freq;
pbch_mib_t mib;
parse_args(argc, argv);
@ -141,21 +140,6 @@ int main(int argc, char **argv) {
exit(-1);
}
if (ue_celldetect_init(&s)) {
fprintf(stderr, "Error initiating UE sync module\n");
exit(-1);
}
if (threshold > 0) {
ue_celldetect_set_threshold(&s, threshold);
}
if (nof_frames_total > 0) {
ue_celldetect_set_nof_frames_total(&s, nof_frames_total);
}
if (nof_frames_detected > 0) {
ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected);
}
for (freq=0;freq<nof_freqs;freq+=10) {
/* set uhd_freq */
@ -171,18 +155,44 @@ int main(int argc, char **argv) {
printf("\n");
}
n = find_all_cells(uhd, found_cells);
bzero(found_cells, 3*sizeof(ue_cell_search_result_t));
if (ue_cell_search_init(&cs, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
exit(-1);
}
if (config.max_frames_pss) {
ue_cell_search_set_nof_frames_to_scan(&cs, config.max_frames_pss);
}
if (config.threshold) {
ue_cell_search_set_threshold(&cs, config.threshold);
}
INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000);
cuhd_set_rx_srate(uhd, CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
n = ue_cell_search_scan(&cs, found_cells, NULL);
if (n < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
if (n == CS_CELL_DETECTED) {
} else if (n == 1) {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > threshold/2) {
if (decode_pbch(uhd, &found_cells[i], nof_frames_total, &mib)) {
fprintf(stderr, "Error decoding PBCH\n");
if (found_cells[i].peak > config.threshold/2) {
lte_cell_t cell;
cell.id = found_cells[i].cell_id;
cell.cp = found_cells[i].cp;
int ret = cuhd_mib_decoder(uhd, 100, &cell);
if (ret < 0) {
fprintf(stderr, "Error decoding MIB\n");
exit(-1);
}
if (ret == MIB_FOUND) {
printf("Found CELL ID %d. %d PRB, %d ports\n",
cell.id, cell.nof_prb, cell.nof_ports);
}
}
}
}
@ -190,7 +200,6 @@ int main(int argc, char **argv) {
printf("\nBye\n");
ue_celldetect_free(&s);
cuhd_close(uhd);
exit(0);
}

@ -0,0 +1,171 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#include "liblte/rrc/rrc.h"
#include "cuhd_utils.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
int cuhd_recv_wrapper_cs(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
/** This function is simply a wrapper to the ue_cell_search module for cuhd devices
* Return 1 if the MIB is decoded, 0 if not or -1 on error.
*/
int cuhd_mib_decoder(void *uhd, uint32_t max_nof_frames, lte_cell_t *cell) {
int ret = LIBLTE_ERROR;
ue_mib_sync_t ue_mib;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
if (ue_mib_sync_init(&ue_mib, cell->id, cell->cp, cuhd_recv_wrapper_cs, uhd)) {
fprintf(stderr, "Error initiating ue_mib_sync\n");
goto clean_exit;
}
int srate = lte_sampling_freq_hz(MIB_NOF_PRB);
INFO("Setting sampling frequency %.2f MHz for PSS search\n", (float) srate/1000000);
cuhd_set_rx_srate(uhd, (float) srate);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
/* Find and decody MIB */
ret = ue_mib_sync_decode(&ue_mib, max_nof_frames, bch_payload, &cell->nof_ports, NULL);
if (ret < 0) {
fprintf(stderr, "Error decoding MIB\n");
goto clean_exit;
}
if (ret == 1) {
bit_unpack_vector(bch_payload, bch_payload_unpacked, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload_unpacked, BCH_PAYLOAD_LEN, cell, NULL);
}
clean_exit:
cuhd_stop_rx_stream(uhd);
ue_mib_sync_free(&ue_mib);
return ret;
}
/** This function is simply a wrapper to the ue_cell_search module for cuhd devices
*/
int cuhd_cell_search(void *uhd, cell_search_cfg_t *config,
int force_N_id_2, lte_cell_t *cell)
{
int ret = LIBLTE_ERROR;
ue_cell_search_t cs;
ue_cell_search_result_t found_cells[3];
bzero(found_cells, 3*sizeof(ue_cell_search_result_t));
if (ue_cell_search_init(&cs, cuhd_recv_wrapper_cs, uhd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
return LIBLTE_ERROR;
}
if (config->max_frames_pss) {
ue_cell_search_set_nof_frames_to_scan(&cs, config->max_frames_pss);
}
if (config->threshold) {
ue_cell_search_set_threshold(&cs, config->threshold);
}
INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000000);
cuhd_set_rx_srate(uhd, CS_SAMP_FREQ);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
/* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */
uint32_t max_peak_cell = 0;
if (force_N_id_2 >= 0) {
ret = ue_cell_search_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]);
max_peak_cell = force_N_id_2;
} else {
ret = ue_cell_search_scan(&cs, found_cells, &max_peak_cell);
}
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
return LIBLTE_ERROR;
} else if (ret == 0) {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_SUCCESS;
}
// Save result
if (cell) {
cell->id = found_cells[max_peak_cell].cell_id;
cell->cp = found_cells[max_peak_cell].cp;
}
cuhd_stop_rx_stream(uhd);
ue_cell_search_free(&cs);
return ret;
}
/* Finds a cell and decodes MIB from the PBCH.
* Returns 1 if the cell is found and MIB is decoded successfully.
* 0 if no cell was found or MIB could not be decoded,
* -1 on error
*/
int cuhd_search_and_decode_mib(void *uhd, cell_search_cfg_t *config, int force_N_id_2, lte_cell_t *cell)
{
int ret = LIBLTE_ERROR;
printf("Searching for cell...\n");
ret = cuhd_cell_search(uhd, config, force_N_id_2, cell);
if (ret > 0) {
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3);
ret = cuhd_mib_decoder(uhd, config->max_frames_pbch, cell);
if (ret < 0) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id);
return LIBLTE_ERROR;
}
}
return ret;
}
#endif

@ -0,0 +1,51 @@
/**
*
* \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 "liblte/phy/phy.h"
typedef struct LIBLTE_API {
uint32_t max_frames_pbch; // maximum number of 5ms frames to capture for MIB decoding
uint32_t max_frames_pss; // maximum number of 5ms frames to capture for PSS correlation
float threshold; // early-stops cell detection if mean PSR is above this value
}cell_search_cfg_t;
int cuhd_mib_decoder(void *uhd,
uint32_t max_nof_frames,
lte_cell_t *cell);
int cuhd_cell_search(void *uhd,
cell_search_cfg_t *config,
int force_N_id_2,
lte_cell_t *cell);
int cuhd_search_and_decode_mib(void *uhd,
cell_search_cfg_t *config,
int force_N_id_2,
lte_cell_t *cell);

@ -103,7 +103,7 @@ int main(int argc, char **argv) {
demod_soft_work(&demod_s);
/* hard decision for soft demodulation */
char* tmp = malloc(nbits);
uint8_t* tmp = malloc(nbits);
for (int i=0;i<nbits;i++) {
tmp[i] = demod_s.output[i]>0?1:0;
}

@ -33,7 +33,7 @@
int main(int argc, char **argv) {
binsource_t bs;
char* output;
uint8_t* output;
binsource_init(&bs);
binsource_seed_time(&bs);

@ -32,6 +32,7 @@
#include <unistd.h>
#include "liblte/phy/phy.h"
#include "liblte/rrc/rrc.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
@ -44,7 +45,9 @@ lte_cell_t cell = {
6, // nof_prb
1, // nof_ports
1, // cell_id
CPNORM // cyclic prefix
CPNORM, // cyclic prefix
R_1, // PHICH resources
PHICH_NORM // PHICH length
};
uint32_t cfi=1;
@ -52,7 +55,7 @@ uint32_t mcs_idx = 12;
int nof_frames = -1;
char *uhd_args = "";
float uhd_amp = 0.01, uhd_gain = 10.0, uhd_freq = 2400000000;
float uhd_amp = 0.1, uhd_gain = 40.0, uhd_freq = 2400000000;
filesink_t fsink;
lte_fft_t ifft;
@ -173,7 +176,7 @@ void base_init() {
exit(-1);
}
if (regs_init(&regs, R_1, PHICH_NORM, cell)) {
if (regs_init(&regs, cell)) {
fprintf(stderr, "Error initiating regs\n");
exit(-1);
}
@ -236,15 +239,16 @@ 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
pbch_mib_t mib;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_packed[BCH_PAYLOAD_LEN/8];
ra_pdsch_t ra_dl;
ra_prb_t prb_alloc;
refsignal_t refs[NSLOTS_X_FRAME];
int i, n;
char *data;
int i;
uint8_t *data;
cf_t *sf_symbols[MAX_PORTS];
dci_msg_t dci_msg;
dci_location_t locations[NSUBFRAMES_X_FRAME][10];
uint32_t sfn;
chest_dl_t est;
#ifdef DISABLE_UHD
if (argc < 3) {
@ -259,6 +263,10 @@ int main(int argc, char **argv) {
sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
sf_n_samples = 2 * SLOT_LEN(lte_symbol_sz(cell.nof_prb));
cell.phich_length = PHICH_NORM;
cell.phich_resources = R_1;
sfn = 0;
/* this *must* be called after setting slot_len_* */
base_init();
@ -266,19 +274,14 @@ int main(int argc, char **argv) {
pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cell.id);
//refsignal_cs_generate(&csr_signal, cell);
/* Generate CRS signals */
for (i = 0; i < NSLOTS_X_FRAME; i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
if (chest_dl_init(&est, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
exit(-1);
}
mib.nof_ports = cell.nof_ports;
mib.nof_prb = cell.nof_prb;
mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1;
mib.sfn = 0;
for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port
sf_symbols[i] = sf_buffer;
@ -315,7 +318,7 @@ int main(int argc, char **argv) {
pdcch_ue_locations(&pdcch, locations[i], 10, i, cfi, 1234);
}
data = malloc(sizeof(char) * ra_dl.mcs.tbs);
data = malloc(sizeof(uint8_t) * ra_dl.mcs.tbs);
if (!data) {
perror("malloc");
exit(-1);
@ -337,14 +340,14 @@ int main(int argc, char **argv) {
sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
CPNORM);
}
refsignal_cs_put_sf(cell, 0, est.csr_signal.pilots[0][sf_idx], sf_buffer);
bcch_bch_pack(&cell, sfn, bch_payload_packed, BCH_PAYLOAD_LEN/8);
bit_pack_vector(bch_payload_packed, bch_payload, BCH_PAYLOAD_LEN);
if (sf_idx == 0) {
pbch_encode(&pbch, &mib, sf_symbols);
pbch_encode(&pbch, bch_payload, sf_symbols);
}
for (n=0;n<2;n++) {
refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]);
}
pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx);
@ -379,8 +382,8 @@ int main(int argc, char **argv) {
}
nf++;
}
mib.sfn = (mib.sfn + 1) % 1024;
printf("SFN: %4d\r", mib.sfn);
sfn = (sfn + 1) % 1024;
printf("SFN: %4d\r", sfn);
fflush(stdout);
}

@ -0,0 +1,418 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/rrc/rrc.h"
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "cuhd_utils.h"
#ifndef DISABLE_GRAPHICS
void init_plots();
void do_plots(ue_dl_t *q, uint32_t sf_idx, ue_sync_t *qs);
#endif
#define B210_DEFAULT_GAIN 40.0
#define B210_DEFAULT_GAIN_CORREC 110.0 // Gain of the Rx chain when the gain is set to 40
float gain_offset = B210_DEFAULT_GAIN_CORREC;
cell_search_cfg_t cell_detect_config = {
5000,
100, // nof_frames_total
16.0 // threshold
};
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
int nof_subframes;
bool disable_plots;
int force_N_id_2;
uint16_t rnti;
char *uhd_args;
float uhd_freq;
float uhd_gain;
}prog_args_t;
void args_default(prog_args_t *args) {
args->nof_subframes = -1;
args->rnti = SIRNTI;
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
args->uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [agldnrv] -f rx_frequency (in Hz)\n", prog);
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
printf("\t-r RNTI [Default 0x%x]\n",args->rnti);
printf("\t-l Force N_id_2 [Default best]\n");
#ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n");
#else
printf("\t plots are disabled. Graphics library not available\n");
#endif
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "agldnvrf")) != -1) {
switch (opt) {
case 'a':
args->uhd_args = argv[optind];
break;
case 'g':
args->uhd_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'r':
args->rnti = atoi(argv[optind]);
break;
case 'l':
args->force_N_id_2 = atoi(argv[optind]);
break;
case 'd':
args->disable_plots = true;
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
/* TODO: Do something with the output data */
uint8_t data[10000], data_unpacked[1000];
bool go_exit = false;
void sig_int_handler(int signo)
{
if (signo == SIGINT) {
go_exit = true;
}
}
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
extern float mean_exec_time;
enum receiver_state { DECODE_MIB, DECODE_SIB} state;
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
prog_args_t prog_args;
lte_cell_t cell;
int64_t sf_cnt;
ue_sync_t ue_sync;
ue_mib_t ue_mib;
void *uhd;
ue_dl_t ue_dl;
uint32_t nof_trials = 0;
uint32_t sfn = 0; // system frame number
int n;
uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN];
uint32_t sfn_offset;
parse_args(&prog_args, argc, argv);
printf("Opening UHD device...\n");
if (cuhd_open(prog_args.uhd_args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
/* Set receiver gain */
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell);
if (ret < 0) {
fprintf(stderr, "Error searching for cell\n");
exit(-1);
} else if (ret == 0) {
printf("Cell not found\n");
exit(0);
}
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell.nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb);
return LIBLTE_ERROR;
}
INFO("Stopping UHD and flushing buffer...\r",0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
if (ue_dl_init(&ue_dl, cell, 1234)) { // This is the User RNTI
fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1);
}
if (ue_mib_init(&ue_mib, cell)) {
fprintf(stderr, "Error initaiting UE MIB decoder\n");
exit(-1);
}
/* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */
ue_dl_set_rnti(&ue_dl, prog_args.rnti);
/* Initialize subframe counter */
sf_cnt = 0;
// Register Ctrl+C handler
signal(SIGINT, sig_int_handler);
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) {
init_plots();
}
#endif
cuhd_start_rx_stream(uhd);
// Variables for measurements
uint32_t nframes=0;
float rsrp=0.0, rsrq=0.0, snr=0.0;
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
/* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
switch (state) {
case DECODE_MIB:
if (ue_sync_get_sfidx(&ue_sync) == 0) {
pbch_decode_reset(&ue_mib.pbch);
n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset);
if (n < 0) {
fprintf(stderr, "Error decoding UE MIB\n");
exit(-1);
} else if (n == MIB_FOUND) {
bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN);
bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn);
printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset);
sfn = (sfn + sfn_offset)%1024;
state = DECODE_SIB;
}
}
break;
case DECODE_SIB:
/* We are looking for SI Blocks, search only in appropiate places */
if ((ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) {
n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync),
((int) ceilf((float)3*(((sfn)/2)%4)/2))%4);
if (n < 0) {
fprintf(stderr, "Error decoding UE DL\n");fflush(stdout);
exit(-1);
}
nof_trials++;
rsrq = VEC_EMA(chest_dl_get_rsrq(&ue_dl.chest), rsrq, 0.05);
rsrp = VEC_EMA(chest_dl_get_rsrp(&ue_dl.chest), rsrp, 0.05);
snr = VEC_EMA(chest_dl_get_snr(&ue_dl.chest), snr, 0.05);
nframes++;
if (isnan(rsrq)) {
rsrq = 0;
}
}
// Plot and Printf
if (ue_sync_get_sfidx(&ue_sync) == 5) {
printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, "
"RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %4.1f dB, "
"PDCCH-Miss: %5.2f%%, PDSCH-BLER: %5.2f%% (%d blocks)\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rsrp*1000)-gain_offset,
10*log10(rsrq), 10*log10(snr),
100*(1-(float) ue_dl.nof_pdcch_detected/nof_trials),
(float) 100*ue_dl.pkt_errors/ue_dl.pkts_total,nof_trials, ue_dl.pkts_total);
}
break;
}
if (ue_sync_get_sfidx(&ue_sync) == 9) {
sfn++;
if (sfn == 1024) {
sfn = 0;
}
}
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots && ue_sync_get_sfidx(&ue_sync) == 5) {
do_plots(&ue_dl, 5, &ue_sync);
}
#endif
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&ue_sync.sfind),
ue_sync.frame_total_cnt, ue_sync.state);
}
sf_cnt++;
} // Main loop
ue_dl_free(&ue_dl);
ue_mib_free(&ue_mib);
ue_sync_free(&ue_sync);
cuhd_close(uhd);
printf("\nBye\n");
exit(0);
}
/**********************************************************************
* Plotting Functions
***********************************************************************/
#ifndef DISABLE_GRAPHICS
#include "liblte/graphics/plot.h"
plot_real_t poutfft, p_sync;
plot_real_t pce;
plot_scatter_t pscatequal, pscatequal_pdcch;
float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)];
float tmp_plot2[SLOT_LEN_RE(MAX_PRB, CPNORM)];
float tmp_plot3[SLOT_LEN_RE(MAX_PRB, CPNORM)];
void init_plots() {
plot_init();
plot_real_init(&poutfft);
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
plot_real_setLabels(&poutfft, "Index", "dB");
plot_real_setYAxisScale(&poutfft, -60, 0);
plot_real_init(&pce);
plot_real_setTitle(&pce, "Channel Response - Magnitude");
plot_real_setLabels(&pce, "Index", "dB");
plot_real_setYAxisScale(&pce, -60, 0);
plot_real_init(&p_sync);
plot_real_setTitle(&p_sync, "PSS Cross-Corr abs value");
plot_real_setYAxisScale(&p_sync, 0, 1);
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "PDSCH - Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -2, 2);
plot_scatter_setYAxisScale(&pscatequal, -2, 2);
plot_scatter_init(&pscatequal_pdcch);
plot_scatter_setTitle(&pscatequal_pdcch, "PDCCH - Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal_pdcch, -2, 2);
plot_scatter_setYAxisScale(&pscatequal_pdcch, -2, 2);
}
void do_plots(ue_dl_t *q, uint32_t sf_idx, ue_sync_t *qs) {
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] = 20 * log10f(cabsf(q->sf_symbols[i]));
if (isinf(tmp_plot[i])) {
tmp_plot[i] = -80;
}
}
for (i = 0; i < REFSIGNAL_NUM_SF(q->cell.nof_prb,0); i++) {
tmp_plot2[i] = 20 * log10f(cabsf(q->chest.pilot_estimates_average[0][i]));
if (isinf(tmp_plot2[i])) {
tmp_plot2[i] = -80;
}
}
plot_real_setNewData(&poutfft, tmp_plot, nof_re);
plot_real_setNewData(&pce, tmp_plot2, REFSIGNAL_NUM_SF(q->cell.nof_prb,0));
int max = vec_max_fi(qs->strack.pss.conv_output_avg, qs->strack.pss.frame_size+qs->strack.pss.fft_size-1);
vec_sc_prod_fff(qs->strack.pss.conv_output_avg,
1/qs->strack.pss.conv_output_avg[max],
tmp_plot2,
qs->strack.pss.frame_size+qs->strack.pss.fft_size-1);
plot_real_setNewData(&p_sync, tmp_plot2, qs->strack.pss.frame_size);
plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols);
plot_scatter_setNewData(&pscatequal_pdcch, q->pdcch.pdcch_d, 36*q->pdcch.nof_cce);
}
#endif

@ -195,7 +195,7 @@ int main(int argc, char **argv) {
gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) {
cfo_correct(&cfocorr, input, input, -force_cfo/128);
cfo_correct(&cfocorr, input, input, force_cfo/128);
}
if (force_N_id_2 != -1) {
@ -221,7 +221,7 @@ int main(int argc, char **argv) {
sss_idx = peak_pos[N_id_2]-2*(symbol_sz+CP(symbol_sz,CPNORM_LEN));
if (sss_idx >= 0) {
sss_synch_m0m1(&sss[N_id_2], &input[sss_idx],
sss_synch_m0m1_diff(&sss[N_id_2], &input[sss_idx],
&m0, &m0_value, &m1, &m1_value);
cfo[frame_cnt] = pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);

@ -39,10 +39,9 @@ FOREACH (_header ${headers})
LIST(APPEND HEADERS_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_header})
ENDFOREACH()
ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL})
ADD_CUSTOM_TARGET (add_lte_phy_headers SOURCES ${HEADERS_ALL})
########################################################################
# Add subdirectories
########################################################################
ADD_SUBDIRECTORY(lib)
ADD_SUBDIRECTORY(examples)

@ -1,218 +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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#include "cell_search_utils.h"
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
int nof_subframes;
bool disable_plots;
int force_N_id_2;
char *uhd_args;
float uhd_freq;
float uhd_gain;
}prog_args_t;
void args_default(prog_args_t *args) {
args->nof_subframes = -1;
args->force_N_id_2 = -1; // Pick the best
args->uhd_args = "";
args->uhd_freq = -1.0;
args->uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [aglnv] -f rx_frequency (in Hz)\n", prog);
printf("\t-a UHD args [Default %s]\n", args->uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain);
printf("\t-l Force N_id_2 [Default best]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "aglnvf")) != -1) {
switch (opt) {
case 'a':
args->uhd_args = argv[optind];
break;
case 'g':
args->uhd_gain = atof(argv[optind]);
break;
case 'f':
args->uhd_freq = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->force_N_id_2 = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->uhd_freq < 0) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
/* TODO: Do something with the output data */
char data[10000];
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
prog_args_t prog_args;
lte_cell_t cell;
int64_t sf_cnt;
pbch_mib_t mib;
ue_sync_t ue_sync;
void *uhd;
parse_args(&prog_args, argc, argv);
printf("Opening UHD device...\n");
if (cuhd_open(prog_args.uhd_args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
/* Set receiver gain */
cuhd_set_rx_gain(uhd, prog_args.uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000);
if (cell_search(uhd, prog_args.force_N_id_2, &cell, &mib)) {
fprintf(stderr, "Cell not found\n");
exit(-1);
}
cuhd_start_rx_stream(uhd);
if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
exit(-1);
}
/* Initialize subframe counter */
sf_cnt = 0;
lte_fft_t fft;
chest_t chest;
if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n");
return -1;
}
if (chest_init_LTEDL(&chest, cell)) {
fprintf(stderr, "Error initiating channel estimator\n");
return -1;
}
int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp);
cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t));
unsigned int nframes=0;
/* Main loop */
while (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) {
ret = ue_sync_get_buffer(&ue_sync, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
float rssi=0, rsrp=0, rsrq=0;
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
/* Run FFT for all subframe data */
lte_fft_run_sf(&fft, sf_buffer, sf_symbols);
chest_measure_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync));
rssi = VEC_CMA(chest_rssi_sf(&chest, sf_symbols),rssi,nframes);
rsrq = VEC_CMA(chest_rsrq_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync)),rsrq,nframes);
rsrp = VEC_CMA(chest_rsrp_sf(&chest, ue_sync_get_sfidx(&ue_sync)),rsrp,nframes);
nframes++;
// Plot and Printf
if ((nframes%10) == 0) {
printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, RSSI: %+5.2f dBm, RSRP: %+4.2f dBm, RSRQ: %4.2f dB\r",
ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000,
10*log10(rssi*1000/4/cell.nof_prb/12/2)-prog_args.uhd_gain,
10*log10(rsrp*1000)-prog_args.uhd_gain,
10*log10(rsrq));
}
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&ue_sync.sfind),
ue_sync.frame_total_cnt, ue_sync.state);
}
sf_cnt++;
} // Main loop
ue_sync_free(&ue_sync);
cuhd_close(uhd);
printf("\nBye\n");
exit(0);
}

@ -1,272 +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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
int decode_pbch(void *uhd, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib)
{
ue_mib_t uemib;
int n;
int ret = LIBLTE_ERROR;
uint32_t nof_frames = 0;
uint32_t flen = MIB_FRAME_SIZE;
cf_t *buffer = vec_malloc(sizeof(cf_t) * flen);
if (!buffer) {
perror("malloc");
goto free_and_exit;
}
bzero(mib, sizeof(pbch_mib_t));
if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) {
fprintf(stderr, "Error initiating PBCH decoder\n");
goto free_and_exit;
}
INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0);
cuhd_set_rx_srate(uhd, 1920000.0);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
DEBUG("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
n = ue_mib_decode(&uemib, buffer, flen, mib);
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling ue_mib_decode()\n");
goto free_and_exit;
}
if (n == MIB_FRAME_UNALIGNED) {
printf("Realigning frame\n");
if (cuhd_recv(uhd, buffer, 1500, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
bzero(buffer, flen * sizeof(cf_t));
}
nof_frames++;
} while (n != MIB_FOUND && nof_frames < 2*nof_frames_total);
if (n == MIB_FOUND) {
printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames);
pbch_mib_fprint(stdout, mib, found_cell->cell_id);
ret = LIBLTE_SUCCESS;
} else {
ret = LIBLTE_ERROR;
}
free_and_exit:
free(buffer);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
ue_mib_free(&uemib);
return ret;
}
int find_cell(void *uhd, ue_celldetect_result_t *found_cell, uint32_t N_id_2)
{
int ret = LIBLTE_ERROR;
ue_celldetect_t cd;
cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000);
if (!buffer) {
perror("malloc");
goto free_and_exit;
}
if (ue_celldetect_init(&cd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
goto free_and_exit;
}
ue_celldetect_set_nof_frames_detected(&cd, 50);
ue_celldetect_set_nof_frames_total(&cd, 500);
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
cuhd_set_rx_srate(uhd, 960000.0);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
uint32_t flen = 4800;
int n;
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
DEBUG("Scanning cell at N_id_2=%d\n",N_id_2);
n = ue_celldetect_scan(&cd, buffer, flen, found_cell, N_id_2);
switch(n) {
case CS_FRAME_UNALIGNED:
printf("Realigning frame\n");
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
goto free_and_exit;
}
/* FIXME: What should we do here?? */
ret = -1;
goto free_and_exit;
case CS_CELL_DETECTED:
if (found_cell->peak > 0) {
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
found_cell->cell_id,
lte_cp_string(found_cell->cp),
found_cell->peak, found_cell->mode,
cd.nof_frames_detected);
}
ret = 1;
INFO("Cell found at N_id_2=%d\n",N_id_2);
break;
case CS_CELL_NOT_DETECTED:
ret = 0;
DEBUG("No cell found at N_id_2=%d\n",N_id_2);
break;
case LIBLTE_ERROR:
case LIBLTE_ERROR_INVALID_INPUTS:
ret = LIBLTE_ERROR;
fprintf(stderr, "Error calling cellsearch_scan()\n");
goto free_and_exit;
}
} while(n == 0);
free_and_exit:
free(buffer);
ue_celldetect_free(&cd);
INFO("Stopping receiver...\n", 0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
return ret;
}
int find_all_cells(void *uhd, ue_celldetect_result_t found_cell[3])
{
uint32_t N_id_2;
int ret;
int nof_detected_cells = 0;
for (N_id_2=0;N_id_2<3;N_id_2++) {
ret = find_cell(uhd, &found_cell[N_id_2], N_id_2);
if (ret == 1) {
nof_detected_cells++;
} else if (ret == LIBLTE_ERROR) {
return LIBLTE_ERROR;
}
}
return nof_detected_cells;
}
int cell_search(void *uhd, int force_N_id_2, lte_cell_t *cell, pbch_mib_t *mib)
{
int ret;
ue_celldetect_result_t found_cells[3];
bzero(found_cells, 3*sizeof(ue_celldetect_result_t));
if (force_N_id_2 >= 0) {
ret = find_cell(uhd, &found_cells[force_N_id_2], force_N_id_2);
} else {
ret = find_all_cells(uhd, found_cells);
}
if (ret < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
int max_peak_cell = 0;
float max_peak_value = -1.0;
if (ret > 0) {
if (force_N_id_2 >= 0) {
max_peak_cell = force_N_id_2;
} else {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > max_peak_value) {
max_peak_value = found_cells[i].peak;
max_peak_cell = i;
}
}
}
printf("Decoding PBCH for cell %d (N_id_2=%d)\n", found_cells[max_peak_cell].cell_id, max_peak_cell);
if (decode_pbch(uhd, &found_cells[max_peak_cell], 400, mib)) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", found_cells[max_peak_cell].cell_id);
return LIBLTE_ERROR;
}
} else {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_ERROR;
}
cell->cp = found_cells[max_peak_cell].cp;
cell->id = found_cells[max_peak_cell].cell_id;
cell->nof_prb = mib->nof_prb;
cell->nof_ports = mib->nof_ports;
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell->nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
return LIBLTE_SUCCESS;
}
#endif

@ -1,204 +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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "iodev.h"
#include "liblte/phy/io/filesource.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
#endif
#include "cell_search_utils.h"
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
/* Setup USRP or input file */
int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mib) {
if (config->input_file_name) {
mib->phich_resources = R_1;
mib->phich_length = PHICH_NORM;
cell->id = config->cell_id_file;
cell->cp = CPNORM;
cell->nof_ports = config->nof_ports_file;
cell->nof_prb = config->nof_prb_file;
if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) {
return LIBLTE_ERROR;
}
q->mode = FILESOURCE;
int symbol_sz = lte_symbol_sz(cell->nof_prb);
if (symbol_sz > 0) {
q->sf_len = SF_LEN(symbol_sz);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
q->input_buffer_file = vec_malloc(q->sf_len * sizeof(cf_t));
if (!q->input_buffer_file) {
perror("malloc");
return LIBLTE_ERROR;
}
q->sf_idx = 9;
} else {
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open(config->uhd_args, &q->uhd)) {
fprintf(stderr, "Error opening uhd\n");
return LIBLTE_ERROR;
}
/* Set receiver gain */
cuhd_set_rx_gain(q->uhd, config->uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq);
cuhd_rx_wait_lo_locked(q->uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq);
if (cell_search(q->uhd, config->force_N_id_2, cell, mib)) {
fprintf(stderr, "Cell not found\n");
return LIBLTE_ERROR;
}
cuhd_start_rx_stream(q->uhd);
if (ue_sync_init(&q->sframe, *cell, cuhd_recv_wrapper, q->uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
return LIBLTE_ERROR;
}
// Here, the subframe length and input buffer is managed by ue_sync
q->mode = UHD;
#else
printf("Error UHD not available. Select an input file\n");
return LIBLTE_ERROR;
#endif
}
memcpy(&q->config, config, sizeof(iodev_cfg_t));
return LIBLTE_SUCCESS;
}
void iodev_free(iodev_t *q) {
if (q->mode == FILESOURCE) {
filesource_free(&q->fsrc);
} else {
#ifndef DISABLE_UHD
cuhd_close(q->uhd);
#endif
}
}
/* Receive samples from the USRP or read from file */
int iodev_receive(iodev_t *q, cf_t **buffer) {
int n;
if (q->mode == FILESOURCE) {
INFO(" ----- READING %d SAMPLES ---- \n", q->sf_len);
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
*buffer = q->input_buffer_file;
if (n == -1) {
fprintf(stderr, "Error reading file\n");
/* wrap file if arrive to end */
} else if (n < q->sf_len) {
DEBUG("Read %d from file. Seeking to 0\n",n);
filesource_seek(&q->fsrc, 0);
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
if (n == -1) {
fprintf(stderr, "Error reading file\n");
/* wrap file if arrive to end */
} else {
n = 1;
}
} else {
n = 1;
}
q->sf_idx++;
if (q->sf_idx == 10) {
q->sf_idx = 0;
}
usleep(5000);
} else {
/* Use ue_sync_work which returns a synchronized buffer of subframe samples */
#ifndef DISABLE_UHD
n = ue_sync_get_buffer(&q->sframe, buffer);
if (n < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
#endif
}
return n;
}
void* iodev_get_cuhd(iodev_t *q) {
if (q->mode == UHD) {
return q->uhd;
} else {
return NULL;
}
}
bool iodev_isfile(iodev_t *q) {
return q->mode == FILESOURCE;
}
bool iodev_isUSRP(iodev_t *q) {
return q->mode == UHD;
}
uint32_t iodev_get_sfidx(iodev_t *q) {
if (iodev_isfile(q)) {
return q->sf_idx;
} else {
return ue_sync_get_sfidx(&q->sframe);
}
}

@ -1,100 +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 IODEF_H
#define IODEF_H
#include "liblte/config.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/io/filesource.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
#endif
/*********
*
* This component is a wrapper to the cuhd or filesource modules. It uses
* sync_frame_t to read aligned subframes from the USRP or filesource to read
* subframes from a file.
*
* When created, it starts receiving/reading at 1.92 MHz. The sampling frequency
* can then be changed using iodev_set_srate()
*/
typedef enum LIBLTE_API {FILESOURCE, UHD} iodev_mode_t;
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
char *input_file_name;
uint32_t cell_id_file;
uint32_t nof_prb_file;
uint32_t nof_ports_file;
int force_N_id_2;
float uhd_freq;
float uhd_gain;
char *uhd_args;
float find_threshold;
} iodev_cfg_t;
typedef struct LIBLTE_API {
#ifndef DISABLE_UHD
void *uhd;
ue_sync_t sframe;
#endif
uint32_t sf_len;
uint32_t sf_idx;
cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t
filesource_t fsrc;
iodev_cfg_t config;
iodev_mode_t mode;
} iodev_t;
LIBLTE_API int iodev_init(iodev_t *q,
iodev_cfg_t *config,
lte_cell_t *cell,
pbch_mib_t *mib);
LIBLTE_API void iodev_free(iodev_t *q);
LIBLTE_API int iodev_receive(iodev_t *q,
cf_t **buffer);
LIBLTE_API void* iodev_get_cuhd(iodev_t *q);
LIBLTE_API uint32_t iodev_get_sfidx(iodev_t *q);
LIBLTE_API bool iodev_isfile(iodev_t *q);
LIBLTE_API bool iodev_isUSRP(iodev_t *q);
#endif

@ -1,309 +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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/phy/phy.h"
#include "iodev.h"
#ifndef DISABLE_GRAPHICS
void init_plots();
void do_plots(ue_dl_t *q, uint32_t sf_idx);
#endif
int go_exit = 0;
/* Local function definitions */
void init_plots();
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
uint16_t rnti;
int nof_subframes;
bool disable_plots;
iodev_cfg_t io_config;
}prog_args_t;
void args_default(prog_args_t *args) {
args->io_config.cell_id_file = 195;
args->io_config.nof_prb_file = 50;
args->io_config.nof_ports_file = 2;
args->rnti = SIRNTI;
args->nof_subframes = -1;
args->disable_plots = false;
args->io_config.find_threshold = -1.0;
args->io_config.input_file_name = NULL;
args->io_config.force_N_id_2 = -1; // Pick the best
args->io_config.uhd_args = "";
args->io_config.uhd_freq = -1.0;
args->io_config.uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [cargndvtbl] [-i input_file | -f rx_frequency (in Hz)]\n", prog);
printf("\t-c cell_id if reading from file [Default %d]\n", args->io_config.cell_id_file);
printf("\t-p nof_prb if reading from file [Default %d]\n", args->io_config.nof_prb_file);
printf("\t-o nof_ports if reading from file [Default %d]\n", args->io_config.nof_ports_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", 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-l Force N_id_2 [Default best]\n");
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
printf("\t plots are disabled. Graphics library not available\n");
#endif
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "icagfndvtbprol")) != -1) {
switch (opt) {
case 'i':
args->io_config.input_file_name = argv[optind];
break;
case 'c':
args->io_config.cell_id_file = atoi(argv[optind]);
break;
case 'p':
args->io_config.nof_prb_file = atoi(argv[optind]);
break;
case 'o':
args->io_config.nof_ports_file = atoi(argv[optind]);
break;
case 'a':
args->io_config.uhd_args = argv[optind];
break;
case 'g':
args->io_config.uhd_gain = atof(argv[optind]);
break;
case 'f':
args->io_config.uhd_freq = atof(argv[optind]);
break;
case 't':
args->io_config.find_threshold = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'l':
args->io_config.force_N_id_2 = atoi(argv[optind]);
break;
case 'r':
args->rnti= atoi(argv[optind]);
break;
case 'd':
args->disable_plots = true;
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) {
usage(args, argv[0]);
exit(-1);
}
}
/**********************************************************************/
void sigintHandler(int x) {
go_exit = 1;
}
/* TODO: Do something with the output data */
char data[10000];
extern float mean_exec_time;
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;
int64_t sf_cnt;
pbch_mib_t mib;
bool printed_sib = false;
int rlen;
parse_args(&prog_args, argc, argv);
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) {
init_plots();
}
#endif
/* Initialize subframe counter */
sf_cnt = 0;
if (iodev_init(&iodev, &prog_args.io_config, &cell, &mib)) {
exit(-1);
}
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);
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
ret = iodev_receive(&iodev, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error reading from input device (%d)\n", ret);
break;
}
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
rlen = ue_dl_decode(&ue_dl, sf_buffer, data, iodev_get_sfidx(&iodev), prog_args.rnti);
if (rlen < 0) {
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
exit(-1);
}
if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) {
printf("\n\nDecoded SIB1 Message: ");
vec_fprint_hex(stdout, data, rlen);
printf("\n");fflush(stdout);
printed_sib = true;
}
// Plot and Printf
if (!(sf_cnt % 10)) {
printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d/%4d, BLER: %.1e, Texec: %.2f\r",
ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000,
pdsch_average_noi(&ue_dl.pdsch),
(int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (int) ue_dl.nof_trials,
(float) ue_dl.pkt_errors / ue_dl.pkts_total,
mean_exec_time);
}
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots && iodev_get_sfidx(&iodev) == 5) {
do_plots(&ue_dl, 5);
}
#endif
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&iodev.sframe.sfind),
iodev.sframe.frame_total_cnt, iodev.sframe.state);
}
sf_cnt++;
} // Main loop
ue_dl_free(&ue_dl);
iodev_free(&iodev);
printf("\nBye\n");
exit(0);
}
/**********************************************************************
* Plotting Functions
***********************************************************************/
#ifndef DISABLE_GRAPHICS
#include "liblte/graphics/plot.h"
plot_real_t poutfft;
plot_complex_t pce;
plot_scatter_t pscatrecv, pscatequal;
float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)];
void init_plots() {
plot_init();
plot_real_init(&poutfft);
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
plot_real_setLabels(&poutfft, "Index", "dB");
plot_real_setYAxisScale(&poutfft, -30, 20);
plot_complex_init(&pce);
plot_complex_setTitle(&pce, "Channel Estimates");
plot_complex_setYAxisScale(&pce, Ip, -3, 3);
plot_complex_setYAxisScale(&pce, Q, -3, 3);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 4);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -4, 4);
plot_scatter_setYAxisScale(&pscatrecv, -4, 4);
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -2, 2);
plot_scatter_setYAxisScale(&pscatequal, -2, 2);
}
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;
}
}
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

@ -1,238 +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 CHEST_
#define CHEST_
#include <stdio.h>
#include "liblte/config.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/common/phy_common.h"
typedef _Complex float cf_t; /* this is only a shortcut */
typedef void (*interpolate_fnc_t) (cf_t *input,
cf_t *output,
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
* refsignal_t
* A 2-D filter is used for freq and time channel interpolation.
*
*/
/* Low-level API */
typedef struct LIBLTE_API {
uint32_t nof_ports;
uint32_t nof_re;
uint32_t nof_symbols;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interp_t interp_time[MAX_PORTS];
interp_t interp_freq[MAX_PORTS];
}chest_t;
LIBLTE_API int chest_init(chest_t *q,
uint32_t nof_re,
uint32_t nof_symbols,
uint32_t nof_ports);
LIBLTE_API void chest_free(chest_t *q);
LIBLTE_API int chest_set_nof_ports(chest_t *q,
uint32_t nof_ports);
LIBLTE_API float chest_rsrp(chest_t *q,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API float chest_rsrp_sf(chest_t *q,
uint32_t sf_idx);
LIBLTE_API float chest_rssi(chest_t *q,
cf_t *input);
LIBLTE_API float chest_rssi_sf(chest_t *q,
cf_t *input);
LIBLTE_API float chest_rsrq(chest_t *q,
cf_t *input,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API float chest_rsrq_sf(chest_t *q,
cf_t *input,
uint32_t sf_idx);
LIBLTE_API int chest_measure_ref(chest_t *q,
cf_t *input,
uint32_t nslot,
uint32_t port_id,
uint32_t nref);
LIBLTE_API void chest_measure_slot(chest_t *q,
cf_t *input,
uint32_t nslot);
LIBLTE_API void chest_measure_sf(chest_t *q,
cf_t *input,
uint32_t sf_idx);
LIBLTE_API int chest_ce_slot_port(chest_t *q,
cf_t *input,
cf_t *ce,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API int chest_ce_sf_port(chest_t *q,
cf_t *input,
cf_t *ce,
uint32_t sf_idx,
uint32_t port_id);
LIBLTE_API int chest_ce_slot(chest_t *q,
cf_t *input,
cf_t *ce[MAX_PORTS],
uint32_t nslot);
LIBLTE_API int chest_ce_sf(chest_t *q,
cf_t *input,
cf_t *ce[MAX_PORTS],
uint32_t sf_idx);
LIBLTE_API void chest_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API void chest_ref_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API void chest_recvsig_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API void chest_ce_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API int chest_ref_get_symbols(chest_t *q,
uint32_t port_id,
uint32_t nslot,
uint32_t l[2]);
/*********************************************************
*
* Downlink Channel Estimator
*
*********************************************************/
LIBLTE_API int chest_init_LTEDL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEDL_slot_port(chest_t *q,
uint32_t nslot,
uint32_t port_id,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEDL_slot(chest_t *q,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEDL(chest_t *q,
lte_cell_t cell);
/*********************************************************
*
* Uplink Channel Estimator
*
*********************************************************/
LIBLTE_API int chest_init_LTEUL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEUL_slot(chest_t *q,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int chest_ref_set_LTEUL(chest_t *q,
lte_cell_t cell);
/* High-level API */
/** TODO: The high-level API has N interfaces, one for each port */
typedef struct LIBLTE_API{
chest_t obj;
struct chest_init {
int nof_symbols; // 7 for normal cp, 6 for extended
int nof_ports;
int nof_prb;
int cell_id; // set to -1 to init at runtime
} init;
cf_t *input;
int in_len;
struct chest_ctrl_in {
int sf_idx; // subframe id in the 10ms frame
} ctrl_in;
cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS];
}chest_hl;
#define DEFAULT_FRAME_SIZE 2048
LIBLTE_API int chest_initialize(chest_hl* h);
LIBLTE_API int chest_work(chest_hl* hl);
LIBLTE_API int chest_stop(chest_hl* hl);
#endif

@ -0,0 +1,113 @@
/**
*
* \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 CHEST_DL_
#define CHEST_DL_
#include <stdio.h>
#include "liblte/config.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/filter/filter2d.h"
#include "liblte/phy/ch_estimation/refsignal_dl.h"
#include "liblte/phy/common/phy_common.h"
/** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest
* of the resource grid.
*
* The equalizer uses the channel estimates to produce an estimation of the transmitted symbol.
*
* This object depends on the refsignal_t object for creating the LTE CSR signal.
*/
#define CHEST_MAX_FILTER_FREQ_LEN 10
#define CHEST_MAX_FILTER_TIME_LEN 4
typedef struct {
lte_cell_t cell;
refsignal_cs_t csr_signal;
cf_t *pilot_estimates[MAX_PORTS];
cf_t *pilot_estimates_average[MAX_PORTS];
cf_t *pilot_recv_signal[MAX_PORTS];
uint32_t filter_freq_len;
float filter_freq[CHEST_MAX_FILTER_FREQ_LEN];
uint32_t filter_time_len;
float filter_time[CHEST_MAX_FILTER_TIME_LEN];
cf_t *tmp_noise;
cf_t *tmp_freqavg;
cf_t *tmp_timeavg[CHEST_MAX_FILTER_TIME_LEN];
interp_linvec_t interp_linvec;
interp_lin_t interp_lin;
float rssi[MAX_PORTS];
float rsrp[MAX_PORTS];
float noise_estimate[MAX_PORTS];
} chest_dl_t;
LIBLTE_API int chest_dl_init(chest_dl_t *q,
lte_cell_t cell);
LIBLTE_API void chest_dl_free(chest_dl_t *q);
LIBLTE_API int chest_dl_set_filter_freq(chest_dl_t *q,
float *filter,
uint32_t filter_len);
LIBLTE_API int chest_dl_set_filter_time(chest_dl_t *q,
float *filter,
uint32_t filter_len);
LIBLTE_API int chest_dl_estimate(chest_dl_t *q,
cf_t *input,
cf_t *ce[MAX_PORTS],
uint32_t sf_idx);
LIBLTE_API int chest_dl_estimate_port(chest_dl_t *q,
cf_t *input,
cf_t *ce,
uint32_t sf_idx,
uint32_t port_id);
LIBLTE_API float chest_dl_get_snr(chest_dl_t *q);
LIBLTE_API float chest_dl_get_noise_estimate(chest_dl_t *q);
LIBLTE_API float chest_dl_get_rssi(chest_dl_t *q);
LIBLTE_API float chest_dl_get_rsrq(chest_dl_t *q);
LIBLTE_API float chest_dl_get_rsrp(chest_dl_t *q);
#endif

@ -1,92 +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 REFSIGNAL_
#define REFSIGNAL_
/* Object to manage reference signals for OFDM channel equalization.
*
* It generates the reference signals for LTE.
*
*/
#include "liblte/config.h"
#include "liblte/phy/common/phy_common.h"
typedef _Complex float cf_t;
typedef struct LIBLTE_API{
uint32_t time_idx;
uint32_t freq_idx;
cf_t symbol;
}ref_t;
typedef struct LIBLTE_API{
uint32_t nof_refs; // number of reference signals
uint32_t *symbols_ref; // symbols with at least one reference
uint32_t nsymbols; // number of symbols with at least one reference
uint32_t voffset; // offset of the first reference in the freq domain
uint32_t nof_prb;
ref_t *refs;
cf_t *ch_est;
cf_t *recv_symbol;
} refsignal_t;
typedef struct LIBLTE_API {
float beta; // amplitude scaling
uint32_t delta_ss; // Set to 0 for PUCCH
uint32_t cyclic_shift;
uint32_t cyclic_shift_for_drms; /* From DCI 0. Set to 0 if no PDCCH with DCI 0 for the same TB
or if the initial PUSCH is semi-persisently scheduled or
if the initial PUSCH is scheduled by the RA response grant */
bool group_hopping_en;
bool sequence_hopping_en;
} refsignal_ul_cfg_t;
LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q,
uint32_t port_id,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int refsignal_init_LTEUL_drms_pusch(refsignal_t *q,
uint32_t nof_prb,
uint32_t prb_start,
uint32_t nslot,
lte_cell_t cell,
refsignal_ul_cfg_t *drms_cfg);
LIBLTE_API void refsignal_free(refsignal_t *q);
LIBLTE_API int refsignal_put(refsignal_t *q,
cf_t *slot_symbols);
#endif

@ -0,0 +1,83 @@
/**
*
* \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 REFSIGNAL_DL_
#define REFSIGNAL_DL_
/* Object to manage Downlink reference signals for channel estimation.
*
*/
#include "liblte/config.h"
#include "liblte/phy/common/phy_common.h"
typedef _Complex float cf_t;
// Number of references in a subframe: there are 2 symbols for port_id=0,1 x 2 slots x 2 refs per prb
#define REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb))
#define REFSIGNAL_MAX_NUM_SF(nof_prb) REFSIGNAL_NUM_SF(nof_prb, 0)
#define REFSIGNAL_PILOT_IDX(i,l,cell) (2*cell.nof_prb*(l)+(i))
/** Cell-Specific Reference Signal */
typedef struct LIBLTE_API {
lte_cell_t cell;
cf_t *pilots[2][NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3
} refsignal_cs_t;
LIBLTE_API int refsignal_cs_generate(refsignal_cs_t *q,
lte_cell_t cell);
LIBLTE_API void refsignal_cs_free(refsignal_cs_t *q);
LIBLTE_API int refsignal_cs_put_sf(lte_cell_t cell,
uint32_t port_id,
cf_t *pilots,
cf_t *sf_symbols);
LIBLTE_API int refsignal_cs_get_sf(lte_cell_t cell,
uint32_t port_id,
cf_t *sf_symbols,
cf_t *pilots);
LIBLTE_API uint32_t refsignal_fidx(lte_cell_t cell,
uint32_t l,
uint32_t port_id,
uint32_t m);
LIBLTE_API uint32_t refsignal_nsymbol(uint32_t l,
lte_cp_t cp,
uint32_t port_id);
LIBLTE_API uint32_t refsignal_cs_v(uint32_t port_id,
uint32_t ref_symbol_idx);
LIBLTE_API uint32_t refsignal_cs_nof_symbols(uint32_t port_id);
#endif

@ -37,6 +37,8 @@
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/utils/dft.h"
//#define LTE_FFT_NORMALIZE
typedef _Complex float cf_t; /* this is only a shortcut */
/* This is common for both directions */

@ -29,8 +29,11 @@
#ifndef _LTEBASE_
#define _LTEBASE_
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "liblte/config.h"
#define NSUBFRAMES_X_FRAME 10
@ -57,6 +60,8 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define CELL_ID_UNKNOWN 1000
#define MAX_NSYMB 7
#define MAX_PRB 110
@ -78,7 +83,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define CP_ISEXT(cp) (cp==CPEXT)
#define CP_NSYMB(cp) (CP_ISNORM(cp)?CPNORM_NSYMB:CPEXT_NSYMB)
#define CP(symbol_sz, c) ((c*symbol_sz)/2048)
#define CP(symbol_sz, c) ((int) ceil((((float) (c)*(symbol_sz))/2048)))
#define CP_NORM(symbol, symbol_sz) ((symbol==0)?CP((symbol_sz),CPNORM_0_LEN):CP((symbol_sz),CPNORM_LEN))
#define CP_EXT(symbol_sz) (CP((symbol_sz),CPEXT_LEN))
@ -86,13 +91,17 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SF_LEN(symbol_sz) (2*SLOT_LEN(symbol_sz))
#define SF_LEN_MAX (SF_LEN(SYMBOL_SZ_MAX))
#define SLOT_LEN_PRB(nof_prb) (SLOT_LEN(lte_symbol_sz(nof_prb)))
#define SF_LEN_PRB(nof_prb) (SF_LEN(lte_symbol_sz(nof_prb)))
#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_CPNORM(symbol_idx, symbol_sz) (symbol_idx==0?0:(symbol_sz + CP(symbol_sz, CPNORM_0_LEN) + \
(symbol_idx-1)*(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 RE_IDX(nof_prb, symbol_idx, sample_idx) ((symbol_idx)*(nof_prb)*(RE_X_RB) + sample_idx)
#define RS_VSHIFT(cell_id) (cell_id%6)
@ -107,20 +116,24 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define NOF_TC_CB_SIZES 188
typedef _Complex float cf_t;
typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef struct LIBLTE_API {
uint32_t nof_prb;
uint32_t nof_ports;
uint32_t id;
lte_cp_t cp;
phich_length_t phich_length;
phich_resources_t phich_resources;
}lte_cell_t;
typedef enum LIBLTE_API {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
} lte_mimo_type_t;
typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef enum LIBLTE_API {
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
} lte_mod_t;
@ -137,6 +150,17 @@ LIBLTE_API enum band_geographical_area {
LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell);
LIBLTE_API void lte_cell_fprint(FILE *stream,
lte_cell_t *cell);
LIBLTE_API bool lte_cellid_isvalid(uint32_t cell_id);
LIBLTE_API bool lte_nofprb_isvalid(uint32_t nof_prb);
LIBLTE_API bool lte_sfidx_isvalid(uint32_t sf_idx);
LIBLTE_API bool lte_portid_isvalid(uint32_t port_id);
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);

@ -32,7 +32,7 @@
#include "liblte/phy/common/phy_common.h"
typedef struct LIBLTE_API {
char *c;
uint8_t *c;
uint32_t len;
} sequence_t;
@ -44,6 +44,9 @@ LIBLTE_API int sequence_LTE_pr(sequence_t *q,
uint32_t len,
uint32_t seed);
LIBLTE_API void sequence_set_LTE_pr(sequence_t *q,
uint32_t seed);
LIBLTE_API int sequence_pbch(sequence_t *seq,
lte_cp_t cp,
uint32_t cell_id);

@ -40,7 +40,7 @@ typedef struct LIBLTE_API {
bool tail_biting;
}convcoder_t;
LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length);
LIBLTE_API int convcoder_encode(convcoder_t *q, uint8_t *input, uint8_t *output, uint32_t frame_length);
/* High-level API */
@ -55,9 +55,9 @@ typedef struct LIBLTE_API {
int generator_2;
int frame_length;
} ctrl_in;
char *input;
uint8_t *input;
int in_len;
char *output;
uint8_t *output;
int out_len;
}convcoder_hl;

@ -34,18 +34,18 @@
typedef struct LIBLTE_API {
unsigned long table[256];
unsigned char byte;
uint8_t byte;
int polynom;
int order;
unsigned long crcinit;
unsigned long crcmask;
unsigned long crchighbit;
unsigned int crc_out;
uint32_t crc_out;
} crc_t;
LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
LIBLTE_API int crc_init(crc_t *h, uint32_t crc_poly, int crc_order);
LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value);
LIBLTE_API void crc_attach(crc_t *h, char *data, int len);
LIBLTE_API uint32_t crc_checksum(crc_t *h, char *data, int len);
LIBLTE_API void crc_attach(crc_t *h, uint8_t *data, int len);
LIBLTE_API uint32_t crc_checksum(crc_t *h, uint8_t *data, int len);
#endif

@ -33,9 +33,9 @@
#define RX_NULL 10000
#define TX_NULL 80
LIBLTE_API int rm_conv_tx(char *input,
LIBLTE_API int rm_conv_tx(uint8_t *input,
uint32_t in_len,
char *output,
uint8_t *output,
uint32_t out_len);
LIBLTE_API int rm_conv_rx(float *input,
@ -49,7 +49,7 @@ typedef struct
struct rm_conv_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
void *input; // input type may be uint8_t or float depending on hard
int in_len;
struct rm_conv_ctrl_in {
int E;

@ -41,11 +41,11 @@
#include "liblte/config.h"
LIBLTE_API int rm_turbo_tx(char *w_buff,
LIBLTE_API int rm_turbo_tx(uint8_t *w_buff,
uint32_t buff_len,
char *input,
uint8_t *input,
uint32_t in_len,
char *output,
uint8_t *output,
uint32_t out_len,
uint32_t rv_idx);
@ -63,7 +63,7 @@ typedef struct LIBLTE_API {
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
void *input; // input type may be uint8_t or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;

@ -43,7 +43,7 @@ typedef struct LIBLTE_API {
LIBLTE_API int tcod_init(tcod_t *h, uint32_t max_long_cb);
LIBLTE_API void tcod_free(tcod_t *h);
LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb);
LIBLTE_API int tcod_encode(tcod_t *h, uint8_t *input, uint8_t *output, uint32_t long_cb);
#endif

@ -80,12 +80,12 @@ LIBLTE_API void tdec_iteration(tdec_t * h,
uint32_t long_cb);
LIBLTE_API void tdec_decision(tdec_t * h,
char *output,
uint8_t *output,
uint32_t long_cb);
LIBLTE_API void tdec_run_all(tdec_t * h,
llr_t * input,
char *output,
uint8_t *output,
uint32_t nof_iterations,
uint32_t long_cb);

@ -40,13 +40,15 @@ typedef struct LIBLTE_API{
void *ptr;
uint32_t R;
uint32_t K;
unsigned int framebits;
uint32_t framebits;
bool tail_biting;
float gain_quant;
uint32_t poly[3];
int (*decode) (void*, uint8_t*, char*, uint32_t);
int (*decode) (void*, uint8_t*, uint8_t*, uint32_t);
int (*decode_f) (void*, float*, uint8_t*, uint32_t);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
uint8_t *tmp;
uint8_t *symbols_uc;
}viterbi_t;
LIBLTE_API int viterbi_init(viterbi_t *q,
@ -55,16 +57,19 @@ LIBLTE_API int viterbi_init(viterbi_t *q,
uint32_t max_frame_length,
bool tail_bitting);
LIBLTE_API void viterbi_set_gain_quant(viterbi_t *q,
float gain_quant);
LIBLTE_API void viterbi_free(viterbi_t *q);
LIBLTE_API int viterbi_decode_f(viterbi_t *q,
float *symbols,
char *data,
uint8_t *data,
uint32_t frame_length);
LIBLTE_API int viterbi_decode_uc(viterbi_t *q,
uint8_t *symbols,
char *data,
uint8_t *data,
uint32_t frame_length);
@ -82,7 +87,7 @@ typedef struct LIBLTE_API{
} init;
float *input;
int in_len;
char *output;
uint8_t *output;
int out_len;
}viterbi_hl;

@ -31,6 +31,7 @@
#define FILTER2D_
#include "liblte/config.h"
#include <stdint.h>
/* 2-D real filter of complex input
*
@ -38,18 +39,42 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API{
int sztime; // Output signal size in the time domain
int szfreq; // Output signal size in the freq domain
int ntime; // 2-D Filter size in time domain
int nfreq; // 2-D Filter size in frequency domain
uint32_t sztime; // Output signal size in the time domain
uint32_t szfreq; // Output signal size in the freq domain
uint32_t ntime; // 2-D Filter size in time domain
uint32_t nfreq; // 2-D Filter size in frequency domain
float **taps; // 2-D filter coefficients
float norm; //normalization factor
cf_t *output; // Output signal
} filter2d_t;
LIBLTE_API int filter2d_init (filter2d_t* q, float **taps, int ntime, int nfreq, int sztime, int szfreq);
LIBLTE_API int filter2d_init_default (filter2d_t* q, int ntime, int nfreq, int sztime, int szfreq);
LIBLTE_API int filter2d_init (filter2d_t* q,
float **taps,
uint32_t ntime,
uint32_t nfreq,
uint32_t sztime,
uint32_t szfreq);
LIBLTE_API int filter2d_init_ones (filter2d_t* q,
uint32_t ntime,
uint32_t nfreq,
uint32_t sztime,
uint32_t szfreq);
LIBLTE_API void filter2d_free(filter2d_t *q);
LIBLTE_API void filter2d_step(filter2d_t *q);
LIBLTE_API void filter2d_reset(filter2d_t *q);
LIBLTE_API void filter2d_add(filter2d_t *q, cf_t h, int time_idx, int freq_idx);
LIBLTE_API void filter2d_add(filter2d_t *q,
cf_t h,
uint32_t time_idx,
uint32_t freq_idx);
LIBLTE_API void filter2d_add_out(filter2d_t *q, cf_t x, int time_idx, int freq_idx);
LIBLTE_API void filter2d_get_symbol(filter2d_t *q,
uint32_t nsymbol,
cf_t *output);
#endif // FILTER2D_

@ -35,7 +35,7 @@
/* Low-level API */
typedef struct LIBLTE_API{
unsigned int seed;
uint32_t seed;
uint32_t *seq_buff;
int seq_buff_nwords;
int seq_cache_nbits;
@ -44,23 +44,23 @@ typedef struct LIBLTE_API{
LIBLTE_API void binsource_init(binsource_t* q);
LIBLTE_API void binsource_free(binsource_t* q);
LIBLTE_API void binsource_seed_set(binsource_t* q, unsigned int seed);
LIBLTE_API void binsource_seed_set(binsource_t* q, uint32_t seed);
LIBLTE_API void binsource_seed_time(binsource_t *q);
LIBLTE_API int binsource_cache_gen(binsource_t* q, int nbits);
LIBLTE_API void binsource_cache_cpy(binsource_t* q, char *bits, int nbits);
LIBLTE_API int binsource_generate(binsource_t* q, char *bits, int nbits);
LIBLTE_API void binsource_cache_cpy(binsource_t* q, uint8_t *bits, int nbits);
LIBLTE_API int binsource_generate(binsource_t* q, uint8_t *bits, int nbits);
/* High-level API */
typedef struct LIBLTE_API {
binsource_t obj;
struct binsource_init {
int cache_seq_nbits; // If non-zero, generates random bits on init
unsigned int seed; // If non-zero, uses as random seed, otherwise local time is used.
uint32_t seed; // If non-zero, uses as random seed, otherwise local time is used.
} init;
struct binsource_ctrl_in {
int nbits; // Number of bits to generate
} ctrl_in;
char* output;
uint8_t* output;
int out_len;
}binsource_hl;

@ -37,20 +37,69 @@ typedef _Complex float cf_t;
* resources on each of the antenna ports.
*/
typedef struct {
cf_t *h_mod;
cf_t *tmp1;
cf_t *tmp2;
cf_t *tmp3;
float *y_mod;
float *z_real;
float *z_imag;
uint32_t max_frame_len;
}precoding_t;
LIBLTE_API int precoding_init(precoding_t *q,
uint32_t max_frame_len);
LIBLTE_API void precoding_free(precoding_t *q);
/* Generates the vector "y" from the input vector "x"
*/
LIBLTE_API int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
LIBLTE_API int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
LIBLTE_API int precoding_single(precoding_t *q,
cf_t *x,
cf_t *y,
int nof_symbols);
LIBLTE_API int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
int nof_ports, int nof_symbols, lte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
*/
LIBLTE_API int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols);
LIBLTE_API int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
LIBLTE_API int precoding_diversity(precoding_t *q,
cf_t *x[MAX_LAYERS],
cf_t *y[MAX_PORTS],
int nof_ports, int nof_symbols);
LIBLTE_API int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type);
LIBLTE_API int precoding_type(precoding_t *q,
cf_t *x[MAX_LAYERS],
cf_t *y[MAX_PORTS],
int nof_layers,
int nof_ports,
int nof_symbols,
lte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "h"
*/
LIBLTE_API int predecoding_single(precoding_t *q,
cf_t *y,
cf_t *h,
cf_t *x,
int nof_symbols,
float noise_estimate);
LIBLTE_API int predecoding_diversity(precoding_t *q,
cf_t *y,
cf_t *h[MAX_PORTS],
cf_t *x[MAX_LAYERS],
int nof_ports,
int nof_symbols,
float noise_estimate);
LIBLTE_API int predecoding_type(precoding_t *q,
cf_t *y,
cf_t *h[MAX_PORTS],
cf_t *x[MAX_LAYERS],
int nof_ports,
int nof_layers,
int nof_symbols,
lte_mimo_type_t type,
float noise_estimate);
#endif /* PRECODING_H_ */

@ -44,7 +44,7 @@ typedef struct LIBLTE_API {
LIBLTE_API void demod_hard_init(demod_hard_t* q);
LIBLTE_API void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod);
LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols);
LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, uint8_t *bits, uint32_t nsymbols);
@ -58,7 +58,7 @@ typedef struct LIBLTE_API {
cf_t* input;
int in_len;
char* output;
uint8_t* output;
int out_len;
}demod_hard_hl;

@ -37,7 +37,7 @@
typedef _Complex float cf_t;
LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, uint32_t nbits);
LIBLTE_API int mod_modulate(modem_table_t* table, const uint8_t *bits, cf_t* symbols, uint32_t nbits);
/* High-level API */
typedef struct LIBLTE_API {
@ -46,7 +46,7 @@ typedef struct LIBLTE_API {
lte_mod_t std; // symbol mapping standard (see modem_table.h)
} init;
const char* input;
const uint8_t* input;
int in_len;
cf_t* output;

@ -46,7 +46,7 @@ typedef _Complex float cf_t;
#define DCI_MAX_BITS 57
typedef enum {
Format0, Format1, Format1A, Format1C
Format0, Format1, Format1A, Format1C, FormatError
} dci_format_t;
// Each type is for a different interface to packing/unpacking functions
@ -67,7 +67,7 @@ typedef struct LIBLTE_API {
} dci_location_t;
typedef struct LIBLTE_API {
char data[DCI_MAX_BITS];
uint8_t data[DCI_MAX_BITS];
uint32_t nof_bits;
} dci_msg_t;
@ -89,6 +89,8 @@ LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg,
uint32_t cfi,
ra_pusch_t *ra_ul);
*/
LIBLTE_API dci_format_t dci_format_from_string(char *str);
LIBLTE_API char* dci_format_string(dci_format_t format);
LIBLTE_API int dci_location_set(dci_location_t *c,

@ -41,19 +41,15 @@
#include "liblte/phy/fec/viterbi.h"
#include "liblte/phy/fec/crc.h"
#define BCH_PAYLOAD_LEN 24
#define BCH_PAYLOADCRC_LEN (BCH_PAYLOAD_LEN+16)
#define BCH_ENCODED_LEN 3*(BCH_PAYLOADCRC_LEN)
#define PBCH_RE_CPNORM 240
#define PBCH_RE_CPEXT 216
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
uint32_t nof_ports;
uint32_t nof_prb;
uint32_t sfn;
phich_length_t phich_length;
phich_resources_t phich_resources;
}pbch_mib_t;
/* PBCH object */
typedef struct LIBLTE_API {
lte_cell_t cell;
@ -67,10 +63,10 @@ typedef struct LIBLTE_API {
cf_t *pbch_d;
float *pbch_llr;
float *temp;
float *pbch_rm_f;
char *pbch_rm_b;
char *data;
char *data_enc;
float pbch_rm_f[BCH_ENCODED_LEN];
uint8_t *pbch_rm_b;
uint8_t data[BCH_PAYLOADCRC_LEN];
uint8_t data_enc[BCH_ENCODED_LEN];
uint32_t frame_idx;
@ -81,6 +77,7 @@ typedef struct LIBLTE_API {
viterbi_t decoder;
crc_t crc;
convcoder_t encoder;
precoding_t precoding;
} pbch_t;
@ -91,16 +88,15 @@ LIBLTE_API void pbch_free(pbch_t *q);
LIBLTE_API int pbch_decode(pbch_t *q,
cf_t *slot1_symbols,
cf_t *ce_slot1[MAX_PORTS],
pbch_mib_t *mib);
float noise_estimate,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports,
uint32_t *sfn_offset);
LIBLTE_API int pbch_encode(pbch_t *q,
pbch_mib_t *mib,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
cf_t *slot1_symbols[MAX_PORTS]);
LIBLTE_API void pbch_decode_reset(pbch_t *q);
LIBLTE_API void pbch_mib_fprint(FILE *stream,
pbch_mib_t *mib,
uint32_t cell_id);
#endif // PBCH_

@ -33,13 +33,12 @@
#include "liblte/phy/mimo/precoding.h"
#include "liblte/phy/mimo/layermap.h"
#include "liblte/phy/modem/mod.h"
#include "liblte/phy/modem/demod_hard.h"
#include "liblte/phy/modem/demod_soft.h"
#include "liblte/phy/scrambling/scrambling.h"
#include "liblte/phy/phch/regs.h"
#define PCFICH_CFI_LEN 32
#define PCFICH_RE PCFICH_CFI_LEN/2
#define PCFICH_MAX_DISTANCE 5
typedef _Complex float cf_t;
@ -57,13 +56,20 @@ typedef struct LIBLTE_API {
cf_t pcfich_x[MAX_PORTS][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE];
// cfi table in floats
float cfi_table_float[3][PCFICH_CFI_LEN];
/* bit message */
char data[PCFICH_CFI_LEN];
uint8_t data[PCFICH_CFI_LEN];
/* received soft bits */
float data_f[PCFICH_CFI_LEN];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
demod_soft_t demod;
sequence_t seq_pcfich[NSUBFRAMES_X_FRAME];
precoding_t precoding;
} pcfich_t;
@ -76,9 +82,10 @@ LIBLTE_API void pcfich_free(pcfich_t *q);
LIBLTE_API int pcfich_decode(pcfich_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
float noise_estimate,
uint32_t subframe,
uint32_t *cfi,
uint32_t *distance);
float *corr_result);
LIBLTE_API int pcfich_encode(pcfich_t *q,
uint32_t cfi,

@ -53,7 +53,6 @@ typedef enum LIBLTE_API {
/* PDCCH object */
typedef struct LIBLTE_API {
lte_cell_t cell;
uint32_t e_bits;
uint32_t nof_regs;
uint32_t nof_cce;
uint32_t max_bits;
@ -65,7 +64,8 @@ typedef struct LIBLTE_API {
cf_t *pdcch_symbols[MAX_PORTS];
cf_t *pdcch_x[MAX_PORTS];
cf_t *pdcch_d;
char *pdcch_e;
uint8_t *pdcch_e;
float pdcch_rm_f[3 * (DCI_MAX_BITS + 16)];
float *pdcch_llr;
/* tx & rx objects */
@ -74,6 +74,8 @@ typedef struct LIBLTE_API {
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
crc_t crc;
precoding_t precoding;
} pdcch_t;
LIBLTE_API int pdcch_init(pdcch_t *q,
@ -96,13 +98,14 @@ LIBLTE_API int pdcch_encode(pdcch_t *q,
LIBLTE_API int pdcch_extract_llr(pdcch_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
dci_location_t location,
float noise_estimate,
uint32_t nsubframe,
uint32_t cfi);
/* Decoding functions: Try to decode a DCI message after calling pdcch_extract_llr */
LIBLTE_API int pdcch_decode_msg(pdcch_t *q,
dci_msg_t *msg,
dci_location_t *location,
dci_format_t format,
uint16_t *crc_rem);

@ -55,7 +55,7 @@ typedef struct LIBLTE_API {
uint32_t max_cb;
uint32_t w_buff_size;
float **pdsch_w_buff_f;
char **pdsch_w_buff_c;
uint8_t **pdsch_w_buff_c;
struct cb_segm {
uint32_t F;
@ -76,7 +76,6 @@ typedef struct LIBLTE_API {
bool rnti_is_set;
uint16_t rnti;
uint32_t nof_iterations;
uint64_t average_nof_iterations_n;
float average_nof_iterations;
/* buffers */
@ -85,7 +84,7 @@ typedef struct LIBLTE_API {
cf_t *pdsch_symbols[MAX_PORTS];
cf_t *pdsch_x[MAX_PORTS];
cf_t *pdsch_d;
char *cb_in;
uint8_t *cb_in;
void *cb_out;
void *pdsch_e;
@ -97,6 +96,8 @@ typedef struct LIBLTE_API {
tdec_t decoder;
crc_t crc_tb;
crc_t crc_cb;
precoding_t precoding;
}pdsch_t;
LIBLTE_API int pdsch_init(pdsch_t *q,
@ -114,10 +115,12 @@ LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p,
ra_mcs_t mcs,
ra_prb_t *prb_alloc);
LIBLTE_API void pdsch_harq_reset(pdsch_harq_t *p);
LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p);
LIBLTE_API int pdsch_encode(pdsch_t *q,
char *data,
uint8_t *data,
cf_t *sf_symbols[MAX_PORTS],
uint32_t nsubframe,
pdsch_harq_t *harq_process,
@ -126,7 +129,8 @@ LIBLTE_API int pdsch_encode(pdsch_t *q,
LIBLTE_API int pdsch_decode(pdsch_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
char *data,
float noise_estimate,
uint8_t *data,
uint32_t nsubframe,
pdsch_harq_t *harq_process,
uint32_t rv_idx);

@ -69,12 +69,13 @@ typedef struct LIBLTE_API {
cf_t phich_z[PHICH_NBITS];
/* bit message */
char data[PHICH_NBITS];
uint8_t data[PHICH_NBITS];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_phich[NSUBFRAMES_X_FRAME];
precoding_t precoding;
}phich_t;
@ -87,14 +88,15 @@ LIBLTE_API void phich_free(phich_t *q);
LIBLTE_API int phich_decode(phich_t *q,
cf_t *slot_symbols,
cf_t *ce[MAX_PORTS],
float noise_estimate,
uint32_t ngroup,
uint32_t nseq,
uint32_t nsubframe,
char *ack,
uint8_t *ack,
uint32_t *distance);
LIBLTE_API int phich_encode(phich_t *q,
char ack,
uint8_t ack,
uint32_t ngroup,
uint32_t nseq,
uint32_t nsubframe,

@ -39,7 +39,7 @@
typedef struct LIBLTE_API {
lte_mod_t mod;
uint32_t tbs;
int tbs;
} ra_mcs_t;
typedef enum LIBLTE_API {
@ -72,7 +72,7 @@ typedef struct LIBLTE_API {
} ra_type2_t;
typedef struct LIBLTE_API {
uint32_t prb_idx[MAX_PRB];
bool prb_idx[MAX_PRB];
uint32_t nof_prb;
} ra_prb_slot_t;
@ -123,7 +123,8 @@ typedef struct LIBLTE_API {
} ra_pusch_t;
LIBLTE_API void ra_prb_fprint(FILE *f,
ra_prb_slot_t *prb);
ra_prb_slot_t *prb,
uint32_t nof_prb);
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb,
ra_pdsch_t *ra,

@ -76,8 +76,6 @@ typedef struct LIBLTE_API {
}regs_t;
LIBLTE_API int regs_init(regs_t *h,
phich_resources_t phich_res,
phich_length_t phich_len,
lte_cell_t cell);
LIBLTE_API void regs_free(regs_t *h);

@ -51,8 +51,8 @@
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/common/fft.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/ch_estimation/refsignal_dl.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/resampling/decim.h"
@ -95,7 +95,7 @@
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/ue/ue_mib.h"
#include "liblte/phy/ue/ue_celldetect.h"
#include "liblte/phy/ue/ue_cell_search.h"
#include "liblte/phy/ue/ue_dl.h"
#include "liblte/phy/scrambling/scrambling.h"

@ -34,65 +34,70 @@
typedef _Complex float cf_t;
typedef enum LIBLTE_API {LINEAR} interp_type_t;
typedef struct LIBLTE_API {
interp_type_t type;
/************* STATIC LINEAR INTERPOLATION FUNCTIONS */
float *in_mag;
float *in_arg;
float *in_mag0;
float *in_arg0;
float *in_mag1;
float *in_arg1;
LIBLTE_API cf_t interp_linear_onesample(cf_t input0,
cf_t input1);
float *out_mag;
float *out_arg;
float *out_arg2;
int16_t *table_idx;
LIBLTE_API cf_t interp_linear_onesample_cabs(cf_t input0,
cf_t input1);
cf_t *out_cexp;
cf_t *out_prod;
LIBLTE_API void interp_linear_offset_cabs(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_f(float *input,
float *output,
uint32_t M,
uint32_t len);
cf_t *cexptable;
uint32_t len;
uint32_t M;
}interp_t;
/* Interpolation between vectors */
LIBLTE_API int interp_init(interp_t *q,
interp_type_t type,
uint32_t len,
typedef struct {
cf_t *diff_vec;
uint32_t vector_len;
} interp_linvec_t;
LIBLTE_API int interp_linear_vector_init(interp_linvec_t *q,
uint32_t vector_len);
LIBLTE_API void interp_linear_vector_free(interp_linvec_t *q);
LIBLTE_API void interp_linear_vector(interp_linvec_t *q,
cf_t *in0,
cf_t *in1,
cf_t *between,
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);
/* Interpolation within a vector */
LIBLTE_API void interp_linear_offset(cf_t *input,
typedef struct {
cf_t *diff_vec;
cf_t *diff_vec2;
float *ramp;
uint32_t vector_len;
uint32_t M;
} interp_lin_t;
LIBLTE_API int interp_linear_init(interp_lin_t *q,
uint32_t vector_len,
uint32_t M);
LIBLTE_API void interp_linear_free(interp_lin_t *q);
LIBLTE_API void interp_linear_offset(interp_lin_t *q,
cf_t *input,
cf_t *output,
uint32_t M,
uint32_t len,
uint32_t off_st,
uint32_t off_end);
LIBLTE_API void interp_linear_c(cf_t *input,
cf_t *output,
uint32_t M,
uint32_t len);
LIBLTE_API void interp_linear_f(float *input,
float *output,
uint32_t M,
uint32_t len);
#endif // INTERP_H

@ -36,8 +36,8 @@
typedef _Complex float cf_t;
/* Scrambling has no state */
LIBLTE_API void scrambling_b(sequence_t *s, char *data);
LIBLTE_API void scrambling_b_offset(sequence_t *s, char *data, int offset, int len);
LIBLTE_API void scrambling_b(sequence_t *s, uint8_t *data);
LIBLTE_API void scrambling_b_offset(sequence_t *s, uint8_t *data, int offset, int len);
LIBLTE_API void scrambling_f(sequence_t *s, float *data);
LIBLTE_API void scrambling_f_offset(sequence_t *s, float *data, int offset, int len);
@ -71,7 +71,7 @@ typedef struct LIBLTE_API {
int channel;
int nof_symbols; // 7 normal 6 extended
} init;
void *input; // input type may be char or float depending on hard
void *input; // input type may be uint8_t or float depending on hard
int in_len;
struct scrambling_ctrl_in {
int subframe;

@ -39,13 +39,18 @@
typedef _Complex float cf_t; /* this is only a shortcut */
#define CONVOLUTION_FFT
#define DEFAULT_CORRELATION_TH 10000
#define DEFAULT_NOSYNC_TIMEOUT 5
#define PSS_LEN 62
#define PSS_RE 6*12
/* PSS processing options */
#define PSS_ACCUMULATE_ABS // If enabled, accumulates the correlation absolute value on consecutive calls to pss_synch_find_pss
#define PSS_ABS_SQUARE // If enabled, compute abs square, otherwise computes absolute value only
#define PSS_RETURN_PSR // If enabled returns peak to side-lobe ratio, otherwise returns absolute peak value
/**
* The pss_synch_t object provides functions for fast computation of the crosscorrelation
@ -62,6 +67,8 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* Low-level API */
typedef struct LIBLTE_API {
dft_plan_t dftp_input;
#ifdef CONVOLUTION_FFT
conv_fft_cc_t conv_fft;
#endif
@ -70,10 +77,14 @@ typedef struct LIBLTE_API {
uint32_t N_id_2;
uint32_t fft_size;
cf_t pss_signal_time[3][PSS_LEN];
cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
cf_t *tmp_input;
cf_t *conv_output;
float *conv_output_abs;
float ema_alpha;
float *conv_output_avg;
float peak_value;
}pss_synch_t;
typedef enum { PSS_TX, PSS_RX } pss_direction_t;
@ -88,6 +99,8 @@ LIBLTE_API int pss_synch_init(pss_synch_t *q,
LIBLTE_API void pss_synch_free(pss_synch_t *q);
LIBLTE_API void pss_synch_reset(pss_synch_t *q);
LIBLTE_API int pss_generate(cf_t *signal,
uint32_t N_id_2);
@ -96,6 +109,9 @@ LIBLTE_API void pss_put_slot(cf_t *pss_signal,
uint32_t nof_prb,
lte_cp_t cp);
LIBLTE_API void pss_synch_set_ema_alpha(pss_synch_t *q,
float alpha);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q,
uint32_t N_id_2);
@ -103,6 +119,10 @@ LIBLTE_API int pss_synch_find_pss(pss_synch_t *q,
cf_t *input,
float *corr_peak_value);
LIBLTE_API int pss_synch_chest(pss_synch_t *q,
cf_t *input,
cf_t ce[PSS_LEN]);
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q,
cf_t *pss_recv);

@ -42,8 +42,6 @@ typedef _Complex float cf_t; /* this is only a shortcut */
#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];
@ -54,9 +52,10 @@ struct sss_tables{
* Should use vec_malloc() to make it platform agnostic.
*/
struct fc_tables{
cf_t z1[N_SSS+1][N_SSS+1];
cf_t c[2][N_SSS+1];
cf_t s[N_SSS+1][N_SSS+1];
float z1[N_SSS][N_SSS];
float c[2][N_SSS];
float s[N_SSS][N_SSS];
float sd[N_SSS][N_SSS-1];
};
@ -75,6 +74,9 @@ typedef struct LIBLTE_API {
uint32_t N_id_1_table[30][30];
struct fc_tables fc_tables[3]; // one for each N_id_2
float corr_output_m0[N_SSS];
float corr_output_m1[N_SSS];
}sss_synch_t;
@ -99,13 +101,31 @@ LIBLTE_API void sss_put_slot(float *sss,
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,
LIBLTE_API int sss_synch_m0m1_partial(sss_synch_t *q,
cf_t *input,
uint32_t M,
cf_t ce[2*N_SSS],
uint32_t *m0,
float *m0_value,
uint32_t *m1,
float *m1_value);
LIBLTE_API int sss_synch_m0m1_diff_coh(sss_synch_t *q,
cf_t *input,
cf_t ce[2*N_SSS],
uint32_t *m0,
float *m0_value,
uint32_t *m1,
float *m1_value);
LIBLTE_API int sss_synch_m0m1_diff(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);

@ -35,6 +35,7 @@
#include "liblte/config.h"
#include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sss.h"
#include "liblte/phy/sync/cfo.h"
#define FFT_SIZE_MIN 64
#define FFT_SIZE_MAX 2048
@ -51,11 +52,12 @@
* functions sync_pss_det_absolute() and sync_pss_det_peakmean().
*/
typedef enum {SSS_DIFF=0, SSS_PARTIAL_3=2, SSS_FULL=1} sss_alg_t;
typedef struct LIBLTE_API {
pss_synch_t pss;
sss_synch_t sss;
float threshold;
float mean_energy;
float peak_value;
float mean_peak_value;
uint32_t N_id_2;
@ -63,16 +65,20 @@ typedef struct LIBLTE_API {
uint32_t sf_idx;
uint32_t fft_size;
uint32_t frame_size;
uint64_t frame_cnt;
float cfo;
float mean_cfo;
cfo_t cfocorr;
sss_alg_t sss_alg;
bool detect_cp;
bool sss_en;
bool normalize_en;
bool correct_cfo;
lte_cp_t cp;
uint32_t m0;
uint32_t m1;
float m0_value;
float m1_value;
float M_norm_avg;
float M_ext_avg;
}sync_t;
@ -90,6 +96,11 @@ LIBLTE_API int sync_find(sync_t *q,
uint32_t find_offset,
uint32_t *peak_position);
/* Estimates the CP length */
LIBLTE_API lte_cp_t sync_detect_cp(sync_t *q,
cf_t *input,
uint32_t peak_pos);
/* Sets the threshold for peak comparison */
LIBLTE_API void sync_set_threshold(sync_t *q,
float threshold);
@ -103,8 +114,13 @@ LIBLTE_API float sync_get_last_peak_value(sync_t *q);
/* Gets the mean peak value */
LIBLTE_API float sync_get_peak_value(sync_t *q);
/* Gets the last input signal energy estimation value */
LIBLTE_API float sync_get_input_energy(sync_t *q);
/* Choose SSS detection algorithm */
LIBLTE_API void sync_set_sss_algorithm(sync_t *q,
sss_alg_t alg);
/* Sets PSS exponential averaging alpha weight */
LIBLTE_API void sync_set_em_alpha(sync_t *q,
float alpha);
/* Sets the N_id_2 to search for */
LIBLTE_API int sync_set_N_id_2(sync_t *q,
@ -122,19 +138,20 @@ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
/* Sets the CP length estimation (must do it if disabled) */
LIBLTE_API void sync_set_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables energy normalization every frame. If disabled, uses the mean */
LIBLTE_API void sync_normalize_en(sync_t *q,
bool enable);
/* Enables/Disables SSS detection */
LIBLTE_API void sync_sss_en(sync_t *q,
bool enabled);
LIBLTE_API bool sync_sss_detected(sync_t *q);
LIBLTE_API bool sync_sss_is_en(sync_t *q);
/* Enables/Disables CP detection */
LIBLTE_API void sync_cp_en(sync_t *q,
bool enabled);
LIBLTE_API void sync_correct_cfo(sync_t *q,
bool enabled);
#endif // SYNC_

@ -0,0 +1,119 @@
/**
*
* \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_CELLSEARCH_
#define UE_CELLSEARCH_
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/ue/ue_mib.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
/************************************************************
*
* This object is a wrapper to the ue_sync object. It receives
* several synchronized frames and obtains the most common cell_id
* and cp length.
*
* The I/O stream device sampling frequency must be set to 1.92 MHz (CS_SAMP_FREQ constant)
* before calling to ue_cell_search_scan() functions.
*
************************************************************/
/**
* TODO: Check also peak offset
*/
#define CS_DEFAULT_MAXFRAMES_TOTAL 500
#define CS_DEFAULT_MAXFRAMES_DETECTED 50
#define CS_DEFAULT_NOFFRAMES_TOTAL 50
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
#define CS_NOF_PRB 6
#define CS_SAMP_FREQ 1920000.0
typedef struct LIBLTE_API {
uint32_t cell_id;
lte_cp_t cp;
float peak;
float mode;
float psr;
} ue_cell_search_result_t;
typedef struct LIBLTE_API {
ue_sync_t ue_sync;
uint32_t max_frames;
uint32_t nof_frames_to_scan; // number of 5 ms frames to scan
float detect_threshold; // early-stops scan if mean PSR above this threshold
uint32_t *mode_ntimes;
uint8_t *mode_counted;
ue_cell_search_result_t *candidates;
} ue_cell_search_t;
LIBLTE_API int ue_cell_search_init(ue_cell_search_t *q,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API int ue_cell_search_init_max(ue_cell_search_t *q,
uint32_t max_frames_total,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API void ue_cell_search_free(ue_cell_search_t *q);
LIBLTE_API int ue_cell_search_scan_N_id_2(ue_cell_search_t *q,
uint32_t N_id_2,
ue_cell_search_result_t *found_cell);
LIBLTE_API int ue_cell_search_scan(ue_cell_search_t * q,
ue_cell_search_result_t found_cells[3],
uint32_t *max_N_id_2);
LIBLTE_API int ue_cell_search_set_nof_frames_to_scan(ue_cell_search_t *q,
uint32_t nof_frames);
LIBLTE_API void ue_cell_search_set_threshold(ue_cell_search_t *q,
float threshold);
#endif // SYNC_FRAME_

@ -1,130 +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 UE_CELLSEARCH_
#define UE_CELLSEARCH_
#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 scans a signal for LTE cells using the known PSS
* and SSS sequences.
*
* The function ue_celldetect_scan() shall be called multiple times,
* each passing a number of samples multiple of 4800, sampled at 960 KHz
* (that is, 5 ms of samples).
*
* The function returns 0 until a signal is found nof_frames_detected times or
* after nof_frames_total with no signal detected.
*
* See ue_cell_detect.c for an example.
*
************************************************************/
/**
* TODO: Check also peak offset
*/
#define CS_DEFAULT_MAXFRAMES_TOTAL 500
#define CS_DEFAULT_MAXFRAMES_DETECTED 50
#define CS_DEFAULT_NOFFRAMES_TOTAL 100
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
#define CS_FIND_THRESHOLD 0.6
#define CS_FRAME_UNALIGNED -3
#define CS_CELL_DETECTED 2
#define CS_CELL_NOT_DETECTED 3
typedef struct LIBLTE_API {
uint32_t cell_id;
lte_cp_t cp;
float peak;
uint32_t mode;
} ue_celldetect_result_t;
typedef struct LIBLTE_API {
sync_t sfind;
uint32_t max_frames_total;
uint32_t max_frames_detected;
uint32_t nof_frames_total;
uint32_t nof_frames_detected;
uint32_t current_nof_detected;
uint32_t current_nof_total;
uint32_t *mode_ntimes;
char *mode_counted;
ue_celldetect_result_t *candidates;
} ue_celldetect_t;
LIBLTE_API int ue_celldetect_init(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_init_max(ue_celldetect_t *q,
uint32_t max_frames_total,
uint32_t max_frames_detected);
LIBLTE_API void ue_celldetect_free(ue_celldetect_t *q);
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q,
cf_t *signal,
uint32_t nsamples,
ue_celldetect_result_t *found_cell,
uint32_t N_id_2);
LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q,
uint32_t nof_frames);
LIBLTE_API int ue_celldetect_set_nof_frames_detected(ue_celldetect_t *q,
uint32_t nof_frames);
LIBLTE_API void ue_celldetect_set_threshold(ue_celldetect_t *q,
float threshold);
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
#endif // SYNC_FRAME_

@ -36,7 +36,7 @@
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/common/fft.h"
#include "liblte/phy/common/phy_common.h"
@ -64,7 +64,7 @@ typedef struct LIBLTE_API {
pdsch_harq_t harq_process[NOF_HARQ_PROCESSES];
regs_t regs;
lte_fft_t fft;
chest_t chest;
chest_dl_t chest;
lte_cell_t cell;
@ -73,27 +73,33 @@ typedef struct LIBLTE_API {
uint64_t pkt_errors;
uint64_t pkts_total;
uint64_t nof_trials;
uint32_t sfn;
bool pbch_decoded;
uint64_t nof_pdcch_detected;
uint16_t user_rnti;
uint16_t current_rnti;
}ue_dl_t;
/* This function shall be called just after the initial synchronization */
LIBLTE_API int ue_dl_init(ue_dl_t *q,
lte_cell_t cell,
phich_resources_t phich_resources,
phich_length_t phich_length,
uint16_t user_rnti);
LIBLTE_API void ue_dl_free(ue_dl_t *q);
LIBLTE_API int ue_dl_decode(ue_dl_t * q,
cf_t *sf_buffer,
char *data,
cf_t *input,
uint8_t *data,
uint32_t sf_idx);
LIBLTE_API int ue_dl_decode_sib(ue_dl_t * q,
cf_t *input,
uint8_t * data,
uint32_t sf_idx,
uint32_t rvidx);
LIBLTE_API void ue_dl_reset(ue_dl_t *q);
LIBLTE_API void ue_dl_set_rnti(ue_dl_t *q,
uint16_t rnti);
#endif

@ -49,56 +49,73 @@
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
#define MIB_NOF_PORTS 2
#define MIB_FRAME_SIZE 9600
#define MIB_MAX_PORTS 4
#define MIB_NOF_PRB 6
#define MIB_FRAME_UNALIGNED -3
#define MIB_FOUND 1
#define MIB_NOTFOUND 0
typedef struct LIBLTE_API {
sync_t sfind;
uint32_t cell_id;
cf_t *slot1_symbols;
cf_t *ce[MIB_NOF_PORTS];
cf_t *sf_symbols;
cf_t *ce[MIB_MAX_PORTS];
lte_fft_t fft;
chest_t chest;
chest_dl_t chest;
pbch_t pbch;
uint8_t bch_payload[BCH_PAYLOAD_LEN];
uint32_t nof_tx_ports;
uint32_t sfn_offset;
uint32_t frame_cnt;
uint32_t last_frame_trial;
} ue_mib_t;
LIBLTE_API int ue_mib_init(ue_mib_t *q,
uint32_t cell_id,
lte_cp_t cp);
lte_cell_t cell);
LIBLTE_API void ue_mib_free(ue_mib_t *q);
LIBLTE_API void ue_mib_reset(ue_mib_t * q);
LIBLTE_API int ue_mib_decode(ue_mib_t * q,
cf_t *signal,
uint32_t nsamples,
pbch_mib_t *mib);
cf_t *input,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports,
uint32_t *sfn_offset);
LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q,
float threshold);
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
/* This interface uses ue_mib and ue_sync to first get synchronized subframes
* and then decode MIB
*/
typedef struct {
ue_mib_t ue_mib;
ue_sync_t ue_sync;
} ue_mib_sync_t;
LIBLTE_API int ue_mib_sync_init(ue_mib_sync_t *q,
uint32_t cell_id,
lte_cp_t cp,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API void ue_mib_sync_free(ue_mib_sync_t *q);
LIBLTE_API void ue_mib_sync_reset(ue_mib_sync_t * q);
LIBLTE_API int ue_mib_sync_decode(ue_mib_sync_t * q,
uint32_t max_frames_timeout,
uint8_t bch_payload[BCH_PAYLOAD_LEN],
uint32_t *nof_tx_ports,
uint32_t *sfn_offset);

@ -33,7 +33,7 @@
#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/ch_estimation/chest_dl.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
@ -53,8 +53,7 @@
typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t;
#define TRACK_MAX_LOST 10
#define MEASURE_EXEC_TIME
//#define MEASURE_EXEC_TIME
typedef struct LIBLTE_API {
sync_t sfind;
@ -67,6 +66,13 @@ typedef struct LIBLTE_API {
cf_t *input_buffer;
uint32_t frame_len;
uint32_t fft_size;
uint32_t nof_recv_sf; // Number of subframes received each call to ue_sync_get_buffer
uint32_t nof_avg_find_frames;
uint32_t frame_find_cnt;
uint32_t sf_len;
/* These count half frames (5ms) */
uint64_t frame_ok_cnt;
uint32_t frame_no_cnt;
@ -78,14 +84,12 @@ typedef struct LIBLTE_API {
lte_cell_t cell;
uint32_t sf_idx;
cfo_t cfocorr;
float cur_cfo;
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
@ -99,11 +103,16 @@ LIBLTE_API int ue_sync_init(ue_sync_t *q,
LIBLTE_API void ue_sync_free(ue_sync_t *q);
LIBLTE_API uint32_t ue_sync_sf_len(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_set_N_id_2(ue_sync_t *q,
uint32_t N_id_2);
LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q,
bool enabled);

@ -34,10 +34,29 @@
#include "liblte/config.h"
LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits);
LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits);
LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits);
LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits);
LIBLTE_API void bit_pack_vector(uint8_t *bit_unpacked,
uint8_t *bits_packed,
int nof_bits);
LIBLTE_API void bit_unpack_vector(uint8_t *bits_packed,
uint8_t *bit_unpacked,
int nof_bits);
LIBLTE_API uint32_t bit_unpack(uint8_t **bits,
int nof_bits);
LIBLTE_API void bit_pack(uint32_t value,
uint8_t **bits,
int nof_bits);
LIBLTE_API void bit_fprint(FILE *stream,
uint8_t *bits,
int nof_bits);
LIBLTE_API uint32_t bit_diff(uint8_t *x,
uint8_t *y,
int nbits);
LIBLTE_API uint32_t bit_count(uint32_t n);
#endif // BIT_

@ -64,4 +64,16 @@ LIBLTE_API uint32_t conv_cc(cf_t *input,
uint32_t input_len,
uint32_t filter_len);
LIBLTE_API uint32_t conv_same_cf(cf_t *input,
float *filter,
cf_t *output,
uint32_t input_len,
uint32_t filter_len);
LIBLTE_API uint32_t conv_same_cc(cf_t *input,
cf_t *filter,
cf_t *output,
uint32_t input_len,
uint32_t filter_len);
#endif // CONVOLUTION_H_

@ -30,8 +30,13 @@
#define PACK_
#include "liblte/config.h"
#include <stdint.h>
LIBLTE_API unsigned int unpack_bits(char **bits, int nof_bits);
LIBLTE_API void pack_bits(unsigned int value, char **bits, int nof_bits);
LIBLTE_API uint32_t unpack_bits(uint8_t **bits,
int nof_bits);
LIBLTE_API void pack_bits(uint32_t value,
uint8_t **bits,
int nof_bits);
#endif // PACK_

@ -35,11 +35,15 @@
typedef _Complex float cf_t;
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
// Cumulative moving average
#define VEC_CMA(data, average, n) ((data) + ((data) - (average)) / ((n)+1))
#define VEC_CMA(data, average, n) ((average) + ((data) - (average)) / ((n)+1))
// Exponential moving average
#define VEC_EMA(data, average, alpha) ((factor)*(data)+(1-alpha)*(average))
#define VEC_EMA(data, average, alpha) (average)==0?(data):((alpha)*(data)+(1-alpha)*(average))
/** Return the sum of all the elements */
LIBLTE_API int vec_acc_ii(int *x, uint32_t len);
@ -53,23 +57,31 @@ 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, 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_b(FILE *stream, uint8_t *x, uint32_t len);
LIBLTE_API void vec_fprint_byte(FILE *stream, uint8_t *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);
LIBLTE_API void vec_fprint_hex(FILE *stream, uint8_t *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 *x, char *y, char *z, uint32_t len);
LIBLTE_API void vec_sum_ch(uint8_t *x, uint8_t *y, char *z, uint32_t len);
LIBLTE_API void vec_sum_fff(float *x, float *y, float *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);
LIBLTE_API void vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* Square distance */
LIBLTE_API void vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints);
/* scalar addition */
LIBLTE_API void vec_sc_add_fff(float *x, float h, float *z, uint32_t len);
LIBLTE_API void vec_sc_add_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
LIBLTE_API void vec_sc_add_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
/* scalar product */
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);
@ -80,6 +92,8 @@ 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);
LIBLTE_API void vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len);
LIBLTE_API void vec_interleave_cf(float *real, float *imag, cf_t *x, uint32_t len);
/* vector product (element-wise) */
LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
@ -90,12 +104,15 @@ LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len);
LIBLTE_API void vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* Dot-product */
LIBLTE_API cf_t vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len);
LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len);
LIBLTE_API cf_t vec_dot_prod_conj_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, uint32_t len);
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, float *z_real, float *z_imag, uint32_t len);
void vec_div_cfc(cf_t *x, float *y, cf_t *z, float *z_real, float *z_imag, uint32_t len);
LIBLTE_API void vec_div_fff(float *x, float *y, float *z, uint32_t len);
/* conjugate */
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len);
@ -107,11 +124,12 @@ LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len);
LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len);
LIBLTE_API uint32_t vec_max_abs_ci(cf_t *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, uint32_t len);
/* quantify vector of floats and convert to uint8_t */
LIBLTE_API void vec_quant_fuc(float *in, uint8_t *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, uint32_t len);
LIBLTE_API void vec_abs_square_cf(cf_t *x, float *abs_square, uint32_t len);
/* argument of each vector element */
LIBLTE_API void vec_arg_cf(cf_t *x, float *arg, uint32_t len);

@ -64,7 +64,6 @@ ELSE(VOLK_FOUND)
MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.")
ENDIF(VOLK_FOUND)
########################################################################
# Recurse subdirectories and find all directories with a CMakeLists.txt file in it
########################################################################

@ -1,503 +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 <strings.h>
#include <string.h>
#include <complex.h>
#include <math.h>
#include "liblte/phy/ch_estimation/chest.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);
chest_ce_fprint(q, stream, nslot, port_id);
}
/* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports
* used during the call to chest_init().
*/
int chest_set_nof_ports(chest_t *q, uint32_t nof_ports) {
if (nof_ports < q->nof_ports) {
q->nof_ports = nof_ports;
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "refs%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].symbol,
__imag__ q->refsignal[port_id][nslot].refs[i].symbol);
}
fprintf(stream, "];\n");
}
void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "recvsig%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].recv_symbol[i],
__imag__ q->refsignal[port_id][nslot].recv_symbol[i]);
}
fprintf(stream, "];\n");
}
void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "mag%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i]));
}
fprintf(stream, "];\nphase%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i],
__real__ q->refsignal[port_id][nslot].ch_est[i]));
}
fprintf(stream, "];\n");
}
float chest_rsrp(chest_t *q, uint32_t nslot, uint32_t port_id) {
int nof_refs = q->refsignal[port_id][nslot].nof_refs;
cf_t *ch_est = q->refsignal[port_id][nslot].ch_est;
return crealf(vec_dot_prod_conj_ccc(ch_est, ch_est, nof_refs))/nof_refs;
}
float chest_rsrp_sf(chest_t *q, uint32_t sf_idx) {
int n,p;
float rsrp=0;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<2;n++) {
rsrp+=chest_rsrp(q, 2*sf_idx+n, p)/(2*q->nof_ports);
}
}
return rsrp;
}
float chest_rssi(chest_t *q, cf_t *input) {
float rssi = 0;
int i;
int l[2];
if (q->nof_symbols == CPNORM_NSYMB) {
l[0] = 0; l[1] = 4;
} else {
l[0] = 0; l[1] = 3;
}
for (i=0;i<2;i++) {
cf_t *tmp = &input[l[i]*q->nof_re];
rssi += crealf(vec_dot_prod_conj_ccc(tmp, tmp, q->nof_re));
}
return rssi;
}
float chest_rssi_sf(chest_t *q, cf_t *input) {
int n;
int slotsz = q->nof_symbols*q->nof_re;
float rssi=0;
for (n=0;n<2;n++) {
rssi += chest_rssi(q, &input[n*slotsz]);
}
return rssi;
}
float chest_rsrq(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id) {
return (q->nof_re/RE_X_RB) * chest_rsrp(q, nslot, port_id) / chest_rssi(q, input);
}
float chest_rsrq_sf(chest_t *q, cf_t *input, uint32_t sf_idx) {
return (4*q->nof_ports*q->nof_re/RE_X_RB) * chest_rsrp_sf(q, sf_idx) / chest_rssi_sf(q, input);
}
int chest_measure_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) {
int fidx, tidx;
cf_t known_ref, channel_ref;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
nslot < NSLOTS_X_FRAME &&
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
known_ref = q->refsignal[port_id][nslot].refs[nref].symbol;
channel_ref = input[tidx * q->nof_re + fidx];
q->refsignal[port_id][nslot].recv_symbol[nref] = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx,
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,
cargf(channel_ref/known_ref)/M_PI);
/* FIXME: compare with threshold */
if (channel_ref != 0) {
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
} else {
q->refsignal[port_id][nslot].ch_est[nref] = 1e-6;
}
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
void chest_measure_slot_port(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id)
{
int i;
refsignal_t *r = &q->refsignal[port_id][nslot];
DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n",
nslot, port_id, r->nof_refs);
for (i=0;i<r->nof_refs;i++) {
chest_measure_ref(q, input, nslot, port_id, i);
}
}
void chest_measure_slot(chest_t *q, cf_t *input, uint32_t nslot) {
int p;
for (p=0;p<q->nof_ports;p++) {
chest_measure_slot_port(q, input, nslot, p);
}
}
void chest_measure_sf(chest_t *q, cf_t *input, uint32_t sf_idx) {
int p, n, slotsz;
slotsz = q->nof_symbols*q->nof_re;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<2;n++) {
chest_measure_slot_port(q, &input[n*slotsz], 2*sf_idx+n, p);
}
}
}
/* Computes channel estimates for each reference in a slot and port.
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce
*/
int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id)
{
uint32_t i, j;
cf_t x[2], y[MAX_NSYMB];
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
nslot < NSLOTS_X_FRAME &&
port_id < q->nof_ports)
{
if (q->refsignal[port_id][nslot].nsymbols <= 2) {
refsignal_t *r = &q->refsignal[port_id][nslot];
chest_measure_slot_port(q, input, nslot, port_id);
/* 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++) {
if (r->nsymbols > 1) {
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];
}
}
for (j=0;j<q->nof_symbols;j++) {
ce[j * q->nof_re + i] = y[j];
}
}
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
/* Computes channel estimates for each reference in a subframe and port id.
*/
int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) {
int n, slotsz, ret;
slotsz = q->nof_symbols*q->nof_re;
for (n=0;n<2;n++) {
ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return LIBLTE_SUCCESS;
}
/* Computes channel estimates for each reference in a slot for all ports.
*/
int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) {
int p, ret;
for (p=0;p<q->nof_ports;p++) {
ret = chest_ce_slot_port(q, input, ce[p], nslot, p);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return LIBLTE_SUCCESS;
}
/* Computes channel estimates for each reference in a subframe for all ports.
*/
int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) {
int p, n, slotsz, ret;
slotsz = q->nof_symbols*q->nof_re;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<2;n++) {
ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
}
return LIBLTE_SUCCESS;
}
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 &&
nof_ports <= MAX_PORTS)
{
bzero(q, sizeof(chest_t));
q->nof_ports = nof_ports;
q->nof_symbols = nof_symbols;
q->nof_re = nof_re;
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, q->nof_re, nof_ports);
ret = LIBLTE_SUCCESS;
}
return ret;
}
void chest_free(chest_t *q) {
int p, n;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<NSLOTS_X_FRAME;n++) {
refsignal_free(&q->refsignal[p][n]);
}
}
#ifdef VOLK_INTERP
for (p=0;p<MAX_PORTS;p++) {
interp_free(&q->interp_freq[p]);
interp_free(&q->interp_time[p]);
}
#endif
bzero(q, sizeof(chest_t));
}
/* Fills l[2] with the symbols in the slot nslot that contain references.
* returns the number of symbols with references (in the slot)
*/
int chest_ref_get_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) {
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/*********************************************************************
*
* Downlink Channel estimator
*
*********************************************************************/
int chest_init_LTEDL(chest_t *q, lte_cell_t cell) {
int ret;
ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports);
if (ret != LIBLTE_SUCCESS) {
return ret;
} else {
return chest_ref_set_LTEDL(q, cell);
}
}
int chest_ref_set_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell);
#ifdef VOLK_INTERP
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]);
}
}
}
#endif
}
return ret;
}
int chest_ref_set_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
int p, ret;
for (p=0;p<q->nof_ports;p++) {
ret = chest_ref_set_LTEDL_slot_port(q, nslot, p, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return LIBLTE_SUCCESS;
}
int chest_ref_set_LTEDL(chest_t *q, lte_cell_t cell) {
int n, ret;
for (n=0;n<NSLOTS_X_FRAME;n++) {
ret = chest_ref_set_LTEDL_slot(q, n, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return LIBLTE_SUCCESS;
}
/*********************************************************************
*
* TODO: Uplink Channel estimator
*
*
*********************************************************************/
/** High-level API
*/
int chest_initialize(chest_hl* h) {
lte_cell_t cell;
if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
}
if (!h->init.nof_prb) {
h->init.nof_prb = 6;
}
cell.id = h->init.cell_id;
cell.nof_ports = h->init.nof_ports;
cell.nof_prb = h->init.nof_prb;
cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT;
if (chest_init_LTEDL(&h->obj, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
return 0;
}
/** This function must be called in an subframe basis (1ms) for LTE */
int chest_work(chest_hl* hl) {
chest_t *q = &hl->obj;
chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx);
return 0;
}
int chest_stop(chest_hl* hl) {
chest_free(&hl->obj);
return 0;
}

@ -0,0 +1,385 @@
/**
*
* \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 <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <complex.h>
#include <math.h>
#include "liblte/config.h"
#include "liblte/phy/ch_estimation/chest_dl.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/convolution.h"
#define CHEST_RS_AVERAGE_TIME 2
#define CHEST_RS_AVERAGE_FREQ 3
/** 3GPP LTE Downlink channel estimator and equalizer.
* Estimates the channel in the resource elements transmitting references and interpolates for the rest
* of the resource grid.
*
* The equalizer uses the channel estimates to produce an estimation of the transmitted symbol.
*
* This object depends on the refsignal_t object for creating the LTE CSR signal.
*/
int chest_dl_init(chest_dl_t *q, lte_cell_t cell)
{
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
lte_cell_isvalid(&cell))
{
bzero(q, sizeof(chest_dl_t));
ret = refsignal_cs_generate(&q->csr_signal, cell);
if (ret != LIBLTE_SUCCESS) {
fprintf(stderr, "Error initializing CSR signal (%d)\n",ret);
goto clean_exit;
}
q->tmp_freqavg = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
if (!q->tmp_freqavg) {
perror("malloc");
goto clean_exit;
}
q->tmp_noise = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
if (!q->tmp_noise) {
perror("malloc");
goto clean_exit;
}
for (int i=0;i<CHEST_MAX_FILTER_TIME_LEN;i++) {
q->tmp_timeavg[i] = vec_malloc(sizeof(cf_t) * 2*cell.nof_prb);
if (!q->tmp_timeavg[i]) {
perror("malloc");
goto clean_exit;
}
bzero(q->tmp_timeavg[i], sizeof(cf_t) * 2*cell.nof_prb);
}
for (int i=0;i<cell.nof_ports;i++) {
q->pilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
if (!q->pilot_estimates[i]) {
perror("malloc");
goto clean_exit;
}
q->pilot_estimates_average[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
if (!q->pilot_estimates_average[i]) {
perror("malloc");
goto clean_exit;
}
q->pilot_recv_signal[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(cell.nof_prb, i));
if (!q->pilot_recv_signal[i]) {
perror("malloc");
goto clean_exit;
}
}
if (interp_linear_vector_init(&q->interp_linvec, RE_X_RB*cell.nof_prb)) {
fprintf(stderr, "Error initializing vector interpolator\n");
goto clean_exit;
}
if (interp_linear_init(&q->interp_lin, 2*cell.nof_prb, RE_X_RB/2)) {
fprintf(stderr, "Error initializing interpolator\n");
goto clean_exit;
}
/* Set default time/freq filters */
//float f[3]={0.1, 0.8, 0.1};
//chest_dl_set_filter_freq(q, f, 3);
float f[5]={0.05, 0.15, 0.6, 0.15, 0.05};
chest_dl_set_filter_freq(q, f, 5);
float t[2]={0.1, 0.9};
chest_dl_set_filter_time(q, t, 2);
q->cell = cell;
}
ret = LIBLTE_SUCCESS;
clean_exit:
if (ret != LIBLTE_SUCCESS) {
chest_dl_free(q);
}
return ret;
}
void chest_dl_free(chest_dl_t *q)
{
refsignal_cs_free(&q->csr_signal);
if (q->tmp_freqavg) {
free(q->tmp_freqavg);
}
if (q->tmp_noise) {
free(q->tmp_noise);
}
for (int i=0;i<CHEST_MAX_FILTER_TIME_LEN;i++) {
if (q->tmp_timeavg[i]) {
free(q->tmp_timeavg[i]);
}
}
interp_linear_vector_free(&q->interp_linvec);
interp_linear_free(&q->interp_lin);
for (int i=0;i<MAX_PORTS;i++) {
if (q->pilot_estimates[i]) {
free(q->pilot_estimates[i]);
}
if (q->pilot_estimates_average[i]) {
free(q->pilot_estimates_average[i]);
}
if (q->pilot_recv_signal[i]) {
free(q->pilot_recv_signal[i]);
}
}
bzero(q, sizeof(chest_dl_t));
}
int chest_dl_set_filter_freq(chest_dl_t *q, float *filter, uint32_t filter_len) {
if (filter_len <= CHEST_MAX_FILTER_FREQ_LEN) {
q->filter_freq_len = filter_len;
for (int i=0;i<filter_len;i++) {
q->filter_freq[i] = filter[i];
}
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR;
}
}
int chest_dl_set_filter_time(chest_dl_t *q, float *filter, uint32_t filter_len) {
if (filter_len <= CHEST_MAX_FILTER_TIME_LEN) {
q->filter_time_len = filter_len;
for (int i=0;i<filter_len;i++) {
q->filter_time[i] = filter[i];
}
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR;
}
}
static float estimate_noise_port(chest_dl_t *q, uint32_t port_id, cf_t *avg_pilots) {
/* Use difference between averaged and noisy LS pilot estimates */
vec_sub_ccc(avg_pilots, q->pilot_estimates[port_id],
q->tmp_noise, REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
return vec_avg_power_cf(q->tmp_noise, REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
}
#define pilot_est(idx) q->pilot_estimates[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
#define pilot_avg(idx) q->pilot_estimates_average[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
#define pilot_tmp(idx) q->tmp_freqavg[REFSIGNAL_PILOT_IDX(idx,l,q->cell)]
static void average_pilots(chest_dl_t *q, uint32_t port_id)
{
int nref=2*q->cell.nof_prb;
uint32_t l, i;
/* For each symbol with pilots in a slot */
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
if (q->filter_freq_len > 0) {
/* Filter pilot estimates in frequency */
conv_same_cf(&pilot_est(0), q->filter_freq, &pilot_tmp(0), nref, q->filter_freq_len);
/* Adjust extremes using linear interpolation */
pilot_tmp(0) += interp_linear_onesample(pilot_est(1), pilot_est(0))
* q->filter_freq[q->filter_freq_len/2-1];
pilot_tmp(nref-1) += interp_linear_onesample(pilot_est(nref-2), pilot_est(nref-1))
* q->filter_freq[q->filter_freq_len/2+1];
} else {
memcpy(&pilot_tmp(0), &pilot_est(0), nref * sizeof(cf_t));
}
}
/* Compute noise estimation before time averaging.
* FIXME: Apparently the noise estimation performance is better with frequency averaging only
*/
q->noise_estimate[port_id] = estimate_noise_port(q, port_id, q->tmp_freqavg);
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
/* Filter in time domain. */
if (q->filter_time_len > 0) {
/* Move last symbols */
for (i=0;i<q->filter_time_len-1;i++) {
memcpy(q->tmp_timeavg[i], q->tmp_timeavg[i+1], nref*sizeof(cf_t));
}
/* Put last symbol to buffer */
memcpy(q->tmp_timeavg[i], &pilot_tmp(0), nref*sizeof(cf_t));
/* Multiply all symbols by filter and add them */
bzero(&pilot_avg(0), nref * sizeof(cf_t));
for (i=0;i<q->filter_time_len;i++) {
vec_sc_prod_cfc(q->tmp_timeavg[i], q->filter_time[i], q->tmp_timeavg[i], nref);
vec_sum_ccc(q->tmp_timeavg[i], &pilot_avg(0), &pilot_avg(0), nref);
}
} else {
memcpy(&pilot_avg(0), &pilot_tmp(0), nref * sizeof(cf_t));
}
}
}
#define cesymb(i) ce[RE_IDX(q->cell.nof_prb,i,0)]
static void interpolate_pilots(chest_dl_t *q, cf_t *ce, uint32_t port_id)
{
/* interpolate the symbols with references in the freq domain */
uint32_t l;
uint32_t nsymbols = refsignal_cs_nof_symbols(port_id);
/* Interpolate in the frequency domain */
for (l=0;l<nsymbols;l++) {
uint32_t fidx_offset = refsignal_fidx(q->cell, l, port_id, 0);
interp_linear_offset(&q->interp_lin, &pilot_avg(0),
&ce[refsignal_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * RE_X_RB],
fidx_offset, RE_X_RB/2-fidx_offset);
}
/* Now interpolate in the time domain between symbols */
if (CP_ISNORM(q->cell.cp)) {
if (nsymbols == 4) {
interp_linear_vector(&q->interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 3);
interp_linear_vector(&q->interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 2);
interp_linear_vector(&q->interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 3);
interp_linear_vector(&q->interp_linvec, &cesymb(7), &cesymb(11), &cesymb(12), 2);
} else {
interp_linear_vector(&q->interp_linvec, &cesymb(8), &cesymb(1), &cesymb(0), 1);
interp_linear_vector(&q->interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 6);
interp_linear_vector(&q->interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 5);
}
} else {
if (nsymbols == 4) {
interp_linear_vector(&q->interp_linvec, &cesymb(0), &cesymb(3), &cesymb(1), 2);
interp_linear_vector(&q->interp_linvec, &cesymb(3), &cesymb(6), &cesymb(4), 2);
interp_linear_vector(&q->interp_linvec, &cesymb(6), &cesymb(9), &cesymb(7), 2);
interp_linear_vector(&q->interp_linvec, &cesymb(6), &cesymb(9), &cesymb(9), 2);
} else {
interp_linear_vector(&q->interp_linvec, &cesymb(7), &cesymb(1), &cesymb(0), 1);
interp_linear_vector(&q->interp_linvec, &cesymb(1), &cesymb(7), &cesymb(2), 5);
interp_linear_vector(&q->interp_linvec, &cesymb(1), &cesymb(7), &cesymb(8), 4);
}
}
}
float chest_dl_rssi(chest_dl_t *q, cf_t *input, uint32_t port_id) {
uint32_t l;
float rssi = 0;
uint32_t nsymbols = refsignal_cs_nof_symbols(port_id);
for (l=0;l<nsymbols;l++) {
cf_t *tmp = &input[refsignal_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * RE_X_RB];
rssi += vec_dot_prod_conj_ccc(tmp,tmp,q->cell.nof_prb * RE_X_RB);
}
return rssi/nsymbols;
}
float chest_dl_rsrp(chest_dl_t *q, uint32_t port_id) {
#ifdef RSRP_FROM_ESTIMATES
return vec_avg_power_cf(q->pilot_estimates[port_id],
REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
#else
return vec_avg_power_cf(q->pilot_estimates_average[port_id],
REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
#endif
}
int chest_dl_estimate_port(chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
{
/* Get references from the input signal */
refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal[port_id]);
/* Compute RSRP for the references in this port */
q->rsrp[port_id] = chest_dl_rsrp(q, port_id);
if (port_id == 0) {
/* compute rssi only for port 0 */
q->rssi[port_id] = chest_dl_rssi(q, input, port_id);
}
/* Use the known CSR signal to compute Least-squares estimates */
vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx],
q->pilot_estimates[port_id], REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
/* Average pilot estimates */
average_pilots(q, port_id);
/* Interpolate to create channel estimates for all resource grid */
if (ce != NULL) {
interpolate_pilots(q, ce, port_id);
}
return 0;
}
int chest_dl_estimate(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx)
{
uint32_t port_id;
for (port_id=0;port_id<q->cell.nof_ports;port_id++) {
chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id);
}
return LIBLTE_SUCCESS;
}
float chest_dl_get_noise_estimate(chest_dl_t *q) {
return vec_acc_ff(q->noise_estimate, q->cell.nof_ports)/q->cell.nof_ports;
}
float chest_dl_get_snr(chest_dl_t *q) {
// Uses RSRP as an estimation of the useful signal power
return chest_dl_get_rsrp(q)/chest_dl_get_noise_estimate(q);
}
float chest_dl_get_rssi(chest_dl_t *q) {
return 4*q->rssi[0]/q->cell.nof_prb/RE_X_RB;
}
/* q->rssi[0] is the average power in all RE in all symbol containing references for port 0 . q->rssi[0]/q->cell.nof_prb is the average power per PRB
* q->rsrp[0] is the average power of RE containing references only (for port 0).
*/
float chest_dl_get_rsrq(chest_dl_t *q) {
return q->cell.nof_prb*q->rsrp[0] / q->rssi[0];
}
float chest_dl_get_rsrp(chest_dl_t *q) {
// return linear average from port 0 only
//return q->rsrp[0];
// return linear average from all ports
return vec_acc_ff(q->rsrp, q->cell.nof_ports)/q->cell.nof_ports;
}

@ -1,382 +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 <math.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <complex.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/common/sequence.h"
#include "ul_rs_tables.h"
#define idx(x, y) (l*nof_refs_x_symbol+i)
int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id)
{
int v = -1;
switch (port_id) {
case 0:
if (symbol_id == 0) {
v = 0;
} else {
v = 3;
}
break;
case 1:
if (symbol_id == 0) {
v = 3;
} else {
v = 0;
}
break;
case 2:
v = 3 * (ns % 2);
break;
case 3:
v = 3 + 3 * (ns % 2);
break;
}
return v;
}
uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id)
{
return 6 * m + ((v + (cell_id % 6)) % 6);
}
int refsignal_put(refsignal_t * q, cf_t * slot_symbols)
{
uint32_t i;
uint32_t fidx, tidx;
if (q != NULL && slot_symbols != NULL) {
for (i = 0; i < q->nof_refs; i++) {
fidx = q->refs[i].freq_idx; // reference frequency index
tidx = q->refs[i].time_idx; // reference time index
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].symbol;
}
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/** Initializes refsignal_t object according to 3GPP 36.211 6.10.1
*
*/
int refsignal_init_LTEDL(refsignal_t * q, uint32_t port_id, uint32_t nslot,
lte_cell_t cell)
{
uint32_t c_init;
uint32_t ns, l, lp[2];
uint32_t N_cp;
uint32_t i;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
sequence_t seq;
int v;
uint32_t mp;
uint32_t nof_refs_x_symbol, nof_ref_symbols;
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) {
bzero(q, sizeof(refsignal_t));
bzero(&seq, sizeof(sequence_t));
if (CP_ISNORM(cell.cp)) {
N_cp = 1;
} else {
N_cp = 0;
}
if (port_id < 2) {
nof_ref_symbols = 2;
lp[0] = 0;
lp[1] = CP_NSYMB(cell.cp) - 3;
} else {
nof_ref_symbols = 1;
lp[0] = 1;
}
nof_refs_x_symbol = 2 * cell.nof_prb;
q->nof_refs = nof_refs_x_symbol * nof_ref_symbols;
q->nsymbols = nof_ref_symbols;
q->voffset = cell.id % 6;
q->nof_prb = cell.nof_prb;
q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols);
if (!q->symbols_ref) {
perror("malloc");
goto free_and_exit;
}
memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols);
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
if (!q->refs) {
goto free_and_exit;
}
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->ch_est) {
goto free_and_exit;
}
q->recv_symbol = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->recv_symbol) {
goto free_and_exit;
}
ns = nslot;
for (l = 0; l < nof_ref_symbols; l++) {
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1)
+ 2 * cell.id + N_cp;
ret = sequence_LTE_pr(&seq, 2 * 2 * MAX_PRB, c_init);
if (ret != LIBLTE_SUCCESS) {
goto free_and_exit;
}
v = refsignal_v(port_id, ns, lp[l]);
for (i = 0; i < nof_refs_x_symbol; i++) {
mp = i + MAX_PRB - cell.nof_prb;
/* generate signal */
__real__ q->refs[idx(l, i)].symbol =
(1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
__imag__ q->refs[idx(l, i)].symbol =
(1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
/* mapping to resource elements */
q->refs[idx(l, i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id);
q->refs[idx(l, i)].time_idx = lp[l];
}
}
ret = LIBLTE_SUCCESS;
}
free_and_exit:
if (ret != LIBLTE_ERROR_INVALID_INPUTS) {
sequence_free(&seq);
}
if (ret == LIBLTE_ERROR) {
refsignal_free(q);
}
return ret;
}
// n_drms_2 table 5.5.2.1.1-1 from 36.211
uint32_t n_drms_2[8] = { 0, 6, 3, 4, 2, 8, 10, 9 };
// n_drms_1 table 5.5.2.1.1-2 from 36.211
uint32_t n_drms_1[8] = { 0, 2, 3, 4, 6, 8, 9, 10 };
/* Generation of the reference signal sequence according to Section 5.5.1 of 36.211 */
int rs_sequence(ref_t * refs, uint32_t len, float alpha, uint32_t ns, uint32_t cell_id,
refsignal_ul_cfg_t * cfg)
{
uint32_t i;
// Calculate u and v
uint32_t u, v;
uint32_t f_ss = (((cell_id % 30) + cfg->delta_ss) % 30);
if (cfg->group_hopping_en) {
sequence_t seq;
sequence_LTE_pr(&seq, cell_id / 30, 160);
uint32_t f_gh = 0;
for (i = 0; i < 8; i++) {
f_gh += seq.c[8 * ns + i] << i;
}
sequence_free(&seq);
u = ((f_gh%30) + f_ss) % 30;
} else {
u = f_ss % 30;
}
if (len < 6 * RE_X_RB) {
v = 0;
} else {
if (!cfg->group_hopping_en && cfg->sequence_hopping_en) {
sequence_t seq;
sequence_LTE_pr(&seq, ((cell_id / 30) << 5) + f_ss, 20);
v = seq.c[ns];
sequence_free(&seq);
} else {
v = 0;
}
}
if (len >= 3 * RE_X_RB) {
uint32_t n_sz;
uint32_t q;
float q_hat;
/* get largest prime n_zc<len */
for (i = NOF_PRIME_NUMBERS - 1; i > 0; i--) {
if (prime_numbers[i] < len) {
n_sz = prime_numbers[i];
break;
}
}
q_hat = (float) n_sz *(u + 1) / 31;
if ((((uint32_t) (2 * q_hat)) % 2) == 0) {
q = (uint32_t) (q_hat + 0.5) + v;
} else {
q = (uint32_t) (q_hat + 0.5) - v;
}
cf_t *x_q = malloc(sizeof(cf_t) * n_sz);
if (!x_q) {
perror("malloc");
return LIBLTE_ERROR;
}
for (i = 0; i < n_sz; i++) {
x_q[i] =
cexpf(-I * M_PI * (float) q * (float) i * ((float) i + 1) / n_sz);
}
for (i = 0; i < len; i++) {
refs[i].symbol = cfg->beta * cexpf(I * alpha * i) * x_q[i % n_sz];
}
free(x_q);
} else {
if (len == RE_X_RB) {
for (i = 0; i < len; i++) {
refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_12[u][i] * M_PI / 4 + alpha * i));
}
} else {
for (i = 0; i < len; i++) {
refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_24[u][i] * M_PI / 4 + alpha * i));
}
}
}
return LIBLTE_SUCCESS;
}
/** Initializes refsignal_t object according to 3GPP 36.211 5.5.2
*
*/
int refsignal_init_LTEUL_drms_pusch(refsignal_t * q, uint32_t nof_prb, uint32_t prb_start,
uint32_t nslot, lte_cell_t cell, refsignal_ul_cfg_t * cfg)
{
uint32_t i;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t n_prs;
uint32_t M_sc;
float alpha;
if (q != NULL && nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) {
bzero(q, sizeof(refsignal_t));
M_sc = nof_prb * RE_X_RB;
q->nof_refs = M_sc;
q->nsymbols = 1;
q->voffset = cell.id % 6;
q->nof_prb = cell.nof_prb;
q->symbols_ref = malloc(sizeof(uint32_t) * 1);
if (!q->symbols_ref) {
perror("malloc");
goto free_and_exit;
}
if (CP_ISNORM(cell.cp)) {
q->symbols_ref[0] = 3;
} else {
q->symbols_ref[0] = 2;
}
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
if (!q->refs) {
goto free_and_exit;
}
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->ch_est) {
goto free_and_exit;
}
/* Calculate n_prs */
uint32_t c_init;
sequence_t seq;
c_init = ((cell.id / 30) << 5) + (((cell.id % 30) + cfg->delta_ss) % 30);
ret = sequence_LTE_pr(&seq, 8 * CP_NSYMB(cell.cp) * 20, c_init);
if (ret != LIBLTE_SUCCESS) {
goto free_and_exit;
}
n_prs = 0;
for (i = 0; i < 8; i++) {
n_prs += (seq.c[8 * CP_NSYMB(cell.cp) * nslot + i] << i);
}
sequence_free(&seq);
// Calculate cyclic shift alpha
uint32_t n_cs =
(n_drms_1[cfg->cyclic_shift] +
n_drms_2[cfg->cyclic_shift_for_drms] + n_prs) % 12;
alpha = 2 * M_PI * (n_cs) / 12;
if (rs_sequence(q->refs, M_sc, alpha, cell.id, nslot, cfg)) {
fprintf(stderr, "Error generating RS sequence\n");
goto free_and_exit;
}
/* mapping to resource elements */
for (i=0;i<M_sc;i++) {
q->refs[i].freq_idx = prb_start*RE_X_RB + i;
q->refs[i].time_idx = q->symbols_ref[0];
}
ret = LIBLTE_SUCCESS;
}
free_and_exit:
if (ret == LIBLTE_ERROR) {
refsignal_free(q);
}
return ret;
}
void refsignal_free(refsignal_t * q)
{
if (q->symbols_ref) {
free(q->symbols_ref);
}
if (q->refs) {
free(q->refs);
}
if (q->ch_est) {
free(q->ch_est);
}
bzero(q, sizeof(refsignal_t));
}

@ -0,0 +1,251 @@
/**
*
* \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 <math.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <complex.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/ch_estimation/refsignal_dl.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/common/sequence.h"
uint32_t refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx)
{
uint32_t v = 0;
switch (port_id) {
case 0:
if (!(ref_symbol_idx % 2)) {
v = 0;
} else {
v = 3;
}
break;
case 1:
if (!(ref_symbol_idx % 2)) {
v = 3;
} else {
v = 0;
}
break;
case 2:
if (ref_symbol_idx < 2) {
v = 0;
} else {
v = 3;
}
break;
case 3:
if (ref_symbol_idx < 2) {
v = 3;
} else {
v = 6;
}
break;
}
return v;
}
uint32_t refsignal_cs_nof_symbols(uint32_t port_id)
{
if (port_id < 2) {
return 4;
} else {
return 2;
}
}
inline uint32_t refsignal_fidx(lte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m) {
return 6*m + ((refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6);
}
inline uint32_t refsignal_nsymbol(uint32_t l, lte_cp_t cp, uint32_t port_id) {
if (port_id < 2) {
if (l % 2) {
return (l/2+1)*CP_NSYMB(cp) - 3;
} else {
return (l/2)*CP_NSYMB(cp);
}
} else {
return 1+l*CP_NSYMB(cp);
}
}
/** Allocates and precomputes the Cell-Specific Reference (CSR) signal for
* the 20 slots in a subframe
*/
int refsignal_cs_generate(refsignal_cs_t * q, lte_cell_t cell)
{
uint32_t c_init;
uint32_t i, ns, l, p;
uint32_t N_cp, mp;
sequence_t seq;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
lte_cell_isvalid(&cell))
{
ret = LIBLTE_ERROR;
bzero(q, sizeof(refsignal_cs_t));
bzero(&seq, sizeof(sequence_t));
if (sequence_init(&seq, 2 * 2 * MAX_PRB)) {
goto free_and_exit;
}
if (CP_ISNORM(cell.cp)) {
N_cp = 1;
} else {
N_cp = 0;
}
q->cell = cell;
for (p=0;p<2;p++) {
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
q->pilots[p][i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(q->cell.nof_prb, 2*p));
if (!q->pilots[p][i]) {
perror("malloc");
goto free_and_exit;
}
}
}
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
for (p=0;p<2;p++) {
uint32_t nsymbols = refsignal_cs_nof_symbols(2*p)/2;
for (l = 0; l < nsymbols; l++) {
/* Compute sequence init value */
uint32_t lp = refsignal_nsymbol(l, cell.cp, 2*p);
c_init = 1024 * (7 * (ns + 1) + lp + 1) * (2 * cell.id + 1)
+ 2 * cell.id + N_cp;
/* generate sequence for this symbol and slot */
sequence_set_LTE_pr(&seq, c_init);
/* Compute signal */
for (i = 0; i < 2*q->cell.nof_prb; i++) {
mp = i + MAX_PRB - cell.nof_prb;
/* save signal */
q->pilots[p][ns/2][REFSIGNAL_PILOT_IDX(i,(ns%2)*nsymbols+l,q->cell)] =
(1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) +
_Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
}
}
}
}
sequence_free(&seq);
ret = LIBLTE_SUCCESS;
}
free_and_exit:
if (ret == LIBLTE_ERROR) {
sequence_free(&seq);
refsignal_cs_free(q);
}
return ret;
}
/** Deallocates a refsignal_cs_t object allocated with refsignal_cs_init */
void refsignal_cs_free(refsignal_cs_t * q)
{
int i, p;
for (p=0;p<2;p++) {
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
if (q->pilots[p][i]) {
free(q->pilots[p][i]);
}
}
}
bzero(q, sizeof(refsignal_cs_t));
}
/* Maps a reference signal initialized with refsignal_cs_init() into an array of subframe symbols */
int refsignal_cs_put_sf(lte_cell_t cell, uint32_t port_id, cf_t *pilots, cf_t *sf_symbols)
{
uint32_t i, l;
uint32_t fidx;
if (lte_cell_isvalid(&cell) &&
lte_portid_isvalid(port_id) &&
pilots != NULL &&
sf_symbols != NULL)
{
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
uint32_t nsymbol = refsignal_nsymbol(l, cell.cp, port_id);
/* Compute offset frequency index */
fidx = ((refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6);
for (i = 0; i < 2*cell.nof_prb; i++) {
sf_symbols[RE_IDX(cell.nof_prb, nsymbol, fidx)] = pilots[REFSIGNAL_PILOT_IDX(i,l,cell)];
fidx += RE_X_RB/2; // 1 reference every 6 RE
}
}
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/** Copies the RE containing references from an array of subframe symbols into the csr_signal[][].
* csr_signal[0] is the signal for the first OFDM symbol containing references and csr_signal[1] is the
* second OFDM symbol containing references (symbol 4 or 3 if port_id < 2)
*/
int refsignal_cs_get_sf(lte_cell_t cell, uint32_t port_id, cf_t *sf_symbols, cf_t *pilots)
{
uint32_t i, l;
uint32_t fidx;
if (lte_cell_isvalid(&cell) &&
lte_portid_isvalid(port_id) &&
pilots != NULL &&
sf_symbols != NULL)
{
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
uint32_t nsymbol = refsignal_nsymbol(l, cell.cp, port_id);
/* Compute offset frequency index */
fidx = ((refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6);
for (i = 0; i < 2*cell.nof_prb; i++) {
pilots[REFSIGNAL_PILOT_IDX(i,l,cell)] = sf_symbols[RE_IDX(cell.nof_prb, nsymbol, fidx)];
fidx += RE_X_RB/2; // 2 references per PRB
}
}
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}

@ -0,0 +1,183 @@
#ifdef nocompile
// n_drms_2 table 5.5.2.1.1-1 from 36.211
uint32_t n_drms_2[8] = { 0, 6, 3, 4, 2, 8, 10, 9 };
// n_drms_1 table 5.5.2.1.1-2 from 36.211
uint32_t n_drms_1[8] = { 0, 2, 3, 4, 6, 8, 9, 10 };
/* Generation of the reference signal sequence according to Section 5.5.1 of 36.211 */
int rs_sequence(ref_t * refs, uint32_t len, float alpha, uint32_t ns, uint32_t cell_id,
refsignal_ul_cfg_t * cfg)
{
uint32_t i;
// Calculate u and v
uint32_t u, v;
uint32_t f_ss = (((cell_id % 30) + cfg->delta_ss) % 30);
printf("f_ss: %d\n", f_ss);
if (cfg->group_hopping_en) {
sequence_t seq;
bzero(&seq, sizeof(sequence_t));
sequence_LTE_pr(&seq, 160, cell_id / 30);
uint32_t f_gh = 0;
for (i = 0; i < 8; i++) {
f_gh += (((uint32_t) seq.c[8 * ns + i]) << i);
}
printf("f_gh: %u\n", f_gh);
sequence_free(&seq);
u = ((f_gh%30) + f_ss) % 30;
} else {
u = f_ss % 30;
}
if (len < 6 * RE_X_RB) {
v = 0;
} else {
if (!cfg->group_hopping_en && cfg->sequence_hopping_en) {
sequence_t seq;
bzero(&seq, sizeof(sequence_t));
sequence_LTE_pr(&seq, 20, ((cell_id / 30) << 5) + f_ss);
v = seq.c[ns];
sequence_free(&seq);
} else {
v = 0;
}
}
printf("u: %d, v: %d\n", u, v);
if (len >= 3 * RE_X_RB) {
uint32_t n_sz;
uint32_t q;
float q_hat;
/* get largest prime n_zc<len */
for (i = NOF_PRIME_NUMBERS - 1; i > 0; i--) {
if (prime_numbers[i] < len) {
n_sz = prime_numbers[i];
break;
}
}
printf("n_sz: %d\n", n_sz);
q_hat = (float) n_sz *(u + 1) / 31;
if ((((uint32_t) (2 * q_hat)) % 2) == 0) {
q = (uint32_t) (q_hat + 0.5) + v;
} else {
q = (uint32_t) (q_hat + 0.5) - v;
}
cf_t *x_q = malloc(sizeof(cf_t) * n_sz);
if (!x_q) {
perror("malloc");
return LIBLTE_ERROR;
}
for (i = 0; i < n_sz; i++) {
x_q[i] =
cexpf(-I * M_PI * (float) q * (float) i * ((float) i + 1) / n_sz);
}
for (i = 0; i < len; i++) {
refs[i].simbol = cfg->beta * cexpf(I * alpha * i) * x_q[i % n_sz];
}
free(x_q);
} else {
if (len == RE_X_RB) {
for (i = 0; i < len; i++) {
refs[i].simbol = cfg->beta * cexpf(I * (phi_M_sc_12[u][i] * M_PI / 4 + alpha * i));
}
} else {
for (i = 0; i < len; i++) {
refs[i].simbol = cfg->beta * cexpf(I * (phi_M_sc_24[u][i] * M_PI / 4 + alpha * i));
}
}
}
return LIBLTE_SUCCESS;
}
/** Initializes refsignal_t object according to 3GPP 36.211 5.5.2
*
*/
int refsignal_init_LTEUL_drms_pusch(refsignal_t * q, uint32_t nof_prb, uint32_t prb_start,
uint32_t nslot, lte_cell_t cell, refsignal_ul_cfg_t * cfg)
{
uint32_t i;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
uint32_t n_prs;
uint32_t M_sc;
float alpha;
if (q != NULL && nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) {
bzero(q, sizeof(refsignal_t));
M_sc = nof_prb * RE_X_RB;
q->nof_refs = M_sc;
q->nsymbols = 1;
q->voffset = cell.id % 6;
q->nof_prb = cell.nof_prb;
q->symbols_ref = malloc(sizeof(uint32_t) * 1);
if (!q->symbols_ref) {
perror("malloc");
goto free_and_exit;
}
if (CP_ISNORM(cell.cp)) {
q->symbols_ref[0] = 3;
} else {
q->symbols_ref[0] = 2;
}
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
if (!q->refs) {
goto free_and_exit;
}
q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t));
if (!q->ch_est) {
goto free_and_exit;
}
/* Calculate n_prs */
uint32_t c_init;
sequence_t seq;
bzero(&seq, sizeof(sequence_t));
c_init = ((cell.id / 30) << 5) + (((cell.id % 30) + cfg->delta_ss) % 30);
ret = sequence_LTE_pr(&seq, 8 * CP_NSYMB(cell.cp) * 20, c_init);
if (ret != LIBLTE_SUCCESS) {
goto free_and_exit;
}
n_prs = 0;
for (i = 0; i < 8; i++) {
n_prs += (seq.c[8 * CP_NSYMB(cell.cp) * nslot + i] << i);
}
sequence_free(&seq);
// Calculate cyclic shift alpha
uint32_t n_cs =
(n_drms_1[cfg->cyclic_shift] +
n_drms_2[cfg->cyclic_shift_for_drms] + n_prs) % 12;
alpha = 2 * M_PI * (n_cs) / 12;
printf("alpha: %g\n", alpha);
if (rs_sequence(q->refs, M_sc, alpha, nslot, cell.id, cfg)) {
fprintf(stderr, "Error generating RS sequence\n");
goto free_and_exit;
}
/* mapping to resource elements */
for (i=0;i<M_sc;i++) {
q->refs[i].freq_idx = prb_start*RE_X_RB + i;
q->refs[i].time_idx = q->symbols_ref[0];
}
ret = LIBLTE_SUCCESS;
}
free_and_exit:
if (ret == LIBLTE_ERROR) {
refsignal_free(q);
}
return ret;
}
#endif

@ -30,6 +30,17 @@ ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0)
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1)
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2)
ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0 -r 50)
ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1 -r 50)
ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2 -r 50)
########################################################################
# Downlink MEX libs
########################################################################
BuildMex(MEXNAME chest SOURCES chest_test_dl_mex.c LIBRARIES lte_phy)
########################################################################
# Uplink Channel Estimation TEST
########################################################################
@ -43,3 +54,9 @@ ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2)

@ -35,7 +35,7 @@
lte_cell_t cell = {
6, // nof_prb
MAX_PORTS, // nof_ports
1, // nof_ports
1000, // cell_id
CPNORM // cyclic prefix
};
@ -80,49 +80,15 @@ void parse_args(int argc, char **argv) {
}
}
int check_mse(float mod, float arg, int n_port) {
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
switch(n_port) {
case 0:
if (mod > 0.029) {
return -1;
}
if (arg > 0.029) {
return -1;
}
break;
case 1:
if (mod > 0.012) {
return -1;
}
if (arg > 0.012) {
return -1;
}
break;
case 2:
case 3:
if (mod > 3.33) {
return -1;
}
if (arg > 0.63) {
return -1;
}
break;
default:
return -1;
}
return 0;
}
int main(int argc, char **argv) {
chest_t eq;
cf_t *input = NULL, *ce = NULL, *h = NULL;
refsignal_t refs;
int i, j, n_port, n_slot, cid, num_re;
chest_dl_t est;
precoding_t cheq;
cf_t *input = NULL, *ce = NULL, *h = NULL, *output = NULL;
int i, j, n_port, sf_idx, cid, num_re;
int ret = -1;
int max_cid;
FILE *fmatlab = NULL;
float mse_mag, mse_phase;
parse_args(argc,argv);
@ -134,13 +100,18 @@ int main(int argc, char **argv) {
}
}
num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
num_re = 2 * cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
perror("malloc");
goto do_exit;
}
output = malloc(num_re * sizeof(cf_t));
if (!output) {
perror("malloc");
goto do_exit;
}
h = malloc(num_re * sizeof(cf_t));
if (!h) {
perror("malloc");
@ -160,21 +131,18 @@ int main(int argc, char **argv) {
max_cid = cell.id;
}
precoding_init(&cheq, num_re);
while(cid <= max_cid) {
cell.id = cid;
if (chest_init_LTEDL(&eq, cell)) {
if (chest_dl_init(&est, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (sf_idx=0;sf_idx<1;sf_idx++) {
for (n_port=0;n_port<cell.nof_ports;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
@ -183,9 +151,10 @@ int main(int argc, char **argv) {
bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re);
refsignal_put(&refs, input);
refsignal_cs_put_sf(cell, n_port,
est.csr_signal.pilots[n_port/2][sf_idx], input);
for (i=0;i<CP_NSYMB(cell.cp);i++) {
for (i=0;i<2*CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
@ -193,15 +162,46 @@ int main(int argc, char **argv) {
}
}
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
struct timeval t[3];
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
chest_dl_estimate_port(&est, input, ce, sf_idx, n_port);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("CHEST: %f us\n", (float) t[0].tv_usec/100);
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
predecoding_single(&cheq, input, ce, output, num_re, 0);
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("CHEQ-ZF: %f us\n", (float) t[0].tv_usec/100);
float mse = 0;
for (i=0;i<num_re;i++) {
mse += cabsf(input[i]-output[i]);
}
mse /= num_re;
printf("MSE: %f\n", mse);
mse_mag = mse_phase = 0;
gettimeofday(&t[1], NULL);
for (int j=0;j<100;j++) {
predecoding_single(&cheq, input, ce, output, num_re, chest_dl_get_noise_estimate(&est));
}
gettimeofday(&t[2], NULL);
get_time_interval(t);
printf("CHEQ-MMSE: %f us\n", (float) t[0].tv_usec/100);
mse = 0;
for (i=0;i<num_re;i++) {
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
mse += cabsf(input[i]-output[i]);
}
mse /= num_re;
printf("MSE: %f\n", mse);
if (check_mse(mse_mag, mse_phase, n_port)) {
if (mse > 1.7) {
goto do_exit;
}
@ -215,11 +215,10 @@ int main(int argc, char **argv) {
fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n");
chest_fprint(&eq, fmatlab, n_slot, n_port);
}
}
}
chest_free(&eq);
chest_dl_free(&est);
cid+=10;
INFO("cid=%d\n", cid);
}
@ -229,6 +228,11 @@ int main(int argc, char **argv) {
do_exit:
precoding_free(&cheq);
if (output) {
free(output);
}
if (ce) {
free(ce);
}
@ -242,7 +246,7 @@ do_exit:
if (!ret) {
printf("OK\n");
} else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
printf("Error at cid=%d, slot=%d, port=%d\n",cid, sf_idx, n_port);
}
exit(ret);

@ -0,0 +1,252 @@
/**
*
* \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 <string.h>
#include "liblte/phy/phy.h"
#ifdef UNDEF_BOOL
#undef bool
#endif
#include "mex.h"
/** MEX function to be called from MATLAB to test the channel estimator
*/
#define CELLID prhs[0]
#define PORTS prhs[1]
#define INPUT prhs[2]
#define FREQ_FILTER prhs[3]
#define TIME_FILTER prhs[4]
#define NOF_INPUTS 5
#define SFIDX prhs[5]
void help()
{
mexErrMsgTxt
("[estChannel, avg_refs, output] = liblte_chest(cell_id, nof_ports, inputSignal,[sf_idx|freq_filter],"
"[time_filter])\n\n"
" Returns a matrix of size equal to the inputSignal matrix with the channel estimates\n "
"for each resource element in inputSignal. The inputSignal matrix is the received Grid\n"
"of size nof_resource_elements x nof_ofdm_symbols.\n"
"The sf_idx is the subframe index only used if inputSignal is 1 subframe length.\n"
"Returns the averaged references and output signal after ZF/MMSE equalization\n"
);
}
/* the gateway function */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int i;
lte_cell_t cell;
chest_dl_t chest;
precoding_t cheq;
cf_t *input_signal = NULL, *output_signal[MAX_LAYERS];
cf_t *output_signal2 = NULL;
cf_t *ce[MAX_PORTS];
double *outr0=NULL, *outi0=NULL;
double *outr1=NULL, *outi1=NULL;
double *outr2=NULL, *outi2=NULL;
if (nrhs < NOF_INPUTS) {
help();
return;
}
if (!mxIsDouble(CELLID) && mxGetN(CELLID) != 1 &&
!mxIsDouble(PORTS) && mxGetN(PORTS) != 1 &&
mxGetM(CELLID) != 1) {
help();
return;
}
cell.id = (uint32_t) *((double*) mxGetPr(CELLID));
cell.nof_prb = mxGetM(INPUT)/RE_X_RB;
cell.nof_ports = (uint32_t) *((double*) mxGetPr(PORTS));
if ((mxGetN(INPUT)%14) == 0) {
cell.cp = CPNORM;
} else if ((mxGetN(INPUT)%12)!=0) {
cell.cp = CPEXT;
} else {
mexErrMsgTxt("Invalid number of symbols\n");
help();
return;
}
if (chest_dl_init(&chest, cell)) {
mexErrMsgTxt("Error initiating channel estimator\n");
return;
}
int nsubframes;
if (cell.cp == CPNORM) {
nsubframes = mxGetN(INPUT)/14;
} else {
nsubframes = mxGetN(INPUT)/12;
}
uint32_t sf_idx=0;
if (nsubframes == 1) {
if (nrhs != NOF_INPUTS+1) {
mexErrMsgTxt("Received 1 subframe. Need to provide subframe index.\n");
help();
return;
}
sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX));
} else {
if (nrhs != NOF_INPUTS) {
help();
return;
}
}
uint32_t filter_len = 0;
float *filter;
double *f;
filter_len = mxGetNumberOfElements(FREQ_FILTER);
filter = malloc(sizeof(float) * filter_len);
f = (double*) mxGetPr(FREQ_FILTER);
for (i=0;i<filter_len;i++) {
filter[i] = (float) f[i];
}
chest_dl_set_filter_freq(&chest, filter, filter_len);
filter_len = mxGetNumberOfElements(TIME_FILTER);
filter = malloc(sizeof(float) * filter_len);
f = (double*) mxGetPr(TIME_FILTER);
for (i=0;i<filter_len;i++) {
filter[i] = (float) f[i];
}
chest_dl_set_filter_time(&chest, filter, filter_len);
double *inr=(double *)mxGetPr(INPUT);
double *ini=(double *)mxGetPi(INPUT);
/** Allocate input buffers */
int nof_re = 2*CP_NSYMB(cell.cp)*cell.nof_prb*RE_X_RB;
for (i=0;i<MAX_PORTS;i++) {
ce[i] = vec_malloc(nof_re * sizeof(cf_t));
}
input_signal = vec_malloc(nof_re * sizeof(cf_t));
for (i=0;i<MAX_PORTS;i++) {
output_signal[i] = vec_malloc(nof_re * sizeof(cf_t));
}
output_signal2 = vec_malloc(nof_re * sizeof(cf_t));
precoding_init(&cheq, nof_re);
/* Create output values */
if (nlhs >= 1) {
plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX);
outr0 = mxGetPr(plhs[0]);
outi0 = mxGetPi(plhs[0]);
}
if (nlhs >= 2) {
plhs[1] = mxCreateDoubleMatrix(REFSIGNAL_MAX_NUM_SF(cell.nof_prb)*nsubframes, cell.nof_ports, mxCOMPLEX);
outr1 = mxGetPr(plhs[1]);
outi1 = mxGetPi(plhs[1]);
}
if (nlhs >= 3) {
plhs[2] = mxCreateDoubleMatrix(nof_re * nsubframes, 1, mxCOMPLEX);
outr2 = mxGetPr(plhs[2]);
outi2 = mxGetPi(plhs[2]);
}
for (int sf=0;sf<nsubframes;sf++) {
/* Convert input to C complex type */
for (i=0;i<nof_re;i++) {
__real__ input_signal[i] = (float) *inr;
if (ini) {
__imag__ input_signal[i] = (float) *ini;
}
inr++;
ini++;
}
if (nsubframes != 1) {
sf_idx = sf%10;
}
/* Loop through the 10 subframes */
if (chest_dl_estimate(&chest, input_signal, ce, sf_idx)) {
mexErrMsgTxt("Error running channel estimator\n");
return;
}
if (cell.nof_ports == 1) {
predecoding_single(&cheq, input_signal, ce[0], output_signal2, nof_re, chest_dl_get_noise_estimate(&chest));
} else {
predecoding_diversity(&cheq, input_signal, ce, output_signal, cell.nof_ports, nof_re, chest_dl_get_noise_estimate(&chest));
layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports);
}
if (nlhs >= 1) {
for (int j=0;j<cell.nof_ports;j++) {
for (i=0;i<nof_re;i++) {
*outr0 = (double) crealf(ce[j][i]);
if (outi0) {
*outi0 = (double) cimagf(ce[j][i]);
}
outr0++;
outi0++;
}
}
}
if (nlhs >= 2) {
for (int j=0;j<cell.nof_ports;j++) {
for (i=0;i<REFSIGNAL_NUM_SF(cell.nof_prb,j);i++) {
*outr1 = (double) crealf(chest.pilot_estimates_average[j][i]);
if (outi1) {
*outi1 = (double) cimagf(chest.pilot_estimates_average[j][i]);
}
outr1++;
outi1++;
}
}
}
if (nlhs >= 3) {
for (i=0;i<nof_re;i++) {
*outr2 = (double) crealf(output_signal2[i]);
if (outi2) {
*outi2 = (double) cimagf(output_signal2[i]);
}
outr2++;
outi2++;
}
}
}
if (nlhs >= 4) {
plhs[3] = mxCreateDoubleScalar(chest_dl_get_snr(&chest));
}
return;
}

@ -40,7 +40,7 @@ lte_cell_t cell = {
CPNORM // cyclic prefix
};
char *output_matlab = NULL;
uint8_t *output_matlab = NULL;
void usage(char *prog) {
printf("Usage: %s [recov]\n", prog);

@ -53,8 +53,10 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb, dft_dir_t dir) {
}
dft_plan_set_mirror(&q->fft_plan, true);
dft_plan_set_norm(&q->fft_plan, true);
dft_plan_set_dc(&q->fft_plan, true);
#ifdef LTE_FFT_NORMALIZE
dft_plan_set_norm(&q->fft_plan, true);
#endif
q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = CP_NSYMB(cp);

@ -52,13 +52,43 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104,
/* Returns true if the structure pointed by cell has valid parameters
*/
bool lte_cellid_isvalid(uint32_t cell_id) {
if (cell_id < 504) {
return true;
} else {
return false;
}
}
bool lte_nofprb_isvalid(uint32_t nof_prb) {
if (nof_prb >= 6 && nof_prb <= MAX_PRB) {
return true;
} else {
return false;
}
}
bool lte_cell_isvalid(lte_cell_t *cell) {
if (cell->id < 504 &&
cell->nof_ports > 0 &&
cell->nof_ports < MAX_PORTS+1 &&
cell->nof_prb > 5 &&
cell->nof_prb < MAX_PRB+1
) {
return lte_cellid_isvalid(cell->id) &&
lte_portid_isvalid(cell->nof_ports) &&
lte_nofprb_isvalid(cell->nof_prb);
}
void lte_cell_fprint(FILE *stream, lte_cell_t *cell) {
fprintf(stream, "PCI: %d, CP: %s, PRB: %d, Ports: %d\n", cell->id, lte_cp_string(cell->cp), cell->nof_prb, cell->nof_ports);
}
bool lte_sfidx_isvalid(uint32_t sf_idx) {
if (sf_idx <= NSUBFRAMES_X_FRAME) {
return true;
} else {
return false;
}
}
bool lte_portid_isvalid(uint32_t port_id) {
if (port_id <= MAX_PORTS) {
return true;
} else {
return false;

@ -40,7 +40,7 @@
* It follows the 3GPP Release 8 (LTE) 36.211
* Section 7.2
*/
void generate_prs_c(sequence_t *q, uint32_t seed) {
void sequence_set_LTE_pr(sequence_t *q, uint32_t seed) {
int n;
uint32_t *x1, *x2;
@ -79,7 +79,7 @@ int sequence_LTE_pr(sequence_t *q, uint32_t len, uint32_t seed) {
return LIBLTE_ERROR;
}
q->len = len;
generate_prs_c(q, seed);
sequence_set_LTE_pr(q, seed);
return LIBLTE_SUCCESS;
}
@ -88,10 +88,11 @@ int sequence_init(sequence_t *q, uint32_t len) {
free(q->c);
}
if (!q->c) {
q->c = malloc(len * sizeof(char));
q->c = malloc(len * sizeof(uint8_t));
if (!q->c) {
return LIBLTE_ERROR;
}
q->len = len;
}
return LIBLTE_SUCCESS;
}

@ -102,10 +102,13 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initializing FFT\n");
exit(-1);
}
dft_plan_set_norm(&fft.fft_plan, true);
if (lte_ifft_init(&ifft, cp, n_prb)) {
fprintf(stderr, "Error initializing iFFT\n");
exit(-1);
}
dft_plan_set_norm(&ifft.fft_plan, true);
for (i=0;i<n_re;i++) {
input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);

@ -34,7 +34,7 @@
#include "liblte/phy/fec/convcoder.h"
#include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length) {
int convcoder_encode(convcoder_t *q, uint8_t *input, uint8_t *output, uint32_t frame_length) {
uint32_t sr;
uint32_t i,j;
uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
@ -53,7 +53,7 @@ int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_l
sr = 0;
}
for (i = 0; i < len; i++) {
char bit = (i < frame_length) ? (input[i] & 1) : 0;
uint8_t bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);

@ -54,14 +54,14 @@ unsigned long crctable(crc_t *h) {
// Polynom order 8, 16, 24 or 32 only.
int ord = h->order - 8;
unsigned long crc = h->crcinit;
unsigned char byte = h->byte;
uint8_t byte = h->byte;
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
h->crcinit = crc;
return (crc & h->crcmask);
}
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) {
unsigned long reversecrcbit(uint32_t crc, int nbits, crc_t *h) {
unsigned long m, rmask = 0x1;
@ -84,7 +84,7 @@ int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) {
return 0;
}
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
int crc_init(crc_t *h, uint32_t crc_poly, int crc_order) {
// Set crc working default parameters
h->polynom = crc_poly;
@ -114,10 +114,10 @@ int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
return 0;
}
uint32_t crc_checksum(crc_t *h, char *data, int len) {
uint32_t crc_checksum(crc_t *h, uint8_t *data, int len) {
int i, k, len8, res8, a = 0;
unsigned int crc = 0;
char *pter;
uint32_t crc = 0;
uint8_t *pter;
crc_set_init(h, 0);
@ -130,14 +130,14 @@ uint32_t crc_checksum(crc_t *h, char *data, int len) {
// Calculate CRC
for (i = 0; i < len8 + a; i++) {
pter = (char *) (data + 8 * i);
pter = (uint8_t *) (data + 8 * i);
if (i == len8) {
h->byte = 0x00;
for (k = 0; k < res8; k++) {
h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
h->byte |= ((uint8_t) *(pter + k)) << (7 - k);
}
} else {
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
h->byte = (uint8_t) (unpack_bits(&pter, 8) & 0xFF);
}
crc = crctable(h);
}
@ -155,11 +155,11 @@ uint32_t crc_checksum(crc_t *h, char *data, int len) {
/** Appends crc_order checksum bits to the buffer data.
* The buffer data must be len + crc_order bytes
*/
void crc_attach(crc_t *h, char *data, int len) {
unsigned int checksum = crc_checksum(h, data, len);
void crc_attach(crc_t *h, uint8_t *data, int len) {
uint32_t checksum = crc_checksum(h, data, len);
// Add CRC
char *ptr = &data[len];
uint8_t *ptr = &data[len];
pack_bits(checksum, &ptr, h->order);
}

@ -40,9 +40,9 @@ uint8_t RM_PERM_CC_INV[NCOLS] =
{ 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9,
21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 };
int rm_conv_tx(char *input, uint32_t in_len, char *output, uint32_t out_len) {
int rm_conv_tx(uint8_t *input, uint32_t in_len, uint8_t *output, uint32_t out_len) {
char tmp[3 * NCOLS * NROWS_MAX];
uint8_t tmp[3 * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p;
int i, j, k, s;

@ -53,7 +53,7 @@ uint8_t RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26,
*
* TODO: Soft buffer size limitation according to UE category
*/
int rm_turbo_tx(char *w_buff, uint32_t w_buff_len, char *input, uint32_t in_len, char *output,
int rm_turbo_tx(uint8_t *w_buff, uint32_t w_buff_len, uint8_t *input, uint32_t in_len, uint8_t *output,
uint32_t out_len, uint32_t rv_idx) {
int ndummy, kidx;

@ -50,7 +50,7 @@ const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
211, 223, 227, 229, 233, 239, 241, 251, 257 };
const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2,
const uint8_t table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2,
2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2, 19,
5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 };

@ -47,12 +47,12 @@ void tcod_free(tcod_t *h) {
h->max_long_cb = 0;
}
int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb) {
int tcod_encode(tcod_t *h, uint8_t *input, uint8_t *output, uint32_t long_cb) {
char reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2;
uint8_t reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2;
uint32_t i, k = 0, j;
char bit;
char in, out;
uint8_t bit;
uint8_t in, out;
uint32_t *per;
if (long_cb > h->max_long_cb) {

@ -317,7 +317,7 @@ int tdec_reset(tdec_t * h, uint32_t long_cb)
return tc_interl_LTE_gen(&h->interleaver, long_cb);
}
void tdec_decision(tdec_t * h, char *output, uint32_t long_cb)
void tdec_decision(tdec_t * h, uint8_t *output, uint32_t long_cb)
{
uint32_t i;
for (i = 0; i < long_cb; i++) {
@ -325,7 +325,7 @@ void tdec_decision(tdec_t * h, char *output, uint32_t long_cb)
}
}
void tdec_run_all(tdec_t * h, llr_t * input, char *output,
void tdec_run_all(tdec_t * h, llr_t * input, uint8_t *output,
uint32_t nof_iterations, uint32_t long_cb)
{
uint32_t iter = 0;

@ -40,7 +40,7 @@
#define DEB 0
int decode37(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
int decode37(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) {
viterbi_t *q = o;
uint32_t i;
@ -57,7 +57,7 @@ int decode37(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
/* Decode block */
if (q->tail_biting) {
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char));
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(uint8_t));
for (i = 0; i < 3 * (q->K - 1); i++) {
q->tmp[i + 3 * frame_length] = q->tmp[i];
}
@ -75,7 +75,7 @@ int decode37(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
return q->framebits;
}
int decode39(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
int decode39(void *o, uint8_t *symbols, uint8_t *data, uint32_t frame_length) {
viterbi_t *q = o;
if (frame_length > q->framebits) {
@ -96,6 +96,7 @@ int decode39(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
return q->framebits;
}
void free37(void *o) {
viterbi_t *q = o;
if (q->symbols_uc) {
@ -119,16 +120,18 @@ int init37(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting)
q->K = 7;
q->R = 3;
q->framebits = framebits;
q->gain_quant = 32;
q->tail_biting = tail_biting;
q->decode = decode37;
q->free = free37;
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
q->decode_f = NULL;
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if (q->tail_biting) {
q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t));
if (!q->tmp) {
perror("malloc");
free37(q);
@ -152,14 +155,16 @@ int init39(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting)
q->R = 3;
q->framebits = framebits;
q->tail_biting = tail_biting;
q->gain_quant = 32;
q->decode = decode39;
q->free = free39;
q->decode_f = NULL;
if (q->tail_biting) {
fprintf(stderr,
"Error: Tailbitting not supported in 1/3 K=9 decoder\n");
return -1;
}
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(uint8_t));
if (!q->symbols_uc) {
perror("malloc");
return -1;
@ -173,6 +178,12 @@ int init39(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting)
}
}
void viterbi_set_gain_quant(viterbi_t *q, float gain_quant) {
q->gain_quant = gain_quant;
}
int viterbi_init(viterbi_t *q, viterbi_type_t type, uint32_t poly[3],
uint32_t max_frame_length, bool tail_bitting) {
switch (type) {
@ -190,10 +201,11 @@ void viterbi_free(viterbi_t *q) {
if (q->free) {
q->free(q);
}
bzero(q, sizeof(viterbi_t));
}
/* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, uint32_t frame_length) {
int viterbi_decode_f(viterbi_t *q, float *symbols, uint8_t *data, uint32_t frame_length) {
uint32_t len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
@ -205,11 +217,17 @@ int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, uint32_t frame_le
} else {
len = 3 * (frame_length + q->K - 1);
}
vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len);
if (!q->decode_f) {
vec_quant_fuc(symbols, q->symbols_uc, q->gain_quant, 127.5, 255, len);
return q->decode(q, q->symbols_uc, data, frame_length);
} else {
return q->decode_f(q, symbols, data, frame_length);
}
}
int viterbi_decode_uc(viterbi_t *q, uint8_t *symbols, char *data,
int viterbi_decode_uc(viterbi_t *q, uint8_t *symbols, uint8_t *data,
uint32_t frame_length) {
return q->decode(q, symbols, data, frame_length);
}

@ -34,13 +34,13 @@ int init_viterbi37_port(void *p,
uint32_t starting_state);
int chainback_viterbi37_port(void *p,
char *data,
uint8_t *data,
uint32_t nbits,
uint32_t endstate);
void delete_viterbi37_port(void *p);
int update_viterbi37_blk_port(void *p,
unsigned char *syms,
uint8_t *syms,
uint32_t nbits,
uint32_t *best_state);

@ -12,14 +12,14 @@
#include <limits.h>
typedef union {
unsigned int w[64];
uint32_t w[64];
} metric_t;
typedef union {
unsigned long w[2];
} decision_t;
static union {
unsigned char c[128];
uint8_t c[128];
} Branchtab37[3];
/* State info for instance of Viterbi decoder */
@ -77,13 +77,12 @@ void *create_viterbi37_port(uint32_t polys[3], uint32_t len) {
free(vp);
return NULL ;
}
init_viterbi37_port(vp, 0);
return vp;
}
/* Viterbi chainback */
int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */
int chainback_viterbi37_port(void *p, uint8_t *data, /* Decoded output data */
uint32_t nbits, /* Number of data bits */
uint32_t endstate) { /* Terminal encoder state */
struct v37 *vp = p;
@ -127,7 +126,7 @@ void delete_viterbi37_port(void *p) {
/* C-language butterfly */
#define BFLY(i) {\
unsigned int metric,m0,m1,decision;\
uint32_t metric,m0,m1,decision;\
metric = (Branchtab37[0].c[i] ^ sym0) + (Branchtab37[1].c[i] ^ sym1) + \
(Branchtab37[2].c[i] ^ sym2);\
m0 = vp->old_metrics->w[i] + metric;\
@ -179,7 +178,7 @@ int update_viterbi37_blk_port(void *p, uint8_t *syms, uint32_t nbits, uint32_t *
uint32_t i, bst=0;
uint32_t minmetric=UINT_MAX;
for (i=0;i<64;i++) {
if (vp->old_metrics->w[i] < minmetric) {
if (vp->old_metrics->w[i] <= minmetric) {
bst = i;
minmetric = vp->old_metrics->w[i];
}

@ -34,7 +34,7 @@ int init_viterbi39_port(void *p,
uint32_t starting_state);
int chainback_viterbi39_port(void *p,
char *data, /* Decoded output data */
uint8_t *data, /* Decoded output data */
uint32_t nbits, /* Number of data bits */
uint32_t endstate);

@ -10,14 +10,14 @@
#include "parity.h"
typedef union {
unsigned int w[256];
uint32_t w[256];
} metric_t;
typedef union {
unsigned long w[8];
} decision_t;
static union {
unsigned char c[128];
uint8_t c[128];
} Branchtab39[3];
/* State info for instance of Viterbi decoder */
@ -79,7 +79,7 @@ void *create_viterbi39_port(uint32_t polys[3], uint32_t len) {
}
/* Viterbi chainback */
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
int chainback_viterbi39_port(void *p, uint8_t *data, /* Decoded output data */
uint32_t nbits, /* Number of data bits */
uint32_t endstate) { /* Terminal encoder state */
struct v39 *vp = p;
@ -121,7 +121,7 @@ void delete_viterbi39_port(void *p) {
/* C-language butterfly */
#define BFLY(i) {\
unsigned int metric,m0,m1,decision;\
uint32_t metric,m0,m1,decision;\
metric = (Branchtab39[0].c[i] ^ sym0) + (Branchtab39[1].c[i] ^ sym1) + \
(Branchtab39[2].c[i] ^ sym2);\
m0 = vp->old_metrics->w[i] + metric;\

@ -67,6 +67,8 @@ ADD_TEST(viterbi_1000_2 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 2.0)
ADD_TEST(viterbi_1000_3 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 3.0)
ADD_TEST(viterbi_1000_4 viterbi_test -n 100 -s 1 -l 1000 -k 7 -t -e 4.5)
BuildMex(MEXNAME viterbi SOURCES viterbi_test_mex.c LIBRARIES lte_phy liblte_mex)
########################################################################
# CRC TEST
########################################################################

@ -37,8 +37,8 @@
#include "crc_test.h"
int num_bits = 5001, crc_length = 24;
unsigned int crc_poly = 0x1864CFB;
unsigned int seed = 1;
uint32_t crc_poly = 0x1864CFB;
uint32_t seed = 1;
void usage(char *prog) {
printf("Usage: %s [nlps]\n", prog);
@ -59,10 +59,10 @@ void parse_args(int argc, char **argv) {
crc_length = atoi(argv[optind]);
break;
case 'p':
crc_poly = (unsigned int) strtoul(argv[optind], NULL, 16);
crc_poly = (uint32_t) strtoul(argv[optind], NULL, 16);
break;
case 's':
seed = (unsigned int) strtoul(argv[optind], NULL, 0);
seed = (uint32_t) strtoul(argv[optind], NULL, 0);
break;
default:
usage(argv[0]);
@ -73,13 +73,13 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) {
int i;
char *data;
unsigned int crc_word, expected_word;
uint8_t *data;
uint32_t crc_word, expected_word;
crc_t crc_p;
parse_args(argc, argv);
data = malloc(sizeof(char) * (num_bits + crc_length * 2));
data = malloc(sizeof(uint8_t) * (num_bits + crc_length * 2));
if (!data) {
perror("malloc");
exit(-1);

@ -32,9 +32,9 @@
typedef struct {
int n;
int l;
unsigned int p;
unsigned int s;
unsigned int word;
uint32_t p;
uint32_t s;
uint32_t word;
}expected_word_t;
@ -48,7 +48,7 @@ static expected_word_t expected_words[] = {
{-1, -1, 0, 0, 0}
};
int get_expected_word(int n, int l, unsigned int p, unsigned int s, unsigned int *word) {
int get_expected_word(int n, int l, uint32_t p, unsigned int s, unsigned int *word) {
int i;
i=0;
while(expected_words[i].n != -1) {

@ -69,18 +69,18 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) {
int i;
char *bits, *rm_bits;
uint8_t *bits, *rm_bits;
float *rm_symbols, *unrm_symbols;
int nof_errors;
parse_args(argc, argv);
bits = malloc(sizeof(char) * nof_tx_bits);
bits = malloc(sizeof(uint8_t) * nof_tx_bits);
if (!bits) {
perror("malloc");
exit(-1);
}
rm_bits = malloc(sizeof(char) * nof_rx_bits);
rm_bits = malloc(sizeof(uint8_t) * nof_rx_bits);
if (!rm_bits) {
perror("malloc");
exit(-1);

@ -73,23 +73,23 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) {
int i;
char *bits, *rm_bits, *w_buff_c;
uint8_t *bits, *rm_bits, *w_buff_c;
float *rm_symbols, *unrm_symbols, *w_buff_f;
int nof_errors;
parse_args(argc, argv);
bits = malloc(sizeof(char) * nof_tx_bits);
bits = malloc(sizeof(uint8_t) * nof_tx_bits);
if (!bits) {
perror("malloc");
exit(-1);
}
w_buff_c = malloc(sizeof(char) * nof_tx_bits * 10);
w_buff_c = malloc(sizeof(uint8_t) * nof_tx_bits * 10);
if (!w_buff_c) {
perror("malloc");
exit(-1);
}
rm_bits = malloc(sizeof(char) * nof_rx_bits);
rm_bits = malloc(sizeof(uint8_t) * nof_rx_bits);
if (!rm_bits) {
perror("malloc");
exit(-1);

@ -90,7 +90,7 @@ void parse_args(int argc, char **argv) {
ebno_db = atof(argv[optind]);
break;
case 's':
seed = (unsigned int) strtoul(argv[optind], NULL, 0);
seed = (uint32_t) strtoul(argv[optind], NULL, 0);
break;
case 'v':
verbose++;
@ -129,8 +129,8 @@ void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) {
int main(int argc, char **argv) {
uint32_t frame_cnt;
float *llr;
unsigned char *llr_c;
char *data_tx, *data_rx, *symbols;
uint8_t *llr_c;
uint8_t *data_tx, *data_rx, *symbols;
uint32_t i, j;
float var[SNR_POINTS];
uint32_t snr_points;
@ -162,19 +162,19 @@ int main(int argc, char **argv) {
printf(" EbNo: %.2f\n", ebno_db);
}
data_tx = malloc(frame_length * sizeof(char));
data_tx = malloc(frame_length * sizeof(uint8_t));
if (!data_tx) {
perror("malloc");
exit(-1);
}
data_rx = malloc(frame_length * sizeof(char));
data_rx = malloc(frame_length * sizeof(uint8_t));
if (!data_rx) {
perror("malloc");
exit(-1);
}
symbols = malloc(coded_length * sizeof(char));
symbols = malloc(coded_length * sizeof(uint8_t));
if (!symbols) {
perror("malloc");
exit(-1);
@ -184,7 +184,7 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
llr_c = malloc(coded_length * sizeof(char));
llr_c = malloc(coded_length * sizeof(uint8_t));
if (!llr_c) {
perror("malloc");
exit(-1);

@ -29,7 +29,7 @@
typedef struct {
int n;
unsigned int s;
uint32_t s;
int iterations;
int len;
float ebno;
@ -55,7 +55,7 @@ static expected_errors_t expected_errors[] = {
};
int get_expected_errors(int n, unsigned int s, int iterations, int len, float ebno) {
int get_expected_errors(int n, uint32_t s, int iterations, int len, float ebno) {
int i;
i = 0;
while (expected_errors[i].n != -1) {
@ -78,7 +78,7 @@ int get_expected_errors(int n, unsigned int s, int iterations, int len, float eb
const int known_data_errors[4] = {47, 18, 0, 0};
#define KNOWN_DATA_LEN 504
const char known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
const uint8_t known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1,
0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1,
1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0,
@ -101,7 +101,7 @@ const char known_data[KNOWN_DATA_LEN] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1,
1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1 };
const char known_data_encoded[3 * KNOWN_DATA_LEN + 12] = { 0, 0, 0, 0, 0, 1, 1,
const uint8_t known_data_encoded[3 * KNOWN_DATA_LEN + 12] = { 0, 0, 0, 0, 0, 1, 1,
1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1,
1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0,
0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0,

@ -41,7 +41,7 @@ typedef _Complex float cf_t;
int frame_length = 1000, nof_frames = 128;
float ebno_db = 100.0;
unsigned int seed = 0;
uint32_t seed = 0;
bool tail_biting = false;
int K = -1;
@ -76,7 +76,7 @@ void parse_args(int argc, char **argv) {
ebno_db = atof(argv[optind]);
break;
case 's':
seed = (unsigned int) strtoul(argv[optind], NULL, 0);
seed = (uint32_t) strtoul(argv[optind], NULL, 0);
break;
case 't':
tail_biting = true;
@ -122,13 +122,13 @@ void output_matlab(float ber[NTYPES][SNR_POINTS], int snr_points,
int main(int argc, char **argv) {
int frame_cnt;
float *llr;
unsigned char *llr_c;
char *data_tx, *data_rx[NTYPES], *symbols;
uint8_t *llr_c;
uint8_t *data_tx, *data_rx[NTYPES], *symbols;
int i, j;
float var[SNR_POINTS], varunc[SNR_POINTS];
int snr_points;
float ber[NTYPES][SNR_POINTS];
unsigned int errors[NTYPES];
uint32_t errors[NTYPES];
viterbi_type_t viterbi_type[NCODS];
viterbi_t dec[NCODS];
convcoder_t cod[NCODS];
@ -200,21 +200,21 @@ int main(int argc, char **argv) {
printf(" EbNo: %.2f\n", ebno_db);
}
data_tx = malloc(frame_length * sizeof(char));
data_tx = malloc(frame_length * sizeof(uint8_t));
if (!data_tx) {
perror("malloc");
exit(-1);
}
for (i = 0; i < NTYPES; i++) {
data_rx[i] = malloc(frame_length * sizeof(char));
data_rx[i] = malloc(frame_length * sizeof(uint8_t));
if (!data_rx[i]) {
perror("malloc");
exit(-1);
}
}
symbols = malloc(max_coded_length * sizeof(char));
symbols = malloc(max_coded_length * sizeof(uint8_t));
if (!symbols) {
perror("malloc");
exit(-1);
@ -224,7 +224,7 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
llr_c = malloc(2 * max_coded_length * sizeof(char));
llr_c = malloc(2 * max_coded_length * sizeof(uint8_t));
if (!llr_c) {
perror("malloc");
exit(-1);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save