mirror of https://github.com/PentHertz/srsLTE.git
Merge branch 'scanner_average_pss'
This commit is contained in:
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)
|
||||
|
|
@ -7,7 +7,7 @@ int main(){
|
|||
char*av[];
|
||||
#else
|
||||
int main(int ac, char*av[]){
|
||||
|
||||
|
||||
#endif
|
||||
float ac2 = sqrtf(rand());
|
||||
CHECK_FUNCTION_EXISTS();
|
||||
|
|
|
@ -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,91 +25,108 @@ FIND_LIBRARY(
|
|||
)
|
||||
|
||||
# Some functions are not defined in old volk versions
|
||||
SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_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_subtract_32f HAVE_VOLK_SUB_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)
|
||||
|
||||
|
||||
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)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION)
|
||||
CHECK_FUNCTION_EXISTS_MATH(volk_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_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)
|
||||
|
||||
|
||||
|
||||
SET(VOLK_DEFINITIONS "HAVE_VOLK")
|
||||
IF(${HAVE_VOLK_MAX_ABS_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_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_SUB_FLOAT_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_CONVERT_FI_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MAX_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_ACC_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_CONJ_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT2_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT_REAL_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MAG_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DIVIDE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DOTPROD_F_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_ATAN_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION")
|
||||
ENDIF()
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS)
|
||||
SET(VOLK_DEFINITIONS "HAVE_VOLK")
|
||||
IF(${HAVE_VOLK_MAX_ABS_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION")
|
||||
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()
|
||||
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_CONVERT_FI_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MAX_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_ACC_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ACC_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_CONJ_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONJ_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT2_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MULT_REAL_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_MAG_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DIVIDE_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_DOTPROD_F_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION")
|
||||
ENDIF()
|
||||
IF(${HAVE_VOLK_ATAN_FUNCTION})
|
||||
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION")
|
||||
ENDIF()
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
|
||||
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS)
|
||||
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);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ int cuhd_open(char *args, void **h)
|
|||
int cuhd_close(void *h)
|
||||
{
|
||||
cuhd_stop_rx_stream(h);
|
||||
/** Something else to close the USRP?? */
|
||||
/** Something else to close the USRP?? */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
handler->usrp->set_rx_rate(freq);
|
||||
double ret = handler->usrp->get_rx_rate();
|
||||
return ret;
|
||||
printf("Changing sampling freq now to %.2f MHz\n", freq/1000000);
|
||||
handler->usrp->set_rx_rate(freq);
|
||||
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,27 +51,24 @@ 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")
|
||||
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
|
||||
ELSE(${GRAPHICS_FIND} EQUAL -1)
|
||||
target_link_libraries(pdsch_ue graphics)
|
||||
target_link_libraries(pdsch_enodeb graphics)
|
||||
ENDIF(${GRAPHICS_FIND} EQUAL -1)
|
||||
IF(${GRAPHICS_FIND} EQUAL -1)
|
||||
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
|
||||
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
|
||||
ELSE(${GRAPHICS_FIND} EQUAL -1)
|
||||
target_link_libraries(pdsch_ue graphics)
|
||||
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,16 +111,20 @@ 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);
|
||||
|
||||
printf("Opening UHD device...\n");
|
||||
|
@ -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 */
|
||||
|
@ -170,19 +154,45 @@ int main(int argc, char **argv) {
|
|||
if (VERBOSE_ISINFO()) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
n = find_all_cells(uhd, found_cells);
|
||||
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(®s, R_1, PHICH_NORM, cell)) {
|
||||
if (regs_init(®s, cell)) {
|
||||
fprintf(stderr, "Error initiating regs\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
@ -236,16 +239,17 @@ 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) {
|
||||
usage(argv[0]);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -363,7 +366,7 @@ int main(int argc, char **argv) {
|
|||
fprintf(stderr, "Error encoding PDSCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
/* Transform to OFDM symbols */
|
||||
lte_ifft_run_sf(&ifft, sf_buffer, output_buffer);
|
||||
|
||||
|
@ -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 void filter2d_free(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 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,
|
||||
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,
|
||||
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);
|
||||
LIBLTE_API int precoding_single(precoding_t *q,
|
||||
cf_t *x,
|
||||
cf_t *y,
|
||||
int nof_symbols);
|
||||
|
||||
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
|
||||
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 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_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],
|
||||
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 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
|
||||
#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,7 +77,8 @@ typedef struct LIBLTE_API {
|
|||
viterbi_t decoder;
|
||||
crc_t crc;
|
||||
convcoder_t encoder;
|
||||
|
||||
precoding_t precoding;
|
||||
|
||||
} pbch_t;
|
||||
|
||||
LIBLTE_API int pbch_init(pbch_t *q,
|
||||
|
@ -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,
|
||||
cf_t *slot1_symbols[MAX_PORTS]);
|
||||
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
|
||||
#define PCFICH_CFI_LEN 32
|
||||
#define PCFICH_RE PCFICH_CFI_LEN/2
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
|
@ -56,14 +55,21 @@ typedef struct LIBLTE_API {
|
|||
cf_t pcfich_symbols[MAX_PORTS][PCFICH_RE];
|
||||
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;
|
||||
|
||||
float *in_mag;
|
||||
float *in_arg;
|
||||
float *in_mag0;
|
||||
float *in_arg0;
|
||||
float *in_mag1;
|
||||
float *in_arg1;
|
||||
|
||||
float *out_mag;
|
||||
float *out_arg;
|
||||
float *out_arg2;
|
||||
int16_t *table_idx;
|
||||
|
||||
cf_t *out_cexp;
|
||||
cf_t *out_prod;
|
||||
|
||||
cf_t *cexptable;
|
||||
|
||||
uint32_t len;
|
||||
uint32_t M;
|
||||
|
||||
}interp_t;
|
||||
/************* STATIC LINEAR INTERPOLATION FUNCTIONS */
|
||||
|
||||
LIBLTE_API int interp_init(interp_t *q,
|
||||
interp_type_t type,
|
||||
uint32_t len,
|
||||
uint32_t M);
|
||||
LIBLTE_API cf_t interp_linear_onesample(cf_t input0,
|
||||
cf_t input1);
|
||||
|
||||
LIBLTE_API void interp_free(interp_t *q);
|
||||
LIBLTE_API cf_t interp_linear_onesample_cabs(cf_t input0,
|
||||
cf_t input1);
|
||||
|
||||
LIBLTE_API void interp_run(interp_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output);
|
||||
|
||||
LIBLTE_API void interp_run_offset(interp_t *q,
|
||||
cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t off_st,
|
||||
uint32_t off_end);
|
||||
|
||||
LIBLTE_API void interp_linear_offset(cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t M,
|
||||
uint32_t len,
|
||||
uint32_t off_st,
|
||||
uint32_t off_end);
|
||||
|
||||
LIBLTE_API void interp_linear_c(cf_t *input,
|
||||
cf_t *output,
|
||||
uint32_t M,
|
||||
uint32_t len);
|
||||
LIBLTE_API void interp_linear_offset_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);
|
||||
|
||||
|
||||
|
||||
/* Interpolation between vectors */
|
||||
|
||||
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);
|
||||
|
||||
|
||||
|
||||
/* Interpolation within a vector */
|
||||
|
||||
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 off_st,
|
||||
uint32_t off_end);
|
||||
|
||||
|
||||
#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
|
||||
|
@ -61,7 +66,9 @@ 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,12 +101,30 @@ 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,
|
||||
cf_t *input,
|
||||
uint32_t *m0,
|
||||
float *m0_value,
|
||||
uint32_t *m1,
|
||||
float *m1_value);
|
||||
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,12 +114,17 @@ 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,
|
||||
uint32_t N_id_2);
|
||||
uint32_t N_id_2);
|
||||
|
||||
/* Gets the Physical CellId from the last call to synch_run() */
|
||||
LIBLTE_API int sync_get_cell_id(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;
|
||||
uint64_t nof_pdcch_detected;
|
||||
|
||||
uint32_t sfn;
|
||||
bool pbch_decoded;
|
||||
|
||||
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,
|
||||
uint32_t sf_idx,
|
||||
uint16_t rnti);
|
||||
LIBLTE_API int ue_dl_decode(ue_dl_t * q,
|
||||
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;
|
||||
pbch_t pbch;
|
||||
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 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);
|
||||
|
||||
LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q,
|
||||
float threshold);
|
||||
|
||||
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
|
||||
LIBLTE_API int ue_mib_decode(ue_mib_t * q,
|
||||
cf_t *input,
|
||||
uint8_t bch_payload[BCH_PAYLOAD_LEN],
|
||||
uint32_t *nof_tx_ports,
|
||||
uint32_t *sfn_offset);
|
||||
|
||||
|
||||
/* 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;
|
||||
|
@ -77,15 +83,13 @@ 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
|
||||
|
@ -93,17 +97,22 @@ typedef struct LIBLTE_API {
|
|||
|
||||
|
||||
LIBLTE_API int ue_sync_init(ue_sync_t *q,
|
||||
lte_cell_t cell,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
lte_cell_t cell,
|
||||
int (recv_callback)(void*, void*, uint32_t),
|
||||
void *stream_handler);
|
||||
|
||||
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);
|
||||
|
|
|
@ -46,7 +46,7 @@ SET(SOURCES_ALL "")
|
|||
FOREACH (_module ${modules})
|
||||
IF(IS_DIRECTORY ${_module})
|
||||
FILE(GLOB_RECURSE tmp "${_module}/src/*.c")
|
||||
LIST(APPEND SOURCES_ALL ${tmp})
|
||||
LIST(APPEND SOURCES_ALL ${tmp})
|
||||
ENDIF(IS_DIRECTORY ${_module})
|
||||
ENDFOREACH()
|
||||
|
||||
|
@ -57,14 +57,13 @@ LIBLTE_SET_PIC(lte_phy)
|
|||
|
||||
IF(VOLK_FOUND)
|
||||
INCLUDE_DIRECTORIES(${VOLK_INCLUDE_DIRS})
|
||||
SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}")
|
||||
SET_TARGET_PROPERTIES(lte_phy PROPERTIES COMPILE_DEFINITIONS "${VOLK_DEFINITIONS}")
|
||||
TARGET_LINK_LIBRARIES(lte_phy ${VOLK_LIBRARIES})
|
||||
MESSAGE(STATUS " Compiling with VOLK SIMD library.")
|
||||
ELSE(VOLK_FOUND)
|
||||
MESSAGE(STATUS " VOLK SIMD library NOT found. Using generic implementation.")
|
||||
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");
|
||||
|
@ -159,22 +130,19 @@ int main(int argc, char **argv) {
|
|||
cid = cell.id;
|
||||
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,28 +151,60 @@ 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);
|
||||
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
|
||||
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
|
||||
}
|
||||
}
|
||||
|
||||
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
|
||||
|
||||
mse_mag = mse_phase = 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;
|
||||
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);
|
||||
|
||||
if (check_mse(mse_mag, mse_phase, n_port)) {
|
||||
float mse = 0;
|
||||
for (i=0;i<num_re;i++) {
|
||||
mse += cabsf(input[i]-output[i]);
|
||||
}
|
||||
mse /= num_re;
|
||||
printf("MSE: %f\n", mse);
|
||||
|
||||
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 += cabsf(input[i]-output[i]);
|
||||
}
|
||||
mse /= num_re;
|
||||
printf("MSE: %f\n", mse);
|
||||
|
||||
if (mse > 1.7) {
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
|
||||
if (fmatlab) {
|
||||
fprintf(fmatlab, "input=");
|
||||
vec_fprint_c(fmatlab, input, num_re);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Binary file not shown.
|
@ -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,19 +52,49 @@ 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_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
|
||||
) {
|
||||
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bool lte_N_id_2_isvalid(uint32_t N_id_2) {
|
||||
if (N_id_2 < 3) {
|
||||
return true;
|
||||
|
|
|
@ -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;
|
||||
|
@ -98,7 +98,7 @@ int rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out_len) {
|
|||
int d_i, d_j;
|
||||
|
||||
float tmp[3 * NCOLS * NROWS_MAX];
|
||||
|
||||
|
||||
nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
|
||||
if (nrows > NROWS_MAX) {
|
||||
fprintf(stderr, "Output too large. Max output length is %d\n",
|
||||
|
|
|
@ -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);
|
||||
|
@ -144,7 +147,7 @@ int init37(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting)
|
|||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int init39(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) {
|
||||
|
@ -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);
|
||||
return q->decode(q, q->symbols_uc, data, frame_length);
|
||||
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,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue