mirror of https://github.com/pvnis/srsRAN_4G.git
Initial commit
commit
0737f1e615
@ -0,0 +1,42 @@
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "Prevented in-tree build. This is bad practice.")
|
||||
endif(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (osldlib)
|
||||
|
||||
|
||||
# The version number.
|
||||
set (OSLDLIB_VERSION_MAJOR 0)
|
||||
set (OSLDLIB_VERSION_MINOR 0)
|
||||
|
||||
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${OSLDLIB_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OSLDLIB_VERSION_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH "1")
|
||||
set(CPACK_SOURCE_GENERATOR "TBZ2")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME
|
||||
"${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||
set(CPACK_SOURCE_IGNORE_FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR};/.bzr/;~$;${CPACK_SOURCE_IGNORE_FILES}")
|
||||
include(CPack)
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
|
||||
|
||||
option(DEBUG "Compiles with debugging symbols and no optimizations" OFF)
|
||||
|
||||
if(DEBUG)
|
||||
message("-- Configuring debugging CFLAGS")
|
||||
set(CFDEB "-O0 -g -rdynamic")
|
||||
else()
|
||||
set(CFDEB "-O2")
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CFDEB} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE")
|
||||
set(CMAKE_BINARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
### INCLUDES
|
||||
include_directories("{CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
add_subdirectory(examples)
|
||||
add_subdirectory(lib)
|
||||
|
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
@ -0,0 +1,24 @@
|
||||
osld-lib
|
||||
========
|
||||
|
||||
OSLD-lib is a free and open-source LTE library for SDR UE and eNodeB. The library does not rely on any external dependencies or frameworks.
|
||||
|
||||
|
||||
The project contains a set of Python tools for the automatic code generation of modules for popular SDR frameworks, including GNURadio, ALOE++, IRIS, and OSSIE. These tools are easy to use and adapt for generating targets for specific platforms or frameworks.
|
||||
|
||||
The DSP modules are based on OSLD (https://github.com/flexnets/aloe).
|
||||
|
||||
## Examples
|
||||
|
||||
Currently, only PSS/SSS decoding is available:
|
||||
|
||||
|
||||
'
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../
|
||||
make
|
||||
examples/synch_test -i ../lte_signal.txt -N 0
|
||||
'
|
||||
|
||||
Searches for an N_id_2 PSS/SSS signal in the provided file.
|
@ -0,0 +1,22 @@
|
||||
# - Find FFTW
|
||||
# Find the native FFTW includes and library
|
||||
#
|
||||
# FFTW_INCLUDES - where to find fftw3.h
|
||||
# FFTW_LIBRARIES - List of libraries when using FFTW.
|
||||
# FFTW_FOUND - True if FFTW found.
|
||||
|
||||
if (FFTWS_INCLUDES)
|
||||
# Already in cache, be silent
|
||||
set (FFTWS_FIND_QUIETLY TRUE)
|
||||
endif (FFTWS_INCLUDES)
|
||||
|
||||
find_path (FFTWS_INCLUDES fftw3.h)
|
||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
find_library (FFTWfS_LIBRARIES NAMES fftw3f)
|
||||
find_library (FFTWnS_LIBRARIES NAMES fftw3)
|
||||
set(FFTWS_LIBRARIES ${FFTWfS_LIBRARIES} ${FFTWnS_LIBRARIES})
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args (FFTWS DEFAULT_MSG FFTWS_LIBRARIES FFTWS_INCLUDES)
|
||||
|
||||
mark_as_advanced (FFTWS_LIBRARIES FFTWS_INCLUDES)
|
@ -0,0 +1,26 @@
|
||||
INCLUDE(FindPkgConfig)
|
||||
PKG_CHECK_MODULES(UHD uhd)
|
||||
IF(NOT UHD_FOUND)
|
||||
|
||||
FIND_PATH(
|
||||
UHD_INCLUDE_DIRS
|
||||
NAMES uhd/config.hpp
|
||||
HINTS $ENV{UHD_DIR}/include
|
||||
PATHS /usr/local/include
|
||||
/usr/include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(
|
||||
UHD_LIBRARIES
|
||||
NAMES uhd
|
||||
HINTS $ENV{UHD_DIR}/lib
|
||||
PATHS /usr/local/lib
|
||||
/usr/lib
|
||||
/usr/local/lib64
|
||||
/usr/local/lib32
|
||||
)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(UHD DEFAULT_MSG UHD_LIBRARIES UHD_INCLUDE_DIRS)
|
||||
|
||||
ENDIF(NOT UHD_FOUND)
|
@ -0,0 +1,49 @@
|
||||
#include fftw3 directories
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/")
|
||||
|
||||
find_package(FFTWS REQUIRED)
|
||||
include_directories(${FFTWS_INCLUDE_DIRS})
|
||||
|
||||
find_package(UHD)
|
||||
|
||||
|
||||
set(LIBRARIES osld m ${FFTWS_LIBRARIES})
|
||||
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
||||
|
||||
add_executable(hl_example hl_example.c)
|
||||
target_link_libraries(hl_example ${LIBRARIES})
|
||||
|
||||
add_executable(ll_example ll_example.c)
|
||||
target_link_libraries(ll_example ${LIBRARIES})
|
||||
|
||||
add_executable(synch_test synch_test.c)
|
||||
target_link_libraries(synch_test ${LIBRARIES})
|
||||
|
||||
add_executable(equalizer_test equalizer_test.c)
|
||||
target_link_libraries(equalizer_test ${LIBRARIES})
|
||||
|
||||
add_executable(viterbi_test viterbi_test.c)
|
||||
target_link_libraries(viterbi_test ${LIBRARIES})
|
||||
|
||||
add_executable(bch_test bch_test.c)
|
||||
target_link_libraries(bch_test ${LIBRARIES})
|
||||
|
||||
add_executable(cell_search cell_search.c)
|
||||
target_link_libraries(cell_search ${LIBRARIES})
|
||||
|
||||
|
||||
include_directories(${UHD_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../uhd)
|
||||
add_executable(rssi_scan_usrp rssi_scan_usrp.c ../uhd/uhd_imp.cpp ../uhd/uhd_utils.c)
|
||||
target_link_libraries(rssi_scan_usrp ${LIBRARIES} ${UHD_LIBRARIES})
|
||||
|
||||
|
||||
include_directories(${UHD_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/../uhd)
|
||||
add_executable(pss_scan_usrp pss_scan_usrp.c ../uhd/uhd_imp.cpp ../uhd/uhd_utils.c)
|
||||
target_link_libraries(pss_scan_usrp ${LIBRARIES} ${UHD_LIBRARIES})
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,130 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
char *input_file_name;
|
||||
int frame_length=1920, symbol_sz=128, nof_slots=1;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [ls] -i input_file\n", prog);
|
||||
printf("\t-l frame_length [Default %d]\n", frame_length);
|
||||
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
|
||||
printf("\t-n nof_frames [Default %d]\n", nof_slots);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "ilsnv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'l':
|
||||
frame_length = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
symbol_sz = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!input_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void fft_run_slot(dft_plan_t *fft_plan, cf_t *input, cf_t *output) {
|
||||
int i;
|
||||
for (i=0;i<7;i++) {
|
||||
input += CP_NORM(i, symbol_sz);
|
||||
dft_run_c2c(fft_plan, input, output);
|
||||
input += symbol_sz;
|
||||
output += symbol_sz;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
filesource_t fsrc;
|
||||
pbch_mib_t pbch_data;
|
||||
pbch_t pbch;
|
||||
dft_plan_t fft_plan;
|
||||
|
||||
int frame_cnt;
|
||||
cf_t *input, *outfft;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT)) {
|
||||
fprintf(stderr, "Error opening file %s\n", input_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
input = malloc(frame_length*sizeof(cf_t));
|
||||
if (!input) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
outfft = malloc(7*symbol_sz*sizeof(cf_t));
|
||||
if (!outfft) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* Init FFT plan */
|
||||
if (dft_plan_c2c(symbol_sz, FORWARD, &fft_plan)) {
|
||||
fprintf(stderr, "Error initiating FFT plan\n");
|
||||
exit(-1);
|
||||
}
|
||||
fft_plan.options = DFT_DC_OFFSET | DFT_MIRROR_POS | DFT_NORMALIZE;
|
||||
|
||||
if (pbch_init(&pbch, 0, CPNORM)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
exit(-1);
|
||||
}
|
||||
int res = 0;
|
||||
frame_cnt = 0;
|
||||
while (frame_length == filesource_read(&fsrc, input, frame_length)
|
||||
&& frame_cnt < nof_slots
|
||||
&& res == 0) {
|
||||
|
||||
fft_run_slot(&fft_plan, &input[960], outfft);
|
||||
|
||||
res = pbch_decode(&pbch, outfft, &pbch_data, 6, 1);
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "Error decoding PBCH\n");
|
||||
break;
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
|
||||
if (res == 1) {
|
||||
printf("MIB found\n");
|
||||
} else {
|
||||
printf("MIB not found after %d frames\n", frame_cnt);
|
||||
}
|
||||
|
||||
pbch_free(&pbch);
|
||||
free(input);
|
||||
free(outfft);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
char *input_file_name = NULL;
|
||||
int nof_slots=100;
|
||||
float corr_peak_threshold=2.5;
|
||||
int ntime = 4;
|
||||
int nfreq = 10;
|
||||
int file_binary = 0;
|
||||
int force_N_id_2=-1;
|
||||
|
||||
filesource_t fsrc;
|
||||
cf_t *input_buffer, *fft_buffer;
|
||||
pbch_t pbch;
|
||||
dft_plan_t fft_plan;
|
||||
chest_t chest;
|
||||
sync_t synch;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [onlt] -i input_file\n", prog);
|
||||
printf("\t-n number of frames [Default %d]\n", nof_slots);
|
||||
printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
printf("\t-b Input files is binary [Default %s]\n", file_binary?"yes":"no");
|
||||
printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "intvbf")) != -1) {
|
||||
switch(opt) {
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
corr_peak_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'b':
|
||||
file_binary = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
case 'f':
|
||||
force_N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!input_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int base_init() {
|
||||
file_data_type_t type = file_binary?COMPLEX_FLOAT_BIN:COMPLEX_FLOAT;
|
||||
if (filesource_init(&fsrc, input_file_name, type)) {
|
||||
fprintf(stderr, "Error opening file %s\n", input_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
input_buffer = malloc(4 * 960 * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
fft_buffer = malloc(CPNORM_NSYMB * 128 * sizeof(cf_t));
|
||||
if (!fft_buffer) {
|
||||
perror("malloc");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Init FFT plan */
|
||||
if (dft_plan_c2c(128, FORWARD, &fft_plan)) {
|
||||
fprintf(stderr, "Error initiating FFT plan\n");
|
||||
return -1;
|
||||
}
|
||||
fft_plan.options = DFT_DC_OFFSET | DFT_MIRROR_POS | DFT_NORMALIZE;
|
||||
|
||||
DEBUG("Memory init OK\n",0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mib_decoder_init(int cell_id) {
|
||||
|
||||
/*
|
||||
if (chest_LTEDL_init(&chest, ntime, nfreq, CPNORM_NSYMB, cell_id, 6)) {
|
||||
fprintf(stderr, "Error initiating LTE equalizer\n");
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
|
||||
DEBUG("Channel estimation initiated ntime=%d nfreq=%d\n", ntime, nfreq);
|
||||
|
||||
if (pbch_init(&pbch, cell_id, CPNORM)) {
|
||||
fprintf(stderr, "Error initiating PBCH\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fft_run_slot(dft_plan_t *fft_plan, cf_t *input, cf_t *output) {
|
||||
int i;
|
||||
for (i=0;i<CPNORM_NSYMB;i++) {
|
||||
DEBUG("Running FFT %d\n", i);
|
||||
input += CP_NORM(i, 128);
|
||||
dft_run_c2c(fft_plan, input, output);
|
||||
input += 128;
|
||||
output += 128;
|
||||
}
|
||||
}
|
||||
|
||||
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
|
||||
fft_run_slot(&fft_plan, input, fft_buffer);
|
||||
DEBUG("Decoding PBCH\n", 0);
|
||||
return pbch_decode(&pbch, fft_buffer, mib, 6, 1);
|
||||
}
|
||||
|
||||
int get_samples(int length, int offset) {
|
||||
int n = 0;
|
||||
if (length != -1 && offset != -1) {
|
||||
while(n < length) {
|
||||
DEBUG("Reading %d samples offset=%d\n", length - n, offset + n);
|
||||
n = filesource_read(&fsrc, &input_buffer[offset + n], length - n);
|
||||
if (n == -1) {
|
||||
fprintf(stderr, "Error reading %d samples from file\n", length - n);
|
||||
break;
|
||||
} else if (n == 0) {
|
||||
printf("End of file\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
enum radio_state { DONE, SYNC, MIB};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
enum radio_state state;
|
||||
int sf_size, slot_start;
|
||||
int read_length, slot_idx;
|
||||
int mib_attempts;
|
||||
pbch_mib_t mib;
|
||||
int cell_id;
|
||||
int idx;
|
||||
int frame_cnt;
|
||||
int read_offset;
|
||||
float cfo;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init()) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (sync_init(&synch)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
sync_force_N_id_2(&synch, force_N_id_2);
|
||||
sync_set_threshold(&synch, corr_peak_threshold);
|
||||
|
||||
state = SYNC;
|
||||
sf_size = 960;
|
||||
read_length = sf_size;
|
||||
slot_start = 0;
|
||||
slot_idx = 0;
|
||||
mib_attempts = 0;
|
||||
frame_cnt = -1;
|
||||
read_offset = 0;
|
||||
cfo = 0.0;
|
||||
|
||||
printf("\n\n-- Initiating MIB search --\n\n");
|
||||
|
||||
while(state != DONE && frame_cnt < nof_slots) {
|
||||
if (get_samples(read_length, read_offset) == -1) {
|
||||
fprintf(stderr, "Error reading %d samples sf_start=%d\n", read_length, slot_start);
|
||||
break;
|
||||
}
|
||||
if (read_length) {
|
||||
frame_cnt++;
|
||||
INFO("\n\tSlot idx=%d\n\n", slot_idx);
|
||||
INFO("Correcting CFO=%.4f\n", cfo);
|
||||
nco_cexp_f_direct(&input_buffer[read_offset], -cfo/128, read_length);
|
||||
}
|
||||
switch(state) {
|
||||
case SYNC:
|
||||
INFO("State Sync, Slot idx=%d\n", slot_idx);
|
||||
idx = sync_run(&synch, input_buffer, read_offset);
|
||||
if (idx != -1) {
|
||||
slot_start = read_offset + idx;
|
||||
read_length = idx;
|
||||
read_offset += 960;
|
||||
cell_id = sync_get_cell_id(&synch);
|
||||
cfo = sync_get_cfo(&synch);
|
||||
slot_idx = sync_get_slot_id(&synch);
|
||||
state = MIB;
|
||||
if (mib_decoder_init(cell_id)) {
|
||||
fprintf(stderr, "Error initiating MIB decoder\n");
|
||||
exit(-1);
|
||||
}
|
||||
INFO("SYNC done, cell_id=%d slot_start=%d\n", cell_id, slot_start);
|
||||
} else {
|
||||
read_offset = 960;
|
||||
memcpy(input_buffer, &input_buffer[960], 960 * sizeof(cf_t));
|
||||
}
|
||||
break;
|
||||
case MIB:
|
||||
read_length = 960;
|
||||
read_offset = slot_start;
|
||||
INFO("State MIB, Slot idx=%d\n", slot_idx);
|
||||
if (slot_idx == 1) {
|
||||
INFO("Trying to find MIB offset %d\n", slot_start);
|
||||
if (mib_decoder_run(&input_buffer[slot_start], &mib)) {
|
||||
INFO("MIB detected attempt=%d\n", mib_attempts);
|
||||
state = DONE;
|
||||
} else {
|
||||
INFO("MIB not detected attempt=%d\n", mib_attempts);
|
||||
if (mib_attempts >= 4) {
|
||||
state = SYNC;
|
||||
}
|
||||
}
|
||||
mib_attempts++;
|
||||
}
|
||||
break;
|
||||
case DONE:
|
||||
INFO("State Done, Slot idx=%d\n", slot_idx);
|
||||
pbch_mib_fprint(stdout, &mib);
|
||||
printf("Done\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (read_length) {
|
||||
slot_idx++;
|
||||
if (slot_idx == 20) {
|
||||
slot_idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sync_free(&synch);
|
||||
filesource_close(&fsrc);
|
||||
|
||||
free(input_buffer);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
# - Find FFTW
|
||||
# Find the native FFTW includes and library
|
||||
#
|
||||
# FFTW_INCLUDES - where to find fftw3.h
|
||||
# FFTW_LIBRARIES - List of libraries when using FFTW.
|
||||
# FFTW_FOUND - True if FFTW found.
|
||||
|
||||
if (FFTWS_INCLUDES)
|
||||
# Already in cache, be silent
|
||||
set (FFTWS_FIND_QUIETLY TRUE)
|
||||
endif (FFTWS_INCLUDES)
|
||||
|
||||
find_path (FFTWS_INCLUDES fftw3.h)
|
||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a)
|
||||
find_library (FFTWfS_LIBRARIES NAMES fftw3f)
|
||||
find_library (FFTWnS_LIBRARIES NAMES fftw3)
|
||||
set(FFTWS_LIBRARIES ${FFTWfS_LIBRARIES} ${FFTWnS_LIBRARIES})
|
||||
|
||||
include (FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args (FFTWS DEFAULT_MSG FFTWS_LIBRARIES FFTWS_INCLUDES)
|
||||
|
||||
mark_as_advanced (FFTWS_LIBRARIES FFTWS_INCLUDES)
|
@ -0,0 +1,175 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
char *input_file_name;
|
||||
int nof_slots=1;
|
||||
int cell_id = 0;
|
||||
int port_id = 0;
|
||||
int nof_prb = 6;
|
||||
lte_cp_t cp = CPNORM;
|
||||
int file_binary = 0;
|
||||
|
||||
int in_slot_length() {
|
||||
if (CP_ISNORM(cp)) {
|
||||
return SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb));
|
||||
} else {
|
||||
return SLOT_LEN_CPEXT(lte_symbol_sz(nof_prb));
|
||||
}
|
||||
}
|
||||
|
||||
int slot_length() {
|
||||
return CP_NSYMB(cp)*lte_symbol_sz(nof_prb);
|
||||
}
|
||||
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [bncprev] -i input_file\n", prog);
|
||||
printf("\t-b input file is binary [Default no]\n");
|
||||
printf("\t-n number of slots [Default %d]\n", nof_slots);
|
||||
printf("\t-c cell_id [Default %d]\n", cell_id);
|
||||
printf("\t-p port_id [Default %d]\n", port_id);
|
||||
printf("\t-r nof_prb [Default %d]\n", nof_prb);
|
||||
printf("\t-e [extended cyclic prefix, Default normal]\n");
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "bincprev")) != -1) {
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
file_binary = 1;
|
||||
break;
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
cell_id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'p':
|
||||
port_id = atoi(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
nof_prb = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
cp = CPEXT;
|
||||
break;
|
||||
case 'v':
|
||||
PRINT_DEBUG;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!input_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
filesource_t fsrc;
|
||||
lte_fft_t fft;
|
||||
FILE *f = NULL;
|
||||
chest_t eq;
|
||||
int slot_cnt;
|
||||
cf_t *input = NULL;
|
||||
cf_t *outfft = NULL;
|
||||
cf_t *ce = NULL;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (filesource_init(&fsrc, input_file_name, file_binary?COMPLEX_FLOAT_BIN:COMPLEX_FLOAT)) {
|
||||
fprintf(stderr, "Error opening file %s\n", input_file_name);
|
||||
goto do_exit;
|
||||
}
|
||||
f = fopen("output.m", "w");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
input = malloc(in_slot_length()*sizeof(cf_t));
|
||||
if (!input) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
outfft = malloc(slot_length()*sizeof(cf_t));
|
||||
if (!outfft) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
ce = malloc(nof_prb * RE_X_RB * CP_NSYMB(cp) * sizeof(cf_t));
|
||||
if (!ce) {
|
||||
perror("malloc");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
if (lte_fft_init(&fft, cp, lte_symbol_sz(nof_prb))) {
|
||||
fprintf(stderr, "Error: initializing FFT\n");
|
||||
goto do_exit;
|
||||
}
|
||||
if (chest_init(&eq, cp, nof_prb, 1)) {
|
||||
fprintf(stderr, "Error initializing equalizer\n");
|
||||
goto do_exit;
|
||||
}
|
||||
if (chest_ref_LTEDL(&eq, cell_id)) {
|
||||
fprintf(stderr, "Error initializing reference signal\n");
|
||||
goto do_exit;
|
||||
}
|
||||
|
||||
bzero(input, sizeof(cf_t) * in_slot_length());
|
||||
bzero(outfft, sizeof(cf_t) * slot_length());
|
||||
|
||||
/* read all file or nof_slots */
|
||||
slot_cnt = 0;
|
||||
while (in_slot_length() == filesource_read(&fsrc, input, in_slot_length())
|
||||
&& (slot_cnt < nof_slots || nof_slots == -1)) {
|
||||
|
||||
lte_fft_run(&fft, input, outfft);
|
||||
|
||||
chest_ce_slot_port(&eq, outfft, ce, slot_cnt%20, 0);
|
||||
|
||||
chest_fprint(&eq, f, slot_cnt%20, 0);
|
||||
|
||||
fprintf(f, "ce=[");
|
||||
vec_fprint_c(f, ce, nof_prb * RE_X_RB * CP_NSYMB(cp));
|
||||
fprintf(f, "];\n");
|
||||
|
||||
slot_cnt++;
|
||||
}
|
||||
|
||||
do_exit:
|
||||
chest_free(&eq);
|
||||
lte_fft_free(&fft);
|
||||
if (ce) {
|
||||
free(ce);
|
||||
}
|
||||
if (outfft) {
|
||||
free(outfft);
|
||||
}
|
||||
if (input) {
|
||||
free(input);
|
||||
}
|
||||
if (f) {
|
||||
fclose(f);
|
||||
}
|
||||
filesource_close(&fsrc);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
void usage(char *arg) {
|
||||
printf("Usage: %s nbits snr_db\n",arg);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
binsource_hl bs;
|
||||
mod_hl mod;
|
||||
ch_awgn_hl ch;
|
||||
demod_soft_hl demod_s;
|
||||
demod_hard_hl demod_h;
|
||||
|
||||
bzero(&bs,sizeof(bs));
|
||||
bzero(&mod,sizeof(mod));
|
||||
bzero(&ch,sizeof(ch));
|
||||
bzero(&demod_s,sizeof(demod_s));
|
||||
bzero(&demod_h,sizeof(demod_h));
|
||||
|
||||
if (argc<3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int nbits = atoi(argv[1]);
|
||||
float snr_db = atof(argv[2]);
|
||||
float var = sqrt(pow(10,-snr_db/10));
|
||||
|
||||
bs.init.seed = 0;
|
||||
bs.init.cache_seq_nbits = 0;
|
||||
bs.ctrl_in.nbits = nbits;
|
||||
bs.output = malloc(nbits);
|
||||
|
||||
mod.in_len = nbits;
|
||||
mod.init.std = LTE_BPSK;
|
||||
mod.input = bs.output;
|
||||
mod.output = malloc(nbits*sizeof(_Complex float));
|
||||
|
||||
ch.in_len = nbits;
|
||||
ch.input = mod.output;
|
||||
ch.ctrl_in.variance = var;
|
||||
ch.output = malloc(nbits*sizeof(_Complex float));
|
||||
|
||||
demod_h.in_len = nbits;
|
||||
demod_h.init.std = LTE_BPSK;
|
||||
demod_h.input = ch.output;
|
||||
demod_h.output = malloc(nbits);
|
||||
|
||||
demod_s.in_len = nbits;
|
||||
demod_s.init.std = LTE_BPSK;
|
||||
demod_s.input = ch.output;
|
||||
demod_s.output = malloc(sizeof(float)*nbits);
|
||||
demod_s.ctrl_in.alg_type = APPROX;
|
||||
demod_s.ctrl_in.sigma = var;
|
||||
|
||||
if ( binsource_initialize(&bs) ||
|
||||
mod_initialize(&mod) ||
|
||||
ch_awgn_initialize(&ch) ||
|
||||
demod_hard_initialize(&demod_h) ||
|
||||
demod_soft_initialize(&demod_s)
|
||||
) {
|
||||
printf("Error initializing modules\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
binsource_work(&bs);
|
||||
mod_work(&mod);
|
||||
ch_awgn_work(&ch);
|
||||
demod_hard_work(&demod_h);
|
||||
demod_soft_work(&demod_s);
|
||||
|
||||
/* hard decision for soft demodulation */
|
||||
char* tmp = malloc(nbits);
|
||||
for (int i=0;i<nbits;i++) {
|
||||
tmp[i] = demod_s.output[i]>0?1:0;
|
||||
}
|
||||
|
||||
printf("Hard errors: %u/%d\n",bit_diff(bs.output,demod_h.output,nbits),nbits);
|
||||
printf("Soft errors: %u/%d\n",bit_diff(bs.output,tmp,nbits),nbits);
|
||||
|
||||
free(bs.output);
|
||||
free(mod.output);
|
||||
free(ch.output);
|
||||
free(demod_h.output);
|
||||
free(demod_s.output);
|
||||
free(tmp);
|
||||
|
||||
printf("Exit\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
binsource_t bs;
|
||||
char* output;
|
||||
|
||||
binsource_init(&bs);
|
||||
binsource_seed_time(&bs);
|
||||
|
||||
output = malloc(100);
|
||||
|
||||
if (binsource_generate(&bs,output,100)) {
|
||||
printf("Error generating bits\n");
|
||||
exit(-1);
|
||||
}
|
||||
printf("output: ");
|
||||
bit_fprint(stdout,output,100);
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,350 @@
|
||||
#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 "lte.h"
|
||||
|
||||
#include "uhd.h"
|
||||
#include "uhd_utils.h"
|
||||
|
||||
int nof_slots=1000;
|
||||
int band, earfcn=-1;
|
||||
float pss_threshold=15.0;
|
||||
int earfcn_start, earfcn_end = -1;
|
||||
float rssi_threshold = -42.0;
|
||||
|
||||
cf_t *input_buffer;
|
||||
float *cfo_v;
|
||||
int *idx_v;
|
||||
float *p2a_v;
|
||||
void *uhd;
|
||||
int nof_bands;
|
||||
int force_N_id_2;
|
||||
float gain = 30.0;
|
||||
|
||||
#define MAX_EARFCN 1000
|
||||
lte_earfcn_t channels[MAX_EARFCN];
|
||||
float rssi[MAX_EARFCN];
|
||||
float freqs[MAX_EARFCN];
|
||||
float cfo[MAX_EARFCN];
|
||||
float p2a[MAX_EARFCN];
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
#define RSSI_FS 1000000
|
||||
#define RSSI_NSAMP 50000
|
||||
#define FLEN 9600
|
||||
#define FLEN_PERIOD 0.005
|
||||
|
||||
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
|
||||
|
||||
void print_to_matlab();
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [senvtr] -b band\n", prog);
|
||||
printf("\t-s earfcn_start [Default %d]\n", earfcn_start);
|
||||
printf("\t-e earfcn_end [Default All]\n");
|
||||
printf("\t-n number of frames [Default %d]\n", nof_slots);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
printf("\t-t pss_threshold [Default %.2f]\n", pss_threshold);
|
||||
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
|
||||
printf("\t-f force_N_id_2 [Default no]\n");
|
||||
printf("\t-g gain [Default no %.2f dB]\n", gain);
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "gfrtbsenv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'g':
|
||||
gain = atof(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
force_N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
pss_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 'r':
|
||||
rssi_threshold = -atof(argv[optind]);
|
||||
break;
|
||||
case 'b':
|
||||
band = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
earfcn_start = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
earfcn_end = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int base_init(int frame_length) {
|
||||
|
||||
input_buffer = malloc(2 * frame_length * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
idx_v = malloc(nof_slots * sizeof(int));
|
||||
if (!idx_v) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
cfo_v = malloc(nof_slots * sizeof(float));
|
||||
if (!cfo_v) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
p2a_v = malloc(nof_slots * sizeof(float));
|
||||
if (!p2a_v) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
bzero(cfo, sizeof(float) * MAX_EARFCN);
|
||||
bzero(p2a, sizeof(float) * MAX_EARFCN);
|
||||
|
||||
/* open UHD device */
|
||||
printf("Opening UHD device...\n");
|
||||
if (uhd_open("",&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void base_free() {
|
||||
|
||||
uhd_close(&uhd);
|
||||
free(input_buffer);
|
||||
free(idx_v);
|
||||
free(cfo_v);
|
||||
free(p2a_v);
|
||||
}
|
||||
|
||||
float mean_valid(int *idx_v, float *x, int nof_frames) {
|
||||
int i;
|
||||
float mean = 0;
|
||||
int n = 0;
|
||||
for (i=0;i<nof_frames;i++) {
|
||||
if (idx_v[i] != -1) {
|
||||
mean += x[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
return mean/n;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt;
|
||||
int i;
|
||||
int nsamples;
|
||||
int cell_id;
|
||||
sync_t synch;
|
||||
float max_peak_to_avg;
|
||||
float sfo;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init(FLEN)) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (sync_init(&synch)) {
|
||||
fprintf(stderr, "Error initiating PSS/SSS\n");
|
||||
exit(-1);
|
||||
}
|
||||
sync_set_threshold(&synch, pss_threshold);
|
||||
sync_pss_det_peakmean(&synch);
|
||||
|
||||
if (force_N_id_2 != -1) {
|
||||
sync_force_N_id_2(&synch, force_N_id_2);
|
||||
}
|
||||
|
||||
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
|
||||
printf("RSSI scan: %d freqs in band %d\n", nof_bands, band);
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
freqs[i] = channels[i].fd * MHZ;
|
||||
}
|
||||
|
||||
|
||||
if (uhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, RSSI_NSAMP)) {
|
||||
fprintf(stderr, "Error while doing RSSI scan\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("\nDone. Starting PSS search\n");
|
||||
usleep(500000);
|
||||
printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
uhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
|
||||
uhd_set_rx_gain(uhd, gain);
|
||||
|
||||
print_to_matlab();
|
||||
|
||||
int first = 1;
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
/* scan only bands above rssi_threshold */
|
||||
if (IS_SIGNAL(i)) {
|
||||
uhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ);
|
||||
uhd_rx_wait_lo_locked(uhd);
|
||||
|
||||
if (first) {
|
||||
INFO("Starting receiver...\n",0);
|
||||
uhd_start_rx_stream(uhd);
|
||||
first = 0;
|
||||
}
|
||||
|
||||
frame_cnt = 0;
|
||||
nsamples = 0;
|
||||
max_peak_to_avg = -99;
|
||||
nsamples += uhd_recv(uhd, input_buffer, FLEN, 1);
|
||||
cell_id = -1;
|
||||
while(frame_cnt < nof_slots) {
|
||||
if (frame_cnt) {
|
||||
nsamples += uhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
|
||||
}
|
||||
|
||||
idx_v[frame_cnt] = sync_run(&synch, input_buffer, frame_cnt?FLEN:0);
|
||||
p2a_v[frame_cnt] = sync_get_peak_to_avg(&synch);
|
||||
if (idx_v[frame_cnt] != -1) {
|
||||
/* save cell id for the best peak-to-avg */
|
||||
if (p2a_v[frame_cnt] > max_peak_to_avg) {
|
||||
max_peak_to_avg = p2a_v[frame_cnt];
|
||||
cell_id = sync_get_cell_id(&synch);
|
||||
}
|
||||
cfo_v[frame_cnt] = sync_get_cfo(&synch);
|
||||
} else {
|
||||
cfo_v[frame_cnt] = 0.0;
|
||||
}
|
||||
if (frame_cnt) {
|
||||
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
|
||||
}
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("[%4d] - idx: %5d\tpeak-to-avg: %3.2f\tcfo=%.3f\r", frame_cnt,
|
||||
idx_v[frame_cnt], p2a_v[frame_cnt], cfo_v[frame_cnt]);
|
||||
}
|
||||
frame_cnt++;
|
||||
}
|
||||
|
||||
cfo[i] = mean_valid(idx_v, cfo_v, nof_slots);
|
||||
p2a[i] = sum_r(p2a_v, nof_slots) / nof_slots;
|
||||
if (channels[i].id == 1900
|
||||
|| channels[i].id == 1901) {
|
||||
vec_fprint_i(stdout, idx_v, nof_slots);
|
||||
}
|
||||
|
||||
sfo = sfo_estimate(idx_v, nof_slots, FLEN_PERIOD);
|
||||
if (VERBOSE_ISINFO()) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz, "
|
||||
"RSSI %3.2f dBm, PSS %2.2f dB, CFO=%+2.1f KHz, SFO=%+2.1f KHz, CELL_ID=%3d\n", i, nof_bands,
|
||||
channels[i].id, channels[i].fd, 10*log10f(rssi[i]) + 30,
|
||||
10*log10f(p2a[i]), cfo[i] * 15, sfo / 1000, cell_id);
|
||||
print_to_matlab();
|
||||
|
||||
} else {
|
||||
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz. RSSI below threshold (%3.2f < %3.2f dBm)\n",
|
||||
i, nof_bands, channels[i].id, channels[i].fd, 10*log10f(rssi[i]) + 30, rssi_threshold);
|
||||
}
|
||||
}
|
||||
|
||||
print_to_matlab();
|
||||
|
||||
sync_free(&synch);
|
||||
base_free();
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void print_to_matlab() {
|
||||
int i;
|
||||
|
||||
FILE *f = fopen("output.m", "w");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(f, "fd=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", channels[i].fd);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
fprintf(f, "rssi=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", rssi[i]);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
/*
|
||||
fprintf(f, "cfo=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
if (IS_SIGNAL(i)) {
|
||||
fprintf(f, "%g, ", cfo[i]);
|
||||
} else {
|
||||
fprintf(f, "NaN, ");
|
||||
}
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
*/
|
||||
fprintf(f, "p2a=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
if (IS_SIGNAL(i)) {
|
||||
fprintf(f, "%g, ", p2a[i]);
|
||||
} else {
|
||||
fprintf(f, "0, ");
|
||||
}
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
fprintf(f, "clf;\n\n");
|
||||
fprintf(f, "subplot(1,2,1)\n");
|
||||
fprintf(f, "plot(fd, 10*log10(rssi)+30)\n");
|
||||
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('RSSI [dBm]');\n");
|
||||
fprintf(f, "title('RSSI Estimation')\n");
|
||||
|
||||
fprintf(f, "subplot(1,2,2)\n");
|
||||
fprintf(f, "plot(fd, p2a)\n");
|
||||
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel('Peak-to-Avg [dB]');\n");
|
||||
fprintf(f, "title('PSS Correlation')\n");
|
||||
/*
|
||||
fprintf(f, "subplot(1,3,3)\n");
|
||||
fprintf(f, "plot(fd, cfo)\n");
|
||||
fprintf(f, "grid on; xlabel('f [Mhz]'); ylabel(''); axis([min(fd) max(fd) -0.5 0.5]);\n");
|
||||
fprintf(f, "title('CFO Estimation')\n");
|
||||
*/
|
||||
fprintf(f, "drawnow;\n");
|
||||
fclose(f);
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "lte.h"
|
||||
#include "uhd.h"
|
||||
|
||||
int nof_slots=1000;
|
||||
int band;
|
||||
|
||||
cf_t *input_buffer, *fft_buffer;
|
||||
void *uhd;
|
||||
int earfcn_start = -1, earfcn_end = -1;
|
||||
|
||||
#define MAX_EARFCN 1000
|
||||
lte_earfcn_t channels[MAX_EARFCN];
|
||||
|
||||
#define MHZ 1000000
|
||||
#define SAMP_FREQ 1920000
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [nvse] -b band\n", prog);
|
||||
printf("\t-s earfcn_start [Default All]\n");
|
||||
printf("\t-e earfcn_end [Default All]\n");
|
||||
printf("\t-n number of frames [Default %d]\n", nof_slots);
|
||||
printf("\t-v [set verbose to debug, default none]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "sebnv")) != -1) {
|
||||
switch(opt) {
|
||||
case 'b':
|
||||
band = atoi(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
earfcn_start = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
earfcn_end = atoi(argv[optind]);
|
||||
break;
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int base_init() {
|
||||
|
||||
input_buffer = malloc(4 * 960 * sizeof(cf_t));
|
||||
if (!input_buffer) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* open UHD device */
|
||||
printf("Opening UHD device...\n");
|
||||
if (uhd_open("",&uhd)) {
|
||||
fprintf(stderr, "Error opening uhd\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
|
||||
uhd_set_rx_srate(uhd, SAMP_FREQ);
|
||||
|
||||
printf("Starting receiver...\n");
|
||||
uhd_start_rx_stream(uhd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int frame_cnt;
|
||||
int i;
|
||||
int nsamples;
|
||||
float rssi[MAX_EARFCN];
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (base_init()) {
|
||||
fprintf(stderr, "Error initializing memory\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
|
||||
printf("Scanning %d freqs in band %d\n", nof_bands, band);
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
uhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ);
|
||||
frame_cnt = 0;
|
||||
nsamples=0;
|
||||
rssi[i]=0;
|
||||
while(frame_cnt < nof_slots) {
|
||||
nsamples += uhd_recv(uhd, input_buffer, 1920, 1);
|
||||
rssi[i] += vec_power(input_buffer, 1920);
|
||||
frame_cnt++;
|
||||
}
|
||||
printf("[%3d/%d]: Scanning earfcn %d freq %.2f MHz RSSI %.2f dBm\n", i, nof_bands,
|
||||
channels[i].id, channels[i].fd, 10*log10f(rssi[i]) + 30);
|
||||
}
|
||||
|
||||
FILE *f = fopen("output.m", "w");
|
||||
if (!f) {
|
||||
perror("fopen");
|
||||
exit(-1);
|
||||
}
|
||||
fprintf(f, "fd=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", channels[i].fd);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
|
||||
fprintf(f, "rssi=[");
|
||||
for (i=0;i<nof_bands;i++) {
|
||||
fprintf(f, "%g, ", rssi[i]);
|
||||
}
|
||||
fprintf(f, "];\n");
|
||||
fprintf(f, "plot(fd/1000, 10*log10(rssi)+30)\ngrid on\nxlabel('f_d [Ghz]')\nylabel('RSSI [dBm]')\n");
|
||||
fclose(f);
|
||||
|
||||
free(input_buffer);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
char *input_file_name;
|
||||
char *output_file_name="abs_corr.txt";
|
||||
int nof_slots=100, frame_length=9600, symbol_sz=128;
|
||||
float corr_peak_threshold=25.0;
|
||||
int file_binary = 0;
|
||||
int out_N_id_2 = 0, force_N_id_2=-1;
|
||||
|
||||
#define CFO_AUTO -9999.0
|
||||
float force_cfo = CFO_AUTO;
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [onlt] -i input_file\n", prog);
|
||||
printf("\t-o output_file [Default %s]\n", output_file_name);
|
||||
printf("\t-l frame_length [Default %d]\n", frame_length);
|
||||
printf("\t-n number of frames [Default %d]\n", nof_slots);
|
||||
printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold);
|
||||
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
|
||||
printf("\t-b Input files is binary [Default %s]\n", file_binary?"yes":"no");
|
||||
printf("\t-N out_N_id_2 [Default %d]\n", out_N_id_2);
|
||||
printf("\t-f force_N_id_2 [Default %d]\n", force_N_id_2);
|
||||
printf("\t-c force_cfo [Default disabled]\n");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "ionltsbNfc")) != -1) {
|
||||
switch(opt) {
|
||||
case 'i':
|
||||
input_file_name = argv[optind];
|
||||
break;
|
||||
case 'o':
|
||||
output_file_name = argv[optind];
|
||||
break;
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
frame_length = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
corr_peak_threshold = atof(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
symbol_sz = atof(argv[optind]);
|
||||
break;
|
||||
case 'b':
|
||||
file_binary = 1;
|
||||
break;
|
||||
case 'N':
|
||||
out_N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
case 'f':
|
||||
force_N_id_2 = atoi(argv[optind]);
|
||||
break;
|
||||
case 'c':
|
||||
force_cfo = atof(argv[optind]);
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
if (!input_file_name) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
filesource_t fsrc;
|
||||
filesink_t fsink;
|
||||
pss_synch_t pss[3]; // One for each N_id_2
|
||||
sss_synch_t sss[3]; // One for each N_id_2
|
||||
int peak_pos[3];
|
||||
float *cfo;
|
||||
float peak_value[3];
|
||||
float mean_value[3];
|
||||
int frame_cnt;
|
||||
cf_t *input;
|
||||
int m0, m1;
|
||||
float m0_value, m1_value;
|
||||
int N_id_2;
|
||||
int sss_idx;
|
||||
struct timeval tdata[3];
|
||||
int *exec_time;
|
||||
|
||||
if (argc < 3) {
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
gettimeofday(&tdata[1], NULL);
|
||||
printf("Initializing...");fflush(stdout);
|
||||
|
||||
file_data_type_t type = file_binary?COMPLEX_FLOAT_BIN:COMPLEX_FLOAT;
|
||||
if (filesource_init(&fsrc, input_file_name, type)) {
|
||||
fprintf(stderr, "Error opening file %s\n", input_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
if (filesink_init(&fsink, output_file_name, type)) {
|
||||
fprintf(stderr, "Error opening file %s\n", output_file_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
input = malloc(frame_length*sizeof(cf_t));
|
||||
if (!input) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
cfo = malloc(nof_slots*sizeof(float));
|
||||
if (!cfo) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
exec_time = malloc(nof_slots*sizeof(int));
|
||||
if (!exec_time) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
/* We have 2 options here:
|
||||
* a) We create 3 pss objects, each initialized with a different N_id_2
|
||||
* b) We create 1 pss object which scans for each N_id_2 one after another.
|
||||
* a) requries more memory but has less latency and is paralellizable.
|
||||
*/
|
||||
for (N_id_2=0;N_id_2<3;N_id_2++) {
|
||||
if (pss_synch_init(&pss[N_id_2], frame_length)) {
|
||||
fprintf(stderr, "Error initializing PSS object\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pss_synch_set_N_id_2(&pss[N_id_2], N_id_2)) {
|
||||
fprintf(stderr, "Error initializing N_id_2\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (sss_synch_init(&sss[N_id_2])) {
|
||||
fprintf(stderr, "Error initializing SSS object\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (sss_synch_set_N_id_2(&sss[N_id_2], N_id_2)) {
|
||||
fprintf(stderr, "Error initializing N_id_2\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
gettimeofday(&tdata[2], NULL);
|
||||
get_time_interval(tdata);
|
||||
printf("done in %d s %d ms\n", (int) tdata[0].tv_sec, (int) tdata[0].tv_usec/1000);
|
||||
|
||||
printf("\n\tFr.Cnt\tN_id_2\tN_id_1\tSubf\tPSS Peak/Avg\tIdx\tm0\tm1\tCFO\n");
|
||||
printf("\t===============================================================================\n");
|
||||
|
||||
/* read all file or nof_frames */
|
||||
frame_cnt = 0;
|
||||
while (frame_length == filesource_read(&fsrc, input, frame_length)
|
||||
&& frame_cnt < nof_slots) {
|
||||
|
||||
gettimeofday(&tdata[1], NULL);
|
||||
if (force_cfo != CFO_AUTO) {
|
||||
nco_cexp_f_direct(input, -force_cfo/128, frame_length);
|
||||
}
|
||||
|
||||
if (force_N_id_2 != -1) {
|
||||
N_id_2 = force_N_id_2;
|
||||
peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]);
|
||||
} else {
|
||||
for (N_id_2=0;N_id_2<3;N_id_2++) {
|
||||
peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]);
|
||||
}
|
||||
float max_value=-99999;
|
||||
N_id_2=-1;
|
||||
int i;
|
||||
for (i=0;i<3;i++) {
|
||||
if (peak_value[i] > max_value) {
|
||||
max_value = peak_value[i];
|
||||
N_id_2 = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If peak detected */
|
||||
if (peak_value[N_id_2]/mean_value[N_id_2] > corr_peak_threshold) {
|
||||
|
||||
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],
|
||||
&m0, &m0_value, &m1, &m1_value);
|
||||
|
||||
cfo[frame_cnt] = pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]);
|
||||
printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n",
|
||||
frame_cnt,N_id_2, sss_synch_N_id_1(&sss[N_id_2], m0, m1),
|
||||
sss_synch_subframe(m0, m1), peak_value[N_id_2]/mean_value[N_id_2],
|
||||
peak_pos[N_id_2], m0, m1,
|
||||
cfo[frame_cnt]);
|
||||
}
|
||||
}
|
||||
gettimeofday(&tdata[2], NULL);
|
||||
get_time_interval(tdata);
|
||||
exec_time[frame_cnt] = tdata[0].tv_usec;
|
||||
frame_cnt++;
|
||||
}
|
||||
|
||||
int i;
|
||||
float avg_time=0;
|
||||
for (i=0;i<frame_cnt;i++) {
|
||||
avg_time += (float) exec_time[i];
|
||||
}
|
||||
avg_time /= frame_cnt;
|
||||
printf("\n");
|
||||
printf("Average exec time: %.3f ms / frame. %.3f Msamp/s (%.3f\%% CPU)\n",
|
||||
avg_time / 1000, frame_length / avg_time, 100 * avg_time / 5000 * (9600 / (float) frame_length ));
|
||||
|
||||
float cfo_mean=0;
|
||||
for (i=0;i<frame_cnt;i++) {
|
||||
cfo_mean += cfo[i] / frame_cnt * (9600 / frame_length);
|
||||
}
|
||||
printf("Average CFO: %.3f\n", cfo_mean);
|
||||
|
||||
for (N_id_2=0;N_id_2<3;N_id_2++) {
|
||||
pss_synch_free(&pss[N_id_2]);
|
||||
sss_synch_free(&sss[N_id_2]);
|
||||
}
|
||||
|
||||
filesource_close(&fsrc);
|
||||
filesink_close(&fsink);
|
||||
|
||||
free(input);
|
||||
free(cfo);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "lte.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
int frame_length=1000, nof_slots=128;
|
||||
float ebno_db = 5.0;
|
||||
unsigned int seed=0;
|
||||
bool tail_biting = false;
|
||||
|
||||
char message[40] = {0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,1,1,0,1,0,0,0,0,1};
|
||||
|
||||
void usage(char *prog) {
|
||||
printf("Usage: %s [nl]\n", prog);
|
||||
printf("\t-n nof_frames [Default %d]\n", nof_slots);
|
||||
printf("\t-l frame_length [Default %d]\n", frame_length);
|
||||
printf("\t-e ebno in dB [Default %.2f dB]\n", ebno_db);
|
||||
printf("\t-s seed [Default 0=time]\n");
|
||||
printf("\t-t tail_bitting [Default %s]\n", tail_biting?"yes":"no");
|
||||
}
|
||||
|
||||
void parse_args(int argc, char **argv) {
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "nlste")) != -1) {
|
||||
switch(opt) {
|
||||
case 'n':
|
||||
nof_slots = atoi(argv[optind]);
|
||||
break;
|
||||
case 'l':
|
||||
frame_length = atoi(argv[optind]);
|
||||
break;
|
||||
case 'e':
|
||||
ebno_db = atof(argv[optind]);
|
||||
break;
|
||||
case 's':
|
||||
seed = atoi(argv[optind]);
|
||||
break;
|
||||
case 't':
|
||||
tail_biting = true;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
viterbi_t dec;
|
||||
convcoder_t cod;
|
||||
modem_table_t modem;
|
||||
demod_soft_t demod;
|
||||
int frame_cnt;
|
||||
float *llr;
|
||||
char *data_tx, *data_rx, *symbols;
|
||||
cf_t *iq;
|
||||
int i;
|
||||
|
||||
parse_args(argc,argv);
|
||||
|
||||
if (!seed) {
|
||||
seed = time(NULL);
|
||||
}
|
||||
srand(seed);
|
||||
|
||||
int coded_length = 3 * (frame_length + ((tail_biting)?0:6));
|
||||
|
||||
printf("Convolutional Code 1/3 K=7 Test\n");
|
||||
printf(" Frame length: %d\n", frame_length);
|
||||
printf(" Codeword length: %d\n", coded_length);
|
||||
printf(" Tail bitting: %s\n", tail_biting?"yes":"no");
|
||||
printf(" EbNo: %.2f\n", ebno_db);
|
||||
|
||||
data_tx = malloc(frame_length * sizeof(char));
|
||||
if (!data_tx) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
data_rx = malloc(frame_length * sizeof(char));
|
||||
if (!data_rx) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
symbols = malloc(coded_length * sizeof(char));
|
||||
if (!symbols) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
llr = malloc(coded_length * sizeof(float));
|
||||
if (!llr) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
iq = malloc(coded_length * sizeof(cf_t));
|
||||
if (!iq) {
|
||||
perror("malloc");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
cod.K = 7;
|
||||
cod.R = 3;
|
||||
cod.tail_biting = tail_biting;
|
||||
cod.framelength = frame_length;
|
||||
cod.poly[0] = 0x6D;
|
||||
cod.poly[1] = 0x4F;
|
||||
cod.poly[2] = 0x57;
|
||||
|
||||
float var = sqrt(pow(10,-ebno_db/10));
|
||||
|
||||
modem_table_init(&modem);
|
||||
modem_table_std(&modem, LTE_QPSK, true);
|
||||
demod_soft_init(&demod);
|
||||
demod_soft_table_set(&demod, &modem);
|
||||
demod_soft_alg_set(&demod, APPROX);
|
||||
demod_soft_sigma_set(&demod, var);
|
||||
|
||||
viterbi_init(&dec, CONVCODER_37, cod.poly, frame_length, tail_biting);
|
||||
|
||||
/* read all file or nof_frames */
|
||||
frame_cnt = 0;
|
||||
unsigned int errors=0;
|
||||
while (frame_cnt < nof_slots) {
|
||||
|
||||
/* generate data_tx */
|
||||
for (i=0;i<frame_length;i++) {
|
||||
data_tx[i] = message[i];
|
||||
}
|
||||
|
||||
conv_encode(&cod, data_tx, symbols);
|
||||
|
||||
bit_fprint(stdout, symbols, 120);
|
||||
|
||||
mod_modulate(&modem, symbols, iq, coded_length);
|
||||
|
||||
if (ebno_db < 100.0) {
|
||||
ch_awgn(iq, iq, var, coded_length/2);
|
||||
}
|
||||
|
||||
demod_soft_demodulate(&demod, iq, llr, coded_length/2);
|
||||
|
||||
viterbi_decode(&dec, llr, data_rx);
|
||||
|
||||
errors += bit_diff(data_tx, data_rx, frame_length);
|
||||
frame_cnt++;
|
||||
}
|
||||
|
||||
printf("BER:\t%g\t%u errors\n", (float) errors/(frame_cnt*frame_length), errors);
|
||||
|
||||
viterbi_free(&dec);
|
||||
|
||||
free(data_tx);
|
||||
free(symbols);
|
||||
free(iq);
|
||||
free(llr);
|
||||
free(data_rx);
|
||||
|
||||
printf("Done\n");
|
||||
exit(0);
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHEST_
|
||||
#define CHEST_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "ch_estimation/refsignal.h"
|
||||
#include "filter/filter2d.h"
|
||||
#include "lte/base.h"
|
||||
|
||||
typedef _Complex float cf_t; /* this is only a shortcut */
|
||||
|
||||
/** 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 {
|
||||
int nof_ports;
|
||||
int nof_symbols;
|
||||
int nof_prb;
|
||||
int symbol_sz;
|
||||
lte_cp_t cp;
|
||||
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
|
||||
}chest_t;
|
||||
|
||||
int chest_init(chest_t *q, lte_cp_t cp, int nof_prb, int nof_ports);
|
||||
void chest_free(chest_t *q);
|
||||
|
||||
int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id);
|
||||
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id);
|
||||
int chest_ref_LTEDL(chest_t *q, int cell_id);
|
||||
|
||||
void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref);
|
||||
void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id);
|
||||
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot);
|
||||
|
||||
void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
|
||||
int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]);
|
||||
|
||||
/* High-level API */
|
||||
|
||||
/** TODO: The high-level API has N interfaces, one for each port */
|
||||
|
||||
typedef struct {
|
||||
chest_t obj;
|
||||
struct chest_init {
|
||||
int nof_symbols; // 7 for normal cp, 6 for extended
|
||||
int port_id;
|
||||
int nof_ports;
|
||||
int cell_id;
|
||||
int nof_prb;
|
||||
int ntime;
|
||||
int nfreq;
|
||||
} init;
|
||||
cf_t *input;
|
||||
int in_len;
|
||||
struct chest_ctrl_in {
|
||||
int slot_id; // slot id in the 10ms frame
|
||||
} ctrl_in;
|
||||
cf_t *output;
|
||||
int *out_len;
|
||||
}chest_hl;
|
||||
|
||||
#define DEFAULT_FRAME_SIZE 2048
|
||||
|
||||
int chest_initialize(chest_hl* h);
|
||||
int chest_work(chest_hl* hl);
|
||||
int chest_stop(chest_hl* hl);
|
||||
|
||||
#endif
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <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 "lte/base.h"
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
typedef struct {
|
||||
int time_idx;
|
||||
int freq_idx;
|
||||
cf_t simbol;
|
||||
cf_t recv_simbol;
|
||||
}ref_t;
|
||||
|
||||
typedef struct {
|
||||
int nof_refs; // number of reference signals
|
||||
int *symbols_ref; // symbols with at least one reference
|
||||
int nsymbols; // number of symbols with at least one reference
|
||||
int voffset; // offset of the first reference in the freq domain
|
||||
ref_t *refs;
|
||||
cf_t *ch_est;
|
||||
} refsignal_t;
|
||||
|
||||
int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot,
|
||||
int cell_id, lte_cp_t cp, int nof_prb);
|
||||
|
||||
void refsignal_free(refsignal_t *q);
|
||||
|
||||
#endif
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <complex.h>
|
||||
|
||||
#ifndef CH_AWGN_
|
||||
#define CH_AWGN_
|
||||
|
||||
typedef _Complex float cf;
|
||||
|
||||
void ch_awgn(const cf* input, cf* output, float variance, int buff_sz);
|
||||
|
||||
/* High-level API */
|
||||
|
||||
typedef struct {
|
||||
const cf* input;
|
||||
int in_len;
|
||||
struct ch_awgn_ctrl_in {
|
||||
float variance; // Noise variance
|
||||
} ctrl_in;
|
||||
|
||||
cf* output;
|
||||
int* out_len;
|
||||
}ch_awgn_hl;
|
||||
|
||||
int ch_awgn_initialize(ch_awgn_hl* hl);
|
||||
int ch_awgn_work(ch_awgn_hl* hl);
|
||||
|
||||
#endif
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONVCODER_
|
||||
#define CONVCODER_
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum {
|
||||
CONVCODER_27, CONVCODER_29, CONVCODER_37, CONVCODER_39
|
||||
}viterbi_type_t;
|
||||
|
||||
typedef struct {
|
||||
void *ptr;
|
||||
int R;
|
||||
int K;
|
||||
unsigned int framebits;
|
||||
bool tail_biting;
|
||||
int poly[3];
|
||||
int (*decode) (void*, float*, char*);
|
||||
void (*free) (void*);
|
||||
}viterbi_t;
|
||||
|
||||
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting);
|
||||
void viterbi_free(viterbi_t *q);
|
||||
int viterbi_decode(viterbi_t *q, float *symbols, char *data);
|
||||
|
||||
typedef struct {
|
||||
int R;
|
||||
int K;
|
||||
int poly[3];
|
||||
int framelength;
|
||||
bool tail_biting;
|
||||
}convcoder_t;
|
||||
|
||||
int conv_encode(convcoder_t *q, char *input, char *output);
|
||||
|
||||
#endif
|
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CRC_
|
||||
#define CRC_
|
||||
|
||||
|
||||
unsigned int crc(unsigned int crc, char *bufptr, int len,
|
||||
int long_crc,unsigned int poly, int paste_word);
|
||||
|
||||
#endif
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FILTER2D_
|
||||
#define FILTER2D_
|
||||
|
||||
/* 2-D real filter of complex input
|
||||
*
|
||||
*/
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
typedef struct {
|
||||
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
|
||||
float **taps; // 2-D filter coefficients
|
||||
cf_t *output; // Output signal
|
||||
} filter2d_t;
|
||||
|
||||
int filter2d_init (filter2d_t* q, float **taps, int ntime, int nfreq, int sztime, int szfreq);
|
||||
int filter2d_init_default (filter2d_t* q, int ntime, int nfreq, int sztime, int szfreq);
|
||||
void filter2d_free(filter2d_t *q);
|
||||
void filter2d_reset(filter2d_t *q);
|
||||
void filter2d_add(filter2d_t *q, cf_t h, int time_idx, int freq_idx);
|
||||
|
||||
#endif
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BINSOURCE_
|
||||
#define BINSOURCE_
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Low-level API */
|
||||
typedef struct {
|
||||
unsigned int seed;
|
||||
uint32_t *seq_buff;
|
||||
int seq_buff_nwords;
|
||||
int seq_cache_nbits;
|
||||
int seq_cache_rp;
|
||||
}binsource_t;
|
||||
|
||||
void binsource_init(binsource_t* q);
|
||||
void binsource_free(binsource_t* q);
|
||||
void binsource_seed_set(binsource_t* q, unsigned int seed);
|
||||
void binsource_seed_time(binsource_t *q);
|
||||
int binsource_cache_gen(binsource_t* q, int nbits);
|
||||
void binsource_cache_cpy(binsource_t* q, char *bits, int nbits);
|
||||
int binsource_generate(binsource_t* q, char *bits, int nbits);
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
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.
|
||||
} init;
|
||||
struct binsource_ctrl_in {
|
||||
int nbits; // Number of bits to generate
|
||||
} ctrl_in;
|
||||
char* output;
|
||||
int* out_len;
|
||||
}binsource_hl;
|
||||
|
||||
int binsource_initialize(binsource_hl* h);
|
||||
int binsource_work( binsource_hl* hl);
|
||||
int binsource_stop(binsource_hl* hl);
|
||||
|
||||
#endif
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FILESINK_
|
||||
#define FILESINK_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "io/format.h"
|
||||
|
||||
/* Low-level API */
|
||||
typedef struct {
|
||||
FILE *f;
|
||||
file_data_type_t type;
|
||||
}filesink_t;
|
||||
|
||||
int filesink_init(filesink_t *q, char *filename, file_data_type_t type);
|
||||
void filesink_close(filesink_t *q);
|
||||
|
||||
int filesink_write(filesink_t *q, void *buffer, int nsamples);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
filesink_t obj;
|
||||
struct filesink_init {
|
||||
char *file_name;
|
||||
int block_length;
|
||||
int data_type;
|
||||
} init;
|
||||
void* input;
|
||||
int in_len;
|
||||
}filesink_hl;
|
||||
|
||||
int filesink_initialize(filesink_hl* h);
|
||||
int filesink_work( filesink_hl* hl);
|
||||
int filesink_stop(filesink_hl* h);
|
||||
|
||||
#endif
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FILESOURCE_
|
||||
#define FILESOURCE_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "io/format.h"
|
||||
|
||||
/* Low-level API */
|
||||
typedef struct {
|
||||
FILE *f;
|
||||
file_data_type_t type;
|
||||
}filesource_t;
|
||||
|
||||
int filesource_init(filesource_t *q, char *filename, file_data_type_t type);
|
||||
void filesource_close(filesource_t *q);
|
||||
|
||||
int filesource_read(filesource_t *q, void *buffer, int nsamples);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
filesource_t obj;
|
||||
struct filesource_init {
|
||||
char *file_name;
|
||||
int block_length;
|
||||
int data_type;
|
||||
} init;
|
||||
struct filesource_ctrl_in {
|
||||
int nsamples; // Number of samples to read
|
||||
} ctrl_in;
|
||||
void* output;
|
||||
int* out_len;
|
||||
}filesource_hl;
|
||||
|
||||
int filesource_initialize(filesource_hl* h);
|
||||
int filesource_work( filesource_hl* hl);
|
||||
int filesource_stop(filesource_hl* h);
|
||||
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
|
||||
#ifndef FORMAT_
|
||||
#define FORMAT_
|
||||
|
||||
typedef enum { FLOAT, COMPLEX_FLOAT, COMPLEX_SHORT, FLOAT_BIN, COMPLEX_FLOAT_BIN, COMPLEX_SHORT_BIN} file_data_type_t;
|
||||
|
||||
#endif
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifndef _LTE_
|
||||
#define _LTE_
|
||||
|
||||
#include "utils/bit.h"
|
||||
#include "utils/convolution.h"
|
||||
#include "utils/debug.h"
|
||||
#include "utils/dft.h"
|
||||
#include "utils/matrix.h"
|
||||
#include "utils/mux.h"
|
||||
#include "utils/nco.h"
|
||||
#include "utils/pack.h"
|
||||
#include "utils/vector.h"
|
||||
|
||||
#include "lte/base.h"
|
||||
#include "lte/fft.h"
|
||||
#include "lte/sequence.h"
|
||||
|
||||
#include "ch_estimation/chest.h"
|
||||
#include "ch_estimation/refsignal.h"
|
||||
|
||||
#include "channel/ch_awgn.h"
|
||||
|
||||
#include "fec/convcoder.h"
|
||||
#include "fec/crc.h"
|
||||
|
||||
#include "filter/filter2d.h"
|
||||
|
||||
#include "io/binsource.h"
|
||||
#include "io/filesink.h"
|
||||
#include "io/filesource.h"
|
||||
|
||||
#include "modem/demod_hard.h"
|
||||
#include "modem/demod_soft.h"
|
||||
#include "modem/mod.h"
|
||||
#include "modem/modem_table.h"
|
||||
|
||||
#include "phch/pbch.h"
|
||||
|
||||
#include "ratematching/rm_conv.h"
|
||||
|
||||
#include "scrambling/scrambling.h"
|
||||
|
||||
#include "resampling/interp.h"
|
||||
|
||||
#include "sync/pss.h"
|
||||
#include "sync/sfo.h"
|
||||
#include "sync/sss.h"
|
||||
#include "sync/sync.h"
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _LTEBASE_
|
||||
#define _LTEBASE_
|
||||
|
||||
#define NSUBFRAMES_X_FRAME 10
|
||||
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
|
||||
|
||||
#define MAX_PORTS 4
|
||||
|
||||
typedef enum {CPNORM, CPEXT} lte_cp_t;
|
||||
|
||||
#define MAX_NSYMB 7
|
||||
|
||||
#define CPNORM_NSYMB 7
|
||||
#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB
|
||||
#define CPNORM_0_LEN 160
|
||||
#define CPNORM_LEN 144
|
||||
|
||||
#define CPEXT_NSYMB 6
|
||||
#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB
|
||||
#define CPEXT_LEN 512
|
||||
#define CPEXT_7_5_LEN 1024
|
||||
|
||||
#define CP_ISNORM(cp) (cp==CPNORM)
|
||||
#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_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)
|
||||
|
||||
#define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN)))
|
||||
#define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
|
||||
|
||||
#define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz)
|
||||
#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz)
|
||||
|
||||
#define SF_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 SF_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
|
||||
|
||||
#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?0:symbol_sz*CPNORM_NSYMB)
|
||||
#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx==0?0:symbol_sz*CPEXT_NSYMB)
|
||||
|
||||
#define MAX_PRB 110
|
||||
#define RE_X_RB 12
|
||||
|
||||
#define RS_VSHIFT(cell_id) (cell_id%6)
|
||||
|
||||
#define GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2)
|
||||
|
||||
#define SAMPLE_IDX(symbol_sz, symbol_idx, sample_idx) (symbol_idx*symbol_sz + sample_idx)
|
||||
|
||||
const int lte_symbol_sz(int nof_prb);
|
||||
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols);
|
||||
int lte_voffset(int symbol_id, int cell_id, int nof_ports);
|
||||
|
||||
#define NOF_LTE_BANDS 29
|
||||
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
float fd;
|
||||
}lte_earfcn_t;
|
||||
|
||||
enum band_geographical_area {
|
||||
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
|
||||
};
|
||||
|
||||
float lte_band_fd(int earfcn);
|
||||
int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, int max_elems);
|
||||
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems);
|
||||
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems);
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LTEFFT_
|
||||
#define LTEFFT_
|
||||
|
||||
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lte/base.h"
|
||||
#include "utils/dft.h"
|
||||
|
||||
typedef _Complex float cf_t; /* this is only a shortcut */
|
||||
|
||||
/* This is common for both directions */
|
||||
typedef struct {
|
||||
dft_plan_t fft_plan;
|
||||
int nof_symbols;
|
||||
int symbol_sz;
|
||||
lte_cp_t cp_type;
|
||||
}lte_fft_t;
|
||||
|
||||
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int symbol_sz);
|
||||
void lte_fft_free(lte_fft_t *q);
|
||||
void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output);
|
||||
|
||||
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int symbol_sz);
|
||||
void lte_ifft_free(lte_fft_t *q);
|
||||
void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output);
|
||||
|
||||
#endif
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LTESEQ_
|
||||
#define LTESEQ_
|
||||
|
||||
#include "lte/base.h"
|
||||
|
||||
typedef struct {
|
||||
char *c;
|
||||
int len;
|
||||
}sequence_t;
|
||||
|
||||
int sequence_init(sequence_t *q, int len);
|
||||
void sequence_free(sequence_t *q);
|
||||
|
||||
int sequence_LTEPRS(sequence_t *q, int len, int seed);
|
||||
|
||||
int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id);
|
||||
int sequence_pbch_crc(sequence_t *seq, int nof_ports);
|
||||
|
||||
#endif
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEMOD_HARD_
|
||||
#define DEMOD_HARD_
|
||||
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modem_table.h"
|
||||
|
||||
typedef _Complex float cf;
|
||||
|
||||
typedef struct {
|
||||
enum modem_std table; /* In this implementation, mapping table is hard-coded */
|
||||
}demod_hard_t;
|
||||
|
||||
|
||||
void demod_hard_init(demod_hard_t* q);
|
||||
void demod_hard_table(demod_hard_t* q, enum modem_std table);
|
||||
int demod_hard_demodulate(demod_hard_t* q, const cf* symbols, char *bits, int nsymbols);
|
||||
|
||||
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
demod_hard_t obj;
|
||||
struct demod_hard_init {
|
||||
enum modem_std std; // Symbol mapping standard (see modem_table.h)
|
||||
} init;
|
||||
|
||||
const cf* input;
|
||||
int in_len;
|
||||
|
||||
char* output;
|
||||
int *out_len;
|
||||
}demod_hard_hl;
|
||||
|
||||
int demod_hard_initialize(demod_hard_hl* hl);
|
||||
int demod_hard_work(demod_hard_hl* hl);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DEMOD_SOFT_
|
||||
#define DEMOD_SOFT_
|
||||
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modem_table.h"
|
||||
|
||||
enum alg { EXACT, APPROX };
|
||||
|
||||
typedef struct {
|
||||
float sigma; // noise power
|
||||
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
|
||||
modem_table_t *table; // symbol mapping table (see modem_table.h)
|
||||
}demod_soft_t;
|
||||
|
||||
void demod_soft_init(demod_soft_t *q);
|
||||
void demod_soft_table_set(demod_soft_t *q, modem_table_t *table);
|
||||
void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type);
|
||||
void demod_soft_sigma_set(demod_soft_t *q, float sigma);
|
||||
int demod_soft_demodulate(demod_soft_t *q, const cf* symbols, float* llr, int nsymbols);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
demod_soft_t obj;
|
||||
modem_table_t table;
|
||||
|
||||
struct demod_soft_init {
|
||||
enum modem_std std; // symbol mapping standard (see modem_table.h)
|
||||
} init;
|
||||
|
||||
const cf* input;
|
||||
int in_len;
|
||||
|
||||
struct demod_soft_ctrl_in {
|
||||
float sigma; // Estimated noise variance
|
||||
enum alg alg_type; // soft demapping algorithm (EXACT or APPROX)
|
||||
}ctrl_in;
|
||||
|
||||
float* output;
|
||||
int *out_len;
|
||||
|
||||
}demod_soft_hl;
|
||||
|
||||
int demod_soft_initialize(demod_soft_hl* hl);
|
||||
int demod_soft_work(demod_soft_hl* hl);
|
||||
int demod_soft_stop(demod_soft_hl* hl);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MOD_
|
||||
#define MOD_
|
||||
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modem_table.h"
|
||||
|
||||
typedef _Complex float cf;
|
||||
|
||||
int mod_modulate(modem_table_t* table, const char *bits, cf* symbols, int nbits);
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
modem_table_t obj;
|
||||
struct mod_init {
|
||||
enum modem_std std; // symbol mapping standard (see modem_table.h)
|
||||
} init;
|
||||
|
||||
const char* input;
|
||||
int in_len;
|
||||
|
||||
cf* output;
|
||||
int *out_len;
|
||||
}mod_hl;
|
||||
|
||||
int mod_initialize(mod_hl* hl);
|
||||
int mod_work(mod_hl* hl);
|
||||
int mod_stop(mod_hl* hl);
|
||||
|
||||
#endif
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MODEM_TABLE_
|
||||
#define MODEM_TABLE_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef _Complex float cf;
|
||||
typedef struct {
|
||||
int idx[2][6][32];
|
||||
}soft_table_t;
|
||||
|
||||
typedef struct {
|
||||
cf* symbol_table; // bit-to-symbol mapping
|
||||
soft_table_t soft_table; // symbol-to-bit mapping (used in soft demodulating)
|
||||
int nsymbols; // number of modulation symbols
|
||||
int nbits_x_symbol; // number of bits per symbol
|
||||
}modem_table_t;
|
||||
|
||||
|
||||
// Modulation standards
|
||||
enum modem_std {
|
||||
LTE_BPSK, LTE_QPSK, LTE_QAM16, LTE_QAM64
|
||||
};
|
||||
|
||||
void modem_table_init(modem_table_t* q);
|
||||
void modem_table_free(modem_table_t* q);
|
||||
void modem_table_reset(modem_table_t* q);
|
||||
int modem_table_set(modem_table_t* q, cf* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol);
|
||||
int modem_table_std(modem_table_t* q, enum modem_std table, bool compute_soft_demod);
|
||||
|
||||
#endif
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PBCH_
|
||||
#define PBCH_
|
||||
|
||||
#include "lte/base.h"
|
||||
#include "modem/mod.h"
|
||||
#include "modem/demod_soft.h"
|
||||
#include "scrambling/scrambling.h"
|
||||
#include "ratematching/rm_conv.h"
|
||||
#include "fec/convcoder.h"
|
||||
#include "fec/crc.h"
|
||||
|
||||
#define PBCH_RE_CPNORM 240
|
||||
#define PBCH_RE_CPEXT 216
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
enum phich_length { NORMAL, EXTENDED};
|
||||
enum phich_resources { R_1_6, R_1_2, R_1, R_2};
|
||||
|
||||
typedef struct {
|
||||
int nof_ports;
|
||||
int nof_prb;
|
||||
int sfn;
|
||||
enum phich_length phich_length;
|
||||
int phich_resources;
|
||||
}pbch_mib_t;
|
||||
|
||||
/* PBCH receiver */
|
||||
typedef struct {
|
||||
int cell_id;
|
||||
lte_cp_t cp;
|
||||
|
||||
/* buffers */
|
||||
cf_t *pbch_symbols;
|
||||
float *pbch_llr;
|
||||
float *temp;
|
||||
float *pbch_rm;
|
||||
char *data;
|
||||
|
||||
int frame_idx;
|
||||
|
||||
/* tx & rx objects */
|
||||
modem_table_t mod;
|
||||
demod_soft_t demod;
|
||||
sequence_t seq_pbch;
|
||||
viterbi_t decoder;
|
||||
|
||||
}pbch_t;
|
||||
|
||||
int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp);
|
||||
void pbch_free(pbch_t *q);
|
||||
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, pbch_mib_t *data, int nof_prb, float ebno);
|
||||
void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib);
|
||||
|
||||
|
||||
bool pbch_exists(int nframe, int nslot);
|
||||
int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id);
|
||||
int pbch_get(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id);
|
||||
|
||||
#endif
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RM_CONV_
|
||||
#define RM_CONV_
|
||||
|
||||
#define RX_NULL 10000
|
||||
|
||||
int rm_conv_rx(float *input, float *output, int in_len, int out_len);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
typedef struct {
|
||||
struct rm_conv_init {
|
||||
int direction;
|
||||
} init;
|
||||
void *input; // input type may be char or float depending on hard
|
||||
int in_len;
|
||||
struct rm_conv_ctrl_in {
|
||||
int E;
|
||||
int S;
|
||||
} ctrl_in;
|
||||
void *output;
|
||||
int *out_len;
|
||||
}rm_conv_hl;
|
||||
|
||||
int rm_conv_initialize(rm_conv_hl* h);
|
||||
int rm_conv_work(rm_conv_hl* hl);
|
||||
int rm_conv_stop(rm_conv_hl* hl);
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
|
||||
void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end);
|
||||
void interp_linear(cf_t *input, cf_t *output, int M, int len);
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SCRAMBLING_
|
||||
#define SCRAMBLING_
|
||||
|
||||
#include "lte/sequence.h"
|
||||
#include "lte/base.h"
|
||||
|
||||
/* Scrambling has no state */
|
||||
void scrambling_bit(sequence_t *s, char *data);
|
||||
void scrambling_float(sequence_t *s, float *data);
|
||||
int scrambling_float_offset(sequence_t *s, float *data, int offset, int len);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
|
||||
/* channel integer values */
|
||||
#define PDSCH 0 /* also PUSCH */
|
||||
#define PCFICH 1
|
||||
#define PDCCH 2
|
||||
#define PBCH 3
|
||||
#define PMCH 4
|
||||
#define PUCCH 5
|
||||
|
||||
typedef struct {
|
||||
sequence_t seq[NSUBFRAMES_X_FRAME];
|
||||
}scrambling_t;
|
||||
|
||||
typedef struct {
|
||||
scrambling_t obj;
|
||||
struct scrambling_init {
|
||||
int hard;
|
||||
int q;
|
||||
int cell_id;
|
||||
int nrnti;
|
||||
int nMBSFN;
|
||||
int channel;
|
||||
int nof_symbols; // 7 normal 6 extended
|
||||
} init;
|
||||
void *input; // input type may be char or float depending on hard
|
||||
int in_len;
|
||||
struct scrambling_ctrl_in {
|
||||
int subframe;
|
||||
} ctrl_in;
|
||||
void *output;
|
||||
int *out_len;
|
||||
}scrambling_hl;
|
||||
|
||||
#endif
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PSS_
|
||||
#define PSS_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "utils/convolution.h"
|
||||
|
||||
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_FREQ 129
|
||||
#define PSS_LEN 62
|
||||
#define PSS_RE 6*12
|
||||
|
||||
|
||||
|
||||
/** The pss_synch_t object provides functions for fast computation of the crosscorrelation
|
||||
* between the PSS and received signal and CFO estimation. Also, the function pss_synch_periodic() is designed
|
||||
* to be called periodically every subframe, taking care of the correct data alignment with respect
|
||||
* to the PSS sequence.
|
||||
*/
|
||||
|
||||
|
||||
/* Low-level API */
|
||||
typedef struct {
|
||||
|
||||
#ifdef CONVOLUTION_FFT
|
||||
conv_fft_cc_t conv_fft;
|
||||
#endif
|
||||
|
||||
int frame_size;
|
||||
int N_id_2;
|
||||
float current_cfo;
|
||||
bool cfo_auto; // default true
|
||||
int nof_nosync_frames;
|
||||
int nosync_timeout_frames; // default 5
|
||||
float correlation_threshold; // default 10000
|
||||
int frame_start_idx;
|
||||
int fb_wp;
|
||||
|
||||
cf_t *pss_signal_freq;
|
||||
cf_t *tmp_input;
|
||||
float *conv_abs;
|
||||
cf_t *frame_buffer;
|
||||
cf_t *conv_output;
|
||||
cf_t *tmp_nco;
|
||||
}pss_synch_t;
|
||||
|
||||
/* Basic functionality */
|
||||
|
||||
int pss_synch_init(pss_synch_t *q, int frame_size);
|
||||
void pss_synch_free(pss_synch_t *q);
|
||||
int pss_generate(cf_t *signal, int direction, int N_id_2);
|
||||
|
||||
int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2);
|
||||
int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value);
|
||||
float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Automatic frame management functions (for periodic calling) */
|
||||
int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples);
|
||||
void pss_synch_set_timeout(pss_synch_t *q, int nof_frames);
|
||||
void pss_synch_set_threshold(pss_synch_t *q, float threshold);
|
||||
void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto);
|
||||
float pss_synch_get_cfo(pss_synch_t *q);
|
||||
int pss_synch_get_frame_start_idx(pss_synch_t *q);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* High-level API */
|
||||
|
||||
typedef struct {
|
||||
pss_synch_t obj;
|
||||
struct pss_synch_init {
|
||||
int frame_size; // if 0, 2048
|
||||
int unsync_nof_pkts;
|
||||
int N_id_2;
|
||||
int do_cfo;
|
||||
} init;
|
||||
cf_t *input;
|
||||
int in_len;
|
||||
struct pss_synch_ctrl_in {
|
||||
int correlation_threshold;
|
||||
float manual_cfo;
|
||||
} ctrl_in;
|
||||
cf_t *output;
|
||||
int *out_len;
|
||||
}pss_synch_hl;
|
||||
|
||||
#define DEFAULT_FRAME_SIZE 2048
|
||||
|
||||
int pss_synch_initialize(pss_synch_hl* h);
|
||||
int pss_synch_work(pss_synch_hl* hl);
|
||||
int pss_synch_stop(pss_synch_hl* hl);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SFO_
|
||||
#define SFO_
|
||||
|
||||
float sfo_estimate(int *t0, int len, float period);
|
||||
|
||||
|
||||
#endif
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SSS_
|
||||
#define SSS_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "utils/dft.h"
|
||||
|
||||
typedef _Complex float cf_t; /* this is only a shortcut */
|
||||
|
||||
/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1).
|
||||
* subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz
|
||||
* symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz
|
||||
*/
|
||||
#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz)
|
||||
#define SSS_POS_SYMBOL 33
|
||||
|
||||
#define SSS_DFT_LEN 128
|
||||
#define N_SSS 31
|
||||
|
||||
struct sss_tables {
|
||||
int z1[N_SSS][N_SSS];
|
||||
int c[2][N_SSS];
|
||||
int s[N_SSS][N_SSS];
|
||||
int N_id_2;
|
||||
};
|
||||
|
||||
/* Allocate 32 complex to make it multiple of 32-byte AVX instructions alignment requirement.
|
||||
* Should use vect_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];
|
||||
};
|
||||
|
||||
|
||||
/* Low-level API */
|
||||
typedef struct {
|
||||
|
||||
dft_plan_t dftp_input;
|
||||
|
||||
float corr_peak_threshold;
|
||||
int symbol_sz;
|
||||
int subframe_sz;
|
||||
|
||||
int N_id_1_table[30][30];
|
||||
struct fc_tables fc_tables;
|
||||
|
||||
}sss_synch_t;
|
||||
|
||||
|
||||
/* Basic functionality */
|
||||
int sss_synch_init(sss_synch_t *q);
|
||||
void sss_synch_free(sss_synch_t *q);
|
||||
void sss_generate(float *signal, int cell_id);
|
||||
|
||||
int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2);
|
||||
|
||||
void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value,
|
||||
int *m1, float *m1_value);
|
||||
int sss_synch_subframe(int m0, int m1);
|
||||
int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1);
|
||||
|
||||
int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1);
|
||||
void sss_synch_set_threshold(sss_synch_t *q, float threshold);
|
||||
void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz);
|
||||
void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
|
||||
|
||||
|
||||
/* High-level API */
|
||||
|
||||
typedef struct {
|
||||
sss_synch_t obj;
|
||||
struct sss_synch_init {
|
||||
int N_id_2;
|
||||
} init;
|
||||
cf_t *input;
|
||||
int in_len;
|
||||
struct sss_synch_ctrl_in {
|
||||
int symbol_sz;
|
||||
int subframe_sz;
|
||||
int correlation_threshold;
|
||||
} ctrl_in;
|
||||
struct sss_synch_ctrl_out {
|
||||
int subframe_idx;
|
||||
int N_id_1;
|
||||
} ctrl_out;
|
||||
}sss_synch_hl;
|
||||
|
||||
#define DEFAULT_FRAME_SIZE 2048
|
||||
|
||||
int sss_synch_initialize(sss_synch_hl* h);
|
||||
int sss_synch_work(sss_synch_hl* hl);
|
||||
int sss_synch_stop(sss_synch_hl* hl);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SYNC_
|
||||
#define SYNC_
|
||||
|
||||
#include "pss.h"
|
||||
#include "sss.h"
|
||||
#include "sfo.h"
|
||||
|
||||
enum sync_pss_det { ABSOLUTE, PEAK_MEAN};
|
||||
|
||||
typedef struct {
|
||||
pss_synch_t pss[3]; // One for each N_id_2
|
||||
sss_synch_t sss[3]; // One for each N_id_2
|
||||
enum sync_pss_det pss_mode;
|
||||
float threshold;
|
||||
float peak_to_avg;
|
||||
int force_N_id_2;
|
||||
int N_id_2;
|
||||
int N_id_1;
|
||||
int slot_id;
|
||||
float cfo;
|
||||
}sync_t;
|
||||
|
||||
int sync_run(sync_t *q, cf_t *input, int read_offset);
|
||||
float sync_get_cfo(sync_t *q);
|
||||
void sync_pss_det_absolute(sync_t *q);
|
||||
void sync_pss_det_peakmean(sync_t *q);
|
||||
void sync_force_N_id_2(sync_t *q, int force_N_id_2);
|
||||
int sync_get_slot_id(sync_t *q);
|
||||
float sync_get_peak_to_avg(sync_t *q);
|
||||
int sync_get_N_id_2(sync_t *q);
|
||||
int sync_get_N_id_1(sync_t *q);
|
||||
int sync_get_cell_id(sync_t *q);
|
||||
void sync_set_threshold(sync_t *q, float threshold);
|
||||
int sync_init(sync_t *q);
|
||||
void sync_free(sync_t *q);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef BIT_
|
||||
#define BIT_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
uint32_t bit_unpack(char **bits, int nof_bits);
|
||||
void bit_pack(uint32_t value, char **bits, int nof_bits);
|
||||
void bit_fprint(FILE *stream, char *bits, int nof_bits);
|
||||
unsigned int bit_diff(char *x, char *y, int nbits);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CONVOLUTION_H_
|
||||
#define CONVOLUTION_H_
|
||||
|
||||
#include "utils/dft.h"
|
||||
|
||||
typedef struct {
|
||||
_Complex float *input_fft;
|
||||
_Complex float *filter_fft;
|
||||
_Complex float *output_fft;
|
||||
_Complex float *output_fft2;
|
||||
int input_len;
|
||||
int filter_len;
|
||||
int output_len;
|
||||
dft_plan_t input_plan;
|
||||
dft_plan_t filter_plan;
|
||||
dft_plan_t output_plan;
|
||||
}conv_fft_cc_t;
|
||||
|
||||
int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len);
|
||||
void conv_fft_cc_free(conv_fft_cc_t *state);
|
||||
int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output);
|
||||
|
||||
int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len);
|
||||
|
||||
#endif
|
@ -0,0 +1,37 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define VERBOSE_DEBUG 2
|
||||
#define VERBOSE_INFO 1
|
||||
#define VERBOSE_NONE 0
|
||||
|
||||
#include <sys/time.h>
|
||||
void get_time_interval(struct timeval * tdata);
|
||||
|
||||
#ifndef DEBUG_DISABLED
|
||||
|
||||
extern int verbose;
|
||||
|
||||
#define VERBOSE_ISINFO() (verbose==VERBOSE_INFO)
|
||||
#define VERBOSE_ISDEBUG() (verbose==VERBOSE_DEBUG)
|
||||
|
||||
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
|
||||
#define PRINT_INFO verbose=VERBOSE_INFO
|
||||
#define PRINT_NONE verbose=VERBOSE_NONE
|
||||
|
||||
#define DEBUG(_fmt, ...) if (verbose >= VERBOSE_DEBUG) \
|
||||
fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__)
|
||||
|
||||
#define INFO(_fmt, ...) if (verbose >= VERBOSE_INFO) \
|
||||
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
|
||||
|
||||
#else
|
||||
|
||||
#define DEBUG
|
||||
#define INFO
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DFT_H_
|
||||
#define DFT_H_
|
||||
|
||||
#include <fftw3.h>
|
||||
|
||||
|
||||
/* dft is a frontend to the fftw3 library. It facilitates the computation of complex or real DFT,
|
||||
* power spectral density, normalization, etc.
|
||||
* It also supports the creation of multiple FFT plans for different FFT sizes or options, selecting
|
||||
* a different one at runtime.
|
||||
*/
|
||||
|
||||
|
||||
typedef enum {
|
||||
COMPLEX_2_COMPLEX, REAL_2_REAL, COMPLEX_2_REAL
|
||||
}dft_mode_t;
|
||||
|
||||
typedef enum {
|
||||
FORWARD, BACKWARD
|
||||
}dft_dir_t;
|
||||
|
||||
|
||||
#define DFT_MIRROR_PRE 1
|
||||
#define DFT_PSD 2
|
||||
#define DFT_OUT_DB 4
|
||||
#define DFT_MIRROR_POS 8
|
||||
#define DFT_NORMALIZE 16
|
||||
#define DFT_DC_OFFSET 32
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
int sign;
|
||||
void *in;
|
||||
void *out;
|
||||
void *p;
|
||||
int options;
|
||||
dft_dir_t dir;
|
||||
dft_mode_t mode;
|
||||
}dft_plan_t;
|
||||
|
||||
typedef _Complex float dft_c_t;
|
||||
typedef float dft_r_t;
|
||||
|
||||
/* Create DFT plans */
|
||||
|
||||
int dft_plan(const int dft_points, dft_mode_t mode, dft_dir_t dir, dft_plan_t *plan);
|
||||
int dft_plan_c2c(const int dft_points, dft_dir_t dir, dft_plan_t *plan);
|
||||
int dft_plan_r2r(const int dft_points, dft_dir_t dir, dft_plan_t *plan);
|
||||
int dft_plan_c2r(const int dft_points, dft_dir_t dir, dft_plan_t *plan);
|
||||
|
||||
void dft_plan_free(dft_plan_t *plan);
|
||||
|
||||
|
||||
/* Create a vector of DFT plans */
|
||||
|
||||
int dft_plan_vector(const int *dft_points, dft_mode_t *modes, dft_dir_t *dirs,
|
||||
int nof_plans, dft_plan_t *plans);
|
||||
int dft_plan_multi_c2c(const int *dft_points, dft_dir_t dir, int nof_plans,
|
||||
dft_plan_t *plans);
|
||||
int dft_plan_multi_c2r(const int *dft_points, dft_dir_t dir, int nof_plans,
|
||||
dft_plan_t *plans);
|
||||
int dft_plan_multi_r2r(const int *dft_points, dft_dir_t dir, int nof_plans,
|
||||
dft_plan_t *plans);
|
||||
void dft_plan_free_vector(dft_plan_t *plan, int nof_plans);
|
||||
|
||||
/* Compute DFT */
|
||||
|
||||
void dft_run(dft_plan_t *plan, void *in, void *out);
|
||||
void dft_run_c2c(dft_plan_t *plan, dft_c_t *in, dft_c_t *out);
|
||||
void dft_run_r2r(dft_plan_t *plan, dft_r_t *in, dft_r_t *out);
|
||||
void dft_run_c2r(dft_plan_t *plan, dft_c_t *in, dft_r_t *out);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef MATRIX_
|
||||
#define MATRIX_
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
int matrix_init(void ***m, int sz_x, int sz_y, int elem_sz);
|
||||
void matrix_free(void **q, int sz_x);
|
||||
void matrix_bzero(void **q, int sz_x, int sz_y, int elem_sz);
|
||||
void matrix_fprintf_cf(FILE *f, cf_t **q, int sz_x, int sz_y);
|
||||
void matrix_fprintf_f(FILE *f, float **q, int sz_x, int sz_y);
|
||||
void matrix_copy(void **dst, void **src, int sz_x, int sz_y, int elem_sz);
|
||||
void matrix_dotprod_cf(cf_t **x, cf_t **y, cf_t **out, int sz_x, int sz_y);
|
||||
void matrix_dotprod_float(float **x, float **y, float **out, int sz_x, int sz_y);
|
||||
void matrix_dotprod_int(int **x, int **y, int **out, int sz_x, int sz_y);
|
||||
|
||||
#endif
|
||||
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MUX_
|
||||
#define MUX_
|
||||
|
||||
void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs,
|
||||
int sample_sz);
|
||||
|
||||
void demux(void *input, void **output, int *output_lengths,
|
||||
int *output_padding_pre, int *output_padding_post, int nof_outputs,
|
||||
int sample_sz);
|
||||
|
||||
#endif
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef NCO_
|
||||
#define NCO_
|
||||
|
||||
#include <complex.h>
|
||||
|
||||
typedef struct {
|
||||
int size;
|
||||
float *cost;
|
||||
float *sint;
|
||||
}nco_t;
|
||||
|
||||
void nco_init(nco_t *nco, int size);
|
||||
void nco_destroy(nco_t *nco);
|
||||
|
||||
float nco_sin(nco_t *nco, float phase);
|
||||
float nco_cos(nco_t *nco, float phase);
|
||||
void nco_sincos(nco_t *nco, float phase, float *sin, float *cos);
|
||||
_Complex float nco_cexp(nco_t *nco, float arg);
|
||||
|
||||
void nco_sin_f(nco_t *nco, float *x, float freq, int len);
|
||||
void nco_cos_f(nco_t *nco, float *x, float freq, int len);
|
||||
void nco_cexp_f(nco_t *nco, _Complex float *x, float freq, int len);
|
||||
void nco_cexp_f_direct(_Complex float *x, float freq, int len);
|
||||
|
||||
#endif
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PACK_
|
||||
#define PACK_
|
||||
|
||||
unsigned int unpack_bits(char **bits, int nof_bits);
|
||||
void pack_bits(unsigned int value, char **bits, int nof_bits);
|
||||
|
||||
#endif
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef VECTOR_
|
||||
#define VECTOR_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int sum_i(int *x, int len);
|
||||
float sum_r(float *x, int len);
|
||||
_Complex float sum_c(_Complex float *x, int len);
|
||||
|
||||
void *vec_malloc(int size);
|
||||
void vec_fprint_c(FILE *stream, _Complex float *x, int len);
|
||||
void vec_fprint_f(FILE *stream, float *x, int len);
|
||||
void vec_fprint_i(FILE *stream, int *x, int len);
|
||||
|
||||
void vec_sum_ch(char *z, char *x, char *y, int len);
|
||||
void vec_sum_c(_Complex float *z, _Complex float *x, _Complex float *y, int len);
|
||||
void vec_mult_c_r(_Complex float *x,_Complex float *y, float h, int len);
|
||||
void vec_mult_c(_Complex float *x,_Complex float *y, _Complex float h, int len);
|
||||
void vec_conj(_Complex float *x, _Complex float *y, int len);
|
||||
float vec_power(_Complex float *x, int len);
|
||||
void vec_dot_prod(_Complex float *x,_Complex float *y, _Complex float *z, int len);
|
||||
void vec_dot_prod_u(_Complex float *x,_Complex float *y, _Complex float *z, int len);
|
||||
void vec_max(float *x, float *max, int *pos, int len);
|
||||
void vec_abs(_Complex float *x, float *abs, int len);
|
||||
|
||||
#endif
|
@ -0,0 +1,28 @@
|
||||
|
||||
|
||||
file(GLOB modules *)
|
||||
|
||||
SET(SOURCES_ALL "")
|
||||
foreach (_module ${modules})
|
||||
if (IS_DIRECTORY ${_module})
|
||||
file(GLOB_RECURSE tmp "${_module}/src/*.c")
|
||||
LIST(APPEND SOURCES_ALL ${tmp})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
|
||||
|
||||
|
||||
add_library(osld ${SOURCES_ALL})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <complex.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "ch_estimation/chest.h"
|
||||
#include "resampling/interp.h"
|
||||
#include "utils/vector.h"
|
||||
#include "utils/debug.h"
|
||||
|
||||
#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz)
|
||||
#define SF_SZ(q) (2 * SLOT_SZ(q))
|
||||
|
||||
void chest_fprint(chest_t *q, FILE *stream, int nslot, int 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);
|
||||
}
|
||||
|
||||
void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
|
||||
int i;
|
||||
fprintf(stream, "refs=[");
|
||||
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].simbol,
|
||||
__imag__ q->refsignal[port_id][nslot].refs[i].simbol);
|
||||
}
|
||||
fprintf(stream, "];\n");
|
||||
}
|
||||
|
||||
void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
|
||||
int i;
|
||||
fprintf(stream, "recvsig=[");
|
||||
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].recv_simbol,
|
||||
__imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol);
|
||||
}
|
||||
fprintf(stream, "];\n");
|
||||
}
|
||||
|
||||
void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
|
||||
int i;
|
||||
fprintf(stream, "mag=[");
|
||||
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=[");
|
||||
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");
|
||||
}
|
||||
|
||||
void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) {
|
||||
int fidx, tidx;
|
||||
cf_t known_ref, channel_ref;
|
||||
|
||||
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].simbol;
|
||||
channel_ref = input[SAMPLE_IDX(q->symbol_sz, tidx, fidx)];
|
||||
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
|
||||
/* FIXME: compare with treshold */
|
||||
if (channel_ref != 0) {
|
||||
q->refsignal[port_id][nslot].ch_est[nref] = known_ref/channel_ref;
|
||||
} else {
|
||||
q->refsignal[port_id][nslot].ch_est[nref] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes channel estimates for each reference in a slot and port.
|
||||
* Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce
|
||||
*/
|
||||
void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id) {
|
||||
int i, j;
|
||||
cf_t x[2], y[MAX_NSYMB];
|
||||
|
||||
assert(nslot >= 0 && nslot < NSLOTS_X_FRAME);
|
||||
assert(port_id >= 0 && port_id < q->nof_ports);
|
||||
assert(q->refsignal[port_id][nslot].nsymbols <= 2);
|
||||
|
||||
refsignal_t *r = &q->refsignal[port_id][nslot];
|
||||
|
||||
INFO("Estimating channel using %d reference signals\n", r->nof_refs);
|
||||
|
||||
for (i=0;i<r->nof_refs;i++) {
|
||||
chest_ce_ref(q, input, nslot, port_id, i);
|
||||
}
|
||||
|
||||
/* interpolate the symbols with references
|
||||
* in the freq domain */
|
||||
for (i=0;i<r->nsymbols;i++) {
|
||||
interp_linear_offset(&r->ch_est[i * r->nof_refs/2],
|
||||
&ce[r->symbols_ref[i] * q->nof_prb * RE_X_RB], RE_X_RB/2,
|
||||
r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset);
|
||||
|
||||
}
|
||||
/* now interpolate in the time domain */
|
||||
for (i=0;i<q->nof_prb * RE_X_RB; i++) {
|
||||
for (j=0;j<r->nsymbols;j++) {
|
||||
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i];
|
||||
printf("x[%d]=ce[%d]=%.3f\n", j,
|
||||
r->symbols_ref[j] * q->nof_prb * RE_X_RB + i,
|
||||
cabsf(x[j]));
|
||||
}
|
||||
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
|
||||
2, r->symbols_ref[0], 3);
|
||||
for (j=0;j<q->nof_symbols;j++) {
|
||||
printf("ce[%d] = y[%d] =%.3f\n", j * q->nof_prb * RE_X_RB + i, j, cabsf(x[j]));
|
||||
ce[j * q->nof_prb * RE_X_RB + i] = y[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes channel estimates for each reference in a slot.
|
||||
* Saves the result for the p-th port to the pointer ce[p]
|
||||
*/
|
||||
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) {
|
||||
int p;
|
||||
for (p=0;p<q->nof_ports;p++) {
|
||||
chest_ce_slot_port(q, input, ce[p], nslot, p);
|
||||
}
|
||||
}
|
||||
|
||||
int chest_init(chest_t *q, lte_cp_t cp, int nof_prb, int nof_ports) {
|
||||
|
||||
if (nof_ports > MAX_PORTS) {
|
||||
fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS);
|
||||
return -1;
|
||||
}
|
||||
bzero(q, sizeof(chest_t));
|
||||
|
||||
q->nof_ports = nof_ports;
|
||||
q->nof_symbols = CP_NSYMB(cp);
|
||||
q->symbol_sz = lte_symbol_sz(nof_prb);
|
||||
q->cp = cp;
|
||||
q->nof_prb = nof_prb;
|
||||
|
||||
INFO("Initializing channel estimator size %dx%d nof_prb=%d, nof_ports=%d\n",
|
||||
q->nof_symbols, q->symbol_sz, nof_prb, nof_ports);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id) {
|
||||
if (port < 0 || port > q->nof_ports) {
|
||||
return -1;
|
||||
}
|
||||
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
INFO("Setting LTE DL reference signals port=%d, nslot=%d, cell_id=%d\n", port, nslot, cell_id);
|
||||
|
||||
if (refsignal_init_LTEDL(&q->refsignal[port][nslot], port, nslot, cell_id, q->cp, q->nof_prb)) {
|
||||
fprintf(stderr, "Error initiating CRS port=%d, slot=%d\n", port, nslot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) {
|
||||
int p;
|
||||
for (p=0;p<q->nof_ports;p++) {
|
||||
if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int chest_ref_LTEDL(chest_t *q, int cell_id) {
|
||||
int n;
|
||||
for (n=0;n<NSLOTS_X_FRAME;n++) {
|
||||
if (chest_ref_LTEDL_slot(q, n, cell_id)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
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_symbols(chest_t *q, int port_id, int nslot, int l[2]) {
|
||||
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(int) * q->refsignal[port_id][nslot].nsymbols);
|
||||
return q->refsignal[port_id][nslot].nsymbols;
|
||||
}
|
||||
|
||||
|
||||
/** High-level API
|
||||
*/
|
||||
int chest_initialize(chest_hl* h) {
|
||||
|
||||
if (!h->init.ntime) {
|
||||
h->init.ntime = 7;
|
||||
}
|
||||
if (!h->init.nfreq) {
|
||||
h->init.nfreq = 10;
|
||||
}
|
||||
if (!h->init.nof_symbols) {
|
||||
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
|
||||
}
|
||||
if (!h->init.port_id) {
|
||||
h->init.port_id = 0;
|
||||
}
|
||||
if (!h->init.cell_id) {
|
||||
h->init.cell_id = 0;
|
||||
}
|
||||
if (!h->init.nof_prb) {
|
||||
h->init.nof_prb = 6;
|
||||
}
|
||||
|
||||
/* if (chest_LTEDL_init(&h->obj, h->init.ntime, h->init.nfreq,
|
||||
h->init.nof_symbols==CPNORM_NSYMB, h->init.cell_id, h->init.nof_prb)) {
|
||||
return -1;
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** This function can be called in a subframe (1ms) or slot basis (0.5ms) for LTE */
|
||||
int chest_work(chest_hl* hl) {
|
||||
chest_t *q = &hl->obj;
|
||||
/*
|
||||
if (hl->in_len == SF_SZ(q)) {
|
||||
*hl->out_len = chest_LTEDL_run_sf(q, hl->input, hl->output, hl->ctrl_in.slot_id/2);
|
||||
} else if (hl->in_len == SLOT_SZ(q)) {
|
||||
*hl->out_len = chest_LTEDL_run_slot(q, hl->input, hl->output, hl->ctrl_in.slot_id);
|
||||
}
|
||||
*/
|
||||
|
||||
if (*hl->out_len < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int chest_stop(chest_hl* hl) {
|
||||
chest_free(&hl->obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lte/base.h"
|
||||
#include "ch_estimation/refsignal.h"
|
||||
#include "utils/vector.h"
|
||||
#include "utils/debug.h"
|
||||
#include "lte/sequence.h"
|
||||
|
||||
#define idx(x, y) (l*nof_refs_x_symbol+i)
|
||||
|
||||
int refsignal_v(int port_id, int ns, int 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;
|
||||
}
|
||||
|
||||
int refsignal_k(int m, int v, int cell_id) {
|
||||
return 6*m+((v+(cell_id%6))%6);
|
||||
}
|
||||
|
||||
/** Initializes refsignal_t object according to 3GPP 36.211 6.10.1
|
||||
*
|
||||
*/
|
||||
int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot,
|
||||
int cell_id, lte_cp_t cp, int nof_prb) {
|
||||
|
||||
unsigned int c_init;
|
||||
int ns, l, lp[2];
|
||||
int N_cp;
|
||||
int i;
|
||||
int ret = -1;
|
||||
sequence_t seq;
|
||||
int v;
|
||||
int mp;
|
||||
int nof_refs_x_symbol, nof_ref_symbols;
|
||||
|
||||
bzero(q, sizeof(refsignal_t));
|
||||
bzero(&seq, sizeof(sequence_t));
|
||||
|
||||
if (CP_ISNORM(cp)) {
|
||||
N_cp = 1;
|
||||
} else {
|
||||
N_cp = 0;
|
||||
}
|
||||
|
||||
if (port_id < 0 || port_id > (MAX_PORTS - 1)) {
|
||||
fprintf(stderr, "Invalid port id %d\n", port_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (port_id < 2) {
|
||||
nof_ref_symbols = 2;
|
||||
lp[0] = 0;
|
||||
lp[1] = CP_NSYMB(cp) - 3;
|
||||
} else {
|
||||
nof_ref_symbols = 1;
|
||||
lp[0] = 1;
|
||||
}
|
||||
nof_refs_x_symbol = 2 * nof_prb;
|
||||
|
||||
q->nof_refs = nof_refs_x_symbol * nof_ref_symbols;
|
||||
q->nsymbols = nof_ref_symbols;
|
||||
q->symbols_ref = malloc(sizeof(int) * nof_ref_symbols);
|
||||
q->voffset = cell_id%6;
|
||||
if (!q->symbols_ref) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols);
|
||||
|
||||
DEBUG("Initializing %d CRS for LTE DL slot=%d, %d RE in %d symbols\n",
|
||||
q->nof_refs, nslot, nof_refs_x_symbol, 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init)) {
|
||||
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 - nof_prb;
|
||||
|
||||
/* generate signal */
|
||||
__real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2);
|
||||
__imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2);
|
||||
|
||||
/* mapping to resource elements */
|
||||
q->refs[idx(l,i)].freq_idx = refsignal_k(i, v, cell_id)+GUARD_RE(nof_prb);
|
||||
q->refs[idx(l,i)].time_idx = lp[l];
|
||||
|
||||
/* print only first slot */
|
||||
if (ns == 0) {
|
||||
DEBUG("(%-2d,%2d) is mapped to (%-2d,%2d) (mp=%d, v=%d)\n",
|
||||
l,i,q->refs[idx(l,i)].time_idx, q->refs[idx(l,i)].freq_idx-GUARD_RE(nof_prb), mp, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
free_and_exit:
|
||||
sequence_free(&seq);
|
||||
if (ret == -1) {
|
||||
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,50 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <complex.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "gauss.h"
|
||||
#include "channel/ch_awgn.h"
|
||||
|
||||
void ch_awgn(const cf* x, cf* y, float variance, int buff_sz) {
|
||||
_Complex float tmp;
|
||||
int i;
|
||||
|
||||
for (i=0;i<buff_sz;i++) {
|
||||
__real__ tmp = rand_gauss();
|
||||
__imag__ tmp = rand_gauss();
|
||||
tmp *= variance;
|
||||
y[i] = tmp + x[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* High-level API */
|
||||
int ch_awgn_initialize(ch_awgn_hl* hl) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ch_awgn_work(ch_awgn_hl* hl) {
|
||||
ch_awgn(hl->input,hl->output,hl->ctrl_in.variance,hl->in_len);
|
||||
if (hl->out_len) {
|
||||
*hl->out_len = hl->in_len;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
float rand_gauss (void) {
|
||||
float v1,v2,s;
|
||||
|
||||
do {
|
||||
v1 = 2.0 * ((float) rand()/RAND_MAX) - 1;
|
||||
v2 = 2.0 * ((float) rand()/RAND_MAX) - 1;
|
||||
|
||||
s = v1*v1 + v2*v2;
|
||||
} while ( s >= 1.0 );
|
||||
|
||||
if (s == 0.0)
|
||||
return 0.0;
|
||||
else
|
||||
return (v1*sqrt(-2.0 * log(s) / s));
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
float rand_gauss (void);
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**@TODO frontend to FEC library if installed
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "fec/convcoder.h"
|
||||
#include "parity.h"
|
||||
#include "viterbi37.h"
|
||||
|
||||
#define DEB 0
|
||||
|
||||
int decode37(void *o, float *symbols, char *data) {
|
||||
viterbi_t *q = o;
|
||||
int i;
|
||||
int len = q->tail_biting ? q->framebits : (q->framebits + q->K - 1);
|
||||
float amp = 0;
|
||||
|
||||
for (i=0;i<3*len;i++) {
|
||||
if (fabsf(symbols[i] > amp)) {
|
||||
amp = symbols[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* Decode it and make sure we get the right answer */
|
||||
/* Initialize Viterbi decoder */
|
||||
init_viterbi37_port(q->ptr, q->tail_biting?-1:0);
|
||||
|
||||
/* Decode block */
|
||||
update_viterbi37_blk_port(q->ptr, symbols,q->framebits + q->K - 1, amp, len);
|
||||
|
||||
/* Do Viterbi chainback */
|
||||
chainback_viterbi37_port(q->ptr, data, q->framebits, 0);
|
||||
|
||||
return q->framebits;
|
||||
}
|
||||
|
||||
void free37(void *o) {
|
||||
viterbi_t *q = o;
|
||||
delete_viterbi37_port(q->ptr);
|
||||
}
|
||||
|
||||
int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
|
||||
q->K = 7;
|
||||
q->R = 3;
|
||||
q->framebits = framebits;
|
||||
q->tail_biting = tail_biting;
|
||||
q->decode = decode37;
|
||||
q->free = free37;
|
||||
|
||||
if ((q->ptr = create_viterbi37_port(poly, framebits, tail_biting)) == NULL) {
|
||||
fprintf(stderr, "create_viterbi37 failed\n");
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int framebits, bool tail_bitting) {
|
||||
switch(type) {
|
||||
case CONVCODER_37:
|
||||
return init37(q, poly, framebits, tail_bitting);
|
||||
default:
|
||||
fprintf(stderr, "Decoder not implemented\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void viterbi_free(viterbi_t *q) {
|
||||
q->free(q);
|
||||
}
|
||||
|
||||
/* symbols are real-valued */
|
||||
int viterbi_decode(viterbi_t *q, float *symbols, char *data) {
|
||||
return q->decode(q, symbols, data);
|
||||
}
|
||||
|
||||
|
||||
int conv_encode(convcoder_t *q, char *input, char *output) {
|
||||
unsigned int sr;
|
||||
int i,j;
|
||||
int len = q->tail_biting ? q->framelength : (q->framelength + q->K - 1);
|
||||
|
||||
if (q->tail_biting) {
|
||||
sr = 0;
|
||||
for (i=q->framelength - q->K + 1; i<q->framelength; i++) {
|
||||
if (DEB) printf("%3d: sr=%3d, bit=%d\n",i,sr&7,input[i]);
|
||||
sr = (sr << 1) | (input[i] & 1);
|
||||
}
|
||||
} else {
|
||||
sr = 0;
|
||||
}
|
||||
|
||||
if (DEB) printf("state st=%d\n",sr&7);
|
||||
for (i = 0; i < len; i++) {
|
||||
int bit = (i < q->framelength) ? (input[i] & 1) : 0;
|
||||
sr = (sr << 1) | bit;
|
||||
if (DEB) printf("%d, ",input[i]);
|
||||
for (j=0;j<q->R;j++) {
|
||||
output[q->R * i + j] = parity(sr & q->poly[j]);
|
||||
}
|
||||
}
|
||||
if (DEB) printf("\n");
|
||||
if (DEB) printf("state fin=%u\n",sr&7);
|
||||
return q->R*len;
|
||||
}
|
||||
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
|
||||
unsigned int cword;
|
||||
|
||||
unsigned int icrc1(unsigned int crc, unsigned short onech,int long_crc,
|
||||
int left_shift,unsigned int poly)
|
||||
{
|
||||
int i;
|
||||
unsigned int tmp=(unsigned int) (crc ^ (onech << (long_crc >> 1) ));
|
||||
|
||||
for (i=0;i<left_shift;i++) {
|
||||
if (tmp & (0x1<<(long_crc-1)))
|
||||
tmp=(tmp<<1)^poly;
|
||||
else
|
||||
tmp <<= 1;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned int crc(unsigned int crc, char *bufptr, int len,
|
||||
int long_crc,unsigned int poly, int paste_word) {
|
||||
|
||||
int i,k;
|
||||
unsigned int data;
|
||||
int stop;
|
||||
unsigned int ret;
|
||||
|
||||
cword=crc;
|
||||
|
||||
k=0;
|
||||
stop=0;
|
||||
while(!stop) {
|
||||
data=0;
|
||||
for (i=0;i<long_crc/2;i++) {
|
||||
if (bufptr[k] && k<len)
|
||||
data|=(0x1<<(long_crc/2-1-i));
|
||||
k++;
|
||||
if (k==len) {
|
||||
stop=1;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cword=(unsigned int) (icrc1((unsigned int) (cword<<long_crc>>long_crc),
|
||||
data,long_crc,i,poly)<<long_crc)>>long_crc;
|
||||
}
|
||||
|
||||
ret=cword;
|
||||
if (paste_word) {
|
||||
cword<<=32-long_crc;
|
||||
for (i=0;i<long_crc;i++) {
|
||||
bufptr[i+len]=((cword&(0x1<<31))>>31);
|
||||
cword<<=1;
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
/* User include file for libfec
|
||||
* Copyright 2004, Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define __i386__
|
||||
#endif
|
||||
|
||||
/* Determine parity of argument: 1 = odd, 0 = even */
|
||||
#ifdef __i386__
|
||||
static inline int parityb(unsigned char x){
|
||||
__asm__ __volatile__ ("test %1,%1;setpo %0" : "=g"(x) : "r" (x));
|
||||
return x;
|
||||
}
|
||||
#else
|
||||
void partab_init();
|
||||
|
||||
static inline int parityb(unsigned char x){
|
||||
extern unsigned char Partab[256];
|
||||
extern int P_init;
|
||||
if(!P_init){
|
||||
partab_init();
|
||||
}
|
||||
return Partab[x];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static inline int parity(int x){
|
||||
/* Fold down to one byte */
|
||||
x ^= (x >> 16);
|
||||
x ^= (x >> 8);
|
||||
return parityb(x);
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
void *create_viterbi37_port(int polys[3], int len, bool tail_biting);
|
||||
int init_viterbi37_port(void *p, int starting_state);
|
||||
int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate);
|
||||
void delete_viterbi37_port(void *p);
|
||||
int update_viterbi37_blk_port(void *p, float *syms, int nbits, float amp, int framebits);
|
@ -0,0 +1,230 @@
|
||||
/* K=9 r=1/3 Viterbi decoder in portable C
|
||||
* Copyright Aug 2006, Phil Karn, KA9Q
|
||||
* May be used under the terms of the GNU Lesser General Public License (LGPL)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
|
||||
#include "parity.h"
|
||||
#include "viterbi37.h"
|
||||
#include "utils/debug.h"
|
||||
|
||||
typedef union {
|
||||
unsigned int w[64];
|
||||
} metric_t;
|
||||
typedef union {
|
||||
unsigned long w[2];
|
||||
} decision_t;
|
||||
|
||||
static union {
|
||||
unsigned char c[32];
|
||||
} Branchtab37[3];
|
||||
|
||||
#define DEB 0
|
||||
|
||||
/* State info for instance of Viterbi decoder */
|
||||
struct v37 {
|
||||
metric_t metrics1; /* path metric buffer 1 */
|
||||
metric_t metrics2; /* path metric buffer 2 */
|
||||
decision_t *dp; /* Pointer to current decision */
|
||||
metric_t *old_metrics, *new_metrics; /* Pointers to path metrics, swapped on every bit */
|
||||
decision_t *decisions; /* Beginning of decisions for block */
|
||||
};
|
||||
|
||||
/* Initialize Viterbi decoder for start of new frame */
|
||||
int init_viterbi37_port(void *p, int starting_state) {
|
||||
struct v37 *vp = p;
|
||||
int i;
|
||||
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
vp->metrics1.w[i] = 63;
|
||||
|
||||
vp->old_metrics = &vp->metrics1;
|
||||
vp->new_metrics = &vp->metrics2;
|
||||
vp->dp = vp->decisions;
|
||||
if (starting_state != -1) {
|
||||
vp->old_metrics->w[starting_state & 63] = 0; /* Bias known start state */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_viterbi37_polynomial_port(int polys[3]) {
|
||||
int state;
|
||||
|
||||
for (state = 0; state < 32; state++) {
|
||||
Branchtab37[0].c[state] =
|
||||
(polys[0] < 0) ^ parity((2 * state) & abs(polys[0])) ? 255 : 0;
|
||||
Branchtab37[1].c[state] =
|
||||
(polys[1] < 0) ^ parity((2 * state) & abs(polys[1])) ? 255 : 0;
|
||||
Branchtab37[2].c[state] =
|
||||
(polys[2] < 0) ^ parity((2 * state) & abs(polys[2])) ? 255 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new instance of a Viterbi decoder */
|
||||
void *create_viterbi37_port(int polys[3], int len, bool tail_biting) {
|
||||
struct v37 *vp;
|
||||
|
||||
set_viterbi37_polynomial_port(polys);
|
||||
|
||||
if ((vp = (struct v37 *) malloc(sizeof(struct v37))) == NULL)
|
||||
return NULL ;
|
||||
|
||||
if ((vp->decisions = (decision_t *) malloc((len + 6) * sizeof(decision_t)))
|
||||
== NULL) {
|
||||
free(vp);
|
||||
return NULL ;
|
||||
}
|
||||
init_viterbi37_port(vp, tail_biting?-1:0);
|
||||
|
||||
return vp;
|
||||
}
|
||||
|
||||
/* Viterbi chainback */
|
||||
int chainback_viterbi37_port(void *p, char *data, /* Decoded output data */
|
||||
unsigned int nbits, /* Number of data bits */
|
||||
unsigned int endstate) { /* Terminal encoder state */
|
||||
|
||||
struct v37 *vp = p;
|
||||
decision_t *d;
|
||||
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
|
||||
d = vp->decisions;
|
||||
|
||||
/* Make room beyond the end of the encoder register so we can
|
||||
* accumulate a full byte of decoded data
|
||||
*/
|
||||
|
||||
endstate=0;
|
||||
/* The store into data[] only needs to be done every 8 bits.
|
||||
* But this avoids a conditional branch, and the writes will
|
||||
* combine in the cache anyway
|
||||
*/
|
||||
d += 6; /* Look past tail */
|
||||
while (nbits-- != 0) {
|
||||
int k;
|
||||
|
||||
k = (d[nbits].w[(endstate >> 2) / 32] >> ((endstate >> 2) % 32)) & 1;
|
||||
endstate = (endstate >> 1) | (k << 7);
|
||||
data[nbits] = k;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Delete instance of a Viterbi decoder */
|
||||
void delete_viterbi37_port(void *p) {
|
||||
struct v37 *vp = p;
|
||||
|
||||
if (vp != NULL) {
|
||||
free(vp->decisions);
|
||||
free(vp);
|
||||
}
|
||||
}
|
||||
|
||||
/* C-language butterfly */
|
||||
#define BFLY(i) {\
|
||||
unsigned int 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;\
|
||||
m1 = vp->old_metrics->w[i+32] + (765 - metric);\
|
||||
decision = (signed int)(m0-m1) > 0;\
|
||||
vp->new_metrics->w[2*i] = decision ? m1 : m0;\
|
||||
d->w[i/16] |= decision << ((2*i)&31);\
|
||||
m0 -= (metric+metric-765);\
|
||||
m1 += (metric+metric-765);\
|
||||
decision = (signed int)(m0-m1) > 0;\
|
||||
vp->new_metrics->w[2*i+1] = decision ? m1 : m0;\
|
||||
d->w[i/16] |= decision << ((2*i+1)&31);\
|
||||
}
|
||||
|
||||
unsigned char tochar_clip(float sym, float amp) {
|
||||
float ret = sym * (127.5 / amp) + 127.5;
|
||||
if (ret > 255) {
|
||||
ret = 255;
|
||||
}
|
||||
if (ret < 0) {
|
||||
ret = 0;
|
||||
}
|
||||
return (unsigned char) ret;
|
||||
}
|
||||
|
||||
/* Update decoder with a block of demodulated symbols
|
||||
* Note that nbits is the number of decoded data bits, not the number
|
||||
* of symbols!
|
||||
*/
|
||||
|
||||
int update_viterbi37_blk_port(void *p, float *syms, int nbits, float amp, int framebits) {
|
||||
struct v37 *vp = p;
|
||||
decision_t *d;
|
||||
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
int k=0;
|
||||
d = (decision_t *) vp->dp;
|
||||
|
||||
while (nbits--) {
|
||||
void *tmp;
|
||||
unsigned char sym0, sym1, sym2;
|
||||
|
||||
d->w[0] = d->w[1] = 0;
|
||||
|
||||
k++;
|
||||
|
||||
if (k < framebits) {
|
||||
sym0 = tochar_clip(*syms++, amp);
|
||||
sym1 = tochar_clip(*syms++, amp);
|
||||
sym2 = tochar_clip(*syms++, amp);
|
||||
} else {
|
||||
sym0=255;
|
||||
sym1=255;
|
||||
sym2=255;
|
||||
}
|
||||
|
||||
BFLY(0);
|
||||
BFLY(1);
|
||||
BFLY(2);
|
||||
BFLY(3);
|
||||
BFLY(4);
|
||||
BFLY(5);
|
||||
BFLY(6);
|
||||
BFLY(7);
|
||||
BFLY(8);
|
||||
BFLY(9);
|
||||
BFLY(10);
|
||||
BFLY(11);
|
||||
BFLY(12);
|
||||
BFLY(13);
|
||||
BFLY(14);
|
||||
BFLY(15);
|
||||
BFLY(16);
|
||||
BFLY(17);
|
||||
BFLY(18);
|
||||
BFLY(19);
|
||||
BFLY(20);
|
||||
BFLY(21);
|
||||
BFLY(22);
|
||||
BFLY(23);
|
||||
BFLY(24);
|
||||
BFLY(25);
|
||||
BFLY(26);
|
||||
BFLY(27);
|
||||
BFLY(28);
|
||||
BFLY(29);
|
||||
BFLY(30);
|
||||
BFLY(31);
|
||||
|
||||
d++;
|
||||
tmp = vp->old_metrics;
|
||||
vp->old_metrics = vp->new_metrics;
|
||||
vp->new_metrics = tmp;
|
||||
}
|
||||
vp->dp = d;
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "utils/debug.h"
|
||||
|
||||
#include "filter/filter2d.h"
|
||||
#include "utils/matrix.h"
|
||||
#include "utils/vector.h"
|
||||
#include "utils/debug.h"
|
||||
|
||||
/* Useful macros */
|
||||
#define intceil(X, Y) ((X-1)/Y+1)
|
||||
|
||||
#define idx(a, b) ((a)*(q->szfreq)+b)
|
||||
|
||||
int filter2d_init(filter2d_t* q, float **taps, int ntime, int nfreq, int sztime,
|
||||
int szfreq) {
|
||||
|
||||
int ret = -1;
|
||||
bzero(q, sizeof(filter2d_t));
|
||||
|
||||
if (matrix_init((void***)&q->taps, ntime, nfreq, sizeof(float))) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
matrix_copy((void**) q->taps, (void**) taps, ntime, nfreq, sizeof(float));
|
||||
|
||||
q->output = vec_malloc((ntime+sztime)*(szfreq)*sizeof(cf_t));
|
||||
if (!q->output) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
bzero(q->output, (ntime+sztime)*(szfreq)*sizeof(cf_t));
|
||||
|
||||
q->nfreq = nfreq;
|
||||
q->ntime = ntime;
|
||||
q->szfreq = szfreq;
|
||||
q->sztime = sztime;
|
||||
|
||||
ret = 0;
|
||||
|
||||
free_and_exit: if (ret == -1) {
|
||||
filter2d_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void filter2d_free(filter2d_t *q) {
|
||||
|
||||
matrix_free((void**) q->taps, q->ntime);
|
||||
if (q->output) {
|
||||
free(q->output);
|
||||
}
|
||||
bzero(q, sizeof(filter2d_t));
|
||||
}
|
||||
|
||||
int filter2d_init_default(filter2d_t* q, int ntime, int nfreq, int sztime,
|
||||
int szfreq) {
|
||||
|
||||
int i, j;
|
||||
int ret = -1;
|
||||
float **taps;
|
||||
|
||||
if (matrix_init((void***) &taps, ntime, nfreq, sizeof(float))) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
/* Compute the default 2-D interpolation mesh */
|
||||
for (i = 0; i < ntime; i++) {
|
||||
for (j = 0; j < nfreq; j++) {
|
||||
if (j < nfreq / 2)
|
||||
taps[i][j] = (j + 1.0) / (2.0 * intceil(nfreq, 2));
|
||||
|
||||
else if (j == nfreq / 2)
|
||||
taps[i][j] = 0.5;
|
||||
|
||||
else if (j > nfreq / 2)
|
||||
taps[i][j] = (nfreq - j) / (2.0 * intceil(nfreq, 2));
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Using default interpolation matrix of size %dx%d\n", ntime, nfreq);
|
||||
if (verbose >= VERBOSE_DEBUG) {
|
||||
matrix_fprintf_f(stdout, taps, ntime, nfreq);
|
||||
}
|
||||
|
||||
if (filter2d_init(q, taps, ntime, nfreq, sztime, szfreq)) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
free_and_exit:
|
||||
matrix_free((void**) taps, ntime);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Moves the last ntime symbols to the start and clears the remaining of the output.
|
||||
* Should be called, for instance, before filtering each OFDM frame.
|
||||
*/
|
||||
void filter2d_reset(filter2d_t *q) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < q->ntime; i++) {
|
||||
memcpy(&q->output[idx(i,0)], &q->output[idx(q->sztime + i,0)],
|
||||
sizeof(cf_t) * (q->szfreq));
|
||||
}
|
||||
for (; i < q->ntime + q->sztime; i++) {
|
||||
memset(&q->output[idx(i,0)], 0, sizeof(cf_t) * (q->szfreq));
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds samples x to the from the given time/freq indexes to the filter
|
||||
* and computes the output.
|
||||
*/
|
||||
void filter2d_add(filter2d_t *q, cf_t x, int time_idx, int freq_idx) {
|
||||
int i, j;
|
||||
|
||||
int ntime = q->ntime;
|
||||
int nfreq = q->nfreq;
|
||||
|
||||
for (i = 0; i < ntime; i++) {
|
||||
for (j = 0; j < nfreq; j++) {
|
||||
q->output[idx(i+time_idx, j+freq_idx - nfreq/2)] += x * (cf_t)(q->taps[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "io/binsource.h"
|
||||
#include "utils/bit.h"
|
||||
|
||||
#define DIV(a,b) ((a-1)/b+1)
|
||||
|
||||
|
||||
/* Internal functions */
|
||||
static int gen_seq_buff(binsource_t* q, int nwords) {
|
||||
if (q->seq_buff_nwords != nwords) {
|
||||
free(q->seq_buff);
|
||||
q->seq_buff_nwords = 0;
|
||||
}
|
||||
if (!q->seq_buff_nwords) {
|
||||
q->seq_buff = malloc(nwords*sizeof(uint32_t));
|
||||
if (!q->seq_buff) {
|
||||
return -1;
|
||||
}
|
||||
q->seq_buff_nwords = nwords;
|
||||
}
|
||||
for (int i=0;i<q->seq_buff_nwords;i++) {
|
||||
q->seq_buff[i] = rand_r(&q->seed);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Low-level API */
|
||||
|
||||
/**
|
||||
* Initializes the binsource object.
|
||||
*/
|
||||
void binsource_init(binsource_t* q) {
|
||||
bzero((void*) q,sizeof(binsource_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys binsource object
|
||||
*/
|
||||
void binsource_free(binsource_t* q) {
|
||||
if (q->seq_buff) {
|
||||
free(q->seq_buff);
|
||||
}
|
||||
bzero(q, sizeof(binsource_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a new seed
|
||||
*/
|
||||
void binsource_seed_set(binsource_t* q, unsigned int seed) {
|
||||
q->seed = seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets local time as seed.
|
||||
*/
|
||||
void binsource_seed_time(binsource_t *q) {
|
||||
struct timeval t1;
|
||||
gettimeofday(&t1, NULL);
|
||||
q->seed = t1.tv_usec * t1.tv_sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a sequence of nbits random bits
|
||||
*/
|
||||
int binsource_cache_gen(binsource_t* q, int nbits) {
|
||||
if (gen_seq_buff(q,DIV(nbits,32))) {
|
||||
return -1;
|
||||
}
|
||||
q->seq_cache_nbits = nbits;
|
||||
q->seq_cache_rp = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int int_2_bits(uint32_t* src, char* dst, int nbits) {
|
||||
int n;
|
||||
n=nbits/32;
|
||||
for (int i=0;i<n;i++) {
|
||||
bit_pack(src[i],&dst,32);
|
||||
}
|
||||
bit_pack(src[n],&dst,nbits-n*32);
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the next random bits to the buffer bits from the array generated by binsource_cache_gen
|
||||
*/
|
||||
void binsource_cache_cpy(binsource_t* q, char *bits, int nbits) {
|
||||
q->seq_cache_rp += int_2_bits(&q->seq_buff[q->seq_cache_rp],bits,nbits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores in the bits buffer a sequence of nbits pseudo-random bits.
|
||||
* Overwrites the bits generated using binsource_cache_gen.
|
||||
*/
|
||||
int binsource_generate(binsource_t* q, char *bits, int nbits) {
|
||||
|
||||
if (gen_seq_buff(q,DIV(nbits,32))) {
|
||||
return -1;
|
||||
}
|
||||
int_2_bits(q->seq_buff,bits,nbits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* High-Level API */
|
||||
int binsource_initialize(binsource_hl* hl) {
|
||||
|
||||
binsource_init(&hl->obj);
|
||||
if (hl->init.seed) {
|
||||
binsource_seed_set(&hl->obj,hl->init.seed);
|
||||
} else {
|
||||
binsource_seed_time(&hl->obj);
|
||||
}
|
||||
|
||||
if (hl->init.cache_seq_nbits) {
|
||||
if (binsource_cache_gen(&hl->obj,hl->init.cache_seq_nbits)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int binsource_work(binsource_hl* hl) {
|
||||
int ret = -1;
|
||||
|
||||
if (hl->init.cache_seq_nbits) {
|
||||
binsource_cache_cpy(&hl->obj,hl->output,hl->ctrl_in.nbits);
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = binsource_generate(&hl->obj,hl->output,hl->ctrl_in.nbits);
|
||||
}
|
||||
if (hl->out_len) {
|
||||
if (!ret) {
|
||||
*hl->out_len = hl->ctrl_in.nbits;
|
||||
} else {
|
||||
*hl->out_len = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int binsource_stop(binsource_hl* hl) {
|
||||
binsource_free(&hl->obj);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,92 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <strings.h>
|
||||
|
||||
|
||||
#include "io/filesink.h"
|
||||
|
||||
int filesink_init(filesink_t *q, char *filename, file_data_type_t type) {
|
||||
bzero(q, sizeof(filesink_t));
|
||||
q->f = fopen(filename, "w");
|
||||
if (!q->f) {
|
||||
perror("fopen");
|
||||
return -1;
|
||||
}
|
||||
q->type = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void filesink_close(filesink_t *q) {
|
||||
if (q->f) {
|
||||
fclose(q->f);
|
||||
}
|
||||
bzero(q, sizeof(filesink_t));
|
||||
}
|
||||
|
||||
int filesink_write(filesink_t *q, void *buffer, int nsamples) {
|
||||
int i;
|
||||
float *fbuf = (float*) buffer;
|
||||
_Complex float *cbuf = (_Complex float*) buffer;
|
||||
_Complex short *sbuf = (_Complex short*) buffer;
|
||||
int size;
|
||||
|
||||
switch(q->type) {
|
||||
case FLOAT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
fprintf(q->f,"%g\n",fbuf[i]);
|
||||
}
|
||||
break;
|
||||
case COMPLEX_FLOAT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
if (__imag__ cbuf[i] >= 0)
|
||||
fprintf(q->f,"%g+%gi\n",__real__ cbuf[i],__imag__ cbuf[i]);
|
||||
else
|
||||
fprintf(q->f,"%g-%gi\n",__real__ cbuf[i],fabsf(__imag__ cbuf[i]));
|
||||
}
|
||||
break;
|
||||
case COMPLEX_SHORT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
if (__imag__ sbuf[i] >= 0)
|
||||
fprintf(q->f,"%hd+%hdi\n",__real__ sbuf[i],__imag__ sbuf[i]);
|
||||
else
|
||||
fprintf(q->f,"%hd-%hdi\n",__real__ sbuf[i],(short) abs(__imag__ sbuf[i]));
|
||||
}
|
||||
break;
|
||||
case FLOAT_BIN:
|
||||
case COMPLEX_FLOAT_BIN:
|
||||
case COMPLEX_SHORT_BIN:
|
||||
if (q->type == FLOAT_BIN) {
|
||||
size = sizeof(float);
|
||||
} else if (q->type == COMPLEX_FLOAT_BIN) {
|
||||
size = sizeof(_Complex float);
|
||||
} else if (q->type == COMPLEX_SHORT_BIN) {
|
||||
size = sizeof(_Complex short);
|
||||
}
|
||||
return fwrite(buffer, size, nsamples, q->f);
|
||||
break;
|
||||
default:
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int filesink_initialize(filesink_hl* h) {
|
||||
return filesink_init(&h->obj, h->init.file_name, h->init.data_type);
|
||||
}
|
||||
|
||||
int filesink_work(filesink_hl* h) {
|
||||
if (filesink_write(&h->obj, h->input, h->in_len)<0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filesink_stop(filesink_hl* h) {
|
||||
filesink_close(&h->obj);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "io/filesource.h"
|
||||
|
||||
int filesource_init(filesource_t *q, char *filename, file_data_type_t type) {
|
||||
bzero(q, sizeof(filesource_t));
|
||||
q->f = fopen(filename, "r");
|
||||
if (!q->f) {
|
||||
perror("fopen");
|
||||
return -1;
|
||||
}
|
||||
q->type = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void filesource_close(filesource_t *q) {
|
||||
if (q->f) {
|
||||
fclose(q->f);
|
||||
}
|
||||
bzero(q, sizeof(filesource_t));
|
||||
}
|
||||
|
||||
int read_complex_f(FILE *f, _Complex float *y) {
|
||||
char in_str[64];
|
||||
_Complex float x;
|
||||
if (NULL == fgets(in_str, 64, f)) {
|
||||
return -1;
|
||||
} else {
|
||||
if (index(in_str, 'i') || index(in_str, 'j')) {
|
||||
sscanf(in_str,"%f%fi",&(__real__ x),&(__imag__ x));
|
||||
} else {
|
||||
__imag__ x = 0;
|
||||
sscanf(in_str,"%f",&(__real__ x));
|
||||
}
|
||||
*y = x;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int filesource_read(filesource_t *q, void *buffer, int nsamples) {
|
||||
int i;
|
||||
float *fbuf = (float*) buffer;
|
||||
_Complex float *cbuf = (_Complex float*) buffer;
|
||||
_Complex short *sbuf = (_Complex short*) buffer;
|
||||
int size;
|
||||
|
||||
switch(q->type) {
|
||||
case FLOAT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
if (EOF == fscanf(q->f,"%g\n",&fbuf[i]))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case COMPLEX_FLOAT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
if (read_complex_f(q->f, &cbuf[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COMPLEX_SHORT:
|
||||
for (i=0;i<nsamples;i++) {
|
||||
if (EOF == fscanf(q->f,"%hd%hdi\n",&(__real__ sbuf[i]),&(__imag__ sbuf[i])))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLOAT_BIN:
|
||||
case COMPLEX_FLOAT_BIN:
|
||||
case COMPLEX_SHORT_BIN:
|
||||
if (q->type == FLOAT_BIN) {
|
||||
size = sizeof(float);
|
||||
} else if (q->type == COMPLEX_FLOAT_BIN) {
|
||||
size = sizeof(_Complex float);
|
||||
} else if (q->type == COMPLEX_SHORT_BIN) {
|
||||
size = sizeof(_Complex short);
|
||||
}
|
||||
return fread(buffer, size, nsamples, q->f);
|
||||
break;
|
||||
default:
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
int filesource_initialize(filesource_hl* h) {
|
||||
return filesource_init(&h->obj, h->init.file_name, h->init.data_type);
|
||||
}
|
||||
|
||||
int filesource_work(filesource_hl* h) {
|
||||
*h->out_len = filesource_read(&h->obj, h->output, h->ctrl_in.nsamples);
|
||||
if (*h->out_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int filesource_stop(filesource_hl* h) {
|
||||
filesource_close(&h->obj);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lte/base.h"
|
||||
#include "utils/dft.h"
|
||||
#include "lte/fft.h"
|
||||
|
||||
int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int symbol_sz, dft_dir_t dir) {
|
||||
|
||||
if (dft_plan_c2c(symbol_sz, dir, &q->fft_plan)) {
|
||||
return -1;
|
||||
}
|
||||
q->fft_plan.options = DFT_DC_OFFSET | DFT_MIRROR_POS | DFT_NORMALIZE;
|
||||
q->nof_symbols = CP_NSYMB(cp_type);
|
||||
q->symbol_sz = symbol_sz;
|
||||
q->cp_type = cp_type;
|
||||
return 0;
|
||||
}
|
||||
void lte_fft_free_(lte_fft_t *q) {
|
||||
dft_plan_free(&q->fft_plan);
|
||||
bzero(q, sizeof(lte_fft_t));
|
||||
}
|
||||
|
||||
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int symbol_sz) {
|
||||
return lte_fft_init_(q, cp_type, symbol_sz, FORWARD);
|
||||
}
|
||||
void lte_fft_free(lte_fft_t *q) {
|
||||
lte_fft_free_(q);
|
||||
}
|
||||
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int symbol_sz) {
|
||||
return lte_fft_init_(q, cp_type, symbol_sz, BACKWARD);
|
||||
}
|
||||
void lte_ifft_free(lte_fft_t *q) {
|
||||
lte_fft_free_(q);
|
||||
}
|
||||
|
||||
/* Transforms input samples into output OFDM symbols.
|
||||
* Performs FFT on a each symbol and removes CP.
|
||||
*/
|
||||
void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
|
||||
int i;
|
||||
for (i=0;i<q->nof_symbols;i++) {
|
||||
input += CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz);
|
||||
dft_run_c2c(&q->fft_plan, input, output);
|
||||
input += q->symbol_sz;
|
||||
output += q->symbol_sz;
|
||||
}
|
||||
}
|
||||
|
||||
/* Transforms input OFDM symbols into output samples.
|
||||
* Performs FFT on a each symbol and adds CP.
|
||||
*/
|
||||
void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
|
||||
fprintf(stderr, "Error: Not implemented\n");
|
||||
}
|
||||
|
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lte/base.h"
|
||||
|
||||
const int lte_symbol_sz(int nof_prb) {
|
||||
if (nof_prb<=0) {
|
||||
return -1;
|
||||
}
|
||||
if (nof_prb<=6) {
|
||||
return 128;
|
||||
} else if (nof_prb<=15) {
|
||||
return 256;
|
||||
} else if (nof_prb<=25) {
|
||||
return 512;
|
||||
} else if (nof_prb<=50) {
|
||||
return 1024;
|
||||
} else if (nof_prb<=75) {
|
||||
return 1536;
|
||||
} else if (nof_prb<=100) {
|
||||
return 2048;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
|
||||
if (nof_ports == 1 && symbol_id==0) {
|
||||
return (cell_id+3) % 6;
|
||||
} else {
|
||||
return cell_id % 6;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the number of available RE per PRB */
|
||||
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
|
||||
if (symbol == 0) {
|
||||
if (((ns % 2) == 0) || (ns == 1)) {
|
||||
return RE_X_RB - 4;
|
||||
} else {
|
||||
if (nof_ports == 1) {
|
||||
return RE_X_RB - 2;
|
||||
} else {
|
||||
return RE_X_RB - 4;
|
||||
}
|
||||
}
|
||||
} else if (symbol == 1) {
|
||||
if (ns == 1) {
|
||||
return RE_X_RB - 4;
|
||||
} else if (nof_ports == 4) {
|
||||
return RE_X_RB - 4;
|
||||
} else {
|
||||
return RE_X_RB;
|
||||
}
|
||||
} else if (symbol == nof_symbols - 3) {
|
||||
if (nof_ports == 1) {
|
||||
return RE_X_RB - 2;
|
||||
} else {
|
||||
return RE_X_RB - 4;
|
||||
}
|
||||
} else {
|
||||
return RE_X_RB;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct lte_band {
|
||||
int band;
|
||||
float fd_low_mhz;
|
||||
int earfcn_offset;
|
||||
int earfcn_max;
|
||||
enum band_geographical_area area;
|
||||
};
|
||||
|
||||
struct lte_band lte_bands[NOF_LTE_BANDS] = {
|
||||
{1, 2110, 0, 599, ALL},
|
||||
{2, 1930, 600, 1199, NAR},
|
||||
{3, 1805, 1200, 1949, ALL},
|
||||
{4, 2110, 1950, 2399, NAR},
|
||||
{5, 869, 2400, 2649, NAR},
|
||||
{6, 875, 2650, 2749, APAC},
|
||||
{7, 2620, 2750, 3449, EMEA},
|
||||
{8, 925, 3450, 3799, ALL},
|
||||
{9, 1844.9, 3800, 4149, APAC},
|
||||
{10, 2110, 4150, 4749, NAR},
|
||||
{11, 1475.9, 4750, 4949, JAPAN},
|
||||
{12, 729, 5010, 5179, NAR},
|
||||
{13, 746, 5180, 5279, NAR},
|
||||
{14, 758, 5280, 5379, NAR},
|
||||
{17, 734, 5730, 5849, NAR},
|
||||
{18, 860, 5850, 5999, JAPAN},
|
||||
{19, 875, 6000, 6149, JAPAN},
|
||||
{20, 791, 6150, 6449, EMEA},
|
||||
{21, 1495.9, 6450, 6599, JAPAN},
|
||||
{22, 3500, 6600, 7399, NA},
|
||||
{23, 2180, 7500, 7699, NAR},
|
||||
{24, 1525, 7700, 8039, NAR},
|
||||
{25, 1930, 8040, 8689, NAR},
|
||||
{26, 859, 8690, 9039, NAR},
|
||||
{27, 852, 9040, 9209, NAR},
|
||||
{28, 758, 9210, 9659, APAC},
|
||||
{29, 717, 9660, 9769, NAR},
|
||||
{30, 2350, 9770, 9869, NAR},
|
||||
{31, 462.5, 9870, 9919, CALA}
|
||||
};
|
||||
#define EOF_BAND 9919
|
||||
|
||||
float get_fd(struct lte_band *band, int earfcn) {
|
||||
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
|
||||
}
|
||||
|
||||
float lte_band_fd(int earfcn) {
|
||||
int i;
|
||||
i=0;
|
||||
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
|
||||
i++;
|
||||
}
|
||||
if (i == NOF_LTE_BANDS) {
|
||||
fprintf(stderr, "Error: EARFCN %d not found\n", earfcn);
|
||||
return -1.0;
|
||||
}
|
||||
return get_fd(<e_bands[i], earfcn);
|
||||
}
|
||||
|
||||
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_elems) {
|
||||
return lte_band_get_fd_band(band, earfcn, -1, -1, max_elems);
|
||||
}
|
||||
|
||||
int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, int max_elems) {
|
||||
int i, j;
|
||||
int nof_earfcn;
|
||||
i=0;
|
||||
while(i < NOF_LTE_BANDS && lte_bands[i].band != band) {
|
||||
i++;
|
||||
}
|
||||
if (i == NOF_LTE_BANDS) {
|
||||
fprintf(stderr, "Error: Invalid band %d\n", band);
|
||||
return -1;
|
||||
}
|
||||
if (end_earfcn == -1) {
|
||||
end_earfcn = lte_bands[i].earfcn_max;
|
||||
} else {
|
||||
if (end_earfcn > lte_bands[i].earfcn_max) {
|
||||
fprintf(stderr, "Error: Invalid end earfcn %d. Max is %d\n", end_earfcn, lte_bands[i].earfcn_max);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (start_earfcn == -1) {
|
||||
start_earfcn = lte_bands[i].earfcn_offset;
|
||||
} else {
|
||||
if (start_earfcn < lte_bands[i].earfcn_offset) {
|
||||
fprintf(stderr, "Error: Invalid start earfcn %d. Min is %d\n", start_earfcn, lte_bands[i].earfcn_offset);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
nof_earfcn = end_earfcn - start_earfcn;
|
||||
|
||||
if (nof_earfcn > max_elems) {
|
||||
nof_earfcn = max_elems;
|
||||
}
|
||||
for (j=0;j<nof_earfcn;j++) {
|
||||
earfcn[j].id = j + start_earfcn;
|
||||
earfcn[j].fd = get_fd(<e_bands[i], earfcn[j].id);
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) {
|
||||
int i;
|
||||
int n;
|
||||
int nof_fd = 0;
|
||||
for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) {
|
||||
if (lte_bands[i].area == region) {
|
||||
n = lte_band_get_fd_band(i, &earfcn[nof_fd], -1, -1, max_elems);
|
||||
if (n != -1) {
|
||||
nof_fd += n;
|
||||
max_elems -= n;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nof_fd;
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lte/base.h"
|
||||
#include "lte/sequence.h"
|
||||
|
||||
int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id) {
|
||||
return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id);
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "lte/sequence.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define Nc 1600
|
||||
#define GOLDMAXLEN (Nc*10)
|
||||
static int x1[GOLDMAXLEN];
|
||||
static int x2[GOLDMAXLEN];
|
||||
|
||||
|
||||
/*
|
||||
* Pseudo Random Sequence generation.
|
||||
* It follows the 3GPP Release 8 (LTE) 36.211
|
||||
* Section 7.2
|
||||
*/
|
||||
void generate_prs_c(sequence_t *q, unsigned int seed) {
|
||||
int n;
|
||||
|
||||
assert(q->len + Nc + 31 < GOLDMAXLEN);
|
||||
|
||||
for (n = 0; n < 31; n++) {
|
||||
x1[n] = 0;
|
||||
x2[n] = (seed >> n) & 0x1;
|
||||
}
|
||||
x1[0] = 1;
|
||||
|
||||
for (n = 0; n < Nc + q->len; n++) {
|
||||
x1[n + 31] = (x1[n + 3] + x1[n]) & 0x1;
|
||||
x2[n + 31] = (x2[n + 3] + x2[n + 2] + x2[n]) & 0x1;
|
||||
}
|
||||
|
||||
for (n = 0; n < q->len; n++) {
|
||||
q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int sequence_LTEPRS(sequence_t *q, int len, int seed) {
|
||||
if (sequence_init(q, len)) {
|
||||
return -1;
|
||||
}
|
||||
q->len = len;
|
||||
generate_prs_c(q, seed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sequence_init(sequence_t *q, int len) {
|
||||
if (q->c && (q->len != len)) {
|
||||
free(q->c);
|
||||
}
|
||||
if (!q->c) {
|
||||
q->c = malloc(len * sizeof(char));
|
||||
if (!q->c) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sequence_free(sequence_t *q) {
|
||||
if (q->c) {
|
||||
free(q->c);
|
||||
}
|
||||
bzero(q, sizeof(sequence_t));
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "modem/demod_hard.h"
|
||||
#include "hard_demod_lte.h"
|
||||
|
||||
|
||||
void demod_hard_init(demod_hard_t* q) {
|
||||
bzero((void*) q, sizeof(demod_hard_t));
|
||||
}
|
||||
|
||||
void demod_hard_table(demod_hard_t* q, enum modem_std table) {
|
||||
q->table = table;
|
||||
}
|
||||
|
||||
int demod_hard_demodulate(demod_hard_t* q, const cf* symbols, char *bits, int nsymbols) {
|
||||
|
||||
int nbits=-1;
|
||||
switch(q->table) {
|
||||
case LTE_BPSK:
|
||||
hard_bpsk_demod(symbols,bits,nsymbols);
|
||||
nbits=nsymbols;
|
||||
break;
|
||||
case LTE_QPSK:
|
||||
hard_qpsk_demod(symbols,bits,nsymbols);
|
||||
nbits=nsymbols*2;
|
||||
break;
|
||||
case LTE_QAM16:
|
||||
hard_qam16_demod(symbols,bits,nsymbols);
|
||||
nbits=nsymbols*4;
|
||||
break;
|
||||
case LTE_QAM64:
|
||||
hard_qam64_demod(symbols,bits,nsymbols);
|
||||
nbits=nsymbols*6;
|
||||
break;
|
||||
}
|
||||
return nbits;
|
||||
}
|
||||
|
||||
|
||||
int demod_hard_initialize(demod_hard_hl* hl) {
|
||||
demod_hard_init(&hl->obj);
|
||||
demod_hard_table(&hl->obj,hl->init.std);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int demod_hard_work(demod_hard_hl* hl) {
|
||||
int ret = demod_hard_demodulate(&hl->obj,hl->input,hl->output,hl->in_len);
|
||||
if (hl->out_len) {
|
||||
*hl->out_len = ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "utils/bit.h"
|
||||
#include "modem/demod_soft.h"
|
||||
#include "soft_algs.h"
|
||||
|
||||
|
||||
void demod_soft_init(demod_soft_t *q) {
|
||||
bzero((void*)q,sizeof(demod_soft_t));
|
||||
}
|
||||
|
||||
void demod_soft_table_set(demod_soft_t *q, modem_table_t *table) {
|
||||
q->table = table;
|
||||
}
|
||||
|
||||
void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type) {
|
||||
q->alg_type = alg_type;
|
||||
}
|
||||
|
||||
void demod_soft_sigma_set(demod_soft_t *q, float sigma) {
|
||||
q->sigma = sigma;
|
||||
}
|
||||
|
||||
int demod_soft_demodulate(demod_soft_t *q, const cf* symbols, float* llr, int nsymbols) {
|
||||
switch(q->alg_type) {
|
||||
case EXACT:
|
||||
llr_exact(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
|
||||
q->table->symbol_table, q->table->soft_table.idx, q->sigma);
|
||||
break;
|
||||
case APPROX:
|
||||
llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
|
||||
q->table->symbol_table, q->table->soft_table.idx, q->sigma);
|
||||
break;
|
||||
}
|
||||
return nsymbols*q->table->nbits_x_symbol;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* High-Level API */
|
||||
int demod_soft_initialize(demod_soft_hl* hl) {
|
||||
modem_table_init(&hl->table);
|
||||
if (modem_table_std(&hl->table,hl->init.std,true)) {
|
||||
return -1;
|
||||
}
|
||||
demod_soft_init(&hl->obj);
|
||||
hl->obj.table = &hl->table;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int demod_soft_work(demod_soft_hl* hl) {
|
||||
hl->obj.sigma = hl->ctrl_in.sigma;
|
||||
hl->obj.alg_type = hl->ctrl_in.alg_type;
|
||||
int ret = demod_soft_demodulate(&hl->obj,hl->input,hl->output,hl->in_len);
|
||||
if (hl->out_len) {
|
||||
*hl->out_len = ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int demod_soft_stop(demod_soft_hl* hl) {
|
||||
modem_table_free(&hl->table);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>, Vuk Marojevic <maroje@vt.edu>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "modem/demod_hard.h"
|
||||
#include "hard_demod_lte.h"
|
||||
|
||||
/**
|
||||
* @ingroup Hard BPSK demodulator
|
||||
*
|
||||
*LTE-BPSK constellation:
|
||||
* Q
|
||||
* | 0
|
||||
*---------> I
|
||||
*1 |
|
||||
* \param in input symbols (_Complex float)
|
||||
* \param out output symbols (chars)
|
||||
* \param N Number of input symbols
|
||||
* \param modulation Modulation type
|
||||
*/
|
||||
inline void hard_bpsk_demod(const cf* in, char* out, int N)
|
||||
{
|
||||
int s;
|
||||
|
||||
for (s=0; s<N; s++) { /* received symbols */
|
||||
if (__real__ in[s] > 0) {
|
||||
if ((__imag__ in[s] > 0) || (__real__ in[s] > -__imag__ in[s])) {
|
||||
out[s] = 0x0;
|
||||
} else {
|
||||
out[s] = 0x1;
|
||||
}
|
||||
} else {
|
||||
if ((__imag__ in[s] < 0) || (__imag__ in[s] < -__real__ in[s])) {
|
||||
out[s] = 0x1;
|
||||
} else {
|
||||
out[s] = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Hard QPSK demodulator
|
||||
*
|
||||
* LTE-QPSK constellation:
|
||||
* Q
|
||||
*10 | 00
|
||||
*-----------> I
|
||||
*11 | 01
|
||||
*
|
||||
* \param in input symbols (_Complex float)
|
||||
* \param out output symbols (chars)
|
||||
* \param N Number of input symbols
|
||||
* \param modulation Modulation type
|
||||
*/
|
||||
inline void hard_qpsk_demod(const cf* in, char* out, int N)
|
||||
{
|
||||
int s;
|
||||
|
||||
for (s=0; s<N; s++) {
|
||||
if (__real__ in[s] > 0) {
|
||||
out[2*s] = 0x0;
|
||||
} else {
|
||||
out[2*s] = 0x1;
|
||||
}
|
||||
if (__imag__ in[s] > 0) {
|
||||
out[2*s+1] = 0x0;
|
||||
} else {
|
||||
out[2*s+1] = 0x1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Hard 16QAM demodulator
|
||||
*
|
||||
* LTE-16QAM constellation:
|
||||
* Q
|
||||
* 1011 1001 | 0001 0011
|
||||
* 1010 1000 | 0000 0010
|
||||
*---------------------------------> I
|
||||
* 1110 1100 | 0100 0110
|
||||
* 1111 1101 | 0101 0111
|
||||
*
|
||||
* \param in input symbols (_Complex float)
|
||||
* \param out output symbols (chars)
|
||||
* \param N Number of input symbols
|
||||
* \param modulation Modulation type
|
||||
*/
|
||||
inline void hard_qam16_demod(const cf* in, char* out, int N)
|
||||
{
|
||||
int s;
|
||||
|
||||
for (s=0; s<N; s++) {
|
||||
if (__real__ in[s] > 0) {
|
||||
out[4*s] = 0x0;
|
||||
} else {
|
||||
out[4*s] = 0x1;
|
||||
}
|
||||
|
||||
if ((__real__ in[s] > QAM16_THRESHOLD) || (__real__ in[s] < -QAM16_THRESHOLD)) {
|
||||
out[4*s+2] = 0x1;
|
||||
} else {
|
||||
out[4*s+2] = 0x0;
|
||||
}
|
||||
|
||||
if (__imag__ in[s] > 0) {
|
||||
out[4*s+1] = 0x0;
|
||||
} else {
|
||||
out[4*s+1] = 0x1;
|
||||
}
|
||||
|
||||
if ((__imag__ in[s] > QAM16_THRESHOLD) || (__imag__ in[s] < -QAM16_THRESHOLD)) {
|
||||
out[4*s+3] = 0x1;
|
||||
} else {
|
||||
out[4*s+3] = 0x0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Hard 64QAM demodulator
|
||||
*
|
||||
* LTE-64QAM constellation:
|
||||
* see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4]
|
||||
*
|
||||
* \param in input symbols (_Complex float)
|
||||
* \param out output symbols (chars)
|
||||
* \param N Number of input symbols
|
||||
* \param modulation Modulation type
|
||||
*/
|
||||
inline void hard_qam64_demod(const cf* in, char* out, int N)
|
||||
{
|
||||
int s;
|
||||
|
||||
for (s=0; s<N; s++) {
|
||||
/* bits associated with/obtained from in-phase component: b0, b2, b4 */
|
||||
if (__real__ in[s] > 0){
|
||||
out[6*s] = 0x0;
|
||||
} else {
|
||||
out[6*s] = 0x1;
|
||||
}
|
||||
if ((__real__ in[s] > QAM64_THRESHOLD_3) || (__real__ in[s] < -QAM64_THRESHOLD_3)) {
|
||||
out[6*s+2] = 0x1;
|
||||
out[6*s+4] = 0x1;
|
||||
} else if ((__real__ in[s] > QAM64_THRESHOLD_2) || (__real__ in[s] < -QAM64_THRESHOLD_2)) {
|
||||
out[6*s+2] = 0x1;
|
||||
out[6*s+4] = 0x0;
|
||||
} else if ((__real__ in[s] > QAM64_THRESHOLD_1) || (__real__ in[s] < -QAM64_THRESHOLD_1)) {
|
||||
out[6*s+2] = 0x0;
|
||||
out[6*s+4] = 0x0;
|
||||
} else {
|
||||
out[6*s+2] = 0x0;
|
||||
out[6*s+4] = 0x1;
|
||||
}
|
||||
|
||||
/* bits associated with/obtained from quadrature component: b1, b3, b5 */
|
||||
if (__imag__ in[s] > 0){
|
||||
out[6*s+1] = 0x0;
|
||||
} else {
|
||||
out[6*s+1] = 0x1;
|
||||
}
|
||||
if ((__imag__ in[s] > QAM64_THRESHOLD_3) || (__imag__ in[s] < -QAM64_THRESHOLD_3)) {
|
||||
out[6*s+3] = 0x1;
|
||||
out[6*s+5] = 0x1;
|
||||
} else if ((__imag__ in[s] > QAM64_THRESHOLD_2) || (__imag__ in[s] < -QAM64_THRESHOLD_2)) {
|
||||
out[6*s+3] = 0x1;
|
||||
out[6*s+5] = 0x0;
|
||||
} else if ((__imag__ in[s] > QAM64_THRESHOLD_1) || (__imag__ in[s] < -QAM64_THRESHOLD_1)) {
|
||||
out[6*s+3] = 0x0;
|
||||
out[6*s+5] = 0x0;
|
||||
} else {
|
||||
out[6*s+3] = 0x0;
|
||||
out[6*s+5] = 0x1;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>, Vuk Marojevic <maroje@vt.edu>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Thresholds for Demodulation */
|
||||
/* Assume perfect amplitude and phase alignment.
|
||||
* Check threshold values for real case
|
||||
* or implement dynamic threshold adjustent as a function of received symbol amplitudes */
|
||||
#define QAM16_THRESHOLD 2/sqrt(10)
|
||||
#define QAM64_THRESHOLD_1 2/sqrt(42)
|
||||
#define QAM64_THRESHOLD_2 4/sqrt(42)
|
||||
#define QAM64_THRESHOLD_3 6/sqrt(42)
|
||||
|
||||
void hard_bpsk_demod(const cf* in, char* out, int N);
|
||||
void hard_qpsk_demod(const cf* in, char* out, int N);
|
||||
void hard_qam16_demod(const cf* in, char* out, int N);
|
||||
void hard_qam64_demod(const cf* in, char* out, int N);
|
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>, Vuk Marojevic <maroje@vt.edu>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "modem/modem_table.h"
|
||||
#include "lte_tables.h"
|
||||
|
||||
/**
|
||||
* Set the BPSK modulation table */
|
||||
void set_BPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod)
|
||||
{
|
||||
// LTE-BPSK constellation:
|
||||
// Q
|
||||
// | 0
|
||||
//---------> I
|
||||
// 1 |
|
||||
table[0] = BPSK_LEVEL + BPSK_LEVEL*_Complex_I;
|
||||
table[1] = -BPSK_LEVEL -BPSK_LEVEL*_Complex_I;
|
||||
|
||||
if (!compute_soft_demod) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */
|
||||
soft_table->idx[0][0][0] = 0;
|
||||
soft_table->idx[1][0][0] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the QPSK modulation table */
|
||||
void set_QPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
// LTE-QPSK constellation:
|
||||
// Q
|
||||
// 10 | 00
|
||||
//-----------> I
|
||||
// 11 | 01
|
||||
table[0] = QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
|
||||
table[1] = QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
|
||||
table[2] = -QPSK_LEVEL + QPSK_LEVEL*_Complex_I;
|
||||
table[3] = -QPSK_LEVEL - QPSK_LEVEL*_Complex_I;
|
||||
for (i=0;i<6;i++) {
|
||||
for (j=0;j<32;j++) {
|
||||
soft_table->idx[0][i][j] = 0;
|
||||
soft_table->idx[1][i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!compute_soft_demod) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* QSPK symbols containing a '0' at the different bit positions */
|
||||
soft_table->idx[0][0][0] = 0;
|
||||
soft_table->idx[0][0][1] = 1;
|
||||
soft_table->idx[0][1][0] = 0;
|
||||
soft_table->idx[0][1][1] = 2;
|
||||
/* QSPK symbols containing a '1' at the different bit positions */
|
||||
soft_table->idx[1][0][0] = 2;
|
||||
soft_table->idx[1][0][1] = 3;
|
||||
soft_table->idx[1][1][0] = 1;
|
||||
soft_table->idx[1][1][1] = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 16QAM modulation table */
|
||||
void set_16QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod)
|
||||
{
|
||||
int i,j;
|
||||
// LTE-16QAM constellation:
|
||||
// Q
|
||||
// 1011 1001 | 0001 0011
|
||||
// 1010 1000 | 0000 0010
|
||||
//---------------------------------> I
|
||||
// 1110 1100 | 0100 0110
|
||||
// 1111 1101 | 0101 0111
|
||||
table[0] = QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
|
||||
table[1] = QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
|
||||
table[2] = QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
|
||||
table[3] = QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
|
||||
table[4] = QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
|
||||
table[5] = QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
|
||||
table[6] = QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
|
||||
table[7] = QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
|
||||
table[8] = -QAM16_LEVEL_1 + QAM16_LEVEL_1*_Complex_I;
|
||||
table[9] = -QAM16_LEVEL_1 + QAM16_LEVEL_2*_Complex_I;
|
||||
table[10] = -QAM16_LEVEL_2 + QAM16_LEVEL_1*_Complex_I;
|
||||
table[11] = -QAM16_LEVEL_2 + QAM16_LEVEL_2*_Complex_I;
|
||||
table[12] = -QAM16_LEVEL_1 - QAM16_LEVEL_1*_Complex_I;
|
||||
table[13] = -QAM16_LEVEL_1 - QAM16_LEVEL_2*_Complex_I;
|
||||
table[14] = -QAM16_LEVEL_2 - QAM16_LEVEL_1*_Complex_I;
|
||||
table[15] = -QAM16_LEVEL_2 - QAM16_LEVEL_2*_Complex_I;
|
||||
for (i=0;i<6;i++) {
|
||||
for (j=0;j<32;j++) {
|
||||
soft_table->idx[0][i][j] = 0;
|
||||
soft_table->idx[1][i][j] = 0;
|
||||
}
|
||||
}
|
||||
if (!compute_soft_demod) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Matrices identifying the zeros and ones of LTE-16QAM constellation */
|
||||
for (i=0;i<8;i++) {
|
||||
soft_table->idx[0][0][i] = i; /* symbols with a '0' at the bit0 (leftmost)*/
|
||||
soft_table->idx[1][0][i] = i+8; /* symbols with a '1' at the bit0 (leftmost)*/
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 1: */
|
||||
for (i=0;i<4;i++) {
|
||||
soft_table->idx[0][1][i] = i;
|
||||
soft_table->idx[0][1][i+4] = i+8;
|
||||
soft_table->idx[1][1][i] = i+4;
|
||||
soft_table->idx[1][1][i+4] = i+12;
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 2: */
|
||||
for (j=0;j<4;j++) {
|
||||
for (i=0;i<2;i++) {
|
||||
soft_table->idx[0][2][i+2*j] = i + 4*j;
|
||||
soft_table->idx[1][2][i+2*j] = i+2 + 4*j;
|
||||
}
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 3: */
|
||||
for (i=0;i<8;i++) {
|
||||
soft_table->idx[0][3][i] = 2*i;
|
||||
soft_table->idx[1][3][i] = 2*i+1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the 64QAM modulation table */
|
||||
void set_64QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod)
|
||||
{
|
||||
int i,j;
|
||||
// LTE-64QAM constellation:
|
||||
// see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4]
|
||||
table[0] = QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[1] = QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[2] = QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[3] = QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[4] = QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[5] = QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[6] = QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[7] = QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[8] = QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[9] = QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[10] = QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[11] = QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[12] = QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[13] = QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[14] = QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[15] = QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[16] = QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[17] = QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[18] = QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[19] = QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[20] = QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[21] = QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[22] = QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[23] = QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[24] = QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[25] = QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[26] = QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[27] = QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[28] = QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[29] = QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[30] = QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[31] = QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[32] = -QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[33] = -QAM64_LEVEL_2 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[34] = -QAM64_LEVEL_1 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[35] = -QAM64_LEVEL_1 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[36] = -QAM64_LEVEL_2 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[37] = -QAM64_LEVEL_2 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[38] = -QAM64_LEVEL_1 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[39] = -QAM64_LEVEL_1 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[40] = -QAM64_LEVEL_3 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[41] = -QAM64_LEVEL_3 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[42] = -QAM64_LEVEL_4 + QAM64_LEVEL_2*_Complex_I;
|
||||
table[43] = -QAM64_LEVEL_4 + QAM64_LEVEL_1*_Complex_I;
|
||||
table[44] = -QAM64_LEVEL_3 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[45] = -QAM64_LEVEL_3 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[46] = -QAM64_LEVEL_4 + QAM64_LEVEL_3*_Complex_I;
|
||||
table[47] = -QAM64_LEVEL_4 + QAM64_LEVEL_4*_Complex_I;
|
||||
table[48] = -QAM64_LEVEL_2 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[49] = -QAM64_LEVEL_2 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[50] = -QAM64_LEVEL_1 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[51] = -QAM64_LEVEL_1 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[52] = -QAM64_LEVEL_2 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[53] = -QAM64_LEVEL_2 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[54] = -QAM64_LEVEL_1 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[55] = -QAM64_LEVEL_1 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[56] = -QAM64_LEVEL_3 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[57] = -QAM64_LEVEL_3 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[58] = -QAM64_LEVEL_4 - QAM64_LEVEL_2*_Complex_I;
|
||||
table[59] = -QAM64_LEVEL_4 - QAM64_LEVEL_1*_Complex_I;
|
||||
table[60] = -QAM64_LEVEL_3 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[61] = -QAM64_LEVEL_3 - QAM64_LEVEL_4*_Complex_I;
|
||||
table[62] = -QAM64_LEVEL_4 - QAM64_LEVEL_3*_Complex_I;
|
||||
table[63] = -QAM64_LEVEL_4 - QAM64_LEVEL_4*_Complex_I;
|
||||
|
||||
if (!compute_soft_demod) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Matrices identifying the zeros and ones of LTE-64QAM constellation */
|
||||
|
||||
for (i=0;i<32;i++) {
|
||||
soft_table->idx[0][0][i] = i; /* symbols with a '0' at the bit0 (leftmost)*/
|
||||
soft_table->idx[1][0][i] = i+32; /* symbols with a '1' at the bit0 (leftmost)*/
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 1: */
|
||||
for (i=0;i<16;i++) {
|
||||
soft_table->idx[0][1][i] = i;
|
||||
soft_table->idx[0][1][i+16] = i+32;
|
||||
soft_table->idx[1][1][i] = i+16;
|
||||
soft_table->idx[1][1][i+16] = i+48;
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 2: */
|
||||
for (i=0;i<8;i++) {
|
||||
soft_table->idx[0][2][i] = i;
|
||||
soft_table->idx[0][2][i+8] = i+16;
|
||||
soft_table->idx[0][2][i+16] = i+32;
|
||||
soft_table->idx[0][2][i+24] = i+48;
|
||||
soft_table->idx[1][2][i] = i+8;
|
||||
soft_table->idx[1][2][i+8] = i+24;
|
||||
soft_table->idx[1][2][i+16] = i+40;
|
||||
soft_table->idx[1][2][i+24] = i+56;
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 3: */
|
||||
for (j=0;j<8;j++) {
|
||||
for (i=0;i<4;i++) {
|
||||
soft_table->idx[0][3][i+4*j] = i + 8*j;
|
||||
soft_table->idx[1][3][i+4*j] = i+4 + 8*j;
|
||||
}
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 4: */
|
||||
for (j=0;j<16;j++) {
|
||||
for (i=0;i<2;i++) {
|
||||
soft_table->idx[0][4][i+2*j] = i + 4*j;
|
||||
soft_table->idx[1][4][i+2*j] = i+2 + 4*j;
|
||||
}
|
||||
}
|
||||
/* symbols with a '0' ans '1' at the bit position 5: */
|
||||
for (i=0;i<32;i++) {
|
||||
soft_table->idx[0][5][i] = 2*i;
|
||||
soft_table->idx[1][5][i] = 2*i+1;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>, Vuk Marojevic <maroje@vt.edu>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#define BPSK_LEVEL 1/sqrt(2)
|
||||
|
||||
#define QPSK_LEVEL 1/sqrt(2)
|
||||
|
||||
#define QAM16_LEVEL_1 1/sqrt(10)
|
||||
#define QAM16_LEVEL_2 3/sqrt(10)
|
||||
|
||||
#define QAM64_LEVEL_1 1/sqrt(42)
|
||||
#define QAM64_LEVEL_2 3/sqrt(42)
|
||||
#define QAM64_LEVEL_3 5/sqrt(42)
|
||||
#define QAM64_LEVEL_4 7/sqrt(42)
|
||||
|
||||
#define QAM64_LEVEL_x 2/sqrt(42)
|
||||
/* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the
|
||||
* symbol from the bit sequence */
|
||||
|
||||
|
||||
|
||||
|
||||
void set_BPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod);
|
||||
void set_QPSKtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod);
|
||||
void set_16QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod);
|
||||
void set_64QAMtable(cf* table, soft_table_t *soft_table, bool compute_soft_demod);
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "utils/bit.h"
|
||||
#include "modem/mod.h"
|
||||
|
||||
/** Low-level API */
|
||||
|
||||
int mod_modulate(modem_table_t* q, const char *bits, cf* symbols, int nbits) {
|
||||
int i,j,idx;
|
||||
char *b_ptr=(char*) bits;
|
||||
j=0;
|
||||
for (i=0;i<nbits;i+=q->nbits_x_symbol) {
|
||||
idx = bit_unpack(&b_ptr,q->nbits_x_symbol);
|
||||
symbols[j] = q->symbol_table[idx];
|
||||
j++;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/* High-Level API */
|
||||
int mod_initialize(mod_hl* hl) {
|
||||
modem_table_init(&hl->obj);
|
||||
if (modem_table_std(&hl->obj,hl->init.std,false)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mod_work(mod_hl* hl) {
|
||||
int ret = mod_modulate(&hl->obj,hl->input,hl->output,hl->in_len);
|
||||
if (hl->out_len) {
|
||||
*hl->out_len = ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mod_stop(mod_hl* hl) {
|
||||
modem_table_free(&hl->obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "modem/modem_table.h"
|
||||
#include "lte_tables.h"
|
||||
|
||||
/** Internal functions */
|
||||
static int table_create(modem_table_t* q) {
|
||||
q->symbol_table = malloc(q->nsymbols*sizeof(cf));
|
||||
return q->symbol_table==NULL;
|
||||
}
|
||||
|
||||
void modem_table_init(modem_table_t* q) {
|
||||
bzero((void*)q,sizeof(modem_table_t));
|
||||
}
|
||||
void modem_table_free(modem_table_t* q) {
|
||||
if (q->symbol_table) {
|
||||
free(q->symbol_table);
|
||||
}
|
||||
bzero(q, sizeof(modem_table_t));
|
||||
}
|
||||
void modem_table_reset(modem_table_t* q) {
|
||||
modem_table_free(q);
|
||||
modem_table_init(q);
|
||||
}
|
||||
|
||||
int modem_table_set(modem_table_t* q, cf* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol) {
|
||||
if (q->nsymbols) {
|
||||
return -1;
|
||||
}
|
||||
q->nsymbols = nsymbols;
|
||||
if (table_create(q)) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf));
|
||||
memcpy(&q->soft_table,soft_table,sizeof(soft_table_t));
|
||||
q->nbits_x_symbol = nbits_x_symbol;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_demod) {
|
||||
switch(std) {
|
||||
case LTE_BPSK:
|
||||
q->nbits_x_symbol = 1;
|
||||
q->nsymbols = 2;
|
||||
if (table_create(q)) {
|
||||
return -1;
|
||||
}
|
||||
set_BPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod);
|
||||
break;
|
||||
case LTE_QPSK:
|
||||
q->nbits_x_symbol = 2;
|
||||
q->nsymbols = 4;
|
||||
if (table_create(q)) {
|
||||
return -1;
|
||||
}
|
||||
set_QPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod);
|
||||
break;
|
||||
case LTE_QAM16:
|
||||
q->nbits_x_symbol = 4;
|
||||
q->nsymbols = 16;
|
||||
if (table_create(q)) {
|
||||
return -1;
|
||||
}
|
||||
set_16QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod);
|
||||
break;
|
||||
case LTE_QAM64:
|
||||
q->nbits_x_symbol = 6;
|
||||
q->nsymbols = 64;
|
||||
if (table_create(q)) {
|
||||
return -1;
|
||||
}
|
||||
set_64QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Vuk Marojevic <maroje@vt.edu>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <complex.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "soft_algs.h"
|
||||
|
||||
/**
|
||||
* @ingroup Soft Modulation Demapping based on the approximate
|
||||
* log-likelihood algorithm
|
||||
* Common algorithm that approximates the log-likelihood ratio. It takes
|
||||
* only the two closest constellation symbols into account, one with a '0'
|
||||
* and the other with a '1' at the given bit position.
|
||||
*
|
||||
* \param in input symbols (_Complex float)
|
||||
* \param out output symbols (float)
|
||||
* \param N Number of input symbols
|
||||
* \param M Number of constellation points
|
||||
* \param B Number of bits per symbol
|
||||
* \param symbols constellation symbols
|
||||
* \param S Soft demapping auxiliary matrix
|
||||
* \param sigma2 Noise vatiance
|
||||
*/
|
||||
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
|
||||
_Complex float *symbols, int (*S)[6][32], float sigma2) {
|
||||
int i, s, b;
|
||||
float num, den;
|
||||
float new_num, new_den;
|
||||
float idiff0, qdiff0, idiff1, qdiff1;
|
||||
int change_sign = -1;
|
||||
|
||||
for (s=0; s<N; s++) { /* recevied symbols */
|
||||
for (b=0; b<B; b++) {/* bits per symbol*/
|
||||
/* initiate num[b] and den[b] */
|
||||
idiff0 = __real__ in[s] - __real__ symbols[S[0][b][0]];
|
||||
qdiff0 = __imag__ in[s] - __imag__ symbols[S[0][b][0]];
|
||||
num = idiff0*idiff0 + qdiff0*qdiff0;
|
||||
|
||||
idiff1 = __real__ in[s] - __real__ symbols[S[1][b][0]];
|
||||
qdiff1 = __imag__ in[s] - __imag__ symbols[S[1][b][0]];
|
||||
den = idiff1*idiff1 + qdiff1*qdiff1;
|
||||
|
||||
/* half the constellation symbols have '1'|'0' at any bit pos. */
|
||||
for (i=1; i<M/2; i++) {
|
||||
idiff0 = __real__ in[s] - __real__ symbols[S[0][b][i]];
|
||||
qdiff0 = __imag__ in[s] - __imag__ symbols[S[0][b][i]];
|
||||
new_num = idiff0*idiff0 + qdiff0*qdiff0;
|
||||
|
||||
idiff1 = __real__ in[s] - __real__ symbols[S[1][b][i]];
|
||||
qdiff1 = __imag__ in[s] - __imag__ symbols[S[1][b][i]];
|
||||
new_den = idiff1*idiff1 + qdiff1*qdiff1;
|
||||
|
||||
if (new_num < num) {
|
||||
num = new_num;
|
||||
}
|
||||
if (new_den < den) {
|
||||
den = new_den;
|
||||
}
|
||||
}
|
||||
/* Theoretical LLR and approximate LLR values are positive if
|
||||
* symbol(s) with '0' is/are closer and negative if symbol(s)
|
||||
* with '1' are closer.
|
||||
* Change sign if mapping negative to '0' and positive to '1' */
|
||||
out[s*B+b] = change_sign*(den-num)/sigma2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Soft Modulation Demapping based on the approximate
|
||||
* log-likelihood ratio algorithm
|
||||
* Common algorithm that approximates the log-likelihood ratio. It takes
|
||||
* only the two closest constellation symbols into account, one with a '0'
|
||||
* and the other with a '1' at the given bit position.
|
||||
*
|
||||
* \param in input symbols (_Complex float)
|
||||
* \param out output symbols (float)
|
||||
* \param N Number of input symbols
|
||||
* \param M Number of constellation points
|
||||
* \param B Number of bits per symbol
|
||||
* \param symbols constellation symbols
|
||||
* \param S Soft demapping auxiliary matrix
|
||||
* \param sigma2 Noise vatiance
|
||||
*/
|
||||
void llr_exact(const _Complex float *in, float *out, int N, int M, int B,
|
||||
_Complex float *symbols, int (*S)[6][32], float sigma2) {
|
||||
int i, s, b;
|
||||
float num, den;
|
||||
float idiff0, qdiff0, idiff1, qdiff1;
|
||||
int change_sign = -1;
|
||||
|
||||
for (s=0; s<N; s++) { /* recevied symbols */
|
||||
for (b=0; b<B; b++) {/* bits per symbol*/
|
||||
/* initiate num[b] and den[b] */
|
||||
num = 0;
|
||||
den = 0;
|
||||
/* half the constellation symbols have '1'|'0' at any bit pos. */
|
||||
for (i=0; i<M/2; i++) {
|
||||
idiff0 = __real__ in[s] - __real__ symbols[S[0][b][i]];
|
||||
qdiff0 = __imag__ in[s] - __imag__ symbols[S[0][b][i]];
|
||||
num += exp(-1*(idiff0*idiff0 + qdiff0*qdiff0)/sigma2);
|
||||
|
||||
idiff1 = __real__ in[s] - __real__ symbols[S[1][b][i]];
|
||||
qdiff1 = __imag__ in[s] - __imag__ symbols[S[1][b][i]];
|
||||
den += exp(-1*(idiff1*idiff1 + qdiff1*qdiff1)/sigma2);
|
||||
}
|
||||
/* Theoretical LLR and approximate LLR values are positive if
|
||||
* symbol(s) with '0' is/are closer and negative if symbol(s)
|
||||
* with '1' are closer.
|
||||
* Change sign if mapping negative to '0' and positive to '1' */
|
||||
out[s*B+b] = change_sign*log(num/den);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Vuk Marojevic <maroje@vt.edu>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
|
||||
_Complex float *symbols, int (*S)[6][32], float sigma2);
|
||||
|
||||
void llr_exact(const _Complex float *in, float *out, int N, int M, int B,
|
||||
_Complex float *symbols, int (*S)[6][32], float sigma2);
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "lte/base.h"
|
||||
|
||||
void phch_cp_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs,
|
||||
int nof_prb, bool advance_output) {
|
||||
int i;
|
||||
|
||||
int ref_interval = ((RE_X_RB / nof_refs) - 1);
|
||||
memcpy(*output, *input, offset * sizeof(cf_t));
|
||||
*input += offset;
|
||||
*output += offset;
|
||||
for (i = 0; i < nof_refs * nof_prb - 1; i++) {
|
||||
if (advance_output) {
|
||||
(*output)++;
|
||||
} else {
|
||||
(*input)++;
|
||||
}
|
||||
memcpy(*output, *input, ref_interval * sizeof(cf_t));
|
||||
*output += ref_interval;
|
||||
*input += ref_interval;
|
||||
}
|
||||
if (ref_interval - offset > 0) {
|
||||
if (advance_output) {
|
||||
(*output)++;
|
||||
} else {
|
||||
(*input)++;
|
||||
}
|
||||
memcpy(*output, *input, (ref_interval - offset) * sizeof(cf_t));
|
||||
*output += (ref_interval - offset);
|
||||
*input += (ref_interval - offset);
|
||||
}
|
||||
}
|
||||
|
||||
void phch_cp_prb(cf_t **input, cf_t **output, int nof_prb) {
|
||||
memcpy(*output, *input, sizeof(cf_t) * RE_X_RB * nof_prb);
|
||||
*input += nof_prb * RE_X_RB;
|
||||
*output += nof_prb * RE_X_RB;
|
||||
}
|
||||
|
||||
void phch_put_prb_ref_(cf_t **input, cf_t **output, int offset, int nof_refs,
|
||||
int nof_prb) {
|
||||
phch_cp_prb_ref(input, output, offset, nof_refs, nof_prb, false);
|
||||
}
|
||||
|
||||
void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs,
|
||||
int nof_prb) {
|
||||
phch_cp_prb_ref(input, output, offset, nof_refs, nof_prb, true);
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef _Complex float cf_t;
|
||||
|
||||
void phch_cp_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs,
|
||||
int nof_prb, bool advance_input);
|
||||
void phch_cp_prb(cf_t **input, cf_t **output, int nof_prb);
|
||||
void phch_put_prb_ref_(cf_t **input, cf_t **output, int offset, int nof_refs,
|
||||
int nof_prb);
|
||||
void phch_get_prb_ref(cf_t **input, cf_t **output, int offset, int nof_refs,
|
||||
int nof_prb);
|
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "phch/pbch.h"
|
||||
#include "lte/base.h"
|
||||
#include "utils/bit.h"
|
||||
#include "utils/vector.h"
|
||||
#include "utils/debug.h"
|
||||
|
||||
bool pbch_exists(int nframe, int nslot) {
|
||||
return (!(nframe % 4) && nslot == 1);
|
||||
}
|
||||
|
||||
int pbch_cp(cf_t *input, cf_t *output, int nof_prb, lte_cp_t cp, int cell_id, bool put) {
|
||||
int i;
|
||||
cf_t *ptr;
|
||||
if (put) {
|
||||
ptr = input;
|
||||
output += nof_prb * RE_X_RB / 2 - 36;
|
||||
output += GUARD_RE(nof_prb);
|
||||
} else {
|
||||
ptr = output;
|
||||
input += nof_prb * RE_X_RB / 2 - 36;
|
||||
input += GUARD_RE(nof_prb);
|
||||
}
|
||||
|
||||
/* symbol 0 & 1 */
|
||||
for (i=0;i<2;i++) {
|
||||
phch_cp_prb_ref(&input, &output, cell_id%3, 4, 6, put);
|
||||
if (put) {
|
||||
output += 2*GUARD_RE(nof_prb);
|
||||
} else {
|
||||
input += 2*GUARD_RE(nof_prb);
|
||||
}
|
||||
}
|
||||
/* symbols 2 & 3 */
|
||||
if (CP_ISNORM(cp)) {
|
||||
for (i=0;i<2;i++) {
|
||||
phch_cp_prb(&input, &output, 6);
|
||||
if (put) {
|
||||
output += 2*GUARD_RE(nof_prb);
|
||||
} else {
|
||||
input += 2*GUARD_RE(nof_prb);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
phch_cp_prb(&input, &output, 6);
|
||||
if (put) {
|
||||
output += 2*GUARD_RE(nof_prb);
|
||||
} else {
|
||||
input += 2*GUARD_RE(nof_prb);
|
||||
}
|
||||
phch_cp_prb_ref(&input, &output, cell_id%3, 4, 6, put);
|
||||
}
|
||||
if (put) {
|
||||
return input - ptr;
|
||||
} else {
|
||||
return output - ptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts PBCH in slot number 1
|
||||
*
|
||||
* Returns the number of symbols written to slot1_data
|
||||
*
|
||||
* 36.211 10.3 section 6.6.4
|
||||
*/
|
||||
int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id) {
|
||||
return pbch_cp(pbch, slot1_data, nof_prb, cp, cell_id, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts PBCH from slot number 1
|
||||
*
|
||||
* Returns the number of symbols written to pbch
|
||||
*
|
||||
* 36.211 10.3 section 6.6.4
|
||||
*/
|
||||
int pbch_get(cf_t *slot1_data, cf_t *pbch, int nof_prb, lte_cp_t cp, int cell_id) {
|
||||
return pbch_cp(slot1_data, pbch, nof_prb, cp, cell_id, false);
|
||||
}
|
||||
|
||||
|
||||
/* Checks CRC and blindly obtains the number of ports, which is saved in nof_ports.
|
||||
*
|
||||
* The bits buffer size must be at least 40 bytes.
|
||||
*
|
||||
* Returns 0 if the data is correct, -1 otherwise
|
||||
*/
|
||||
int pbch_crc_check(char *bits, int *nof_ports) {
|
||||
int i, j;
|
||||
const char crc_mask[3][16] = {
|
||||
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
|
||||
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
|
||||
{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}
|
||||
};
|
||||
const int ports[3] = {1, 2, 4};
|
||||
char data[40];
|
||||
|
||||
memcpy(data, bits, 24 * sizeof(char));
|
||||
|
||||
for (i=0;i<3;i++) {
|
||||
for (j=0;j<16;j++) {
|
||||
data[24+j] = (bits[24+j] + crc_mask[i][j]) % 2;
|
||||
}
|
||||
if (!crc(0, data, 40, 16, 0x11021, 0)) {
|
||||
*nof_ports = ports[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
*nof_ports = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/** Initializes the PBCH channel receiver */
|
||||
int pbch_init(pbch_t *q, int cell_id, lte_cp_t cp) {
|
||||
int ret = -1;
|
||||
bzero(q, sizeof(pbch_t));
|
||||
q->cell_id = cell_id;
|
||||
q->cp = cp;
|
||||
if (modem_table_std(&q->mod, LTE_QPSK, true)) {
|
||||
goto clean;
|
||||
}
|
||||
demod_soft_init(&q->demod);
|
||||
demod_soft_table_set(&q->demod, &q->mod);
|
||||
demod_soft_alg_set(&q->demod, APPROX);
|
||||
if (sequence_pbch(&q->seq_pbch, q->cp, q->cell_id)) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
int poly[3] = {0x6D, 0x4F, 0x57};
|
||||
if (viterbi_init(&q->decoder, CONVCODER_37, poly, 40, true)) {
|
||||
goto clean;
|
||||
}
|
||||
int nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM: PBCH_RE_CPEXT;
|
||||
|
||||
q->pbch_symbols = malloc(sizeof(cf_t) * nof_symbols);
|
||||
if (!q->pbch_symbols) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_llr = malloc(sizeof(float) * nof_symbols * 4 * 2);
|
||||
if (!q->pbch_llr) {
|
||||
goto clean;
|
||||
}
|
||||
q->temp = malloc(sizeof(float) * nof_symbols * 4 * 2);
|
||||
if (!q->temp) {
|
||||
goto clean;
|
||||
}
|
||||
q->pbch_rm = malloc(sizeof(float) * 120);
|
||||
if (!q->pbch_rm) {
|
||||
goto clean;
|
||||
}
|
||||
q->data = malloc(sizeof(char) * 40);
|
||||
if (!q->data) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
clean:
|
||||
if (ret == -1) {
|
||||
pbch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pbch_free(pbch_t *q) {
|
||||
if (q->pbch_symbols) {
|
||||
free(q->pbch_symbols);
|
||||
}
|
||||
if (q->pbch_llr) {
|
||||
free(q->pbch_llr);
|
||||
}
|
||||
if (q->pbch_rm) {
|
||||
free(q->pbch_rm);
|
||||
}
|
||||
if (q->data) {
|
||||
free(q->data);
|
||||
}
|
||||
sequence_free(&q->seq_pbch);
|
||||
modem_table_free(&q->mod);
|
||||
viterbi_free(&q->decoder);
|
||||
}
|
||||
|
||||
/** Unpacks MIB from PBCH message.
|
||||
* msg buffer must be 24 byte length at least
|
||||
*/
|
||||
void pbch_mib_unpack(char *msg, pbch_mib_t *mib) {
|
||||
int bw, phich_res;
|
||||
char *buffer;
|
||||
|
||||
bw = 4*msg[0] + 2*msg[1] + msg[2];
|
||||
switch(bw) {
|
||||
case 0:
|
||||
mib->nof_prb = 6;
|
||||
break;
|
||||
case 1:
|
||||
mib->nof_prb = 15;
|
||||
break;
|
||||
default:
|
||||
mib->nof_prb = (bw-1)*25;
|
||||
break;
|
||||
}
|
||||
if (msg[3]) {
|
||||
mib->phich_length = EXTENDED;
|
||||
} else {
|
||||
mib->phich_length = NORMAL;
|
||||
}
|
||||
phich_res = 2*msg[4] + msg[5];
|
||||
switch(phich_res) {
|
||||
case 0:
|
||||
mib->phich_resources = R_1_6;
|
||||
break;
|
||||
case 1:
|
||||
mib->phich_resources = R_1_2;
|
||||
break;
|
||||
case 2:
|
||||
mib->phich_resources = R_1;
|
||||
break;
|
||||
case 3:
|
||||
mib->phich_resources = R_2;
|
||||
break;
|
||||
}
|
||||
buffer = &msg[6];
|
||||
mib->sfn = bit_unpack(&buffer, 8);
|
||||
}
|
||||
|
||||
void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib) {
|
||||
printf(" - Nof ports: %d\n", mib->nof_ports);
|
||||
printf(" - PRB: %d\n", mib->nof_prb);
|
||||
printf(" - PHICH Length: %s\n", mib->phich_length==EXTENDED?"Extended":"Normal");
|
||||
printf(" - PHICH Resources: ");
|
||||
switch(mib->phich_resources) {
|
||||
case R_1_6:
|
||||
printf("1/6");
|
||||
break;
|
||||
case R_1_2:
|
||||
printf("1/2");
|
||||
break;
|
||||
case R_1:
|
||||
printf("1");
|
||||
break;
|
||||
case R_2:
|
||||
printf("2");
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
printf(" - SFN: %d\n", mib->sfn);
|
||||
}
|
||||
|
||||
void pbch_decode_reset(pbch_t *q) {
|
||||
q->frame_idx = 0;
|
||||
}
|
||||
|
||||
int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, int src, int dst, int n, int nof_bits) {
|
||||
int j;
|
||||
|
||||
memcpy(&q->temp[dst*nof_bits], &q->pbch_llr[src*nof_bits], n*nof_bits*sizeof(float));
|
||||
|
||||
/* descramble */
|
||||
scrambling_float_offset(&q->seq_pbch, &q->temp[dst*nof_bits], dst*nof_bits, n*nof_bits);
|
||||
|
||||
for (j=0;j<dst*nof_bits;j++) {
|
||||
q->temp[j] = RX_NULL;
|
||||
}
|
||||
for (j=(dst+n)*nof_bits;j<4*nof_bits;j++) {
|
||||
q->temp[j] = RX_NULL;
|
||||
}
|
||||
|
||||
/* unrate matching */
|
||||
rm_conv_rx(q->temp, q->pbch_rm, 4*nof_bits, 120);
|
||||
|
||||
/* decode */
|
||||
viterbi_decode(&q->decoder, q->pbch_rm, q->data);
|
||||
|
||||
/* check crc and get nof ports */
|
||||
if (pbch_crc_check(q->data, &mib->nof_ports)) {
|
||||
|
||||
return 0;
|
||||
} else {
|
||||
|
||||
printf("BCH Decoded Correctly.\n");
|
||||
|
||||
/* unpack MIB */
|
||||
pbch_mib_unpack(q->data, mib);
|
||||
|
||||
mib->sfn += dst-src;
|
||||
|
||||
pbch_mib_fprint(stdout, mib);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes the PBCH channel
|
||||
*
|
||||
* The PBCH spans in 40 ms. This function is called every 10 ms. It tries to decode the MIB
|
||||
* given the symbols of the slot #1 of each radio frame. Successive calls will use more frames
|
||||
* to help the decoding process.
|
||||
*
|
||||
* Returns 1 if successfully decoded MIB, 0 if not and -1 on error
|
||||
*/
|
||||
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, pbch_mib_t *mib, int nof_prb, float ebno) {
|
||||
int src, dst, res, nb;
|
||||
|
||||
int nof_symbols = (CP_ISNORM(q->cp)) ? PBCH_RE_CPNORM: PBCH_RE_CPEXT;
|
||||
int nof_bits = 2 * nof_symbols;
|
||||
|
||||
/* extract symbols */
|
||||
if (nof_symbols != pbch_get(slot1_symbols, q->pbch_symbols, nof_prb,
|
||||
q->cp, q->cell_id)) {
|
||||
fprintf(stderr, "There was an error getting the PBCH symbols\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* demodulate symbols */
|
||||
demod_soft_sigma_set(&q->demod, ebno);
|
||||
demod_soft_demodulate(&q->demod, q->pbch_symbols,
|
||||
&q->pbch_llr[nof_bits * q->frame_idx], nof_symbols);
|
||||
|
||||
q->frame_idx++;
|
||||
|
||||
INFO("PBCH: %d frames in buffer\n", q->frame_idx);
|
||||
|
||||
/* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received
|
||||
* 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234.
|
||||
* We know they are ordered.
|
||||
*/
|
||||
res = 0;
|
||||
for (nb=0;nb<q->frame_idx && !res;nb++) {
|
||||
for (dst=0;(dst<4-nb) && !res;dst++) {
|
||||
for (src=0;src<q->frame_idx && !res;src++) {
|
||||
DEBUG("Trying %d blocks at offset %d as subframe mod4 number %d\n", nb+1, src, dst);
|
||||
res = pbch_decode_frame(q, mib, src, dst, nb+1, nof_bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (res) {
|
||||
q->frame_idx = 0;
|
||||
return 1;
|
||||
} else {
|
||||
/* make room for the next packet of radio frame symbols */
|
||||
if (q->frame_idx == 4) {
|
||||
memcpy(&q->pbch_llr[nof_bits], q->pbch_llr, nof_bits * 3 * sizeof(float));
|
||||
q->frame_idx = 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "ratematching/rm_conv.h"
|
||||
|
||||
#define NCOLS 32
|
||||
#define NROWS_MAX NCOLS
|
||||
#define RATE 3
|
||||
|
||||
unsigned char RM_PERM_CC[NCOLS] =
|
||||
{ 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31, 0, 16, 8,
|
||||
24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30 };
|
||||
unsigned char 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 };
|
||||
|
||||
|
||||
/* Undoes Convolutional Code Rate Matching.
|
||||
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
|
||||
*/
|
||||
int rm_conv_rx(float *input, float *output, int in_len, int out_len) {
|
||||
|
||||
int nrows, ndummy, K_p;
|
||||
int i, j, k;
|
||||
int d_i, d_j;
|
||||
|
||||
float tmp[RATE * NCOLS * NROWS_MAX];
|
||||
|
||||
nrows = (int) (out_len / RATE - 1) / NCOLS + 1;
|
||||
if (nrows > NROWS_MAX) {
|
||||
fprintf(stderr, "Output too large. Max output length is %d\n", RATE * NCOLS * NROWS_MAX);
|
||||
return -1;
|
||||
}
|
||||
K_p = nrows * NCOLS;
|
||||
|
||||
ndummy = K_p - out_len / RATE;
|
||||
if (ndummy < 0) {
|
||||
ndummy = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < RATE * K_p; i++) {
|
||||
tmp[i] = RX_NULL;
|
||||
}
|
||||
|
||||
/* Undo bit collection. Account for dummy bits */
|
||||
k = 0;
|
||||
j = 0;
|
||||
while (k < in_len) {
|
||||
d_i = (j % K_p) / nrows;
|
||||
d_j = (j % K_p) % nrows;
|
||||
|
||||
if (d_j * NCOLS + RM_PERM_CC[d_i] >= ndummy) {
|
||||
if (tmp[j] == RX_NULL) {
|
||||
tmp[j] = input[k];
|
||||
} else if (input[k] != RX_NULL) {
|
||||
tmp[j] += input[k]; /* soft combine LLRs */
|
||||
}
|
||||
k++;
|
||||
}
|
||||
j++;
|
||||
if (j == RATE * K_p) {
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* interleaving and bit selection */
|
||||
for (i = 0; i < out_len / RATE; i++) {
|
||||
d_i = (i + ndummy) / NCOLS;
|
||||
d_j = (i + ndummy) % NCOLS;
|
||||
for (j = 0; j < RATE; j++) {
|
||||
output[i * RATE + j] = tmp[K_p * j
|
||||
+ RM_PERM_CC_INV[d_j] * nrows + d_i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** High-level API */
|
||||
|
||||
int rm_conv_initialize(rm_conv_hl* h) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** This function can be called in a subframe (1ms) basis */
|
||||
int rm_conv_work(rm_conv_hl* hl) {
|
||||
if (hl->init.direction) {
|
||||
//rm_conv_tx(hl->input, hl->output, hl->in_len, hl->ctrl_in.S);
|
||||
*(hl->out_len) = hl->ctrl_in.S;
|
||||
} else {
|
||||
rm_conv_rx(hl->input, hl->output, hl->in_len, hl->ctrl_in.E);
|
||||
*(hl->out_len) = hl->ctrl_in.E;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rm_conv_stop(rm_conv_hl* hl) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
#include "resampling/interp.h"
|
||||
#include "utils/debug.h"
|
||||
|
||||
/* Performs 1st order linear interpolation with out-of-bound interpolation */
|
||||
void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end) {
|
||||
int i, j;
|
||||
float mag0, mag1, arg0, arg1, mag, arg;
|
||||
|
||||
for (i=0;i<len-1;i++) {
|
||||
mag0 = cabsf(input[i]);
|
||||
mag1 = cabsf(input[i+1]);
|
||||
arg0 = cargf(input[i]);
|
||||
arg1 = cargf(input[i+1]);
|
||||
if (i==0) {
|
||||
for (j=0;j<off_st;j++) {
|
||||
mag = mag0 - (j+1)*(mag1-mag0)/M;
|
||||
arg = arg0 - (j+1)*(arg1-arg0)/M;
|
||||
output[j] = mag * cexpf(I * arg);
|
||||
}
|
||||
}
|
||||
for (j=0;j<M;j++) {
|
||||
mag = mag0 + j*(mag1-mag0)/M;
|
||||
arg = arg0 + j*(arg1-arg0)/M;
|
||||
output[i*M+j+off_st] = mag * cexpf(I * arg);
|
||||
// DEBUG("output[%d] = input[%d]+%d*(input[%d]-input[%d])/%d = %.3f+%.3f = %.3f delta=%.3f\n",
|
||||
// i*M+j, i, j, i+1, i, M, cabsf(input[i]), cabsf(j*(input[i+1] - input[i])/M),
|
||||
// cabsf(output[i*M+j]));
|
||||
}
|
||||
}
|
||||
for (j=0;j<off_end;j++) {
|
||||
mag = mag1 + j*(mag1-mag0)/M;
|
||||
arg = arg1 + j*(arg1-arg0)/M;
|
||||
output[i*M+j+off_st] = mag * cexpf(I * arg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Performs 1st order linear interpolation */
|
||||
void interp_linear(cf_t *input, cf_t *output, int M, int len) {
|
||||
interp_linear_offset(input, output, M, len, 0, 0);
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "scrambling/scrambling.h"
|
||||
|
||||
/**
|
||||
* @ingroup Soft-bit Scrambling
|
||||
* Scrambles the input softbit-sequence (floats) with the scrambling
|
||||
* sequence (32-bit integers).
|
||||
*
|
||||
*/
|
||||
void scrambling_float(sequence_t *s, float *data) {
|
||||
scrambling_float_offset(s, data, 0, s->len);
|
||||
}
|
||||
|
||||
int scrambling_float_offset(sequence_t *s, float *data, int offset, int len) {
|
||||
int i;
|
||||
if (len + offset > s->len) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; i++) {
|
||||
data[i] = data[i]*(1-2*s->c[i+offset]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup Bit Scrambling
|
||||
* Directly scrambles the input bit-sequence (char) with the scrambling
|
||||
* sequence.
|
||||
*/
|
||||
void scrambling_bit(sequence_t *s, char *data) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < s->len; i++) {
|
||||
data[i] = (data[i] + s->c[i]) % 2;
|
||||
}
|
||||
}
|
||||
|
||||
/** High-level API */
|
||||
|
||||
int compute_sequences(scrambling_hl* h) {
|
||||
|
||||
switch (h->init.channel) {
|
||||
case PBCH:
|
||||
return sequence_pbch(&h->obj.seq[0], h->init.nof_symbols == CPNORM_NSYMB,
|
||||
h->init.cell_id);
|
||||
case PDSCH:
|
||||
case PCFICH:
|
||||
case PDCCH:
|
||||
case PMCH:
|
||||
case PUCCH:
|
||||
fprintf(stderr, "Not implemented\n");
|
||||
return -1;
|
||||
default:
|
||||
fprintf(stderr, "Invalid channel %d\n", h->init.channel);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int scrambling_initialize(scrambling_hl* h) {
|
||||
|
||||
bzero(&h->obj, sizeof(scrambling_t));
|
||||
|
||||
return compute_sequences(h);
|
||||
}
|
||||
|
||||
/** This function can be called in a subframe (1ms) basis for LTE */
|
||||
int scrambling_work(scrambling_hl* hl) {
|
||||
int sf;
|
||||
if (hl->init.channel == PBCH) {
|
||||
sf = 0;
|
||||
} else {
|
||||
sf = hl->ctrl_in.subframe;
|
||||
}
|
||||
sequence_t *seq = &hl->obj.seq[sf];
|
||||
|
||||
if (hl->init.hard) {
|
||||
memcpy(hl->output, hl->input, sizeof(char) * hl->in_len);
|
||||
scrambling_bit(seq, hl->output);
|
||||
} else {
|
||||
memcpy(hl->output, hl->input, sizeof(float) * hl->in_len);
|
||||
scrambling_float(seq, hl->output);
|
||||
}
|
||||
*(hl->out_len) = hl->in_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scrambling_stop(scrambling_hl* hl) {
|
||||
int i;
|
||||
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
|
||||
sequence_free(&hl->obj.seq[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
/** TODO: Cyclic-prefix based synchronization
|
||||
*
|
||||
*/
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/vector.h"
|
||||
#include "sync/sss.h"
|
||||
|
||||
cf_t corr_sz(cf_t *z, cf_t *s) {
|
||||
cf_t sum;
|
||||
cf_t zsprod[32];
|
||||
vec_dot_prod(z, s, zsprod, N_SSS - 1);
|
||||
sum = sum_c(zsprod, N_SSS - 1);
|
||||
|
||||
return sum;
|
||||
}
|
||||
void corr_all_zs(cf_t *z, cf_t s[32][32], cf_t *output) {
|
||||
int m;
|
||||
for (m = 0; m < N_SSS; m++) {
|
||||
output[m] = corr_sz(z, s[m]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Assumes input points to the beginning of the SSS symbol. The SSS symbol start is
|
||||
* given by SSS_SYMBOL_ST() macro in sss.h.
|
||||
* Estimates the m0 and m1 values and saves in m0_value and m1_value
|
||||
* the resulted correlation (higher is more likely)
|
||||
*
|
||||
*
|
||||
* Source: "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver"
|
||||
* Jung-In Kim, Jung-Su Han, Hee-Jin Roh and Hyung-Jin Choi
|
||||
|
||||
*
|
||||
*/
|
||||
void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value,
|
||||
int *m1, float *m1_value) {
|
||||
|
||||
/* This is aprox 3-4 kbytes of stack. Consider moving to sss_synch_t?? */
|
||||
cf_t zdelay[N_SSS+1],zconj[N_SSS+1],zprod[N_SSS+1];
|
||||
cf_t y[2][N_SSS+1], z[N_SSS+1], tmp[N_SSS+1];
|
||||
float tmp_real[N_SSS+1];
|
||||
cf_t input_fft[SSS_DFT_LEN];
|
||||
|
||||
int i;
|
||||
|
||||
dft_run_c2c(&q->dftp_input, input, input_fft);
|
||||
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
y[0][i] = input_fft[SSS_POS_SYMBOL + 2 * i];
|
||||
y[1][i] = input_fft[SSS_POS_SYMBOL + 2 * i + 1];
|
||||
}
|
||||
|
||||
vec_dot_prod(y[0], q->fc_tables.c[0], z, N_SSS);
|
||||
memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t));
|
||||
vec_conj(z, zconj, N_SSS - 1);
|
||||
vec_dot_prod(zdelay, zconj, zprod, N_SSS - 1);
|
||||
|
||||
corr_all_zs(zprod, q->fc_tables.s, tmp);
|
||||
vec_abs(tmp, tmp_real, N_SSS);
|
||||
vec_max(tmp_real, m0_value, m0, N_SSS);
|
||||
|
||||
vec_dot_prod(y[1], q->fc_tables.c[1], tmp, N_SSS);
|
||||
vec_dot_prod(tmp, q->fc_tables.z1[*m0], z, N_SSS);
|
||||
memcpy(zdelay, &z[1], (N_SSS - 1) * sizeof(cf_t));
|
||||
vec_conj(z, zconj, N_SSS - 1);
|
||||
vec_dot_prod(zdelay, zconj, zprod, N_SSS - 1);
|
||||
|
||||
corr_all_zs(zprod, q->fc_tables.s, tmp);
|
||||
vec_abs(tmp, tmp_real, N_SSS);
|
||||
vec_max(tmp_real, m1_value, m1, N_SSS);
|
||||
|
||||
}
|
||||
|
||||
void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in) {
|
||||
int i, j;
|
||||
bzero(fc_tables, sizeof(struct fc_tables));
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
for (j = 0; j < N_SSS; j++) {
|
||||
__real__ fc_tables->z1[i][j] = (float) in->z1[i][j];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
for (j = 0; j < N_SSS - 1; j++) {
|
||||
__real__ fc_tables->s[i][j] = (float) in->s[i][j + 1] * in->s[i][j];
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < N_SSS; j++) {
|
||||
__real__ fc_tables->c[i][j] = (float) in->c[i][j];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include "sync/sss.h"
|
||||
|
||||
/**
|
||||
* @brief Function documentation: initSSStables()
|
||||
* This function generates the scrambling sequences required for generation of
|
||||
* SSS sequence according with 3GPP TS 36.211 version 10.5.0 Release 10.
|
||||
*/
|
||||
void generate_zsc_tilde(int *z_tilde, int *s_tilde, int *c_tilde) {
|
||||
|
||||
int i;
|
||||
int x[N_SSS];
|
||||
bzero(x, sizeof(int) * N_SSS);
|
||||
x[4] = 1;
|
||||
|
||||
for (i = 0; i < 26; i++)
|
||||
x[i + 5] = (x[i + 2] + x[i]) % 2;
|
||||
for (i = 0; i < N_SSS; i++)
|
||||
s_tilde[i] = 1 - 2 * x[i];
|
||||
|
||||
for (i = 0; i < 26; i++)
|
||||
x[i + 5] = (x[i + 3] + x[i]) % 2;
|
||||
for (i = 0; i < N_SSS; i++)
|
||||
c_tilde[i] = 1 - 2 * x[i];
|
||||
|
||||
for (i = 0; i < 26; i++)
|
||||
x[i + 5] = (x[i + 4] + x[i + 2] + x[i + 1] + x[i]) % 2;
|
||||
for (i = 0; i < N_SSS; i++)
|
||||
z_tilde[i] = 1 - 2 * x[i];
|
||||
}
|
||||
|
||||
void generate_m0m1(int N_id_1, int *m0, int *m1) {
|
||||
int q_prime = N_id_1 / (N_SSS - 1);
|
||||
int q = (N_id_1 + (q_prime * (q_prime + 1) / 2)) / (N_SSS - 1);
|
||||
int m_prime = N_id_1 + (q * (q + 1) / 2);
|
||||
*m0 = m_prime % N_SSS;
|
||||
*m1 = (*m0 + m_prime / N_SSS + 1) % N_SSS;
|
||||
}
|
||||
|
||||
|
||||
/* table[m0][m1-1]=N_id_1 */
|
||||
void generate_N_id_1_table(int table[30][30]) {
|
||||
int m0, m1;
|
||||
int N_id_1;
|
||||
for (N_id_1=0;N_id_1<168;N_id_1++) {
|
||||
generate_m0m1(N_id_1, &m0, &m1);
|
||||
table[m0][m1-1] = N_id_1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void generate_s(int *s, int *s_tilde, int m0_m1) {
|
||||
int i;
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
s[i] = s_tilde[(i + m0_m1) % N_SSS];
|
||||
}
|
||||
}
|
||||
|
||||
void generate_s_all(int s[N_SSS][N_SSS], int *s_tilde) {
|
||||
int i;
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
generate_s(s[i], s_tilde, i);
|
||||
}
|
||||
}
|
||||
|
||||
void generate_c(int *c, int *c_tilde, int N_id_2, int is_c0) {
|
||||
int i;
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
c[i] = c_tilde[(i + N_id_2 + (is_c0 > 0 ? 3 : 0)) % N_SSS];
|
||||
}
|
||||
}
|
||||
|
||||
void generate_z(int *z, int *z_tilde, int m0_m1) {
|
||||
int i;
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
z[i] = z_tilde[(i + (m0_m1 % 8)) % N_SSS];
|
||||
}
|
||||
}
|
||||
|
||||
void generate_z_all(int z[N_SSS][N_SSS], int *z_tilde) {
|
||||
int i;
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
generate_z(z[i], z_tilde, i);
|
||||
}
|
||||
}
|
||||
|
||||
void generate_sss_all_tables(struct sss_tables *tables, int N_id_2) {
|
||||
int i;
|
||||
int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS];
|
||||
|
||||
generate_zsc_tilde(z_t, s_t, c_t);
|
||||
generate_s_all(tables->s, s_t);
|
||||
generate_z_all(tables->z1, z_t);
|
||||
for (i = 0; i < 2; i++) {
|
||||
generate_c(tables->c[i], c_t, N_id_2, i);
|
||||
}
|
||||
tables->N_id_2 = N_id_2;
|
||||
}
|
||||
|
||||
void generate_sss(float *signal, int cell_id) {
|
||||
|
||||
int i;
|
||||
int id1 = cell_id / 3;
|
||||
int id2 = cell_id % 3;
|
||||
int m0;
|
||||
int m1;
|
||||
int s_t[N_SSS], c_t[N_SSS], z_t[N_SSS];
|
||||
int s0[N_SSS], s1[N_SSS], c0[N_SSS], c1[N_SSS], z1_0[N_SSS], z1_1[N_SSS];
|
||||
|
||||
generate_m0m1(id1, &m0, &m1);
|
||||
generate_zsc_tilde(z_t, s_t, c_t);
|
||||
|
||||
generate_s(s0, s_t, m0);
|
||||
generate_s(s1, s_t, m1);
|
||||
|
||||
generate_c(c0, c_t, id2, 0);
|
||||
generate_c(c1, c_t, id2, 1);
|
||||
|
||||
generate_z(z1_0, z_t, m0);
|
||||
generate_z(z1_1, z_t, m1);
|
||||
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
/** Even Resource Elements: Sub-frame 0*/
|
||||
signal[2 * i] = (float) (s0[i] * c0[i]);
|
||||
/** Odd Resource Elements: Sub-frame 0*/
|
||||
signal[2 * i + 1] = (float) (s1[i] * c1[i] * z1_0[i]);
|
||||
}
|
||||
for (i = 0; i < N_SSS; i++) {
|
||||
/** Even Resource Elements: Sub-frame 5*/
|
||||
signal[2 * i + N_SSS * 2] = (float) (s1[i] * c0[i]);
|
||||
/** Odd Resource Elements: Sub-frame 5*/
|
||||
signal[2 * i + 1 + N_SSS * 2] = (float) (s0[i] * c1[i] * z1_1[i]);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <complex.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sync/pss.h"
|
||||
#include "utils/dft.h"
|
||||
#include "utils/vector.h"
|
||||
#include "utils/convolution.h"
|
||||
|
||||
#define NOT_SYNC 0xF0F0F0F0
|
||||
|
||||
/* Initializes the object. subframe_size is the size, in samples, of the 1ms subframe
|
||||
*
|
||||
*/
|
||||
int pss_synch_init(pss_synch_t *q, int frame_size) {
|
||||
int ret = -1;
|
||||
bzero(q, sizeof(pss_synch_t));
|
||||
|
||||
q->pss_signal_freq = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(cf_t));
|
||||
if (!q->pss_signal_freq) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
q->conv_abs = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(float));
|
||||
if (!q->conv_abs) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
q->tmp_input = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(cf_t));
|
||||
if (!q->tmp_input) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
q->frame_buffer = vec_malloc(4*frame_size * sizeof(cf_t));
|
||||
if (!q->frame_buffer) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
q->conv_output = vec_malloc((PSS_LEN_FREQ+frame_size) * sizeof(cf_t));
|
||||
if (!q->conv_output) {
|
||||
fprintf(stderr, "Error allocating memory\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
|
||||
#ifdef CONVOLUTION_FFT
|
||||
if (conv_fft_cc_init(&q->conv_fft, frame_size, PSS_LEN_FREQ)) {
|
||||
fprintf(stderr, "Error initiating convolution FFT\n");
|
||||
goto clean_and_exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
q->correlation_threshold = DEFAULT_CORRELATION_TH;
|
||||
q->nosync_timeout_frames = DEFAULT_NOSYNC_TIMEOUT;
|
||||
q->cfo_auto = true;
|
||||
q->N_id_2 = -1;
|
||||
q->frame_size = frame_size;
|
||||
q->frame_start_idx = NOT_SYNC;
|
||||
q->fb_wp = 0;
|
||||
|
||||
ret = 0;
|
||||
clean_and_exit:
|
||||
if (ret == -1) {
|
||||
pss_synch_free(q);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pss_synch_free(pss_synch_t *q) {
|
||||
if (q->pss_signal_freq) {
|
||||
free(q->pss_signal_freq);
|
||||
}
|
||||
if (q->conv_abs) {
|
||||
free(q->conv_abs);
|
||||
}
|
||||
if (q->tmp_input) {
|
||||
free(q->tmp_input);
|
||||
}
|
||||
if (q->frame_buffer) {
|
||||
free(q->frame_buffer);
|
||||
}
|
||||
if (q->conv_output) {
|
||||
free(q->conv_output);
|
||||
}
|
||||
|
||||
#ifdef CONVOLUTION_FFT
|
||||
conv_fft_cc_free(&q->conv_fft);
|
||||
#endif
|
||||
|
||||
bzero(q, sizeof(pss_synch_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* This function calculates the Zadoff-Chu sequence.
|
||||
* @param signal Output array.
|
||||
* @param direction 0 for tx, 1 for rx
|
||||
*/
|
||||
int pss_generate(cf_t *signal, int direction, int N_id_2) {
|
||||
int i;
|
||||
float arg;
|
||||
const float root_value[] = {25.0,29.0,34.0};
|
||||
int root_idx;
|
||||
|
||||
int sign = direction ? 1 : -1;
|
||||
|
||||
if (N_id_2 < 0 || N_id_2 > 2) {
|
||||
fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
root_idx = N_id_2;
|
||||
|
||||
for (i = 0; i < PSS_LEN / 2; i++) {
|
||||
arg = (float) sign * M_PI * root_value[root_idx]
|
||||
* ((float) i * ((float) i + 1.0)) / 63.0;
|
||||
__real__ signal[i] = cos(arg);
|
||||
__imag__ signal[i] = sin(arg);
|
||||
}
|
||||
for (i = PSS_LEN / 2; i < PSS_LEN; i++) {
|
||||
arg = (float) sign * M_PI * root_value[root_idx]
|
||||
* (((float) i + 2.0) * ((float) i + 1.0)) / 63.0;
|
||||
__real__ signal[i] = cos(arg);
|
||||
__imag__ signal[i] = sin(arg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Sets the current N_id_2 value. Initializes the object for this PSS sequence
|
||||
* Returns -1 on error, 0 otherwise
|
||||
*/
|
||||
int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2) {
|
||||
q->N_id_2 = N_id_2;
|
||||
|
||||
dft_plan_t plan;
|
||||
cf_t pss_signal_pad[PSS_LEN_FREQ];
|
||||
cf_t pss_signal_time[PSS_LEN];
|
||||
|
||||
if (N_id_2 < 0 || N_id_2 > 2) {
|
||||
fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pss_generate(pss_signal_time, 0, N_id_2);
|
||||
|
||||
memset(pss_signal_pad, 0, PSS_LEN_FREQ * sizeof(cf_t));
|
||||
memset(q->pss_signal_freq, 0, PSS_LEN_FREQ * sizeof(cf_t));
|
||||
memcpy(&pss_signal_pad[33], pss_signal_time, PSS_LEN * sizeof(cf_t));
|
||||
|
||||
if (dft_plan(PSS_LEN_FREQ - 1, COMPLEX_2_COMPLEX, BACKWARD, &plan)) {
|
||||
return -1;
|
||||
}
|
||||
plan.options = DFT_MIRROR_PRE | DFT_DC_OFFSET;
|
||||
|
||||
dft_run_c2c(&plan, pss_signal_pad, q->pss_signal_freq);
|
||||
|
||||
vec_mult_c_r(q->pss_signal_freq, pss_signal_pad,
|
||||
(float) 1 / (PSS_LEN_FREQ - 1), PSS_LEN_FREQ);
|
||||
|
||||
vec_conj(pss_signal_pad, q->pss_signal_freq, PSS_LEN_FREQ);
|
||||
|
||||
q->N_id_2 = N_id_2;
|
||||
|
||||
dft_plan_free(&plan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Returns the index of the PSS correlation peak in a subframe.
|
||||
* The frame starts at corr_peak_pos-subframe_size/2.
|
||||
* The value of the correlation is stored in corr_peak_value.
|
||||
*
|
||||
* Input buffer must be subframe_size long.
|
||||
*/
|
||||
int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value) {
|
||||
int corr_peak_pos;
|
||||
int conv_output_len;
|
||||
|
||||
memset(&q->pss_signal_freq[PSS_LEN_FREQ], 0, q->frame_size * sizeof(cf_t));
|
||||
memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t));
|
||||
memset(&q->tmp_input[q->frame_size], 0, PSS_LEN_FREQ * sizeof(cf_t));
|
||||
|
||||
#ifdef CONVOLUTION_FFT
|
||||
conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_freq, q->conv_output);
|
||||
#else
|
||||
conv_output_len = conv_cc(input, q->pss_signal_freq, q->conv_output, q->frame_size, PSS_LEN_FREQ);
|
||||
#endif
|
||||
|
||||
vec_abs(q->conv_output, q->conv_abs, conv_output_len);
|
||||
vec_max(q->conv_abs, corr_peak_value, &corr_peak_pos, conv_output_len);
|
||||
if (corr_mean_value) {
|
||||
*corr_mean_value = sum_r(q->conv_abs, conv_output_len) / conv_output_len;
|
||||
}
|
||||
|
||||
return corr_peak_pos;
|
||||
}
|
||||
|
||||
/* Returns the CFO estimation given a PSS received sequence
|
||||
*
|
||||
* Source: An Efficient CFO Estimation Algorithm for the Downlink of 3GPP-LTE
|
||||
* Feng Wang and Yu Zhu
|
||||
*/
|
||||
float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv) {
|
||||
cf_t y0, y1, yr;
|
||||
cf_t y[PSS_LEN_FREQ-1];
|
||||
|
||||
vec_dot_prod_u(q->pss_signal_freq, pss_recv, y, PSS_LEN_FREQ - 1);
|
||||
|
||||
y0 = sum_c(y, (PSS_LEN_FREQ - 1)/2);
|
||||
y1 = sum_c(&y[(PSS_LEN_FREQ - 1)/2], (PSS_LEN_FREQ - 1)/2);
|
||||
yr = conjf(y0) * y1;
|
||||
|
||||
return atan2f(__imag__ yr, __real__ yr) / M_PI;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** This function is designed to be called periodically on a subframe basis.
|
||||
* The function finds the PSS correlation peak and computes (does not adjust) CFO automatically as defined by
|
||||
* pss_synch_set_cfo_mode().
|
||||
*
|
||||
* If the PSS sequence is not found, returns 0 writes nothing to the output buffer.
|
||||
* If the PSS sequence is found, aligns the beginning of the subframe to the output buffer and returns the number of samples
|
||||
* written to the output buffer.
|
||||
* If synchronized, subsequent calls to this function align the input buffer to the subframe beginning.
|
||||
*/
|
||||
int pss_synch_frame(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples) {
|
||||
int max_idx, tmp_start_idx;
|
||||
int retval;
|
||||
float max_value;
|
||||
|
||||
if (nsamples != q->frame_size) {
|
||||
fprintf(stderr, "Configured for frame size %d but got %d samples\n",
|
||||
q->frame_size, nsamples);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (q->N_id_2 < 0) {
|
||||
fprintf(stderr,
|
||||
"N_id_2 must be configured before calling pss_synch()\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
max_idx = pss_synch_find_pss(q, input, &max_value, NULL);
|
||||
if (max_value > q->correlation_threshold) {
|
||||
tmp_start_idx = max_idx - nsamples / 2;
|
||||
if (q->frame_start_idx != tmp_start_idx) {
|
||||
printf("Re-synchronizing: new index is %d, old was %d\n",
|
||||
tmp_start_idx, q->frame_start_idx);
|
||||
}
|
||||
q->frame_start_idx = tmp_start_idx;
|
||||
} else {
|
||||
if (q->nosync_timeout_frames > 0) {
|
||||
q->nof_nosync_frames++;
|
||||
if (q->nof_nosync_frames >= q->nosync_timeout_frames) {
|
||||
q->frame_start_idx = NOT_SYNC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (q->frame_start_idx == NOT_SYNC) {
|
||||
|
||||
memcpy(q->frame_buffer, input, nsamples * sizeof(cf_t));
|
||||
retval = 0;
|
||||
|
||||
} else if (q->frame_start_idx > 0) {
|
||||
|
||||
if (q->fb_wp) {
|
||||
memcpy(&q->frame_buffer[(nsamples - q->frame_start_idx)], input,
|
||||
q->frame_start_idx * sizeof(cf_t));
|
||||
memcpy(output, q->frame_buffer, nsamples * sizeof(cf_t));
|
||||
retval = nsamples;
|
||||
} else {
|
||||
retval = 0;
|
||||
}
|
||||
memcpy(q->frame_buffer, &input[q->frame_start_idx],
|
||||
(nsamples - q->frame_start_idx) * sizeof(cf_t));
|
||||
q->fb_wp = 1;
|
||||
|
||||
} else {
|
||||
|
||||
memcpy(output, &q->frame_buffer[nsamples + q->frame_start_idx],
|
||||
(-q->frame_start_idx) * sizeof(cf_t));
|
||||
memcpy(&output[-q->frame_start_idx], input,
|
||||
(nsamples + q->frame_start_idx) * sizeof(cf_t));
|
||||
memcpy(&q->frame_buffer[nsamples + q->frame_start_idx],
|
||||
&input[nsamples + q->frame_start_idx],
|
||||
(-q->frame_start_idx) * sizeof(cf_t));
|
||||
retval = nsamples;
|
||||
}
|
||||
|
||||
if (q->frame_start_idx != NOT_SYNC && q->cfo_auto && retval) {
|
||||
q->current_cfo = pss_synch_cfo_compute(q, &output[q->frame_size/2 - PSS_LEN_FREQ + 1]);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void pss_synch_set_timeout(pss_synch_t *q, int nof_frames) {
|
||||
q->nosync_timeout_frames = nof_frames;
|
||||
}
|
||||
|
||||
void pss_synch_set_threshold(pss_synch_t *q, float threshold) {
|
||||
q->correlation_threshold = threshold;
|
||||
}
|
||||
|
||||
void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto) {
|
||||
q->cfo_auto = cfo_auto;
|
||||
}
|
||||
|
||||
float pss_synch_get_cfo(pss_synch_t *q) {
|
||||
return q->current_cfo;
|
||||
}
|
||||
|
||||
int pss_synch_get_frame_start_idx(pss_synch_t *q) {
|
||||
return q->frame_start_idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** High-level API */
|
||||
|
||||
|
||||
|
||||
int pss_synch_initialize(pss_synch_hl* h) {
|
||||
int fs = h->init.frame_size;
|
||||
if (!fs) {
|
||||
fs = DEFAULT_FRAME_SIZE;
|
||||
}
|
||||
if (pss_synch_init(&h->obj, fs)) {
|
||||
return -1;
|
||||
}
|
||||
if (h->init.unsync_nof_pkts) {
|
||||
pss_synch_set_timeout(&h->obj, h->init.unsync_nof_pkts);
|
||||
}
|
||||
|
||||
pss_synch_set_N_id_2(&h->obj, h->init.N_id_2);
|
||||
if (h->init.do_cfo) {
|
||||
pss_synch_set_cfo_mode(&h->obj, true);
|
||||
} else {
|
||||
pss_synch_set_cfo_mode(&h->obj, false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pss_synch_work(pss_synch_hl* hl) {
|
||||
|
||||
if (hl->ctrl_in.correlation_threshold) {
|
||||
pss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold);
|
||||
}
|
||||
|
||||
*hl->out_len = pss_synch_frame(&hl->obj, hl->input, hl->output, hl->in_len);
|
||||
if (*hl->out_len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pss_synch_stop(pss_synch_hl* hl) {
|
||||
pss_synch_free(&hl->obj);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sync/sfo.h"
|
||||
|
||||
/* Estimate SFO based on the array of time estimates t0
|
||||
* of length len. The parameter period is the time between t0 samples
|
||||
*/
|
||||
float sfo_estimate(int *t0, int len, float period) {
|
||||
int i;
|
||||
float sfo=0.0;
|
||||
for (i=1;i<len;i++) {
|
||||
sfo += (t0[i]-t0[i-1])/period/len;
|
||||
}
|
||||
return sfo;
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sync/sss.h"
|
||||
#include "utils/dft.h"
|
||||
#include "utils/convolution.h"
|
||||
|
||||
void generate_sss_all_tables(struct sss_tables *tables, int N_id_2);
|
||||
void convert_tables(struct fc_tables *fc_tables, struct sss_tables *in);
|
||||
void generate_N_id_1_table(int table[30][30]);
|
||||
|
||||
int sss_synch_init(sss_synch_t *q) {
|
||||
bzero(q, sizeof(sss_synch_t));
|
||||
|
||||
if (dft_plan(SSS_DFT_LEN, COMPLEX_2_COMPLEX, FORWARD, &q->dftp_input)) {
|
||||
return -1;
|
||||
}
|
||||
generate_N_id_1_table(q->N_id_1_table);
|
||||
q->dftp_input.options = DFT_MIRROR_POS | DFT_DC_OFFSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sss_synch_free(sss_synch_t *q) {
|
||||
dft_plan_free(&q->dftp_input);
|
||||
bzero(q, sizeof(sss_synch_t));
|
||||
}
|
||||
|
||||
/** Initializes the SSS sequences for the given N_id_2 */
|
||||
int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2) {
|
||||
if (N_id_2 < 0 || N_id_2 > 2) {
|
||||
fprintf(stderr, "Invalid N_id_2 %d\n", N_id_2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct sss_tables sss_tables;
|
||||
generate_sss_all_tables(&sss_tables,N_id_2);
|
||||
convert_tables(&q->fc_tables, &sss_tables);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* In this function, input points to the beginning of the subframe. Saves result in subframe_idx and N_id_1
|
||||
* Return 1 if the sequence was found, 0 if the peak is not found, -1 if the subframe_sz or symbol_sz are
|
||||
* invalid or not configured.
|
||||
* Before calling this function, the correlation threshold and symbol size duration need to be set
|
||||
* using sss_synch_set_threshold() and sss_synch_set_symbol_sz().
|
||||
*/
|
||||
int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx,
|
||||
int *N_id_1) {
|
||||
int m0,m1;
|
||||
float m0_value, m1_value;
|
||||
|
||||
if (q->subframe_sz <= 0 || q->symbol_sz <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sss_synch_m0m1(q, &input[SSS_SYMBOL_ST(q->subframe_sz, q->symbol_sz)],
|
||||
&m0, &m0_value, &m1, &m1_value);
|
||||
|
||||
if (m0_value > q->corr_peak_threshold && m1_value > q->corr_peak_threshold) {
|
||||
if (subframe_idx) {
|
||||
*subframe_idx = sss_synch_subframe(m0, m1);
|
||||
}
|
||||
if (N_id_1) {
|
||||
*N_id_1 = sss_synch_N_id_1(q, m0, m1);
|
||||
}
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Used by sss_synch_frame() to compute the beginning of the SSS symbol
|
||||
* symbol_sz MUST INCLUDE THE CYCLIC PREFIX SIZE
|
||||
*/
|
||||
void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz) {
|
||||
q->symbol_sz = symbol_sz;
|
||||
}
|
||||
|
||||
/** Used by sss_synch_frame() to compute the beginning of the SSS symbol */
|
||||
void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz) {
|
||||
q->subframe_sz = subframe_sz;
|
||||
}
|
||||
|
||||
|
||||
/** Sets the SSS correlation peak detection threshold */
|
||||
void sss_synch_set_threshold(sss_synch_t *q, float threshold) {
|
||||
q->corr_peak_threshold = threshold;
|
||||
}
|
||||
|
||||
/** Returns the subframe index based on the m0 and m1 values */
|
||||
int sss_synch_subframe(int m0, int m1) {
|
||||
if (m1 > m0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the N_id_1 value based on the m0 and m1 values */
|
||||
int sss_synch_N_id_1(sss_synch_t *q, int m0, int m1) {
|
||||
if (m0<0 || m0>29 || m1<0 || m1>29) {
|
||||
return -1;
|
||||
}
|
||||
if (m1 > m0) {
|
||||
return q->N_id_1_table[m0][m1-1];
|
||||
} else {
|
||||
return q->N_id_1_table[m1][m0-1];
|
||||
}
|
||||
}
|
||||
|
||||
/** High-level API */
|
||||
|
||||
int sss_synch_initialize(sss_synch_hl* h) {
|
||||
|
||||
if (sss_synch_init(&h->obj)) {
|
||||
return -1;
|
||||
}
|
||||
sss_synch_set_N_id_2(&h->obj, h->init.N_id_2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sss_synch_work(sss_synch_hl* hl) {
|
||||
|
||||
if (hl->ctrl_in.correlation_threshold) {
|
||||
sss_synch_set_threshold(&hl->obj, hl->ctrl_in.correlation_threshold);
|
||||
}
|
||||
if (hl->ctrl_in.subframe_sz) {
|
||||
sss_synch_set_subframe_sz(&hl->obj, hl->ctrl_in.subframe_sz);
|
||||
}
|
||||
if (hl->ctrl_in.symbol_sz) {
|
||||
sss_synch_set_symbol_sz(&hl->obj, hl->ctrl_in.symbol_sz);
|
||||
}
|
||||
sss_synch_frame(&hl->obj, hl->input, &hl->ctrl_out.subframe_idx, &hl->ctrl_out.N_id_1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sss_synch_stop(sss_synch_hl* hl) {
|
||||
sss_synch_free(&hl->obj);
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include "utils/debug.h"
|
||||
#include "lte/base.h"
|
||||
#include "sync/sync.h"
|
||||
|
||||
int sync_init(sync_t *q) {
|
||||
int N_id_2;
|
||||
|
||||
bzero(q, sizeof(sync_t));
|
||||
q->force_N_id_2 = -1;
|
||||
q->threshold = 1.5;
|
||||
q->pss_mode = PEAK_MEAN;
|
||||
|
||||
for (N_id_2=0;N_id_2<3;N_id_2++) {
|
||||
if (pss_synch_init(&q->pss[N_id_2], 960)) {
|
||||
fprintf(stderr, "Error initializing PSS object\n");
|
||||
return -1;
|
||||
}
|
||||
if (pss_synch_set_N_id_2(&q->pss[N_id_2], N_id_2)) {
|
||||
fprintf(stderr, "Error initializing N_id_2\n");
|
||||
return -1;
|
||||
}
|
||||
if (sss_synch_init(&q->sss[N_id_2])) {
|
||||
fprintf(stderr, "Error initializing SSS object\n");
|
||||
return -1;
|
||||
}
|
||||
if (sss_synch_set_N_id_2(&q->sss[N_id_2], N_id_2)) {
|
||||
fprintf(stderr, "Error initializing N_id_2\n");
|
||||
return -1;
|
||||
}
|
||||
DEBUG("PSS and SSS initiated N_id_2=%d\n", N_id_2);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sync_free(sync_t *q) {
|
||||
int N_id_2;
|
||||
|
||||
for (N_id_2=0;N_id_2<3;N_id_2++) {
|
||||
pss_synch_free(&q->pss[N_id_2]);
|
||||
sss_synch_free(&q->sss[N_id_2]);
|
||||
}
|
||||
}
|
||||
|
||||
void sync_pss_det_absolute(sync_t *q) {
|
||||
q->pss_mode = ABSOLUTE;
|
||||
}
|
||||
void sync_pss_det_peakmean(sync_t *q) {
|
||||
q->pss_mode = PEAK_MEAN;
|
||||
}
|
||||
|
||||
void sync_set_threshold(sync_t *q, float threshold) {
|
||||
q->threshold = threshold;
|
||||
}
|
||||
|
||||
void sync_force_N_id_2(sync_t *q, int force_N_id_2) {
|
||||
q->force_N_id_2 = force_N_id_2;
|
||||
}
|
||||
|
||||
int sync_get_cell_id(sync_t *q) {
|
||||
if (q->N_id_1 >=0 && q->N_id_2 >= 0) {
|
||||
return q->N_id_1*3 + q->N_id_2;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int sync_get_N_id_1(sync_t *q) {
|
||||
return q->N_id_1;
|
||||
}
|
||||
|
||||
int sync_get_N_id_2(sync_t *q) {
|
||||
return q->N_id_2;
|
||||
}
|
||||
|
||||
int sync_get_slot_id(sync_t *q) {
|
||||
return q->slot_id;
|
||||
}
|
||||
|
||||
float sync_get_cfo(sync_t *q) {
|
||||
return q->cfo;
|
||||
}
|
||||
|
||||
float sync_get_peak_to_avg(sync_t *q) {
|
||||
return q->peak_to_avg;
|
||||
}
|
||||
|
||||
int sync_run(sync_t *q, cf_t *input, int read_offset) {
|
||||
int N_id_2, peak_pos[3], sss_idx;
|
||||
int m0, m1;
|
||||
float m0_value, m1_value;
|
||||
float peak_value[3];
|
||||
float mean_value[3];
|
||||
float max=-999;
|
||||
int i;
|
||||
int peak_detected;
|
||||
|
||||
if (q->force_N_id_2 == -1) {
|
||||
for (N_id_2=0;N_id_2<3;N_id_2++) {
|
||||
peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], &input[read_offset],
|
||||
&peak_value[N_id_2], &mean_value[N_id_2]);
|
||||
}
|
||||
for (i=0;i<3;i++) {
|
||||
if (peak_value[i] > max) {
|
||||
max = peak_value[i];
|
||||
N_id_2 = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
N_id_2 = q->force_N_id_2;
|
||||
peak_pos[N_id_2] = pss_synch_find_pss(&q->pss[N_id_2], &input[read_offset],
|
||||
&peak_value[N_id_2], &mean_value[N_id_2]);
|
||||
}
|
||||
|
||||
DEBUG("PSS possible peak N_id_2=%d, pos=%d value=%.2f threshold=%.2f\n",
|
||||
N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->threshold);
|
||||
|
||||
q->peak_to_avg = peak_value[N_id_2] / mean_value[N_id_2];
|
||||
|
||||
/* If peak detected */
|
||||
peak_detected = 0;
|
||||
if (peak_pos[N_id_2] > 128) {
|
||||
if (q->pss_mode == ABSOLUTE) {
|
||||
if (peak_value[N_id_2] > q->threshold) {
|
||||
peak_detected = 1;
|
||||
}
|
||||
} else {
|
||||
if (q->peak_to_avg > q->threshold) {
|
||||
peak_detected = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (peak_detected) {
|
||||
|
||||
INFO("PSS peak detected N_id_2=%d, pos=%d value=%.2f\n", N_id_2, peak_pos[N_id_2], peak_value[N_id_2]);
|
||||
|
||||
q->cfo = pss_synch_cfo_compute(&q->pss[N_id_2], &input[read_offset + peak_pos[N_id_2]-128]);
|
||||
INFO("Estimated CFO=%.4f\n", q->cfo);
|
||||
|
||||
sss_idx = read_offset + peak_pos[N_id_2]-2*(128+CP(128,CPNORM_LEN));
|
||||
if (sss_idx>= 0) {
|
||||
sss_synch_m0m1(&q->sss[N_id_2], &input[sss_idx],
|
||||
&m0, &m0_value, &m1, &m1_value);
|
||||
|
||||
q->N_id_2 = N_id_2;
|
||||
q->slot_id = 2 * sss_synch_subframe(m0, m1);
|
||||
q->N_id_1 = sss_synch_N_id_1(&q->sss[N_id_2], m0, m1);
|
||||
|
||||
INFO("SSS detected N_id_1=%d, slot_idx=%d, m0=%d, m1=%d\n",
|
||||
q->N_id_1, q->slot_id, m0, m1);
|
||||
|
||||
return peak_pos[N_id_2];
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void bit_pack(uint32_t value, char **bits, int nof_bits)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<nof_bits; i++) {
|
||||
(*bits)[i] = (value >> (nof_bits-i-1)) & 0x1;
|
||||
}
|
||||
*bits += nof_bits;
|
||||
}
|
||||
|
||||
uint32_t bit_unpack(char **bits, int nof_bits)
|
||||
{
|
||||
int i;
|
||||
unsigned int value=0;
|
||||
|
||||
for(i=0; i<nof_bits; i++) {
|
||||
value |= (*bits)[i] << (nof_bits-i-1);
|
||||
}
|
||||
*bits += nof_bits;
|
||||
return value;
|
||||
}
|
||||
|
||||
void bit_fprint(FILE *stream, char *bits, int nof_bits) {
|
||||
int i;
|
||||
|
||||
fprintf(stream,"[");
|
||||
for (i=0;i<nof_bits-1;i++) {
|
||||
fprintf(stream,"%d,",bits[i]);
|
||||
}
|
||||
fprintf(stream,"%d]\n",bits[i]);
|
||||
}
|
||||
|
||||
unsigned int bit_diff(char *x, char *y, int nbits) {
|
||||
unsigned int errors=0;
|
||||
for (int i=0;i<nbits;i++) {
|
||||
if (x[i] != y[i]) {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/dft.h"
|
||||
#include "utils/vector.h"
|
||||
#include "utils/convolution.h"
|
||||
|
||||
|
||||
int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len) {
|
||||
state->input_len = input_len;
|
||||
state->filter_len = filter_len;
|
||||
state->output_len = input_len+filter_len-1;
|
||||
state->input_fft = vec_malloc(sizeof(_Complex float)*state->output_len);
|
||||
state->filter_fft = vec_malloc(sizeof(_Complex float)*state->output_len);
|
||||
state->output_fft = vec_malloc(sizeof(_Complex float)*state->output_len);
|
||||
if (!state->input_fft || !state->filter_fft || !state->output_fft) {
|
||||
return -1;
|
||||
}
|
||||
if (dft_plan(state->output_len,COMPLEX_2_COMPLEX,FORWARD,&state->input_plan)) {
|
||||
return -2;
|
||||
}
|
||||
if (dft_plan(state->output_len,COMPLEX_2_COMPLEX,FORWARD,&state->filter_plan)) {
|
||||
return -3;
|
||||
}
|
||||
if (dft_plan(state->output_len,COMPLEX_2_COMPLEX,BACKWARD,&state->output_plan)) {
|
||||
return -4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void conv_fft_cc_free(conv_fft_cc_t *state) {
|
||||
if (state->input_fft) {
|
||||
free(state->input_fft);
|
||||
}
|
||||
if (state->filter_fft) {
|
||||
free(state->filter_fft);
|
||||
}
|
||||
if (state->output_fft) {
|
||||
free(state->output_fft);
|
||||
}
|
||||
dft_plan_free(&state->input_plan);
|
||||
dft_plan_free(&state->filter_plan);
|
||||
dft_plan_free(&state->output_plan);
|
||||
}
|
||||
|
||||
int conv_fft_cc_run(conv_fft_cc_t *state, _Complex float *input, _Complex float *filter, _Complex float *output) {
|
||||
|
||||
dft_run_c2c(&state->input_plan, input, state->input_fft);
|
||||
dft_run_c2c(&state->filter_plan, filter, state->filter_fft);
|
||||
|
||||
vec_dot_prod(state->input_fft,state->filter_fft,state->output_fft,state->output_len);
|
||||
|
||||
dft_run_c2c(&state->output_plan, state->output_fft, output);
|
||||
|
||||
return state->output_len;
|
||||
|
||||
}
|
||||
|
||||
int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len) {
|
||||
int i,j;
|
||||
int output_len;
|
||||
output_len=input_len+filter_len-1;
|
||||
memset(output,0,output_len*sizeof(_Complex float));
|
||||
for (i=0;i<input_len;i++) {
|
||||
for (j=0;j<filter_len;j++) {
|
||||
output[i+j]+=input[i]*filter[j];
|
||||
}
|
||||
}
|
||||
return output_len;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#include "utils/debug.h"
|
||||
|
||||
int verbose = 0;
|
||||
|
||||
void get_time_interval(struct timeval * tdata) {
|
||||
|
||||
tdata[0].tv_sec = tdata[2].tv_sec - tdata[1].tv_sec;
|
||||
tdata[0].tv_usec = tdata[2].tv_usec - tdata[1].tv_usec;
|
||||
if (tdata[0].tv_usec < 0) {
|
||||
tdata[0].tv_sec--;
|
||||
tdata[0].tv_usec += 1000000;
|
||||
}
|
||||
}
|
@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <complex.h>
|
||||
#include <fftw3.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils/dft.h"
|
||||
|
||||
#define div(a,b) ((a-1)/b+1)
|
||||
|
||||
|
||||
int dft_plan_multi(const int *dft_points, dft_mode_t *modes, dft_dir_t *dirs,
|
||||
int nof_plans, dft_plan_t *plans) {
|
||||
int i;
|
||||
for (i=0;i<nof_plans;i++) {
|
||||
if (dft_plan(dft_points[i],modes[i],dirs[i], &plans[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dft_plan_multi_c2c(const int *dft_points, dft_dir_t dir, int nof_plans, dft_plan_t *plans) {
|
||||
int i;
|
||||
for (i=0;i<nof_plans;i++) {
|
||||
if (dft_plan(dft_points[i],COMPLEX_2_COMPLEX,dir,&plans[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dft_plan_multi_c2r(const int *dft_points, dft_dir_t dir, int nof_plans, dft_plan_t *plans) {
|
||||
int i;
|
||||
for (i=0;i<nof_plans;i++) {
|
||||
if (dft_plan(dft_points[i],COMPLEX_2_REAL,dir,&plans[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int dft_plan_multi_r2r(const int *dft_points, dft_dir_t dir, int nof_plans, dft_plan_t *plans) {
|
||||
int i;
|
||||
for (i=0;i<nof_plans;i++) {
|
||||
if (dft_plan(dft_points[i],REAL_2_REAL,dir,&plans[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dft_plan(const int dft_points, dft_mode_t mode, dft_dir_t dir, dft_plan_t *plan) {
|
||||
|
||||
switch(mode) {
|
||||
case COMPLEX_2_COMPLEX:
|
||||
if (dft_plan_c2c(dft_points,dir,plan)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case REAL_2_REAL:
|
||||
if (dft_plan_r2r(dft_points,dir,plan)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case COMPLEX_2_REAL:
|
||||
if (dft_plan_c2r(dft_points,dir,plan)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void allocate(dft_plan_t *plan, int size_in, int size_out, int len) {
|
||||
plan->in = fftwf_malloc(size_in*len);
|
||||
plan->out = fftwf_malloc(size_out*len);
|
||||
}
|
||||
|
||||
int dft_plan_c2c(const int dft_points, dft_dir_t dir, dft_plan_t *plan) {
|
||||
int sign;
|
||||
sign = (dir == FORWARD) ? FFTW_FORWARD : FFTW_BACKWARD;
|
||||
allocate(plan,sizeof(fftwf_complex),sizeof(fftwf_complex), dft_points);
|
||||
|
||||
plan->p = fftwf_plan_dft_1d(dft_points, plan->in, plan->out, sign, 0U);
|
||||
if (!plan->p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
plan->size = dft_points;
|
||||
plan->mode = COMPLEX_2_COMPLEX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dft_plan_r2r(const int dft_points, dft_dir_t dir, dft_plan_t *plan) {
|
||||
int sign;
|
||||
sign = (dir == FORWARD) ? FFTW_R2HC : FFTW_HC2R;
|
||||
|
||||
allocate(plan,sizeof(float),sizeof(float), dft_points);
|
||||
|
||||
plan->p = fftwf_plan_r2r_1d(dft_points, plan->in, plan->out, sign, 0U);
|
||||
if (!plan->p) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
plan->size = dft_points;
|
||||
plan->mode = REAL_2_REAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dft_plan_c2r(const int dft_points, dft_dir_t dir, dft_plan_t *plan) {
|
||||
if (dft_plan_c2c(dft_points, dir, plan)) {
|
||||
return -1;
|
||||
}
|
||||
plan->mode = COMPLEX_2_REAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void copy(char *dst, char *src, int size_d, int len, int mirror, int dc_offset) {
|
||||
int offset=dc_offset?1:0;
|
||||
int hlen;
|
||||
if (mirror == DFT_MIRROR_PRE) {
|
||||
hlen = div(len,2);
|
||||
memset(dst,0,size_d*offset);
|
||||
memcpy(&dst[offset*size_d], &src[size_d*hlen], size_d*(hlen-offset));
|
||||
memcpy(&dst[hlen*size_d], src, size_d*(len - hlen));
|
||||
} else if (mirror == DFT_MIRROR_POS) {
|
||||
hlen = div(len,2);
|
||||
memcpy(dst, &src[size_d*hlen], size_d*hlen);
|
||||
memcpy(&dst[hlen*size_d], &src[size_d*offset], size_d*(len - hlen));
|
||||
} else {
|
||||
memcpy(dst,src,size_d*len);
|
||||
}
|
||||
}
|
||||
|
||||
void dft_run(dft_plan_t *plan, void *in, void *out) {
|
||||
switch(plan->mode) {
|
||||
case COMPLEX_2_COMPLEX:
|
||||
dft_run_c2c(plan,in,out);
|
||||
break;
|
||||
case REAL_2_REAL:
|
||||
dft_run_r2r(plan,in,out);
|
||||
break;
|
||||
case COMPLEX_2_REAL:
|
||||
dft_run_c2r(plan,in,out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void dft_run_c2c(dft_plan_t *plan, dft_c_t *in, dft_c_t *out) {
|
||||
float norm;
|
||||
int i;
|
||||
fftwf_complex *f_out = plan->out;
|
||||
|
||||
copy((char*) plan->in,(char*) in,sizeof(dft_c_t),plan->size,plan->options & DFT_MIRROR_PRE,
|
||||
plan->options & DFT_DC_OFFSET);
|
||||
|
||||
fftwf_execute(plan->p);
|
||||
|
||||
if (plan->options & DFT_NORMALIZE) {
|
||||
norm = sqrtf(plan->size);
|
||||
for (i=0;i<plan->size;i++) {
|
||||
f_out[i] /= norm;
|
||||
}
|
||||
}
|
||||
if (plan->options & DFT_OUT_DB) {
|
||||
for (i=0;i<plan->size;i++) {
|
||||
f_out[i] = 10*log10(f_out[i]);
|
||||
}
|
||||
}
|
||||
copy((char*) out,(char*) plan->out,sizeof(dft_c_t),plan->size,plan->options & DFT_MIRROR_POS,
|
||||
plan->options & DFT_DC_OFFSET);
|
||||
}
|
||||
|
||||
void dft_run_r2r(dft_plan_t *plan, dft_r_t *in, dft_r_t *out) {
|
||||
float norm;
|
||||
int i;
|
||||
int len = plan->size;
|
||||
float *f_out = plan->out;
|
||||
|
||||
copy((char*) plan->in,(char*) in,sizeof(dft_r_t),plan->size,plan->options & DFT_MIRROR_PRE,
|
||||
plan->options & DFT_DC_OFFSET);
|
||||
|
||||
fftwf_execute(plan->p);
|
||||
|
||||
if (plan->options & DFT_NORMALIZE) {
|
||||
norm = plan->size;
|
||||
for (i=0;i<len;i++) {
|
||||
f_out[i] /= norm;
|
||||
}
|
||||
}
|
||||
if (plan->options & DFT_PSD) {
|
||||
for (i=0;i<(len+1)/2-1;i++) {
|
||||
out[i] = sqrtf(f_out[i]*f_out[i]+f_out[len-i-1]*f_out[len-i-1]);
|
||||
}
|
||||
}
|
||||
if (plan->options & DFT_OUT_DB) {
|
||||
for (i=0;i<len;i++) {
|
||||
out[i] = 10*log10(out[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dft_run_c2r(dft_plan_t *plan, dft_c_t *in, dft_r_t *out) {
|
||||
int i;
|
||||
float norm;
|
||||
float *f_out = plan->out;
|
||||
|
||||
copy((char*) plan->in,(char*) in,sizeof(dft_r_t),plan->size,plan->options & DFT_MIRROR_PRE,
|
||||
plan->options & DFT_DC_OFFSET);
|
||||
|
||||
fftwf_execute(plan->p);
|
||||
|
||||
if (plan->options & DFT_NORMALIZE) {
|
||||
norm = plan->size;
|
||||
for (i=0;i<plan->size;i++) {
|
||||
f_out[i] /= norm;
|
||||
}
|
||||
}
|
||||
if (plan->options & DFT_PSD) {
|
||||
for (i=0;i<plan->size;i++) {
|
||||
out[i] = (__real__ f_out[i])*(__real__ f_out[i])+
|
||||
(__imag__ f_out[i])*(__imag__ f_out[i]);
|
||||
if (!(plan->options & DFT_OUT_DB)) {
|
||||
out[i] = sqrtf(out[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (plan->options & DFT_OUT_DB) {
|
||||
for (i=0;i<plan->size;i++) {
|
||||
out[i] = 10*log10(out[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dft_plan_free(dft_plan_t *plan) {
|
||||
if (!plan) return;
|
||||
if (!plan->size) return;
|
||||
if (plan->in) fftwf_free(plan->in);
|
||||
if (plan->out) fftwf_free(plan->out);
|
||||
if (plan->p) fftwf_destroy_plan(plan->p);
|
||||
bzero(plan, sizeof(dft_plan_t));
|
||||
}
|
||||
|
||||
void dft_plan_free_vector(dft_plan_t *plan, int nof_plans) {
|
||||
int i;
|
||||
for (i=0;i<nof_plans;i++) {
|
||||
dft_plan_free(&plan[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "utils/matrix.h"
|
||||
|
||||
int matrix_init(void ***q, int sz_x, int sz_y, int elem_sz) {
|
||||
int i;
|
||||
int ret = -1;
|
||||
*q = malloc(sizeof(void*) * sz_x);
|
||||
if (!*q) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
for (i=0;i<sz_x;i++) {
|
||||
(*q)[i] = malloc(elem_sz * sz_y);
|
||||
if (!(*q)[i]) {
|
||||
goto free_and_exit;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
free_and_exit:
|
||||
if (ret == -1) {
|
||||
matrix_free(*q, sz_x);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void matrix_free(void **q, int sz_x) {
|
||||
int i;
|
||||
if (q) {
|
||||
for (i=0;i<sz_x;i++) {
|
||||
if (q[i]) {
|
||||
free(q[i]);
|
||||
}
|
||||
}
|
||||
free(q);
|
||||
}
|
||||
}
|
||||
|
||||
void matrix_bzero(void **q, int sz_x, int sz_y, int elem_sz) {
|
||||
int i;
|
||||
for (i=0;i<sz_x;i++) {
|
||||
bzero(q[i], sz_y * elem_sz);
|
||||
}
|
||||
}
|
||||
|
||||
void matrix_copy(void **dst, void **src, int sz_x, int sz_y, int elem_sz) {
|
||||
int i;
|
||||
for (i=0;i<sz_x;i++) {
|
||||
memcpy(dst[i], src[i], sz_y * elem_sz);
|
||||
}
|
||||
}
|
||||
|
||||
void matrix_fprintf_cf(FILE *f, cf_t **q, int sz_x, int sz_y) {
|
||||
int i, j;
|
||||
for (i=0;i<sz_x;i++) {
|
||||
printf("(");
|
||||
for (j=0;j<sz_y;j++) {
|
||||
fprintf(f, "%+6.2f%+6.2fi ", __real__ q[i][j], __imag__ q[i][j]);
|
||||
}
|
||||
fprintf(f, ")\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void matrix_fprintf_f(FILE *f, float **q, int sz_x, int sz_y) {
|
||||
int i, j;
|
||||
for (i=0;i<sz_x;i++) {
|
||||
printf("(");
|
||||
for (j=0;j<sz_y;j++) {
|
||||
fprintf(f, "%-6.2f", q[i][j]);
|
||||
}
|
||||
fprintf(f, ")\n");
|
||||
}
|
||||
}
|
||||
|
||||
#define DOTPROD_GEN(x, y, out, sz_x, sz_y) \
|
||||
int i,j; \
|
||||
for (i=0;i<sz_x;i++) { \
|
||||
for (j=0;j<sz_y;j++) { \
|
||||
out[i][j] = x[i][j] * y[i][j]; \
|
||||
} \
|
||||
} \
|
||||
|
||||
/**TODO: Use volk for vector multiplication
|
||||
*
|
||||
*/
|
||||
void matrix_dotprod_cf(cf_t **x, cf_t **y, cf_t **out, int sz_x, int sz_y) {
|
||||
DOTPROD_GEN(x, y, out, sz_x, sz_y);
|
||||
}
|
||||
void matrix_dotprod_float(float **x, float **y, float **out, int sz_x, int sz_y) {
|
||||
DOTPROD_GEN(x, y, out, sz_x, sz_y);
|
||||
}
|
||||
void matrix_dotprod_int(int **x, int **y, int **out, int sz_x, int sz_y) {
|
||||
DOTPROD_GEN(x, y, out, sz_x, sz_y);
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Multiplexes a signal from nof_inputs interfaces.
|
||||
* Copies output_lengths[i] samples to the i-th interfaces, ignores output_padding_pre[i] samples
|
||||
* from the beginning each input interface.
|
||||
*/
|
||||
void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs,
|
||||
int sample_sz) {
|
||||
int i,r;
|
||||
char *out = (char*) output;
|
||||
char **in = (char**) input;
|
||||
|
||||
r=0;
|
||||
for (i=0;i<nof_inputs;i++) {
|
||||
memcpy(&out[r*sample_sz],&in[i][sample_sz*input_padding_pre[i]],sample_sz*input_lengths[i]);
|
||||
r+=input_lengths[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* De-multiplexes a signal to nof_outputs interfaces.
|
||||
* Copies output_lengths[i] samples to the i-th interfaces, adds output_padding_pre[i] zeros
|
||||
* to the beginning and output_padding_post[i] zeros to the end.
|
||||
*/
|
||||
void demux(void *input, void **output, int *output_lengths,
|
||||
int *output_padding_pre, int *output_padding_post, int nof_outputs,
|
||||
int sample_sz) {
|
||||
int i,r;
|
||||
char **out = (char**) output;
|
||||
char *in = (char*) input;
|
||||
|
||||
r=0;
|
||||
for (i=0;i<nof_outputs;i++) {
|
||||
memset(&out[i][0],0,sample_sz*output_padding_pre[i]);
|
||||
memcpy(&out[i][sample_sz*output_padding_pre[i]],&in[r*sample_sz],sample_sz*output_lengths[i]);
|
||||
memset(&out[i][sample_sz*(output_padding_pre[i]+output_lengths[i])],0,sample_sz*output_padding_post[i]);
|
||||
r+=output_lengths[i]+output_padding_post[i];
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Ismael Gomez-Miguelez <gomezi@tcd.ie>.
|
||||
* This file is part of OSLD-lib (http://https://github.com/ismagom/osld-lib)
|
||||
*
|
||||
* OSLD-lib 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.
|
||||
*
|
||||
* OSLD-lib 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 OSLD-lib. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <complex.h>
|
||||
|
||||
#include "utils/nco.h"
|
||||
|
||||
void nco_init(nco_t *nco, int size) {
|
||||
int i;
|
||||
|
||||
nco->size=size;
|
||||
nco->cost=malloc(size*sizeof(float));
|
||||
nco->sint=malloc(size*sizeof(float));
|
||||
assert(nco->cost && nco->sint);
|
||||
|
||||
for (i=0;i<size;i++) {
|
||||
nco->cost[i] = cosf(2*M_PI*i/size);
|
||||
nco->sint[i] = sinf(2*M_PI*i/size);
|
||||
}
|
||||
}
|
||||
|
||||
void nco_destroy(nco_t *nco) {
|
||||
if (nco->cost) {
|
||||
free(nco->cost);
|
||||
}
|
||||
if (nco->sint) {
|
||||
free(nco->sint);
|
||||
}
|
||||
nco->size=0;
|
||||
bzero(nco, sizeof(nco_t));
|
||||
}
|
||||
|
||||
unsigned int nco_idx(float phase, int size) {
|
||||
while(phase>=2*M_PI) {
|
||||
phase-=2*M_PI;
|
||||
}
|
||||
unsigned int idx = (unsigned int) (phase*size/(2*M_PI));
|
||||
return idx;
|
||||
}
|
||||
|
||||
inline float nco_sin(nco_t *nco, float phase) {
|
||||
return nco->sint[nco_idx(phase,nco->size)];
|
||||
}
|
||||
inline float nco_cos(nco_t *nco, float phase) {
|
||||
return nco->cost[nco_idx(phase,nco->size)];
|
||||
}
|
||||
inline void nco_sincos(nco_t *nco, float phase, float *sin, float *cos) {
|
||||
unsigned int idx = nco_idx(phase,nco->size);
|
||||
*sin = nco->sint[idx];
|
||||
*cos = nco->cost[idx];
|
||||
}
|
||||
|
||||
inline _Complex float nco_cexp(nco_t *nco, float arg) {
|
||||
float s,c;
|
||||
nco_sincos(nco,arg,&s,&c);
|
||||
return c+I*s;
|
||||
}
|
||||
|
||||
void nco_sin_f(nco_t *nco, float *x, float freq, int len) {
|
||||
int i;
|
||||
unsigned int idx;
|
||||
|
||||
idx=0;
|
||||
for (i=0;i<len;i++) {
|
||||
idx=((unsigned int) (freq*i*nco->size/len))%nco->size;
|
||||
x[i] = nco->sint[idx];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nco_cos_f(nco_t *nco, float *x, float freq, int len) {
|
||||
int i;
|
||||
unsigned int idx;
|
||||
|
||||
idx=0;
|
||||
for (i=0;i<len;i++) {
|
||||
idx=((unsigned int) (freq*i*nco->size/len))%nco->size;
|
||||
x[i] = nco->cost[idx];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nco_cexp_f(nco_t *nco, _Complex float *x, float freq, int len) {
|
||||
int i;
|
||||
unsigned int idx;
|
||||
|
||||
idx=0;
|
||||
for (i=0;i<len;i++) {
|
||||
idx=((unsigned int) (freq*i*nco->size/len))%nco->size;
|
||||
x[i] = nco->cost[idx] + I*nco->sint[idx];
|
||||
}
|
||||
}
|
||||
|
||||
void nco_cexp_f_direct(_Complex float *x, float freq, int len) {
|
||||
int i;
|
||||
for (i=0;i<len;i++) {
|
||||
x[i] *= cexpf(_Complex_I * 2 * M_PI * freq * i);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue