Resolved merge conflict with issue #24

master
ismagom 11 years ago
commit 60e5ed1ee1

@ -23,13 +23,11 @@
########################################################################
# Prevent in-tree builds
########################################################################
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})
########################################################################
# Project setup
########################################################################
@ -66,12 +64,23 @@ SET(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "")
########################################################################
# Compiler specific setup
########################################################################
macro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE flag have)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(${flag} ${have})
if(${have})
add_definitions(${flag})
endif(${have})
endmacro(ADD_CXX_COMPILER_FLAG_IF_AVAILABLE)
IF(CMAKE_COMPILER_IS_GNUCXX)
# do something
#Any additional flags for CXX
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
IF(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE")
IF(NOT WIN32)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
ENDIF(NOT WIN32)
ENDIF(CMAKE_COMPILER_IS_GNUCC)
IF(MSVC)

@ -35,22 +35,25 @@
SET(QWT_FOUND "NO")
SET(HINT_INCLUDE_PATHS $ENV{QWT_DIR}/include
$ENV{QWT_DIR}/src
$ENV{QWTDIR}/include
$ENV{QWTDIR}/src
$ENV{QWT_ROOT}/include
$ENV{QWT_ROOT}/src
$ENV{QWTROOT}/include
$ENV{QWTROOT}/src)
SET(POTENTIAL_INCLUDE_PATHS /usr/local/qwt/include
/usr/local/include
/usr/include/qwt
/usr/include/qwt-qt4
/usr/include/qwt5
/usr/include
/opt/local/include/qwt) #macports path
FIND_PATH(QWT_INCLUDE_DIR qwt.h
$ENV{QWT_DIR}/include
$ENV{QWT_DIR}/src
$ENV{QWTDIR}/include
$ENV{QWTDIR}/src
$ENV{QWT_ROOT}/include
$ENV{QWT_ROOT}/src
$ENV{QWTROOT}/include
$ENV{QWTROOT}/src
/usr/local/qwt/include
/usr/local/include
/usr/include/qwt
/usr/include/qwt-qt4
/usr/include/qwt5
/usr/include
/opt/local/include/qwt #macports path
HINTS ${HINT_INCLUDE_PATHS}
PATHS ${POTENTIAL_INCLUDE_PATHS}
)
SET(QWT_INCLUDE_DIRS ${QWT_INCLUDE_DIR})
@ -82,20 +85,19 @@ IF( Qwt_FIND_VERSION AND QWT_VERSION_STRING )
ENDIF()
ENDIF()
SET(POTENTIAL_LIBRARY_PATHS
$ENV{QWT_DIR}/lib
$ENV{QWTDIR}/lib
$ENV{QWT_ROOT}/lib
$ENV{QWTROOT}/lib
/usr/local/qwt/lib
/usr/local/lib /usr/lib
/opt/local/lib
)
SET(QWT_NAMES ${QWT_NAMES} qwt qwt-qt4 qwt5 )
SET(HINT_LIBRARY_PATHS $ENV{QWT_DIR}/lib
$ENV{QWTDIR}/lib
$ENV{QWT_ROOT}/lib
$ENV{QWTROOT}/lib)
SET(POTENTIAL_LIBRARY_PATHS /usr/local/qwt/lib
/usr/local/lib
/usr/lib
/opt/local/lib)
FIND_LIBRARY(QWT_LIBRARY
NAMES ${QWT_NAMES}
HINTS ${HINT_LIBRARY_PATHS}
PATHS ${POTENTIAL_LIBRARY_PATHS}
)
MARK_AS_ADVANCED(QWT_LIBRARY)
@ -107,6 +109,7 @@ IF (QWT_LIBRARY)
SET(QWT_NAMES_DEBUG qwtd qwtd-qt4 qwtd5 )
FIND_LIBRARY(QWT_LIBRARY_DEBUG
NAMES ${QWT_NAMES_DEBUG}
HINTS ${HINT_LIBRARY_PATHS}
PATHS ${POTENTIAL_LIBRARY_PATHS}
)
MARK_AS_ADVANCED(QWT_LIBRARY_DEBUG)

@ -22,6 +22,7 @@
########################################################################
# Install headers
########################################################################
ADD_SUBDIRECTORY(include)
INSTALL(DIRECTORY include/ DESTINATION "${INCLUDE_DIR}"
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE

@ -0,0 +1,38 @@
#
# Copyright 2012-2013 The libLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the libLTE library.
#
# libLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# libLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# A copy of the GNU Lesser General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
########################################################################
# Add headers to cmake project (useful for IDEs)
########################################################################
SET(HEADERS_ALL "")
FILE(GLOB_RECURSE tmp "*.h")
LIST(APPEND HEADERS_ALL ${tmp})
FILE(GLOB headers *)
FOREACH (_header ${headers})
IF(IS_DIRECTORY ${_header})
FILE(GLOB_RECURSE tmp "${_header}/*.h")
LIST(APPEND HEADERS_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_header})
ENDFOREACH()
ADD_CUSTOM_TARGET (add_cuhd_headers SOURCES ${HEADERS_ALL})

@ -36,44 +36,44 @@
#include "lte/utils/debug.h"
int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double fs, int nsamp) {
int i, j;
int ret = -1;
_Complex float *buffer;
double f;
int i, j;
int ret = -1;
_Complex float *buffer;
double f;
buffer = calloc(nsamp, sizeof(_Complex float));
if (!buffer) {
goto free_and_exit;
}
buffer = calloc(nsamp, sizeof(_Complex float));
if (!buffer) {
goto free_and_exit;
}
cuhd_set_rx_gain(uhd, 0.0);
cuhd_set_rx_srate(uhd, fs);
cuhd_set_rx_gain(uhd, 0.0);
cuhd_set_rx_srate(uhd, fs);
for (i=0;i<nof_bands;i++) {
cuhd_stop_rx_stream(uhd);
for (i=0;i<nof_bands;i++) {
cuhd_stop_rx_stream(uhd);
f = (double) freqs[i];
cuhd_set_rx_freq(uhd, f);
cuhd_rx_wait_lo_locked(uhd);
f = (double) freqs[i];
cuhd_set_rx_freq(uhd, f);
cuhd_rx_wait_lo_locked(uhd);
cuhd_start_rx_stream(uhd);
cuhd_start_rx_stream(uhd);
/* discard first samples */
for (j=0;j<2;j++) {
if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) {
goto free_and_exit;
}
}
rssi[i] = vec_avg_power_cf(buffer, nsamp);
printf("[%3d]: Freq %4.1f Mhz - RSSI: %3.2f dBm\r", i, f/1000000, 10*log10f(rssi[i]) + 30); fflush(stdout);
if (VERBOSE_ISINFO()) {
printf("\n");
}
}
cuhd_stop_rx_stream(uhd);
/* discard first samples */
for (j=0;j<2;j++) {
if (cuhd_recv(uhd, buffer, nsamp, 1) != nsamp) {
goto free_and_exit;
}
}
rssi[i] = vec_avg_power_cf(buffer, nsamp);
printf("[%3d]: Freq %4.1f Mhz - RSSI: %3.2f dBm\r", i, f/1000000, 10*log10f(rssi[i]) + 30); fflush(stdout);
if (VERBOSE_ISINFO()) {
printf("\n");
}
}
cuhd_stop_rx_stream(uhd);
ret = 0;
ret = 0;
free_and_exit:
free(buffer);
return ret;
free(buffer);
return ret;
}

@ -34,90 +34,90 @@
#include "lte.h"
void usage(char *arg) {
printf("Usage: %s nbits snr_db\n",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);
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);
}

@ -32,20 +32,20 @@
#include "lte.h"
int main(int argc, char **argv) {
binsource_t bs;
char* output;
binsource_t bs;
char* output;
binsource_init(&bs);
binsource_seed_time(&bs);
binsource_init(&bs);
binsource_seed_time(&bs);
output = malloc(100);
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);
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);
}

@ -34,8 +34,8 @@
#include "lte.h"
#ifndef DISABLE_UHD
#include "cuhd.h"
void *uhd;
#include "cuhd.h"
void *uhd;
#endif
char *output_file_name = NULL;
@ -53,231 +53,231 @@ pbch_t pbch;
cf_t *slot_buffer = NULL, *output_buffer = NULL;
int slot_n_re, slot_n_samples;
#define UHD_SAMP_FREQ 1920000
#define UHD_SAMP_FREQ 1920000
void usage(char *prog) {
printf("Usage: %s [agmfoncvp]\n", prog);
printf("Usage: %s [agmfoncvp]\n", prog);
#ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp);
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-m UHD signal amplitude [Default %.2f]\n", uhd_amp);
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
#else
printf("\t UHD is disabled. CUHD library not available\n");
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-o output_file [Default USRP]\n");
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-v [set verbose to debug, default none]\n");
printf("\t-o output_file [Default USRP]\n");
printf("\t-n number of frames [Default %d]\n", nof_frames);
printf("\t-c cell id [Default %d]\n", cell_id);
printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) {
switch(opt) {
case 'a':
uhd_args = argv[optind];
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'm':
uhd_amp = atof(argv[optind]);
break;
case 'f':
uhd_freq = atof(argv[optind]);
break;
case 'o':
output_file_name = argv[optind];
break;
case 'n':
nof_frames = atoi(argv[optind]);
break;
case 'p':
nof_prb = atoi(argv[optind]);
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
int opt;
while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) {
switch(opt) {
case 'a':
uhd_args = argv[optind];
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'm':
uhd_amp = atof(argv[optind]);
break;
case 'f':
uhd_freq = atof(argv[optind]);
break;
case 'o':
output_file_name = argv[optind];
break;
case 'n':
nof_frames = atoi(argv[optind]);
break;
case 'p':
nof_prb = atoi(argv[optind]);
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
#ifdef DISABLE_UHD
if (!output_file_name) {
usage(argv[0]);
exit(-1);
}
if (!output_file_name) {
usage(argv[0]);
exit(-1);
}
#endif
}
void base_init() {
/* init memory */
slot_buffer = malloc(sizeof(cf_t) * slot_n_re);
if (!slot_buffer) {
perror("malloc");
exit(-1);
}
output_buffer = malloc(sizeof(cf_t) * slot_n_samples);
if (!output_buffer) {
perror("malloc");
exit(-1);
}
/* open file or USRP */
if (output_file_name) {
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", output_file_name);
exit(-1);
}
} else {
/* init memory */
slot_buffer = malloc(sizeof(cf_t) * slot_n_re);
if (!slot_buffer) {
perror("malloc");
exit(-1);
}
output_buffer = malloc(sizeof(cf_t) * slot_n_samples);
if (!output_buffer) {
perror("malloc");
exit(-1);
}
/* open file or USRP */
if (output_file_name) {
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", output_file_name);
exit(-1);
}
} else {
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open(uhd_args,&uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
printf("Opening UHD device...\n");
if (cuhd_open(uhd_args,&uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
#else
printf("Error UHD not available. Select an output file\n");
exit(-1);
printf("Error UHD not available. Select an output file\n");
exit(-1);
#endif
}
/* create ifft object */
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
}
/* create ifft object */
if (lte_ifft_init(&ifft, CPNORM, nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
}
void base_free() {
pbch_free(&pbch);
pbch_free(&pbch);
lte_ifft_free(&ifft);
lte_ifft_free(&ifft);
if (slot_buffer) {
free(slot_buffer);
}
if (output_buffer) {
free(output_buffer);
}
if (output_file_name) {
filesink_free(&fsink);
} else {
if (slot_buffer) {
free(slot_buffer);
}
if (output_buffer) {
free(output_buffer);
}
if (output_file_name) {
filesink_free(&fsink);
} else {
#ifndef DISABLE_UHD
cuhd_close(&uhd);
cuhd_close(&uhd);
#endif
}
}
}
int main(int argc, char **argv) {
int nf, ns, N_id_2;
cf_t pss_signal[PSS_LEN];
float sss_signal0[SSS_LEN]; // for subframe 0
float sss_signal5[SSS_LEN]; // for subframe 5
pbch_mib_t mib;
refsignal_t refs[NSLOTS_X_FRAME];
int i;
cf_t *slot1_symbols[MAX_PORTS_CTRL];
int nf, ns, N_id_2;
cf_t pss_signal[PSS_LEN];
float sss_signal0[SSS_LEN]; // for subframe 0
float sss_signal5[SSS_LEN]; // for subframe 5
pbch_mib_t mib;
refsignal_t refs[NSLOTS_X_FRAME];
int i;
cf_t *slot1_symbols[MAX_PORTS_CTRL];
#ifdef DISABLE_UHD
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
#endif
parse_args(argc,argv);
parse_args(argc,argv);
N_id_2 = cell_id%3;
slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb));
N_id_2 = cell_id%3;
slot_n_re = CPNORM_NSYMB * nof_prb * RE_X_RB;
slot_n_samples = SLOT_LEN_CPNORM(lte_symbol_sz(nof_prb));
/* this *must* be called after setting slot_len_* */
base_init();
/* this *must* be called after setting slot_len_* */
base_init();
/* Generate PSS/SSS signals */
pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cell_id);
/* Generate PSS/SSS signals */
pss_generate(pss_signal, N_id_2);
sss_generate(sss_signal0, sss_signal5, cell_id);
/* Generate CRS signals */
for (i=0;i<NSLOTS_X_FRAME;i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
}
/* Generate CRS signals */
for (i=0;i<NSLOTS_X_FRAME;i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell_id, CPNORM, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
}
mib.nof_ports = 1;
mib.nof_prb = 6;
mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1;
mib.sfn = 0;
mib.nof_ports = 1;
mib.nof_prb = 6;
mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1;
mib.sfn = 0;
for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port
slot1_symbols[i] = slot_buffer;
}
for (i=0;i<MAX_PORTS_CTRL;i++) { // now there's only 1 port
slot1_symbols[i] = slot_buffer;
}
#ifndef DISABLE_UHD
if (!output_file_name) {
printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/1000000);
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
printf("Set TX freq: %.2f MHz\n", cuhd_set_tx_freq(uhd, uhd_freq)/1000000);
}
if (!output_file_name) {
printf("Set TX rate: %.2f MHz\n", cuhd_set_tx_srate(uhd, UHD_SAMP_FREQ)/1000000);
printf("Set TX gain: %.1f dB\n", cuhd_set_tx_gain(uhd, uhd_gain));
printf("Set TX freq: %.2f MHz\n", cuhd_set_tx_freq(uhd, uhd_freq)/1000000);
}
#endif
nf = 0;
while(nf<nof_frames || nof_frames == -1) {
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
switch(ns) {
case 0: // tx pss/sss
case 10: // tx pss/sss
pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM);
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
break;
case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, 1);
break;
default: // transmit zeros
break;
}
refsignal_put(&refs[ns], slot_buffer);
/* Transform to OFDM symbols */
lte_ifft_run(&ifft, slot_buffer, output_buffer);
/* send to file or usrp */
if (output_file_name) {
filesink_write(&fsink, output_buffer, slot_n_samples);
usleep(5000);
} else {
nf = 0;
while(nf<nof_frames || nof_frames == -1) {
for (ns=0;ns<NSLOTS_X_FRAME;ns++) {
bzero(slot_buffer, sizeof(cf_t) * slot_n_re);
switch(ns) {
case 0: // tx pss/sss
case 10: // tx pss/sss
pss_put_slot(pss_signal, slot_buffer, nof_prb, CPNORM);
sss_put_slot(ns?sss_signal5:sss_signal0, slot_buffer, nof_prb, CPNORM);
break;
case 1: // tx pbch
pbch_encode(&pbch, &mib, slot1_symbols, 1);
break;
default: // transmit zeros
break;
}
refsignal_put(&refs[ns], slot_buffer);
/* Transform to OFDM symbols */
lte_ifft_run(&ifft, slot_buffer, output_buffer);
/* send to file or usrp */
if (output_file_name) {
filesink_write(&fsink, output_buffer, slot_n_samples);
usleep(5000);
} else {
#ifndef DISABLE_UHD
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples);
cuhd_send(uhd, output_buffer, slot_n_samples, 1);
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, slot_n_samples);
cuhd_send(uhd, output_buffer, slot_n_samples, 1);
#endif
}
}
mib.sfn=(mib.sfn+1)%1024;
printf("SFN: %4d\r", mib.sfn);fflush(stdout);
nf++;
}
}
}
mib.sfn=(mib.sfn+1)%1024;
printf("SFN: %4d\r", mib.sfn);fflush(stdout);
nf++;
}
base_free();
base_free();
printf("Done\n");
exit(0);
printf("Done\n");
exit(0);
}

@ -39,21 +39,21 @@
#include "lte.h"
#ifndef DISABLE_UHD
#include "cuhd.h"
void *uhd;
#include "cuhd.h"
void *uhd;
#endif
#ifndef DISABLE_GRAPHICS
#include "plot.h"
plot_real_t poutfft;
plot_complex_t pce;
plot_scatter_t pscatrecv, pscatequal;
#include "plot.h"
plot_real_t poutfft;
plot_complex_t pce;
plot_scatter_t pscatrecv, pscatequal;
#endif
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define NOF_PORTS 2
@ -80,422 +80,422 @@ cfo_t cfocorr;
enum sync_state {FIND, TRACK};
void usage(char *prog) {
printf("Usage: %s [iagfndvp]\n", prog);
printf("\t-i input_file [Default use USRP]\n");
printf("Usage: %s [iagfndvp]\n", prog);
printf("\t-i input_file [Default use USRP]\n");
#ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-f UHD RX frequency [Default %.1f MHz]\n", uhd_freq/1000000);
#else
printf("\t UHD is disabled. CUHD library not available\n");
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-p PSS threshold [Default %f]\n", find_threshold);
printf("\t-n nof_frames [Default %d]\n", nof_frames);
printf("\t-p PSS threshold [Default %f]\n", find_threshold);
#ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n");
printf("\t-d disable plots [Default enabled]\n");
#else
printf("\t plots are disabled. Graphics library not available\n");
printf("\t plots are disabled. Graphics library not available\n");
#endif
printf("\t-v [set verbose to debug, default none]\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, "iagfndvp")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'a':
uhd_args = argv[optind];
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'f':
uhd_freq = atof(argv[optind]);
break;
case 'p':
find_threshold = atof(argv[optind]);
break;
case 'n':
nof_frames = atoi(argv[optind]);
break;
case 'd':
disable_plots = 1;
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
int opt;
while ((opt = getopt(argc, argv, "iagfndvp")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'a':
uhd_args = argv[optind];
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'f':
uhd_freq = atof(argv[optind]);
break;
case 'p':
find_threshold = atof(argv[optind]);
break;
case 'n':
nof_frames = atoi(argv[optind]);
break;
case 'd':
disable_plots = 1;
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
#ifndef DISABLE_GRAPHICS
void init_plots() {
plot_init();
plot_real_init(&poutfft);
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
plot_real_setLabels(&poutfft, "Index", "dB");
plot_real_setYAxisScale(&poutfft, -60, 0);
plot_real_setXAxisScale(&poutfft, 1, 504);
plot_complex_init(&pce);
plot_complex_setTitle(&pce, "Channel Estimates");
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -1, 1);
plot_scatter_setYAxisScale(&pscatequal, -1, 1);
plot_init();
plot_real_init(&poutfft);
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
plot_real_setLabels(&poutfft, "Index", "dB");
plot_real_setYAxisScale(&poutfft, -60, 0);
plot_real_setXAxisScale(&poutfft, 1, 504);
plot_complex_init(&pce);
plot_complex_setTitle(&pce, "Channel Estimates");
plot_complex_setYAxisScale(&pce, Ip, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Q, -0.01, 0.01);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 0.01);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_setYAxisScale(&pscatrecv, -0.01, 0.01);
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -1, 1);
plot_scatter_setYAxisScale(&pscatequal, -1, 1);
}
#endif
int base_init(int frame_length) {
int i;
int i;
#ifndef DISABLE_GRAPHICS
if (!disable_plots) {
init_plots();
}
if (!disable_plots) {
init_plots();
}
#else
printf("-- PLOTS are disabled. Graphics library not available --\n\n");
printf("-- PLOTS are disabled. Graphics library not available --\n\n");
#endif
if (input_file_name) {
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
return -1;
}
} else {
/* open UHD device */
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open(uhd_args,&uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
#else
printf("Error UHD not available. Select an input file\n");
return -1;
#endif
}
input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
return -1;
}
fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n");
return -1;
}
if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
return 0;
if (input_file_name) {
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
return -1;
}
} else {
/* open UHD device */
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open(uhd_args,&uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
#else
printf("Error UHD not available. Select an input file\n");
return -1;
#endif
}
input_buffer = (cf_t*) malloc(frame_length * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
return -1;
}
fft_buffer = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<MAX_PORTS_CTRL;i++) {
ce[i] = (cf_t*) malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (chest_init(&chest, LINEAR, CPNORM, 6, NOF_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n");
return -1;
}
if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
return 0;
}
void base_free() {
int i;
int i;
if (input_file_name) {
filesource_free(&fsrc);
} else {
#ifndef DISABLE_UHD
cuhd_close(uhd);
#endif
}
if (input_file_name) {
filesource_free(&fsrc);
} else {
#ifndef DISABLE_UHD
cuhd_close(uhd);
#endif
}
#ifndef DISABLE_GRAPHICS
plot_exit();
plot_exit();
#endif
sync_free(&sfind);
sync_free(&strack);
lte_fft_free(&fft);
chest_free(&chest);
cfo_free(&cfocorr);
free(input_buffer);
free(fft_buffer);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
}
sync_free(&sfind);
sync_free(&strack);
lte_fft_free(&fft);
chest_free(&chest);
cfo_free(&cfocorr);
free(input_buffer);
free(fft_buffer);
for (i=0;i<MAX_PORTS_CTRL;i++) {
free(ce[i]);
}
}
int mib_decoder_init(int cell_id) {
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0;
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0;
}
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i, n;
lte_fft_run(&fft, input, fft_buffer);
int i, n;
lte_fft_run(&fft, input, fft_buffer);
/* Get channel estimates for each port */
for (i=0;i<NOF_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
}
/* Get channel estimates for each port */
for (i=0;i<NOF_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
}
DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
DEBUG("Decoding PBCH\n", 0);
n = pbch_decode(&pbch, fft_buffer, ce, 1, mib);
#ifndef DISABLE_GRAPHICS
float tmp[72*7];
if (!disable_plots) {
for (i=0;i<72*7;i++) {
tmp[i] = 10*log10f(cabsf(fft_buffer[i]));
}
plot_real_setNewData(&poutfft, tmp, 72*7);
plot_complex_setNewData(&pce, ce[0], 72*7);
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
if (n) {
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
}
}
float tmp[72*7];
if (!disable_plots) {
for (i=0;i<72*7;i++) {
tmp[i] = 10*log10f(cabsf(fft_buffer[i]));
}
plot_real_setNewData(&poutfft, tmp, 72*7);
plot_complex_setNewData(&pce, ce[0], 72*7);
plot_scatter_setNewData(&pscatrecv, pbch.pbch_symbols[0], pbch.nof_symbols);
if (n) {
plot_scatter_setNewData(&pscatequal, pbch.pbch_d, pbch.nof_symbols);
}
}
#endif
return n;
return n;
}
void sigintHandler(int sig_num)
{
go_exit=1;
go_exit=1;
}
int main(int argc, char **argv) {
int frame_cnt;
int cell_id;
int find_idx, track_idx, last_found;
enum sync_state state;
int nslot;
pbch_mib_t mib;
float cfo;
int n;
int nof_found_mib = 0;
float timeoffset = 0;
int frame_cnt;
int cell_id;
int find_idx, track_idx, last_found;
enum sync_state state;
int nslot;
pbch_mib_t mib;
float cfo;
int n;
int nof_found_mib = 0;
float timeoffset = 0;
#ifdef DISABLE_UHD
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
#endif
parse_args(argc,argv);
if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack);
if (!input_file_name) {
#ifndef DISABLE_UHD
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain);
/* set uhd_freq */
cuhd_set_rx_freq(uhd, (double) uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double) uhd_freq);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
#endif
}
printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler);
state = FIND;
nslot = 0;
find_idx = 0;
cfo = 0;
mib.sfn = -1;
frame_cnt = 0;
last_found = 0;
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
if (input_file_name) {
n = filesource_read(&fsrc, input_buffer, FLEN);
if (n == -1) {
fprintf(stderr, "Error reading file\n");
exit(-1);
} else if (n < FLEN) {
filesource_seek(&fsrc, 0);
filesource_read(&fsrc, input_buffer, FLEN);
}
} else {
#ifndef DISABLE_UHD
cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif
}
switch(state) {
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, input_buffer);
INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set track threshold */
cell_id = sync_get_cell_id(&sfind);
if (cell_id != -1) {
frame_cnt = -1;
last_found = 0;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
sync_force_cp(&strack, sync_get_cp(&sfind));
mib_decoder_init(cell_id);
nof_found_mib = 0;
nslot = sync_get_slot_id(&sfind);
nslot=(nslot+10)%20;
cfo = 0;
timeoffset = 0;
printf("\n");
state = TRACK;
} else {
printf("cellid=-1\n");
}
}
if (verbose == VERBOSE_NONE) {
printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind));
}
break;
case TRACK:
/* Find peak around known position find_idx */
INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]);
if (track_idx != -1) {
/* compute cumulative moving average CFO */
cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1);
/* compute cumulative moving average time offset */
timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1);
last_found = frame_cnt;
find_idx = (find_idx + track_idx - track_len)%FLEN;
if (nslot != sync_get_slot_id(&strack)) {
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
printf("\r\n");
fflush(stdout);
printf("\r\n");
state = FIND;
}
} else {
/* if sync not found, adjust time offset with the averaged value */
find_idx = (find_idx + (int) timeoffset)%FLEN;
}
/* if we missed too many PSS go back to FIND */
if (frame_cnt - last_found > max_track_lost) {
INFO("%d frames lost. Going back to FIND", frame_cnt - last_found);
printf("\r\n");
fflush(stdout);
printf("\r\n");
state = FIND;
}
// Correct CFO
INFO("Correcting CFO=%.4f\n", cfo);
cfo_correct(&cfocorr, input_buffer, -cfo/128);
if (nslot == 0 && find_idx + 960 < FLEN) {
INFO("Finding MIB at idx %d\n", find_idx);
if (mib_decoder_run(&input_buffer[find_idx], &mib)) {
INFO("MIB detected attempt=%d\n", frame_cnt);
if (verbose == VERBOSE_NONE) {
if (!nof_found_mib) {
printf("\r\n");
fflush(stdout);
printf("\r\n");
printf(" - Phy. CellId:\t%d\n", cell_id);
pbch_mib_fprint(stdout, &mib);
}
}
nof_found_mib++;
} else {
INFO("MIB not found attempt %d\n",frame_cnt);
}
if (frame_cnt) {
printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn,
cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt,
(float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt);
fflush(stdout);
}
}
if (input_file_name) {
usleep(5000);
}
nslot = (nslot+10)%20;
break;
}
frame_cnt++;
}
base_free();
printf("\nBye\n");
exit(0);
parse_args(argc,argv);
if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack);
if (!input_file_name) {
#ifndef DISABLE_UHD
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain);
/* set uhd_freq */
cuhd_set_rx_freq(uhd, (double) uhd_freq);
cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double) uhd_freq);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
#endif
}
printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler);
state = FIND;
nslot = 0;
find_idx = 0;
cfo = 0;
mib.sfn = -1;
frame_cnt = 0;
last_found = 0;
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
while(!go_exit && (frame_cnt < nof_frames || nof_frames==-1)) {
INFO(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
if (input_file_name) {
n = filesource_read(&fsrc, input_buffer, FLEN);
if (n == -1) {
fprintf(stderr, "Error reading file\n");
exit(-1);
} else if (n < FLEN) {
filesource_seek(&fsrc, 0);
filesource_read(&fsrc, input_buffer, FLEN);
}
} else {
#ifndef DISABLE_UHD
cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif
}
switch(state) {
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, input_buffer);
INFO("FIND %3d:\tPAR=%.2f\n", frame_cnt, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set track threshold */
cell_id = sync_get_cell_id(&sfind);
if (cell_id != -1) {
frame_cnt = -1;
last_found = 0;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
sync_force_cp(&strack, sync_get_cp(&sfind));
mib_decoder_init(cell_id);
nof_found_mib = 0;
nslot = sync_get_slot_id(&sfind);
nslot=(nslot+10)%20;
cfo = 0;
timeoffset = 0;
printf("\n");
state = TRACK;
} else {
printf("cellid=-1\n");
}
}
if (verbose == VERBOSE_NONE) {
printf("Finding PSS... PAR=%.2f\r", sync_get_peak_to_avg(&sfind));
}
break;
case TRACK:
/* Find peak around known position find_idx */
INFO("TRACK %3d: PSS find_idx %d offset %d\n", frame_cnt, find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[find_idx - track_len]);
if (track_idx != -1) {
/* compute cumulative moving average CFO */
cfo = (sync_get_cfo(&strack) + frame_cnt * cfo) / (frame_cnt + 1);
/* compute cumulative moving average time offset */
timeoffset = (float) (track_idx-track_len + timeoffset * frame_cnt) / (frame_cnt + 1);
last_found = frame_cnt;
find_idx = (find_idx + track_idx - track_len)%FLEN;
if (nslot != sync_get_slot_id(&strack)) {
INFO("Expected slot %d but got %d\n", nslot, sync_get_slot_id(&strack));
printf("\r\n");
fflush(stdout);
printf("\r\n");
state = FIND;
}
} else {
/* if sync not found, adjust time offset with the averaged value */
find_idx = (find_idx + (int) timeoffset)%FLEN;
}
/* if we missed too many PSS go back to FIND */
if (frame_cnt - last_found > max_track_lost) {
INFO("%d frames lost. Going back to FIND", frame_cnt - last_found);
printf("\r\n");
fflush(stdout);
printf("\r\n");
state = FIND;
}
// Correct CFO
INFO("Correcting CFO=%.4f\n", cfo);
cfo_correct(&cfocorr, input_buffer, -cfo/128);
if (nslot == 0 && find_idx + 960 < FLEN) {
INFO("Finding MIB at idx %d\n", find_idx);
if (mib_decoder_run(&input_buffer[find_idx], &mib)) {
INFO("MIB detected attempt=%d\n", frame_cnt);
if (verbose == VERBOSE_NONE) {
if (!nof_found_mib) {
printf("\r\n");
fflush(stdout);
printf("\r\n");
printf(" - Phy. CellId:\t%d\n", cell_id);
pbch_mib_fprint(stdout, &mib);
}
}
nof_found_mib++;
} else {
INFO("MIB not found attempt %d\n",frame_cnt);
}
if (frame_cnt) {
printf("SFN: %4d, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, ErrorRate: %.1e\r", mib.sfn,
cfo*15, timeoffset/5, find_idx, frame_cnt-2*(nof_found_mib-1), frame_cnt,
(float) (frame_cnt-2*(nof_found_mib-1))/frame_cnt);
fflush(stdout);
}
}
if (input_file_name) {
usleep(5000);
}
nslot = (nslot+10)%20;
break;
}
frame_cnt++;
}
base_free();
printf("\nBye\n");
exit(0);
}

@ -42,13 +42,13 @@
#include "cuhd.h"
#endif
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define RSSI_FS 1000000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define RSSI_FS 1000000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define RSSI_DECIM 20
#define RSSI_DECIM 20
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
@ -86,474 +86,474 @@ enum sync_state {INIT, FIND, TRACK, MIB, DONE};
void usage(char *prog) {
printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
printf("\t-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n");
printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
printf("\t-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -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 'R':
nof_samples_rssi = atoi(argv[optind]);
break;
case 'r':
rssi_threshold = -atof(argv[optind]);
break;
case 'F':
nof_frames_find = atoi(argv[optind]);
break;
case 'f':
find_threshold = atof(argv[optind]);
break;
case 'T':
nof_frames_track = atoi(argv[optind]);
break;
case 't':
track_threshold = atof(argv[optind]);
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -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 'R':
nof_samples_rssi = atoi(argv[optind]);
break;
case 'r':
rssi_threshold = -atof(argv[optind]);
break;
case 'F':
nof_frames_find = atoi(argv[optind]);
break;
case 'f':
find_threshold = atof(argv[optind]);
break;
case 'T':
nof_frames_track = atoi(argv[optind]);
break;
case 't':
track_threshold = atof(argv[optind]);
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int base_init(int frame_length) {
int i;
input_buffer = malloc(2 * frame_length * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
return -1;
}
fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<MAX_PORTS;i++) {
ce[i] = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n");
return -1;
}
idx_v = malloc(nof_frames_track * sizeof(int));
if (!idx_v) {
perror("malloc");
return -1;
}
idx_valid = malloc(nof_frames_track * sizeof(int));
if (!idx_valid) {
perror("malloc");
return -1;
}
t = malloc(nof_frames_track * sizeof(int));
if (!t) {
perror("malloc");
return -1;
}
cfo_v = malloc(nof_frames_track * sizeof(float));
if (!cfo_v) {
perror("malloc");
return -1;
}
p2a_v = malloc(nof_frames_track * sizeof(float));
if (!p2a_v) {
perror("malloc");
return -1;
}
bzero(cfo, sizeof(float) * MAX_EARFCN);
bzero(p2a, sizeof(float) * MAX_EARFCN);
/* open UHD device */
int i;
input_buffer = malloc(2 * frame_length * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
return -1;
}
fft_buffer = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!fft_buffer) {
perror("malloc");
return -1;
}
for (i=0;i<MAX_PORTS;i++) {
ce[i] = malloc(CPNORM_NSYMB * 72 * sizeof(cf_t));
if (!ce[i]) {
perror("malloc");
return -1;
}
}
if (sync_init(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
return -1;
}
if (chest_init(&chest, LINEAR, CPNORM, 6, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (lte_fft_init(&fft, CPNORM, 6)) {
fprintf(stderr, "Error initializing FFT\n");
return -1;
}
if (cfo_init(&cfocorr, FLEN)) {
fprintf(stderr, "Error initiating CFO\n");
return -1;
}
idx_v = malloc(nof_frames_track * sizeof(int));
if (!idx_v) {
perror("malloc");
return -1;
}
idx_valid = malloc(nof_frames_track * sizeof(int));
if (!idx_valid) {
perror("malloc");
return -1;
}
t = malloc(nof_frames_track * sizeof(int));
if (!t) {
perror("malloc");
return -1;
}
cfo_v = malloc(nof_frames_track * sizeof(float));
if (!cfo_v) {
perror("malloc");
return -1;
}
p2a_v = malloc(nof_frames_track * sizeof(float));
if (!p2a_v) {
perror("malloc");
return -1;
}
bzero(cfo, sizeof(float) * MAX_EARFCN);
bzero(p2a, sizeof(float) * MAX_EARFCN);
/* open UHD device */
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
#endif
return 0;
return 0;
}
void base_free() {
int i;
int i;
#ifndef DISABLE_UHD
cuhd_close(uhd);
cuhd_close(uhd);
#endif
sync_free(&sfind);
sync_free(&strack);
lte_fft_free(&fft);
chest_free(&chest);
cfo_free(&cfocorr);
free(input_buffer);
free(fft_buffer);
for (i=0;i<MAX_PORTS;i++) {
free(ce[i]);
}
free(idx_v);
free(idx_valid);
free(t);
free(cfo_v);
free(p2a_v);
sync_free(&sfind);
sync_free(&strack);
lte_fft_free(&fft);
chest_free(&chest);
cfo_free(&cfocorr);
free(input_buffer);
free(fft_buffer);
for (i=0;i<MAX_PORTS;i++) {
free(ce[i]);
}
free(idx_v);
free(idx_valid);
free(t);
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 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 preprocess_idx(int *in, int *out, int *period, int len) {
int i, n;
n=0;
for (i=0;i<len;i++) {
if (in[i] != -1) {
out[n] = in[i];
period[n] = i;
n++;
}
}
return n;
int i, n;
n=0;
for (i=0;i<len;i++) {
if (in[i] != -1) {
out[n] = in[i];
period[n] = i;
n++;
}
}
return n;
}
int rssi_scan() {
int n=0;
int i;
if (nof_bands > 100) {
/* scan every Mhz, that is 10 freqs */
for (i=0;i<nof_bands;i+=RSSI_DECIM) {
freqs[n] = channels[i].fd * MHZ;
n++;
}
int n=0;
int i;
if (nof_bands > 100) {
/* scan every Mhz, that is 10 freqs */
for (i=0;i<nof_bands;i+=RSSI_DECIM) {
freqs[n] = channels[i].fd * MHZ;
n++;
}
#ifndef DISABLE_UHD
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
#endif
/* linearly interpolate the rssi vector */
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
} else {
for (i=0;i<nof_bands;i++) {
freqs[i] = channels[i].fd * MHZ;
}
/* linearly interpolate the rssi vector */
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
} else {
for (i=0;i<nof_bands;i++) {
freqs[i] = channels[i].fd * MHZ;
}
#ifndef DISABLE_UHD
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
#endif
n = nof_bands;
}
n = nof_bands;
}
return n;
return n;
}
int mib_decoder_init(int cell_id) {
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0;
if (chest_ref_LTEDL(&chest, cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
if (pbch_init(&pbch, 6, cell_id, CPNORM)) {
fprintf(stderr, "Error initiating PBCH\n");
return -1;
}
DEBUG("PBCH initiated cell_id=%d\n", cell_id);
return 0;
}
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
int i;
lte_fft_run(&fft, input, fft_buffer);
int i;
lte_fft_run(&fft, input, fft_buffer);
/* Get channel estimates for each port */
for (i=0;i<MAX_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
}
/* Get channel estimates for each port */
for (i=0;i<MAX_PORTS;i++) {
chest_ce_slot_port(&chest, fft_buffer, ce[i], 1, i);
}
DEBUG("Decoding PBCH\n", 0);
return pbch_decode(&pbch, fft_buffer, ce, 1, mib);
DEBUG("Decoding PBCH\n", 0);
return pbch_decode(&pbch, fft_buffer, ce, 1, mib);
}
int main(int argc, char **argv) {
int frame_cnt, valid_frames;
int freq;
int cell_id;
float max_peak_to_avg;
float sfo;
int find_idx, track_idx, last_found;
enum sync_state state;
int n;
int mib_attempts;
int nslot;
pbch_mib_t mib;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
n = rssi_scan();
if (n == -1) {
exit(-1);
}
printf("\nDone. Starting PSS search on %d channels\n", n);
usleep(500000);
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
int frame_cnt, valid_frames;
int freq;
int cell_id;
float max_peak_to_avg;
float sfo;
int find_idx, track_idx, last_found;
enum sync_state state;
int n;
int mib_attempts;
int nslot;
pbch_mib_t mib;
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
if (base_init(FLEN)) {
fprintf(stderr, "Error initializing memory\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
n = rssi_scan();
if (n == -1) {
exit(-1);
}
printf("\nDone. Starting PSS search on %d channels\n", n);
usleep(500000);
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
#ifndef DISABLE_UHD
cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain);
cuhd_set_rx_gain(uhd, uhd_gain);
#endif
freq=0;
state = INIT;
nslot = 0;
sfo = 0;
find_idx = 0;
frame_cnt = 0;
max_peak_to_avg = -1;
last_found = 0;
cell_id = 0;
while(freq<nof_bands) {
/* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) {
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
freq++;
} else {
if (state != INIT && state != DONE) {
freq=0;
state = INIT;
nslot = 0;
sfo = 0;
find_idx = 0;
frame_cnt = 0;
max_peak_to_avg = -1;
last_found = 0;
cell_id = 0;
while(freq<nof_bands) {
/* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) {
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
freq++;
} else {
if (state != INIT && state != DONE) {
#ifndef DISABLE_UHD
DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
#endif
}
switch(state) {
case INIT:
DEBUG("Stopping receiver...\n",0);
}
switch(state) {
case INIT:
DEBUG("Stopping receiver...\n",0);
#ifndef DISABLE_UHD
cuhd_stop_rx_stream(uhd);
cuhd_stop_rx_stream(uhd);
/* set freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
/* set freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
#endif
/* init variables */
frame_cnt = 0;
max_peak_to_avg = -1;
cell_id = -1;
/* init variables */
frame_cnt = 0;
max_peak_to_avg = -1;
cell_id = -1;
/* receive first frame */
/* receive first frame */
#ifndef DISABLE_UHD
cuhd_recv(uhd, input_buffer, FLEN, 1);
cuhd_recv(uhd, input_buffer, FLEN, 1);
#endif
/* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
state = FIND;
break;
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set lower threshold */
frame_cnt = -1;
last_found = 0;
max_peak_to_avg = -1;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
cell_id = sync_get_cell_id(&sfind);
state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind)));
} else {
if (frame_cnt >= nof_frames_find) {
state = INIT;
freq++;
}
}
break;
case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
/* 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(&strack);
}
if (track_idx != -1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt;
find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx;
nslot = sync_get_slot_id(&strack);
} else {
idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0;
}
/* if we missed to many PSS it is not a cell, next freq */
if (frame_cnt - last_found > max_track_lost) {
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
state = INIT;
freq++;
} else if (frame_cnt >= nof_frames_track) {
mib_decoder_init(cell_id);
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
state = MIB;
nslot=(nslot+10)%20;
}
break;
case MIB:
INFO("Finding MIB at freq %.2f Mhz offset=%d, cell_id=%d, slot_idx=%d\n", channels[freq].fd, find_idx, cell_id, nslot);
// TODO: Correct SFO
// Correct CFO
INFO("Correcting CFO=%.4f\n", cfo[freq]);
cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128);
if (nslot == 0) {
if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) {
INFO("MIB detected attempt=%d\n", mib_attempts);
state = DONE;
} else {
INFO("MIB not detected attempt=%d\n", mib_attempts);
if (mib_attempts == 0) {
freq++;
state = INIT;
}
}
mib_attempts++;
}
nslot = (nslot+10)%20;
break;
case DONE:
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
pbch_mib_fprint(stdout, &mib);
state = INIT;
freq++;
break;
}
/** FIXME: This is not necessary at all */
if (state == TRACK || state == FIND) {
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
}
frame_cnt++;
}
}
base_free();
printf("\n\nDone\n");
exit(0);
/* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
state = FIND;
break;
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set lower threshold */
frame_cnt = -1;
last_found = 0;
max_peak_to_avg = -1;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
cell_id = sync_get_cell_id(&sfind);
state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind)));
} else {
if (frame_cnt >= nof_frames_find) {
state = INIT;
freq++;
}
}
break;
case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx - track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
/* 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(&strack);
}
if (track_idx != -1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt;
find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx;
nslot = sync_get_slot_id(&strack);
} else {
idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0;
}
/* if we missed to many PSS it is not a cell, next freq */
if (frame_cnt - last_found > max_track_lost) {
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
state = INIT;
freq++;
} else if (frame_cnt >= nof_frames_track) {
mib_decoder_init(cell_id);
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
state = MIB;
nslot=(nslot+10)%20;
}
break;
case MIB:
INFO("Finding MIB at freq %.2f Mhz offset=%d, cell_id=%d, slot_idx=%d\n", channels[freq].fd, find_idx, cell_id, nslot);
// TODO: Correct SFO
// Correct CFO
INFO("Correcting CFO=%.4f\n", cfo[freq]);
cfo_correct(&cfocorr, &input_buffer[FLEN], (-cfo[freq])/128);
if (nslot == 0) {
if (mib_decoder_run(&input_buffer[FLEN+find_idx], &mib)) {
INFO("MIB detected attempt=%d\n", mib_attempts);
state = DONE;
} else {
INFO("MIB not detected attempt=%d\n", mib_attempts);
if (mib_attempts == 0) {
freq++;
state = INIT;
}
}
mib_attempts++;
}
nslot = (nslot+10)%20;
break;
case DONE:
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
pbch_mib_fprint(stdout, &mib);
state = INIT;
freq++;
break;
}
/** FIXME: This is not necessary at all */
if (state == TRACK || state == FIND) {
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
}
frame_cnt++;
}
}
base_free();
printf("\n\nDone\n");
exit(0);
}

@ -37,13 +37,13 @@
#include "lte.h"
#include "cuhd.h"
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define RSSI_FS 1000000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define RSSI_FS 1000000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define RSSI_DECIM 20
#define RSSI_DECIM 20
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
@ -77,433 +77,433 @@ enum sync_state {INIT, FIND, TRACK, DONE};
void print_to_matlab();
void usage(char *prog) {
printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
printf("\t-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n");
printf("Usage: %s [seRrFfTtgv] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-R rssi_nof_samples [Default %d]\n", nof_samples_rssi);
printf("\t-r rssi_threshold [Default %.2f dBm]\n", rssi_threshold);
printf("\t-F pss_find_nof_frames [Default %d]\n", nof_frames_find);
printf("\t-f pss_find_threshold [Default %.2f]\n", find_threshold);
printf("\t-T pss_track_nof_frames [Default %d]\n", nof_frames_track);
printf("\t-t pss_track_threshold [Default %.2f]\n", track_threshold);
printf("\t-l pss_track_len [Default %d]\n", track_len);
printf("\t-g gain [Default %.2f dB]\n", uhd_gain);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -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 'R':
nof_samples_rssi = atoi(argv[optind]);
break;
case 'r':
rssi_threshold = -atof(argv[optind]);
break;
case 'F':
nof_frames_find = atoi(argv[optind]);
break;
case 'f':
find_threshold = atof(argv[optind]);
break;
case 'T':
nof_frames_track = atoi(argv[optind]);
break;
case 't':
track_threshold = atof(argv[optind]);
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
int opt;
while ((opt = getopt(argc, argv, "bseRrFfTtgv")) != -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 'R':
nof_samples_rssi = atoi(argv[optind]);
break;
case 'r':
rssi_threshold = -atof(argv[optind]);
break;
case 'F':
nof_frames_find = atoi(argv[optind]);
break;
case 'f':
find_threshold = atof(argv[optind]);
break;
case 'T':
nof_frames_track = atoi(argv[optind]);
break;
case 't':
track_threshold = atof(argv[optind]);
break;
case 'g':
uhd_gain = atof(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_frames_track * sizeof(int));
if (!idx_v) {
perror("malloc");
exit(-1);
}
idx_valid = malloc(nof_frames_track * sizeof(int));
if (!idx_valid) {
perror("malloc");
exit(-1);
}
t = malloc(nof_frames_track * sizeof(int));
if (!t) {
perror("malloc");
exit(-1);
}
cfo_v = malloc(nof_frames_track * sizeof(float));
if (!cfo_v) {
perror("malloc");
exit(-1);
}
p2a_v = malloc(nof_frames_track * 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 (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
return 0;
input_buffer = malloc(2 * frame_length * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
exit(-1);
}
idx_v = malloc(nof_frames_track * sizeof(int));
if (!idx_v) {
perror("malloc");
exit(-1);
}
idx_valid = malloc(nof_frames_track * sizeof(int));
if (!idx_valid) {
perror("malloc");
exit(-1);
}
t = malloc(nof_frames_track * sizeof(int));
if (!t) {
perror("malloc");
exit(-1);
}
cfo_v = malloc(nof_frames_track * sizeof(float));
if (!cfo_v) {
perror("malloc");
exit(-1);
}
p2a_v = malloc(nof_frames_track * 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 (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
return 0;
}
void base_free() {
cuhd_close(uhd);
free(input_buffer);
free(idx_v);
free(idx_valid);
free(t);
free(cfo_v);
free(p2a_v);
cuhd_close(uhd);
free(input_buffer);
free(idx_v);
free(idx_valid);
free(t);
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 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 preprocess_idx(int *in, int *out, int *period, int len) {
int i, n;
n=0;
for (i=0;i<len;i++) {
if (in[i] != -1) {
out[n] = in[i];
period[n] = i;
n++;
}
}
return n;
int i, n;
n=0;
for (i=0;i<len;i++) {
if (in[i] != -1) {
out[n] = in[i];
period[n] = i;
n++;
}
}
return n;
}
int rssi_scan() {
int n=0;
int i;
if (nof_bands > 100) {
/* scan every Mhz, that is 10 freqs */
for (i=0;i<nof_bands;i+=RSSI_DECIM) {
freqs[n] = channels[i].fd * MHZ;
n++;
}
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
/* linearly interpolate the rssi vector */
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
} else {
for (i=0;i<nof_bands;i++) {
freqs[i] = channels[i].fd * MHZ;
}
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
n = nof_bands;
}
return n;
int n=0;
int i;
if (nof_bands > 100) {
/* scan every Mhz, that is 10 freqs */
for (i=0;i<nof_bands;i+=RSSI_DECIM) {
freqs[n] = channels[i].fd * MHZ;
n++;
}
if (cuhd_rssi_scan(uhd, freqs, rssi_d, n, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
/* linearly interpolate the rssi vector */
interp_linear_f(rssi_d, rssi, RSSI_DECIM, n);
} else {
for (i=0;i<nof_bands;i++) {
freqs[i] = channels[i].fd * MHZ;
}
if (cuhd_rssi_scan(uhd, freqs, rssi, nof_bands, (double) RSSI_FS, nof_samples_rssi)) {
fprintf(stderr, "Error while doing RSSI scan\n");
return -1;
}
n = nof_bands;
}
return n;
}
int main(int argc, char **argv) {
int frame_cnt, valid_frames;
int freq;
int cell_id;
sync_t sfind, strack;
float max_peak_to_avg;
float sfo;
int find_idx, track_idx, last_found;
enum sync_state state;
int n;
filesink_t fs;
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(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
n = rssi_scan();
if (n == -1) {
exit(-1);
}
printf("\nDone. Starting PSS search on %d channels\n", n);
usleep(500000);
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain);
print_to_matlab();
filesink_init(&fs, "test.dat", COMPLEX_FLOAT_BIN);
freq=0;
state = INIT;
find_idx = 0;
max_peak_to_avg = 0;
last_found = 0;
frame_cnt = 0;
while(freq<nof_bands) {
/* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) {
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
freq++;
} else {
if (state == TRACK || state == FIND) {
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
}
switch(state) {
case INIT:
DEBUG("Stopping receiver...\n",0);
cuhd_stop_rx_stream(uhd);
/* set freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
/* init variables */
frame_cnt = 0;
max_peak_to_avg = -99;
cell_id = -1;
/* receive first frame */
cuhd_recv(uhd, input_buffer, FLEN, 1);
/* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
state = FIND;
break;
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set lower threshold */
frame_cnt = -1;
last_found = 0;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind)));
} else {
if (frame_cnt >= nof_frames_find) {
state = INIT;
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz No PSS found\r", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
if (VERBOSE_ISINFO()) {
printf("\n");
}
freq++;
}
}
break;
case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx + track_len);
filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
/* 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(&strack);
}
if (track_idx != -1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt;
find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx;
} else {
idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0;
}
/* if we missed to many PSS it is not a cell, next freq */
if (frame_cnt - last_found > max_track_lost) {
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
state = INIT;
freq++;
} else if (frame_cnt >= nof_frames_track) {
state = DONE;
}
break;
case DONE:
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
state = INIT;
freq++;
break;
}
if (state == TRACK || (state == FIND && frame_cnt)) {
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
}
frame_cnt++;
}
}
print_to_matlab();
sync_free(&sfind);
base_free();
printf("\n\nDone\n");
exit(0);
int frame_cnt, valid_frames;
int freq;
int cell_id;
sync_t sfind, strack;
float max_peak_to_avg;
float sfo;
int find_idx, track_idx, last_found;
enum sync_state state;
int n;
filesink_t fs;
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(&sfind, FLEN)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&sfind);
if (sync_init(&strack, track_len)) {
fprintf(stderr, "Error initiating PSS/SSS\n");
exit(-1);
}
sync_pss_det_peak_to_avg(&strack);
nof_bands = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
printf("RSSI scan: %d freqs in band %d, RSSI threshold %.2f dBm\n", nof_bands, band, rssi_threshold);
n = rssi_scan();
if (n == -1) {
exit(-1);
}
printf("\nDone. Starting PSS search on %d channels\n", n);
usleep(500000);
INFO("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
cuhd_set_rx_gain(uhd, uhd_gain);
print_to_matlab();
filesink_init(&fs, "test.dat", COMPLEX_FLOAT_BIN);
freq=0;
state = INIT;
find_idx = 0;
max_peak_to_avg = 0;
last_found = 0;
frame_cnt = 0;
while(freq<nof_bands) {
/* scan only bands above rssi_threshold */
if (!IS_SIGNAL(freq)) {
INFO("[%3d/%d]: Skipping EARFCN %d %.2f MHz RSSI %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,10*log10f(rssi[freq]) + 30);
freq++;
} else {
if (state == TRACK || state == FIND) {
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
}
switch(state) {
case INIT:
DEBUG("Stopping receiver...\n",0);
cuhd_stop_rx_stream(uhd);
/* set freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set freq to %.3f MHz\n", (double) channels[freq].fd);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
/* init variables */
frame_cnt = 0;
max_peak_to_avg = -99;
cell_id = -1;
/* receive first frame */
cuhd_recv(uhd, input_buffer, FLEN, 1);
/* set find_threshold and go to FIND state */
sync_set_threshold(&sfind, find_threshold);
sync_force_N_id_2(&sfind, -1);
state = FIND;
break;
case FIND:
/* find peak in all frame */
find_idx = sync_run(&sfind, &input_buffer[FLEN]);
DEBUG("[%3d/%d]: PAR=%.2f\n", freq, nof_bands, sync_get_peak_to_avg(&sfind));
if (find_idx != -1) {
/* if found peak, go to track and set lower threshold */
frame_cnt = -1;
last_found = 0;
sync_set_threshold(&strack, track_threshold);
sync_force_N_id_2(&strack, sync_get_N_id_2(&sfind));
state = TRACK;
INFO("[%3d/%d]: EARFCN %d Freq. %.2f MHz PSS found PAR %.2f dB\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(sync_get_peak_to_avg(&sfind)));
} else {
if (frame_cnt >= nof_frames_find) {
state = INIT;
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz No PSS found\r", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
if (VERBOSE_ISINFO()) {
printf("\n");
}
freq++;
}
}
break;
case TRACK:
INFO("Tracking PSS find_idx %d offset %d\n", find_idx, find_idx + track_len);
filesink_write(&fs, &input_buffer[FLEN+find_idx+track_len], track_len);
track_idx = sync_run(&strack, &input_buffer[FLEN + find_idx - track_len]);
p2a_v[frame_cnt] = sync_get_peak_to_avg(&strack);
/* 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(&strack);
}
if (track_idx != -1) {
cfo_v[frame_cnt] = sync_get_cfo(&strack);
last_found = frame_cnt;
find_idx += track_idx - track_len;
idx_v[frame_cnt] = find_idx;
} else {
idx_v[frame_cnt] = -1;
cfo_v[frame_cnt] = 0.0;
}
/* if we missed to many PSS it is not a cell, next freq */
if (frame_cnt - last_found > max_track_lost) {
INFO("\n[%3d/%d]: EARFCN %d Freq. %.2f MHz %d frames lost\n", freq, nof_bands,
channels[freq].id, channels[freq].fd, frame_cnt - last_found);
state = INIT;
freq++;
} else if (frame_cnt >= nof_frames_track) {
state = DONE;
}
break;
case DONE:
cfo[freq] = mean_valid(idx_v, cfo_v, frame_cnt);
p2a[freq] = mean_valid(idx_v, p2a_v, frame_cnt);
valid_frames = preprocess_idx(idx_v, idx_valid, t, frame_cnt);
sfo = sfo_estimate_period(idx_valid, t, valid_frames, FLEN_PERIOD);
printf("\n[%3d/%d]: FOUND EARFCN %d Freq. %.2f MHz. "
"PAR %2.2f dB, CFO=%+.2f KHz, SFO=%+2.3f KHz, CELL_ID=%3d\n", freq, nof_bands,
channels[freq].id, channels[freq].fd,
10*log10f(p2a[freq]), cfo[freq] * 15, sfo / 1000, cell_id);
state = INIT;
freq++;
break;
}
if (state == TRACK || (state == FIND && frame_cnt)) {
memcpy(input_buffer, &input_buffer[FLEN], FLEN * sizeof(cf_t));
}
frame_cnt++;
}
}
print_to_matlab();
sync_free(&sfind);
base_free();
printf("\n\nDone\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, "rssi_d=[");
for (i=0;i<nof_bands/RSSI_DECIM;i++) {
fprintf(f, "%g, ", rssi_d[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");
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, "rssi_d=[");
for (i=0;i<nof_bands/RSSI_DECIM;i++) {
fprintf(f, "%g, ", rssi_d[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, "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);
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);
}

@ -49,119 +49,119 @@ lte_earfcn_t channels[MAX_EARFCN];
#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_frames);
printf("\t-v [set verbose to debug, default none]\n");
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_frames);
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_frames = atoi(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
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_frames = 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 (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
printf("Starting receiver...\n");
cuhd_start_rx_stream(uhd);
return 0;
input_buffer = malloc(4 * 960 * sizeof(cf_t));
if (!input_buffer) {
perror("malloc");
exit(-1);
}
/* open UHD device */
printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
printf("Setting sampling frequency %.2f MHz\n", (float) SAMP_FREQ/MHZ);
cuhd_set_rx_srate(uhd, SAMP_FREQ);
printf("Starting receiver...\n");
cuhd_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++) {
cuhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ);
frame_cnt = 0;
nsamples=0;
rssi[i]=0;
while(frame_cnt < nof_frames) {
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
rssi[i] += vec_avg_power_cf(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);
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++) {
cuhd_set_rx_freq(uhd, (double) channels[i].fd * MHZ);
frame_cnt = 0;
nsamples=0;
rssi[i]=0;
while(frame_cnt < nof_frames) {
nsamples += cuhd_recv(uhd, input_buffer, 1920, 1);
rssi[i] += vec_avg_power_cf(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);
}

@ -39,233 +39,233 @@ int nof_frames=100, frame_length=9600, symbol_sz=128;
float corr_peak_threshold=25.0;
int out_N_id_2 = 0, force_N_id_2=-1;
#define CFO_AUTO -9999.0
#define CFO_AUTO -9999.0
float force_cfo = CFO_AUTO;
void usage(char *prog) {
printf("Usage: %s [olntsNfcv] -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_frames);
printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold);
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
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");
printf("\t-v verbose\n");
printf("Usage: %s [olntsNfcv] -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_frames);
printf("\t-t correlation threshold [Default %g]\n", corr_peak_threshold);
printf("\t-s symbol_sz [Default %d]\n", symbol_sz);
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");
printf("\t-v verbose\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "ionltsNfcv")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'o':
output_file_name = argv[optind];
break;
case 'n':
nof_frames = 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 '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;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (!input_file_name) {
usage(argv[0]);
exit(-1);
}
int opt;
while ((opt = getopt(argc, argv, "ionltsNfcv")) != -1) {
switch(opt) {
case 'i':
input_file_name = argv[optind];
break;
case 'o':
output_file_name = argv[optind];
break;
case 'n':
nof_frames = 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 '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;
case 'v':
verbose++;
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
cfo_t cfocorr;
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;
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
cfo_t cfocorr;
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);
}
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
parse_args(argc,argv);
parse_args(argc,argv);
gettimeofday(&tdata[1], NULL);
printf("Initializing...");fflush(stdout);
gettimeofday(&tdata[1], NULL);
printf("Initializing...");fflush(stdout);
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1);
}
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", output_file_name);
exit(-1);
}
if (filesource_init(&fsrc, input_file_name, COMPLEX_FLOAT_BIN)) {
fprintf(stderr, "Error opening file %s\n", input_file_name);
exit(-1);
}
if (filesink_init(&fsink, output_file_name, COMPLEX_FLOAT_BIN)) {
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_frames*sizeof(float));
if (!cfo) {
perror("malloc");
exit(-1);
}
exec_time = malloc(nof_frames*sizeof(int));
if (!exec_time) {
perror("malloc");
exit(-1);
}
input = malloc(frame_length*sizeof(cf_t));
if (!input) {
perror("malloc");
exit(-1);
}
cfo = malloc(nof_frames*sizeof(float));
if (!cfo) {
perror("malloc");
exit(-1);
}
exec_time = malloc(nof_frames*sizeof(int));
if (!exec_time) {
perror("malloc");
exit(-1);
}
if (cfo_init(&cfocorr, frame_length)) {
fprintf(stderr, "Error initiating CFO\n");
return -1;
}
if (cfo_init(&cfocorr, frame_length)) {
fprintf(stderr, "Error initiating CFO\n");
return -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);
/* 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");
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_frames) {
/* read all file or nof_frames */
frame_cnt = 0;
while (frame_length == filesource_read(&fsrc, input, frame_length)
&& frame_cnt < nof_frames) {
gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) {
cfo_correct(&cfocorr, input, -force_cfo/128);
}
gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) {
cfo_correct(&cfocorr, input, -force_cfo/128);
}
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 (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) {
/* 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);
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++;
}
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 ));
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);
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]);
}
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_free(&fsrc);
filesink_free(&fsink);
filesource_free(&fsrc);
filesink_free(&fsink);
free(input);
free(cfo);
free(input);
free(cfo);
printf("Done\n");
exit(0);
printf("Done\n");
exit(0);
}

@ -22,6 +22,7 @@
########################################################################
# Install headers
########################################################################
ADD_SUBDIRECTORY(include)
INSTALL(DIRECTORY include/ DESTINATION "${INCLUDE_DIR}"
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE

@ -0,0 +1,38 @@
#
# Copyright 2012-2013 The libLTE Developers. See the
# COPYRIGHT file at the top-level directory of this distribution.
#
# This file is part of the libLTE library.
#
# libLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# libLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# A copy of the GNU Lesser General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
########################################################################
# Add headers to cmake project (useful for IDEs)
########################################################################
SET(HEADERS_ALL "")
FILE(GLOB_RECURSE tmp "*.h")
LIST(APPEND HEADERS_ALL ${tmp})
FILE(GLOB headers *)
FOREACH (_header ${headers})
IF(IS_DIRECTORY ${_header})
FILE(GLOB_RECURSE tmp "${_header}/*.h")
LIST(APPEND HEADERS_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_header})
ENDFOREACH()
ADD_CUSTOM_TARGET (add_graphics_headers SOURCES ${HEADERS_ALL})

@ -33,13 +33,15 @@
extern "C" {
#endif
#include "lte/config.h"
#include "plot/plot_real.h"
#include "plot/plot_scatter.h"
#include "plot/plot_complex.h"
#include "plot/plot_waterfall.h"
int plot_init();
void plot_exit();
LIBLTE_API int plot_init();
LIBLTE_API void plot_exit();
#ifdef __cplusplus
}

@ -35,22 +35,23 @@ extern "C" {
#endif
#include <stdbool.h>
#include "lte/config.h"
typedef enum {
Ip, Q, Magnitude, Phase
Ip, Q, Magnitude, Phase
} plot_complex_id_t;
typedef void* plot_complex_t;
int plot_complex_init(plot_complex_t *h);
void plot_complex_setTitle(plot_complex_t *h, char *title);
void plot_complex_setNewData(plot_complex_t *h, _Complex float *data,
int num_points);
void plot_complex_setXAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on);
void plot_complex_setYAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on);
void plot_complex_setXAxisScale(plot_complex_t *h, plot_complex_id_t id, double xMin, double xMax);
void plot_complex_setYAxisScale(plot_complex_t *h, plot_complex_id_t id, double yMin, double yMax);
void plot_complex_setXAxisRange(plot_complex_t *h, double xMin, double xMax);
LIBLTE_API int plot_complex_init(plot_complex_t *h);
LIBLTE_API void plot_complex_setTitle(plot_complex_t *h, char *title);
LIBLTE_API void plot_complex_setNewData(plot_complex_t *h, _Complex float *data,
int num_points);
LIBLTE_API void plot_complex_setXAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on);
LIBLTE_API void plot_complex_setYAxisAutoScale(plot_complex_t *h, plot_complex_id_t id, bool on);
LIBLTE_API void plot_complex_setXAxisScale(plot_complex_t *h, plot_complex_id_t id, double xMin, double xMax);
LIBLTE_API void plot_complex_setYAxisScale(plot_complex_t *h, plot_complex_id_t id, double yMin, double yMax);
LIBLTE_API void plot_complex_setXAxisRange(plot_complex_t *h, double xMin, double xMax);
#ifdef __cplusplus
}

@ -34,19 +34,20 @@ extern "C" {
#endif
#include <stdbool.h>
#include "lte/config.h"
typedef void* plot_real_t;
int plot_real_init(plot_real_t *h);
void plot_real_setTitle(plot_real_t *h, char *title);
void plot_real_setNewData(plot_real_t *h, float *data,
int num_points);
void plot_real_setXAxisAutoScale(plot_real_t *h, bool on);
void plot_real_setYAxisAutoScale(plot_real_t *h, bool on);
void plot_real_setXAxisScale(plot_real_t *h, double xMin, double xMax);
void plot_real_setYAxisScale(plot_real_t *h, double yMin, double yMax);
void plot_real_setXAxisRange(plot_real_t *h, double xMin, double xMax);
void plot_real_setLabels(plot_real_t *h, char *xLabel, char *yLabel);
LIBLTE_API int plot_real_init(plot_real_t *h);
LIBLTE_API void plot_real_setTitle(plot_real_t *h, char *title);
LIBLTE_API void plot_real_setNewData(plot_real_t *h, float *data,
int num_points);
LIBLTE_API void plot_real_setXAxisAutoScale(plot_real_t *h, bool on);
LIBLTE_API void plot_real_setYAxisAutoScale(plot_real_t *h, bool on);
LIBLTE_API void plot_real_setXAxisScale(plot_real_t *h, double xMin, double xMax);
LIBLTE_API void plot_real_setYAxisScale(plot_real_t *h, double yMin, double yMax);
LIBLTE_API void plot_real_setXAxisRange(plot_real_t *h, double xMin, double xMax);
LIBLTE_API void plot_real_setLabels(plot_real_t *h, char *xLabel, char *yLabel);
#ifdef __cplusplus
}

@ -34,18 +34,19 @@ extern "C" {
#endif
#include <stdbool.h>
#include "lte/config.h"
typedef void* plot_scatter_t;
int plot_scatter_init(plot_scatter_t *h);
void plot_scatter_setTitle(plot_scatter_t *h, char *title);
void plot_scatter_setNewData(plot_scatter_t *h, _Complex float *data,
int num_points);
void plot_scatter_setXAxisAutoScale(plot_scatter_t *h, bool on);
void plot_scatter_setYAxisAutoScale(plot_scatter_t *h, bool on);
void plot_scatter_setXAxisScale(plot_scatter_t *h, double xMin, double xMax);
void plot_scatter_setYAxisScale(plot_scatter_t *h, double yMin, double yMax);
void plot_scatter_setAxisLabels(plot_scatter_t *h, char *xLabel, char *yLabel);
LIBLTE_API int plot_scatter_init(plot_scatter_t *h);
LIBLTE_API void plot_scatter_setTitle(plot_scatter_t *h, char *title);
LIBLTE_API void plot_scatter_setNewData(plot_scatter_t *h, _Complex float *data,
int num_points);
LIBLTE_API void plot_scatter_setXAxisAutoScale(plot_scatter_t *h, bool on);
LIBLTE_API void plot_scatter_setYAxisAutoScale(plot_scatter_t *h, bool on);
LIBLTE_API void plot_scatter_setXAxisScale(plot_scatter_t *h, double xMin, double xMax);
LIBLTE_API void plot_scatter_setYAxisScale(plot_scatter_t *h, double yMin, double yMax);
LIBLTE_API void plot_scatter_setAxisLabels(plot_scatter_t *h, char *xLabel, char *yLabel);
#ifdef __cplusplus
}

@ -34,24 +34,25 @@ extern "C" {
#endif
#include <stdbool.h>
#include "lte/config.h"
typedef void* plot_waterfall_t;
int plot_waterfall_init(plot_waterfall_t *h);
void plot_waterfall_setTitle(plot_waterfall_t *h, char *title);
void plot_waterfall_appendNewData(plot_waterfall_t *h, float *data,
int num_points);
void plot_complex_setPlotXLabel(plot_waterfall_t *h, char *xLabel);
void plot_complex_setPlotYLabel(plot_waterfall_t *h, char *yLabel);
void plot_waterfall_setPlotXAxisRange(plot_waterfall_t *h, double xMin, double xMax);
void plot_waterfall_setPlotXAxisScale(plot_waterfall_t *h, double xMin, double xMax);
void plot_waterfall_setPlotYAxisScale(plot_waterfall_t *h, double yMin, double yMax);
void plot_waterfall_setSpectrogramXLabel(plot_waterfall_t *h, char* xLabel);
void plot_waterfall_setSpectrogramYLabel(plot_waterfall_t *h, char* yLabel);
void plot_waterfall_setSpectrogramXAxisRange(plot_waterfall_t *h, double xMin, double xMax);
void plot_waterfall_setSpectrogramYAxisRange(plot_waterfall_t *h, double yMin, double yMax);
void plot_waterfall_setSpectrogramZAxisScale(plot_waterfall_t *h, double zMin, double zMax);
LIBLTE_API int plot_waterfall_init(plot_waterfall_t *h);
LIBLTE_API void plot_waterfall_setTitle(plot_waterfall_t *h, char *title);
LIBLTE_API void plot_waterfall_appendNewData(plot_waterfall_t *h, float *data,
int num_points);
LIBLTE_API void plot_complex_setPlotXLabel(plot_waterfall_t *h, char *xLabel);
LIBLTE_API void plot_complex_setPlotYLabel(plot_waterfall_t *h, char *yLabel);
LIBLTE_API void plot_waterfall_setPlotXAxisRange(plot_waterfall_t *h, double xMin, double xMax);
LIBLTE_API void plot_waterfall_setPlotXAxisScale(plot_waterfall_t *h, double xMin, double xMax);
LIBLTE_API void plot_waterfall_setPlotYAxisScale(plot_waterfall_t *h, double yMin, double yMax);
LIBLTE_API void plot_waterfall_setSpectrogramXLabel(plot_waterfall_t *h, char* xLabel);
LIBLTE_API void plot_waterfall_setSpectrogramYLabel(plot_waterfall_t *h, char* yLabel);
LIBLTE_API void plot_waterfall_setSpectrogramXAxisRange(plot_waterfall_t *h, double xMin, double xMax);
LIBLTE_API void plot_waterfall_setSpectrogramYAxisRange(plot_waterfall_t *h, double yMin, double yMax);
LIBLTE_API void plot_waterfall_setSpectrogramZAxisScale(plot_waterfall_t *h, double zMin, double zMax);
#ifdef __cplusplus

@ -67,7 +67,7 @@ IF(QT4_FOUND AND QWT_FOUND AND QWT_MAJOR_VERSION EQUAL 6)
INCLUDE_DIRECTORIES(common complexplot realplot scatterplot waterfallplot ${Boost_INCLUDE_DIRS})
ADD_LIBRARY(graphics ${eventwraps} ${lineplotwraps} ${pointplotwraps} ${spectrogramplotwraps} ${complex} ${real} ${scatter} ${waterfall} ${SOURCES_ALL} )
ADD_LIBRARY(graphics SHARED ${eventwraps} ${lineplotwraps} ${pointplotwraps} ${spectrogramplotwraps} ${complex} ${real} ${scatter} ${waterfall} ${SOURCES_ALL} )
TARGET_LINK_LIBRARIES(graphics pthread ${QT_LIBRARIES} ${QWT_LIBRARIES})
INSTALL(TARGETS graphics DESTINATION ${LIBRARY_DIR})
LIBLTE_SET_PIC(graphics)
@ -75,10 +75,10 @@ IF(QT4_FOUND AND QWT_FOUND AND QWT_MAJOR_VERSION EQUAL 6)
APPEND_INTERNAL_LIST(OPTIONAL_LIBS graphics)
ADD_SUBDIRECTORY(complexplot/test)
ADD_SUBDIRECTORY(realplot/test)
ADD_SUBDIRECTORY(scatterplot/test)
ADD_SUBDIRECTORY(waterfallplot/test)
#ADD_SUBDIRECTORY(complexplot/test)
#ADD_SUBDIRECTORY(realplot/test)
#ADD_SUBDIRECTORY(scatterplot/test)
#ADD_SUBDIRECTORY(waterfallplot/test)
MESSAGE(STATUS " GRAPHICS library will be installed.")

@ -33,8 +33,6 @@
#include "Lineplot.h"
#include "qwt_scale_div.h"
#include "qwt_plot_canvas.h"
#include <algorithm>
class MyZoomer: public QwtPlotZoomer
@ -96,8 +94,7 @@ Lineplot::Lineplot(QWidget *parent)
axisScaleEngine(QwtPlot::yLeft)->setAttribute(QwtScaleEngine::Floating,true);
axisScaleEngine(QwtPlot::yRight)->setAttribute(QwtScaleEngine::Floating,true);
QwtPlotCanvas *mycanvas = qobject_cast<QwtPlotCanvas*>(canvas());
zoomer_ = new MyZoomer(mycanvas);
zoomer_ = new MyZoomer(qobject_cast<QwtPlotCanvas*>(canvas()));
zoomer_->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
zoomer_->setMousePattern(QwtEventPattern::MouseSelect2, Qt::LeftButton,
Qt::ControlModifier);
@ -163,5 +160,9 @@ void Lineplot::resetZoom()
void Lineplot::linkScales()
{
// setAxisScaleDiv(QwtPlot::yRight, *axisScaleDiv(QwtPlot::yLeft));
#if QWT_VERSION < 0x060100
setAxisScaleDiv(QwtPlot::yRight, *axisScaleDiv(QwtPlot::yLeft));
#else // QWT_VERSION < 0x060100
setAxisScaleDiv(QwtPlot::yRight, axisScaleDiv(QwtPlot::yLeft));
#endif // QWT_VERSION < 0x060100
}

@ -32,7 +32,6 @@
*/
#include "Pointplot.h"
#include "qwt_plot_canvas.h"
#include <algorithm>
using namespace std;
@ -84,8 +83,7 @@ Pointplot::Pointplot(QWidget *parent)
memset(realPoints_, 0x0, numPoints_*sizeof(double));
memset(imagPoints_, 0x0, numPoints_*sizeof(double));
QwtPlotCanvas *mycanvas = qobject_cast<QwtPlotCanvas*>(canvas());
zoomer_ = new MyZoomer(mycanvas);
zoomer_ = new MyZoomer(qobject_cast<QwtPlotCanvas*>(canvas()));
zoomer_->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
zoomer_->setMousePattern(QwtEventPattern::MouseSelect2, Qt::LeftButton,
Qt::ControlModifier);

@ -117,8 +117,7 @@ Spectrogramplot::Spectrogramplot(int numDataPoints, int numRows, QWidget *parent
// RightButton: zoom out by 1
// Ctrl+RighButton: zoom out to full size
QwtPlotCanvas *mycanvas = qobject_cast<QwtPlotCanvas*>(canvas());
zoomer_ = new MyZoomer(mycanvas);
zoomer_ = new MyZoomer(qobject_cast<QwtPlotCanvas*>(canvas()));
zoomer_->setMousePattern(QwtEventPattern::MouseSelect1,
Qt::LeftButton);
zoomer_->setMousePattern(QwtEventPattern::MouseSelect2,

@ -61,5 +61,6 @@ void plot_exit() {
if (plot_initiated) {
pthread_cancel(thread);
}
plot_initiated=0;
}

@ -3,10 +3,11 @@
#include <string>
#include <complex>
#include "lte/config.h"
class ScatterplotWrapper;
class Scatterplot
class LIBLTE_API Scatterplot
{
public:
Scatterplot();
@ -28,7 +29,7 @@ private:
};
template<class Iterator>
void Scatterplot::setNewData(Iterator begin, Iterator end)
LIBLTE_API void Scatterplot::setNewData(Iterator begin, Iterator end)
{
int numPoints = end-begin;
std::complex<double>* data = new std::complex<double>[numPoints];

@ -22,15 +22,17 @@
########################################################################
# Add headers to cmake project (useful for IDEs)
########################################################################
FILE(GLOB headers *)
SET(HEADERS_ALL "")
FILE(GLOB_RECURSE tmp "*.h")
LIST(APPEND HEADERS_ALL ${tmp})
FILE(GLOB headers *)
FOREACH (_header ${headers})
IF(IS_DIRECTORY ${_header})
FILE(GLOB_RECURSE tmp "${_header}/*.h")
LIST(APPEND HEADERS_ALL ${tmp})
ENDIF(IS_DIRECTORY ${_header})
ENDFOREACH()
ADD_CUSTOM_TARGET (add_headers SOURCES ${HEADERS_ALL})
ADD_CUSTOM_TARGET (add_lte_headers SOURCES ${HEADERS_ALL})

@ -32,6 +32,12 @@
#ifndef _LTE_
#define _LTE_
#ifdef __cplusplus
extern "C" {
#endif
#include "lte/config.h"
#include "lte/utils/bit.h"
#include "lte/utils/convolution.h"
#include "lte/utils/debug.h"
@ -94,4 +100,8 @@
#include "lte/sync/sync.h"
#include "lte/sync/cfo.h"
#ifdef __cplusplus
}
#endif
#endif

@ -32,6 +32,7 @@
#include <stdio.h>
#include "lte/config.h"
#include "lte/ch_estimation/refsignal.h"
#include "lte/filter/filter2d.h"
#include "lte/common/base.h"
@ -49,58 +50,58 @@ typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, in
*/
/* Low-level API */
typedef struct {
int nof_ports;
int nof_symbols;
int nof_prb;
lte_cp_t cp;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interpolate_fnc_t interp;
typedef struct LIBLTE_API{
int nof_ports;
int nof_symbols;
int nof_prb;
lte_cp_t cp;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interpolate_fnc_t interp;
}chest_t;
int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports);
void chest_free(chest_t *q);
LIBLTE_API int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports);
LIBLTE_API 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);
LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, int port, int nslot, int cell_id);
LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id);
LIBLTE_API 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);
LIBLTE_API void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref);
LIBLTE_API void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_id);
LIBLTE_API 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]);
LIBLTE_API void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
LIBLTE_API void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
LIBLTE_API void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
LIBLTE_API void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id);
LIBLTE_API 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 nof_ports;
int nof_prb;
int cell_id; // set to -1 to init at runtime
} init;
cf_t *input;
int in_len;
struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame
int cell_id;
} ctrl_in;
cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS];
typedef struct LIBLTE_API{
chest_t obj;
struct chest_init {
int nof_symbols; // 7 for normal cp, 6 for extended
int nof_ports;
int nof_prb;
int cell_id; // set to -1 to init at runtime
} init;
cf_t *input;
int in_len;
struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame
int cell_id;
} ctrl_in;
cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS];
}chest_hl;
#define DEFAULT_FRAME_SIZE 2048
#define DEFAULT_FRAME_SIZE 2048
int chest_initialize(chest_hl* h);
int chest_work(chest_hl* hl);
int chest_stop(chest_hl* hl);
LIBLTE_API int chest_initialize(chest_hl* h);
LIBLTE_API int chest_work(chest_hl* hl);
LIBLTE_API int chest_stop(chest_hl* hl);
#endif

@ -37,31 +37,32 @@
*
*/
#include "lte/config.h"
#include "lte/common/base.h"
typedef _Complex float cf_t;
typedef struct {
int time_idx;
int freq_idx;
cf_t simbol;
cf_t recv_simbol;
typedef struct LIBLTE_API{
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
int nof_prb;
ref_t *refs;
cf_t *ch_est;
typedef struct LIBLTE_API{
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
int nof_prb;
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);
LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot,
int cell_id, lte_cp_t cp, int nof_prb);
LIBLTE_API void refsignal_free(refsignal_t *q);
void refsignal_put(refsignal_t *q, cf_t *slot_symbols);
LIBLTE_API void refsignal_put(refsignal_t *q, cf_t *slot_symbols);
#endif

@ -27,30 +27,31 @@
#include <complex.h>
#include "lte/config.h"
#ifndef CH_AWGN_
#define CH_AWGN_
typedef _Complex float cf_t;
void ch_awgn_c(const cf_t* input, cf_t* output, float variance, int buff_sz);
void ch_awgn_f(const float* x, float* y, float variance, int buff_sz);
LIBLTE_API void ch_awgn_c(const cf_t* input, cf_t* output, float variance, int buff_sz);
LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, int buff_sz);
/* High-level API */
typedef struct {
const cf_t* input;
int in_len;
struct ch_awgn_ctrl_in {
float variance; // Noise variance
} ctrl_in;
typedef struct LIBLTE_API{
const cf_t* input;
int in_len;
struct ch_awgn_ctrl_in {
float variance; // Noise variance
} ctrl_in;
cf_t* output;
int out_len;
cf_t* output;
int out_len;
}ch_awgn_hl;
int ch_awgn_initialize(ch_awgn_hl* hl);
int ch_awgn_work(ch_awgn_hl* hl);
int ch_awgn_stop(ch_awgn_hl* hl);
LIBLTE_API int ch_awgn_initialize(ch_awgn_hl* hl);
LIBLTE_API int ch_awgn_work(ch_awgn_hl* hl);
LIBLTE_API int ch_awgn_stop(ch_awgn_hl* hl);
#endif

@ -29,42 +29,44 @@
#ifndef _LTEBASE_
#define _LTEBASE_
#define NSUBFRAMES_X_FRAME 10
#include "lte/config.h"
#define NSUBFRAMES_X_FRAME 10
#define NSLOTS_X_FRAME (2*NSUBFRAMES_X_FRAME)
#define LTE_NSOFT_BITS 250368 // Soft buffer size for Category 1 UE
#define LTE_NSOFT_BITS 250368 // Soft buffer size for Category 1 UE
#define LTE_NULL_BIT 0
#define LTE_NULL_SYMBOL 2
#define LTE_NIL_SYMBOL 2
#define LTE_NULL_BIT 0
#define LTE_NULL_SYMBOL 2
#define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
#define LTE_CRC24A 0x1864CFB
#define LTE_CRC24B 0X1800063
#define LTE_CRC16 0x11021
#define LTE_CRC8 0x19B
typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define SIRNTI 0xFFFF
#define PRNTI 0xFFFE
#define MRNTI 0xFFFD
#define MAX_NSYMB 7
#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 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 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)
@ -87,50 +89,50 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx)
#define MAX_PRB 110
#define RE_X_RB 12
#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 GUARD_RE(nof_prb) ((lte_symbol_sz(nof_prb)-nof_prb*RE_X_RB)/2)
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);
LIBLTE_API const int lte_symbol_sz(int nof_prb);
LIBLTE_API int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols);
LIBLTE_API int lte_voffset(int symbol_id, int cell_id, int nof_ports);
#define NOF_LTE_BANDS 29
#define NOF_LTE_BANDS 29
#define NOF_TC_CB_SIZES 188
typedef enum {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
typedef enum LIBLTE_API {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
} lte_mimo_type_t;
typedef enum { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef struct {
int id;
float fd;
typedef struct LIBLTE_API {
int id;
float fd;
}lte_earfcn_t;
enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
LIBLTE_API enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
};
int lte_cb_size(int index);
int lte_find_cb_index(int long_cb);
LIBLTE_API int lte_cb_size(int index);
LIBLTE_API int lte_find_cb_index(int long_cb);
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);
LIBLTE_API float lte_band_fd(int earfcn);
LIBLTE_API int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int earfcn_start, int earfcn_end, int max_elems);
LIBLTE_API int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_nelems);
LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems);
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
char *lte_mimotype2str(lte_mimo_type_t type);
LIBLTE_API int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
LIBLTE_API char *lte_mimotype2str(lte_mimo_type_t type);
#endif

@ -33,28 +33,29 @@
#include <strings.h>
#include <stdlib.h>
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/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;
int nof_guards;
int nof_re;
lte_cp_t cp_type;
cf_t *tmp; // for removing zero padding
typedef struct LIBLTE_API{
dft_plan_t fft_plan;
int nof_symbols;
int symbol_sz;
int nof_guards;
int nof_re;
lte_cp_t cp_type;
cf_t *tmp; // for removing zero padding
}lte_fft_t;
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);
void lte_fft_free(lte_fft_t *q);
void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output);
LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);
LIBLTE_API void lte_fft_free(lte_fft_t *q);
LIBLTE_API 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 nof_prb);
void lte_ifft_free(lte_fft_t *q);
void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output);
LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);
LIBLTE_API void lte_ifft_free(lte_fft_t *q);
LIBLTE_API void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output);
#endif

@ -25,26 +25,26 @@
*
*/
#ifndef LTESEQ_
#define LTESEQ_
#include "lte/common/base.h"
typedef struct {
char *c;
int len;
}sequence_t;
typedef struct LIBLTE_API {
char *c;
int len;
} sequence_t;
int sequence_init(sequence_t *q, int len);
void sequence_free(sequence_t *q);
LIBLTE_API int sequence_init(sequence_t *q, int len);
LIBLTE_API void sequence_free(sequence_t *q);
int sequence_LTEPRS(sequence_t *q, int len, int seed);
LIBLTE_API 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_pcfich(sequence_t *seq, int nslot, int cell_id);
int sequence_phich(sequence_t *seq, int nslot, int cell_id);
int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len);
int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, int nslot, int cell_id, int len);
LIBLTE_API int sequence_pbch(sequence_t *seq, lte_cp_t cp, int cell_id);
LIBLTE_API int sequence_pcfich(sequence_t *seq, int nslot, int cell_id);
LIBLTE_API int sequence_phich(sequence_t *seq, int nslot, int cell_id);
LIBLTE_API int sequence_pdcch(sequence_t *seq, int nslot, int cell_id, int len);
LIBLTE_API int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q,
int nslot, int cell_id, int len);
#endif

@ -0,0 +1,55 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef CONFIG_H
#define CONFIG_H
// Generic helper definitions for shared library support
#if defined _WIN32 || defined __CYGWIN__
#define LIBLTE_IMPORT __declspec(dllimport)
#define LIBLTE_EXPORT __declspec(dllexport)
#define LIBLTE_LOCAL
#else
#if __GNUC__ >= 4
#define LIBLTE_IMPORT __attribute__ ((visibility ("default")))
#define LIBLTE_EXPORT __attribute__ ((visibility ("default")))
#else
#define LIBLTE_IMPORT
#define LIBLTE_EXPORT
#define LIBLTE_LOCAL
#endif
#endif
// Define LIBLTE_API
// LIBLTE_API is used for the public API symbols.
#ifdef LIBLTE_DLL_EXPORTS // defined if we are building the LIBLTE DLL (instead of using it)
#define LIBLTE_API LIBLTE_EXPORT
#else
#define LIBLTE_API LIBLTE_IMPORT
#endif
#endif // CONFIG_H

@ -31,39 +31,38 @@
#define CONVCODER_
#include <stdbool.h>
#include "lte/config.h"
typedef struct {
int R;
int K;
int poly[3];
bool tail_biting;
typedef struct LIBLTE_API {
int R;
int K;
int poly[3];
bool tail_biting;
}convcoder_t;
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length);
LIBLTE_API int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length);
/* High-level API */
typedef struct {
convcoder_t obj;
struct convcoder_ctrl_in {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} ctrl_in;
char *input;
int in_len;
char *output;
int out_len;
typedef struct LIBLTE_API {
convcoder_t obj;
struct convcoder_ctrl_in {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} ctrl_in;
char *input;
int in_len;
char *output;
int out_len;
}convcoder_hl;
int convcoder_initialize(convcoder_hl* h);
int convcoder_work(convcoder_hl* hl);
int convcoder_stop(convcoder_hl* h);
LIBLTE_API int convcoder_initialize(convcoder_hl* h);
LIBLTE_API int convcoder_work(convcoder_hl* hl);
LIBLTE_API int convcoder_stop(convcoder_hl* h);
#endif

@ -29,20 +29,22 @@
#ifndef CRC_
#define CRC_
typedef struct {
unsigned long table[256];
unsigned char byte;
int polynom;
int order;
unsigned long crcinit;
unsigned long crcmask;
unsigned long crchighbit;
unsigned int crc_out;
#include "lte/config.h"
typedef struct LIBLTE_API {
unsigned long table[256];
unsigned char byte;
int polynom;
int order;
unsigned long crcinit;
unsigned long crcmask;
unsigned long crchighbit;
unsigned int crc_out;
} crc_t;
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
int crc_set_init(crc_t *h, unsigned long crc_init_value);
void crc_attach(crc_t *h, char *data, int len);
unsigned int crc_checksum(crc_t *h, char *data, int len);
LIBLTE_API int crc_init(crc_t *h, unsigned int crc_poly, int crc_order);
LIBLTE_API int crc_set_init(crc_t *h, unsigned long crc_init_value);
LIBLTE_API void crc_attach(crc_t *h, char *data, int len);
LIBLTE_API unsigned int crc_checksum(crc_t *h, char *data, int len);
#endif

@ -25,35 +25,35 @@
*
*/
#ifndef RM_CONV_
#define RM_CONV_
#include "lte/config.h"
#define RX_NULL 10000
#define TX_NULL 80
int rm_conv_tx(char *input, int in_len, char *output, int out_len);
int rm_conv_rx(float *input, int in_len, float *output, int out_len);
LIBLTE_API int rm_conv_tx(char *input, int in_len, char *output, int out_len);
LIBLTE_API int rm_conv_rx(float *input, int in_len, float *output, 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);
typedef struct
LIBLTE_API {
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;
LIBLTE_API int rm_conv_initialize(rm_conv_hl* h);
LIBLTE_API int rm_conv_work(rm_conv_hl* hl);
LIBLTE_API int rm_conv_stop(rm_conv_hl* hl);
#endif

@ -25,7 +25,6 @@
*
*/
#ifndef RM_TURBO_
#define RM_TURBO_
@ -37,36 +36,39 @@
#define TX_NULL 100
#endif
typedef struct {
int buffer_len;
char *buffer;
} rm_turbo_t;
#include "lte/config.h"
int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len);
void rm_turbo_free(rm_turbo_t *q);
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx);
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx);
typedef struct LIBLTE_API {
int buffer_len;
char *buffer;
} rm_turbo_t;
LIBLTE_API int rm_turbo_init(rm_turbo_t *q, int max_codeblock_len);
LIBLTE_API void rm_turbo_free(rm_turbo_t *q);
LIBLTE_API int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
int out_len, int rv_idx);
LIBLTE_API int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len,
float *output, int out_len, int rv_idx);
/* High-level API */
typedef struct {
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;
int S;
int rv_idx;
} ctrl_in;
void *output;
int out_len;
}rm_turbo_hl;
typedef struct LIBLTE_API {
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;
void *input; // input type may be char or float depending on hard
int in_len;
struct rm_turbo_ctrl_in {
int E;
int S;
int rv_idx;
} ctrl_in;
void *output;
int out_len;
} rm_turbo_hl;
int rm_turbo_initialize(rm_turbo_hl* h);
int rm_turbo_work(rm_turbo_hl* hl);
int rm_turbo_stop(rm_turbo_hl* hl);
LIBLTE_API int rm_turbo_initialize(rm_turbo_hl* h);
LIBLTE_API int rm_turbo_work(rm_turbo_hl* hl);
LIBLTE_API int rm_turbo_stop(rm_turbo_hl* hl);
#endif

@ -28,16 +28,18 @@
#ifndef _TC_INTERL_H
#define _TC_INTERL_H
typedef struct {
int *forward;
int *reverse;
int max_long_cb;
}tc_interl_t;
#include "lte/config.h"
int tc_interl_LTE_gen(tc_interl_t *h, int long_cb);
int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb);
typedef struct LIBLTE_API {
int *forward;
int *reverse;
int max_long_cb;
} tc_interl_t;
int tc_interl_init(tc_interl_t *h, int max_long_cb);
void tc_interl_free(tc_interl_t *h);
LIBLTE_API int tc_interl_LTE_gen(tc_interl_t *h, int long_cb);
LIBLTE_API int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb);
LIBLTE_API int tc_interl_init(tc_interl_t *h, int max_long_cb);
LIBLTE_API void tc_interl_free(tc_interl_t *h);
#endif

@ -29,21 +29,21 @@
#define TURBOCODER_
#include "lte/fec/tc_interl.h"
#include "lte/config.h"
#define NUMREGS 3
#define RATE 3
#define TOTALTAIL 12
typedef struct {
int max_long_cb;
tc_interl_t interl;
typedef struct LIBLTE_API {
int max_long_cb;
tc_interl_t interl;
} tcod_t;
}tcod_t;
int tcod_init(tcod_t *h, int max_long_cb);
void tcod_free(tcod_t *h);
int tcod_encode(tcod_t *h, char *input, char *output, int long_cb);
LIBLTE_API int tcod_init(tcod_t *h, int max_long_cb);
LIBLTE_API void tcod_free(tcod_t *h);
LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, int long_cb);
#endif

@ -29,6 +29,7 @@
#define TURBODECODER_
#include "lte/fec/tc_interl.h"
#include "lte/config.h"
#define RATE 3
#define TOTALTAIL 12
@ -48,31 +49,32 @@
typedef float llr_t;
typedef struct {
int max_long_cb;
llr_t *beta;
}map_gen_t;
typedef struct LIBLTE_API {
int max_long_cb;
llr_t *beta;
} map_gen_t;
typedef struct {
int max_long_cb;
typedef struct LIBLTE_API {
int max_long_cb;
map_gen_t dec;
map_gen_t dec;
llr_t *llr1;
llr_t *llr2;
llr_t *w;
llr_t *syst;
llr_t *parity;
llr_t *llr1;
llr_t *llr2;
llr_t *w;
llr_t *syst;
llr_t *parity;
tc_interl_t interleaver;
}tdec_t;
tc_interl_t interleaver;
} tdec_t;
int tdec_init(tdec_t *h, int max_long_cb);
void tdec_free(tdec_t *h);
LIBLTE_API int tdec_init(tdec_t *h, int max_long_cb);
LIBLTE_API void tdec_free(tdec_t *h);
int tdec_reset(tdec_t *h, int long_cb);
void tdec_iteration(tdec_t *h, llr_t *input, int long_cb);
void tdec_decision(tdec_t *h, char *output, int long_cb);
void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations, int long_cb);
LIBLTE_API int tdec_reset(tdec_t *h, int long_cb);
LIBLTE_API void tdec_iteration(tdec_t *h, llr_t *input, int long_cb);
LIBLTE_API void tdec_decision(tdec_t *h, char *output, int long_cb);
LIBLTE_API void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations,
int long_cb);
#endif

@ -30,50 +30,51 @@
#define VITERBI_
#include <stdbool.h>
#include "lte/config.h"
typedef enum {
viterbi_27, viterbi_29, viterbi_37, viterbi_39
viterbi_27, viterbi_29, viterbi_37, viterbi_39
}viterbi_type_t;
typedef struct {
void *ptr;
int R;
int K;
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
typedef struct LIBLTE_API{
void *ptr;
int R;
int K;
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*, int);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
}viterbi_t;
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
void viterbi_free(viterbi_t *q);
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length);
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length);
LIBLTE_API int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
LIBLTE_API void viterbi_free(viterbi_t *q);
LIBLTE_API int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length);
LIBLTE_API int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data, int frame_length);
/* High-level API */
typedef struct {
viterbi_t obj;
struct viterbi_init {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} init;
float *input;
int in_len;
char *output;
int out_len;
typedef struct LIBLTE_API{
viterbi_t obj;
struct viterbi_init {
int rate;
int constraint_length;
int tail_bitting;
int generator_0;
int generator_1;
int generator_2;
int frame_length;
} init;
float *input;
int in_len;
char *output;
int out_len;
}viterbi_hl;
int viterbi_initialize(viterbi_hl* h);
int viterbi_work(viterbi_hl* hl);
int viterbi_stop(viterbi_hl* h);
LIBLTE_API int viterbi_initialize(viterbi_hl* h);
LIBLTE_API int viterbi_work(viterbi_hl* hl);
LIBLTE_API int viterbi_stop(viterbi_hl* h);
#endif

@ -30,24 +30,26 @@
#ifndef FILTER2D_
#define FILTER2D_
#include "lte/config.h"
/* 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
typedef struct LIBLTE_API{
int sztime; // Output signal size in the time domain
int szfreq; // Output signal size in the freq domain
int ntime; // 2-D Filter size in time domain
int nfreq; // 2-D Filter size in frequency domain
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);
LIBLTE_API int filter2d_init (filter2d_t* q, float **taps, int ntime, int nfreq, int sztime, int szfreq);
LIBLTE_API int filter2d_init_default (filter2d_t* q, int ntime, int nfreq, int sztime, int szfreq);
LIBLTE_API void filter2d_free(filter2d_t *q);
LIBLTE_API void filter2d_reset(filter2d_t *q);
LIBLTE_API void filter2d_add(filter2d_t *q, cf_t h, int time_idx, int freq_idx);
#endif
#endif // FILTER2D_

@ -31,40 +31,41 @@
#include <stdint.h>
#include "lte/config.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;
typedef struct LIBLTE_API{
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);
LIBLTE_API void binsource_init(binsource_t* q);
LIBLTE_API void binsource_free(binsource_t* q);
LIBLTE_API void binsource_seed_set(binsource_t* q, unsigned int seed);
LIBLTE_API void binsource_seed_time(binsource_t *q);
LIBLTE_API int binsource_cache_gen(binsource_t* q, int nbits);
LIBLTE_API void binsource_cache_cpy(binsource_t* q, char *bits, int nbits);
LIBLTE_API int binsource_generate(binsource_t* q, char *bits, int nbits);
/* 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;
typedef struct LIBLTE_API {
binsource_t obj;
struct binsource_init {
int cache_seq_nbits; // If non-zero, generates random bits on init
unsigned int seed; // If non-zero, uses as random seed, otherwise local time is used.
} 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);
LIBLTE_API int binsource_initialize(binsource_hl* h);
LIBLTE_API int binsource_work( binsource_hl* hl);
LIBLTE_API int binsource_stop(binsource_hl* hl);
#endif
#endif // BINSOURCE_

@ -32,34 +32,35 @@
#include <stdint.h>
#include <stdlib.h>
#include "lte/config.h"
#include "lte/io/format.h"
/* Low-level API */
typedef struct {
FILE *f;
data_type_t type;
typedef struct LIBLTE_API {
FILE *f;
data_type_t type;
}filesink_t;
int filesink_init(filesink_t *q, char *filename, data_type_t type);
void filesink_free(filesink_t *q);
LIBLTE_API int filesink_init(filesink_t *q, char *filename, data_type_t type);
LIBLTE_API void filesink_free(filesink_t *q);
int filesink_write(filesink_t *q, void *buffer, int nsamples);
LIBLTE_API 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;
typedef struct LIBLTE_API {
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);
LIBLTE_API int filesink_initialize(filesink_hl* h);
LIBLTE_API int filesink_work( filesink_hl* hl);
LIBLTE_API int filesink_stop(filesink_hl* h);
#endif
#endif // FILESINK_

@ -32,38 +32,39 @@
#include <stdint.h>
#include <stdlib.h>
#include "lte/config.h"
#include "lte/io/format.h"
/* Low-level API */
typedef struct {
FILE *f;
data_type_t type;
typedef struct LIBLTE_API {
FILE *f;
data_type_t type;
}filesource_t;
int filesource_init(filesource_t *q, char *filename, data_type_t type);
void filesource_free(filesource_t *q);
LIBLTE_API int filesource_init(filesource_t *q, char *filename, data_type_t type);
LIBLTE_API void filesource_free(filesource_t *q);
void filesource_seek(filesource_t *q, int pos);
int filesource_read(filesource_t *q, void *buffer, int nsamples);
LIBLTE_API void filesource_seek(filesource_t *q, int pos);
LIBLTE_API 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;
typedef struct LIBLTE_API {
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);
LIBLTE_API int filesource_initialize(filesource_hl* h);
LIBLTE_API int filesource_work( filesource_hl* hl);
LIBLTE_API int filesource_stop(filesource_hl* h);
#endif
#endif // FILESOURCE_

@ -31,4 +31,4 @@
typedef enum { FLOAT, COMPLEX_FLOAT, COMPLEX_SHORT, FLOAT_BIN, COMPLEX_FLOAT_BIN, COMPLEX_SHORT_BIN} data_type_t;
#endif
#endif // FORMAT_

@ -26,8 +26,8 @@
*/
#ifndef udpsink_
#define udpsink_
#ifndef UDPSINK_
#define UDPSINK_
#include <sys/socket.h>
#include <netinet/in.h>
@ -35,36 +35,37 @@
#include <stdint.h>
#include <stdlib.h>
#include "lte/config.h"
#include "lte/io/format.h"
/* Low-level API */
typedef struct {
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
typedef struct LIBLTE_API {
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
}udpsink_t;
int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type);
void udpsink_free(udpsink_t *q);
LIBLTE_API int udpsink_init(udpsink_t *q, char *address, int port, data_type_t type);
LIBLTE_API void udpsink_free(udpsink_t *q);
int udpsink_write(udpsink_t *q, void *buffer, int nsamples);
LIBLTE_API int udpsink_write(udpsink_t *q, void *buffer, int nsamples);
/* High-level API */
typedef struct {
udpsink_t obj;
struct udpsink_init {
char *address;
int port;
int block_length;
int data_type;
} init;
void* input;
int in_len;
typedef struct LIBLTE_API {
udpsink_t obj;
struct udpsink_init {
char *address;
int port;
int block_length;
int data_type;
} init;
void* input;
int in_len;
}udpsink_hl;
int udpsink_initialize(udpsink_hl* h);
int udpsink_work( udpsink_hl* hl);
int udpsink_stop(udpsink_hl* h);
LIBLTE_API int udpsink_initialize(udpsink_hl* h);
LIBLTE_API int udpsink_work( udpsink_hl* hl);
LIBLTE_API int udpsink_stop(udpsink_hl* h);
#endif
#endif // UDPSINK_

@ -26,8 +26,8 @@
*/
#ifndef udpsource_
#define udpsource_
#ifndef UDPSOURCE_
#define UDPSOURCE_
#include <sys/socket.h>
@ -36,38 +36,39 @@
#include <stdint.h>
#include <stdlib.h>
#include "lte/config.h"
#include "lte/io/format.h"
/* Low-level API */
typedef struct {
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
typedef struct LIBLTE_API {
int sockfd;
struct sockaddr_in servaddr;
data_type_t type;
}udpsource_t;
int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type);
void udpsource_free(udpsource_t *q);
LIBLTE_API int udpsource_init(udpsource_t *q, char *address, int port, data_type_t type);
LIBLTE_API void udpsource_free(udpsource_t *q);
int udpsource_read(udpsource_t *q, void *buffer, int nsamples);
LIBLTE_API int udpsource_read(udpsource_t *q, void *buffer, int nsamples);
/* High-level API */
typedef struct {
udpsource_t obj;
struct udpsource_init {
char *address;
int port;
int data_type;
} init;
struct udpsource_ctrl_in {
int nsamples; // Number of samples to read
} ctrl_in;
void* output;
int out_len;
typedef struct LIBLTE_API {
udpsource_t obj;
struct udpsource_init {
char *address;
int port;
int data_type;
} init;
struct udpsource_ctrl_in {
int nsamples; // Number of samples to read
} ctrl_in;
void* output;
int out_len;
}udpsource_hl;
int udpsource_initialize(udpsource_hl* h);
int udpsource_work( udpsource_hl* hl);
int udpsource_stop(udpsource_hl* h);
LIBLTE_API int udpsource_initialize(udpsource_hl* h);
LIBLTE_API int udpsource_work( udpsource_hl* hl);
LIBLTE_API int udpsource_stop(udpsource_hl* h);
#endif
#endif // UDPSOURCE_

@ -29,25 +29,27 @@
#ifndef LAYERMAP_H_
#define LAYERMAP_H_
#include "lte/config.h"
typedef _Complex float cf_t;
/* Generates the vector of layer-mapped symbols "x" based on the vector of data symbols "d"
*/
int layermap_single(cf_t *d, cf_t *x, int nof_symbols);
int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols);
int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]);
int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
LIBLTE_API int layermap_single(cf_t *d, cf_t *x, int nof_symbols);
LIBLTE_API int layermap_diversity(cf_t *d, cf_t *x[MAX_LAYERS], int nof_layers, int nof_symbols);
LIBLTE_API int layermap_multiplex(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS]);
LIBLTE_API int layermap_type(cf_t *d[MAX_CODEWORDS], cf_t *x[MAX_LAYERS], int nof_cw, int nof_layers,
int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
/* Generates the vector of data symbols "d" based on the vector of layer-mapped symbols "x"
*/
int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols);
int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols);
int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]);
int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
#endif
LIBLTE_API int layerdemap_single(cf_t *x, cf_t *d, int nof_symbols);
LIBLTE_API int layerdemap_diversity(cf_t *x[MAX_LAYERS], cf_t *d, int nof_layers, int nof_layer_symbols);
LIBLTE_API int layerdemap_multiplex(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS]);
LIBLTE_API int layerdemap_type(cf_t *x[MAX_LAYERS], cf_t *d[MAX_CODEWORDS], int nof_layers, int nof_cw,
int nof_layer_symbols, int nof_symbols[MAX_CODEWORDS], lte_mimo_type_t type);
#endif // LAYERMAP_H_

@ -25,7 +25,6 @@
*
*/
#ifndef PRECODING_H_
#define PRECODING_H_
@ -38,19 +37,18 @@ typedef _Complex float cf_t;
/* Generates the vector "y" from the input vector "x"
*/
int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports, int nof_symbols);
int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, int nof_ports,
int nof_symbols, lte_mimo_type_t type);
LIBLTE_API int precoding_single(cf_t *x, cf_t *y, int nof_symbols);
LIBLTE_API int precoding_diversity(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_ports,
int nof_symbols);
LIBLTE_API int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
int nof_ports, int nof_symbols, lte_mimo_type_t type);
/* Estimates the vector "x" based on the received signal "y" and the channel estimates "ce"
*/
int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols);
int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols);
int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS],
cf_t *x[MAX_LAYERS], int nof_ports, int nof_layers, int nof_symbols,
lte_mimo_type_t type);
LIBLTE_API int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols);
LIBLTE_API int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
int nof_ports, int nof_symbols);
LIBLTE_API int predecoding_type(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
int nof_ports, int nof_layers, int nof_symbols, lte_mimo_type_t type);
#endif /* PRECODING_H_ */

@ -32,38 +32,39 @@
#include <complex.h>
#include <stdint.h>
#include "lte/config.h"
#include "modem_table.h"
typedef _Complex float cf_t;
typedef struct {
enum modem_std table; /* In this implementation, mapping table is hard-coded */
typedef struct LIBLTE_API {
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_set(demod_hard_t* q, enum modem_std table);
int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols);
LIBLTE_API void demod_hard_init(demod_hard_t* q);
LIBLTE_API void demod_hard_table_set(demod_hard_t* q, enum modem_std table);
LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* 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;
typedef struct LIBLTE_API {
demod_hard_t obj;
struct demod_hard_init {
enum modem_std std; // Symbol mapping standard (see modem_table.h)
} init;
cf_t* input;
int in_len;
cf_t* input;
int in_len;
char* output;
int out_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);
int demod_hard_stop(demod_hard_hl* hl);
LIBLTE_API int demod_hard_initialize(demod_hard_hl* hl);
LIBLTE_API int demod_hard_work(demod_hard_hl* hl);
LIBLTE_API int demod_hard_stop(demod_hard_hl* hl);
#endif
#endif // DEMOD_HARD_

@ -32,48 +32,49 @@
#include <complex.h>
#include <stdint.h>
#include "lte/config.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)
typedef struct LIBLTE_API {
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_t* symbols, float* llr, int nsymbols);
LIBLTE_API void demod_soft_init(demod_soft_t *q);
LIBLTE_API void demod_soft_table_set(demod_soft_t *q, modem_table_t *table);
LIBLTE_API void demod_soft_alg_set(demod_soft_t *q, enum alg alg_type);
LIBLTE_API void demod_soft_sigma_set(demod_soft_t *q, float sigma);
LIBLTE_API int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int nsymbols);
/* High-level API */
typedef struct {
demod_soft_t obj;
modem_table_t table;
typedef struct LIBLTE_API {
demod_soft_t obj;
modem_table_t table;
struct demod_soft_init {
enum modem_std std; // symbol mapping standard (see modem_table.h)
} init;
struct demod_soft_init{
enum modem_std std; // symbol mapping standard (see modem_table.h)
} init;
const cf_t* input;
int in_len;
const cf_t* 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;
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;
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);
LIBLTE_API int demod_soft_initialize(demod_soft_hl* hl);
LIBLTE_API int demod_soft_work(demod_soft_hl* hl);
LIBLTE_API int demod_soft_stop(demod_soft_hl* hl);
#endif
#endif // DEMOD_SOFT_

@ -32,28 +32,29 @@
#include <complex.h>
#include <stdint.h>
#include "lte/config.h"
#include "modem_table.h"
typedef _Complex float cf_t;
int mod_modulate(modem_table_t* table, const char *bits, cf_t* symbols, int nbits);
LIBLTE_API int mod_modulate(modem_table_t* table, const char *bits, cf_t* 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;
typedef struct LIBLTE_API {
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;
const char* input;
int in_len;
cf_t* output;
int out_len;
cf_t* output;
int out_len;
}mod_hl;
int mod_initialize(mod_hl* hl);
int mod_work(mod_hl* hl);
int mod_stop(mod_hl* hl);
LIBLTE_API int mod_initialize(mod_hl* hl);
LIBLTE_API int mod_work(mod_hl* hl);
LIBLTE_API int mod_stop(mod_hl* hl);
#endif
#endif // MOD_

@ -34,28 +34,30 @@
#include <complex.h>
#include <stdint.h>
#include "lte/config.h"
typedef _Complex float cf_t;
typedef struct {
int idx[2][6][32];
typedef struct LIBLTE_API {
int idx[2][6][32];
}soft_table_t;
typedef struct {
cf_t* 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
typedef struct LIBLTE_API {
cf_t* 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 = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
};
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_t* 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);
LIBLTE_API void modem_table_init(modem_table_t* q);
LIBLTE_API void modem_table_free(modem_table_t* q);
LIBLTE_API void modem_table_reset(modem_table_t* q);
LIBLTE_API int modem_table_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, int nsymbols, int nbits_x_symbol);
LIBLTE_API int modem_table_std(modem_table_t* q, enum modem_std table, bool compute_soft_demod);
#endif
#endif // MODEM_TABLE_

@ -28,8 +28,10 @@
#ifndef DCI_
#define DCI_
#include "lte/common/base.h"
#include <stdint.h>
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/phch/ra.h"
typedef _Complex float cf_t;
@ -41,60 +43,60 @@ typedef _Complex float cf_t;
*/
#define DCI_MAX_BITS 57
#define DCI_MAX_BITS 57
typedef enum {
Format0, Format1, Format1A, Format1C
Format0, Format1, Format1A, Format1C
} dci_format_t;
// Each type is for a different interface to packing/unpacking functions
typedef struct {
enum {
PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH
} type;
dci_format_t format;
typedef struct LIBLTE_API {
enum {
PUSCH_SCHED, PDSCH_SCHED, MCCH_CHANGE, TPC_COMMAND, RA_PROC_PDCCH
} type;
dci_format_t format;
}dci_msg_type_t;
typedef enum {
DCI_COMMON = 0, DCI_UE = 1
DCI_COMMON = 0, DCI_UE = 1
} dci_spec_t;
typedef struct {
unsigned char nof_bits;
unsigned char L; // Aggregation level
unsigned char ncce; // Position of first CCE of the dci
unsigned short rnti;
typedef struct LIBLTE_API {
unsigned char nof_bits;
unsigned char L; // Aggregation level
unsigned char ncce; // Position of first CCE of the dci
unsigned short rnti;
} dci_candidate_t;
typedef struct {
char data[DCI_MAX_BITS];
dci_candidate_t location;
typedef struct LIBLTE_API {
char data[DCI_MAX_BITS];
dci_candidate_t location;
} dci_msg_t;
typedef struct {
dci_msg_t *msg;
int nof_dcis;
int max_dcis;
typedef struct LIBLTE_API {
dci_msg_t *msg;
int nof_dcis;
int max_dcis;
} dci_t;
int dci_init(dci_t *q, int max_dci);
void dci_free(dci_t *q);
char* dci_format_string(dci_format_t format);
LIBLTE_API int dci_init(dci_t *q, int max_dci);
LIBLTE_API void dci_free(dci_t *q);
LIBLTE_API char* dci_format_string(dci_format_t format);
int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti);
void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
LIBLTE_API int dci_msg_candidate_set(dci_msg_t *msg, int L, int nCCE, unsigned short rnti);
LIBLTE_API void dci_candidate_fprint(FILE *f, dci_candidate_t *q);
int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
void dci_msg_type_fprint(FILE *f, dci_msg_type_t type);
LIBLTE_API int dci_msg_get_type(dci_msg_t *msg, dci_msg_type_t *type, int nof_prb, unsigned short crnti);
LIBLTE_API void dci_msg_type_fprint(FILE *f, dci_msg_type_t type);
// For dci_msg_type_t = PUSCH_SCHED
int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb);
int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb);
LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data, dci_msg_t *msg, int nof_prb);
LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg, ra_pusch_t *data, int nof_prb);
// For dci_msg_type_t = PDSCH_SCHED
int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti);
int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti);
LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data, dci_msg_t *msg, dci_format_t format, int nof_prb, bool crc_is_crnti);
LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg, ra_pdsch_t *data, int nof_prb, bool crc_is_crnti);
int dci_format_sizeof(dci_format_t format, int nof_prb);
LIBLTE_API int dci_format_sizeof(dci_format_t format, int nof_prb);
#endif
#endif // DCI_

@ -29,6 +29,7 @@
#ifndef PBCH_
#define PBCH_
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/mimo/precoding.h"
#include "lte/mimo/layermap.h"
@ -40,59 +41,59 @@
#include "lte/fec/viterbi.h"
#include "lte/fec/crc.h"
#define PBCH_RE_CPNORM 240
#define PBCH_RE_CPEXT 216
#define PBCH_RE_CPNORM 240
#define PBCH_RE_CPEXT 216
typedef _Complex float cf_t;
typedef struct {
int nof_ports;
int nof_prb;
int sfn;
phich_length_t phich_length;
phich_resources_t phich_resources;
typedef struct LIBLTE_API {
int nof_ports;
int nof_prb;
int sfn;
phich_length_t phich_length;
phich_resources_t phich_resources;
}pbch_mib_t;
/* PBCH object */
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_symbols;
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_symbols;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pbch_symbols[MAX_PORTS_CTRL];
cf_t *pbch_x[MAX_PORTS_CTRL];
cf_t *pbch_d;
float *pbch_llr;
float *temp;
float *pbch_rm_f;
char *pbch_rm_b;
char *data;
char *data_enc;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pbch_symbols[MAX_PORTS_CTRL];
cf_t *pbch_x[MAX_PORTS_CTRL];
cf_t *pbch_d;
float *pbch_llr;
float *temp;
float *pbch_rm_f;
char *pbch_rm_b;
char *data;
char *data_enc;
int frame_idx;
int frame_idx;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pbch;
viterbi_t decoder;
crc_t crc;
convcoder_t encoder;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pbch;
viterbi_t decoder;
crc_t crc;
convcoder_t encoder;
}pbch_t;
int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp);
void pbch_free(pbch_t *q);
int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib);
void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports);
void pbch_decode_reset(pbch_t *q);
LIBLTE_API int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp);
LIBLTE_API void pbch_free(pbch_t *q);
LIBLTE_API int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce[MAX_PORTS_CTRL], float ebno, pbch_mib_t *mib);
LIBLTE_API void pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS_CTRL], int nof_ports);
LIBLTE_API void pbch_decode_reset(pbch_t *q);
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);
LIBLTE_API void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib);
LIBLTE_API bool pbch_exists(int nframe, int nslot);
LIBLTE_API int pbch_put(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id);
LIBLTE_API int pbch_get(cf_t *pbch, cf_t *slot1_data, int nof_prb, lte_cp_t cp, int cell_id);
#endif
#endif // PBCH_

@ -25,7 +25,6 @@
*
*/
#ifndef PCFICH_
#define PCFICH_
@ -44,39 +43,42 @@
typedef _Complex float cf_t;
/* PCFICH object */
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_symbols;
int nof_prb;
int nof_ports;
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_symbols;
int nof_prb;
int nof_ports;
/* handler to REGs resource mapper */
regs_t *regs;
/* handler to REGs resource mapper */
regs_t *regs;
/* buffers */
cf_t ce[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE];
/* buffers */
cf_t ce[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_symbols[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_x[MAX_PORTS_CTRL][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE];
/* bit message */
char data[PCFICH_CFI_LEN];
/* bit message */
char data[PCFICH_CFI_LEN];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_pcfich[NSUBFRAMES_X_FRAME];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_pcfich[NSUBFRAMES_X_FRAME];
}pcfich_t;
} pcfich_t;
int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp);
void pcfich_free(pcfich_t *q);
int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], int nsubframe, int *cfi, int *distance);
int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL], int nsubframe);
LIBLTE_API int pcfich_init(pcfich_t *q, regs_t *regs, int cell_id, int nof_prb,
int nof_tx_ports, lte_cp_t cp);
LIBLTE_API void pcfich_free(pcfich_t *q);
LIBLTE_API int pcfich_decode(pcfich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
int nsubframe, int *cfi, int *distance);
LIBLTE_API int pcfich_encode(pcfich_t *q, int cfi, cf_t *slot_symbols[MAX_PORTS_CTRL],
int nsubframe);
bool pcfich_exists(int nframe, int nslot);
int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data);
int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data);
LIBLTE_API bool pcfich_exists(int nframe, int nslot);
LIBLTE_API int pcfich_put(regs_t *h, cf_t *pcfich, cf_t *slot_data);
LIBLTE_API int pcfich_get(regs_t *h, cf_t *pcfich, cf_t *slot_data);
#endif

@ -25,7 +25,6 @@
*
*/
#ifndef PDCCH_
#define PDCCH_
@ -46,57 +45,58 @@ typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
typedef enum {
SEARCH_NONE=3, SEARCH_SI=0, SEARCH_RA=1, SEARCH_UE=2
}pdcch_search_mode_t;
typedef enum LIBLTE_API {
SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2
} pdcch_search_mode_t;
/*
* A search mode is indicated by higher layers to look for SI/C/RA-RNTI
* DCI messages as defined in Section 7.1 of 36.213
*/
typedef struct {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
}pdcch_search_t;
typedef struct LIBLTE_API {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
} pdcch_search_t;
/* PDCCH object */
typedef struct {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
crc_t crc;
}pdcch_t;
int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports, int cell_id, lte_cp_t cp);
void pdcch_free(pdcch_t *q);
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_bits;
int nof_symbols;
int nof_ports;
int nof_regs;
int nof_cce;
pdcch_search_t search_mode[PDCCH_NOF_SEARCH_MODES];
pdcch_search_mode_t current_search_mode;
regs_t *regs;
/* buffers */
cf_t *ce[MAX_PORTS_CTRL];
cf_t *pdcch_symbols[MAX_PORTS_CTRL];
cf_t *pdcch_x[MAX_PORTS_CTRL];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
/* tx & rx objects */
modem_table_t mod;
demod_soft_t demod;
sequence_t seq_pdcch[NSUBFRAMES_X_FRAME];
viterbi_t decoder;
crc_t crc;
} pdcch_t;
LIBLTE_API int pdcch_init(pdcch_t *q, regs_t *regs, int nof_prb, int nof_ports,
int cell_id, lte_cp_t cp);
LIBLTE_API void pdcch_free(pdcch_t *q);
/* Encoding functions */
int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], int nsubframe);
LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL],
int nsubframe);
/* Decoding functions */
@ -105,22 +105,21 @@ int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL], int
* b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra
*/
int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno);
int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL], float *llr,
int nsubframe, float ebno);
void pdcch_init_search_si(pdcch_t *q);
void pdcch_set_search_si(pdcch_t *q);
int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci);
LIBLTE_API int pdcch_decode(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
dci_t *dci, int nsubframe, float ebno);
LIBLTE_API int pdcch_extract_llr(pdcch_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
float *llr, int nsubframe, float ebno);
void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti);
void pdcch_set_search_ue(pdcch_t *q);
int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe);
LIBLTE_API void pdcch_init_search_si(pdcch_t *q);
LIBLTE_API void pdcch_set_search_si(pdcch_t *q);
LIBLTE_API int pdcch_decode_si(pdcch_t *q, float *llr, dci_t *dci);
void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti);
void pdcch_set_search_ra(pdcch_t *q);
int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci);
LIBLTE_API void pdcch_init_search_ue(pdcch_t *q, unsigned short c_rnti);
LIBLTE_API void pdcch_set_search_ue(pdcch_t *q);
LIBLTE_API int pdcch_decode_ue(pdcch_t *q, float *llr, dci_t *dci, int nsubframe);
LIBLTE_API void pdcch_init_search_ra(pdcch_t *q, unsigned short ra_rnti);
LIBLTE_API void pdcch_set_search_ra(pdcch_t *q);
LIBLTE_API int pdcch_decode_ra(pdcch_t *q, float *llr, dci_t *dci);
#endif

@ -29,6 +29,7 @@
#ifndef PDSCH_
#define PDSCH_
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/mimo/precoding.h"
#include "lte/mimo/layermap.h"
@ -47,7 +48,7 @@
typedef _Complex float cf_t;
/* PDSCH object */
typedef struct {
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
@ -77,13 +78,13 @@ typedef struct {
crc_t crc_cb;
}pdsch_t;
int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb,
LIBLTE_API int pdsch_init(pdsch_t *q, unsigned short user_rnti, int nof_prb,
int nof_ports, int cell_id, lte_cp_t cp);
void pdsch_free(pdsch_t *q);
LIBLTE_API void pdsch_free(pdsch_t *q);
int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS],
LIBLTE_API int pdsch_encode(pdsch_t *q, char *data, cf_t *sf_symbols[MAX_PORTS],
int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc);
int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
LIBLTE_API int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS],
char *data, int nsubframe, ra_mcs_t mcs, ra_prb_t *prb_alloc);

@ -29,6 +29,7 @@
#ifndef PHICH_
#define PHICH_
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/mimo/precoding.h"
#include "lte/mimo/layermap.h"
@ -39,58 +40,58 @@
typedef _Complex float cf_t;
#define PHICH_NORM_NSEQUENCES 8
#define PHICH_EXT_NSEQUENCES 4
#define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES
#define PHICH_NBITS 3
#define PHICH_NORM_NSEQUENCES 8
#define PHICH_EXT_NSEQUENCES 4
#define PHICH_MAX_SEQUENCES PHICH_NORM_NSEQUENCES
#define PHICH_NBITS 3
#define PHICH_NORM_MSYMB PHICH_NBITS * 4
#define PHICH_EXT_MSYMB PHICH_NBITS * 2
#define PHICH_MAX_NSYMB PHICH_NORM_MSYMB
#define PHICH_NORM_C 1
#define PHICH_EXT_C 2
#define PHICH_NORM_NSF 4
#define PHICH_EXT_NSF 2
#define PHICH_NORM_MSYMB PHICH_NBITS * 4
#define PHICH_EXT_MSYMB PHICH_NBITS * 2
#define PHICH_MAX_NSYMB PHICH_NORM_MSYMB
#define PHICH_NORM_C 1
#define PHICH_EXT_C 2
#define PHICH_NORM_NSF 4
#define PHICH_EXT_NSF 2
/* phich object */
typedef struct {
lte_cp_t cp;
int nof_prb;
int nof_tx_ports;
/* handler to REGs resource mapper */
regs_t *regs;
/* buffers */
cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS];
/* bit message */
char data[PHICH_NBITS];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_phich[NSUBFRAMES_X_FRAME];
typedef struct LIBLTE_API {
lte_cp_t cp;
int nof_prb;
int nof_tx_ports;
/* handler to REGs resource mapper */
regs_t *regs;
/* buffers */
cf_t ce[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_symbols[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_x[MAX_PORTS_CTRL][PHICH_MAX_NSYMB];
cf_t phich_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS];
/* bit message */
char data[PHICH_NBITS];
/* tx & rx objects */
modem_table_t mod;
demod_hard_t demod;
sequence_t seq_phich[NSUBFRAMES_X_FRAME];
}phich_t;
int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp);
void phich_free(phich_t *q);
int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
int ngroup, int nseq, int nsubframe, char *ack, int *distance);
int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe,
cf_t *slot_symbols[MAX_PORTS_CTRL]);
LIBLTE_API int phich_init(phich_t *q, regs_t *regs, int cell_id, int nof_prb, int nof_tx_ports, lte_cp_t cp);
LIBLTE_API void phich_free(phich_t *q);
LIBLTE_API int phich_decode(phich_t *q, cf_t *slot_symbols, cf_t *ce[MAX_PORTS_CTRL],
int ngroup, int nseq, int nsubframe, char *ack, int *distance);
LIBLTE_API int phich_encode(phich_t *q, char ack, int ngroup, int nseq, int nsubframe,
cf_t *slot_symbols[MAX_PORTS_CTRL]);
void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]);
int phich_ngroups(phich_t *q);
bool phich_exists(int nframe, int nslot);
int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data);
int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data);
LIBLTE_API void phich_reset(phich_t *q, cf_t *slot_symbols[MAX_PORTS_CTRL]);
LIBLTE_API int phich_ngroups(phich_t *q);
LIBLTE_API bool phich_exists(int nframe, int nslot);
LIBLTE_API int phich_put(regs_t *h, cf_t *phich, cf_t *slot_data);
LIBLTE_API int phich_get(regs_t *h, cf_t *phich, cf_t *slot_data);
#endif
#endif // PHICH_

@ -35,127 +35,130 @@
* allocation.
*/
typedef enum {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4
typedef enum LIBLTE_API {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4
} ra_mod_t;
typedef struct {
ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions
// otherwise mod + tbs values are used to generate the mcs_idx automatically.
uint8_t tbs_idx;
uint8_t mcs_idx;
int tbs; // If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI
// message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken.
}ra_mcs_t;
typedef enum {
alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2
}ra_type_t;
typedef struct {
uint32_t rbg_bitmask;
}ra_type0_t;
typedef struct {
uint32_t vrb_bitmask;
uint8_t rbg_subset;
bool shift;
}ra_type1_t;
typedef struct {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb;
uint16_t RB_start;
enum {nprb1a_2 = 0, nprb1a_3 = 1} n_prb1a;
enum {t2_ng1 = 0, t2_ng2 = 1} n_gap;
enum {t2_loc = 0, t2_dist = 1} mode;
}ra_type2_t;
typedef struct {
unsigned short rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;
bool ndi;
typedef struct LIBLTE_API {
ra_mod_t mod; // By default, mod = MOD_NULL and the mcs_idx value is taken by the packing functions
// otherwise mod + tbs values are used to generate the mcs_idx automatically.
uint8_t tbs_idx;
uint8_t mcs_idx;
int tbs;// If tbs<=0, the tbs_idx value is taken by the packing functions to generate the DCI
// message. Otherwise the tbs_idx corresponding to the lower nearest TBS is taken.
} ra_mcs_t;
typedef enum LIBLTE_API {
alloc_type0 = 0, alloc_type1 = 1, alloc_type2 = 2
} ra_type_t;
typedef struct LIBLTE_API {
uint32_t rbg_bitmask;
} ra_type0_t;
typedef struct LIBLTE_API {
uint32_t vrb_bitmask;
uint8_t rbg_subset;bool shift;
} ra_type1_t;
typedef struct LIBLTE_API {
uint32_t riv; // if L_crb==0, DCI message packer will take this value directly
uint16_t L_crb;
uint16_t RB_start;
enum {
nprb1a_2 = 0, nprb1a_3 = 1
} n_prb1a;
enum {
t2_ng1 = 0, t2_ng2 = 1
} n_gap;
enum {
t2_loc = 0, t2_dist = 1
} mode;
} ra_type2_t;
typedef struct LIBLTE_API {
unsigned short rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;bool ndi;
} ra_pdsch_t;
typedef struct {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
hop_disabled = -1,
hop_quart = 0,
hop_quart_neg = 1,
hop_half = 2,
hop_type_2 = 3
} freq_hop_fl;
ra_type2_t type2_alloc;
ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
// than before (Format0 message, see also 8.6.1 in 36.2313).
bool ndi;
bool cqi_request;
typedef struct LIBLTE_API {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
hop_disabled = -1,
hop_quart = 0,
hop_quart_neg = 1,
hop_half = 2,
hop_type_2 = 3
} freq_hop_fl;
ra_type2_t type2_alloc;
ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
// than before (Format0 message, see also 8.6.1 in 36.2313).
bool ndi;bool cqi_request;
} ra_pusch_t;
typedef struct {
uint8_t prb_idx[110];
int nof_prb;
}ra_prb_slot_t;
typedef struct {
ra_prb_slot_t slot[2];
int lstart;
int re_sf[NSUBFRAMES_X_FRAME];
}ra_prb_t;
void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb);
int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb);
int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb);
void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports, int nof_ctrl_symbols, lte_cp_t cp);
int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb);
int ra_nprb_ul(ra_pusch_t *ra, int nof_prb);
int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb, int nof_ports,
int nof_ctrl_symbols, lte_cp_t cp);
uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
int ra_tbs_from_idx_format1c(uint8_t tbs_idx);
int ra_tbs_to_table_idx_format1c(int tbs);
int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb);
int ra_tbs_to_table_idx(int tbs, int n_prb);
uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
char *ra_mod_string(ra_mod_t mod);
int ra_type0_P(int nof_prb);
uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb);
void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start, int nof_prb, int nof_vrb);
int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1);
int ra_type2_n_rb_step(int nof_prb);
int ra_type2_ngap(int nof_prb, bool ngap_is_1);
int ra_type1_N_rb(int nof_prb);
void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx);
void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx);
void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb);
void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb);
typedef struct LIBLTE_API {
uint8_t prb_idx[110];
int nof_prb;
} ra_prb_slot_t;
typedef struct LIBLTE_API {
ra_prb_slot_t slot[2];
int lstart;
int re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t;
LIBLTE_API void ra_prb_fprint(FILE *f, ra_prb_slot_t *prb);
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb, ra_pdsch_t *ra, int nof_prb);
LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb, ra_pusch_t *ra, int nof_prb);
LIBLTE_API void ra_prb_get_re(ra_prb_t *prb_dist, int nof_prb, int nof_ports,
int nof_ctrl_symbols, lte_cp_t cp);
LIBLTE_API int ra_nprb_dl(ra_pdsch_t *ra, int nof_prb);
LIBLTE_API int ra_nprb_ul(ra_pusch_t *ra, int nof_prb);
LIBLTE_API int ra_re_x_prb(int nsubframe, int nslot, int prb_idx, int nof_prb,
int nof_ports, int nof_ctrl_symbols, lte_cp_t cp);
LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
LIBLTE_API int ra_tbs_from_idx_format1c(uint8_t tbs_idx);
LIBLTE_API int ra_tbs_to_table_idx_format1c(int tbs);
LIBLTE_API int ra_tbs_from_idx(uint8_t tbs_idx, int n_prb);
LIBLTE_API int ra_tbs_to_table_idx(int tbs, int n_prb);
LIBLTE_API uint8_t ra_mcs_to_table_idx(ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_dl(uint8_t idx, ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint8_t idx, ra_mcs_t *mcs);
LIBLTE_API char *ra_mod_string(ra_mod_t mod);
LIBLTE_API int ra_type0_P(int nof_prb);
LIBLTE_API uint32_t ra_type2_to_riv(uint16_t L_crb, uint16_t RB_start, int nof_prb);
LIBLTE_API void ra_type2_from_riv(uint32_t riv, uint16_t *L_crb, uint16_t *RB_start,
int nof_prb, int nof_vrb);
LIBLTE_API int ra_type2_n_vrb_dl(int nof_prb, bool ngap_is_1);
LIBLTE_API int ra_type2_n_rb_step(int nof_prb);
LIBLTE_API int ra_type2_ngap(int nof_prb, bool ngap_is_1);
LIBLTE_API int ra_type1_N_rb(int nof_prb);
LIBLTE_API void ra_pdsch_set_mcs_index(ra_pdsch_t *ra, uint8_t mcs_idx);
LIBLTE_API void ra_pdsch_set_mcs(ra_pdsch_t *ra, ra_mod_t mod, uint8_t tbs_idx);
LIBLTE_API void ra_pdsch_fprint(FILE *f, ra_pdsch_t *ra, int nof_prb);
LIBLTE_API void ra_pusch_fprint(FILE *f, ra_pusch_t *ra, int nof_prb);
#endif /* RB_ALLOC_H_ */

@ -30,71 +30,72 @@
#define _REGS_H_
#include <stdbool.h>
#include "lte/config.h"
#include "lte/common/base.h"
#define REGS_PHICH_NSYM 12
#define REGS_PHICH_REGS_X_GROUP 3
#define REGS_PHICH_NSYM 12
#define REGS_PHICH_REGS_X_GROUP 3
#define REGS_PCFICH_NSYM 16
#define REGS_PCFICH_NREGS 4
#define REGS_PCFICH_NSYM 16
#define REGS_PCFICH_NREGS 4
#define REGS_RE_X_REG 4
#define REGS_RE_X_REG 4
typedef _Complex float cf_t;
typedef struct {
int k[4];
int k0;
int l;
bool assigned;
typedef struct LIBLTE_API {
int k[4];
int k0;
int l;
bool assigned;
}regs_reg_t;
typedef struct {
int nof_regs;
regs_reg_t **regs;
typedef struct LIBLTE_API {
int nof_regs;
regs_reg_t **regs;
}regs_ch_t;
typedef struct {
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res;
phich_length_t phich_len;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
regs_reg_t *regs;
typedef struct LIBLTE_API {
int cell_id;
int nof_prb;
int max_ctrl_symbols;
int cfi;
int ngroups_phich;
int nof_ports;
lte_cp_t cp;
phich_resources_t phich_res;
phich_length_t phich_len;
regs_ch_t pcfich;
regs_ch_t *phich; // there are several phich
regs_ch_t pdcch[3]; /* PDCCH indexing, permutation and interleaving is computed for
the three possible CFI value */
int nof_regs;
regs_reg_t *regs;
}regs_t;
int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
void regs_free(regs_t *h);
int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
LIBLTE_API int regs_init(regs_t *h, int cell_id, int nof_prb, int nof_ports,
phich_resources_t phich_res, phich_length_t phich_len, lte_cp_t cp);
LIBLTE_API void regs_free(regs_t *h);
LIBLTE_API int regs_set_cfi(regs_t *h, int nof_ctrl_symbols);
int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
LIBLTE_API int regs_put_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
LIBLTE_API int regs_add_reg(regs_reg_t *reg, cf_t *reg_data, cf_t *slot_symbols, int nof_prb);
LIBLTE_API int regs_get_reg(regs_reg_t *reg, cf_t *slot_symbols, cf_t *reg_data, int nof_prb);
LIBLTE_API int regs_reset_reg(regs_reg_t *reg, cf_t *slot_symbols, int nof_prb);
int regs_pcfich_nregs(regs_t *h);
int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
LIBLTE_API int regs_pcfich_nregs(regs_t *h);
LIBLTE_API int regs_pcfich_put(regs_t *h, cf_t pcfich_symbols[REGS_PCFICH_NSYM], cf_t *slot_symbols);
LIBLTE_API int regs_pcfich_get(regs_t *h, cf_t *slot_symbols, cf_t pcfich_symbols[REGS_PCFICH_NSYM]);
int regs_phich_nregs(regs_t *h);
int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols);
int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup);
int regs_phich_ngroups(regs_t *h);
int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
LIBLTE_API int regs_phich_nregs(regs_t *h);
LIBLTE_API int regs_phich_add(regs_t *h, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup, cf_t *slot_symbols);
LIBLTE_API int regs_phich_get(regs_t *h, cf_t *slot_symbols, cf_t phich_symbols[REGS_PHICH_NSYM], int ngroup);
LIBLTE_API int regs_phich_ngroups(regs_t *h);
LIBLTE_API int regs_phich_reset(regs_t *h, cf_t *slot_symbols);
int regs_pdcch_nregs(regs_t *h);
int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols);
int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols);
LIBLTE_API int regs_pdcch_nregs(regs_t *h);
LIBLTE_API int regs_pdcch_put(regs_t *h, cf_t *pdcch_symbols, cf_t *slot_symbols);
LIBLTE_API int regs_pdcch_get(regs_t *h, cf_t *slot_symbols, cf_t *pdcch_symbols);
#endif
#endif // REGS_H_

@ -25,10 +25,16 @@
*
*/
#ifndef INTERP_H
#define INTERP_H_
#include "lte/config.h"
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);
void interp_linear_f(float *input, float *output, int M, int len);
LIBLTE_API void interp_linear_offset(cf_t *input, cf_t *output, int M, int len, int off_st, int off_end);
LIBLTE_API void interp_linear(cf_t *input, cf_t *output, int M, int len);
LIBLTE_API void interp_linear_f(float *input, float *output, int M, int len);
#endif // INTERP_H

@ -31,19 +31,21 @@
#include <stdint.h>
#include <complex.h>
#include "lte/config.h"
typedef _Complex float cf_t;
#define RESAMPLE_ARB_N 32 // Polyphase filter rows
#define RESAMPLE_ARB_M 8 // Polyphase filter columns
typedef struct {
typedef struct LIBLTE_API {
float rate; // Resample rate
float step; // Step increment through filter
float acc; // Index into filter
cf_t reg[RESAMPLE_ARB_M]; // Our window of samples
}resample_arb_t;
void resample_arb_init(resample_arb_t *q, float rate);
int resample_arb_compute(resample_arb_t *q, cf_t *input, cf_t *output, int n_in);
LIBLTE_API void resample_arb_init(resample_arb_t *q, float rate);
LIBLTE_API int resample_arb_compute(resample_arb_t *q, cf_t *input, cf_t *output, int n_in);
#endif //RESAMPLE_ARB_

@ -29,54 +29,55 @@
#ifndef SCRAMBLING_
#define SCRAMBLING_
#include "lte/config.h"
#include "lte/common/sequence.h"
#include "lte/common/base.h"
typedef _Complex float cf_t;
/* Scrambling has no state */
void scrambling_b(sequence_t *s, char *data);
void scrambling_b_offset(sequence_t *s, char *data, int offset, int len);
LIBLTE_API void scrambling_b(sequence_t *s, char *data);
LIBLTE_API void scrambling_b_offset(sequence_t *s, char *data, int offset, int len);
void scrambling_f(sequence_t *s, float *data);
void scrambling_f_offset(sequence_t *s, float *data, int offset, int len);
LIBLTE_API void scrambling_f(sequence_t *s, float *data);
LIBLTE_API void scrambling_f_offset(sequence_t *s, float *data, int offset, int len);
void scrambling_c(sequence_t *s, cf_t *data);
void scrambling_c_offset(sequence_t *s, cf_t *data, int offset, int len);
LIBLTE_API void scrambling_c(sequence_t *s, cf_t *data);
LIBLTE_API void scrambling_c_offset(sequence_t *s, cf_t *data, int offset, int len);
/* High-level API */
/* channel integer values */
#define SCRAMBLING_PDSCH 0 /* also PUSCH */
#define SCRAMBLING_PCFICH 1
#define SCRAMBLING_PDCCH 2
#define SCRAMBLING_PBCH 3
#define SCRAMBLING_PMCH 4
#define SCRAMBLING_PUCCH 5
#define SCRAMBLING_PDSCH 0 /* also PUSCH */
#define SCRAMBLING_PCFICH 1
#define SCRAMBLING_PDCCH 2
#define SCRAMBLING_PBCH 3
#define SCRAMBLING_PMCH 4
#define SCRAMBLING_PUCCH 5
typedef struct {
sequence_t seq[NSUBFRAMES_X_FRAME];
typedef struct LIBLTE_API {
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;
typedef struct LIBLTE_API {
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
#endif // SCRAMBLING_

@ -26,11 +26,13 @@
*/
#ifndef _cfo_
#define _cfo_
#ifndef CFO_
#define CFO_
#include <complex.h>
#include "lte/config.h"
typedef _Complex float cf_t;
/** If the frequency is changed more than the tolerance, a new table is generated */
@ -38,18 +40,18 @@ typedef _Complex float cf_t;
#define CFO_CEXPTAB_SIZE 4096
typedef struct {
float last_freq;
float tol;
int nsamples;
cexptab_t tab;
cf_t *cur_cexp;
typedef struct LIBLTE_API {
float last_freq;
float tol;
int nsamples;
cexptab_t tab;
cf_t *cur_cexp;
}cfo_t;
int cfo_init(cfo_t *h, int nsamples);
void cfo_free(cfo_t *h);
LIBLTE_API int cfo_init(cfo_t *h, int nsamples);
LIBLTE_API void cfo_free(cfo_t *h);
void cfo_set_tol(cfo_t *h, float tol);
void cfo_correct(cfo_t *h, cf_t *x, float freq);
LIBLTE_API void cfo_set_tol(cfo_t *h, float tol);
LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq);
#endif
#endif // CFO_

@ -32,6 +32,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/utils/convolution.h"
@ -39,11 +40,11 @@ typedef _Complex float cf_t; /* this is only a shortcut */
#define CONVOLUTION_FFT
#define DEFAULT_CORRELATION_TH 10000
#define DEFAULT_NOSYNC_TIMEOUT 5
#define DEFAULT_NOSYNC_TIMEOUT 5
#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128
#define PSS_LEN 62
#define PSS_RE 6*12
#define PSS_LEN_FREQ 129 // FFT-based convolution removes 1 leaving it in 128
#define PSS_LEN 62
#define PSS_RE 6*12
@ -60,88 +61,78 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* Low-level API */
typedef struct {
typedef struct LIBLTE_API {
#ifdef CONVOLUTION_FFT
conv_fft_cc_t conv_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;
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;
typedef enum { PSS_TX, PSS_RX } pss_direction_t;
/* Basic functionality */
LIBLTE_API int pss_synch_init(pss_synch_t *q, int frame_size);
LIBLTE_API void pss_synch_free(pss_synch_t *q);
LIBLTE_API int pss_generate(cf_t *signal, int N_id_2);
LIBLTE_API void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp);
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 N_id_2);
void pss_put_slot(cf_t *pss_signal, cf_t *slot, int nof_prb, lte_cp_t cp);
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);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, int N_id_2);
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value, float *corr_mean_value);
LIBLTE_API 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);
LIBLTE_API int pss_synch_periodic(pss_synch_t *q, cf_t *input, cf_t *output, int nsamples);
LIBLTE_API void pss_synch_set_timeout(pss_synch_t *q, int nof_frames);
LIBLTE_API void pss_synch_set_threshold(pss_synch_t *q, float threshold);
LIBLTE_API void pss_synch_set_cfo_mode(pss_synch_t *q, bool cfo_auto);
LIBLTE_API float pss_synch_get_cfo(pss_synch_t *q);
LIBLTE_API 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;
typedef struct LIBLTE_API {
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
#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);
LIBLTE_API int pss_synch_initialize(pss_synch_hl* h);
LIBLTE_API int pss_synch_work(pss_synch_hl* hl);
LIBLTE_API int pss_synch_stop(pss_synch_hl* hl);
#endif
#endif // PSS_

@ -29,7 +29,9 @@
#ifndef SFO_
#define SFO_
float sfo_estimate(int *t0, int len, float period);
float sfo_estimate_period(int *t0, int *t, int len, float period);
#include "lte/config.h"
#endif
LIBLTE_API float sfo_estimate(int *t0, int len, float period);
LIBLTE_API float sfo_estimate_period(int *t0, int *t, int len, float period);
#endif // SFO_

@ -32,6 +32,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "lte/config.h"
#include "lte/common/base.h"
#include "lte/utils/dft.h"
@ -42,88 +43,88 @@ typedef _Complex float cf_t; /* this is only a shortcut */
* 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_POS_SYMBOL 33
#define SSS_DFT_LEN 128
#define N_SSS 31
#define SSS_LEN 2*N_SSS
struct sss_tables {
int z1[N_SSS][N_SSS];
int c[2][N_SSS];
int s[N_SSS][N_SSS];
int N_id_2;
#define N_SSS 31
#define SSS_LEN 2*N_SSS
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];
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 {
typedef struct LIBLTE_API {
dft_plan_t dftp_input;
dft_plan_t dftp_input;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
int N_id_1_table[30][30];
struct fc_tables fc_tables;
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 *signal0, float *signal5, int cell_id);
void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp);
LIBLTE_API int sss_synch_init(sss_synch_t *q);
LIBLTE_API void sss_synch_free(sss_synch_t *q);
LIBLTE_API void sss_generate(float *signal0, float *signal5, int cell_id);
LIBLTE_API void sss_put_slot(float *sss, cf_t *symbol, int nof_prb, lte_cp_t cp);
int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2);
LIBLTE_API 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);
LIBLTE_API void sss_synch_m0m1(sss_synch_t *q, cf_t *input, int *m0, float *m0_value,
int *m1, float *m1_value);
LIBLTE_API int sss_synch_subframe(int m0, int m1);
LIBLTE_API 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);
LIBLTE_API int sss_synch_frame(sss_synch_t *q, cf_t *input, int *subframe_idx, int *N_id_1);
LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q, float threshold);
LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q, int symbol_sz);
LIBLTE_API 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;
typedef struct LIBLTE_API {
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
#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);
LIBLTE_API int sss_synch_initialize(sss_synch_hl* h);
LIBLTE_API int sss_synch_work(sss_synch_hl* hl);
LIBLTE_API int sss_synch_stop(sss_synch_hl* hl);
#endif
#endif // SSS_

@ -31,6 +31,7 @@
#include <stdbool.h>
#include "lte/config.h"
#include "pss.h"
#include "sss.h"
#include "sfo.h"
@ -48,58 +49,58 @@
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;
lte_cp_t cp;
bool detect_cp;
bool sss_en;
typedef struct LIBLTE_API {
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;
lte_cp_t cp;
bool detect_cp;
bool sss_en;
}sync_t;
int sync_init(sync_t *q, int frame_size);
void sync_free(sync_t *q);
LIBLTE_API int sync_init(sync_t *q, int frame_size);
LIBLTE_API void sync_free(sync_t *q);
/* Runs the synchronization algorithm. input signal must be sampled at 1.92 MHz and should be frame_size long at least */
int sync_run(sync_t *q, cf_t *input);
LIBLTE_API int sync_run(sync_t *q, cf_t *input);
/* Sets the threshold for peak comparison */
void sync_set_threshold(sync_t *q, float threshold);
LIBLTE_API void sync_set_threshold(sync_t *q, float threshold);
/* Set peak comparison to absolute value */
void sync_pss_det_absolute(sync_t *q);
LIBLTE_API void sync_pss_det_absolute(sync_t *q);
/* Set peak comparison to relative to the mean */
void sync_pss_det_peak_to_avg(sync_t *q);
LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q);
/* Forces the synchronizer to check one N_id_2 PSS sequence only (useful for tracking mode) */
void sync_force_N_id_2(sync_t *q, int force_N_id_2);
LIBLTE_API void sync_force_N_id_2(sync_t *q, int force_N_id_2);
/* Forces the synchronizer to skip CP detection (useful for tracking mode) */
void sync_force_cp(sync_t *q, lte_cp_t cp);
LIBLTE_API void sync_force_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables SSS detection (useful for tracking mode) */
void sync_sss_en(sync_t *q, bool enabled);
LIBLTE_API void sync_sss_en(sync_t *q, bool enabled);
/* Gets the slot id (0 or 10) */
int sync_get_slot_id(sync_t *q);
LIBLTE_API int sync_get_slot_id(sync_t *q);
/* Gets the last peak-to-average ratio */
float sync_get_peak_to_avg(sync_t *q);
LIBLTE_API float sync_get_peak_to_avg(sync_t *q);
/* Gets the N_id_2 from the last call to synch_run() */
int sync_get_N_id_2(sync_t *q);
LIBLTE_API int sync_get_N_id_2(sync_t *q);
/* Gets the N_id_1 from the last call to synch_run() */
int sync_get_N_id_1(sync_t *q);
LIBLTE_API int sync_get_N_id_1(sync_t *q);
/* Gets the Physical CellId from the last call to synch_run() */
int sync_get_cell_id(sync_t *q);
LIBLTE_API int sync_get_cell_id(sync_t *q);
/* Gets the CFO estimation from the last call to synch_run() */
float sync_get_cfo(sync_t *q);
LIBLTE_API float sync_get_cfo(sync_t *q);
/* Gets the CP length estimation from the last call to synch_run() */
lte_cp_t sync_get_cp(sync_t *q);
LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
#endif
#endif // SYNC_

@ -32,11 +32,13 @@
#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);
int bit_count(unsigned int n);
#include "lte/config.h"
#endif
LIBLTE_API uint32_t bit_unpack(char **bits, int nof_bits);
LIBLTE_API void bit_pack(uint32_t value, char **bits, int nof_bits);
LIBLTE_API void bit_fprint(FILE *stream, char *bits, int nof_bits);
LIBLTE_API unsigned int bit_diff(char *x, char *y, int nbits);
LIBLTE_API int bit_count(unsigned int n);
#endif // BIT_

@ -26,22 +26,23 @@
*/
#ifndef _cexptab_
#define _cexptab_
#ifndef CEXPTAB_
#define CEXPTAB_
#include <complex.h>
#include "lte/config.h"
typedef _Complex float cf_t;
typedef struct {
int size;
cf_t *tab;
typedef struct LIBLTE_API {
int size;
cf_t *tab;
}cexptab_t;
int cexptab_init(cexptab_t *nco, int size);
void cexptab_free(cexptab_t *nco);
LIBLTE_API int cexptab_init(cexptab_t *nco, int size);
LIBLTE_API void cexptab_free(cexptab_t *nco);
void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len);
void cexptab_gen_direct(cf_t *x, float freq, int len);
LIBLTE_API void cexptab_gen(cexptab_t *nco, cf_t *x, float freq, int len);
LIBLTE_API void cexptab_gen_direct(cf_t *x, float freq, int len);
#endif
#endif // CEXPTAB_

@ -29,25 +29,26 @@
#ifndef CONVOLUTION_H_
#define CONVOLUTION_H_
#include "lte/config.h"
#include "lte/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;
typedef struct LIBLTE_API {
_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);
LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *state, int input_len, int filter_len);
LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *state);
LIBLTE_API 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);
LIBLTE_API int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len);
#endif
#endif // CONVOLUTION_H_

@ -29,17 +29,18 @@
#define DEBUG_H
#include <stdio.h>
#include "lte/config.h"
#define VERBOSE_DEBUG 2
#define VERBOSE_INFO 1
#define VERBOSE_NONE 0
#define VERBOSE_DEBUG 2
#define VERBOSE_INFO 1
#define VERBOSE_NONE 0
#include <sys/time.h>
void get_time_interval(struct timeval * tdata);
LIBLTE_API void get_time_interval(struct timeval * tdata);
#ifndef DEBUG_DISABLED
extern int verbose;
LIBLTE_API extern int verbose;
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
@ -49,16 +50,16 @@ extern int verbose;
#define PRINT_NONE verbose=VERBOSE_NONE
#define DEBUG(_fmt, ...) if (verbose >= VERBOSE_DEBUG) \
fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__)
fprintf(stdout, "[DEBUG]: " _fmt, __VA_ARGS__)
#define INFO(_fmt, ...) if (verbose >= VERBOSE_INFO) \
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
fprintf(stdout, "[INFO]: " _fmt, __VA_ARGS__)
#else
#else // DEBUG_DISABLED
#define DEBUG
#define INFO
#endif
#endif // DEBUG_DISABLED
#endif
#endif // DEBUG_H

@ -30,40 +30,41 @@
#define DFT_H_
#include <fftw3.h>
#include "lte/config.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.
/* 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
COMPLEX_2_COMPLEX, REAL_2_REAL, COMPLEX_2_REAL
}dft_mode_t;
typedef enum {
FORWARD, BACKWARD
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_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;
typedef struct LIBLTE_API {
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;
@ -71,32 +72,32 @@ 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);
LIBLTE_API int dft_plan(dft_plan_t *plan, const int dft_points,
dft_mode_t mode, dft_dir_t dir);
LIBLTE_API int dft_plan_c2c(dft_plan_t *plan, const int dft_points, dft_dir_t dir);
LIBLTE_API int dft_plan_r2r(dft_plan_t *plan, const int dft_points, dft_dir_t dir);
LIBLTE_API int dft_plan_c2r(dft_plan_t *plan, const int dft_points, dft_dir_t dir);
LIBLTE_API 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);
LIBLTE_API int dft_plan_vector(dft_plan_t *plans, const int *dft_points,
dft_mode_t *modes, dft_dir_t *dirs, int nof_plans);
LIBLTE_API int dft_plan_multi_c2c(dft_plan_t *plans, const int *dft_points,
dft_dir_t dir, int nof_plans);
LIBLTE_API int dft_plan_multi_c2r(dft_plan_t *plans, const int *dft_points,
dft_dir_t dir, int nof_plans);
LIBLTE_API int dft_plan_multi_r2r(dft_plan_t *plans, const int *dft_points,
dft_dir_t dir, int nof_plans);
LIBLTE_API void dft_plan_free_vector(dft_plan_t *plans, 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);
LIBLTE_API void dft_run(dft_plan_t *plan, void *in, void *out);
LIBLTE_API void dft_run_c2c(dft_plan_t *plan, dft_c_t *in, dft_c_t *out);
LIBLTE_API void dft_run_r2r(dft_plan_t *plan, dft_r_t *in, dft_r_t *out);
LIBLTE_API void dft_run_c2r(dft_plan_t *plan, dft_c_t *in, dft_r_t *out);
#endif
#endif // DFT_H_

@ -25,24 +25,23 @@
*
*/
#include <stdio.h>
#ifndef MATRIX_
#define MATRIX_
typedef _Complex float cf_t;
#include <stdio.h>
#include "lte/config.h"
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);
typedef _Complex float cf_t;
#endif
LIBLTE_API int matrix_init(void ***m, int sz_x, int sz_y, int elem_sz);
LIBLTE_API void matrix_free(void **q, int sz_x);
LIBLTE_API void matrix_bzero(void **q, int sz_x, int sz_y, int elem_sz);
LIBLTE_API void matrix_fprintf_cf(FILE *f, cf_t **q, int sz_x, int sz_y);
LIBLTE_API void matrix_fprintf_f(FILE *f, float **q, int sz_x, int sz_y);
LIBLTE_API void matrix_copy(void **dst, void **src, int sz_x, int sz_y, int elem_sz);
LIBLTE_API void matrix_dotprod_cf(cf_t **x, cf_t **y, cf_t **out, int sz_x, int sz_y);
LIBLTE_API void matrix_dotprod_float(float **x, float **y, float **out, int sz_x, int sz_y);
LIBLTE_API void matrix_dotprod_int(int **x, int **y, int **out, int sz_x, int sz_y);
#endif // MATRIX_

@ -25,16 +25,16 @@
*
*/
#ifndef MUX_
#define MUX_
void mux(void **input, void *output, int *input_lengths, int *input_padding_pre, int nof_inputs,
int sample_sz);
#include "lte/config.h"
LIBLTE_API 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);
LIBLTE_API void demux(void *input, void **output, int *output_lengths,
int *output_padding_pre, int *output_padding_post, int nof_outputs,
int sample_sz);
#endif
#endif // MUX_

@ -29,7 +29,9 @@
#ifndef PACK_
#define PACK_
unsigned int unpack_bits(char **bits, int nof_bits);
void pack_bits(unsigned int value, char **bits, int nof_bits);
#include "lte/config.h"
#endif
LIBLTE_API unsigned int unpack_bits(char **bits, int nof_bits);
LIBLTE_API void pack_bits(unsigned int value, char **bits, int nof_bits);
#endif // PACK_

@ -30,50 +30,51 @@
#define VECTOR_
#include <stdio.h>
#include "lte/config.h"
typedef _Complex float cf_t;
/** Return the sum of all the elements */
int vec_acc_ii(int *x, int len);
float vec_acc_ff(float *x, int len);
cf_t vec_acc_cc(cf_t *x, int len);
LIBLTE_API int vec_acc_ii(int *x, int len);
LIBLTE_API float vec_acc_ff(float *x, int len);
LIBLTE_API cf_t vec_acc_cc(cf_t *x, int len);
void *vec_malloc(int size);
LIBLTE_API void *vec_malloc(int size);
/* print vectors */
void vec_fprint_c(FILE *stream, cf_t *x, int len);
void vec_fprint_f(FILE *stream, float *x, int len);
void vec_fprint_b(FILE *stream, char *x, int len);
void vec_fprint_i(FILE *stream, int *x, int len);
LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, int len);
LIBLTE_API void vec_fprint_f(FILE *stream, float *x, int len);
LIBLTE_API void vec_fprint_b(FILE *stream, char *x, int len);
LIBLTE_API void vec_fprint_i(FILE *stream, int *x, int len);
/* sum two vectors */
void vec_sum_ch(char *z, char *x, char *y, int len);
void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len);
LIBLTE_API void vec_sum_ch(char *z, char *x, char *y, int len);
LIBLTE_API void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len);
/* scalar product */
void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len);
void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len);
LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, int len);
LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, int len);
/* vector product (element-wise) */
void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_prod_ccc_unalign(cf_t *x, cf_t *y, cf_t *z, int len);
/* z=x/y vector division (element-wise) */
void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
/* conjugate */
void vec_conj_cc(cf_t *x, cf_t *y, int len);
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, int len);
/* average vector power */
float vec_avg_power_cf(cf_t *x, int len);
LIBLTE_API float vec_avg_power_cf(cf_t *x, int len);
/* return the index of the maximum value in the vector */
int vec_max_fi(float *x, int len);
LIBLTE_API int vec_max_fi(float *x, int len);
/* quantify vector of floats and convert to unsigned char */
void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len);
LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len);
/* magnitude of each vector element */
void vec_abs_cf(cf_t *x, float *abs, int len);
LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, int len);
#endif
#endif // VECTOR_

@ -51,7 +51,7 @@ FOREACH (_module ${modules})
ENDIF(IS_DIRECTORY ${_module})
ENDFOREACH()
ADD_LIBRARY(lte ${SOURCES_ALL})
ADD_LIBRARY(lte SHARED ${SOURCES_ALL})
TARGET_LINK_LIBRARIES(lte m ${FFTW3F_LIBRARIES})
INSTALL(TARGETS lte DESTINATION ${LIBRARY_DIR})
LIBLTE_SET_PIC(lte)

@ -41,203 +41,203 @@
#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);
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%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].simbol,
__imag__ q->refsignal[port_id][nslot].refs[i].simbol);
}
fprintf(stream, "];\n");
int i;
fprintf(stream, "refs%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].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%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].recv_simbol,
__imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol);
}
fprintf(stream, "];\n");
int i;
fprintf(stream, "recvsig%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].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%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i]));
}
fprintf(stream, "];\nphase%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i],
__real__ q->refsignal[port_id][nslot].ch_est[i]));
}
fprintf(stream, "];\n");
int i;
fprintf(stream, "mag%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i]));
}
fprintf(stream, "];\nphase%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i],
__real__ q->refsignal[port_id][nslot].ch_est[i]));
}
fprintf(stream, "];\n");
}
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->nof_prb, tidx, fidx)];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx),
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI);
/* FIXME: compare with threshold */
if (channel_ref != 0) {
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
} else {
q->refsignal[port_id][nslot].ch_est[nref] = 0;
}
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->nof_prb, tidx, fidx)];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref;
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, SAMPLE_IDX(q->nof_prb, tidx, fidx),
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI);
/* FIXME: compare with threshold */
if (channel_ref != 0) {
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
} else {
q->refsignal[port_id][nslot].ch_est[nref] = 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 slot=%d port=%d using %d reference signals\n",
nslot, port_id, 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++) {
if (r->nsymbols > 1) {
for (j=0;j<r->nsymbols;j++) {
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i];
}
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
2, r->symbols_ref[0], 3);
} else {
for (j=0;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i];
}
}
for (j=0;j<q->nof_symbols;j++) {
ce[j * q->nof_prb * RE_X_RB + i] = y[j];
}
}
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 slot=%d port=%d using %d reference signals\n",
nslot, port_id, 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++) {
if (r->nsymbols > 1) {
for (j=0;j<r->nsymbols;j++) {
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i];
}
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
2, r->symbols_ref[0], 3);
} else {
for (j=0;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i];
}
}
for (j=0;j<q->nof_symbols;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 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, chest_interp_t interp, 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));
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->cp = cp;
q->nof_prb = nof_prb;
q->nof_ports = nof_ports;
q->nof_symbols = CP_NSYMB(cp);
q->cp = cp;
q->nof_prb = nof_prb;
switch(interp) {
case LINEAR:
q->interp = interp_linear_offset;
}
switch(interp) {
case LINEAR:
q->interp = interp_linear_offset;
}
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, nof_prb, nof_ports);
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, nof_prb, nof_ports);
return 0;
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;
}
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;
if (port < 0 || port > q->nof_ports) {
return -1;
}
if (nslot < 0 || nslot > NSLOTS_X_FRAME) {
return -1;
}
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 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;
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));
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;
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;
}
@ -245,50 +245,50 @@ int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) {
*/
int chest_initialize(chest_hl* h) {
if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
}
if (!h->init.nof_prb) {
h->init.nof_prb = 6;
}
if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT,
h->init.nof_prb, h->init.nof_ports)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (h->init.cell_id != -1) {
if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
}
return 0;
if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
}
if (!h->init.nof_prb) {
h->init.nof_prb = 6;
}
if (chest_init(&h->obj, LINEAR, (h->init.nof_symbols==CPNORM_NSYMB)?CPNORM:CPEXT,
h->init.nof_prb, h->init.nof_ports)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
if (h->init.cell_id != -1) {
if (chest_ref_LTEDL(&h->obj, h->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
}
return 0;
}
/** This function must be called in an slot basis (0.5ms) for LTE */
int chest_work(chest_hl* hl) {
int i;
chest_t *q = &hl->obj;
if (hl->init.cell_id != hl->ctrl_in.cell_id) {
if (chest_ref_LTEDL(q, hl->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
}
for (i=0;i<hl->init.nof_ports;i++) {
chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0);
hl->out_len[i] = hl->in_len;
}
return 0;
int i;
chest_t *q = &hl->obj;
if (hl->init.cell_id != hl->ctrl_in.cell_id) {
if (chest_ref_LTEDL(q, hl->init.cell_id)) {
fprintf(stderr, "Error initializing reference signal\n");
return -1;
}
}
for (i=0;i<hl->init.nof_ports;i++) {
chest_ce_slot_port(q, hl->input, hl->output[i], 1, 0);
hl->out_len[i] = hl->in_len;
}
return 0;
}
int chest_stop(chest_hl* hl) {
chest_free(&hl->obj);
return 0;
chest_free(&hl->obj);
return 0;
}

@ -41,150 +41,150 @@
#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 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);
return 6*m+((v+(cell_id%6))%6);
}
void refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
int i;
int fidx, tidx;
for (i=0;i<q->nof_refs;i++) {
fidx = q->refs[i].freq_idx; // reference frequency index
tidx = q->refs[i].time_idx; // reference time index
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol;
}
int i;
int fidx, tidx;
for (i=0;i<q->nof_refs;i++) {
fidx = q->refs[i].freq_idx; // reference frequency index
tidx = q->refs[i].time_idx; // reference time index
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol;
}
}
/** 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;
q->nof_prb = nof_prb;
if (!q->symbols_ref) {
return -1;
}
memcpy(q->symbols_ref, lp, sizeof(int) * 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);
q->refs[idx(l,i)].time_idx = lp[l];
}
}
ret = 0;
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;
q->nof_prb = nof_prb;
if (!q->symbols_ref) {
return -1;
}
memcpy(q->symbols_ref, lp, sizeof(int) * 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);
q->refs[idx(l,i)].time_idx = lp[l];
}
}
ret = 0;
free_and_exit:
sequence_free(&seq);
if (ret == -1) {
refsignal_free(q);
}
return ret;
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));
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));
}

@ -40,212 +40,212 @@ lte_cp_t cp = CPNORM;
char *output_matlab = NULL;
void usage(char *prog) {
printf("Usage: %s [recov]\n", prog);
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-r nof_prb [Default %d]\n", nof_prb);
printf("\t-e extended cyclic prefix [Default normal]\n");
printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id);
printf("\t-c cell_id (-1 tests all). [Default %d]\n", cell_id);
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n");
printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None");
printf("\t-v increase verbosity\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) {
case 'r':
nof_prb = atoi(argv[optind]);
break;
case 'e':
cp = CPEXT;
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'o':
output_matlab = argv[optind];
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
int opt;
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) {
case 'r':
nof_prb = atoi(argv[optind]);
break;
case 'e':
cp = CPEXT;
break;
case 'c':
cell_id = atoi(argv[optind]);
break;
case 'o':
output_matlab = argv[optind];
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int check_mse(float mod, float arg, int n_port) {
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
switch(n_port) {
case 0:
if (mod > 0.029) {
return -1;
}
if (arg > 0.029) {
return -1;
}
break;
case 1:
if (mod > 0.012) {
return -1;
}
if (arg > 0.012) {
return -1;
}
break;
case 2:
case 3:
if (mod > 3.33) {
return -1;
}
if (arg > 0.63) {
return -1;
}
break;
default:
return -1;
}
return 0;
INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port);
switch(n_port) {
case 0:
if (mod > 0.029) {
return -1;
}
if (arg > 0.029) {
return -1;
}
break;
case 1:
if (mod > 0.012) {
return -1;
}
if (arg > 0.012) {
return -1;
}
break;
case 2:
case 3:
if (mod > 3.33) {
return -1;
}
if (arg > 0.63) {
return -1;
}
break;
default:
return -1;
}
return 0;
}
int main(int argc, char **argv) {
chest_t eq;
cf_t *input = NULL, *ce = NULL, *h = NULL;
refsignal_t refs;
int i, j, n_port, n_slot, cid, num_re;
int ret = -1;
int max_cid;
FILE *fmatlab = NULL;
float mse_mag, mse_phase;
parse_args(argc,argv);
if (output_matlab) {
fmatlab=fopen(output_matlab, "w");
if (!fmatlab) {
perror("fopen");
goto do_exit;
}
}
num_re = nof_prb * RE_X_RB * CP_NSYMB(cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
perror("malloc");
goto do_exit;
}
h = malloc(num_re * sizeof(cf_t));
if (!h) {
perror("malloc");
goto do_exit;
}
ce = malloc(num_re * sizeof(cf_t));
if (!ce) {
perror("malloc");
goto do_exit;
}
if (cell_id == -1) {
cid = 0;
max_cid = 504;
} else {
cid = cell_id;
max_cid = cell_id;
}
while(cid <= max_cid) {
if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
if (chest_ref_LTEDL(&eq, cid)) {
fprintf(stderr, "Error initializing reference signal\n");
goto do_exit;
}
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (n_port=0;n_port<MAX_PORTS;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
}
bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re);
refsignal_put(&refs, input);
refsignal_free(&refs);
for (i=0;i<CP_NSYMB(cp);i++) {
for (j=0;j<nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cp) + cosf(2 * M_PI * (float) j/nof_prb/RE_X_RB);
h[i*nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*nof_prb * RE_X_RB+j] *= h[i*nof_prb * RE_X_RB+j];
}
}
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
mse_mag = mse_phase = 0;
for (i=0;i<num_re;i++) {
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
}
if (check_mse(mse_mag, mse_phase, n_port)) {
goto do_exit;
}
if (fmatlab) {
fprintf(fmatlab, "input=");
vec_fprint_c(fmatlab, input, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "h=");
vec_fprint_c(fmatlab, h, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n");
chest_fprint(&eq, fmatlab, n_slot, n_port);
}
}
}
chest_free(&eq);
cid+=10;
INFO("cid=%d\n", cid);
}
ret = 0;
chest_t eq;
cf_t *input = NULL, *ce = NULL, *h = NULL;
refsignal_t refs;
int i, j, n_port, n_slot, cid, num_re;
int ret = -1;
int max_cid;
FILE *fmatlab = NULL;
float mse_mag, mse_phase;
parse_args(argc,argv);
if (output_matlab) {
fmatlab=fopen(output_matlab, "w");
if (!fmatlab) {
perror("fopen");
goto do_exit;
}
}
num_re = nof_prb * RE_X_RB * CP_NSYMB(cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
perror("malloc");
goto do_exit;
}
h = malloc(num_re * sizeof(cf_t));
if (!h) {
perror("malloc");
goto do_exit;
}
ce = malloc(num_re * sizeof(cf_t));
if (!ce) {
perror("malloc");
goto do_exit;
}
if (cell_id == -1) {
cid = 0;
max_cid = 504;
} else {
cid = cell_id;
max_cid = cell_id;
}
while(cid <= max_cid) {
if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) {
fprintf(stderr, "Error initializing equalizer\n");
goto do_exit;
}
if (chest_ref_LTEDL(&eq, cid)) {
fprintf(stderr, "Error initializing reference signal\n");
goto do_exit;
}
for (n_slot=0;n_slot<NSLOTS_X_FRAME;n_slot++) {
for (n_port=0;n_port<MAX_PORTS;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
bzero(input, sizeof(cf_t) * num_re);
for (i=0;i<num_re;i++) {
input[i] = 0.5-rand()/RAND_MAX+I*(0.5-rand()/RAND_MAX);
}
bzero(ce, sizeof(cf_t) * num_re);
bzero(h, sizeof(cf_t) * num_re);
refsignal_put(&refs, input);
refsignal_free(&refs);
for (i=0;i<CP_NSYMB(cp);i++) {
for (j=0;j<nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cp) + cosf(2 * M_PI * (float) j/nof_prb/RE_X_RB);
h[i*nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*nof_prb * RE_X_RB+j] *= h[i*nof_prb * RE_X_RB+j];
}
}
chest_ce_slot_port(&eq, input, ce, n_slot, n_port);
mse_mag = mse_phase = 0;
for (i=0;i<num_re;i++) {
mse_mag += (cabsf(h[i]) - cabsf(ce[i])) * (cabsf(h[i]) - cabsf(ce[i])) / num_re;
mse_phase += (cargf(h[i]) - cargf(ce[i])) * (cargf(h[i]) - cargf(ce[i])) / num_re;
}
if (check_mse(mse_mag, mse_phase, n_port)) {
goto do_exit;
}
if (fmatlab) {
fprintf(fmatlab, "input=");
vec_fprint_c(fmatlab, input, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "h=");
vec_fprint_c(fmatlab, h, num_re);
fprintf(fmatlab, ";\n");
fprintf(fmatlab, "ce=");
vec_fprint_c(fmatlab, ce, num_re);
fprintf(fmatlab, ";\n");
chest_fprint(&eq, fmatlab, n_slot, n_port);
}
}
}
chest_free(&eq);
cid+=10;
INFO("cid=%d\n", cid);
}
ret = 0;
do_exit:
if (ce) {
free(ce);
}
if (input) {
free(input);
}
if (h) {
free(h);
}
if (!ret) {
printf("OK\n");
} else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
}
exit(ret);
if (ce) {
free(ce);
}
if (input) {
free(input);
}
if (h) {
free(h);
}
if (!ret) {
printf("OK\n");
} else {
printf("Error at cid=%d, slot=%d, port=%d\n",cid, n_slot, n_port);
}
exit(ret);
}

@ -34,36 +34,36 @@
#include "lte/channel/ch_awgn.h"
void ch_awgn_c(const cf_t* x, cf_t* y, float variance, int buff_sz) {
_Complex float tmp;
int i;
_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];
}
for (i=0;i<buff_sz;i++) {
__real__ tmp = rand_gauss();
__imag__ tmp = rand_gauss();
tmp *= variance;
y[i] = tmp + x[i];
}
}
void ch_awgn_f(const float* x, float* y, float variance, int buff_sz) {
int i;
int i;
for (i=0;i<buff_sz;i++) {
y[i] = x[i] + variance * rand_gauss();
}
for (i=0;i<buff_sz;i++) {
y[i] = x[i] + variance * rand_gauss();
}
}
/* High-level API */
int ch_awgn_initialize(ch_awgn_hl* hl) {
return 0;
return 0;
}
int ch_awgn_work(ch_awgn_hl* hl) {
ch_awgn_c(hl->input,hl->output,hl->ctrl_in.variance,hl->in_len);
hl->out_len = hl->in_len;
return 0;
ch_awgn_c(hl->input,hl->output,hl->ctrl_in.variance,hl->in_len);
hl->out_len = hl->in_len;
return 0;
}
int ch_awgn_stop(ch_awgn_hl* hl) {
return 0;
return 0;
}

@ -36,99 +36,99 @@
#include "lte/utils/vector.h"
int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
int symbol_sz = lte_symbol_sz(nof_prb);
int symbol_sz = lte_symbol_sz(nof_prb);
if (symbol_sz == -1) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
if (dft_plan_c2c(symbol_sz, dir, &q->fft_plan)) {
fprintf(stderr, "Error: Creating DFT plan\n");
return -1;
}
q->tmp = malloc(symbol_sz * sizeof(cf_t));
if (!q->tmp) {
perror("malloc");
return -1;
}
if (symbol_sz == -1) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
if (dft_plan_c2c(&q->fft_plan, symbol_sz, dir)) {
fprintf(stderr, "Error: Creating DFT plan\n");
return -1;
}
q->tmp = malloc(symbol_sz * sizeof(cf_t));
if (!q->tmp) {
perror("malloc");
return -1;
}
q->fft_plan.options = DFT_NORMALIZE;
if (dir==FORWARD) {
q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_POS;
} else {
q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_PRE;
}
q->symbol_sz = symbol_sz;
q->nof_symbols = CP_NSYMB(cp_type);
q->cp_type = cp_type;
q->nof_re = nof_prb * RE_X_RB;
q->nof_guards = ((symbol_sz - q->nof_re) / 2);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n",
dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,
q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return 0;
q->fft_plan.options = DFT_NORMALIZE;
if (dir==FORWARD) {
q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_POS;
} else {
q->fft_plan.options |= DFT_DC_OFFSET | DFT_MIRROR_PRE;
}
q->symbol_sz = symbol_sz;
q->nof_symbols = CP_NSYMB(cp_type);
q->cp_type = cp_type;
q->nof_re = nof_prb * RE_X_RB;
q->nof_guards = ((symbol_sz - q->nof_re) / 2);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp_type=%s, nof_re=%d, nof_guards=%d\n",
dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols,
q->cp_type==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return 0;
}
void lte_fft_free_(lte_fft_t *q) {
dft_plan_free(&q->fft_plan);
if (q->tmp) {
free(q->tmp);
}
bzero(q, sizeof(lte_fft_t));
dft_plan_free(&q->fft_plan);
if (q->tmp) {
free(q->tmp);
}
bzero(q, sizeof(lte_fft_t));
}
int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
return lte_fft_init_(q, cp_type, nof_prb, FORWARD);
return lte_fft_init_(q, cp_type, nof_prb, FORWARD);
}
void lte_fft_free(lte_fft_t *q) {
lte_fft_free_(q);
lte_fft_free_(q);
}
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
int i;
if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) {
return -1;
}
/* set now zeros at CP */
for (i=0;i<q->nof_symbols;i++) {
bzero(q->tmp, q->nof_guards * sizeof(cf_t));
bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t));
}
return 0;
int i;
if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) {
return -1;
}
/* set now zeros at CP */
for (i=0;i<q->nof_symbols;i++) {
bzero(q->tmp, q->nof_guards * sizeof(cf_t));
bzero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards * sizeof(cf_t));
}
return 0;
}
void lte_ifft_free(lte_fft_t *q) {
lte_fft_free_(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, q->tmp);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz;
output += q->nof_re;
}
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, q->tmp);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz;
output += q->nof_re;
}
}
/* 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) {
int i, cp_len;
for (i=0;i<q->nof_symbols;i++) {
cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));
dft_run_c2c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re;
/* add CP */
memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t));
output += q->symbol_sz + cp_len;
}
int i, cp_len;
for (i=0;i<q->nof_symbols;i++) {
cp_len = CP_ISNORM(q->cp_type)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz);
memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t));
dft_run_c2c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re;
/* add CP */
memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t));
output += q->symbol_sz + cp_len;
}
}

@ -35,249 +35,249 @@
#include "lte/common/base.h"
const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120,
128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232,
240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344,
352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456,
464, 472, 480, 488, 496, 504, 512, 528, 544, 560, 576, 592, 608, 624,
640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848,
864, 880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1056, 1088,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472,
1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432,
2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968,
4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
128, 136, 144, 152, 160, 168, 176, 184, 192, 200, 208, 216, 224, 232,
240, 248, 256, 264, 272, 280, 288, 296, 304, 312, 320, 328, 336, 344,
352, 360, 368, 376, 384, 392, 400, 408, 416, 424, 432, 440, 448, 456,
464, 472, 480, 488, 496, 504, 512, 528, 544, 560, 576, 592, 608, 624,
640, 656, 672, 688, 704, 720, 736, 752, 768, 784, 800, 816, 832, 848,
864, 880, 896, 912, 928, 944, 960, 976, 992, 1008, 1024, 1056, 1088,
1120, 1152, 1184, 1216, 1248, 1280, 1312, 1344, 1376, 1408, 1440, 1472,
1504, 1536, 1568, 1600, 1632, 1664, 1696, 1728, 1760, 1792, 1824, 1856,
1888, 1920, 1952, 1984, 2016, 2048, 2112, 2176, 2240, 2304, 2368, 2432,
2496, 2560, 2624, 2688, 2752, 2816, 2880, 2944, 3008, 3072, 3136, 3200,
3264, 3328, 3392, 3456, 3520, 3584, 3648, 3712, 3776, 3840, 3904, 3968,
4032, 4096, 4160, 4224, 4288, 4352, 4416, 4480, 4544, 4608, 4672, 4736,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
/*
* Returns Turbo coder interleaver size for Table 5.1.3-3 (36.212) index
*/
int lte_cb_size(int index) {
if (index >= 0 && index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
}
if (index >= 0 && index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
}
}
/*
* Finds index of minimum K>=long_cb in Table 5.1.3-3 of 36.212
*/
int lte_find_cb_index(int long_cb) {
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
} else {
return j;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
} else {
return j;
}
}
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;
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;
}
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;
}
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;
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}
{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
int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
*type = TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX;
} else {
return -1;
}
return 0;
if (!strcmp(mimo_type_str, "single")) {
*type = SINGLE_ANTENNA;
} else if (!strcmp(mimo_type_str, "diversity")) {
*type = TX_DIVERSITY;
} else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX;
} else {
return -1;
}
return 0;
}
char *lte_mimotype2str(lte_mimo_type_t type) {
switch(type) {
case SINGLE_ANTENNA:
return "single";
case TX_DIVERSITY:
return "diversity";
case SPATIAL_MULTIPLEX:
return "multiplex";
}
return NULL;
switch(type) {
case SINGLE_ANTENNA:
return "single";
case TX_DIVERSITY:
return "diversity";
case SPATIAL_MULTIPLEX:
return "multiplex";
}
return NULL;
}
float get_fd(struct lte_band *band, int earfcn) {
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
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 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);
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;
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;
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;
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;
}

@ -42,67 +42,67 @@
* Section 7.2
*/
void generate_prs_c(sequence_t *q, unsigned int seed) {
int n;
unsigned int *x1;
unsigned int *x2;
x1 = calloc(Nc + q->len + 31, sizeof(unsigned int));
if (!x1) {
perror("calloc");
return;
}
x2 = calloc(Nc + q->len + 31, sizeof(unsigned int));
if (!x2) {
free(x1);
perror("calloc");
return;
}
for (n = 0; n < 31; n++) {
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+1] + x2[n]) & 0x1;
}
for (n = 0; n < q->len; n++) {
q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1;
}
free(x1);
free(x2);
int n;
unsigned int *x1;
unsigned int *x2;
x1 = calloc(Nc + q->len + 31, sizeof(unsigned int));
if (!x1) {
perror("calloc");
return;
}
x2 = calloc(Nc + q->len + 31, sizeof(unsigned int));
if (!x2) {
free(x1);
perror("calloc");
return;
}
for (n = 0; n < 31; n++) {
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+1] + x2[n]) & 0x1;
}
for (n = 0; n < q->len; n++) {
q->c[n] = (x1[n + Nc] + x2[n + Nc]) & 0x1;
}
free(x1);
free(x2);
}
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;
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;
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));
if (q->c) {
free(q->c);
}
bzero(q, sizeof(sequence_t));
}

@ -38,104 +38,104 @@ int nof_prb = -1;
lte_cp_t cp = CPNORM;
void usage(char *prog) {
printf("Usage: %s\n", prog);
printf("\t-n nof_prb [Default All]\n");
printf("\t-e extended cyclic prefix [Default Normal]\n");
printf("Usage: %s\n", prog);
printf("\t-n nof_prb [Default All]\n");
printf("\t-e extended cyclic prefix [Default Normal]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "ne")) != -1) {
switch (opt) {
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'e':
cp = CPEXT;
break;
default:
usage(argv[0]);
exit(-1);
}
}
int opt;
while ((opt = getopt(argc, argv, "ne")) != -1) {
switch (opt) {
case 'n':
nof_prb = atoi(argv[optind]);
break;
case 'e':
cp = CPEXT;
break;
default:
usage(argv[0]);
exit(-1);
}
}
}
int main(int argc, char **argv) {
lte_fft_t fft, ifft;
cf_t *input, *outfft, *outifft;
float mse;
int n_prb, max_prb, n_re;
int i;
parse_args(argc, argv);
if (nof_prb == -1) {
n_prb = 6;
max_prb = 100;
} else {
n_prb = nof_prb;
max_prb = nof_prb;
}
while(n_prb <= max_prb) {
n_re = CP_NSYMB(cp) * n_prb * RE_X_RB;
printf("Running test for %d PRB, %d RE... ", n_prb, n_re);fflush(stdout);
input = malloc(sizeof(cf_t) * n_re);
if (!input) {
perror("malloc");
exit(-1);
}
outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb)));
if (!outfft) {
perror("malloc");
exit(-1);
}
outifft = malloc(sizeof(cf_t) * n_re);
if (!outifft) {
perror("malloc");
exit(-1);
}
if (lte_fft_init(&fft, cp, n_prb)) {
fprintf(stderr, "Error initializing FFT\n");
exit(-1);
}
if (lte_ifft_init(&ifft, cp, n_prb)) {
fprintf(stderr, "Error initializing iFFT\n");
exit(-1);
}
for (i=0;i<n_re;i++) {
input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);
}
lte_ifft_run(&ifft, input, outfft);
lte_fft_run(&fft, outfft, outifft);
/* compute MSE */
mse = 0;
for (i=0;i<n_re;i++) {
mse += cabsf(input[i] - outifft[i]);
}
printf("MSE=%f\n", mse);
if (mse >= 0.07) {
printf("MSE too large\n");
exit(-1);
}
lte_fft_free(&fft);
lte_ifft_free(&ifft);
free(input);
free(outfft);
free(outifft);
n_prb++;
}
fftwf_cleanup();
exit(0);
lte_fft_t fft, ifft;
cf_t *input, *outfft, *outifft;
float mse;
int n_prb, max_prb, n_re;
int i;
parse_args(argc, argv);
if (nof_prb == -1) {
n_prb = 6;
max_prb = 100;
} else {
n_prb = nof_prb;
max_prb = nof_prb;
}
while(n_prb <= max_prb) {
n_re = CP_NSYMB(cp) * n_prb * RE_X_RB;
printf("Running test for %d PRB, %d RE... ", n_prb, n_re);fflush(stdout);
input = malloc(sizeof(cf_t) * n_re);
if (!input) {
perror("malloc");
exit(-1);
}
outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb)));
if (!outfft) {
perror("malloc");
exit(-1);
}
outifft = malloc(sizeof(cf_t) * n_re);
if (!outifft) {
perror("malloc");
exit(-1);
}
if (lte_fft_init(&fft, cp, n_prb)) {
fprintf(stderr, "Error initializing FFT\n");
exit(-1);
}
if (lte_ifft_init(&ifft, cp, n_prb)) {
fprintf(stderr, "Error initializing iFFT\n");
exit(-1);
}
for (i=0;i<n_re;i++) {
input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);
}
lte_ifft_run(&ifft, input, outfft);
lte_fft_run(&fft, outfft, outifft);
/* compute MSE */
mse = 0;
for (i=0;i<n_re;i++) {
mse += cabsf(input[i] - outifft[i]);
}
printf("MSE=%f\n", mse);
if (mse >= 0.07) {
printf("MSE too large\n");
exit(-1);
}
lte_fft_free(&fft);
lte_ifft_free(&ifft);
free(input);
free(outfft);
free(outifft);
n_prb++;
}
fftwf_cleanup();
exit(0);
}

@ -34,47 +34,47 @@
#include "parity.h"
int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length) {
unsigned int sr;
int i,j;
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
unsigned int sr;
int i,j;
int len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q->tail_biting) {
sr = 0;
for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1);
}
} else {
sr = 0;
}
for (i = 0; i < len; i++) {
int bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);
}
}
if (q->tail_biting) {
sr = 0;
for (i=frame_length - q->K + 1; i<frame_length; i++) {
sr = (sr << 1) | (input[i] & 1);
}
} else {
sr = 0;
}
for (i = 0; i < len; i++) {
int bit = (i < frame_length) ? (input[i] & 1) : 0;
sr = (sr << 1) | bit;
for (j=0;j<q->R;j++) {
output[q->R * i + j] = parity(sr & q->poly[j]);
}
}
return q->R*len;
return q->R*len;
}
int convcoder_initialize(convcoder_hl* h) {
return 0;
return 0;
}
int convcoder_work(convcoder_hl* hl) {
hl->obj.K = hl->ctrl_in.constraint_length;
hl->obj.R = hl->ctrl_in.rate;
hl->obj.poly[0] = hl->ctrl_in.generator_0;
hl->obj.poly[1] = hl->ctrl_in.generator_1;
hl->obj.poly[2] = hl->ctrl_in.generator_2;
hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false;
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len);
return 0;
hl->obj.K = hl->ctrl_in.constraint_length;
hl->obj.R = hl->ctrl_in.rate;
hl->obj.poly[0] = hl->ctrl_in.generator_0;
hl->obj.poly[1] = hl->ctrl_in.generator_1;
hl->obj.poly[2] = hl->ctrl_in.generator_2;
hl->obj.tail_biting = hl->ctrl_in.tail_bitting?true:false;
hl->out_len = convcoder_encode(&hl->obj, hl->input, hl->output, hl->in_len);
return 0;
}
int convcoder_stop(convcoder_hl* h) {
return 0;
return 0;
}

@ -34,121 +34,121 @@
void gen_crc_table(crc_t *h) {
int i, j, ord = (h->order - 8);
unsigned long bit, crc;
for (i = 0; i < 256; i++) {
crc = ((unsigned long) i) << ord;
for (j = 0; j < 8; j++) {
bit = crc & h->crchighbit;
crc <<= 1;
if (bit)
crc ^= h->polynom;
}
h->table[i] = crc & h->crcmask;
}
int i, j, ord = (h->order - 8);
unsigned long bit, crc;
for (i = 0; i < 256; i++) {
crc = ((unsigned long) i) << ord;
for (j = 0; j < 8; j++) {
bit = crc & h->crchighbit;
crc <<= 1;
if (bit)
crc ^= h->polynom;
}
h->table[i] = crc & h->crcmask;
}
}
unsigned long crctable(crc_t *h) {
// Polynom order 8, 16, 24 or 32 only.
int ord = h->order - 8;
unsigned long crc = h->crcinit;
unsigned char byte = h->byte;
// Polynom order 8, 16, 24 or 32 only.
int ord = h->order - 8;
unsigned long crc = h->crcinit;
unsigned char byte = h->byte;
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
h->crcinit = crc;
return (crc & h->crcmask);
crc = (crc << 8) ^ h->table[((crc >> (ord)) & 0xff) ^ byte];
h->crcinit = crc;
return (crc & h->crcmask);
}
unsigned long reversecrcbit(unsigned int crc, int nbits, crc_t *h) {
unsigned long m, rmask = 0x1;
unsigned long m, rmask = 0x1;
for (m = 0; m < nbits; m++) {
if ((rmask & crc) == 0x01)
crc = (crc ^ h->polynom) >> 1;
else
crc = crc >> 1;
}
return (crc & h->crcmask);
for (m = 0; m < nbits; m++) {
if ((rmask & crc) == 0x01)
crc = (crc ^ h->polynom) >> 1;
else
crc = crc >> 1;
}
return (crc & h->crcmask);
}
int crc_set_init(crc_t *crc_par, unsigned long crc_init_value) {
crc_par->crcinit = crc_init_value;
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
printf("ERROR, invalid crcinit in crc_set_init().\n");
return -1;
}
return 0;
crc_par->crcinit = crc_init_value;
if (crc_par->crcinit != (crc_par->crcinit & crc_par->crcmask)) {
printf("ERROR, invalid crcinit in crc_set_init().\n");
return -1;
}
return 0;
}
int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
// Set crc working default parameters
h->polynom = crc_poly;
h->order = crc_order;
h->crcinit = 0x00000000;
// Set crc working default parameters
h->polynom = crc_poly;
h->order = crc_order;
h->crcinit = 0x00000000;
// Compute bit masks for whole CRC and CRC high bit
h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1)
| 1;
h->crchighbit = (unsigned long) 1 << (h->order - 1);
// Compute bit masks for whole CRC and CRC high bit
h->crcmask = ((((unsigned long) 1 << (h->order - 1)) - 1) << 1)
| 1;
h->crchighbit = (unsigned long) 1 << (h->order - 1);
// check parameters
if (h->order % 8 != 0) {
fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n",
h->order);
return -1;
}
// check parameters
if (h->order % 8 != 0) {
fprintf(stderr, "ERROR, invalid order=%d, it must be 8, 16, 24 or 32.\n",
h->order);
return -1;
}
if (crc_set_init(h, h->crcinit)) {
fprintf(stderr, "Error setting CRC init word\n");
return -1;
}
if (crc_set_init(h, h->crcinit)) {
fprintf(stderr, "Error setting CRC init word\n");
return -1;
}
// generate lookup table
gen_crc_table(h);
// generate lookup table
gen_crc_table(h);
return 0;
return 0;
}
unsigned int crc_checksum(crc_t *h, char *data, int len) {
int i, k, len8, res8, a = 0;
unsigned int crc = 0;
char *pter;
crc_set_init(h, 0);
// Pack bits into bytes
len8 = (len >> 3);
res8 = (len - (len8 << 3));
if (res8 > 0) {
a = 1;
}
// Calculate CRC
for (i = 0; i < len8 + a; i++) {
pter = (char *) (data + 8 * i);
if (i == len8) {
h->byte = 0x00;
for (k = 0; k < res8; k++) {
h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
}
} else {
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
}
crc = crctable(h);
}
// Reverse CRC res8 positions
if (a == 1) {
crc = reversecrcbit(crc, 8 - res8, h);
}
//Return CRC value
return crc;
int i, k, len8, res8, a = 0;
unsigned int crc = 0;
char *pter;
crc_set_init(h, 0);
// Pack bits into bytes
len8 = (len >> 3);
res8 = (len - (len8 << 3));
if (res8 > 0) {
a = 1;
}
// Calculate CRC
for (i = 0; i < len8 + a; i++) {
pter = (char *) (data + 8 * i);
if (i == len8) {
h->byte = 0x00;
for (k = 0; k < res8; k++) {
h->byte |= ((unsigned char) *(pter + k)) << (7 - k);
}
} else {
h->byte = (unsigned char) (unpack_bits(&pter, 8) & 0xFF);
}
crc = crctable(h);
}
// Reverse CRC res8 positions
if (a == 1) {
crc = reversecrcbit(crc, 8 - res8, h);
}
//Return CRC value
return crc;
}
@ -156,10 +156,10 @@ unsigned int crc_checksum(crc_t *h, char *data, int len) {
* The buffer data must be len + crc_order bytes
*/
void crc_attach(crc_t *h, char *data, int len) {
unsigned int checksum = crc_checksum(h, data, len);
unsigned int checksum = crc_checksum(h, data, len);
// Add CRC
char *ptr = &data[len];
pack_bits(checksum, &ptr, h->order);
// Add CRC
char *ptr = &data[len];
pack_bits(checksum, &ptr, h->order);
}

@ -25,7 +25,6 @@
*
*/
#include <string.h>
#include <stdio.h>
#include "lte/fec/rm_conv.h"
@ -33,148 +32,145 @@
#define NCOLS 32
#define NROWS_MAX NCOLS
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 };
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 };
int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
char tmp[3 * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p;
int i, j, k, s;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Input too large. Max input length is %d\n",
3 * NCOLS * NROWS_MAX);
return -1;
}
K_p = nrows * NCOLS;
ndummy = K_p - in_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver 5.1.4.2.1 */
k=0;
for (s = 0; s < 3; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (i*NCOLS + RM_PERM_CC[j] < ndummy) {
tmp[k] = TX_NULL;
} else {
tmp[k] = input[(i*NCOLS + RM_PERM_CC[j]-ndummy)*3+s];
}
k++;
}
}
}
/* Bit collection, selection and transmission 5.1.4.2.2 */
k = 0;
j = 0;
while (k < out_len) {
if (tmp[j] != TX_NULL) {
output[k] = tmp[j];
k++;
}
j++;
if (j == 3 * K_p) {
j = 0;
}
}
return 0;
char tmp[3 * NCOLS * NROWS_MAX];
int nrows, ndummy, K_p;
int i, j, k, s;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Input too large. Max input length is %d\n",
3 * NCOLS * NROWS_MAX);
return -1;
}
K_p = nrows * NCOLS;
ndummy = K_p - in_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver 5.1.4.2.1 */
k = 0;
for (s = 0; s < 3; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (i * NCOLS + RM_PERM_CC[j] < ndummy) {
tmp[k] = TX_NULL;
} else {
tmp[k] = input[(i * NCOLS + RM_PERM_CC[j] - ndummy) * 3 + s];
}
k++;
}
}
}
/* Bit collection, selection and transmission 5.1.4.2.2 */
k = 0;
j = 0;
while (k < out_len) {
if (tmp[j] != TX_NULL) {
output[k] = tmp[j];
k++;
}
j++;
if (j == 3 * K_p) {
j = 0;
}
}
return 0;
}
/* Undoes Convolutional Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.2
*/
int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
int nrows, ndummy, K_p;
int i, j, k;
int d_i, d_j;
float tmp[3 * NCOLS * NROWS_MAX];
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Output too large. Max output length is %d\n",
3 * NCOLS * NROWS_MAX);
return -1;
}
K_p = nrows * NCOLS;
ndummy = K_p - out_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < 3 * 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 == 3 * K_p) {
j = 0;
}
}
/* interleaving and bit selection */
for (i = 0; i < out_len / 3; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < 3; j++) {
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows
+ d_i];
if (o != RX_NULL) {
output[i * 3 + j] = o;
} else {
output[i * 3 + j] = 0;
}
}
}
return 0;
int nrows, ndummy, K_p;
int i, j, k;
int d_i, d_j;
float tmp[3 * NCOLS * NROWS_MAX];
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
if (nrows > NROWS_MAX) {
fprintf(stderr, "Output too large. Max output length is %d\n",
3 * NCOLS * NROWS_MAX);
return -1;
}
K_p = nrows * NCOLS;
ndummy = K_p - out_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < 3 * 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 == 3 * K_p) {
j = 0;
}
}
/* interleaving and bit selection */
for (i = 0; i < out_len / 3; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < 3; j++) {
float o = tmp[K_p * j + RM_PERM_CC_INV[d_j] * nrows + d_i];
if (o != RX_NULL) {
output[i * 3 + j] = o;
} else {
output[i * 3 + j] = 0;
}
}
}
return 0;
}
/** High-level API */
int rm_conv_initialize(rm_conv_hl* h) {
return 0;
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->in_len, hl->output, hl->ctrl_in.E);
hl->out_len = hl->ctrl_in.E;
} else {
rm_conv_rx(hl->input, hl->in_len, hl->output, hl->ctrl_in.S);
hl->out_len = hl->ctrl_in.S;
}
return 0;
if (hl->init.direction) {
rm_conv_tx(hl->input, hl->in_len, hl->output, hl->ctrl_in.E);
hl->out_len = hl->ctrl_in.E;
} else {
rm_conv_rx(hl->input, hl->in_len, hl->output, hl->ctrl_in.S);
hl->out_len = hl->ctrl_in.S;
}
return 0;
}
int rm_conv_stop(rm_conv_hl* hl) {
return 0;
return 0;
}

@ -36,24 +36,23 @@
#define NCOLS 32
#define NROWS_MAX NCOLS
unsigned char RM_PERM_TC[NCOLS] =
{ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9,
25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
unsigned char RM_PERM_TC[NCOLS] = { 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26,
6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31 };
int rm_turbo_init(rm_turbo_t *q, int buffer_len) {
q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) {
perror("malloc");
return -1;
}
return 0;
q->buffer_len = buffer_len;
q->buffer = malloc(buffer_len * sizeof(float));
if (!q->buffer) {
perror("malloc");
return -1;
}
return 0;
}
void rm_turbo_free(rm_turbo_t *q) {
if (q->buffer) {
free(q->buffer);
}
if (q->buffer) {
free(q->buffer);
}
}
/* Turbo Code Rate Matching.
@ -61,194 +60,198 @@ void rm_turbo_free(rm_turbo_t *q) {
*
* TODO: Soft buffer size limitation according to UE category
*/
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output, int out_len, int rv_idx) {
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n",
q->buffer_len, nrows, in_len);
return -1;
}
ndummy = K_p - in_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k%K_p;
} else {
kidx = K_p + 2 * (k%K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
}
}
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
/* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb];
k++;
}
j++;
}
return 0;
int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
int out_len, int rv_idx) {
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int i, j, k, s, kidx, N_cb, k0;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max input length including dummy bits is %d (3x%dx32, in_len %d)\n",
q->buffer_len, nrows, in_len);
return -1;
}
ndummy = K_p - in_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
for (j = 0; j < NCOLS; j++) {
for (i = 0; i < nrows; i++) {
if (s == 0) {
kidx = k % K_p;
} else {
kidx = K_p + 2 * (k % K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
}
}
// d_k^(2) goes through special permutation
for (k = 0; k < K_p; k++) {
kidx = (RM_PERM_TC[k / nrows] + NCOLS * (k % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
tmp[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
/* Bit selection and transmission 5.1.4.1.2 */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
k = 0;
j = 0;
while (k < out_len) {
if (tmp[(k0 + j) % N_cb] != TX_NULL) {
output[k] = tmp[(k0 + j) % N_cb];
k++;
}
j++;
}
return 0;
}
/* Undoes Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*/
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output, int out_len, int rv_idx) {
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k;
int d_i, d_j;
bool isdummy;
float *tmp = (float*) q->buffer;
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n",
q->buffer_len, nrows, out_len);
return -1;
}
ndummy = K_p - out_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < 3 * K_p; i++) {
tmp[i] = RX_NULL;
}
/* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows * (2 * (int) ceilf((float) N_cb / (float) (8 * nrows))
* rv_idx + 2);
k = 0;
j = 0;
while (k < in_len) {
jp = (k0 + j) % N_cb;
if (jp < K_p || !(jp%2)) {
if (jp >= K_p) {
d_i = ((jp-K_p) / 2) / nrows;
d_j = ((jp-K_p) / 2) % nrows;
} else {
d_i = jp / nrows;
d_j = jp % nrows;
}
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
isdummy = false;
} else {
isdummy = true;
}
} else {
int jpp = (jp-K_p-1)/2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
isdummy = true;
} else {
isdummy = false;
}
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
j++;
}
/* interleaving and bit selection */
for (i = 0; i < out_len / 3; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < 3; j++) {
if (j != 2) {
kidx = K_p * j + (j+1)*(RM_PERM_TC[d_j] * nrows + d_i);
} else {
k=(i+ndummy-1)%K_p;
if (k<0) k+=K_p;
kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p;
kidx = 2*kidx+K_p+1;
}
if (tmp[kidx] != RX_NULL) {
output[i * 3 + j] = tmp[kidx];
} else {
output[i * 3 + j] = 0;
}
}
}
return 0;
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
int out_len, int rv_idx) {
int nrows, ndummy, K_p, k0, N_cb, jp, kidx;
int i, j, k;
int d_i, d_j;
bool isdummy;
float *tmp = (float*) q->buffer;
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
fprintf(stderr,
"Input too large. Max output length including dummy bits is %d (3x%dx32, in_len %d)\n",
q->buffer_len, nrows, out_len);
return -1;
}
ndummy = K_p - out_len / 3;
if (ndummy < 0) {
ndummy = 0;
}
for (i = 0; i < 3 * K_p; i++) {
tmp[i] = RX_NULL;
}
/* Undo bit collection. Account for dummy bits */
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
k = 0;
j = 0;
while (k < in_len) {
jp = (k0 + j) % N_cb;
if (jp < K_p || !(jp % 2)) {
if (jp >= K_p) {
d_i = ((jp - K_p) / 2) / nrows;
d_j = ((jp - K_p) / 2) % nrows;
} else {
d_i = jp / nrows;
d_j = jp % nrows;
}
if (d_j * NCOLS + RM_PERM_TC[d_i] >= ndummy) {
isdummy = false;
} else {
isdummy = true;
}
} else {
int jpp = (jp - K_p - 1) / 2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
isdummy = true;
} else {
isdummy = false;
}
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
j++;
}
/* interleaving and bit selection */
for (i = 0; i < out_len / 3; i++) {
d_i = (i + ndummy) / NCOLS;
d_j = (i + ndummy) % NCOLS;
for (j = 0; j < 3; j++) {
if (j != 2) {
kidx = K_p * j + (j + 1) * (RM_PERM_TC[d_j] * nrows + d_i);
} else {
k = (i + ndummy - 1) % K_p;
if (k < 0)
k += K_p;
kidx = (k / NCOLS + nrows * RM_PERM_TC[k % NCOLS]) % K_p;
kidx = 2 * kidx + K_p + 1;
}
if (tmp[kidx] != RX_NULL) {
output[i * 3 + j] = tmp[kidx];
} else {
output[i * 3 + j] = 0;
}
}
}
return 0;
}
/** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000);
return rm_turbo_init(&h->q, 7000);
}
/** This function can be called in a subframe (1ms) basis */
int rm_turbo_work(rm_turbo_hl* hl) {
if (hl->init.direction) {
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.E;
} else {
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S, hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.S;
}
return 0;
if (hl->init.direction) {
rm_turbo_tx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.E,
hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.E;
} else {
rm_turbo_rx(&hl->q, hl->input, hl->in_len, hl->output, hl->ctrl_in.S,
hl->ctrl_in.rv_idx);
hl->out_len = hl->ctrl_in.S;
}
return 0;
}
int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0;
rm_turbo_free(&hl->q);
return 0;
}

@ -39,71 +39,61 @@
*
************************************************/
const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103, 15, 9, 17,
9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33, 103, 19,
19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155, 25,
51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19,
37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239,
17, 137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39,
19, 199, 21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27,
29, 29, 57, 45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181,
39, 27, 127, 143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257,
57, 313, 271, 179, 331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233,
357, 337, 37, 71, 71, 37, 39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43,
45, 45, 161, 89, 323, 47, 23, 47, 263 };
const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84, 90, 32,
34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32, 198,
68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40,
102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68,
420, 96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102,
52, 106, 48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140,
72, 74, 76, 78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104,
954, 96, 110, 112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420,
216, 444, 456, 468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240,
204, 104, 212, 192, 220, 336, 228, 232, 236, 120, 244, 248, 168, 64,
130, 264, 134, 408, 138, 280, 142, 480, 146, 444, 120, 152, 462, 234,
158, 80, 96, 902, 166, 336, 170, 86, 174, 176, 178, 120, 182, 184, 186,
94, 190, 480 };
const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103,
15, 9, 17, 9, 21, 101, 21, 57, 23, 13, 27, 11, 27, 85, 29, 33, 15, 17, 33,
103, 19, 19, 37, 19, 21, 21, 115, 193, 21, 133, 81, 45, 23, 243, 151, 155,
25, 51, 47, 91, 29, 29, 247, 29, 89, 91, 157, 55, 31, 17, 35, 227, 65, 19,
37, 41, 39, 185, 43, 21, 155, 79, 139, 23, 217, 25, 17, 127, 25, 239, 17,
137, 215, 29, 15, 147, 29, 59, 65, 55, 31, 17, 171, 67, 35, 19, 39, 19, 199,
21, 211, 21, 43, 149, 45, 49, 71, 13, 17, 25, 183, 55, 127, 27, 29, 29, 57,
45, 31, 59, 185, 113, 31, 17, 171, 209, 253, 367, 265, 181, 39, 27, 127,
143, 43, 29, 45, 157, 47, 13, 111, 443, 51, 51, 451, 257, 57, 313, 271, 179,
331, 363, 375, 127, 31, 33, 43, 33, 477, 35, 233, 357, 337, 37, 71, 71, 37,
39, 127, 39, 39, 31, 113, 41, 251, 43, 21, 43, 45, 45, 161, 89, 323, 47, 23,
47, 263 };
const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84,
90, 32, 34, 108, 38, 120, 84, 44, 46, 48, 50, 52, 36, 56, 58, 60, 62, 32,
198, 68, 210, 36, 74, 76, 78, 120, 82, 84, 86, 44, 90, 46, 94, 48, 98, 40,
102, 52, 106, 72, 110, 168, 114, 58, 118, 180, 122, 62, 84, 64, 66, 68, 420,
96, 74, 76, 234, 80, 82, 252, 86, 44, 120, 92, 94, 48, 98, 80, 102, 52, 106,
48, 110, 112, 114, 58, 118, 60, 122, 124, 84, 64, 66, 204, 140, 72, 74, 76,
78, 240, 82, 252, 86, 88, 60, 92, 846, 48, 28, 80, 102, 104, 954, 96, 110,
112, 114, 116, 354, 120, 610, 124, 420, 64, 66, 136, 420, 216, 444, 456,
468, 80, 164, 504, 172, 88, 300, 92, 188, 96, 28, 240, 204, 104, 212, 192,
220, 336, 228, 232, 236, 120, 244, 248, 168, 64, 130, 264, 134, 408, 138,
280, 142, 480, 146, 444, 120, 152, 462, 234, 158, 80, 96, 902, 166, 336,
170, 86, 174, 176, 178, 120, 182, 184, 186, 94, 190, 480 };
int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) {
int cb_table_idx, f1, f2;
unsigned long long i, j;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",h->max_long_cb);
return -1;
}
cb_table_idx = lte_find_cb_index(long_cb);
if (cb_table_idx == -1) {
fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb);
return -1;
}
f1 = f1_list[cb_table_idx];
f2 = f2_list[cb_table_idx];
DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2);
h->forward[0] = 0;
h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) {
j = (f1*i + f2*i*i) % (long_cb);
h->forward[i] = j;
h->reverse[j] = i;
}
return 0;
int cb_table_idx, f1, f2;
unsigned long long i, j;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",
h->max_long_cb);
return -1;
}
cb_table_idx = lte_find_cb_index(long_cb);
if (cb_table_idx == -1) {
fprintf(stderr, "Can't find long_cb=%d in valid TC CB table\n", long_cb);
return -1;
}
f1 = f1_list[cb_table_idx];
f2 = f2_list[cb_table_idx];
DEBUG("table_idx: %d, f1: %d, f2: %d\n", cb_table_idx, f1, f2);
h->forward[0] = 0;
h->reverse[0] = 0;
for (i = 1; i < long_cb; i++) {
j = (f1 * i + f2 * i * i) % (long_cb);
h->forward[i] = j;
h->reverse[j] = i;
}
return 0;
}

@ -46,228 +46,227 @@ int mcd(int x, int y);
#define MAX_COLS 256
const unsigned short table_p[52] = { 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193,
197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257 };
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127,
131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199,
211, 223, 227, 229, 233, 239, 241, 251, 257 };
const unsigned char table_v[52] = { 3, 2, 2, 3, 2, 5, 2, 3, 2, 6, 3, 5, 2, 2, 2,
2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2,
19, 5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 };
2, 7, 5, 3, 2, 3, 5, 2, 5, 2, 6, 3, 3, 2, 3, 2, 2, 6, 5, 2, 5, 2, 2, 2, 19,
5, 2, 3, 2, 3, 2, 6, 3, 7, 7, 6, 3 };
int tc_interl_init(tc_interl_t *h, int max_long_cb) {
int ret = -1;
h->forward = malloc(sizeof(int) * max_long_cb);
if (!h->forward) {
perror("malloc");
goto clean_exit;
}
h->reverse = malloc(sizeof(int) * max_long_cb);
if (!h->reverse) {
perror("malloc");
goto clean_exit;
}
h->max_long_cb = max_long_cb;
ret = 0;
clean_exit:
if (ret == -1) {
tc_interl_free(h);
}
return ret;
int ret = -1;
h->forward = malloc(sizeof(int) * max_long_cb);
if (!h->forward) {
perror("malloc");
goto clean_exit;
}
h->reverse = malloc(sizeof(int) * max_long_cb);
if (!h->reverse) {
perror("malloc");
goto clean_exit;
}
h->max_long_cb = max_long_cb;
ret = 0;
clean_exit: if (ret == -1) {
tc_interl_free(h);
}
return ret;
}
void tc_interl_free(tc_interl_t *h) {
if (h->forward) {
free(h->forward);
}
if (h->reverse) {
free(h->reverse);
}
bzero(h, sizeof(tc_interl_t));
if (h->forward) {
free(h->forward);
}
if (h->reverse) {
free(h->reverse);
}
bzero(h, sizeof(tc_interl_t));
}
int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) {
int i, j;
int res, prim, aux;
int kp, k;
int *per, *desper;
unsigned char v;
unsigned short p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long;
int i, j;
int res, prim, aux;
int kp, k;
int *per, *desper;
unsigned char v;
unsigned short p;
unsigned short s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
unsigned short U[MAX_COLS * MAX_ROWS];
int M_Rows, M_Cols, M_long;
M_long = long_cb;
M_long = long_cb;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",h->max_long_cb);
return -1;
}
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",
h->max_long_cb);
return -1;
}
/* Find R*/
if ((40 <= M_long) && (M_long <= 159))
M_Rows = 5;
else if (((160 <= M_long) && (M_long <= 200))
|| ((481 <= M_long) && (M_long <= 530)))
M_Rows = 10;
else
M_Rows = 20;
/* Find R*/
if ((40 <= M_long) && (M_long <= 159))
M_Rows = 5;
else if (((160 <= M_long) && (M_long <= 200))
|| ((481 <= M_long) && (M_long <= 530)))
M_Rows = 10;
else
M_Rows = 20;
/* Find p i v*/
if ((481 <= M_long) && (M_long <= 530)) {
p = 53;
v = 2;
M_Cols = p;
} else {
i = 0;
do {
p = table_p[i];
v = table_v[i];
i++;
} while (M_long > (M_Rows * (p + 1)));
/* Find p i v*/
if ((481 <= M_long) && (M_long <= 530)) {
p = 53;
v = 2;
M_Cols = p;
} else {
i = 0;
do {
p = table_p[i];
v = table_v[i];
i++;
} while (M_long > (M_Rows * (p + 1)));
}
}
/* Find C*/
if ((M_long) <= (M_Rows) * ((p) - 1))
M_Cols = (p) - 1;
else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p)))
M_Cols = p;
else if ((M_Rows) * (p) < M_long)
M_Cols = (p) + 1;
/* Find C*/
if ((M_long) <= (M_Rows) * ((p) - 1))
M_Cols = (p) - 1;
else if (((M_Rows) * (p - 1) < M_long) && (M_long <= (M_Rows) * (p)))
M_Cols = p;
else if ((M_Rows) * (p) < M_long)
M_Cols = (p) + 1;
q[0] = 1;
prim = 6;
q[0] = 1;
prim = 6;
for (i = 1; i < M_Rows; i++) {
do {
prim++;
res = mcd(prim, p - 1);
} while (res != 1);
q[i] = prim;
}
for (i = 1; i < M_Rows; i++) {
do {
prim++;
res = mcd(prim, p - 1);
} while (res != 1);
q[i] = prim;
}
s[0] = 1;
for (i = 1; i < p - 1; i++) {
s[i] = (v * s[i - 1]) % p;
}
s[0] = 1;
for (i = 1; i < p - 1; i++) {
s[i] = (v * s[i - 1]) % p;
}
if (M_long <= 159 && M_long >= 40) {
T[0] = 4;
T[1] = 3;
T[2] = 2;
T[3] = 1;
T[4] = 0;
} else if ((M_long <= 200 && M_long >= 160)
|| (M_long <= 530 && M_long >= 481)) {
T[0] = 9;
T[1] = 8;
T[2] = 7;
T[3] = 6;
T[4] = 5;
T[5] = 4;
T[6] = 3;
T[7] = 2;
T[8] = 1;
T[9] = 0;
} else if ((M_long <= 2480 && M_long >= 2281)
|| (M_long <= 3210 && M_long >= 3161)) {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 16;
T[11] = 13;
T[12] = 17;
T[13] = 15;
T[14] = 3;
T[15] = 1;
T[16] = 6;
T[17] = 11;
T[18] = 8;
T[19] = 10;
} else {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 10;
T[11] = 8;
T[12] = 13;
T[13] = 17;
T[14] = 3;
T[15] = 1;
T[16] = 16;
T[17] = 6;
T[18] = 15;
T[19] = 11;
}
if (M_long <= 159 && M_long >= 40) {
T[0] = 4;
T[1] = 3;
T[2] = 2;
T[3] = 1;
T[4] = 0;
} else if ((M_long <= 200 && M_long >= 160)
|| (M_long <= 530 && M_long >= 481)) {
T[0] = 9;
T[1] = 8;
T[2] = 7;
T[3] = 6;
T[4] = 5;
T[5] = 4;
T[6] = 3;
T[7] = 2;
T[8] = 1;
T[9] = 0;
} else if ((M_long <= 2480 && M_long >= 2281)
|| (M_long <= 3210 && M_long >= 3161)) {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 16;
T[11] = 13;
T[12] = 17;
T[13] = 15;
T[14] = 3;
T[15] = 1;
T[16] = 6;
T[17] = 11;
T[18] = 8;
T[19] = 10;
} else {
T[0] = 19;
T[1] = 9;
T[2] = 14;
T[3] = 4;
T[4] = 0;
T[5] = 2;
T[6] = 5;
T[7] = 7;
T[8] = 12;
T[9] = 18;
T[10] = 10;
T[11] = 8;
T[12] = 13;
T[13] = 17;
T[14] = 3;
T[15] = 1;
T[16] = 16;
T[17] = 6;
T[18] = 15;
T[19] = 11;
}
for (i = 0; i < M_Rows; i++) {
r[T[i]] = q[i];
}
for (i = 0; i < M_Rows; i++) {
r[T[i]] = q[i];
}
for (i = 0; i < M_Rows; i++) {
for (j = 0; j < p - 1; j++) {
U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)];
if (M_Cols == (p - 1))
U[i * M_Cols + j] -= 1;
}
}
for (i = 0; i < M_Rows; i++) {
for (j = 0; j < p - 1; j++) {
U[i * M_Cols + j] = s[(j * r[i]) % (p - 1)];
if (M_Cols == (p - 1))
U[i * M_Cols + j] -= 1;
}
}
if (M_Cols == p) {
for (i = 0; i < M_Rows; i++)
U[i * M_Cols + p - 1] = 0;
} else if (M_Cols == p + 1) {
for (i = 0; i < M_Rows; i++) {
U[i * M_Cols + p - 1] = 0;
U[i * M_Cols + p] = p;
}
if (M_long == M_Cols * M_Rows) {
aux = U[(M_Rows - 1) * M_Cols + p];
U[(M_Rows - 1) * M_Cols + p] = U[(M_Rows - 1) * M_Cols + 0];
U[(M_Rows - 1) * M_Cols + 0] = aux;
}
}
if (M_Cols == p) {
for (i = 0; i < M_Rows; i++)
U[i * M_Cols + p - 1] = 0;
} else if (M_Cols == p + 1) {
for (i = 0; i < M_Rows; i++) {
U[i * M_Cols + p - 1] = 0;
U[i * M_Cols + p] = p;
}
if (M_long == M_Cols * M_Rows) {
aux = U[(M_Rows - 1) * M_Cols + p];
U[(M_Rows - 1) * M_Cols + p] = U[(M_Rows - 1) * M_Cols + 0];
U[(M_Rows - 1) * M_Cols + 0] = aux;
}
}
per = h->forward;
desper = h->reverse;
per = h->forward;
desper = h->reverse;
k = 0;
for (j = 0; j < M_Cols; j++) {
for (i = 0; i < M_Rows; i++) {
kp = T[i] * M_Cols + U[i * M_Cols + j];
if (kp < M_long) {
desper[kp] = k;
per[k] = kp;
k++;
}
}
}
k = 0;
for (j = 0; j < M_Cols; j++) {
for (i = 0; i < M_Rows; i++) {
kp = T[i] * M_Cols + U[i * M_Cols + j];
if (kp < M_long) {
desper[kp] = k;
per[k] = kp;
k++;
}
}
}
return 0;
return 0;
}
int mcd(int x, int y) {
int r = 1;
int r = 1;
while (r) {
r = x % y;
x = y;
y = r;
}
return x;
while (r) {
r = x % y;
x = y;
y = r;
}
return x;
}

@ -33,113 +33,114 @@
int tcod_init(tcod_t *h, int max_long_cb) {
if (tc_interl_init(&h->interl, max_long_cb)) {
return -1;
}
h->max_long_cb = max_long_cb;
return 0;
if (tc_interl_init(&h->interl, max_long_cb)) {
return -1;
}
h->max_long_cb = max_long_cb;
return 0;
}
void tcod_free(tcod_t *h) {
tc_interl_free(&h->interl);
h->max_long_cb = 0;
tc_interl_free(&h->interl);
h->max_long_cb = 0;
}
int tcod_encode(tcod_t *h, char *input, char *output, int long_cb) {
char reg1_0,reg1_1,reg1_2, reg2_0,reg2_1,reg2_2;
int i,k=0,j;
char bit;
char in,out;
int *per;
char reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2;
int i, k = 0, j;
char bit;
char in, out;
int *per;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n", h->max_long_cb);
return -1;
}
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n",
h->max_long_cb);
return -1;
}
if (tc_interl_LTE_gen(&h->interl, long_cb)) {
fprintf(stderr, "Error initiating TC interleaver\n");
return -1;
}
if (tc_interl_LTE_gen(&h->interl, long_cb)) {
fprintf(stderr, "Error initiating TC interleaver\n");
return -1;
}
per=h->interl.forward;
per = h->interl.forward;
reg1_0=0;
reg1_1=0;
reg1_2=0;
reg1_0 = 0;
reg1_1 = 0;
reg1_2 = 0;
reg2_0=0;
reg2_1=0;
reg2_2=0;
reg2_0 = 0;
reg2_1 = 0;
reg2_2 = 0;
k=0;
for (i=0;i<long_cb;i++) {
bit=input[i];
k = 0;
for (i = 0; i < long_cb; i++) {
bit = input[i];
output[k]=bit;
k++;
output[k] = bit;
k++;
in=bit^(reg1_2^reg1_1);
out=reg1_2^(reg1_0^in);
in = bit ^ (reg1_2 ^ reg1_1);
out = reg1_2 ^ (reg1_0 ^ in);
reg1_2=reg1_1;
reg1_1=reg1_0;
reg1_0=in;
reg1_2 = reg1_1;
reg1_1 = reg1_0;
reg1_0 = in;
output[k]=out;
k++;
output[k] = out;
k++;
bit=input[per[i]];
bit = input[per[i]];
in=bit^(reg2_2^reg2_1);
out=reg2_2^(reg2_0^in);
in = bit ^ (reg2_2 ^ reg2_1);
out = reg2_2 ^ (reg2_0 ^ in);
reg2_2=reg2_1;
reg2_1=reg2_0;
reg2_0=in;
reg2_2 = reg2_1;
reg2_1 = reg2_0;
reg2_0 = in;
output[k]=out;
k++;
}
output[k] = out;
k++;
}
k=3*long_cb;
k = 3 * long_cb;
/* TAILING CODER #1 */
for (j=0;j<NOF_REGS;j++) {
bit=reg1_2^reg1_1;
/* TAILING CODER #1 */
for (j = 0; j < NOF_REGS; j++) {
bit = reg1_2 ^ reg1_1;
output[k]=bit;
k++;
output[k] = bit;
k++;
in=bit^(reg1_2^reg1_1);
out=reg1_2^(reg1_0^in);
in = bit ^ (reg1_2 ^ reg1_1);
out = reg1_2 ^ (reg1_0 ^ in);
reg1_2=reg1_1;
reg1_1=reg1_0;
reg1_0=in;
reg1_2 = reg1_1;
reg1_1 = reg1_0;
reg1_0 = in;
output[k]=out;
k++;
}
output[k] = out;
k++;
}
/* TAILING CODER #2 */
for (j=0;j<NOF_REGS;j++) {
bit=reg2_2^reg2_1;
/* TAILING CODER #2 */
for (j = 0; j < NOF_REGS; j++) {
bit = reg2_2 ^ reg2_1;
output[k]=bit;
k++;
output[k] = bit;
k++;
in=bit^(reg2_2^reg2_1);
out=reg2_2^(reg2_0^in);
in = bit ^ (reg2_2 ^ reg2_1);
out = reg2_2 ^ (reg2_0 ^ in);
reg2_2=reg2_1;
reg2_1=reg2_0;
reg2_0=in;
reg2_2 = reg2_1;
reg2_1 = reg2_0;
reg2_0 = in;
output[k]=out;
k++;
}
return 0;
output[k] = out;
k++;
}
return 0;
}

@ -25,7 +25,6 @@
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -40,292 +39,290 @@
*
************************************************/
void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) {
llr_t m_b[8], new[8], old[8];
llr_t x, y, xy;
int k;
int end = long_cb + RATE;
llr_t *beta = s->beta;
int i;
for (i=0;i<8;i++) {
old[i] = beta[8 * (end) + i];
}
for (k = end - 1; k >= 0; k--) {
x = input[k];
y = parity[k];
xy = x + y;
m_b[0] = old[4] + xy;
m_b[1] = old[4];
m_b[2] = old[5] + y;
m_b[3] = old[5] + x;
m_b[4] = old[6] + x;
m_b[5] = old[6] + y;
m_b[6] = old[7];
m_b[7] = old[7] + xy;
new[0] = old[0];
new[1] = old[0] + xy;
new[2] = old[1] + x;
new[3] = old[1] + y;
new[4] = old[2] + y;
new[5] = old[2] + x;
new[6] = old[3] + xy;
new[7] = old[3];
for (i=0;i<8;i++) {
if (m_b[i] > new[i])
new[i] = m_b[i];
beta[8 * k + i] = new[i];
old[i] = new[i];
}
}
llr_t m_b[8], new[8], old[8];
llr_t x, y, xy;
int k;
int end = long_cb + RATE;
llr_t *beta = s->beta;
int i;
for (i = 0; i < 8; i++) {
old[i] = beta[8 * (end) + i];
}
for (k = end - 1; k >= 0; k--) {
x = input[k];
y = parity[k];
xy = x + y;
m_b[0] = old[4] + xy;
m_b[1] = old[4];
m_b[2] = old[5] + y;
m_b[3] = old[5] + x;
m_b[4] = old[6] + x;
m_b[5] = old[6] + y;
m_b[6] = old[7];
m_b[7] = old[7] + xy;
new[0] = old[0];
new[1] = old[0] + xy;
new[2] = old[1] + x;
new[3] = old[1] + y;
new[4] = old[2] + y;
new[5] = old[2] + x;
new[6] = old[3] + xy;
new[7] = old[3];
for (i = 0; i < 8; i++) {
if (m_b[i] > new[i])
new[i] = m_b[i];
beta[8 * k + i] = new[i];
old[i] = new[i];
}
}
}
void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, int long_cb) {
llr_t m_b[8], new[8], old[8], max1[8], max0[8];
llr_t m1, m0;
llr_t x, y, xy;
llr_t out;
int k;
int end = long_cb;
llr_t *beta = s->beta;
int i;
old[0] = 0;
for (i=1;i<8;i++) {
old[i] = -INF;
}
for (k = 1; k < end + 1; k++) {
x = input[k - 1];
y = parity[k - 1];
xy = x + y;
m_b[0] = old[0];
m_b[1] = old[3] + y;
m_b[2] = old[4] + y;
m_b[3] = old[7];
m_b[4] = old[1];
m_b[5] = old[2] + y;
m_b[6] = old[5] + y;
m_b[7] = old[6];
new[0] = old[1] + xy;
new[1] = old[2] + x;
new[2] = old[5] + x;
new[3] = old[6] + xy;
new[4] = old[0] + xy;
new[5] = old[3] + x;
new[6] = old[4] + x;
new[7] = old[7] + xy;
for (i=0;i<8;i++) {
max0[i] = m_b[i] + beta[8 * k + i];
max1[i] = new[i] + beta[8 * k + i];
}
m1 = max1[0];
m0 = max0[0];
for (i=1;i<8;i++) {
if (max1[i] > m1)
m1 = max1[i];
if (max0[i] > m0)
m0 = max0[i];
}
for (i=0;i<8;i++) {
if (m_b[i] > new[i])
new[i] = m_b[i];
old[i] = new[i];
}
out = m1 - m0;
output[k - 1] = out;
}
void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output,
int long_cb) {
llr_t m_b[8], new[8], old[8], max1[8], max0[8];
llr_t m1, m0;
llr_t x, y, xy;
llr_t out;
int k;
int end = long_cb;
llr_t *beta = s->beta;
int i;
old[0] = 0;
for (i = 1; i < 8; i++) {
old[i] = -INF;
}
for (k = 1; k < end + 1; k++) {
x = input[k - 1];
y = parity[k - 1];
xy = x + y;
m_b[0] = old[0];
m_b[1] = old[3] + y;
m_b[2] = old[4] + y;
m_b[3] = old[7];
m_b[4] = old[1];
m_b[5] = old[2] + y;
m_b[6] = old[5] + y;
m_b[7] = old[6];
new[0] = old[1] + xy;
new[1] = old[2] + x;
new[2] = old[5] + x;
new[3] = old[6] + xy;
new[4] = old[0] + xy;
new[5] = old[3] + x;
new[6] = old[4] + x;
new[7] = old[7] + xy;
for (i = 0; i < 8; i++) {
max0[i] = m_b[i] + beta[8 * k + i];
max1[i] = new[i] + beta[8 * k + i];
}
m1 = max1[0];
m0 = max0[0];
for (i = 1; i < 8; i++) {
if (max1[i] > m1)
m1 = max1[i];
if (max0[i] > m0)
m0 = max0[i];
}
for (i = 0; i < 8; i++) {
if (m_b[i] > new[i])
new[i] = m_b[i];
old[i] = new[i];
}
out = m1 - m0;
output[k - 1] = out;
}
}
int map_gen_init(map_gen_t *h, int max_long_cb) {
bzero(h, sizeof(map_gen_t));
h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1)* NUMSTATES);
if (!h->beta) {
perror("malloc");
return -1;
}
h->max_long_cb = max_long_cb;
return 0;
bzero(h, sizeof(map_gen_t));
h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1) * NUMSTATES);
if (!h->beta) {
perror("malloc");
return -1;
}
h->max_long_cb = max_long_cb;
return 0;
}
void map_gen_free(map_gen_t *h) {
if (h->beta) {
free(h->beta);
}
bzero(h, sizeof(map_gen_t));
if (h->beta) {
free(h->beta);
}
bzero(h, sizeof(map_gen_t));
}
void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, int long_cb) {
int k;
void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output,
int long_cb) {
int k;
h->beta[(long_cb + TAIL) * NUMSTATES] = 0;
for (k = 1; k < NUMSTATES; k++)
h->beta[(long_cb + TAIL) * NUMSTATES + k] = -INF;
h->beta[(long_cb + TAIL) * NUMSTATES] = 0;
for (k = 1; k < NUMSTATES; k++)
h->beta[(long_cb + TAIL) * NUMSTATES + k] = -INF;
map_gen_beta(h, input, parity, long_cb);
map_gen_alpha(h, input, parity, output, long_cb);
map_gen_beta(h, input, parity, long_cb);
map_gen_alpha(h, input, parity, output, long_cb);
}
/************************************************
*
* TURBO DECODER INTERFACE
*
************************************************/
int tdec_init(tdec_t *h, int max_long_cb) {
int ret = -1;
bzero(h, sizeof(tdec_t));
int len = max_long_cb + TOTALTAIL;
h->max_long_cb = max_long_cb;
h->llr1 = malloc(sizeof(llr_t) * len);
if (!h->llr1) {
perror("malloc");
goto clean_and_exit;
}
h->llr2 = malloc(sizeof(llr_t) * len);
if (!h->llr2) {
perror("malloc");
goto clean_and_exit;
}
h->w = malloc(sizeof(llr_t) * len);
if (!h->w) {
perror("malloc");
goto clean_and_exit;
}
h->syst = malloc(sizeof(llr_t) * len);
if (!h->syst) {
perror("malloc");
goto clean_and_exit;
}
h->parity = malloc(sizeof(llr_t) * len);
if (!h->parity) {
perror("malloc");
goto clean_and_exit;
}
if (map_gen_init(&h->dec, h->max_long_cb)) {
goto clean_and_exit;
}
if (tc_interl_init(&h->interleaver, h->max_long_cb) < 0) {
goto clean_and_exit;
}
ret = 0;
clean_and_exit:
if (ret == -1) {
tdec_free(h);
}
return ret;
int ret = -1;
bzero(h, sizeof(tdec_t));
int len = max_long_cb + TOTALTAIL;
h->max_long_cb = max_long_cb;
h->llr1 = malloc(sizeof(llr_t) * len);
if (!h->llr1) {
perror("malloc");
goto clean_and_exit;
}
h->llr2 = malloc(sizeof(llr_t) * len);
if (!h->llr2) {
perror("malloc");
goto clean_and_exit;
}
h->w = malloc(sizeof(llr_t) * len);
if (!h->w) {
perror("malloc");
goto clean_and_exit;
}
h->syst = malloc(sizeof(llr_t) * len);
if (!h->syst) {
perror("malloc");
goto clean_and_exit;
}
h->parity = malloc(sizeof(llr_t) * len);
if (!h->parity) {
perror("malloc");
goto clean_and_exit;
}
if (map_gen_init(&h->dec, h->max_long_cb)) {
goto clean_and_exit;
}
if (tc_interl_init(&h->interleaver, h->max_long_cb) < 0) {
goto clean_and_exit;
}
ret = 0;
clean_and_exit: if (ret == -1) {
tdec_free(h);
}
return ret;
}
void tdec_free(tdec_t *h) {
if (h->llr1) {
free(h->llr1);
}
if (h->llr2) {
free(h->llr2);
}
if (h->w) {
free(h->w);
}
if (h->syst) {
free(h->syst);
}
if (h->parity) {
free(h->parity);
}
map_gen_free(&h->dec);
tc_interl_free(&h->interleaver);
bzero(h, sizeof(tdec_t));
if (h->llr1) {
free(h->llr1);
}
if (h->llr2) {
free(h->llr2);
}
if (h->w) {
free(h->w);
}
if (h->syst) {
free(h->syst);
}
if (h->parity) {
free(h->parity);
}
map_gen_free(&h->dec);
tc_interl_free(&h->interleaver);
bzero(h, sizeof(tdec_t));
}
void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) {
int i;
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) {
h->syst[i] = input[RATE * i] + h->w[i];
h->parity[i] = input[RATE * i + 1];
}
for (i=long_cb;i<long_cb+RATE;i++) {
h->syst[i] = input[RATE * long_cb + NINPUTS * (i - long_cb)];
h->parity[i] = input[RATE * long_cb + NINPUTS * (i - long_cb) + 1];
}
// Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr1, long_cb);
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) {
h->syst[i] = h->llr1[h->interleaver.forward[i]] - h->w[h->interleaver.forward[i]];
h->parity[i] = input[RATE * i + 2];
}
for (i=long_cb;i<long_cb+RATE;i++) {
h->syst[i] = input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)];
h->parity[i] = input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb) + 1];
}
// Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb);
// Update a-priori LLR from the last iteration
for (i = 0; i < long_cb; i++) {
h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i];
}
int i;
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) {
h->syst[i] = input[RATE * i] + h->w[i];
h->parity[i] = input[RATE * i + 1];
}
for (i = long_cb; i < long_cb + RATE; i++) {
h->syst[i] = input[RATE * long_cb + NINPUTS * (i - long_cb)];
h->parity[i] = input[RATE * long_cb + NINPUTS * (i - long_cb) + 1];
}
// Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr1, long_cb);
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) {
h->syst[i] = h->llr1[h->interleaver.forward[i]]
- h->w[h->interleaver.forward[i]];
h->parity[i] = input[RATE * i + 2];
}
for (i = long_cb; i < long_cb + RATE; i++) {
h->syst[i] =
input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)];
h->parity[i] = input[RATE * long_cb + NINPUTS * RATE
+ NINPUTS * (i - long_cb) + 1];
}
// Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb);
// Update a-priori LLR from the last iteration
for (i = 0; i < long_cb; i++) {
h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i];
}
}
int tdec_reset(tdec_t *h, int long_cb) {
memset(h->w, 0, sizeof(llr_t) * long_cb);
if (long_cb > h->max_long_cb) {
fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", h->max_long_cb);
return -1;
}
return tc_interl_LTE_gen(&h->interleaver, long_cb);
memset(h->w, 0, sizeof(llr_t) * long_cb);
if (long_cb > h->max_long_cb) {
fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n",
h->max_long_cb);
return -1;
}
return tc_interl_LTE_gen(&h->interleaver, long_cb);
}
void tdec_decision(tdec_t *h, char *output, int long_cb) {
int i;
for (i = 0; i < long_cb; i++) {
output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0;
}
int i;
for (i = 0; i < long_cb; i++) {
output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0;
}
}
void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations, int long_cb) {
int iter = 0;
void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations,
int long_cb) {
int iter = 0;
tdec_reset(h, long_cb);
tdec_reset(h, long_cb);
do {
tdec_iteration(h, input, long_cb);
iter++;
} while (iter < nof_iterations);
do {
tdec_iteration(h, input, long_cb);
iter++;
} while (iter < nof_iterations);
tdec_decision(h, output, long_cb);
tdec_decision(h, output, long_cb);
}

@ -39,222 +39,222 @@
#define DEB 0
int decode37(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o;
int i;
viterbi_t *q = o;
int i;
int best_state;
int best_state;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi37_port(q->ptr, q->tail_biting ? -1 : 0);
/* Initialize Viterbi decoder */
init_viterbi37_port(q->ptr, q->tail_biting ? -1 : 0);
/* Decode block */
if (q->tail_biting) {
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char));
for (i = 0; i < 3 * (q->K - 1); i++) {
q->tmp[i + 3 * frame_length] = q->tmp[i];
}
} else {
q->tmp = symbols;
}
/* Decode block */
if (q->tail_biting) {
memcpy(q->tmp, symbols, 3 * frame_length * sizeof(char));
for (i = 0; i < 3 * (q->K - 1); i++) {
q->tmp[i + 3 * frame_length] = q->tmp[i];
}
} else {
q->tmp = symbols;
}
update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1,
q->tail_biting ? &best_state : NULL);
update_viterbi37_blk_port(q->ptr, q->tmp, frame_length + q->K - 1,
q->tail_biting ? &best_state : NULL);
/* Do Viterbi chainback */
chainback_viterbi37_port(q->ptr, data, frame_length,
q->tail_biting ? best_state : 0);
/* Do Viterbi chainback */
chainback_viterbi37_port(q->ptr, data, frame_length,
q->tail_biting ? best_state : 0);
return q->framebits;
return q->framebits;
}
int decode39(void *o, unsigned char *symbols, char *data, int frame_length) {
viterbi_t *q = o;
viterbi_t *q = o;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
/* Initialize Viterbi decoder */
init_viterbi39_port(q->ptr, 0);
/* Initialize Viterbi decoder */
init_viterbi39_port(q->ptr, 0);
/* Decode block */
update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1);
/* Decode block */
update_viterbi39_blk_port(q->ptr, symbols, frame_length + q->K - 1);
/* Do Viterbi chainback */
chainback_viterbi39_port(q->ptr, data, frame_length, 0);
/* Do Viterbi chainback */
chainback_viterbi39_port(q->ptr, data, frame_length, 0);
return q->framebits;
return q->framebits;
}
void free37(void *o) {
viterbi_t *q = o;
if (q->symbols_uc) {
free(q->symbols_uc);
}
if (q->tmp) {
free(q->tmp);
}
delete_viterbi37_port(q->ptr);
viterbi_t *q = o;
if (q->symbols_uc) {
free(q->symbols_uc);
}
if (q->tmp) {
free(q->tmp);
}
delete_viterbi37_port(q->ptr);
}
void free39(void *o) {
viterbi_t *q = o;
if (q->symbols_uc) {
free(q->symbols_uc);
}
delete_viterbi39_port(q->ptr);
viterbi_t *q = o;
if (q->symbols_uc) {
free(q->symbols_uc);
}
delete_viterbi39_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;
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if (q->tail_biting) {
q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->tmp) {
perror("malloc");
free37(q);
return -1;
}
} else {
q->tmp = NULL;
}
q->K = 7;
q->R = 3;
q->framebits = framebits;
q->tail_biting = tail_biting;
q->decode = decode37;
q->free = free37;
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if (q->tail_biting) {
q->tmp = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->tmp) {
perror("malloc");
free37(q);
return -1;
}
} else {
q->tmp = NULL;
}
if ((q->ptr = create_viterbi37_port(poly, framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n");
free37(q);
return -1;
} else {
return 0;
}
if ((q->ptr = create_viterbi37_port(poly, framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n");
free37(q);
return -1;
} else {
return 0;
}
}
int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
q->K = 9;
q->R = 3;
q->framebits = framebits;
q->tail_biting = tail_biting;
q->decode = decode39;
q->free = free39;
if (q->tail_biting) {
fprintf(stderr,
"Error: Tailbitting not supported in 1/3 K=9 decoder\n");
return -1;
}
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if ((q->ptr = create_viterbi39_port(poly, framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n");
free39(q);
return -1;
} else {
return 0;
}
q->K = 9;
q->R = 3;
q->framebits = framebits;
q->tail_biting = tail_biting;
q->decode = decode39;
q->free = free39;
if (q->tail_biting) {
fprintf(stderr,
"Error: Tailbitting not supported in 1/3 K=9 decoder\n");
return -1;
}
q->symbols_uc = malloc(3 * (q->framebits + q->K - 1) * sizeof(char));
if (!q->symbols_uc) {
perror("malloc");
return -1;
}
if ((q->ptr = create_viterbi39_port(poly, framebits)) == NULL) {
fprintf(stderr, "create_viterbi37 failed\n");
free39(q);
return -1;
} else {
return 0;
}
}
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3],
int max_frame_length, bool tail_bitting) {
switch (type) {
case viterbi_37:
return init37(q, poly, max_frame_length, tail_bitting);
case viterbi_39:
return init39(q, poly, max_frame_length, tail_bitting);
default:
fprintf(stderr, "Decoder not implemented\n");
return -1;
}
int max_frame_length, bool tail_bitting) {
switch (type) {
case viterbi_37:
return init37(q, poly, max_frame_length, tail_bitting);
case viterbi_39:
return init39(q, poly, max_frame_length, tail_bitting);
default:
fprintf(stderr, "Decoder not implemented\n");
return -1;
}
}
void viterbi_free(viterbi_t *q) {
q->free(q);
q->free(q);
}
/* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) {
int len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (q->tail_biting) {
len = 3 * frame_length;
} else {
len = 3 * (frame_length + q->K - 1);
}
vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len);
return q->decode(q, q->symbols_uc, data, frame_length);
int len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
return -1;
}
if (q->tail_biting) {
len = 3 * frame_length;
} else {
len = 3 * (frame_length + q->K - 1);
}
vec_quant_fuc(symbols, q->symbols_uc, 32, 127.5, 255, len);
return q->decode(q, q->symbols_uc, data, frame_length);
}
int viterbi_decode_uc(viterbi_t *q, unsigned char *symbols, char *data,
int frame_length) {
return q->decode(q, symbols, data, frame_length);
int frame_length) {
return q->decode(q, symbols, data, frame_length);
}
int viterbi_initialize(viterbi_hl* h) {
int poly[3];
viterbi_type_t type;
if (h->init.rate == 2) {
if (h->init.constraint_length == 7) {
type = viterbi_27;
} else if (h->init.constraint_length == 9) {
type = viterbi_29;
} else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length);
return -1;
}
} else if (h->init.rate == 3) {
if (h->init.constraint_length == 7) {
type = viterbi_37;
} else if (h->init.constraint_length == 9) {
type = viterbi_39;
} else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length);
return -1;
}
} else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length);
return -1;
}
poly[0] = h->init.generator_0;
poly[1] = h->init.generator_1;
poly[2] = h->init.generator_2;
return viterbi_init(&h->obj, type, poly, h->init.frame_length,
h->init.tail_bitting ? true : false);
int poly[3];
viterbi_type_t type;
if (h->init.rate == 2) {
if (h->init.constraint_length == 7) {
type = viterbi_27;
} else if (h->init.constraint_length == 9) {
type = viterbi_29;
} else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length);
return -1;
}
} else if (h->init.rate == 3) {
if (h->init.constraint_length == 7) {
type = viterbi_37;
} else if (h->init.constraint_length == 9) {
type = viterbi_39;
} else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length);
return -1;
}
} else {
fprintf(stderr, "Unsupported decoder %d/%d\n", h->init.rate,
h->init.constraint_length);
return -1;
}
poly[0] = h->init.generator_0;
poly[1] = h->init.generator_1;
poly[2] = h->init.generator_2;
return viterbi_init(&h->obj, type, poly, h->init.frame_length,
h->init.tail_bitting ? true : false);
}
int viterbi_work(viterbi_hl* hl) {
if (hl->in_len != hl->init.frame_length) {
fprintf(stderr, "Expected input length %d but got %d\n",
hl->init.frame_length, hl->in_len);
return -1;
}
return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length);
if (hl->in_len != hl->init.frame_length) {
fprintf(stderr, "Expected input length %d but got %d\n",
hl->init.frame_length, hl->in_len);
return -1;
}
return viterbi_decode_f(&hl->obj, hl->input, hl->output, hl->init.frame_length);
}
int viterbi_stop(viterbi_hl* h) {
viterbi_free(&h->obj);
return 0;
viterbi_free(&h->obj);
return 0;
}

@ -10,117 +10,117 @@
#include <limits.h>
typedef union {
unsigned int w[64];
unsigned int w[64];
} metric_t;
typedef union {
unsigned long w[2];
unsigned long w[2];
} decision_t;
static union {
unsigned char c[128];
unsigned char c[128];
} Branchtab37[3];
/* 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 */
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 & 255] = 0; /* Bias known start state */
}
return 0;
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 & 255] = 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;
}
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) {
struct v37 *vp;
struct v37 *vp;
set_viterbi37_polynomial_port(polys);
set_viterbi37_polynomial_port(polys);
if ((vp = (struct v37 *) malloc(sizeof(struct v37))) == NULL)
return NULL ;
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, 0);
if ((vp->decisions = (decision_t *) malloc((len + 6) * sizeof(decision_t)))
== NULL) {
free(vp);
return NULL ;
}
init_viterbi37_port(vp, 0);
return vp;
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 %= 64;
endstate <<= 2;
/* 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;
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 %= 64;
endstate <<= 2;
/* 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;
struct v37 *vp = p;
if (vp != NULL) {
free(vp->decisions);
free(vp);
}
if (vp != NULL) {
free(vp->decisions);
free(vp);
}
}
/* C-language butterfly */
@ -146,44 +146,44 @@ unsigned int metric,m0,m1,decision;\
*/
int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) {
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;
int i;
d->w[0] = d->w[1] = 0;
sym0 = *syms++;
sym1 = *syms++;
sym2 = *syms++;
k++;
for (i = 0; i < 32; i++)
BFLY(i);
d++;
tmp = vp->old_metrics;
vp->old_metrics = vp->new_metrics;
vp->new_metrics = tmp;
}
if (best_state) {
int i, bst=0;
unsigned int minmetric=UINT_MAX;
for (i=0;i<64;i++) {
if (vp->old_metrics->w[i] < minmetric) {
bst = i;
minmetric = vp->old_metrics->w[i];
}
}
*best_state = bst;
}
vp->dp = d;
return 0;
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;
int i;
d->w[0] = d->w[1] = 0;
sym0 = *syms++;
sym1 = *syms++;
sym2 = *syms++;
k++;
for (i = 0; i < 32; i++)
BFLY(i);
d++;
tmp = vp->old_metrics;
vp->old_metrics = vp->new_metrics;
vp->new_metrics = tmp;
}
if (best_state) {
int i, bst=0;
unsigned int minmetric=UINT_MAX;
for (i=0;i<64;i++) {
if (vp->old_metrics->w[i] < minmetric) {
bst = i;
minmetric = vp->old_metrics->w[i];
}
}
*best_state = bst;
}
vp->dp = d;
return 0;
}

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

Loading…
Cancel
Save