Initial commit

This commit is contained in:
ismagom 2014-01-28 11:41:17 +00:00
commit 0737f1e615
158 changed files with 23195 additions and 0 deletions

42
CMakeLists.txt Normal file
View File

@ -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)

165
LICENSE Normal file
View File

@ -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.

24
README.md Normal file
View File

@ -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.

22
cmake/FindFFTWS.cmake Normal file
View 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)

26
cmake/FindUHD.cmake Normal file
View File

@ -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)

49
examples/CMakeLists.txt Normal file
View File

@ -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})

130
examples/bch_test.c Normal file
View File

@ -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);
}

272
examples/cell_search.c Normal file
View File

@ -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);
}

View 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)

175
examples/equalizer_test.c Normal file
View File

@ -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);
}

95
examples/hl_example.c Normal file
View File

@ -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);
}

23
examples/ll_example.c Normal file
View File

@ -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);
}

350
examples/pss_scan_usrp.c Normal file
View File

@ -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);
}

140
examples/rssi_scan_usrp.c Normal file
View File

@ -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);
}

240
examples/synch_test.c Normal file
View File

@ -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);
}

168
examples/viterbi_test.c Normal file
View File

@ -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);
}

View File

@ -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

View File

@ -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

43
include/channel/ch_awgn.h Normal file
View File

@ -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

54
include/fec/convcoder.h Normal file
View File

@ -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

26
include/fec/crc.h Normal file
View File

@ -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

42
include/filter/filter2d.h Normal file
View File

@ -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

60
include/io/binsource.h Normal file
View File

@ -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

55
include/io/filesink.h Normal file
View File

@ -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

58
include/io/filesource.h Normal file
View File

@ -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

7
include/io/format.h Normal file
View File

@ -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

72
include/lte.h Normal file
View File

@ -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

93
include/lte/base.h Normal file
View File

@ -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

47
include/lte/fft.h Normal file
View File

@ -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

37
include/lte/sequence.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

49
include/modem/mod.h Normal file
View File

@ -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

View File

@ -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

78
include/phch/pbch.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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

127
include/sync/pss.h Normal file
View File

@ -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

25
include/sync/sfo.h Normal file
View File

@ -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

116
include/sync/sss.h Normal file
View File

@ -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

56
include/sync/sync.h Normal file
View File

@ -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

31
include/utils/bit.h Normal file
View File

@ -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

View File

@ -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

37
include/utils/debug.h Normal file
View File

@ -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

92
include/utils/dft.h Normal file
View File

@ -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

38
include/utils/matrix.h Normal file
View File

@ -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

30
include/utils/mux.h Normal file
View File

@ -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

43
include/utils/nco.h Normal file
View File

@ -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

25
include/utils/pack.h Normal file
View File

@ -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

44
include/utils/vector.h Normal file
View File

@ -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

28
lib/CMakeLists.txt Normal file
View File

@ -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})

View File

@ -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;
}

View File

@ -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));
}

50
lib/channel/src/ch_awgn.c Normal file
View File

@ -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;
}

37
lib/channel/src/gauss.c Normal file
View File

@ -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));
}

19
lib/channel/src/gauss.h Normal file
View File

@ -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);

125
lib/fec/src/convcoder.c Normal file
View File

@ -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;
}

78
lib/fec/src/crc.c Normal file
View File

@ -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);
}

36
lib/fec/src/parity.h Normal file
View File

@ -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);
}

7
lib/fec/src/viterbi37.h Normal file
View File

@ -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);

View File

@ -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;
}

145
lib/filter/src/filter2d.c Normal file
View File

@ -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]);
}
}
}

172
lib/io/src/binsource.c Normal file
View File

@ -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;
}

92
lib/io/src/filesink.c Normal file
View File

@ -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;
}

105
lib/io/src/filesource.c Normal file
View File

@ -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;
}

73
lib/lte/src/fft.c Normal file
View File

@ -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");
}

203
lib/lte/src/lte.c Normal file
View File

@ -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(&lte_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(&lte_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;
}

View File

@ -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);
}

87
lib/lte/src/sequence.c Normal file
View File

@ -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));
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}
}

View File

@ -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);

270
lib/modem/src/lte_tables.c Normal file
View File

@ -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;
}
}

View File

@ -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);

63
lib/modem/src/mod.c Normal file
View File

@ -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;
}

View File

@ -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;
}

133
lib/modem/src/soft_algs.c Normal file
View File

@ -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);
}
}
}

23
lib/modem/src/soft_algs.h Normal file
View File

@ -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);

70
lib/phch/src/common.c Normal file
View File

@ -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);
}

27
lib/phch/src/common.h Normal file
View File

@ -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);

375
lib/phch/src/pbch.c Normal file
View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

5
lib/sync/src/cp.c Normal file
View File

@ -0,0 +1,5 @@
/** TODO: Cyclic-prefix based synchronization
*
*/

108
lib/sync/src/find_sss.c Normal file
View File

@ -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];
}
}
}

154
lib/sync/src/gen_sss.c Normal file
View File

@ -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]);
}
}

395
lib/sync/src/pss.c Normal file
View File

@ -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;
}

31
lib/sync/src/sfo.c Normal file
View File

@ -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;
}

165
lib/sync/src/sss.c Normal file
View File

@ -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;
}

180
lib/sync/src/sync.c Normal file
View File

@ -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;
}
}

62
lib/utils/src/bit.c Normal file
View File

@ -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;
}

View File

@ -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;
}

13
lib/utils/src/debug.c Normal file
View File

@ -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;
}
}

273
lib/utils/src/dft.c Normal file
View File

@ -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]);
}
}

117
lib/utils/src/matrix.c Normal file
View File

@ -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);
}

60
lib/utils/src/mux.c Normal file
View File

@ -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];
}
}

121
lib/utils/src/nco.c Normal file
View File

@ -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