mirror of https://github.com/pvnis/srsRAN_4G.git
Testing CH est
parent
17dd292089
commit
61ebfaf3b2
@ -0,0 +1,65 @@
|
|||||||
|
# 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()
|
||||||
|
|
||||||
|
IF (MATLAB_FOUND)
|
||||||
|
message(STATUS "Found MATLAB in ${MATLAB_ROOT}")
|
||||||
|
ELSE(MATLAB_FOUND)
|
||||||
|
message(STATUS "Could NOT find MATLAB. MEX files won't be compiled")
|
||||||
|
ENDIF(MATLAB_FOUND)
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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)
|
||||||
|
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)
|
||||||
|
endif (OCTAVE_FOUND)
|
||||||
|
ENDFUNCTION(BuildMex)
|
||||||
|
|
@ -0,0 +1,212 @@
|
|||||||
|
# - this module looks for Matlab
|
||||||
|
# Defines:
|
||||||
|
# MATLAB_INCLUDE_DIR: include path for mex.h, engine.h
|
||||||
|
# MATLAB_LIBRARIES: required libraries: libmex, etc
|
||||||
|
# MATLAB_MEX_LIBRARY: path to libmex.lib
|
||||||
|
# MATLAB_MX_LIBRARY: path to libmx.lib
|
||||||
|
# MATLAB_MAT_LIBRARY: path to libmat.lib # added
|
||||||
|
# MATLAB_ENG_LIBRARY: path to libeng.lib
|
||||||
|
# MATLAB_ROOT: path to Matlab's root directory
|
||||||
|
|
||||||
|
# This file is part of Gerardus
|
||||||
|
#
|
||||||
|
# This is a derivative work of file FindMatlab.cmake released with
|
||||||
|
# CMake v2.8, because the original seems to be a bit outdated and
|
||||||
|
# doesn't work with my Windows XP and Visual Studio 10 install
|
||||||
|
#
|
||||||
|
# (Note that the original file does work for Ubuntu Natty)
|
||||||
|
#
|
||||||
|
# Author: Ramon Casero <rcasero at gmail.com>, Tom Doel
|
||||||
|
# Version: 0.2.3
|
||||||
|
# $Rev$
|
||||||
|
# $Date$
|
||||||
|
#
|
||||||
|
# The original file was copied from an Ubuntu Linux install
|
||||||
|
# /usr/share/cmake-2.8/Modules/FindMatlab.cmake
|
||||||
|
|
||||||
|
set(MATLAB_FOUND 0)
|
||||||
|
if(WIN32)
|
||||||
|
# Search for a version of Matlab available, starting from the most modern one to older versions
|
||||||
|
foreach(MATVER "7.14" "7.11" "7.10" "7.9" "7.8" "7.7" "7.6" "7.5" "7.4")
|
||||||
|
if((NOT DEFINED MATLAB_ROOT)
|
||||||
|
OR ("${MATLAB_ROOT}" STREQUAL "")
|
||||||
|
OR ("${MATLAB_ROOT}" STREQUAL "/registry"))
|
||||||
|
get_filename_component(MATLAB_ROOT "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MathWorks\\MATLAB\\${MATVER};MATLABROOT]"
|
||||||
|
ABSOLUTE)
|
||||||
|
set(MATLAB_VERSION ${MATVER})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
# Directory name depending on whether the Windows architecture is 32
|
||||||
|
# bit or 64 bit
|
||||||
|
set(CMAKE_SIZEOF_VOID_P 8) # Note: For some wierd reason this variable is undefined in my system...
|
||||||
|
if(CMAKE_SIZEOF_VOID_P MATCHES "4")
|
||||||
|
set(WINDIR "win32")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
|
set(WINDIR "win64")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) doesn't indicate a valid platform")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Folder where the MEX libraries are, depending of the Windows compiler
|
||||||
|
if(${CMAKE_GENERATOR} MATCHES "Visual Studio 6")
|
||||||
|
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/msvc60")
|
||||||
|
elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio 7")
|
||||||
|
# Assume people are generally using Visual Studio 7.1,
|
||||||
|
# if using 7.0 need to link to: ../extern/lib/${WINDIR}/microsoft/msvc70
|
||||||
|
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/msvc71")
|
||||||
|
# set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/msvc70")
|
||||||
|
elseif(${CMAKE_GENERATOR} MATCHES "Borland")
|
||||||
|
# Assume people are generally using Borland 5.4,
|
||||||
|
# if using 7.0 need to link to ../extern/lib/${WINDIR}/microsoft/msvc70
|
||||||
|
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/bcc54")
|
||||||
|
# set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/bcc50")
|
||||||
|
# set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/bcc51")
|
||||||
|
elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio*")
|
||||||
|
# If the compiler is Visual Studio, but not any of the specific
|
||||||
|
# versions above, we try our luck with the microsoft directory
|
||||||
|
set(MATLAB_LIBRARIES_DIR "${MATLAB_ROOT}/extern/lib/${WINDIR}/microsoft/")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Generator not compatible: ${CMAKE_GENERATOR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get paths to the Matlab MEX libraries
|
||||||
|
find_library(MATLAB_MEX_LIBRARY libmex ${MATLAB_LIBRARIES_DIR} )
|
||||||
|
find_library(MATLAB_MX_LIBRARY libm ${MATLAB_LIBRARIES_DIR} )
|
||||||
|
find_library(MATLAB_MAT_LIBRARY libmat ${MATLAB_LIBRARIES_DIR} )
|
||||||
|
find_library(MATLAB_ENG_LIBRARY libeng ${MATLAB_LIBRARIES_DIR} )
|
||||||
|
|
||||||
|
# Get path to the include directory
|
||||||
|
find_path(MATLAB_INCLUDE_DIR "mex.h" "${MATLAB_ROOT}/extern/include" )
|
||||||
|
|
||||||
|
else()
|
||||||
|
|
||||||
|
if((NOT DEFINED MATLAB_ROOT)
|
||||||
|
OR ("${MATLAB_ROOT}" STREQUAL ""))
|
||||||
|
# get path to the Matlab root directory
|
||||||
|
execute_process(
|
||||||
|
COMMAND which matlab
|
||||||
|
COMMAND xargs readlink
|
||||||
|
COMMAND xargs dirname
|
||||||
|
COMMAND xargs dirname
|
||||||
|
COMMAND xargs echo -n
|
||||||
|
OUTPUT_VARIABLE MATLAB_ROOT
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if this is a Mac
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
|
|
||||||
|
set(LIBRARY_EXTENSION .dylib)
|
||||||
|
|
||||||
|
# If this is a Mac and the attempts to find MATLAB_ROOT have so far failed,
|
||||||
|
# we look in the applications folder
|
||||||
|
if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
|
||||||
|
|
||||||
|
# Search for a version of Matlab available, starting from the most modern one to older versions
|
||||||
|
foreach(MATVER "R2013b" "R2013a" "R2012b" "R2012a" "R2011b" "R2011a" "R2010b" "R2010a" "R2009b" "R2009a" "R2008b")
|
||||||
|
if((NOT DEFINED MATLAB_ROOT) OR ("${MATLAB_ROOT}" STREQUAL ""))
|
||||||
|
if(EXISTS /Applications/MATLAB_${MATVER}.app)
|
||||||
|
set(MATLAB_ROOT /Applications/MATLAB_${MATVER}.app)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
else()
|
||||||
|
set(LIBRARY_EXTENSION .so)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Get path to the MEX libraries
|
||||||
|
execute_process(
|
||||||
|
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libmex${LIBRARY_EXTENSION} # Peter
|
||||||
|
COMMAND find "${MATLAB_ROOT}/bin" -name libmex${LIBRARY_EXTENSION} # standard
|
||||||
|
COMMAND xargs echo -n
|
||||||
|
OUTPUT_VARIABLE MATLAB_MEX_LIBRARY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libmx${LIBRARY_EXTENSION} # Peter
|
||||||
|
COMMAND find "${MATLAB_ROOT}/bin" -name libmx${LIBRARY_EXTENSION} # Standard
|
||||||
|
COMMAND xargs echo -n
|
||||||
|
OUTPUT_VARIABLE MATLAB_MX_LIBRARY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libmat${LIBRARY_EXTENSION} # Peter
|
||||||
|
COMMAND find "${MATLAB_ROOT}/bin" -name libmat${LIBRARY_EXTENSION} # Standard
|
||||||
|
COMMAND xargs echo -n
|
||||||
|
OUTPUT_VARIABLE MATLAB_MAT_LIBRARY
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
#COMMAND find "${MATLAB_ROOT}/extern/lib" -name libeng${LIBRARY_EXTENSION} # Peter
|
||||||
|
COMMAND find "${MATLAB_ROOT}/bin" -name libeng${LIBRARY_EXTENSION} # Standard
|
||||||
|
COMMAND xargs echo -n
|
||||||
|
OUTPUT_VARIABLE MATLAB_ENG_LIBRARY
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get path to the include directory
|
||||||
|
find_path(MATLAB_INCLUDE_DIR
|
||||||
|
"mex.h"
|
||||||
|
PATHS "${MATLAB_ROOT}/extern/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
find_program( MATLAB_MEX_PATH mex
|
||||||
|
HINTS ${MATLAB_ROOT}/bin
|
||||||
|
PATHS ${MATLAB_ROOT}/bin
|
||||||
|
DOC "The mex program path"
|
||||||
|
)
|
||||||
|
|
||||||
|
find_program( MATLAB_MEXEXT_PATH mexext
|
||||||
|
HINTS ${MATLAB_ROOT}/bin
|
||||||
|
PATHS ${MATLAB_ROOT}/bin
|
||||||
|
DOC "The mexext program path"
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${MATLAB_MEXEXT_PATH}
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
OUTPUT_VARIABLE MATLAB_MEX_EXT
|
||||||
|
)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# This is common to UNIX and Win32:
|
||||||
|
set(MATLAB_LIBRARIES
|
||||||
|
${MATLAB_MEX_LIBRARY}
|
||||||
|
${MATLAB_MX_LIBRARY}
|
||||||
|
${MATLAB_ENG_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MATLAB_INCLUDE_DIR AND MATLAB_LIBRARIES)
|
||||||
|
set(MATLAB_FOUND 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# 32-bit or 64-bit mex
|
||||||
|
if(WIN32)
|
||||||
|
if (CMAKE_CL_64)
|
||||||
|
SET(MATLAB_MEX_EXTENSION .mexw64)
|
||||||
|
else(CMAKE_CL_64)
|
||||||
|
SET(MATLAB_MEX_EXTENSION .mexw32)
|
||||||
|
endif(CMAKE_CL_64)
|
||||||
|
else(WIN32)
|
||||||
|
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
|
SET(MATLAB_MEX_EXTENSION .mexa64)
|
||||||
|
else(CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
|
SET(MATLAB_MEX_EXTENSION .mexglx)
|
||||||
|
endif (CMAKE_SIZEOF_VOID_P MATCHES "8")
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
SET(MATLAB_MEX_CFLAGS "-DMATLAB_MEX_FILE -DMX_COMPAT_32")
|
||||||
|
|
||||||
|
mark_as_advanced(
|
||||||
|
MATLAB_LIBRARIES
|
||||||
|
MATLAB_MEX_LIBRARY
|
||||||
|
MATLAB_MX_LIBRARY
|
||||||
|
MATLAB_ENG_LIBRARY
|
||||||
|
MATLAB_INCLUDE_DIR
|
||||||
|
MATLAB_FOUND
|
||||||
|
MATLAB_ROOT
|
||||||
|
MATLAB_MEX_PATH
|
||||||
|
MATLAB_MEXEXT_PATH
|
||||||
|
MATLAB_MEX_EXT
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,138 @@
|
|||||||
|
# - Try to find a version of Octave and headers/library required by the
|
||||||
|
# used compiler. It determines the right MEX-File extension and add
|
||||||
|
# a macro to help the build of MEX-functions.
|
||||||
|
#
|
||||||
|
# This module defines:
|
||||||
|
# OCTAVE_INCLUDE_DIR: include path for mex.h, mexproto.h
|
||||||
|
# OCTAVE_OCTINTERP_LIBRARY: path to the library octinterp
|
||||||
|
# OCTAVE_OCTAVE_LIBRARY: path to the library octave
|
||||||
|
# OCTAVE_CRUFT_LIBRARY: path to the library cruft
|
||||||
|
# OCTAVE_LIBRARIES: required libraries: octinterp, octave, cruft
|
||||||
|
# OCTAVE_CREATE_MEX: macro to build a MEX-file
|
||||||
|
#
|
||||||
|
# The macro OCTAVE_CREATE_MEX requires in this order:
|
||||||
|
# - function's name which will be called in Octave;
|
||||||
|
# - C/C++ source files;
|
||||||
|
# - third libraries required.
|
||||||
|
|
||||||
|
# Copyright (c) 2009-2013 Arnaud Barré <arnaud.barre@gmail.com>
|
||||||
|
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||||
|
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||||
|
|
||||||
|
IF(OCTAVE_ROOT AND OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES)
|
||||||
|
STRING(COMPARE NOTEQUAL "${OCTAVE_ROOT}" "${OCTAVE_ROOT_LAST}" OCTAVE_CHANGED)
|
||||||
|
IF(OCTAVE_CHANGED)
|
||||||
|
SET(OCTAVE_USE_MINGW32 OCTAVE_USE_MINGW32-NOTFOUND CACHE INTERNAL "")
|
||||||
|
SET(OCTAVE_OCTAVE_LIBRARY OCTAVE_OCTAVE_LIBRARY-NOTFOUND CACHE INTERNAL "")
|
||||||
|
SET(OCTAVE_INCLUDE_DIR OCTAVE_INCLUDE_DIR-NOTFOUND CACHE INTERNAL "")
|
||||||
|
ELSE(OCTAVE_CHANGED)
|
||||||
|
# in cache already
|
||||||
|
SET(Octave_FIND_QUIETLY TRUE)
|
||||||
|
ENDIF(OCTAVE_CHANGED)
|
||||||
|
ENDIF(OCTAVE_ROOT AND OCTAVE_INCLUDE_DIR AND OCTAVE_LIBRARIES)
|
||||||
|
|
||||||
|
SET(OCTAVE_MEXFILE_EXT mex)
|
||||||
|
|
||||||
|
IF(WIN32)
|
||||||
|
SET(OCTAVE_PATHS_L1 )
|
||||||
|
SET(OCTAVE_PATHS_L2 )
|
||||||
|
# Level 0
|
||||||
|
FILE(GLOB OCTAVE_PATHS_L0 "c:/Octave*")
|
||||||
|
# Level 1
|
||||||
|
FOREACH(_file_ ${OCTAVE_PATHS_L0})
|
||||||
|
FILE(GLOB OCTAVE_PATHS_TEMP "${_file_}/*")
|
||||||
|
SET(OCTAVE_PATHS_L1 ${OCTAVE_PATHS_L1};${OCTAVE_PATHS_TEMP})
|
||||||
|
ENDFOREACH(_file_ OCTAVE_PATHS_L0)
|
||||||
|
# Level 2
|
||||||
|
FOREACH(_file_ ${OCTAVE_PATHS_L1})
|
||||||
|
FILE(GLOB OCTAVE_PATHS_TEMP "${_file_}/*")
|
||||||
|
SET(OCTAVE_PATHS_L2 ${OCTAVE_PATHS_L2};${OCTAVE_PATHS_TEMP})
|
||||||
|
ENDFOREACH(_file_ OCTAVE_PATHS_L1)
|
||||||
|
# Merge levels
|
||||||
|
SET(OCTAVE_PATHS ${OCTAVE_PATHS_L0} ${OCTAVE_PATHS_L1} ${OCTAVE_PATHS_L2})
|
||||||
|
|
||||||
|
FIND_PATH(OCTAVE_ROOT "bin/octave.exe" ${OCTAVE_PATHS})
|
||||||
|
FIND_PATH(OCTAVE_USE_MINGW32 "bin/mingw32-make.exe" "${OCTAVE_ROOT}/mingw32")
|
||||||
|
|
||||||
|
IF(MSVC AND OCTAVE_USE_MINGW32)
|
||||||
|
MESSAGE(FATAL_ERROR
|
||||||
|
"You must use the generator \"MinGW Makefiles\" as the "
|
||||||
|
"version of Octave installed on your computer was compiled "
|
||||||
|
"with MinGW. You should also specify the native compiler "
|
||||||
|
"(GCC, G++ and GFortan) and add the path of MinGW in the "
|
||||||
|
"environment variable PATH. Contact the developers of the "
|
||||||
|
"project for more details")
|
||||||
|
ENDIF(MSVC AND OCTAVE_USE_MINGW32)
|
||||||
|
|
||||||
|
FILE(GLOB OCTAVE_INCLUDE_PATHS "${OCTAVE_ROOT}/include/octave-*/octave")
|
||||||
|
FILE(GLOB OCTAVE_LIBRARIES_PATHS "${OCTAVE_ROOT}/lib/octave-*")
|
||||||
|
IF (NOT OCTAVE_LIBRARIES_PATHS)
|
||||||
|
FILE(GLOB OCTAVE_LIBRARIES_PATHS "${OCTAVE_ROOT}/lib/octave/*")
|
||||||
|
ENDIF (NOT OCTAVE_LIBRARIES_PATHS)
|
||||||
|
|
||||||
|
# LIBOCTINTERP, LIBOCTAVE, LIBCRUFT names
|
||||||
|
SET(LIBOCTAVE "liboctave")
|
||||||
|
|
||||||
|
ELSE(WIN32)
|
||||||
|
IF(APPLE)
|
||||||
|
FILE(GLOB OCTAVE_PATHS "/Applications/Octave*")
|
||||||
|
FIND_PATH(OCTAVE_ROOT "Contents/Resources/bin/octave" ${OCTAVE_PATHS})
|
||||||
|
|
||||||
|
FILE(GLOB OCTAVE_INCLUDE_PATHS "${OCTAVE_ROOT}/Contents/Resources/include/octave-*/octave")
|
||||||
|
FILE(GLOB OCTAVE_LIBRARIES_PATHS "${OCTAVE_ROOT}/Contents/Resources/lib/octave-*")
|
||||||
|
|
||||||
|
SET(LIBOCTAVE "liboctave.dylib")
|
||||||
|
ELSE(APPLE)
|
||||||
|
FILE(GLOB OCTAVE_LOCAL_PATHS "/usr/local/lib/octave-*")
|
||||||
|
FILE(GLOB OCTAVE_USR_PATHS "/usr/lib/octave-*")
|
||||||
|
FILE(GLOB OCTAVE_INCLUDE_PATHS "/usr/include/octave-*")
|
||||||
|
|
||||||
|
SET (OCTAVE_INCLUDE_PATHS
|
||||||
|
"/usr/local/include"
|
||||||
|
"/usr/local/include/octave"
|
||||||
|
"/usr/include"
|
||||||
|
"${OCTAVE_INCLUDE_PATHS}"
|
||||||
|
"${OCTAVE_INCLUDE_PATHS}/octave")
|
||||||
|
SET (OCTAVE_LIBRARIES_PATHS
|
||||||
|
"/usr/local/lib"
|
||||||
|
"/usr/local/lib/octave"
|
||||||
|
${OCTAVE_LOCAL_PATHS}
|
||||||
|
"/usr/lib"
|
||||||
|
"/usr/lib/octave"
|
||||||
|
${OCTAVE_USR_PATHS})
|
||||||
|
|
||||||
|
SET (LIBOCTAVE "octave")
|
||||||
|
ENDIF(APPLE)
|
||||||
|
ENDIF(WIN32)
|
||||||
|
|
||||||
|
FIND_LIBRARY(OCTAVE_OCTAVE_LIBRARY
|
||||||
|
${LIBOCTAVE}
|
||||||
|
${OCTAVE_LIBRARIES_PATHS}
|
||||||
|
)
|
||||||
|
FIND_PATH(OCTAVE_INCLUDE_DIR
|
||||||
|
"mex.h"
|
||||||
|
${OCTAVE_INCLUDE_PATHS}
|
||||||
|
)
|
||||||
|
|
||||||
|
SET(OCTAVE_ROOT_LAST "${OCTAVE_ROOT}" CACHE INTERNAL "" FORCE)
|
||||||
|
|
||||||
|
# This is common to UNIX and Win32:
|
||||||
|
SET(OCTAVE_LIBRARIES
|
||||||
|
${OCTAVE_OCTAVE_LIBRARY}
|
||||||
|
CACHE INTERNAL "Octave libraries" FORCE
|
||||||
|
)
|
||||||
|
|
||||||
|
INCLUDE(FindPackageHandleStandardArgs)
|
||||||
|
|
||||||
|
# The variable OCTAVE_ROOT is only relevant for WIN32
|
||||||
|
IF(WIN32)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Octave DEFAULT_MSG OCTAVE_ROOT OCTAVE_INCLUDE_DIR OCTAVE_OCTAVE_LIBRARY )
|
||||||
|
ELSE(WIN32)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Octave DEFAULT_MSG OCTAVE_INCLUDE_DIR OCTAVE_OCTAVE_LIBRARY )
|
||||||
|
ENDIF(WIN32)
|
||||||
|
|
||||||
|
MARK_AS_ADVANCED(
|
||||||
|
OCTAVE_OCTAVE_LIBRARY
|
||||||
|
OCTAVE_LIBRARIES
|
||||||
|
OCTAVE_INCLUDE_DIR
|
||||||
|
)
|
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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"
|
||||||
|
|
||||||
|
#define CHEST_RS_AVERAGE_TIME 0
|
||||||
|
#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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
lte_cell_t cell;
|
||||||
|
refsignal_cs_t csr_signal;
|
||||||
|
cf_t *pilot_estimates[MAX_PORTS];
|
||||||
|
cf_t *pilot_recv_signal[MAX_PORTS];
|
||||||
|
cf_t *pilot_symbol_avg;
|
||||||
|
|
||||||
|
interp_t interp_time[MAX_PORTS];
|
||||||
|
interp_t interp_freq[MAX_PORTS];
|
||||||
|
|
||||||
|
float rssi;
|
||||||
|
float rsrq;
|
||||||
|
float rsrp;
|
||||||
|
} 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_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 int chest_dl_equalize_zf(chest_dl_t *q,
|
||||||
|
cf_t *input,
|
||||||
|
cf_t *ce[MAX_PORTS],
|
||||||
|
cf_t *output);
|
||||||
|
|
||||||
|
LIBLTE_API int chest_dl_equalize_mmse(chest_dl_t *q,
|
||||||
|
cf_t *input,
|
||||||
|
cf_t *ce[MAX_PORTS],
|
||||||
|
float *noise_estimate,
|
||||||
|
cf_t *output);
|
||||||
|
|
||||||
|
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
|
@ -0,0 +1,87 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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,ns,cell) (2*cell.nof_prb*((l)+2*((ns)%2))+(i))
|
||||||
|
|
||||||
|
|
||||||
|
/** Cell-Specific Reference Signal */
|
||||||
|
typedef struct LIBLTE_API {
|
||||||
|
lte_cell_t cell;
|
||||||
|
cf_t *pilots[NSUBFRAMES_X_FRAME]; // save 2 reference symbols per slot
|
||||||
|
} 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,
|
||||||
|
uint32_t sf_idx,
|
||||||
|
cf_t *pilots,
|
||||||
|
cf_t *sf_symbols);
|
||||||
|
|
||||||
|
LIBLTE_API int refsignal_cs_get_sf(lte_cell_t cell,
|
||||||
|
uint32_t port_id,
|
||||||
|
uint32_t sf_idx,
|
||||||
|
cf_t *sf_symbols,
|
||||||
|
cf_t *pilots);
|
||||||
|
|
||||||
|
LIBLTE_API uint32_t refsignal_fidx(lte_cell_t cell,
|
||||||
|
uint32_t ns,
|
||||||
|
uint32_t l,
|
||||||
|
uint32_t port_id,
|
||||||
|
uint32_t m);
|
||||||
|
|
||||||
|
LIBLTE_API uint32_t refsignal_nsymbol(lte_cell_t cell,
|
||||||
|
uint32_t ns,
|
||||||
|
uint32_t l);
|
||||||
|
|
||||||
|
LIBLTE_API uint32_t refsignal_cs_v(uint32_t port_id,
|
||||||
|
uint32_t ns,
|
||||||
|
uint32_t symbol_id);
|
||||||
|
|
||||||
|
LIBLTE_API uint32_t refsignal_cs_nof_symbols(uint32_t port_id);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,317 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 "liblte/config.h"
|
||||||
|
|
||||||
|
#include "liblte/phy/ch_estimation/chest_dl.h"
|
||||||
|
#include "liblte/phy/utils/vector.h"
|
||||||
|
|
||||||
|
//#define VOLK_INTERP
|
||||||
|
|
||||||
|
/** 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->pilot_symbol_avg = vec_malloc(sizeof(cf_t) * 2*cell.nof_prb);
|
||||||
|
if (!q->pilot_symbol_avg) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0;i<cell.nof_ports;i++) {
|
||||||
|
q->pilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
||||||
|
if (!q->pilot_estimates[i]) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
q->pilot_recv_signal[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb));
|
||||||
|
if (!q->pilot_recv_signal[i]) {
|
||||||
|
perror("malloc");
|
||||||
|
goto clean_exit;
|
||||||
|
}
|
||||||
|
#ifdef VOLK_INTERP
|
||||||
|
ret = interp_init(&q->interp_freq[i], LINEAR, 2*cell.nof_prb, RE_X_RB/2);
|
||||||
|
if (ret == LIBLTE_SUCCESS) {
|
||||||
|
ret = interp_init(&q->interp_time[i], LINEAR, 2, CP_NSYMB(cell.cp) - 3);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init buffer for holding CE estimates averages */
|
||||||
|
|
||||||
|
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->pilot_symbol_avg) {
|
||||||
|
free(q->pilot_symbol_avg);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0;i<MAX_PORTS;i++) {
|
||||||
|
if (q->pilot_estimates[i]) {
|
||||||
|
free(q->pilot_estimates[i]);
|
||||||
|
}
|
||||||
|
if (q->pilot_recv_signal[i]) {
|
||||||
|
free(q->pilot_recv_signal[i]);
|
||||||
|
}
|
||||||
|
#ifdef VOLK_INTERP
|
||||||
|
interp_free(&q->interp_freq[i]);
|
||||||
|
interp_free(&q->interp_time[i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define pilot_est(idx) q->pilot_estimates[port_id][REFSIGNAL_PILOT_IDX(idx,l,ns,q->cell)]
|
||||||
|
|
||||||
|
#if CHEST_RS_AVERAGE_TIME > 1
|
||||||
|
cf_t timeavg[CHEST_RS_AVERAGE_TIME-1][12];
|
||||||
|
int nof_timeavg=0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void average_pilots(chest_dl_t *q, uint32_t sf_idx, uint32_t port_id)
|
||||||
|
{
|
||||||
|
uint32_t ns, l;
|
||||||
|
int i;
|
||||||
|
/* For each symbol with pilots in a slot */
|
||||||
|
for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
|
||||||
|
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
|
||||||
|
bzero(q->pilot_symbol_avg, 2*q->cell.nof_prb);
|
||||||
|
|
||||||
|
/** Frequency average */
|
||||||
|
#if CHEST_RS_AVERAGE_FREQ > 1
|
||||||
|
const uint32_t M = CHEST_RS_AVERAGE_FREQ;
|
||||||
|
cf_t xint[CHEST_RS_AVERAGE_FREQ];
|
||||||
|
int j, k;
|
||||||
|
/* Extrapolate first M/2 samples */
|
||||||
|
for (i=M/2-1;i>=0;i--) {
|
||||||
|
k=0;
|
||||||
|
for (j=i+M/2;j>=0;j--) {
|
||||||
|
xint[k]=pilot_est(j);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
for (;j>=i-M/2;j--) {
|
||||||
|
if (k>=2) {
|
||||||
|
xint[k] = interp_linear_onesample(&xint[k-2]);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q->pilot_symbol_avg[i] = vec_acc_cc(xint,M)/M;
|
||||||
|
//q->pilot_symbol_avg[i] = (pilot_est(0)+pilot_est(1))/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=M/2;i<2*q->cell.nof_prb-M/2;i++) {
|
||||||
|
q->pilot_symbol_avg[i] = vec_acc_cc(&pilot_est(i-M/2),M)/M;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extrapolate last M/2 samples */
|
||||||
|
for (;i<2*q->cell.nof_prb;i++) {
|
||||||
|
k=0;
|
||||||
|
for (j=i-M/2;j<2*q->cell.nof_prb;j++) {
|
||||||
|
xint[k]=pilot_est(j);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
for (;k<M;k++) {
|
||||||
|
if (k>=2) {
|
||||||
|
xint[k] = interp_linear_onesample(&xint[k-2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
q->pilot_symbol_avg[i] = vec_acc_cc(xint,M)/M;
|
||||||
|
//q->pilot_symbol_avg[i] = (pilot_est(i)+pilot_est(i+1))/2;
|
||||||
|
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
memcpy(q->pilot_symbol_avg, &pilot_est(0), 2*q->cell.nof_prb*sizeof(cf_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Time average last symbols */
|
||||||
|
#if CHEST_RS_AVERAGE_TIME > 1
|
||||||
|
if (nof_timeavg<CHEST_RS_AVERAGE_TIME-1) {
|
||||||
|
memcpy(timeavg[nof_timeavg],q->pilot_symbol_avg, 2*q->cell.nof_prb * sizeof(cf_t));
|
||||||
|
nof_timeavg++;
|
||||||
|
} else {
|
||||||
|
bzero(&pilot_est(0),2*q->cell.nof_prb*sizeof(cf_t));
|
||||||
|
for (i=0;i<nof_timeavg;i++) {
|
||||||
|
vec_sum_ccc(timeavg[i],&pilot_est(0),&pilot_est(0),2*q->cell.nof_prb);
|
||||||
|
}
|
||||||
|
vec_sum_ccc(q->pilot_symbol_avg,&pilot_est(0),&pilot_est(0),2*q->cell.nof_prb);
|
||||||
|
vec_sc_prod_cfc(&pilot_est(0), 1.0/CHEST_RS_AVERAGE_TIME, &pilot_est(0), 2*q->cell.nof_prb);
|
||||||
|
for (i=0;i<nof_timeavg-1;i++) {
|
||||||
|
memcpy(timeavg[i],timeavg[i+1],2*q->cell.nof_prb*sizeof(cf_t));
|
||||||
|
}
|
||||||
|
memcpy(timeavg[i],q->pilot_symbol_avg,2*q->cell.nof_prb*sizeof(cf_t));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
memcpy(&pilot_est(0), q->pilot_symbol_avg, 2*q->cell.nof_prb * sizeof(cf_t));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void interpolate_pilots(chest_dl_t *q, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
|
||||||
|
{
|
||||||
|
/* interpolate the symbols with references in the freq domain */
|
||||||
|
uint32_t ns, l, i,j;
|
||||||
|
cf_t x[2], y[MAX_NSYMB];
|
||||||
|
|
||||||
|
for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
|
||||||
|
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
|
||||||
|
uint32_t fidx_offset = refsignal_fidx(q->cell, ns, l, port_id, 0);
|
||||||
|
#ifdef VOLK_INTERP
|
||||||
|
interp_run_offset(&q->interp_freq[port_id],
|
||||||
|
&q->pilot_estimates[port_id][((ns%2)*2+l)*2*q->cell.nof_prb],
|
||||||
|
&ce[refsignal_nsymbol(q->cell,ns,l) * q->cell.nof_prb * RE_X_RB],
|
||||||
|
fidx_offset, RE_X_RB/2-fidx_offset);
|
||||||
|
#else
|
||||||
|
interp_linear_offset(&q->pilot_estimates[port_id][((ns%2)*2+l)*2*q->cell.nof_prb],
|
||||||
|
&ce[refsignal_nsymbol(q->cell,ns,l) * q->cell.nof_prb * RE_X_RB], RE_X_RB/2,
|
||||||
|
2*q->cell.nof_prb, fidx_offset, RE_X_RB/2-fidx_offset);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* now interpolate in the time domain */
|
||||||
|
for (i=0;i<RE_X_RB*q->cell.nof_prb; i++) {
|
||||||
|
if (refsignal_cs_nof_symbols(port_id) > 1) {
|
||||||
|
for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
|
||||||
|
j=0;
|
||||||
|
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
|
||||||
|
x[j] = ce[refsignal_nsymbol(q->cell,ns,l) * q->cell.nof_prb * RE_X_RB + i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
#ifdef VOLK_INTERP
|
||||||
|
interp_run_offset(&q->interp_time[port_id], x, y,
|
||||||
|
0, CP_NSYMB(q->cell.cp) - 4);
|
||||||
|
#else
|
||||||
|
interp_linear_offset(x, y, CP_NSYMB(q->cell.cp) - 3,
|
||||||
|
2, 0, CP_NSYMB(q->cell.cp) - 4);
|
||||||
|
#endif
|
||||||
|
for (j=0;j<CP_NSYMB(q->cell.cp);j++) {
|
||||||
|
ce[(j+((ns%2)*CP_NSYMB(q->cell.cp))) * q->cell.nof_prb*RE_X_RB + i] = y[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "3/4 Ports interpolator not implemented\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int chest_dl_estimate_port(chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id)
|
||||||
|
{
|
||||||
|
//filter2d_reset(&q->filter);
|
||||||
|
|
||||||
|
/* Get references from the input signal */
|
||||||
|
refsignal_cs_get_sf(q->cell, port_id, sf_idx, input, q->pilot_recv_signal[port_id]);
|
||||||
|
|
||||||
|
/* Use the known CSR signal to compute Least-squares estimates */
|
||||||
|
vec_div_ccc_mod1(q->pilot_recv_signal[port_id], q->csr_signal.pilots[sf_idx],
|
||||||
|
q->pilot_estimates[port_id], REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id));
|
||||||
|
|
||||||
|
/* Average pilot estimates */
|
||||||
|
average_pilots(q, sf_idx, port_id);
|
||||||
|
|
||||||
|
/* Interpolate to create channel estimates for all resource grid */
|
||||||
|
interpolate_pilots(q, ce, sf_idx, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chest_dl_equalize_zf(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], cf_t *output)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Not implemented\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chest_dl_equalize_mmse(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], float *noise_estimate, cf_t *output)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Not implemented\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float chest_dl_get_rssi(chest_dl_t *q) {
|
||||||
|
return q->rssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
float chest_dl_get_rsrq(chest_dl_t *q) {
|
||||||
|
return q->rsrq;
|
||||||
|
}
|
||||||
|
|
||||||
|
float chest_dl_get_rsrp(chest_dl_t *q) {
|
||||||
|
return q->rsrp;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,246 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* \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 ns, uint32_t symbol_id)
|
||||||
|
{
|
||||||
|
uint32_t v = 0;
|
||||||
|
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_cs_nof_symbols(uint32_t port_id)
|
||||||
|
{
|
||||||
|
if (port_id < 2) {
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t lp(uint32_t l, lte_cp_t cp) {
|
||||||
|
if (l == 1) {
|
||||||
|
return CP_NSYMB(cp) - 3;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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;
|
||||||
|
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 (i=0;i<NSUBFRAMES_X_FRAME;i++) {
|
||||||
|
q->pilots[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(q->cell.nof_prb));
|
||||||
|
if (!q->pilots[i]) {
|
||||||
|
perror("malloc");
|
||||||
|
goto free_and_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
|
||||||
|
for (l = 0; l < 2; l++) {
|
||||||
|
/* Compute sequence init value */
|
||||||
|
c_init = 1024 * (7 * (ns + 1) + lp(l,cell.cp) + 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[ns/2][REFSIGNAL_PILOT_IDX(i,l,ns,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;
|
||||||
|
|
||||||
|
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
|
||||||
|
if (q->pilots[i]) {
|
||||||
|
free(q->pilots[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bzero(q, sizeof(refsignal_cs_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline uint32_t refsignal_fidx(lte_cell_t cell, uint32_t ns, uint32_t l, uint32_t port_id, uint32_t m) {
|
||||||
|
return 6*m + ((refsignal_cs_v(port_id, ns, lp(l,cell.cp)) + (cell.id % 6)) % 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t refsignal_nsymbol(lte_cell_t cell, uint32_t ns, uint32_t l) {
|
||||||
|
return (ns%2)*CP_NSYMB(cell.cp)+lp(l,cell.cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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, uint32_t sf_idx,
|
||||||
|
cf_t *pilots, cf_t *sf_symbols)
|
||||||
|
{
|
||||||
|
uint32_t i, l, ns;
|
||||||
|
uint32_t fidx;
|
||||||
|
|
||||||
|
if (lte_cell_isvalid(&cell) &&
|
||||||
|
lte_sfidx_isvalid(sf_idx) &&
|
||||||
|
lte_portid_isvalid(port_id) &&
|
||||||
|
pilots != NULL &&
|
||||||
|
sf_symbols != NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
|
||||||
|
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
|
||||||
|
/* Compute offset frequency index */
|
||||||
|
fidx = ((refsignal_cs_v(port_id, ns, lp(l,cell.cp)) + (cell.id % 6)) % 6);
|
||||||
|
for (i = 0; i < 2*cell.nof_prb; i++) {
|
||||||
|
uint32_t nsymbol = refsignal_nsymbol(cell, ns, l);
|
||||||
|
sf_symbols[SAMPLE_IDX(cell.nof_prb, nsymbol, fidx)] = pilots[REFSIGNAL_PILOT_IDX(i,l,ns,cell)];
|
||||||
|
fidx += 6; // 1 reference every 6 RE
|
||||||
|
DEBUG("Putting %d to %d (fidx: %d, lp:%d)\n",REFSIGNAL_PILOT_IDX(i,l,ns,cell), SAMPLE_IDX(cell.nof_prb, nsymbol, fidx),
|
||||||
|
fidx, nsymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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, uint32_t sf_idx,
|
||||||
|
cf_t *sf_symbols, cf_t *pilots)
|
||||||
|
{
|
||||||
|
uint32_t i, l, ns;
|
||||||
|
uint32_t fidx;
|
||||||
|
|
||||||
|
if (lte_cell_isvalid(&cell) &&
|
||||||
|
lte_sfidx_isvalid(sf_idx) &&
|
||||||
|
lte_portid_isvalid(port_id) &&
|
||||||
|
pilots != NULL &&
|
||||||
|
sf_symbols != NULL)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) {
|
||||||
|
for (l=0;l<refsignal_cs_nof_symbols(port_id);l++) {
|
||||||
|
/* Compute offset frequency index */
|
||||||
|
fidx = ((refsignal_cs_v(port_id, ns, lp(l,cell.cp)) + (cell.id % 6)) % 6);
|
||||||
|
for (i = 0; i < 2*cell.nof_prb; i++) {
|
||||||
|
uint32_t nsymbol = refsignal_nsymbol(cell, ns, l);
|
||||||
|
pilots[REFSIGNAL_PILOT_IDX(i,l,ns,cell)] = sf_symbols[SAMPLE_IDX(cell.nof_prb, nsymbol, fidx)];
|
||||||
|
fidx += 6; // 1 reference every 6 RE
|
||||||
|
DEBUG("Getting %d from %d (fidx: %d, lp:%d)\n",REFSIGNAL_PILOT_IDX(i,l,ns,cell), SAMPLE_IDX(cell.nof_prb, nsymbol, fidx),
|
||||||
|
fidx, nsymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return LIBLTE_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return LIBLTE_ERROR_INVALID_INPUTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Ismael Gomez-Miguelez <ismael.gomez@tsc.upc.edu>.
|
||||||
|
* This file is part of ALOE++ (http://flexnets.upc.edu/)
|
||||||
|
*
|
||||||
|
* ALOE++ 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.
|
||||||
|
*
|
||||||
|
* ALOE++ 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with ALOE++. If not, see <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
|
||||||
|
*
|
||||||
|
* [estChannel] = liblte_chest(cell_id, nof_ports, inputSignal, (optional) sf_idx)
|
||||||
|
*
|
||||||
|
* Returns a matrix of size equal to the inputSignal matrix with the channel estimates
|
||||||
|
* for each resource element in inputSignal. The inputSignal matrix is the received Grid
|
||||||
|
* of size nof_resource_elements x nof_ofdm_symbols_in_subframe.
|
||||||
|
*
|
||||||
|
* The sf_idx is the subframe index only used if inputSignal is 1 subframe length.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CELLID prhs[0]
|
||||||
|
#define PORTS prhs[1]
|
||||||
|
#define INPUT prhs[2]
|
||||||
|
#define NOF_INPUTS 3
|
||||||
|
#define SFIDX prhs[3]
|
||||||
|
|
||||||
|
void help()
|
||||||
|
{
|
||||||
|
mexErrMsgTxt
|
||||||
|
("[estChannel] = liblte_chest(cell_id, nof_ports, inputSignal,[sf_idx])\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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the gateway function */
|
||||||
|
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
|
||||||
|
{
|
||||||
|
|
||||||
|
int i;
|
||||||
|
lte_cell_t cell;
|
||||||
|
chest_dl_t chest;
|
||||||
|
cf_t *input_signal;
|
||||||
|
cf_t *ce[MAX_PORTS];
|
||||||
|
double *outr0, *outi0, *outr1, *outi1;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
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) {
|
||||||
|
help();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX));
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
/* Create output values */
|
||||||
|
if (nlhs >= 1) {
|
||||||
|
plhs[0] = mxCreateDoubleMatrix(1,nof_re * nsubframes, 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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (nlhs >= 1) {
|
||||||
|
for (i=0;i<nof_re;i++) {
|
||||||
|
*outr0 = (double) crealf(ce[0][i]);
|
||||||
|
if (outi0) {
|
||||||
|
*outi0 = (double) cimagf(ce[0][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[j][i]);
|
||||||
|
if (outi1) {
|
||||||
|
*outi1 = (double) cimagf(chest.pilot_estimates[j][i]);
|
||||||
|
}
|
||||||
|
outr1++;
|
||||||
|
outi1++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
Binary file not shown.
@ -0,0 +1,213 @@
|
|||||||
|
%% LTE Downlink Channel Estimation and Equalization
|
||||||
|
|
||||||
|
%% Cell-Wide Settings
|
||||||
|
|
||||||
|
clear
|
||||||
|
|
||||||
|
SNR_values_db=15;%linspace(5,20,8);
|
||||||
|
Nrealizations=1;
|
||||||
|
|
||||||
|
preEVM = zeros(length(SNR_values_db),Nrealizations);
|
||||||
|
postEVM_mmse = zeros(length(SNR_values_db),Nrealizations);
|
||||||
|
postEVM_mmse2 = zeros(length(SNR_values_db),Nrealizations);
|
||||||
|
postEVM_zf = zeros(length(SNR_values_db),Nrealizations);
|
||||||
|
postEVM_zf2 = zeros(length(SNR_values_db),Nrealizations);
|
||||||
|
|
||||||
|
|
||||||
|
enb.NDLRB = 6; % Number of resource blocks
|
||||||
|
enb.CellRefP = 1; % One transmit antenna port
|
||||||
|
enb.NCellID = 0; % Cell ID
|
||||||
|
enb.CyclicPrefix = 'Normal'; % Normal cyclic prefix
|
||||||
|
enb.DuplexMode = 'FDD'; % FDD
|
||||||
|
|
||||||
|
%% Channel Model Configuration
|
||||||
|
rng(1); % Configure random number generators
|
||||||
|
|
||||||
|
cfg.Seed = 1; % Random channel seed
|
||||||
|
cfg.NRxAnts = 1; % 1 receive antenna
|
||||||
|
cfg.DelayProfile = 'EVA'; % EVA delay spread
|
||||||
|
cfg.DopplerFreq = 120; % 120Hz Doppler frequency
|
||||||
|
cfg.MIMOCorrelation = 'Low'; % Low (no) MIMO correlation
|
||||||
|
cfg.InitTime = 0; % Initialize at time zero
|
||||||
|
cfg.NTerms = 16; % Oscillators used in fading model
|
||||||
|
cfg.ModelType = 'GMEDS'; % Rayleigh fading model type
|
||||||
|
cfg.InitPhase = 'Random'; % Random initial phases
|
||||||
|
cfg.NormalizePathGains = 'On'; % Normalize delay profile power
|
||||||
|
cfg.NormalizeTxAnts = 'On'; % Normalize for transmit antennas
|
||||||
|
|
||||||
|
%% Channel Estimator Configuration
|
||||||
|
|
||||||
|
cec.FreqWindow = 9; % Frequency averaging window in
|
||||||
|
% Resource Elements (REs)
|
||||||
|
cec.TimeWindow = 9; % Time averaging window in REs
|
||||||
|
cec.InterpType = 'Cubic'; % Cubic interpolation
|
||||||
|
cec.PilotAverage = 'UserDefined'; % Pilot averaging method
|
||||||
|
cec.InterpWinSize = 3; % Interpolate up to 3 subframes
|
||||||
|
% simultaneously
|
||||||
|
cec.InterpWindow = 'Centred'; % Interpolation windowing method
|
||||||
|
|
||||||
|
cec2.FreqWindow = 9; % Frequency averaging window in
|
||||||
|
% Resource Elements (REs)
|
||||||
|
cec2.TimeWindow = 9; % Time averaging window in REs
|
||||||
|
cec2.InterpType = 'Linear'; % Cubic interpolation
|
||||||
|
cec2.PilotAverage = 'UserDefined'; % Pilot averaging method
|
||||||
|
cec2.InterpWinSize = 3; % Interpolate up to 3 subframes
|
||||||
|
% simultaneously
|
||||||
|
cec2.InterpWindow = 'Centered'; % Interpolation windowing method
|
||||||
|
|
||||||
|
%% Subframe Resource Grid Size
|
||||||
|
|
||||||
|
gridsize = lteDLResourceGridSize(enb);
|
||||||
|
K = gridsize(1); % Number of subcarriers
|
||||||
|
L = gridsize(2); % Number of OFDM symbols in one subframe
|
||||||
|
P = gridsize(3); % Number of transmit antenna ports
|
||||||
|
|
||||||
|
for nreal=1:Nrealizations
|
||||||
|
%% Transmit Resource Grid
|
||||||
|
txGrid = [];
|
||||||
|
|
||||||
|
%% Payload Data Generation
|
||||||
|
% Number of bits needed is size of resource grid (K*L*P) * number of bits
|
||||||
|
% per symbol (2 for QPSK)
|
||||||
|
numberOfBits = K*L*P*2;
|
||||||
|
|
||||||
|
% Create random bit stream
|
||||||
|
inputBits = randi([0 1], numberOfBits, 1);
|
||||||
|
|
||||||
|
% Modulate input bits
|
||||||
|
inputSym = lteSymbolModulate(inputBits,'QPSK');
|
||||||
|
|
||||||
|
%% Frame Generation
|
||||||
|
|
||||||
|
% For all subframes within the frame
|
||||||
|
for sf = 0:10
|
||||||
|
|
||||||
|
% Set subframe number
|
||||||
|
enb.NSubframe = mod(sf,10);
|
||||||
|
|
||||||
|
% Generate empty subframe
|
||||||
|
subframe = lteDLResourceGrid(enb);
|
||||||
|
|
||||||
|
% Map input symbols to grid
|
||||||
|
subframe(:) = inputSym;
|
||||||
|
|
||||||
|
% Generate synchronizing signals
|
||||||
|
pssSym = ltePSS(enb);
|
||||||
|
sssSym = lteSSS(enb);
|
||||||
|
pssInd = ltePSSIndices(enb);
|
||||||
|
sssInd = lteSSSIndices(enb);
|
||||||
|
|
||||||
|
% Map synchronizing signals to the grid
|
||||||
|
subframe(pssInd) = pssSym;
|
||||||
|
subframe(sssInd) = sssSym;
|
||||||
|
|
||||||
|
% Generate cell specific reference signal symbols and indices
|
||||||
|
cellRsSym = lteCellRS(enb);
|
||||||
|
cellRsInd = lteCellRSIndices(enb);
|
||||||
|
|
||||||
|
% Map cell specific reference signal to grid
|
||||||
|
subframe(cellRsInd) = cellRsSym;
|
||||||
|
|
||||||
|
% Append subframe to grid to be transmitted
|
||||||
|
txGrid = [txGrid subframe]; %#ok
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
%% OFDM Modulation
|
||||||
|
|
||||||
|
[txWaveform,info] = lteOFDMModulate(enb,txGrid);
|
||||||
|
txGrid = txGrid(:,1:140);
|
||||||
|
|
||||||
|
%% SNR Configuration
|
||||||
|
|
||||||
|
for snr_idx=1:length(SNR_values_db)
|
||||||
|
SNRdB = SNR_values_db(snr_idx); % Desired SNR in dB
|
||||||
|
SNR = 10^(SNRdB/20); % Linear SNR
|
||||||
|
|
||||||
|
|
||||||
|
%% Fading Channel
|
||||||
|
|
||||||
|
cfg.SamplingRate = info.SamplingRate;
|
||||||
|
|
||||||
|
% Pass data through the fading channel model
|
||||||
|
rxWaveform = lteFadingChannel(cfg,txWaveform);
|
||||||
|
|
||||||
|
%% Additive Noise
|
||||||
|
|
||||||
|
% Calculate noise gain
|
||||||
|
N0 = 1/(sqrt(2.0*enb.CellRefP*double(info.Nfft))*SNR);
|
||||||
|
|
||||||
|
% Create additive white Gaussian noise
|
||||||
|
noise = N0*complex(randn(size(rxWaveform)),randn(size(rxWaveform)));
|
||||||
|
|
||||||
|
% Add noise to the received time domain waveform
|
||||||
|
%rxWaveform = rxWaveform + noise;
|
||||||
|
|
||||||
|
%% Synchronization
|
||||||
|
|
||||||
|
offset = lteDLFrameOffset(enb,rxWaveform);
|
||||||
|
rxWaveform = rxWaveform(1+offset:end,:);
|
||||||
|
|
||||||
|
%% OFDM Demodulation
|
||||||
|
rxGrid = lteOFDMDemodulate(enb,rxWaveform);
|
||||||
|
%rxGrid = txGrid;
|
||||||
|
|
||||||
|
addpath('../../debug/lte/phy/lib/ch_estimation/test')
|
||||||
|
%% Channel Estimation
|
||||||
|
[estChannel, noiseEst, avg_ref1, noavg_ref1] = lteDLChannelEstimate2(enb,cec2,rxGrid);
|
||||||
|
[dumm, refs] = liblte_chest(enb.NCellID,enb.CellRefP,rxGrid);
|
||||||
|
%estChannel2=reshape(estChannel2,72,[]);
|
||||||
|
[estChannel2] = lteDLChannelEstimate3(enb,cec2,rxGrid,refs);
|
||||||
|
|
||||||
|
%error(snr_idx,nreal) = mean(mean(abs(avg_ref-transpose(refs)),2));
|
||||||
|
|
||||||
|
%% MMSE Equalization
|
||||||
|
eqGrid_mmse = lteEqualizeMMSE(rxGrid, estChannel, noiseEst);
|
||||||
|
eqGrid_mmse2 = lteEqualizeMMSE(rxGrid, estChannel2, noiseEst);
|
||||||
|
|
||||||
|
eqGrid_zf = lteEqualizeZF(rxGrid, estChannel);
|
||||||
|
eqGrid_zf2 = lteEqualizeZF(rxGrid, estChannel2);
|
||||||
|
|
||||||
|
%% Analysis
|
||||||
|
|
||||||
|
% Compute EVM across all input values
|
||||||
|
% EVM of pre-equalized receive signal
|
||||||
|
preEqualisedEVM = lteEVM(txGrid,rxGrid);
|
||||||
|
fprintf('%d-%d: Pre-EQ: %0.3f%%\n', ...
|
||||||
|
snr_idx,nreal,preEqualisedEVM.RMS*100);
|
||||||
|
|
||||||
|
%EVM of post-equalized receive signal
|
||||||
|
postEqualisedEVM_mmse = lteEVM(txGrid,eqGrid_mmse);
|
||||||
|
fprintf('%d-%d: MMSE: %0.3f%%\n', ...
|
||||||
|
snr_idx,nreal,postEqualisedEVM_mmse.RMS*100);
|
||||||
|
postEqualisedEVM_mmse2 = lteEVM(txGrid,eqGrid_mmse2);
|
||||||
|
fprintf('%d-%d: MMSE-lin: %0.3f%%\n', ...
|
||||||
|
snr_idx,nreal,postEqualisedEVM_mmse2.RMS*100);
|
||||||
|
|
||||||
|
|
||||||
|
postEqualisedEVM_zf = lteEVM(txGrid,eqGrid_zf);
|
||||||
|
fprintf('%d-%d: zf: %0.3f%%\n', ...
|
||||||
|
snr_idx,nreal,postEqualisedEVM_zf.RMS*100);
|
||||||
|
postEqualisedEVM_zf2 = lteEVM(txGrid,eqGrid_zf2);
|
||||||
|
fprintf('%d-%d: zf-linear: %0.3f%%\n', ...
|
||||||
|
snr_idx,nreal,postEqualisedEVM_zf2.RMS*100);
|
||||||
|
|
||||||
|
preEVM(snr_idx,nreal) =preEqualisedEVM.RMS;
|
||||||
|
postEVM_mmse(snr_idx,nreal) = postEqualisedEVM_mmse.RMS;
|
||||||
|
postEVM_mmse2(snr_idx,nreal) = postEqualisedEVM_mmse2.RMS;
|
||||||
|
postEVM_zf(snr_idx,nreal) = postEqualisedEVM_zf.RMS;
|
||||||
|
postEVM_zf2(snr_idx,nreal) = postEqualisedEVM_zf2.RMS;
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
plot(SNR_values_db, mean(preEVM,2), ...
|
||||||
|
SNR_values_db, mean(postEVM_mmse,2), ...
|
||||||
|
SNR_values_db, mean(postEVM_mmse2,2), ...
|
||||||
|
SNR_values_db, mean(postEVM_zf,2), ...
|
||||||
|
SNR_values_db, mean(postEVM_zf2,2))
|
||||||
|
legend('No Eq','MMSE','MMSE-linear','ZF','ZF-linear')
|
||||||
|
%plot(SNR_values_db, mean(error,2))
|
||||||
|
grid on
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue