Merge pull request #8 from libLTE/master

Merge from main repo
master
suttonpd 11 years ago
commit 60456d29bd

@ -78,6 +78,9 @@ 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")
# IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=implicit-function-declaration -Wno-error=unused-but-set-variable")
# ENDIF(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
IF(NOT WIN32)
ADD_CXX_COMPILER_FLAG_IF_AVAILABLE(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN)
ENDIF(NOT WIN32)

@ -11,15 +11,15 @@ Current Status
===============
The following parts are available:
* Physical Broadcast channel (PBCH) eNodeB and UE part. The UE supports multi-antenna transmitters
* Physical Channels: PBCH, PCFICH, PDCCH, PHICH, PDSCH eNodeB and UE side
* Synchronization and CFO estimation/correction
* Equalization
* UE receiver verified with live LTE signals
* UE receiver (MIB + SIB1 decoding) verified with live LTE signals
Hardware
========
The library currently uses Ettus Universal Hardware Driver (UHD). Thus, any hardware supported by UHD can be used. There is no sampling rate conversion, therefore the hardware should support 30.72 MHz clock in order to work correctly with LTE sampling frequencies and decode signals from live LTE base stations.
The library currently uses Ettus Universal Hardware Driver (UHD). Thus, any hardware supported by UHD can be used. There is no sampling rate conversion, therefore the hardware should support 30.72 MHz clock in order to work correctly with LTE sampling frequencies and decode signals from live LTE base stations. We are using the B210 USRP.
Download & Install Instructions
@ -50,12 +50,12 @@ PHY Examples
Setup one or two computers connected to two USRP or UHD-compatible hardware. From the eNodeB, type
```
lte/phy/examples/pbch_enodeb -f [frequency_in_Hz] -c [cell_id] [-a [UHD args]] [-h for more commands]
lte/phy/examples/pdsch_enodeb -f [frequency_in_Hz] -c [cell_id] [-a [UHD args]] [-h for more commands]
```
From the UE, type
```
lte/phy/examples/pbch_ue -f [frequency_in_Hz] -c [cell_id] [-a [UHD args]] [-h for more commands]
lte/phy/examples/pdsch_ue -f [frequency_in_Hz] [-a [UHD args]] [-h for more commands]
```
And the output should look something like the following video. In this example, we removed the transmitter and receiver antennas in the middle of the demonstration, showing how reception is still possible (despite with some erros).
@ -65,17 +65,26 @@ https://www.dropbox.com/s/txh1nuzdb0igq5n/demo_pbch.ogv
![Screenshopt of the PBCH example output](pbch_capture.png "Screenshopt of the PBCH example output")
The SIB1 message is decoded and shown on the console, for example:
```
Decoded SIB1 Message: [40 48 50 03 02 0b 14 4a 30 18 28 20 90 81 84 79 a0 00 ];
```
Then, you can use any ASN.1 SIB decoder to read the message. This site http://www.marben-products.com/asn.1/services/decoder-asn1-lte.html is a good example.
If you don't have a pair of USRP, you can also test the demo by writing the samples to a file and then reading them:
From the eNodeB, type
```
lte/phy/examples/pbch_enodeb -o [output_file] -c [cell_id] [-h for more commands]
lte/phy/examples/pdsch_enodeb -o [output_file] -c [cell_id] [-h for more commands]
```
From the UE, type
```
lte/phy/examples/pbch_ue -i [input_file] -c [cell_id] [-h for more commands]
lte/phy/examples/pdsch_ue -i [input_file] -c [cell_id] [-h for more commands]
```

@ -31,10 +31,49 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_conjugate_32fc HAVE_VOLK_CONJ_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_32fc HAVE_VOLK_MULT2_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_multiply_conjugate_32fc HAVE_VOLK_MULT2_CONJ_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_multiply_32fc HAVE_VOLK_MULT_REAL_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_conjugate_dot_prod_32fc HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION)
CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION)
SET(VOLK_DEFINITIONS "HAVE_VOLK")
IF(${HAVE_VOLK_MAX_ABS_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_SQUARE_DIST_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SQUARE_DIST_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_CONVERT_FI_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_CONVERT_FI_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAX_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_FUNCTION")
ENDIF()
@ -50,10 +89,27 @@ ENDIF()
IF(${HAVE_VOLK_MULT2_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT_FLOAT_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_FLOAT_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MULT_REAL_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT_REAL_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_MAG_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAG_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DIVIDE_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DIVIDE_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DOTPROD_FC_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_FC_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_DOTPROD_F_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_F_FUNCTION")
ENDIF()
IF(${HAVE_VOLK_ATAN_FUNCTION})
SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ATAN_FUNCTION")
ENDIF()
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(VOLK DEFAULT_MSG VOLK_LIBRARIES VOLK_INCLUDE_DIRS)
MARK_AS_ADVANCED(VOLK_LIBRARIES VOLK_INCLUDE_DIRS VOLK_DEFINITIONS)

@ -31,26 +31,65 @@
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include "liblte/config.h"
#include "liblte/cuhd/cuhd_utils.h"
LIBLTE_API int cuhd_open(char *args, void **handler);
LIBLTE_API int cuhd_open(char *args,
void **handler);
LIBLTE_API int cuhd_close(void *h);
LIBLTE_API int cuhd_start_rx_stream(void *h);
LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, int nsamples);
LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h,
uint32_t nsamples);
LIBLTE_API int cuhd_stop_rx_stream(void *h);
LIBLTE_API void cuhd_flush_buffer(void *h);
LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h);
LIBLTE_API double cuhd_set_rx_srate(void *h, double freq);
LIBLTE_API double cuhd_set_rx_gain(void *h, double gain);
LIBLTE_API double cuhd_set_rx_freq(void *h, double freq);
LIBLTE_API int cuhd_recv(void *h, void *data, int nsamples, int blocking);
LIBLTE_API double cuhd_set_tx_srate(void *h, double freq);
LIBLTE_API double cuhd_set_tx_gain(void *h, double gain);
LIBLTE_API double cuhd_set_tx_freq(void *h, double freq);
LIBLTE_API int cuhd_send(void *h, void *data, int nsamples, int blocking);
LIBLTE_API double cuhd_set_rx_srate(void *h,
double freq);
LIBLTE_API double cuhd_set_rx_gain(void *h,
double gain);
LIBLTE_API double cuhd_set_rx_freq(void *h,
double freq);
LIBLTE_API double cuhd_set_rx_freq_offset(void *h,
double freq,
double off);
LIBLTE_API int cuhd_recv(void *h,
void *data,
uint32_t nsamples,
bool blocking);
LIBLTE_API int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
bool blocking,
time_t *secs,
double *frac_secs);
LIBLTE_API double cuhd_set_tx_srate(void *h,
double freq);
LIBLTE_API double cuhd_set_tx_gain(void *h,
double gain);
LIBLTE_API double cuhd_set_tx_freq(void *h,
double freq);
LIBLTE_API int cuhd_send(void *h,
void *data,
uint32_t nsamples,
bool blocking);
#ifdef __cplusplus

@ -34,8 +34,10 @@
#include "cuhd_handler.hpp"
#include "liblte/cuhd/cuhd.h"
//#define METADATA_VERBOSE
void my_handler(uhd::msg::type_t type, const std::string &msg){
void my_handler(uhd::msg::type_t type, const std::string & msg)
{
//handle the message...
}
@ -46,15 +48,17 @@ typedef _Complex float complex_t;
bool isLocked(void *h)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
std::vector<std::string> mb_sensors = handler->usrp->get_mboard_sensor_names();
std::vector<std::string> rx_sensors = handler->usrp->get_rx_sensor_names(0);
if(std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") != rx_sensors.end()) {
std::vector < std::string > mb_sensors =
handler->usrp->get_mboard_sensor_names();
std::vector < std::string > rx_sensors =
handler->usrp->get_rx_sensor_names(0);
if (std::find(rx_sensors.begin(), rx_sensors.end(), "lo_locked") !=
rx_sensors.end()) {
return handler->usrp->get_rx_sensor("lo_locked", 0).to_bool();
}
else if(std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") != mb_sensors.end()) {
} else if (std::find(mb_sensors.begin(), mb_sensors.end(), "ref_locked") !=
mb_sensors.end()) {
return handler->usrp->get_mboard_sensor("ref_locked", 0).to_bool();
}
else {
} else {
usleep(500);
return true;
}
@ -64,15 +68,15 @@ bool cuhd_rx_wait_lo_locked(void *h)
{
double report = 0.0;
while(isLocked(h) && report < 3.0)
{
while (isLocked(h) && report < 3.0) {
report += 0.1;
usleep(1000);
}
return isLocked(h);
}
int cuhd_start_rx_stream(void *h) {
int cuhd_start_rx_stream(void *h)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
cmd.time_spec = handler->usrp->get_time_now();
@ -81,7 +85,8 @@ int cuhd_start_rx_stream(void *h) {
return 0;
}
int cuhd_stop_rx_stream(void *h) {
int cuhd_stop_rx_stream(void *h)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
cmd.time_spec = handler->usrp->get_time_now();
@ -90,7 +95,17 @@ int cuhd_stop_rx_stream(void *h) {
return 0;
}
int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
void cuhd_flush_buffer(void *h)
{
int n;
_Complex float tmp[1024];
do {
n = cuhd_recv(h, tmp, 1024, 0);
} while (n > 0);
}
int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::stream_cmd_t cmd(uhd::stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE);
cmd.time_spec = handler->usrp->get_time_now();
@ -100,14 +115,13 @@ int cuhd_start_rx_stream_nsamples(void *h, int nsamples) {
return 0;
}
int cuhd_open(char *args, void **h) {
int cuhd_open(char *args, void **h)
{
cuhd_handler *handler = new cuhd_handler();
std::string _args = std::string(args);
handler->usrp = uhd::usrp::multi_usrp::make(_args);
// Try to set LTE clock
handler->usrp->set_master_clock_rate(30720000);
handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000" + ", num_recv_frames=512");
// handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512");
handler->usrp->set_clock_source("internal");
std::string otw, cpu;
@ -122,33 +136,44 @@ int cuhd_open(char *args, void **h) {
return 0;
}
int cuhd_close(void *h) {
int cuhd_close(void *h)
{
cuhd_stop_rx_stream(h);
/** Something else to close the USRP?? */
return 0;
}
double cuhd_set_rx_srate(void *h, double freq) {
double cuhd_set_rx_srate(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_rx_rate(freq);
double ret = handler->usrp->get_rx_rate();
return ret;
}
double cuhd_set_rx_gain(void *h, double gain) {
double cuhd_set_rx_gain(void *h, double gain)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_rx_gain(gain);
return handler->usrp->get_rx_gain();
}
double cuhd_set_rx_freq(void *h, double freq) {
double cuhd_set_rx_freq(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_rx_freq(freq);
return handler->usrp->get_rx_freq();
}
int cuhd_recv(void *h, void *data, int nsamples, int blocking) {
double cuhd_set_rx_freq_offset(void *h, double freq, double off) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
handler->usrp->set_rx_freq(uhd::tune_request_t(freq,off));
return handler->usrp->get_rx_freq();
}
int cuhd_recv(void *h, void *data, uint32_t nsamples, bool blocking)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::rx_metadata_t md;
if (blocking) {
@ -160,6 +185,11 @@ int cuhd_recv(void *h, void *data, int nsamples, int blocking) {
return -1;
}
n += p;
#ifdef METADATA_VERBOSE
if (md.error_code != uhd::rx_metadata_t::ERROR_CODE_NONE) {
std::cout << "\nError code: " << md.to_pp_string() << "\n\n";
}
#endif
} while (n < nsamples);
return nsamples;
} else {
@ -167,25 +197,64 @@ int cuhd_recv(void *h, void *data, int nsamples, int blocking) {
}
}
double cuhd_set_tx_gain(void *h, double gain) {
int cuhd_recv_timed(void *h,
void *data,
uint32_t nsamples,
int blocking,
time_t *secs,
double *frac_secs) {
cuhd_handler* handler = static_cast<cuhd_handler*>(h);
uhd::rx_metadata_t md;
*secs = -1;
*frac_secs = -1;
int p;
if (blocking) {
int n=0;
complex_t *data_c = (complex_t*) data;
do {
p=handler->rx_stream->recv(&data_c[n], nsamples-n, md);
if (p == -1) {
return -1;
}
if(*secs < 0){
*secs = md.time_spec.get_full_secs();
*frac_secs = md.time_spec.get_frac_secs();
}
n+=p;
} while(n<nsamples);
return n;
} else {
p = handler->rx_stream->recv(data, nsamples, md, 0.0);
*secs = md.time_spec.get_full_secs();
*frac_secs = md.time_spec.get_frac_secs();
return p;
}
}
double cuhd_set_tx_gain(void *h, double gain)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_gain(gain);
return handler->usrp->get_tx_gain();
}
double cuhd_set_tx_srate(void *h, double freq) {
double cuhd_set_tx_srate(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_rate(freq);
return handler->usrp->get_tx_rate();
}
double cuhd_set_tx_freq(void *h, double freq) {
double cuhd_set_tx_freq(void *h, double freq)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
handler->usrp->set_tx_freq(freq);
return handler->usrp->get_tx_freq();
}
int cuhd_send(void *h, void *data, int nsamples, int blocking) {
int cuhd_send(void *h, void *data, uint32_t nsamples, bool blocking)
{
cuhd_handler *handler = static_cast < cuhd_handler * >(h);
uhd::tx_metadata_t md;
if (blocking) {

@ -46,7 +46,7 @@ int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double f
goto free_and_exit;
}
cuhd_set_rx_gain(uhd, 0.0);
cuhd_set_rx_gain(uhd, 20.0);
cuhd_set_rx_srate(uhd, fs);
for (i=0;i<nof_bands;i++) {
@ -55,7 +55,7 @@ int cuhd_rssi_scan(void *uhd, float *freqs, float *rssi, int nof_bands, double f
f = (double) freqs[i];
cuhd_set_rx_freq(uhd, f);
cuhd_rx_wait_lo_locked(uhd);
usleep(10000);
cuhd_start_rx_stream(uhd);
/* discard first samples */

@ -51,26 +51,26 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
# These two can be compiled without UHD or graphics support
#################################################################
add_executable(pbch_ue pbch_ue.c)
target_link_libraries(pbch_ue lte_phy)
add_executable(pdsch_ue pdsch_ue.c iodev.c cell_search_utils.c)
target_link_libraries(pdsch_ue lte_phy)
add_executable(pbch_enodeb pbch_enodeb.c)
target_link_libraries(pbch_enodeb lte_phy)
add_executable(pdsch_enodeb pdsch_enodeb.c)
target_link_libraries(pdsch_enodeb lte_phy)
IF(${CUHD_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_UHD")
ELSE(${CUHD_FIND} EQUAL -1)
target_link_libraries(pbch_ue cuhd)
target_link_libraries(pbch_enodeb cuhd)
target_link_libraries(pdsch_ue cuhd)
target_link_libraries(pdsch_enodeb cuhd)
ENDIF(${CUHD_FIND} EQUAL -1)
IF(${GRAPHICS_FIND} EQUAL -1)
SET_TARGET_PROPERTIES(pbch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pbch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pdsch_ue PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
SET_TARGET_PROPERTIES(pdsch_enodeb PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS")
ELSE(${GRAPHICS_FIND} EQUAL -1)
target_link_libraries(pbch_ue graphics)
target_link_libraries(pbch_enodeb graphics)
target_link_libraries(pdsch_ue graphics)
target_link_libraries(pdsch_enodeb graphics)
ENDIF(${GRAPHICS_FIND} EQUAL -1)
@ -81,14 +81,8 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1)
add_executable(scan_rssi scan_rssi.c)
target_link_libraries(scan_rssi lte_phy cuhd )
add_executable(scan_pss scan_pss.c)
target_link_libraries(scan_pss lte_phy cuhd )
add_executable(scan_mib scan_mib.c)
target_link_libraries(scan_mib lte_phy cuhd )
add_executable(cell_search cell_search.c cell_search_utils.c)
target_link_libraries(cell_search lte_phy cuhd )
MESSAGE(STATUS " UHD examples will be installed.")

@ -0,0 +1,203 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#include "cell_search_utils.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
#endif
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define MAX_EARFCN 1000
int band = -1;
int earfcn_start=-1, earfcn_end = -1;
int nof_frames_total = 50;
int nof_frames_detected = 10;
float threshold = CS_FIND_THRESHOLD;
float uhd_gain = 60.0;
char *uhd_args="";
void usage(char *prog) {
printf("Usage: %s [agsendtvb] -b band\n", prog);
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD gain [Default %.2f dB]\n", uhd_gain);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-n nof_frames_total [Default 100]\n");
printf("\t-d nof_frames_detected [Default 10]\n");
printf("\t-t threshold [Default %.2f]\n",threshold);
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(int argc, char **argv) {
int opt;
while ((opt = getopt(argc, argv, "agsendtvb")) != -1) {
switch(opt) {
case 'a':
uhd_args = argv[optind];
break;
case 'b':
band = atoi(argv[optind]);
break;
case 's':
earfcn_start = atoi(argv[optind]);
break;
case 'e':
earfcn_end = atoi(argv[optind]);
break;
case 'n':
nof_frames_total = atoi(argv[optind]);
break;
case 'd':
nof_frames_detected = atoi(argv[optind]);
break;
case 't':
threshold = atof(argv[optind]);
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'v':
verbose++;
break;
default:
usage(argv[0]);
exit(-1);
}
}
if (band == -1) {
usage(argv[0]);
exit(-1);
}
}
int main(int argc, char **argv) {
int n;
void *uhd;
ue_celldetect_t s;
ue_celldetect_result_t found_cells[3];
cf_t *buffer;
int nof_freqs;
lte_earfcn_t channels[MAX_EARFCN];
uint32_t freq;
pbch_mib_t mib;
parse_args(argc, argv);
printf("Opening UHD device...\n");
if (cuhd_open(uhd_args, &uhd)) {
fprintf(stderr, "Error opening uhd\n");
exit(-1);
}
cuhd_set_rx_gain(uhd, uhd_gain);
nof_freqs = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN);
if (nof_freqs < 0) {
fprintf(stderr, "Error getting EARFCN list\n");
exit(-1);
}
buffer = vec_malloc(sizeof(cf_t) * 96000);
if (!buffer) {
perror("malloc");
return LIBLTE_ERROR;
}
if (ue_celldetect_init(&s)) {
fprintf(stderr, "Error initiating UE sync module\n");
exit(-1);
}
if (threshold > 0) {
ue_celldetect_set_threshold(&s, threshold);
}
if (nof_frames_total > 0) {
ue_celldetect_set_nof_frames_total(&s, nof_frames_total);
}
if (nof_frames_detected > 0) {
ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected);
}
for (freq=0;freq<nof_freqs;freq+=10) {
/* set uhd_freq */
cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ);
cuhd_rx_wait_lo_locked(uhd);
usleep(10000);
INFO("Set uhd_freq to %.3f MHz\n", (double) channels[freq].fd * MHZ/1000000);
printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz looking for PSS. \r", freq, nof_freqs,
channels[freq].id, channels[freq].fd);fflush(stdout);
if (VERBOSE_ISINFO()) {
printf("\n");
}
n = find_cell(uhd, &s, buffer, found_cells);
if (n < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
if (n == CS_CELL_DETECTED) {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > threshold/2) {
if (decode_pbch(uhd, buffer, &found_cells[i], nof_frames_total, &mib)) {
fprintf(stderr, "Error decoding PBCH\n");
exit(-1);
}
}
}
}
}
ue_celldetect_free(&s);
cuhd_close(uhd);
exit(0);
}

@ -0,0 +1,157 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib)
{
ue_mib_t uemib;
int n;
bzero(mib, sizeof(pbch_mib_t));
uint32_t nof_frames = 0;
uint32_t flen = MIB_FRAME_SIZE;
if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) {
fprintf(stderr, "Error initiating PBCH decoder\n");
return LIBLTE_ERROR;
}
INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0);
cuhd_set_rx_srate(uhd, 1920000.0);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
}
INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total);
n = ue_mib_decode(&uemib, buffer, flen, mib);
if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) {
fprintf(stderr, "Error calling ue_mib_decode()\n");
return LIBLTE_ERROR;
}
if (n == MIB_FRAME_UNALIGNED) {
printf("Realigning frame\n");
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
}
}
nof_frames++;
} while (n != MIB_FOUND && nof_frames < 2*nof_frames_total);
if (n == MIB_FOUND) {
printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames);
pbch_mib_fprint(stdout, mib, found_cell->cell_id);
} else {
printf("\nCould not decode MIB\n");
}
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
ue_mib_free(&uemib);
return LIBLTE_SUCCESS;
}
int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3])
{
int n;
INFO("Setting sampling frequency 960 KHz for PSS search\n", 0);
cuhd_set_rx_srate(uhd, 960000.0);
INFO("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd);
uint32_t nof_scanned_cells = 0;
uint32_t flen = 4800;
int nof_detected_cells = 0;
do {
if (cuhd_recv(uhd, buffer, flen, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
}
n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]);
switch(n) {
case CS_FRAME_UNALIGNED:
printf("Realigning frame\n");
if (cuhd_recv(uhd, buffer, flen/2, 1)<0) {
fprintf(stderr, "Error receiving from USRP\n");
return LIBLTE_ERROR;
}
return LIBLTE_ERROR;
case CS_CELL_DETECTED:
nof_detected_cells++;
if (found_cell[nof_scanned_cells].peak > 0) {
printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n",
found_cell[nof_scanned_cells].cell_id,
lte_cp_string(found_cell[nof_scanned_cells].cp),
found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode,
s->nof_frames_detected);
}
nof_scanned_cells++;
break;
case CS_CELL_NOT_DETECTED:
nof_scanned_cells++;
break;
case LIBLTE_ERROR:
case LIBLTE_ERROR_INVALID_INPUTS:
fprintf(stderr, "Error calling cellsearch_scan()\n");
return LIBLTE_ERROR;
}
} while(nof_scanned_cells < 3);
INFO("Stopping receiver...\n", 0);
cuhd_stop_rx_stream(uhd);
cuhd_flush_buffer(uhd);
return nof_detected_cells;
}
#endif

@ -0,0 +1,40 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "liblte/phy/phy.h"
int decode_pbch(void *uhd,
cf_t *buffer,
ue_celldetect_result_t *found_cell,
uint32_t nof_frames_total,
pbch_mib_t *mib);
int find_cell(void *uhd,
ue_celldetect_t *s,
cf_t *buffer,
ue_celldetect_result_t found_cell[3]);

@ -0,0 +1,254 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "iodev.h"
#include "liblte/phy/io/filesource.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
#endif
#include "cell_search_utils.h"
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples);
return cuhd_recv(h, data, nsamples, 1);
}
/* Setup USRP or input file */
int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mib) {
if (config->input_file_name) {
mib->phich_resources = R_1;
mib->phich_length = PHICH_NORM;
cell->id = config->cell_id_file;
cell->cp = CPNORM;
cell->nof_ports = config->nof_ports_file;
cell->nof_prb = config->nof_prb_file;
if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) {
return LIBLTE_ERROR;
}
q->mode = FILESOURCE;
int symbol_sz = lte_symbol_sz(cell->nof_prb);
if (symbol_sz > 0) {
q->sf_len = SF_LEN(symbol_sz);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
q->input_buffer_file = vec_malloc(q->sf_len * sizeof(cf_t));
if (!q->input_buffer_file) {
perror("malloc");
return LIBLTE_ERROR;
}
q->sf_idx = 9;
} else {
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open(config->uhd_args, &q->uhd)) {
fprintf(stderr, "Error opening uhd\n");
return LIBLTE_ERROR;
}
cuhd_set_rx_gain(q->uhd, config->uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq);
cuhd_rx_wait_lo_locked(q->uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq);
int n;
ue_celldetect_t cd;
ue_celldetect_result_t found_cells[3];
cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000);
if (!buffer) {
perror("malloc");
return LIBLTE_ERROR;
}
if (ue_celldetect_init(&cd)) {
fprintf(stderr, "Error initiating UE cell detect\n");
exit(-1);
}
n = find_cell(q->uhd, &cd, buffer, found_cells);
if (n < 0) {
fprintf(stderr, "Error searching cell\n");
exit(-1);
}
int max_peak_cell = 0;
float max_peak_value = -1.0;
if (n > 0) {
for (int i=0;i<3;i++) {
if (found_cells[i].peak > max_peak_value) {
max_peak_value = found_cells[i].peak;
max_peak_cell = i;
}
}
if (decode_pbch(q->uhd, buffer, &found_cells[max_peak_cell], 400, mib)) {
fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", found_cells[max_peak_cell].cell_id);
return LIBLTE_ERROR;
}
} else {
fprintf(stderr, "Could not find any cell in this frequency\n");
return LIBLTE_ERROR;
}
free(buffer);
cell->cp = found_cells[max_peak_cell].cp;
cell->id = found_cells[max_peak_cell].cell_id;
cell->nof_prb = mib->nof_prb;
cell->nof_ports = mib->nof_ports;
/* set sampling frequency */
int srate = lte_sampling_freq_hz(cell->nof_prb);
if (srate != -1) {
cuhd_set_rx_srate(q->uhd, (double) srate);
} else {
fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb);
return LIBLTE_ERROR;
}
DEBUG("Starting receiver...\n", 0);
cuhd_start_rx_stream(q->uhd);
if (ue_sync_init(&q->sframe, *cell, cuhd_recv_wrapper, q->uhd)) {
fprintf(stderr, "Error initiating ue_sync\n");
return LIBLTE_ERROR;
}
/* Decodes the SSS signal during the tracking phase. Extra overhead, but makes sure we are in the correct subframe */
ue_sync_decode_sss_on_track(&q->sframe, true);
// Here, the subframe length and input buffer is managed by ue_sync
q->mode = UHD;
#else
printf("Error UHD not available. Select an input file\n");
return LIBLTE_ERROR;
#endif
}
memcpy(&q->config, config, sizeof(iodev_cfg_t));
return LIBLTE_SUCCESS;
}
void iodev_free(iodev_t *q) {
if (q->mode == FILESOURCE) {
filesource_free(&q->fsrc);
} else {
#ifndef DISABLE_UHD
cuhd_close(q->uhd);
#endif
}
}
/* Receive samples from the USRP or read from file */
int iodev_receive(iodev_t *q, cf_t **buffer) {
int n;
if (q->mode == FILESOURCE) {
INFO(" ----- READING %d SAMPLES ---- \n", q->sf_len);
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
*buffer = q->input_buffer_file;
if (n == -1) {
fprintf(stderr, "Error reading file\n");
/* wrap file if arrive to end */
} else if (n < q->sf_len) {
DEBUG("Read %d from file. Seeking to 0\n",n);
filesource_seek(&q->fsrc, 0);
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
if (n == -1) {
fprintf(stderr, "Error reading file\n");
/* wrap file if arrive to end */
} else {
n = 1;
}
} else {
n = 1;
}
q->sf_idx++;
if (q->sf_idx == 10) {
q->sf_idx = 0;
}
usleep(5000);
} else {
/* Use ue_sync_work which returns a synchronized buffer of subframe samples */
#ifndef DISABLE_UHD
n = ue_sync_get_buffer(&q->sframe, buffer);
if (n < 0) {
fprintf(stderr, "Error calling ue_sync_work()\n");
}
#endif
}
return n;
}
void* iodev_get_cuhd(iodev_t *q) {
if (q->mode == UHD) {
return q->uhd;
} else {
return NULL;
}
}
bool iodev_isfile(iodev_t *q) {
return q->mode == FILESOURCE;
}
bool iodev_isUSRP(iodev_t *q) {
return q->mode == UHD;
}
uint32_t iodev_get_sfidx(iodev_t *q) {
if (iodev_isfile(q)) {
return q->sf_idx;
} else {
return ue_sync_get_sfidx(&q->sframe);
}
}

@ -0,0 +1,99 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef IODEF_H
#define IODEF_H
#include "liblte/config.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/io/filesource.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
#endif
/*********
*
* This component is a wrapper to the cuhd or filesource modules. It uses
* sync_frame_t to read aligned subframes from the USRP or filesource to read
* subframes from a file.
*
* When created, it starts receiving/reading at 1.92 MHz. The sampling frequency
* can then be changed using iodev_set_srate()
*/
typedef enum LIBLTE_API {FILESOURCE, UHD} iodev_mode_t;
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
char *input_file_name;
uint32_t cell_id_file;
uint32_t nof_prb_file;
uint32_t nof_ports_file;
float uhd_freq;
float uhd_gain;
char *uhd_args;
float find_threshold;
} iodev_cfg_t;
typedef struct LIBLTE_API {
#ifndef DISABLE_UHD
void *uhd;
ue_sync_t sframe;
#endif
uint32_t sf_len;
uint32_t sf_idx;
cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t
filesource_t fsrc;
iodev_cfg_t config;
iodev_mode_t mode;
} iodev_t;
LIBLTE_API int iodev_init(iodev_t *q,
iodev_cfg_t *config,
lte_cell_t *cell,
pbch_mib_t *mib);
LIBLTE_API void iodev_free(iodev_t *q);
LIBLTE_API int iodev_receive(iodev_t *q,
cf_t **buffer);
LIBLTE_API void* iodev_get_cuhd(iodev_t *q);
LIBLTE_API uint32_t iodev_get_sfidx(iodev_t *q);
LIBLTE_API bool iodev_isfile(iodev_t *q);
LIBLTE_API bool iodev_isUSRP(iodev_t *q);
#endif

@ -1,283 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
void *uhd;
#endif
char *output_file_name = NULL;
int nof_frames=-1;
int cell_id = 1;
int nof_prb = 6;
char *uhd_args = "";
float uhd_amp=0.25, uhd_gain=10.0, uhd_freq=2400000000;
filesink_t fsink;
lte_fft_t ifft;
pbch_t pbch;
cf_t *slot_buffer = NULL, *output_buffer = NULL;
int slot_n_re, slot_n_samples;
#define UHD_SAMP_FREQ 1920000
void usage(char *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);
#else
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");
}
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);
}
}
#ifdef DISABLE_UHD
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 {
#ifndef DISABLE_UHD
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);
#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);
}
}
void base_free() {
pbch_free(&pbch);
lte_ifft_free(&ifft);
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);
#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];
#ifdef DISABLE_UHD
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
#endif
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));
/* 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 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;
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);
}
#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 {
#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);
#endif
}
}
mib.sfn=(mib.sfn+1)%1024;
printf("SFN: %4d\r", mib.sfn);fflush(stdout);
nf++;
}
base_free();
printf("Done\n");
exit(0);
}

@ -1,501 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/phy/phy.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
void *uhd;
#endif
#ifndef DISABLE_GRAPHICS
#include "liblte/graphics/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 NOF_PORTS 2
float find_threshold = 20.0, track_threshold = 10.0;
int max_track_lost = 20, nof_frames = -1;
int track_len=300;
char *input_file_name = NULL;
int disable_plots = 0;
int go_exit=0;
float uhd_freq = 2600000000.0, uhd_gain = 20.0;
char *uhd_args = "";
filesource_t fsrc;
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS_CTRL];
pbch_t pbch;
lte_fft_t fft;
chest_t chest;
sync_t sfind, strack;
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");
#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);
#else
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);
#ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n");
#else
printf("\t plots are disabled. Graphics library not available\n");
#endif
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(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);
}
}
}
#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);
}
#endif
int base_init(int frame_length) {
int i;
#ifndef DISABLE_GRAPHICS
if (!disable_plots) {
init_plots();
}
#else
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;
}
void base_free() {
int i;
if (input_file_name) {
filesource_free(&fsrc);
} else {
#ifndef DISABLE_UHD
cuhd_close(uhd);
#endif
}
#ifndef DISABLE_GRAPHICS
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]);
}
}
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;
}
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
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);
}
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);
}
}
#endif
return n;
}
void sigintHandler(int sig_num)
{
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;
#ifdef DISABLE_UHD
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);
}

@ -0,0 +1,393 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
void *uhd;
#endif
char *output_file_name = NULL;
lte_cell_t cell = {
6, // nof_prb
1, // nof_ports
1, // cell_id
CPNORM // cyclic prefix
};
uint32_t cfi=1;
uint32_t mcs_idx = 12;
int nof_frames = -1;
char *uhd_args = "";
float uhd_amp = 0.01, uhd_gain = 10.0, uhd_freq = 2400000000;
filesink_t fsink;
lte_fft_t ifft;
pbch_t pbch;
pcfich_t pcfich;
pdcch_t pdcch;
pdsch_t pdsch;
pdsch_harq_t harq_process;
regs_t regs;
cf_t *sf_buffer = NULL, *output_buffer = NULL;
int sf_n_re, sf_n_samples;
void usage(char *prog) {
printf("Usage: %s [agmfoncvp]\n", prog);
#ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-l UHD amplitude [Default %.2f]\n", uhd_amp);
printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq / 1000000);
#else
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-o output_file [Default USRP]\n");
printf("\t-m MCS index [Default %d]\n", mcs_idx);
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", cell.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, "aglfmoncpv")) != -1) {
switch (opt) {
case 'a':
uhd_args = argv[optind];
break;
case 'g':
uhd_gain = atof(argv[optind]);
break;
case 'l':
uhd_amp = atof(argv[optind]);
break;
case 'f':
uhd_freq = atof(argv[optind]);
break;
case 'o':
output_file_name = argv[optind];
break;
case 'm':
mcs_idx = atoi(argv[optind]);
break;
case 'n':
nof_frames = atoi(argv[optind]);
break;
case 'p':
cell.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);
}
#endif
}
void base_init() {
/* init memory */
sf_buffer = malloc(sizeof(cf_t) * sf_n_re);
if (!sf_buffer) {
perror("malloc");
exit(-1);
}
output_buffer = malloc(sizeof(cf_t) * sf_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);
}
#else
printf("Error UHD not available. Select an output file\n");
exit(-1);
#endif
}
/* create ifft object */
if (lte_ifft_init(&ifft, CPNORM, cell.nof_prb)) {
fprintf(stderr, "Error creating iFFT object\n");
exit(-1);
}
if (pbch_init(&pbch, cell)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
if (regs_init(&regs, R_1, PHICH_NORM, cell)) {
fprintf(stderr, "Error initiating regs\n");
exit(-1);
}
if (pcfich_init(&pcfich, &regs, cell)) {
fprintf(stderr, "Error creating PBCH object\n");
exit(-1);
}
if (regs_set_cfi(&regs, cfi)) {
fprintf(stderr, "Error setting CFI\n");
exit(-1);
}
if (pdcch_init(&pdcch, &regs, cell)) {
fprintf(stderr, "Error creating PDCCH object\n");
exit(-1);
}
if (pdsch_init(&pdsch, cell)) {
fprintf(stderr, "Error creating PDSCH object\n");
exit(-1);
}
pdsch_set_rnti(&pdsch, 1234);
if (pdsch_harq_init(&harq_process, &pdsch)) {
fprintf(stderr, "Error initiating HARQ process\n");
exit(-1);
}
}
void base_free() {
pdsch_harq_free(&harq_process);
pdsch_free(&pdsch);
pdcch_free(&pdcch);
regs_free(&regs);
pbch_free(&pbch);
lte_ifft_free(&ifft);
if (sf_buffer) {
free(sf_buffer);
}
if (output_buffer) {
free(output_buffer);
}
if (output_file_name) {
filesink_free(&fsink);
} else {
#ifndef DISABLE_UHD
cuhd_close(&uhd);
#endif
}
}
int main(int argc, char **argv) {
int nf, sf_idx, 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;
ra_pdsch_t ra_dl;
ra_prb_t prb_alloc;
refsignal_t refs[NSLOTS_X_FRAME];
int i, n;
char *data;
cf_t *sf_symbols[MAX_PORTS];
dci_msg_t dci_msg;
dci_location_t locations[NSUBFRAMES_X_FRAME][10];
#ifdef DISABLE_UHD
if (argc < 3) {
usage(argv[0]);
exit(-1);
}
#endif
parse_args(argc, argv);
N_id_2 = cell.id % 3;
sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB;
sf_n_samples = 2 * SLOT_LEN(lte_symbol_sz(cell.nof_prb));
/* 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 CRS signals */
for (i = 0; i < NSLOTS_X_FRAME; i++) {
if (refsignal_init_LTEDL(&refs[i], 0, i, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
}
mib.nof_ports = cell.nof_ports;
mib.nof_prb = cell.nof_prb;
mib.phich_length = PHICH_NORM;
mib.phich_resources = R_1;
mib.sfn = 0;
for (i = 0; i < MAX_PORTS; i++) { // now there's only 1 port
sf_symbols[i] = sf_buffer;
}
#ifndef DISABLE_UHD
if (!output_file_name) {
printf("Set TX rate: %.2f MHz\n",
cuhd_set_tx_srate(uhd, lte_sampling_freq_hz(cell.nof_prb)) / 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
bzero(&ra_dl, sizeof(ra_pdsch_t));
ra_dl.harq_process = 0;
ra_dl.mcs_idx = mcs_idx;
ra_dl.ndi = 0;
ra_dl.rv_idx = 0;
ra_dl.alloc_type = alloc_type0;
ra_dl.type0_alloc.rbg_bitmask = 0xffffffff;
dci_msg_pack_pdsch(&ra_dl, &dci_msg, Format1, cell.nof_prb, false);
ra_prb_get_dl(&prb_alloc, &ra_dl, cell.nof_prb);
ra_prb_get_re_dl(&prb_alloc, cell.nof_prb, 1, cell.nof_prb<10?(cfi+1):cfi, CPNORM);
ra_mcs_from_idx_dl(mcs_idx, cell.nof_prb, &ra_dl.mcs);
ra_pdsch_fprint(stdout, &ra_dl, cell.nof_prb);
/* Initiate valid DCI locations */
for (i=0;i<NSUBFRAMES_X_FRAME;i++) {
pdcch_ue_locations(&pdcch, locations[i], 10, i, cfi, 1234);
}
data = malloc(sizeof(char) * ra_dl.mcs.tbs);
if (!data) {
perror("malloc");
exit(-1);
}
nf = 0;
if (pdsch_harq_setup(&harq_process, ra_dl.mcs, &prb_alloc)) {
fprintf(stderr, "Error configuring HARQ process\n");
exit(-1);
}
while (nf < nof_frames || nof_frames == -1) {
for (sf_idx = 0; sf_idx < NSUBFRAMES_X_FRAME && (nf < nof_frames || nof_frames == -1); sf_idx++) {
bzero(sf_buffer, sizeof(cf_t) * sf_n_re);
if (sf_idx == 0 || sf_idx == 5) {
pss_put_slot(pss_signal, sf_buffer, cell.nof_prb, CPNORM);
sss_put_slot(sf_idx ? sss_signal5 : sss_signal0, sf_buffer, cell.nof_prb,
CPNORM);
}
if (sf_idx == 0) {
pbch_encode(&pbch, &mib, sf_symbols);
}
for (n=0;n<2;n++) {
refsignal_put(&refs[2*sf_idx+n], &sf_buffer[n*sf_n_re/2]);
}
pcfich_encode(&pcfich, cfi, sf_symbols, sf_idx);
INFO("SF: %d, Generating %d random bits\n", sf_idx, ra_dl.mcs.tbs);
for (i=0;i<ra_dl.mcs.tbs;i++) {
data[i] = rand()%2;
}
INFO("Puttting DCI to location: n=%d, L=%d\n", locations[sf_idx][0].ncce, locations[sf_idx][0].L);
if (pdcch_encode(&pdcch, &dci_msg, locations[sf_idx][0], 1234, sf_symbols, sf_idx, cfi)) {
fprintf(stderr, "Error encoding DCI message\n");
exit(-1);
}
if (pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx)) {
fprintf(stderr, "Error encoding PDSCH\n");
exit(-1);
}
/* Transform to OFDM symbols */
lte_ifft_run_sf(&ifft, sf_buffer, output_buffer);
/* send to file or usrp */
if (output_file_name) {
filesink_write(&fsink, output_buffer, sf_n_samples);
usleep(5000);
} else {
#ifndef DISABLE_UHD
vec_sc_prod_cfc(output_buffer, uhd_amp, output_buffer, sf_n_samples);
cuhd_send(uhd, output_buffer, sf_n_samples, true);
#endif
}
nf++;
}
mib.sfn = (mib.sfn + 1) % 1024;
printf("SFN: %4d\r", mib.sfn);
fflush(stdout);
}
base_free();
printf("Done\n");
exit(0);
}

@ -0,0 +1,306 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include "liblte/phy/phy.h"
#include "iodev.h"
#ifndef DISABLE_GRAPHICS
void init_plots();
void do_plots(ue_dl_t *q, uint32_t sf_idx);
#endif
int go_exit = 0;
/* Local function definitions */
void init_plots();
/**********************************************************************
* Program arguments processing
***********************************************************************/
typedef struct {
uint16_t rnti;
int nof_subframes;
bool disable_plots;
iodev_cfg_t io_config;
}prog_args_t;
void args_default(prog_args_t *args) {
args->io_config.cell_id_file = 195;
args->io_config.nof_prb_file = 50;
args->io_config.nof_ports_file = 2;
args->rnti = SIRNTI;
args->nof_subframes = -1;
args->disable_plots = false;
args->io_config.find_threshold = -1.0;
args->io_config.input_file_name = NULL;
args->io_config.uhd_args = "";
args->io_config.uhd_freq = -1.0;
args->io_config.uhd_gain = 60.0;
}
void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog);
printf("\t-c cell_id if reading from file [Default %d]\n", args->io_config.cell_id_file);
printf("\t-p nof_prb if reading from file [Default %d]\n", args->io_config.nof_prb_file);
printf("\t-o nof_ports if reading from file [Default %d]\n", args->io_config.nof_ports_file);
printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti);
#ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", args->io_config.uhd_gain);
#else
printf("\t UHD is disabled. CUHD library not available\n");
#endif
printf("\t-b Decode PBCH only [Default All channels]\n");
printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes);
printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold);
#ifndef DISABLE_GRAPHICS
printf("\t-d disable plots [Default enabled]\n");
#else
printf("\t plots are disabled. Graphics library not available\n");
#endif
printf("\t-v [set verbose to debug, default none]\n");
}
void parse_args(prog_args_t *args, int argc, char **argv) {
int opt;
args_default(args);
while ((opt = getopt(argc, argv, "icagfndvtbpro")) != -1) {
switch (opt) {
case 'i':
args->io_config.input_file_name = argv[optind];
break;
case 'c':
args->io_config.cell_id_file = atoi(argv[optind]);
break;
case 'p':
args->io_config.nof_prb_file = atoi(argv[optind]);
break;
case 'o':
args->io_config.nof_ports_file = atoi(argv[optind]);
break;
case 'a':
args->io_config.uhd_args = argv[optind];
break;
case 'g':
args->io_config.uhd_gain = atof(argv[optind]);
break;
case 'f':
args->io_config.uhd_freq = atof(argv[optind]);
break;
case 't':
args->io_config.find_threshold = atof(argv[optind]);
break;
case 'n':
args->nof_subframes = atoi(argv[optind]);
break;
case 'r':
args->rnti= atoi(argv[optind]);
break;
case 'd':
args->disable_plots = true;
break;
case 'v':
verbose++;
break;
default:
usage(args, argv[0]);
exit(-1);
}
}
if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) {
usage(args, argv[0]);
}
}
/**********************************************************************/
void sigintHandler(int x) {
go_exit = 1;
}
/* TODO: Do something with the output data */
char data[10000];
extern float mean_exec_time;
int main(int argc, char **argv) {
int ret;
cf_t *sf_buffer;
iodev_t iodev;
prog_args_t prog_args;
lte_cell_t cell;
ue_dl_t ue_dl;
int64_t sf_cnt;
pbch_mib_t mib;
bool printed_sib = false;
int rlen;
parse_args(&prog_args, argc, argv);
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) {
init_plots();
}
#endif
/* Setup SIGINT handler */
printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler);
/* Initialize subframe counter */
sf_cnt = 0;
if (iodev_init(&iodev, &prog_args.io_config, &cell, &mib)) {
exit(-1);
}
if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) {
fprintf(stderr, "Error initiating UE downlink processing module\n");
exit(-1);
}
pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti);
/* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
ret = iodev_receive(&iodev, &sf_buffer);
if (ret < 0) {
fprintf(stderr, "Error reading from input device (%d)\n", ret);
break;
}
/* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 1) {
rlen = ue_dl_decode(&ue_dl, sf_buffer, data, iodev_get_sfidx(&iodev), prog_args.rnti);
if (rlen < 0) {
fprintf(stderr, "\nError running receiver\n");fflush(stdout);
exit(-1);
}
if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) {
printf("\n\nDecoded SIB1 Message: ");
vec_fprint_hex(stdout, data, rlen);
printf("\n");fflush(stdout);
printed_sib = true;
}
// Plot and Printf
if (!(sf_cnt % 10)) {
printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d/%4d, BLER: %.1e, Texec: %.2f\r",
ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000,
pdsch_average_noi(&ue_dl.pdsch),
(int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (int) ue_dl.nof_trials,
(float) ue_dl.pkt_errors / ue_dl.pkts_total,
mean_exec_time);
}
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots && iodev_get_sfidx(&iodev) == 5) {
do_plots(&ue_dl, 5);
}
#endif
} else if (ret == 0) {
printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r",
sync_get_peak_value(&iodev.sframe.sfind),
iodev.sframe.frame_total_cnt, iodev.sframe.state);
}
sf_cnt++;
} // Main loop
ue_dl_free(&ue_dl);
iodev_free(&iodev);
printf("\nBye\n");
exit(0);
}
/**********************************************************************
* Plotting Functions
***********************************************************************/
#ifndef DISABLE_GRAPHICS
#include "liblte/graphics/plot.h"
plot_real_t poutfft;
plot_complex_t pce;
plot_scatter_t pscatrecv, pscatequal;
float tmp_plot[SLOT_LEN_RE(MAX_PRB, CPNORM)];
void init_plots() {
plot_init();
plot_real_init(&poutfft);
plot_real_setTitle(&poutfft, "Output FFT - Magnitude");
plot_real_setLabels(&poutfft, "Index", "dB");
plot_real_setYAxisScale(&poutfft, -30, 20);
plot_complex_init(&pce);
plot_complex_setTitle(&pce, "Channel Estimates");
plot_complex_setYAxisScale(&pce, Ip, -3, 3);
plot_complex_setYAxisScale(&pce, Q, -3, 3);
plot_complex_setYAxisScale(&pce, Magnitude, 0, 4);
plot_complex_setYAxisScale(&pce, Phase, -M_PI, M_PI);
plot_scatter_init(&pscatrecv);
plot_scatter_setTitle(&pscatrecv, "Received Symbols");
plot_scatter_setXAxisScale(&pscatrecv, -4, 4);
plot_scatter_setYAxisScale(&pscatrecv, -4, 4);
plot_scatter_init(&pscatequal);
plot_scatter_setTitle(&pscatequal, "Equalized Symbols");
plot_scatter_setXAxisScale(&pscatequal, -2, 2);
plot_scatter_setYAxisScale(&pscatequal, -2, 2);
}
void do_plots(ue_dl_t *q, uint32_t sf_idx) {
int i;
uint32_t nof_re = SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp);
uint32_t nof_symbols = q->harq_process[0].prb_alloc.re_sf[sf_idx];
for (i = 0; i < nof_re; i++) {
tmp_plot[i] = 10 * log10f(cabsf(q->sf_symbols[i]));
if (isinf(tmp_plot[i])) {
tmp_plot[i] = -80;
}
}
plot_real_setNewData(&poutfft, tmp_plot, nof_re);
plot_complex_setNewData(&pce, q->ce[0], nof_re);
plot_scatter_setNewData(&pscatrecv, q->pdsch.pdsch_symbols[0], nof_symbols);
plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols);
}
#endif

@ -1,559 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
//#define DISABLE_UHD
#ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h"
#endif
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define RSSI_FS 1000000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define RSSI_DECIM 20
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
int band, earfcn=-1;
float find_threshold = 10.0, track_threshold = 8.0;
int earfcn_start=-1, earfcn_end = -1;
float rssi_threshold = -45.0;
int max_track_lost=9;
int nof_frames_find=20, nof_frames_track=100, nof_samples_rssi=50000;
int track_len=500;
cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS];
pbch_t pbch;
lte_fft_t fft;
chest_t chest;
sync_t sfind, strack;
cfo_t cfocorr;
float *cfo_v;
int *idx_v, *idx_valid, *t;
float *p2a_v;
void *uhd;
int nof_bands;
float uhd_gain = 20.0;
#define MAX_EARFCN 1000
lte_earfcn_t channels[MAX_EARFCN];
float rssi[MAX_EARFCN];
float rssi_d[MAX_EARFCN/RSSI_DECIM];
float freqs[MAX_EARFCN];
float cfo[MAX_EARFCN];
float p2a[MAX_EARFCN];
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");
}
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 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 */
#ifndef DISABLE_UHD
printf("Opening UHD device...\n");
if (cuhd_open("",&uhd)) {
fprintf(stderr, "Error opening uhd\n");
return -1;
}
#endif
return 0;
}
void base_free() {
int i;
#ifndef DISABLE_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);
}
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 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 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++;
}
#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;
}
#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;
}
#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;
}
#endif
n = nof_bands;
}
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;
}
int mib_decoder_run(cf_t *input, pbch_mib_t *mib) {
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);
}
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);
#ifndef DISABLE_UHD
cuhd_set_rx_srate(uhd, SAMP_FREQ);
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) {
#ifndef DISABLE_UHD
DEBUG(" ----- RECEIVING %d SAMPLES ---- \n", FLEN);
cuhd_recv(uhd, &input_buffer[FLEN], FLEN, 1);
#endif
}
switch(state) {
case INIT:
DEBUG("Stopping receiver...\n",0);
#ifndef DISABLE_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);
DEBUG("Starting receiver...\n",0);
cuhd_start_rx_stream(uhd);
#endif
/* init variables */
frame_cnt = 0;
max_peak_to_avg = -1;
cell_id = -1;
/* receive first frame */
#ifndef DISABLE_UHD
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);
}

@ -1,509 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <unistd.h>
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
#define MHZ 1000000
#define SAMP_FREQ 1920000
#define RSSI_FS 1000000
#define FLEN 9600
#define FLEN_PERIOD 0.005
#define RSSI_DECIM 20
#define IS_SIGNAL(i) (10*log10f(rssi[i]) + 30 > rssi_threshold)
int band, earfcn=-1;
float find_threshold = 10.0, track_threshold = 8.0;
int earfcn_start=-1, earfcn_end = -1;
float rssi_threshold = -45.0;
int max_track_lost=9;
int nof_frames_find=20, nof_frames_track=100, nof_samples_rssi=50000;
int track_len=500;
cf_t *input_buffer;
float *cfo_v;
int *idx_v, *idx_valid, *t;
float *p2a_v;
void *uhd;
int nof_bands;
float uhd_gain = 20.0;
#define MAX_EARFCN 1000
lte_earfcn_t channels[MAX_EARFCN];
float rssi[MAX_EARFCN];
float rssi_d[MAX_EARFCN/RSSI_DECIM];
float freqs[MAX_EARFCN];
float cfo[MAX_EARFCN];
float p2a[MAX_EARFCN];
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");
}
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 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;
}
void base_free() {
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 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 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 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);
}
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");
*/
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);
}

@ -1,167 +0,0 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <math.h>
#include "liblte/phy/phy.h"
#include "liblte/cuhd/cuhd.h"
int nof_frames=1000;
int band;
cf_t *input_buffer, *fft_buffer;
void *uhd;
int earfcn_start = -1, earfcn_end = -1;
#define MAX_EARFCN 1000
lte_earfcn_t channels[MAX_EARFCN];
#define MHZ 1000000
#define SAMP_FREQ 1920000
void usage(char *prog) {
printf("Usage: %s [nvse] -b band\n", prog);
printf("\t-s earfcn_start [Default All]\n");
printf("\t-e earfcn_end [Default All]\n");
printf("\t-n number of frames [Default %d]\n", nof_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 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;
}
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);
}

@ -109,13 +109,12 @@ int main(int argc, char **argv) {
int peak_pos[3];
float *cfo;
float peak_value[3];
float mean_value[3];
int frame_cnt;
cf_t *input;
int m0, m1;
uint32_t m0, m1;
float m0_value, m1_value;
int N_id_2;
int sss_idx;
uint32_t N_id_2;
uint32_t sss_idx;
struct timeval tdata[3];
int *exec_time;
@ -173,7 +172,7 @@ int main(int argc, char **argv) {
fprintf(stderr, "Error initializing N_id_2\n");
exit(-1);
}
if (sss_synch_init(&sss[N_id_2])) {
if (sss_synch_init(&sss[N_id_2], 128)) {
fprintf(stderr, "Error initializing SSS object\n");
exit(-1);
}
@ -196,15 +195,15 @@ int main(int argc, char **argv) {
gettimeofday(&tdata[1], NULL);
if (force_cfo != CFO_AUTO) {
cfo_correct(&cfocorr, input, -force_cfo/128);
cfo_correct(&cfocorr, input, 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]);
peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_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]);
peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]);
}
float max_value=-99999;
N_id_2=-1;
@ -218,7 +217,7 @@ int main(int argc, char **argv) {
}
/* If peak detected */
if (peak_value[N_id_2]/mean_value[N_id_2] > corr_peak_threshold) {
if (peak_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) {
@ -228,7 +227,7 @@ int main(int argc, char **argv) {
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],
sss_synch_subframe(m0, m1), peak_value[N_id_2],
peak_pos[N_id_2], m0, m1,
cfo[frame_cnt]);
}

@ -0,0 +1,77 @@
/**
*
* \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 AGC_
#define AGC_
#include <stdbool.h>
#include <stdint.h>
#include <complex.h>
#include "liblte/config.h"
/* Automatic Gain Control
*
*/
typedef _Complex float cf_t;
#define AGC_DEFAULT_BW (5e-2)
typedef struct LIBLTE_API{
float bandwidth;
float gain;
float y_out;
bool lock;
bool isfirst;
} agc_t;
LIBLTE_API int agc_init (agc_t *q);
LIBLTE_API void agc_free(agc_t *q);
LIBLTE_API void agc_reset(agc_t *q);
LIBLTE_API void agc_set_bandwidth(agc_t *q,
float bandwidth);
LIBLTE_API float agc_get_rssi(agc_t *q);
LIBLTE_API float agc_get_output_level(agc_t *q);
LIBLTE_API float agc_get_gain(agc_t *q);
LIBLTE_API void agc_lock(agc_t *q,
bool enable);
LIBLTE_API void agc_process(agc_t *q,
cf_t *input,
cf_t *output,
uint32_t len);
#endif // AGC_

@ -33,14 +33,19 @@
#include <stdio.h>
#include "liblte/config.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/filter/filter2d.h"
#include "liblte/phy/common/phy_common.h"
typedef _Complex float cf_t; /* this is only a shortcut */
typedef enum {LINEAR} chest_interp_t;
typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, int off_st, int off_end);
typedef void (*interpolate_fnc_t) (cf_t *input,
cf_t *output,
uint32_t M,
uint32_t len,
uint32_t off_st,
uint32_t off_end);
/** This is an OFDM channel estimator.
* It works with any reference signal pattern, provided by the object
@ -51,30 +56,93 @@ typedef void (*interpolate_fnc_t) (cf_t *input, cf_t *output, int M, int len, in
/* Low-level API */
typedef struct LIBLTE_API {
int nof_ports;
int nof_symbols;
int nof_prb;
lte_cp_t cp;
uint32_t nof_ports;
uint32_t nof_re;
uint32_t nof_symbols;
refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME];
interpolate_fnc_t interp;
}chest_t;
interp_t interp_time[MAX_PORTS];
interp_t interp_freq[MAX_PORTS];
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);
}chest_t;
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);
LIBLTE_API int chest_init(chest_t *q,
uint32_t nof_re,
uint32_t nof_symbols,
uint32_t nof_ports);
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);
LIBLTE_API void chest_free(chest_t *q);
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]);
LIBLTE_API int chest_set_nof_ports(chest_t *q,
uint32_t nof_ports);
LIBLTE_API int chest_init_LTEDL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q,
uint32_t nslot,
uint32_t port_id,
lte_cell_t cell);
LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API int chest_ref_LTEDL(chest_t *q,
lte_cell_t cell);
LIBLTE_API int chest_ce_ref(chest_t *q,
cf_t *input,
uint32_t nslot,
uint32_t port_id,
uint32_t nref);
LIBLTE_API int chest_ce_slot_port(chest_t *q,
cf_t *input,
cf_t *ce,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API int chest_ce_sf_port(chest_t *q,
cf_t *input,
cf_t *ce,
uint32_t sf_idx,
uint32_t port_id);
LIBLTE_API int chest_ce_slot(chest_t *q,
cf_t *input,
cf_t *ce[MAX_PORTS],
uint32_t nslot);
LIBLTE_API int chest_ce_sf(chest_t *q,
cf_t *input,
cf_t *ce[MAX_PORTS],
uint32_t sf_idx);
LIBLTE_API void chest_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API void chest_ref_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API void chest_recvsig_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API void chest_ce_fprint(chest_t *q,
FILE *stream,
uint32_t nslot,
uint32_t port_id);
LIBLTE_API int chest_ref_symbols(chest_t *q,
uint32_t port_id,
uint32_t nslot,
uint32_t l[2]);
/* High-level API */
@ -91,8 +159,7 @@ typedef struct LIBLTE_API{
cf_t *input;
int in_len;
struct chest_ctrl_in {
int slot_id; // slot id in the 10ms frame
int cell_id;
int sf_idx; // subframe id in the 10ms frame
} ctrl_in;
cf_t *output[MAX_PORTS];
int out_len[MAX_PORTS];
@ -105,3 +172,11 @@ LIBLTE_API int chest_work(chest_hl* hl);
LIBLTE_API int chest_stop(chest_hl* hl);
#endif

@ -43,26 +43,30 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API{
int time_idx;
int freq_idx;
uint32_t time_idx;
uint32_t freq_idx;
cf_t simbol;
cf_t recv_simbol;
}ref_t;
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;
uint32_t nof_refs; // number of reference signals
uint32_t *symbols_ref; // symbols with at least one reference
uint32_t nsymbols; // number of symbols with at least one reference
uint32_t voffset; // offset of the first reference in the freq domain
uint32_t nof_prb;
ref_t *refs;
cf_t *ch_est;
} refsignal_t;
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 int refsignal_init_LTEDL(refsignal_t *q,
uint32_t port_id,
uint32_t nslot,
lte_cell_t cell);
LIBLTE_API void refsignal_free(refsignal_t *q);
LIBLTE_API void refsignal_put(refsignal_t *q, cf_t *slot_symbols);
LIBLTE_API int refsignal_put(refsignal_t *q,
cf_t *slot_symbols);
#endif

@ -27,6 +27,8 @@
#include <complex.h>
#include <stdint.h>
#include "liblte/config.h"
#ifndef CH_AWGN_
@ -34,8 +36,18 @@
typedef _Complex float cf_t;
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);
LIBLTE_API void ch_awgn_c(const cf_t* input,
cf_t* output,
float variance,
uint32_t len);
LIBLTE_API void ch_awgn_f(const float* x,
float* y,
float variance,
uint32_t len);
LIBLTE_API float ch_awgn_get_variance(float ebno_db,
float rate);
/* High-level API */

@ -42,20 +42,41 @@ typedef _Complex float cf_t; /* this is only a shortcut */
/* This is common for both directions */
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;
uint32_t nof_symbols;
uint32_t symbol_sz;
uint32_t nof_guards;
uint32_t nof_re;
uint32_t slot_sz;
lte_cp_t cp;
cf_t *tmp; // for removing zero padding
}lte_fft_t;
LIBLTE_API int lte_fft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);
LIBLTE_API int lte_fft_init(lte_fft_t *q,
lte_cp_t cp_type,
uint32_t 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);
LIBLTE_API int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb);
LIBLTE_API void lte_fft_run_slot(lte_fft_t *q,
cf_t *input,
cf_t *output);
LIBLTE_API void lte_fft_run_sf(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,
uint32_t 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);
LIBLTE_API void lte_ifft_run_slot(lte_fft_t *q,
cf_t *input,
cf_t *output);
LIBLTE_API void lte_ifft_run_sf(lte_fft_t *q,
cf_t *input,
cf_t *output);
#endif

@ -29,6 +29,8 @@
#ifndef _LTEBASE_
#define _LTEBASE_
#include <stdint.h>
#include <stdbool.h>
#include "liblte/config.h"
#define NSUBFRAMES_X_FRAME 10
@ -41,7 +43,6 @@
#define LTE_NIL_SYMBOL 2
#define MAX_PORTS 4
#define MAX_PORTS_CTRL 4
#define MAX_LAYERS 8
#define MAX_CODEWORDS 2
@ -58,13 +59,18 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define MAX_NSYMB 7
#define MAX_PRB 110
#define RE_X_RB 12
#define SYMBOL_SZ_MAX 2048
#define CPNORM_NSYMB 7
#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB
#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_SF_NSYMB (2*CPEXT_NSYMB)
#define CPEXT_LEN 512
#define CPEXT_7_5_LEN 1024
@ -72,39 +78,41 @@ typedef enum {CPNORM, CPEXT} lte_cp_t;
#define CP_ISEXT(cp) (cp==CPEXT)
#define CP_NSYMB(cp) (CP_ISNORM(cp)?CPNORM_NSYMB:CPEXT_NSYMB)
#define CP(symbol_sz, c) (c*symbol_sz/2048)
#define CP_NORM(symbol, symbol_sz) (symbol==0)?CP(symbol_sz,CPNORM_0_LEN):CP(symbol_sz,CPNORM_LEN)
#define CP_EXT(symbol_sz) CP(symbol_sz,CPEXT_LEN)
#define CP(symbol_sz, c) ((c*symbol_sz)/2048)
#define CP_NORM(symbol, symbol_sz) ((symbol==0)?CP((symbol_sz),CPNORM_0_LEN):CP((symbol_sz),CPNORM_LEN))
#define CP_EXT(symbol_sz) (CP((symbol_sz),CPEXT_LEN))
#define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN)))
#define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define SLOT_LEN(symbol_sz, cp) CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz)
#define SLOT_LEN(symbol_sz) (480*((symbol_sz)/64))
#define SF_LEN(symbol_sz) (2*SLOT_LEN(symbol_sz))
#define SF_LEN_MAX (SF_LEN(SYMBOL_SZ_MAX))
#define SF_LEN_CPNORM(symbol_sz) 2*SLOT_LEN_CPNORM(symbol_sz)
#define SF_LEN_CPEXT(symbol_sz) 2*SLOT_LEN_CPEXT(symbol_sz)
#define SF_LEN(symbol_sz, cp) 2*SLOT_LEN(cp, symbol_sz)
#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp))
#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp))
#define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN))))
#define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN)))
#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx)
#define 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 SYMBOL_HAS_REF(l, cp, nof_ports) ((l == 1 && nof_ports == 4) \
|| l == 0 \
|| l == CP_NSYMB(cp) - 3)
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_TC_CB_SIZES 188
typedef struct LIBLTE_API {
uint32_t nof_prb;
uint32_t nof_ports;
uint32_t id;
lte_cp_t cp;
}lte_cell_t;
typedef enum LIBLTE_API {
SINGLE_ANTENNA,TX_DIVERSITY, SPATIAL_MULTIPLEX
@ -113,6 +121,10 @@ typedef enum LIBLTE_API {
typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t;
typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t;
typedef enum LIBLTE_API {
LTE_BPSK = 1, LTE_QPSK = 2, LTE_QAM16 = 4, LTE_QAM64 = 6
} lte_mod_t;
typedef struct LIBLTE_API {
int id;
@ -123,16 +135,59 @@ LIBLTE_API enum band_geographical_area {
ALL, NAR, APAC, EMEA, JAPAN, CALA, NA
};
LIBLTE_API int lte_cb_size(int index);
LIBLTE_API int lte_find_cb_index(int long_cb);
LIBLTE_API bool lte_cell_isvalid(lte_cell_t *cell);
LIBLTE_API bool lte_N_id_2_isvalid(uint32_t N_id_2);
LIBLTE_API bool lte_N_id_1_isvalid(uint32_t N_id_1);
LIBLTE_API bool lte_symbol_sz_isvalid(uint32_t symbol_sz);
LIBLTE_API int lte_symbol_sz(uint32_t nof_prb);
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);
LIBLTE_API int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type);
LIBLTE_API int lte_sampling_freq_hz(uint32_t nof_prb);
LIBLTE_API uint32_t lte_re_x_prb(uint32_t ns,
uint32_t symbol,
uint32_t nof_ports,
uint32_t nof_symbols);
LIBLTE_API uint32_t lte_voffset(uint32_t symbol_id,
uint32_t cell_id,
uint32_t nof_ports);
LIBLTE_API int lte_cb_size(uint32_t index);
LIBLTE_API char *lte_cp_string(lte_cp_t cp);
LIBLTE_API char *lte_mod_string(lte_mod_t mod);
LIBLTE_API uint32_t lte_mod_bits_x_symbol(lte_mod_t mod);
LIBLTE_API int lte_find_cb_index(uint32_t long_cb);
LIBLTE_API float lte_band_fd(uint32_t earfcn);
LIBLTE_API int lte_band_get_fd_band(uint32_t band,
lte_earfcn_t *earfcn,
int earfcn_start,
int earfcn_end,
uint32_t max_elems);
LIBLTE_API int lte_band_get_fd_band_all(uint32_t band,
lte_earfcn_t *earfcn,
uint32_t max_nelems);
LIBLTE_API int lte_band_get_fd_region(enum band_geographical_area region,
lte_earfcn_t *earfcn,
uint32_t max_elems);
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,19 +33,39 @@
typedef struct LIBLTE_API {
char *c;
int len;
uint32_t len;
} sequence_t;
LIBLTE_API int sequence_init(sequence_t *q, int len);
LIBLTE_API int sequence_init(sequence_t *q, uint32_t len);
LIBLTE_API void sequence_free(sequence_t *q);
LIBLTE_API int sequence_LTEPRS(sequence_t *q, int len, int seed);
LIBLTE_API int sequence_LTEPRS(sequence_t *q,
uint32_t len,
uint32_t seed);
LIBLTE_API int sequence_pbch(sequence_t *seq,
lte_cp_t cp,
uint32_t cell_id);
LIBLTE_API int sequence_pcfich(sequence_t *seq,
uint32_t nslot,
uint32_t cell_id);
LIBLTE_API int sequence_phich(sequence_t *seq,
uint32_t nslot,
uint32_t cell_id);
LIBLTE_API int sequence_pdcch(sequence_t *seq,
uint32_t nslot,
uint32_t cell_id,
uint32_t 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);
LIBLTE_API int sequence_pdsch(sequence_t *seq,
unsigned short rnti,
int q,
uint32_t nslot,
uint32_t cell_id,
uint32_t len);
#endif

@ -34,13 +34,13 @@
#include "liblte/config.h"
typedef struct LIBLTE_API {
int R;
int K;
int poly[3];
uint32_t R;
uint32_t K;
uint32_t poly[3];
bool tail_biting;
}convcoder_t;
LIBLTE_API 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, uint32_t frame_length);
/* High-level API */

@ -30,6 +30,7 @@
#define CRC_
#include "liblte/config.h"
#include <stdint.h>
typedef struct LIBLTE_API {
unsigned long table[256];
@ -45,6 +46,6 @@ typedef struct LIBLTE_API {
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);
LIBLTE_API uint32_t crc_checksum(crc_t *h, char *data, int len);
#endif

@ -33,8 +33,15 @@
#define RX_NULL 10000
#define TX_NULL 80
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);
LIBLTE_API int rm_conv_tx(char *input,
uint32_t in_len,
char *output,
uint32_t out_len);
LIBLTE_API int rm_conv_rx(float *input,
uint32_t in_len,
float *output,
uint32_t out_len);
/* High-level API */
typedef struct

@ -40,21 +40,26 @@
#include "liblte/config.h"
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);
LIBLTE_API int rm_turbo_tx(char *w_buff,
uint32_t buff_len,
char *input,
uint32_t in_len,
char *output,
uint32_t out_len,
uint32_t rv_idx);
LIBLTE_API int rm_turbo_rx(float *w_buff,
uint32_t buff_len,
float *input,
uint32_t in_len,
float *output,
uint32_t out_len,
uint32_t rv_idx);
/* High-level API */
typedef struct LIBLTE_API {
rm_turbo_t q;
struct rm_turbo_init {
int direction;
} init;

@ -31,15 +31,15 @@
#include "liblte/config.h"
typedef struct LIBLTE_API {
int *forward;
int *reverse;
int max_long_cb;
uint32_t *forward;
uint32_t *reverse;
uint32_t max_long_cb;
} tc_interl_t;
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_LTE_gen(tc_interl_t *h, uint32_t long_cb);
LIBLTE_API int tc_interl_UMTS_gen(tc_interl_t *h, uint32_t long_cb);
LIBLTE_API int tc_interl_init(tc_interl_t *h, int max_long_cb);
LIBLTE_API int tc_interl_init(tc_interl_t *h, uint32_t max_long_cb);
LIBLTE_API void tc_interl_free(tc_interl_t *h);
#endif

@ -37,13 +37,13 @@
#define TOTALTAIL 12
typedef struct LIBLTE_API {
int max_long_cb;
uint32_t max_long_cb;
tc_interl_t interl;
} tcod_t;
LIBLTE_API int tcod_init(tcod_t *h, int max_long_cb);
LIBLTE_API int tcod_init(tcod_t *h, uint32_t max_long_cb);
LIBLTE_API void tcod_free(tcod_t *h);
LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, int long_cb);
LIBLTE_API int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb);
#endif

@ -68,13 +68,25 @@ typedef struct LIBLTE_API {
tc_interl_t interleaver;
} tdec_t;
LIBLTE_API int tdec_init(tdec_t *h, int max_long_cb);
LIBLTE_API int tdec_init(tdec_t * h,
uint32_t max_long_cb);
LIBLTE_API void tdec_free(tdec_t * h);
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);
LIBLTE_API int tdec_reset(tdec_t * h, uint32_t long_cb);
LIBLTE_API void tdec_iteration(tdec_t * h,
llr_t * input,
uint32_t long_cb);
LIBLTE_API void tdec_decision(tdec_t * h,
char *output,
uint32_t long_cb);
LIBLTE_API void tdec_run_all(tdec_t * h,
llr_t * input,
char *output,
uint32_t nof_iterations,
uint32_t long_cb);
#endif

@ -38,21 +38,34 @@ typedef enum {
typedef struct LIBLTE_API{
void *ptr;
int R;
int K;
uint32_t R;
uint32_t K;
unsigned int framebits;
bool tail_biting;
int poly[3];
int (*decode) (void*, unsigned char*, char*, int);
uint32_t poly[3];
int (*decode) (void*, uint8_t*, char*, uint32_t);
void (*free) (void*);
unsigned char *tmp;
unsigned char *symbols_uc;
}viterbi_t;
LIBLTE_API int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3], int max_frame_length, bool tail_bitting);
LIBLTE_API int viterbi_init(viterbi_t *q,
viterbi_type_t type,
uint32_t poly[3],
uint32_t 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);
LIBLTE_API int viterbi_decode_f(viterbi_t *q,
float *symbols,
char *data,
uint32_t frame_length);
LIBLTE_API int viterbi_decode_uc(viterbi_t *q,
uint8_t *symbols,
char *data,
uint32_t frame_length);
/* High-level API */

@ -38,13 +38,13 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
enum modem_std table; /* In this implementation, mapping table is hard-coded */
lte_mod_t mod; /* In this implementation, mapping table is hard-coded */
}demod_hard_t;
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);
LIBLTE_API void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod);
LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols);
@ -52,7 +52,7 @@ LIBLTE_API int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits,
typedef struct LIBLTE_API {
demod_hard_t obj;
struct demod_hard_init {
enum modem_std std; // Symbol mapping standard (see modem_table.h)
lte_mod_t std; // Symbol mapping standard (see modem_table.h)
} init;
cf_t* input;

@ -56,7 +56,7 @@ typedef struct LIBLTE_API {
modem_table_t table;
struct demod_soft_init{
enum modem_std std; // symbol mapping standard (see modem_table.h)
lte_mod_t std; // symbol mapping standard (see modem_table.h)
} init;
const cf_t* input;

@ -37,13 +37,13 @@
typedef _Complex float cf_t;
LIBLTE_API 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, uint32_t nbits);
/* High-level API */
typedef struct LIBLTE_API {
modem_table_t obj;
struct mod_init {
enum modem_std std; // symbol mapping standard (see modem_table.h)
lte_mod_t std; // symbol mapping standard (see modem_table.h)
} init;
const char* input;

@ -34,30 +34,39 @@
#include <complex.h>
#include <stdint.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/config.h"
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int idx[2][6][32];
uint32_t idx[2][6][32];
uint32_t min_idx[2][64][6]; /* NEW: for each constellation point zone (2, 4, 16, 64 for BPSK, QPSK, 16QAM, 64QAM) the 2x(1, 2, 4, and 6 closest constellation points) for each bit, respectively. */
uint32_t d_idx[64][7]; /* NEW: for each constellation point zone (2, 4, 16, 64 for BPSK, QPSK, 16QAM, 64QAM) the 2, 3, 5 and 7 indices to constellation points that need to be computed for any recevied symbol modulated as BPSK, QPSK, 16QAM, and 64QAM, respectively. */
}soft_table_t;
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
uint32_t nsymbols; // number of modulation symbols
uint32_t 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
};
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);
LIBLTE_API int modem_table_set(modem_table_t* q,
cf_t* table,
soft_table_t *soft_table,
uint32_t nsymbols,
uint32_t nbits_x_symbol);
LIBLTE_API int modem_table_lte(modem_table_t* q,
lte_mod_t modulation,
bool compute_soft_demod);
#endif // MODEM_TABLE_

@ -62,41 +62,72 @@ typedef enum {
} dci_spec_t;
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;
uint32_t L; // Aggregation level
uint32_t ncce; // Position of first CCE of the dci
} dci_location_t;
typedef struct LIBLTE_API {
char data[DCI_MAX_BITS];
dci_candidate_t location;
uint32_t nof_bits;
} dci_msg_t;
typedef struct LIBLTE_API {
dci_msg_t *msg;
int nof_dcis;
int max_dcis;
} dci_t;
LIBLTE_API int dci_init(dci_t *q, int max_dci);
LIBLTE_API void dci_free(dci_t *q);
/* Converts a received PDSCH DL scheduling DCI message
* to ra structures ready to be passed to the harq setup function
*/
LIBLTE_API int dci_msg_to_ra_dl(dci_msg_t *msg,
uint16_t msg_rnti,
uint16_t c_rnti,
lte_cell_t cell,
uint32_t cfi,
ra_pdsch_t *ra_dl);
/* TODO
LIBLTE_API int dci_msg_to_ra_ul(dci_msg_t *msg,
uint16_t msg_rnti,
uint16_t c_rnti,
lte_cell_t cell,
uint32_t cfi,
ra_pusch_t *ra_ul);
*/
LIBLTE_API char* dci_format_string(dci_format_t format);
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);
LIBLTE_API int dci_location_set(dci_location_t *c,
uint32_t L,
uint32_t nCCE);
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);
LIBLTE_API bool dci_location_isvalid(dci_location_t *c);
LIBLTE_API int dci_msg_get_type(dci_msg_t *msg,
dci_msg_type_t *type,
uint32_t nof_prb,
uint16_t msg_rnti,
uint16_t crnti);
LIBLTE_API void dci_msg_type_fprint(FILE *f,
dci_msg_type_t type);
// For dci_msg_type_t = PUSCH_SCHED
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);
LIBLTE_API int dci_msg_pack_pusch(ra_pusch_t *data,
dci_msg_t *msg,
uint32_t nof_prb);
// For dci_msg_type_t = PDSCH_SCHED
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);
LIBLTE_API int dci_msg_unpack_pusch(dci_msg_t *msg,
ra_pusch_t *data,
uint32_t nof_prb);
LIBLTE_API int dci_format_sizeof(dci_format_t format, int nof_prb);
// For dci_msg_type_t = PDSCH_SCHED
LIBLTE_API int dci_msg_pack_pdsch(ra_pdsch_t *data,
dci_msg_t *msg,
dci_format_t format,
uint32_t nof_prb,
bool crc_is_crnti);
LIBLTE_API int dci_msg_unpack_pdsch(dci_msg_t *msg,
ra_pdsch_t *data,
uint32_t nof_prb,
bool crc_is_crnti);
LIBLTE_API uint32_t dci_format_sizeof(dci_format_t format,
uint32_t nof_prb);
#endif // DCI_

@ -47,24 +47,23 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int nof_ports;
int nof_prb;
int sfn;
uint32_t nof_ports;
uint32_t nof_prb;
uint32_t sfn;
phich_length_t phich_length;
phich_resources_t phich_resources;
}pbch_mib_t;
/* PBCH object */
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_symbols;
lte_cell_t cell;
uint32_t 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 *ce[MAX_PORTS];
cf_t *pbch_symbols[MAX_PORTS];
cf_t *pbch_x[MAX_PORTS];
cf_t *pbch_d;
float *pbch_llr;
float *temp;
@ -73,7 +72,7 @@ typedef struct LIBLTE_API {
char *data;
char *data_enc;
int frame_idx;
uint32_t frame_idx;
/* tx & rx objects */
modem_table_t mod;
@ -85,15 +84,23 @@ typedef struct LIBLTE_API {
} pbch_t;
LIBLTE_API int pbch_init(pbch_t *q, int nof_prb, int cell_id, lte_cp_t cp);
LIBLTE_API int pbch_init(pbch_t *q,
lte_cell_t cell);
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 int pbch_decode(pbch_t *q,
cf_t *slot1_symbols,
cf_t *ce_slot1[MAX_PORTS],
pbch_mib_t *mib);
LIBLTE_API int pbch_encode(pbch_t *q,
pbch_mib_t *mib,
cf_t *slot1_symbols[MAX_PORTS]);
LIBLTE_API void pbch_decode_reset(pbch_t *q);
LIBLTE_API void pbch_mib_fprint(FILE *stream, pbch_mib_t *mib);
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);
LIBLTE_API void pbch_mib_fprint(FILE *stream,
pbch_mib_t *mib,
uint32_t cell_id);
#endif // PBCH_

@ -45,19 +45,16 @@ typedef _Complex float cf_t;
/* PCFICH object */
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
lte_cell_t cell;
int nof_symbols;
int nof_prb;
int nof_ports;
/* 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 ce[MAX_PORTS][PCFICH_RE];
cf_t pcfich_symbols[MAX_PORTS][PCFICH_RE];
cf_t pcfich_x[MAX_PORTS][PCFICH_RE];
cf_t pcfich_d[PCFICH_RE];
/* bit message */
@ -70,16 +67,22 @@ typedef struct LIBLTE_API {
} pcfich_t;
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 int pcfich_init(pcfich_t *q,
regs_t *regs,
lte_cell_t cell);
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);
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);
LIBLTE_API int pcfich_decode(pcfich_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
uint32_t subframe,
uint32_t *cfi,
uint32_t *distance);
LIBLTE_API int pcfich_encode(pcfich_t *q,
uint32_t cfi,
cf_t *sf_symbols[MAX_PORTS],
uint32_t subframe);
#endif

@ -44,41 +44,26 @@
typedef _Complex float cf_t;
#define PDCCH_NOF_SEARCH_MODES 3
typedef enum LIBLTE_API {
SEARCH_NONE = 3, SEARCH_SI = 0, SEARCH_RA = 1, SEARCH_UE = 2
SEARCH_UE, SEARCH_COMMON
} 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 LIBLTE_API {
int nof_candidates;
dci_candidate_t *candidates[NSUBFRAMES_X_FRAME];
} pdcch_search_t;
/* PDCCH object */
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;
lte_cell_t cell;
uint32_t e_bits;
uint32_t nof_regs;
uint32_t nof_cce;
uint32_t max_bits;
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 *ce[MAX_PORTS];
cf_t *pdcch_symbols[MAX_PORTS];
cf_t *pdcch_x[MAX_PORTS];
cf_t *pdcch_d;
char *pdcch_e;
float *pdcch_llr;
@ -91,36 +76,48 @@ typedef struct LIBLTE_API {
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 */
LIBLTE_API int pdcch_encode(pdcch_t *q, dci_t *dci, cf_t *slot_symbols[MAX_PORTS_CTRL],
int nsubframe);
/* Decoding functions */
LIBLTE_API int pdcch_init(pdcch_t *q,
regs_t *regs,
lte_cell_t cell);
/* There are two ways to decode the DCI messages:
* a) call pdcch_set_search_si/ue/ra and then call pdcch_decode()
* b) call pdcch_extract_llr() and then call pdcch_decode_si/ue/ra
*/
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);
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);
LIBLTE_API void pdcch_free(pdcch_t *q);
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);
/* Encoding function */
LIBLTE_API int pdcch_encode(pdcch_t *q,
dci_msg_t *msg,
dci_location_t location,
uint16_t rnti,
cf_t *sf_symbols[MAX_PORTS],
uint32_t nsubframe,
uint32_t cfi);
/* Decoding functions: Extract the LLRs and save them in the pdcch_t object */
LIBLTE_API int pdcch_extract_llr(pdcch_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
dci_location_t location,
uint32_t nsubframe,
uint32_t cfi);
/* Decoding functions: Try to decode a DCI message after calling pdcch_extract_llr */
LIBLTE_API int pdcch_decode_msg(pdcch_t *q,
dci_msg_t *msg,
dci_format_t format,
uint16_t *crc_rem);
/* Function for generation of UE-specific search space DCI locations */
LIBLTE_API uint32_t pdcch_ue_locations(pdcch_t *q,
dci_location_t *locations,
uint32_t max_locations,
uint32_t nsubframe,
uint32_t cfi,
uint16_t rnti);
/* Function for generation of common search space DCI locations */
LIBLTE_API uint32_t pdcch_common_locations(pdcch_t *q,
dci_location_t *locations,
uint32_t max_locations,
uint32_t cfi);
#endif

@ -43,29 +43,51 @@
#include "liblte/phy/phch/dci.h"
#include "liblte/phy/phch/regs.h"
#define TDEC_ITERATIONS 1
#define TDEC_MAX_ITERATIONS 6
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
ra_mcs_t mcs;
ra_prb_t prb_alloc;
lte_cell_t cell;
uint32_t max_cb;
uint32_t w_buff_size;
float **pdsch_w_buff_f;
char **pdsch_w_buff_c;
struct cb_segm {
uint32_t F;
uint32_t C;
uint32_t K1;
uint32_t K2;
uint32_t C1;
uint32_t C2;
} cb_segm;
} pdsch_harq_t;
/* PDSCH object */
typedef struct LIBLTE_API {
int cell_id;
lte_cp_t cp;
int nof_prb;
int nof_ports;
int max_symbols;
unsigned short rnti;
lte_cell_t cell;
uint32_t max_symbols;
bool rnti_is_set;
uint16_t rnti;
uint32_t nof_iterations;
uint64_t average_nof_iterations_n;
float average_nof_iterations;
/* buffers */
// void buffers are shared for tx and rx
cf_t *ce[MAX_PORTS];
cf_t *pdsch_symbols[MAX_PORTS];
cf_t *pdsch_x[MAX_PORTS];
cf_t *pdsch_d;
char *pdsch_e_bits;
char *cb_in_b;
char *cb_out_b;
float *pdsch_llr;
float *pdsch_rm_f;
char *cb_in;
void *cb_out;
void *pdsch_e;
/* tx & rx objects */
modem_table_t mod[4];
@ -73,19 +95,50 @@ typedef struct LIBLTE_API {
sequence_t seq_pdsch[NSUBFRAMES_X_FRAME];
tcod_t encoder;
tdec_t decoder;
rm_turbo_t rm_turbo;
crc_t crc_tb;
crc_t crc_cb;
}pdsch_t;
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);
LIBLTE_API int pdsch_init(pdsch_t *q,
lte_cell_t cell);
LIBLTE_API void pdsch_free(pdsch_t *q);
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);
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);
LIBLTE_API int pdsch_set_rnti(pdsch_t *q,
uint16_t rnti);
LIBLTE_API int pdsch_harq_init(pdsch_harq_t *p,
pdsch_t *pdsch);
LIBLTE_API int pdsch_harq_setup(pdsch_harq_t *p,
ra_mcs_t mcs,
ra_prb_t *prb_alloc);
LIBLTE_API void pdsch_harq_free(pdsch_harq_t *p);
LIBLTE_API int pdsch_encode(pdsch_t *q,
char *data,
cf_t *sf_symbols[MAX_PORTS],
uint32_t nsubframe,
pdsch_harq_t *harq_process,
uint32_t rv_idx);
LIBLTE_API int pdsch_decode(pdsch_t *q,
cf_t *sf_symbols,
cf_t *ce[MAX_PORTS],
char *data,
uint32_t nsubframe,
pdsch_harq_t *harq_process,
uint32_t rv_idx);
LIBLTE_API float pdsch_average_noi(pdsch_t *q);
LIBLTE_API uint32_t pdsch_last_noi(pdsch_t *q);
LIBLTE_API int pdsch_get(pdsch_t *q,
cf_t *sf_symbols,
cf_t *pdsch_symbols,
ra_prb_t *prb_alloc,
uint32_t subframe);
#endif

@ -55,17 +55,15 @@ typedef _Complex float cf_t;
/* phich object */
typedef struct LIBLTE_API {
lte_cp_t cp;
int nof_prb;
int nof_tx_ports;
lte_cell_t cell;
/* 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 ce[MAX_PORTS][PHICH_MAX_NSYMB];
cf_t phich_symbols[MAX_PORTS][PHICH_MAX_NSYMB];
cf_t phich_x[MAX_PORTS][PHICH_MAX_NSYMB];
cf_t phich_d[PHICH_MAX_NSYMB];
cf_t phich_d0[PHICH_MAX_NSYMB];
cf_t phich_z[PHICH_NBITS];
@ -80,18 +78,31 @@ typedef struct LIBLTE_API {
}phich_t;
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]);
LIBLTE_API int phich_init(phich_t *q,
regs_t *regs,
lte_cell_t cell);
LIBLTE_API void phich_free(phich_t *q);
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);
LIBLTE_API int phich_decode(phich_t *q,
cf_t *slot_symbols,
cf_t *ce[MAX_PORTS],
uint32_t ngroup,
uint32_t nseq,
uint32_t nsubframe,
char *ack,
uint32_t *distance);
LIBLTE_API int phich_encode(phich_t *q,
char ack,
uint32_t ngroup,
uint32_t nseq,
uint32_t nsubframe,
cf_t *slot_symbols[MAX_PORTS]);
LIBLTE_API void phich_reset(phich_t *q,
cf_t *slot_symbols[MAX_PORTS]);
LIBLTE_API uint32_t phich_ngroups(phich_t *q);
#endif // PHICH_

@ -37,17 +37,9 @@
* allocation.
*/
typedef enum LIBLTE_API {
MOD_NULL = 0, BPSK = 1, QPSK = 2, QAM16 = 3, QAM64 = 4
} ra_mod_t;
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.
lte_mod_t mod;
uint32_t tbs;
} ra_mcs_t;
typedef enum LIBLTE_API {
@ -60,13 +52,14 @@ typedef struct LIBLTE_API {
typedef struct LIBLTE_API {
uint32_t vrb_bitmask;
uint8_t rbg_subset;bool shift;
uint32_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;
uint32_t L_crb;
uint32_t RB_start;
enum {
nprb1a_2 = 0, nprb1a_3 = 1
} n_prb1a;
@ -79,20 +72,34 @@ typedef struct LIBLTE_API {
} ra_type2_t;
typedef struct LIBLTE_API {
unsigned short rnti;
uint32_t prb_idx[MAX_PRB];
uint32_t nof_prb;
} ra_prb_slot_t;
typedef struct LIBLTE_API {
ra_prb_slot_t slot[2];
uint32_t lstart;
uint32_t re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t;
typedef struct LIBLTE_API {
uint16_t rnti;
ra_type_t alloc_type;
union {
ra_type0_t type0_alloc;
ra_type1_t type1_alloc;
ra_type2_t type2_alloc;
};
ra_prb_t prb_alloc;
uint32_t mcs_idx;
ra_mcs_t mcs;
uint8_t harq_process;
uint8_t rv_idx;bool ndi;
uint32_t harq_process;
uint32_t rv_idx;
bool ndi;
} ra_pdsch_t;
typedef struct LIBLTE_API {
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mh.
/* 36.213 Table 8.4-2: hop_half is 0 for < 10 Mhz and 10 for > 10 Mhz.
* hop_quart is 00 for > 10 Mhz and hop_quart_neg is 01 for > 10 Mhz.
*/
enum {
@ -103,64 +110,85 @@ typedef struct LIBLTE_API {
hop_type_2 = 3
} freq_hop_fl;
ra_prb_t prb_alloc;
ra_type2_t type2_alloc;
uint32_t mcs_idx;
ra_mcs_t mcs;
uint8_t rv_idx; // If set to non-zero, a retransmission is requested with the same modulation
uint32_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;
bool ndi;
bool cqi_request;
} ra_pusch_t;
typedef struct LIBLTE_API {
uint8_t prb_idx[110];
int nof_prb;
} ra_prb_slot_t;
LIBLTE_API void ra_prb_fprint(FILE *f,
ra_prb_slot_t *prb);
typedef struct LIBLTE_API {
ra_prb_slot_t slot[2];
int lstart;
int re_sf[NSUBFRAMES_X_FRAME];
} ra_prb_t;
LIBLTE_API int ra_prb_get_dl(ra_prb_t *prb,
ra_pdsch_t *ra,
uint32_t nof_prb);
LIBLTE_API int ra_prb_get_ul(ra_prb_slot_t *prb,
ra_pusch_t *ra,
uint32_t nof_prb);
LIBLTE_API void ra_prb_get_re_dl(ra_prb_t *prb_dist,
uint32_t nof_prb,
uint32_t nof_ports,
uint32_t nof_ctrl_symbols,
lte_cp_t cp);
LIBLTE_API uint32_t ra_nprb_dl(ra_pdsch_t *ra,
uint32_t nof_prb);
LIBLTE_API uint32_t ra_nprb_ul(ra_pusch_t *ra,
uint32_t nof_prb);
LIBLTE_API int ra_mcs_from_idx_dl(uint32_t mcs_idx,
uint32_t nof_prb,
ra_mcs_t *mcs);
LIBLTE_API int ra_mcs_from_idx_ul(uint32_t mcs_idx,
uint32_t nof_prb,
ra_mcs_t *mcs);
LIBLTE_API int ra_tbs_from_idx_format1c(uint32_t tbs_idx);
LIBLTE_API int ra_tbs_from_idx(uint32_t tbs_idx,
uint32_t n_prb);
LIBLTE_API int ra_tbs_to_table_idx(uint32_t tbs,
uint32_t n_prb);
LIBLTE_API uint32_t ra_type0_P(uint32_t nof_prb);
LIBLTE_API uint32_t ra_type2_to_riv(uint32_t L_crb,
uint32_t RB_start,
uint32_t nof_prb);
LIBLTE_API void ra_type2_from_riv(uint32_t riv,
uint32_t *L_crb,
uint32_t *RB_start,
uint32_t nof_prb,
uint32_t nof_vrb);
LIBLTE_API uint32_t ra_type2_n_vrb_dl(uint32_t nof_prb,
bool ngap_is_1);
LIBLTE_API uint32_t ra_type2_n_rb_step(uint32_t nof_prb);
LIBLTE_API uint32_t ra_type2_ngap(uint32_t nof_prb,
bool ngap_is_1);
LIBLTE_API uint32_t ra_type1_N_rb(uint32_t nof_prb);
LIBLTE_API void ra_pdsch_fprint(FILE *f,
ra_pdsch_t *ra,
uint32_t nof_prb);
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);
LIBLTE_API void ra_pusch_fprint(FILE *f,
ra_pusch_t *ra,
uint32_t nof_prb);
#endif /* RB_ALLOC_H_ */

@ -45,57 +45,91 @@
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int k[4];
int k0;
int l;
uint32_t k[4];
uint32_t k0;
uint32_t l;
bool assigned;
}regs_reg_t;
typedef struct LIBLTE_API {
int nof_regs;
uint32_t nof_regs;
regs_reg_t **regs;
}regs_ch_t;
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;
lte_cell_t cell;
uint32_t max_ctrl_symbols;
uint32_t cfi;
bool cfi_initiated;
uint32_t ngroups_phich;
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;
uint32_t nof_regs;
regs_reg_t *regs;
}regs_t;
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);
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);
LIBLTE_API int regs_init(regs_t *h,
phich_resources_t phich_res,
phich_length_t phich_len,
lte_cell_t cell);
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]);
LIBLTE_API void regs_free(regs_t *h);
LIBLTE_API int regs_set_cfi(regs_t *h,
uint32_t nof_ctrl_symbols);
LIBLTE_API uint32_t 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]);
LIBLTE_API uint32_t regs_phich_nregs(regs_t *h);
LIBLTE_API int regs_phich_add(regs_t *h,
cf_t phich_symbols[REGS_PHICH_NSYM],
uint32_t 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],
uint32_t ngroup);
LIBLTE_API uint32_t regs_phich_ngroups(regs_t *h);
LIBLTE_API int regs_phich_reset(regs_t *h,
cf_t *slot_symbols);
LIBLTE_API int regs_pdcch_nregs(regs_t *h, uint32_t cfi);
LIBLTE_API int regs_pdcch_put(regs_t *h,
cf_t *pdcch_symbols,
cf_t *slot_symbols);
LIBLTE_API int regs_pdcch_put_offset(regs_t *h,
cf_t *pdcch_symbols,
cf_t *slot_symbols,
uint32_t start_reg,
uint32_t nof_regs);
LIBLTE_API int regs_pdcch_get(regs_t *h,
cf_t *slot_symbols,
cf_t *pdcch_symbols);
LIBLTE_API int regs_pdcch_get_offset(regs_t *h,
cf_t *slot_symbols,
cf_t *pdcch_symbols,
uint32_t start_reg,
uint32_t nof_regs);
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);
#endif // REGS_H_
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 // REGS_H_

@ -50,11 +50,14 @@
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/common/fft.h"
#include "liblte/phy/common/sequence.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/ch_estimation/refsignal.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/resampling/decim.h"
#include "liblte/phy/resampling/resample_arb.h"
#include "liblte/phy/channel/ch_awgn.h"
#include "liblte/phy/fec/viterbi.h"
@ -90,9 +93,12 @@
#include "liblte/phy/phch/pcfich.h"
#include "liblte/phy/phch/phich.h"
#include "liblte/phy/scrambling/scrambling.h"
#include "liblte/phy/ue/ue_sync.h"
#include "liblte/phy/ue/ue_mib.h"
#include "liblte/phy/ue/ue_celldetect.h"
#include "liblte/phy/ue/ue_dl.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/scrambling/scrambling.h"
#include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sfo.h"

@ -0,0 +1,39 @@
/**
*
* \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 DECIM_H
#define DECIM_H_
#include "liblte/config.h"
typedef _Complex float cf_t;
LIBLTE_API void decim_c(cf_t *input, cf_t *output, int M, int len);
LIBLTE_API void decim_f(float *input, float *output, int M, int len);
#endif // DECIM_H

@ -26,15 +26,73 @@
*/
#ifndef INTERP_H
#define INTERP_H_
#define INTERP_H
#include <stdint.h>
#include "liblte/config.h"
typedef _Complex float cf_t;
typedef enum LIBLTE_API {LINEAR} interp_type_t;
typedef struct LIBLTE_API {
interp_type_t type;
float *in_mag;
float *in_arg;
float *in_mag0;
float *in_arg0;
float *in_mag1;
float *in_arg1;
float *out_mag;
float *out_arg;
float *out_arg2;
int16_t *table_idx;
cf_t *out_cexp;
cf_t *out_prod;
cf_t *cexptable;
uint32_t len;
uint32_t M;
}interp_t;
LIBLTE_API int interp_init(interp_t *q,
interp_type_t type,
uint32_t len,
uint32_t M);
LIBLTE_API void interp_free(interp_t *q);
LIBLTE_API void interp_run(interp_t *q,
cf_t *input,
cf_t *output);
LIBLTE_API void interp_run_offset(interp_t *q,
cf_t *input,
cf_t *output,
uint32_t off_st,
uint32_t off_end);
LIBLTE_API void interp_linear_offset(cf_t *input,
cf_t *output,
uint32_t M,
uint32_t len,
uint32_t off_st,
uint32_t off_end);
LIBLTE_API void interp_linear_c(cf_t *input,
cf_t *output,
uint32_t M,
uint32_t len);
LIBLTE_API void interp_linear_offset(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);
LIBLTE_API void interp_linear_f(float *input,
float *output,
uint32_t M,
uint32_t len);
#endif // INTERP_H

@ -32,6 +32,7 @@
#include <complex.h>
#include "liblte/config.h"
#include "liblte/phy/utils/cexptab.h"
typedef _Complex float cf_t;
@ -48,10 +49,20 @@ typedef struct LIBLTE_API {
cf_t *cur_cexp;
}cfo_t;
LIBLTE_API int cfo_init(cfo_t *h, int nsamples);
LIBLTE_API int cfo_init(cfo_t *h,
uint32_t nsamples);
LIBLTE_API void cfo_free(cfo_t *h);
LIBLTE_API void cfo_set_tol(cfo_t *h, float tol);
LIBLTE_API void cfo_correct(cfo_t *h, cf_t *x, float freq);
LIBLTE_API int cfo_realloc(cfo_t *h,
uint32_t samples);
LIBLTE_API void cfo_set_tol(cfo_t *h,
float tol);
LIBLTE_API void cfo_correct(cfo_t *h,
cf_t *input,
cf_t *output,
float freq);
#endif // CFO_

@ -42,7 +42,6 @@ typedef _Complex float cf_t; /* this is only a shortcut */
#define DEFAULT_CORRELATION_TH 10000
#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
@ -67,45 +66,45 @@ typedef struct LIBLTE_API {
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;
uint32_t frame_size;
uint32_t N_id_2;
uint32_t fft_size;
cf_t *pss_signal_freq[3]; // One sequence for each N_id_2
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 int pss_synch_init_fft(pss_synch_t *q,
uint32_t frame_size,
uint32_t fft_size);
LIBLTE_API int pss_synch_init(pss_synch_t *q,
uint32_t 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);
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);
LIBLTE_API int pss_generate(cf_t *signal,
uint32_t N_id_2);
LIBLTE_API void pss_put_slot(cf_t *pss_signal,
cf_t *slot,
uint32_t nof_prb,
lte_cp_t cp);
LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q,
uint32_t N_id_2);
/* Automatic frame management functions (for periodic calling) */
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);
LIBLTE_API int pss_synch_find_pss(pss_synch_t *q,
cf_t *input,
float *corr_peak_value);
LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q,
cf_t *pss_recv);
/* High-level API */

@ -38,26 +38,20 @@
typedef _Complex float cf_t; /* this is only a shortcut */
/** gives the beginning of the SSS symbol (to be passed to sss_synch_m0m1).
* subframe_sz is the length of the subframe, e.g. 1920 for the 1.9 MHz
* symbol_sz is the OFDM symbol size (including CP), e.g. 137 for the 1.9 MHz
*/
#define SSS_SYMBOL_ST(subframe_sz, symbol_sz) (subframe_sz/2-2*symbol_sz)
#define SSS_POS_SYMBOL 33
#define SSS_DFT_LEN 128
#define N_SSS 31
#define SSS_LEN 2*N_SSS
#define SSS_MAX_FFT_LEN 2048
struct sss_tables{
int z1[N_SSS][N_SSS];
int c[2][N_SSS];
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.
* Should use vec_malloc() to make it platform agnostic.
*/
struct fc_tables{
cf_t z1[N_SSS+1][N_SSS+1];
@ -71,33 +65,67 @@ typedef struct LIBLTE_API {
dft_plan_t dftp_input;
uint32_t fft_size;
float corr_peak_threshold;
int symbol_sz;
int subframe_sz;
uint32_t symbol_sz;
uint32_t subframe_sz;
uint32_t N_id_2;
int N_id_1_table[30][30];
struct fc_tables fc_tables;
uint32_t N_id_1_table[30][30];
struct fc_tables fc_tables[3]; // one for each N_id_2
}sss_synch_t;
/* Basic functionality */
LIBLTE_API int sss_synch_init(sss_synch_t *q);
LIBLTE_API int sss_synch_init(sss_synch_t *q,
uint32_t fft_size);
LIBLTE_API int sss_synch_realloc(sss_synch_t *q,
uint32_t fft_size);
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);
LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q, int N_id_2);
LIBLTE_API void sss_generate(float *signal0,
float *signal5,
uint32_t cell_id);
LIBLTE_API void sss_put_slot(float *sss,
cf_t *symbol,
uint32_t nof_prb,
lte_cp_t cp);
LIBLTE_API int sss_synch_set_N_id_2(sss_synch_t *q,
uint32_t N_id_2);
LIBLTE_API int sss_synch_m0m1(sss_synch_t *q,
cf_t *input,
uint32_t *m0,
float *m0_value,
uint32_t *m1,
float *m1_value);
LIBLTE_API uint32_t sss_synch_subframe(uint32_t m0,
uint32_t m1);
LIBLTE_API int sss_synch_N_id_1(sss_synch_t *q,
uint32_t m0,
uint32_t m1);
LIBLTE_API int sss_synch_frame(sss_synch_t *q,
cf_t *input,
uint32_t *subframe_idx,
uint32_t *N_id_1);
LIBLTE_API void sss_synch_set_threshold(sss_synch_t *q,
float threshold);
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);
LIBLTE_API void sss_synch_set_symbol_sz(sss_synch_t *q,
uint32_t symbol_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);
LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q,
uint32_t subframe_sz);
/* High-level API */
@ -105,18 +133,18 @@ LIBLTE_API void sss_synch_set_subframe_sz(sss_synch_t *q, int subframe_sz);
typedef struct LIBLTE_API {
sss_synch_t obj;
struct sss_synch_init {
int N_id_2;
uint32_t N_id_2;
} init;
cf_t *input;
int in_len;
uint32_t in_len;
struct sss_synch_ctrl_in {
int symbol_sz;
int subframe_sz;
int correlation_threshold;
uint32_t symbol_sz;
uint32_t subframe_sz;
uint32_t correlation_threshold;
} ctrl_in;
struct sss_synch_ctrl_out {
int subframe_idx;
int N_id_1;
uint32_t subframe_idx;
uint32_t N_id_1;
} ctrl_out;
}sss_synch_hl;

@ -30,15 +30,19 @@
#define SYNC_
#include <stdbool.h>
#include <math.h>
#include "liblte/config.h"
#include "pss.h"
#include "sss.h"
#include "sfo.h"
#include "liblte/phy/sync/pss.h"
#include "liblte/phy/sync/sss.h"
#define FFT_SIZE_MIN 64
#define FFT_SIZE_MAX 2048
/**
*
* This object performs time and frequency synchronization using the PSS and SSS signals.
*
* The object is designed to work with signals sampled at 1.92 Mhz centered at the carrier frequency.
* Thus, downsampling is required if the signal is sampled at higher frequencies.
*
@ -47,60 +51,83 @@
* functions sync_pss_det_absolute() and sync_pss_det_peakmean().
*/
enum sync_pss_det { ABSOLUTE, PEAK_MEAN};
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;
pss_synch_t pss;
sss_synch_t sss;
float threshold;
float peak_to_avg;
int force_N_id_2;
int N_id_2;
int N_id_1;
int slot_id;
float mean_energy;
float peak_value;
float mean_peak_value;
uint32_t N_id_2;
uint32_t N_id_1;
uint32_t sf_idx;
uint32_t fft_size;
uint32_t frame_size;
uint64_t frame_cnt;
float cfo;
lte_cp_t cp;
bool detect_cp;
bool sss_en;
bool normalize_en;
lte_cp_t cp;
}sync_t;
LIBLTE_API int sync_init(sync_t *q, int frame_size);
LIBLTE_API int sync_init(sync_t *q,
uint32_t frame_size,
uint32_t fft_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 */
LIBLTE_API int sync_run(sync_t *q, cf_t *input);
LIBLTE_API void sync_reset(sync_t *q);
/* Finds a correlation peak in the input signal around position find_offset */
LIBLTE_API int sync_find(sync_t *q,
cf_t *input,
uint32_t find_offset,
uint32_t *peak_position);
/* Sets the threshold for peak comparison */
LIBLTE_API void sync_set_threshold(sync_t *q, float threshold);
/* Set peak comparison to absolute value */
LIBLTE_API void sync_pss_det_absolute(sync_t *q);
/* Set peak comparison to relative to the mean */
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) */
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) */
LIBLTE_API void sync_force_cp(sync_t *q, lte_cp_t cp);
/* Enables/Disables SSS detection (useful for tracking mode) */
LIBLTE_API void sync_sss_en(sync_t *q, bool enabled);
/* Gets the slot id (0 or 10) */
LIBLTE_API int sync_get_slot_id(sync_t *q);
/* Gets the last peak-to-average ratio */
LIBLTE_API float sync_get_peak_to_avg(sync_t *q);
/* Gets the N_id_2 from the last call to synch_run() */
LIBLTE_API int sync_get_N_id_2(sync_t *q);
/* Gets the N_id_1 from the last call to synch_run() */
LIBLTE_API int sync_get_N_id_1(sync_t *q);
LIBLTE_API void sync_set_threshold(sync_t *q,
float threshold);
/* Gets the subframe idx (0 or 5) */
LIBLTE_API uint32_t sync_get_sf_idx(sync_t *q);
/* Gets the last peak value */
LIBLTE_API float sync_get_last_peak_value(sync_t *q);
/* Gets the mean peak value */
LIBLTE_API float sync_get_peak_value(sync_t *q);
/* Gets the last input signal energy estimation value */
LIBLTE_API float sync_get_input_energy(sync_t *q);
/* Sets the N_id_2 to search for */
LIBLTE_API int sync_set_N_id_2(sync_t *q,
uint32_t N_id_2);
/* Gets the Physical CellId from the last call to synch_run() */
LIBLTE_API int sync_get_cell_id(sync_t *q);
/* Gets the CFO estimation from the last call to synch_run() */
LIBLTE_API float sync_get_cfo(sync_t *q);
/* Gets the CP length estimation from the last call to synch_run() */
LIBLTE_API lte_cp_t sync_get_cp(sync_t *q);
/* Enables/Disables energy normalization every frame. If disabled, uses the mean */
LIBLTE_API void sync_normalize_en(sync_t *q,
bool enable);
/* Enables/Disables SSS detection */
LIBLTE_API void sync_sss_en(sync_t *q,
bool enabled);
LIBLTE_API bool sync_sss_detected(sync_t *q);
/* Enables/Disables CP detection */
LIBLTE_API void sync_cp_en(sync_t *q,
bool enabled);
#endif // SYNC_

@ -0,0 +1,131 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef UE_CELLSEARCH_
#define UE_CELLSEARCH_
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
/************************************************************
*
* This object scans a signal for LTE cells using the known PSS
* and SSS sequences.
*
* The function ue_celldetect_scan() shall be called multiple times,
* each passing a number of samples multiple of 4800, sampled at 960 KHz
* (that is, 5 ms of samples).
*
* The function returns 0 until a signal is found nof_frames_detected times or
* after nof_frames_total with no signal detected.
*
* See ue_cell_detect.c for an example.
*
************************************************************/
/**
* TODO: Check also peak offset
*/
#define CS_DEFAULT_MAXFRAMES_TOTAL 300
#define CS_DEFAULT_MAXFRAMES_DETECTED 30
#define CS_DEFAULT_NOFFRAMES_TOTAL 100
#define CS_DEFAULT_NOFFRAMES_DETECTED 10
#define CS_FIND_THRESHOLD 0.6
#define CS_FRAME_UNALIGNED -3
#define CS_CELL_DETECTED 2
#define CS_CELL_NOT_DETECTED 3
typedef struct LIBLTE_API {
uint32_t cell_id;
lte_cp_t cp;
float peak;
uint32_t mode;
} ue_celldetect_result_t;
typedef struct LIBLTE_API {
sync_t sfind;
uint32_t max_frames_total;
uint32_t max_frames_detected;
uint32_t nof_frames_total;
uint32_t nof_frames_detected;
uint32_t current_nof_detected;
uint32_t current_nof_total;
uint32_t current_N_id_2;
uint32_t *mode_ntimes;
char *mode_counted;
ue_celldetect_result_t *candidates;
} ue_celldetect_t;
LIBLTE_API int ue_celldetect_init(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_init_max(ue_celldetect_t *q,
uint32_t max_frames_total,
uint32_t max_frames_detected);
LIBLTE_API void ue_celldetect_free(ue_celldetect_t *q);
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q,
cf_t *signal,
uint32_t nsamples,
ue_celldetect_result_t *found_cell);
LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q,
uint32_t nof_frames);
LIBLTE_API int ue_celldetect_set_nof_frames_detected(ue_celldetect_t *q,
uint32_t nof_frames);
LIBLTE_API void ue_celldetect_set_threshold(ue_celldetect_t *q,
float threshold);
LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q);
#endif // SYNC_FRAME_

@ -0,0 +1,99 @@
/**
*
* \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 UEDL_H
#define UEDL_H
/*******************************************************
*
* This module is a frontend to all the data and control channels processing
* modules.
********************************************************/
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/common/fft.h"
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/phch/dci.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/phch/pcfich.h"
#include "liblte/phy/phch/pdcch.h"
#include "liblte/phy/phch/pdsch.h"
#include "liblte/phy/phch/phich.h"
#include "liblte/phy/phch/ra.h"
#include "liblte/phy/phch/regs.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
#include "liblte/config.h"
#define NOF_HARQ_PROCESSES 8
typedef struct LIBLTE_API {
pbch_t pbch;
pcfich_t pcfich;
pdcch_t pdcch;
pdsch_t pdsch;
pdsch_harq_t harq_process[NOF_HARQ_PROCESSES];
regs_t regs;
lte_fft_t fft;
chest_t chest;
lte_cell_t cell;
cf_t *sf_symbols;
cf_t *ce[MAX_PORTS];
uint64_t pkt_errors;
uint64_t pkts_total;
uint64_t nof_trials;
uint32_t sfn;
bool pbch_decoded;
uint16_t user_rnti;
}ue_dl_t;
/* This function shall be called just after the initial synchronization */
LIBLTE_API int ue_dl_init(ue_dl_t *q,
lte_cell_t cell,
phich_resources_t phich_resources,
phich_length_t phich_length,
uint16_t user_rnti);
LIBLTE_API void ue_dl_free(ue_dl_t *q);
LIBLTE_API int ue_dl_decode(ue_dl_t *q,
cf_t *sf_buffer,
char *data,
uint32_t sf_idx,
uint16_t rnti);
#endif

@ -0,0 +1,109 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef UE_MIB_
#define UE_MIB_
/************************************************************
*
* This object decodes the MIB from the PBCH of an LTE signal.
*
* The function ue_mib_decode() shall be called multiple times,
* each passing a number of samples multiple of 19200, sampled at 1.92 MHz
* (that is, 10 ms of samples).
*
* The function uses the sync_t object to find the PSS sequence and
* decode the PBCH to obtain the MIB.
*
* The function returns 0 until the MIB is decoded.
*
* See ue_cell_detect.c for an example.
*
************************************************************/
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
#define MIB_FIND_THRESHOLD 0.6
#define MIB_NOF_PORTS 2
#define MIB_FRAME_SIZE 9600
#define MIB_FRAME_UNALIGNED -3
#define MIB_FOUND 1
#define MIB_NOTFOUND 0
typedef struct LIBLTE_API {
sync_t sfind;
uint32_t cell_id;
cf_t *slot1_symbols;
cf_t *ce[MIB_NOF_PORTS];
lte_fft_t fft;
chest_t chest;
pbch_t pbch;
uint32_t frame_cnt;
uint32_t last_frame_trial;
} ue_mib_t;
LIBLTE_API int ue_mib_init(ue_mib_t *q,
uint32_t cell_id,
lte_cp_t cp);
LIBLTE_API void ue_mib_free(ue_mib_t *q);
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
LIBLTE_API int ue_mib_decode(ue_mib_t *q,
cf_t *signal,
uint32_t nsamples,
pbch_mib_t *mib);
LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q,
float threshold);
LIBLTE_API void ue_mib_reset(ue_mib_t *q);
#endif // SYNC_FRAME_

@ -0,0 +1,124 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef UE_SYNC_
#define UE_SYNC_
#include <stdbool.h>
#include "liblte/config.h"
#include "liblte/phy/sync/sync.h"
#include "liblte/phy/sync/cfo.h"
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/phch/pbch.h"
#include "liblte/phy/common/fft.h"
/**************************************************************
*
* This object automatically manages the cell synchronization procedure.
*
* The main function is ue_sync_get_buffer(), which returns a pointer
* to the aligned subframe of samples (before FFT). This function
* should be called regularly, returning every 1 ms. It reads from the
* USRP, aligns the samples to the subframe and performs time/freq synch.
*
* The function returns 1 when the signal is correctly acquired and the
* returned buffer is aligned with the subframe.
*
*************************************************************/
typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t;
#define TRACK_MAX_LOST 10
#define MEASURE_EXEC_TIME
typedef struct LIBLTE_API {
sync_t sfind;
sync_t strack;
void *stream;
int (*recv_callback)(void*, void*, uint32_t);
ue_sync_state_t state;
cf_t *input_buffer;
/* These count half frames (5ms) */
uint64_t frame_ok_cnt;
uint32_t frame_no_cnt;
uint32_t frame_total_cnt;
/* this is the system frame number (SFN) */
uint32_t frame_number;
lte_cell_t cell;
uint32_t sf_idx;
cfo_t cfocorr;
float cur_cfo;
bool decode_sss_on_track;
uint32_t peak_idx;
int time_offset;
float mean_time_offset;
#ifdef MEASURE_EXEC_TIME
float mean_exec_time;
#endif
} ue_sync_t;
LIBLTE_API int ue_sync_init(ue_sync_t *q,
lte_cell_t cell,
int (recv_callback)(void*, void*, uint32_t),
void *stream_handler);
LIBLTE_API void ue_sync_free(ue_sync_t *q);
LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q,
cf_t **sf_symbols);
LIBLTE_API void ue_sync_reset(ue_sync_t *q);
LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q,
bool enabled);
LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q);
LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q);
LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q);
LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q);
#endif // SYNC_FRAME_

@ -38,7 +38,7 @@ 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);
LIBLTE_API uint32_t bit_count(uint32_t n);
#endif // BIT_

@ -30,19 +30,28 @@
#define CEXPTAB_
#include <complex.h>
#include <stdint.h>
#include "liblte/config.h"
typedef _Complex float cf_t;
typedef struct LIBLTE_API {
int size;
uint32_t size;
cf_t *tab;
}cexptab_t;
LIBLTE_API int cexptab_init(cexptab_t *nco, int size);
LIBLTE_API int cexptab_init(cexptab_t *nco,
uint32_t size);
LIBLTE_API void cexptab_free(cexptab_t *nco);
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);
LIBLTE_API void cexptab_gen(cexptab_t *nco,
cf_t *x,
float freq,
uint32_t len);
LIBLTE_API void cexptab_gen_direct(cf_t *x,
float freq,
uint32_t len);
#endif // CEXPTAB_

@ -32,23 +32,36 @@
#include "liblte/config.h"
#include "liblte/phy/utils/dft.h"
typedef _Complex float cf_t;
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;
cf_t *input_fft;
cf_t *filter_fft;
cf_t *output_fft;
cf_t *output_fft2;
uint32_t input_len;
uint32_t filter_len;
uint32_t output_len;
dft_plan_t input_plan;
dft_plan_t filter_plan;
dft_plan_t output_plan;
}conv_fft_cc_t;
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);
LIBLTE_API int conv_fft_cc_init(conv_fft_cc_t *q,
uint32_t input_len,
uint32_t filter_len);
LIBLTE_API void conv_fft_cc_free(conv_fft_cc_t *q);
LIBLTE_API uint32_t conv_fft_cc_run(conv_fft_cc_t *q,
cf_t *input,
cf_t *filter,
cf_t *output);
LIBLTE_API int conv_cc(_Complex float *input, _Complex float *filter, _Complex float *output, int input_len, int filter_len);
LIBLTE_API uint32_t conv_cc(cf_t *input,
cf_t *filter,
cf_t *output,
uint32_t input_len,
uint32_t filter_len);
#endif // CONVOLUTION_H_

@ -44,6 +44,7 @@ LIBLTE_API extern int verbose;
#define VERBOSE_ISINFO() (verbose>=VERBOSE_INFO)
#define VERBOSE_ISDEBUG() (verbose>=VERBOSE_DEBUG)
#define VERBOSE_ISNONE() (verbose==VERBOSE_NONE)
#define PRINT_DEBUG verbose=VERBOSE_DEBUG
#define PRINT_INFO verbose=VERBOSE_INFO

@ -30,51 +30,87 @@
#define VECTOR_
#include <stdio.h>
#include <stdint.h>
#include "liblte/config.h"
typedef _Complex float cf_t;
#define EXPAVERAGE(data, average, nframes) (((data) + (average) * (nframes)) / ((nframes) + 1))
/** Return the sum of all the elements */
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);
LIBLTE_API int vec_acc_ii(int *x, uint32_t len);
LIBLTE_API float vec_acc_ff(float *x, uint32_t len);
LIBLTE_API cf_t vec_acc_cc(cf_t *x, uint32_t len);
LIBLTE_API void *vec_malloc(int size);
LIBLTE_API void *vec_malloc(uint32_t size);
LIBLTE_API void *vec_realloc(void *ptr, uint32_t old_size, uint32_t new_size);
/* print vectors */
LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, 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);
LIBLTE_API void vec_fprint_c(FILE *stream, cf_t *x, uint32_t len);
LIBLTE_API void vec_fprint_f(FILE *stream, float *x, uint32_t len);
LIBLTE_API void vec_fprint_b(FILE *stream, char *x, uint32_t len);
LIBLTE_API void vec_fprint_i(FILE *stream, int *x, uint32_t len);
LIBLTE_API void vec_fprint_hex(FILE *stream, char *x, uint32_t len);
/* Saves a vector to a file */
LIBLTE_API void vec_save_file(char *filename, void *buffer, uint32_t len);
/* sum two vectors */
LIBLTE_API void vec_sum_ch(char *z, char *x, char *y, int len);
LIBLTE_API void vec_sum_ccc(cf_t *z, cf_t *x, cf_t *y, int len);
LIBLTE_API void vec_sum_ch(char *x, char *y, char *z, uint32_t len);
LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* substract two vectors z=x-y */
LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len);
/* Square distance */
LIBLTE_API void vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints);
/* scalar product */
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);
LIBLTE_API void vec_sc_prod_cfc(cf_t *x, float h, cf_t *z, uint32_t len);
LIBLTE_API void vec_sc_prod_ccc(cf_t *x, cf_t h, cf_t *z, uint32_t len);
LIBLTE_API void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len);
LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len);
LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len);
LIBLTE_API void vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len);
/* vector product (element-wise) */
LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* vector product (element-wise) */
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);
LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len);
/* conjugate vector product (element-wise) */
LIBLTE_API void vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* Dot-product */
LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len);
LIBLTE_API cf_t vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len);
LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len);
/* z=x/y vector division (element-wise) */
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, int len);
LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len);
/* conjugate */
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, int len);
LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len);
/* average vector power */
LIBLTE_API float vec_avg_power_cf(cf_t *x, int len);
LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len);
/* return the index of the maximum value in the vector */
LIBLTE_API int vec_max_fi(float *x, int len);
LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len);
LIBLTE_API uint32_t vec_max_abs_ci(cf_t *x, uint32_t len);
/* quantify vector of floats and convert to unsigned char */
LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, int len);
LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len);
/* magnitude of each vector element */
LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, int len);
LIBLTE_API void vec_abs_cf(cf_t *x, float *abs, uint32_t len);
/* argument of each vector element */
LIBLTE_API void vec_arg_cf(cf_t *x, float *arg, uint32_t len);
#endif // VECTOR_

@ -0,0 +1,100 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2014 The libLTE Developers. See the
* COPYRIGHT file at the top-level directory of this distribution.
*
* \section LICENSE
*
* This file is part of the libLTE library.
*
* libLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* libLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* A copy of the GNU Lesser General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/agc/agc.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
int agc_init (agc_t *q) {
bzero(q, sizeof(agc_t));
agc_reset(q);
return LIBLTE_SUCCESS;
}
void agc_free(agc_t *q) {
bzero(q, sizeof(agc_t));
}
void agc_reset(agc_t *q) {
q->bandwidth = AGC_DEFAULT_BW;
q->lock = false;
q->gain = 1.0;
q->y_out = 1.0;
q->isfirst = true;
}
void agc_set_bandwidth(agc_t *q, float bandwidth) {
q->bandwidth = bandwidth;
}
float agc_get_rssi(agc_t *q) {
return 1.0/q->gain;
}
float agc_get_output_level(agc_t *q) {
return q->y_out;
}
float agc_get_gain(agc_t *q) {
return q->gain;
}
void agc_lock(agc_t *q, bool enable) {
q->lock = enable;
}
void agc_process(agc_t *q, cf_t *input, cf_t *output, uint32_t len) {
// Apply current gain to input signal
vec_sc_prod_cfc(input, q->gain, output, len);
// compute output energy estimate
float y = sqrtf(crealf(vec_dot_prod_conj_ccc(output, output, len))/len);
if (q->isfirst) {
q->y_out = y;
q->gain = 1/y;
q->isfirst = false;
} else {
q->y_out = (1-q->bandwidth) * q->y_out + q->bandwidth * y;
if (!q->lock) {
q->gain *= expf(-0.5*q->bandwidth*logf(q->y_out));
}
}
DEBUG("AGC gain: %.3f y_out=%.3f, y=%.3f\n", q->gain, q->y_out, y);
}

@ -29,24 +29,36 @@
#include <strings.h>
#include <string.h>
#include <complex.h>
#include <assert.h>
#include <math.h>
#include "liblte/phy/ch_estimation/chest.h"
#include "liblte/phy/resampling/interp.h"
#include "liblte/phy/utils/vector.h"
#include "liblte/phy/utils/debug.h"
#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz)
#define SF_SZ(q) (2 * SLOT_SZ(q))
void chest_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
#define VOLK_INTERP
void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
chest_ref_fprint(q, stream, nslot, port_id);
chest_recvsig_fprint(q, stream, nslot, port_id);
chest_ce_fprint(q, stream, nslot, port_id);
}
void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
/* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports
* used during the call to chest_init().
*/
int chest_set_nof_ports(chest_t *q, uint32_t nof_ports) {
if (nof_ports < q->nof_ports) {
q->nof_ports = nof_ports;
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "refs%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
@ -56,7 +68,7 @@ void chest_ref_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
fprintf(stream, "];\n");
}
void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "recvsig%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
@ -66,7 +78,7 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
fprintf(stream, "];\n");
}
void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
int i;
fprintf(stream, "mag%d=[",port_id);
for (i=0;i<q->refsignal[port_id][nslot].nof_refs;i++) {
@ -80,42 +92,62 @@ void chest_ce_fprint(chest_t *q, FILE *stream, int nslot, int port_id) {
fprintf(stream, "];\n");
}
void chest_ce_ref(chest_t *q, cf_t *input, int nslot, int port_id, int nref) {
int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) {
int fidx, tidx;
cf_t known_ref, channel_ref;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
nslot < NSLOTS_X_FRAME &&
port_id < q->nof_ports)
{
if (nref < q->refsignal[port_id][nslot].nof_refs) {
fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index
tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index
known_ref = q->refsignal[port_id][nslot].refs[nref].simbol;
channel_ref = input[SAMPLE_IDX(q->nof_prb, tidx, fidx)];
channel_ref = input[tidx * q->nof_re + 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),
DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx,
10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,cargf(channel_ref/known_ref)/M_PI);
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;
q->refsignal[port_id][nslot].ch_est[nref] = 1e-6;
}
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
/* 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;
int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) {
uint32_t i, j;
cf_t x[2], y[MAX_NSYMB];
assert(nslot >= 0 && nslot < NSLOTS_X_FRAME);
assert(port_id >= 0 && port_id < q->nof_ports);
assert(q->refsignal[port_id][nslot].nsymbols <= 2);
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
input != NULL &&
nslot < NSLOTS_X_FRAME &&
port_id < q->nof_ports)
{
if (q->refsignal[port_id][nslot].nsymbols <= 2) {
refsignal_t *r = &q->refsignal[port_id][nslot];
INFO("Estimating channel slot=%d port=%d using %d reference signals\n",
DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n",
nslot, port_id, r->nof_refs);
for (i=0;i<r->nof_refs;i++) {
@ -125,98 +157,162 @@ void chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, int nslot, int port_i
/* interpolate the symbols with references
* in the freq domain */
for (i=0;i<r->nsymbols;i++) {
#ifdef VOLK_INTERP
interp_run_offset(&q->interp_freq[port_id],
&r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re],
r->voffset, RE_X_RB/2-r->voffset);
#else
interp_linear_offset(&r->ch_est[i * r->nof_refs/2],
&ce[r->symbols_ref[i] * q->nof_prb * RE_X_RB], RE_X_RB/2,
&ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2,
r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset);
#endif
}
/* now interpolate in the time domain */
for (i=0;i<q->nof_prb * RE_X_RB; i++) {
for (i=0;i<q->nof_re; i++) {
if (r->nsymbols > 1) {
for (j=0;j<r->nsymbols;j++) {
x[j] = ce[r->symbols_ref[j] * q->nof_prb * RE_X_RB + i];
x[j] = ce[r->symbols_ref[j] * q->nof_re + i];
}
#ifdef VOLK_INTERP
interp_run_offset(&q->interp_time[port_id], x, y,
r->symbols_ref[0], 3);
#else
interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0],
2, r->symbols_ref[0], 3);
#endif
} else {
for (j=0;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_prb * RE_X_RB + i];
y[j] = ce[r->symbols_ref[0] * q->nof_re + i];
}
}
for (j=0;j<q->nof_symbols;j++) {
ce[j * q->nof_prb * RE_X_RB + i] = y[j];
ce[j * q->nof_re + i] = y[j];
}
}
ret = LIBLTE_SUCCESS;
}
}
return ret;
}
/* Computes channel estimates for each reference in a slot.
* Saves the result for the p-th port to the pointer ce[p]
/* Computes channel estimates for each reference in a subframe and port id.
*/
void chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, int nslot) {
int p;
for (p=0;p<q->nof_ports;p++) {
chest_ce_slot_port(q, input, ce[p], nslot, p);
int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) {
int n, slotsz, ret;
slotsz = q->nof_symbols*q->nof_re;
for (n=0;n<2;n++) {
ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return LIBLTE_SUCCESS;
}
int chest_init(chest_t *q, chest_interp_t interp, lte_cp_t cp, int nof_prb, int nof_ports) {
/* Computes channel estimates for each reference in a slot for all ports.
*/
int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) {
int p, ret;
for (p=0;p<q->nof_ports;p++) {
ret = chest_ce_slot_port(q, input, ce[p], nslot, p);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return LIBLTE_SUCCESS;
}
if (nof_ports > MAX_PORTS) {
fprintf(stderr, "Error: Maximum ports %d\n", MAX_PORTS);
return -1;
/* Computes channel estimates for each reference in a subframe for all ports.
*/
int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) {
int p, n, slotsz, ret;
slotsz = q->nof_symbols*q->nof_re;
for (p=0;p<q->nof_ports;p++) {
for (n=0;n<2;n++) {
ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
}
return LIBLTE_SUCCESS;
}
int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
if (q != NULL &&
nof_ports <= MAX_PORTS)
{
bzero(q, sizeof(chest_t));
q->nof_ports = nof_ports;
q->nof_symbols = CP_NSYMB(cp);
q->cp = cp;
q->nof_prb = nof_prb;
switch(interp) {
case LINEAR:
q->interp = interp_linear_offset;
}
q->nof_symbols = nof_symbols;
q->nof_re = nof_re;
INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n",
q->nof_symbols, nof_prb, nof_ports);
q->nof_symbols, q->nof_re, nof_ports);
return 0;
ret = LIBLTE_SUCCESS;
}
return ret;
}
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;
int chest_init_LTEDL(chest_t *q, lte_cell_t cell) {
int ret;
ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports);
if (ret != LIBLTE_SUCCESS) {
return ret;
} else {
return chest_ref_LTEDL(q, cell);
}
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;
}
int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) {
int ret = LIBLTE_ERROR_INVALID_INPUTS;
return 0;
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell);
#ifdef VOLK_INTERP
if (ret == LIBLTE_SUCCESS) {
if (nslot == 0) {
ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2);
if (ret == LIBLTE_SUCCESS) {
ret = interp_init(&q->interp_time[port_id], LINEAR, 2,
q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]);
}
}
}
#endif
}
return ret;
}
int chest_ref_LTEDL_slot(chest_t *q, int nslot, int cell_id) {
int p;
int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) {
int p, ret;
for (p=0;p<q->nof_ports;p++) {
if (chest_ref_LTEDL_slot_port(q, p, nslot, cell_id)) {
return -1;
ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return 0;
return LIBLTE_SUCCESS;
}
int chest_ref_LTEDL(chest_t *q, int cell_id) {
int n;
int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) {
int n, ret;
for (n=0;n<NSLOTS_X_FRAME;n++) {
if (chest_ref_LTEDL_slot(q, n, cell_id)) {
return -1;
ret = chest_ref_LTEDL_slot(q, n, cell);
if (ret != LIBLTE_SUCCESS) {
return ret;
}
}
return 0;
return LIBLTE_SUCCESS;
}
void chest_free(chest_t *q) {
@ -226,18 +322,29 @@ void chest_free(chest_t *q) {
refsignal_free(&q->refsignal[p][n]);
}
}
#ifdef VOLK_INTERP
for (p=0;p<MAX_PORTS;p++) {
interp_free(&q->interp_freq[p]);
interp_free(&q->interp_time[p]);
}
#endif
bzero(q, sizeof(chest_t));
}
/* Fills l[2] with the symbols in the slot nslot that contain references.
* returns the number of symbols with references (in the slot)
*/
int chest_ref_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);
int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) {
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME)
{
memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols);
return q->refsignal[port_id][nslot].nsymbols;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
@ -245,6 +352,8 @@ int chest_ref_symbols(chest_t *q, int port_id, int nslot, int l[2]) {
*/
int chest_initialize(chest_hl* h) {
lte_cell_t cell;
if (!h->init.nof_symbols) {
h->init.nof_symbols = CPNORM_NSYMB; // Normal CP
}
@ -252,37 +361,23 @@ int chest_initialize(chest_hl* h) {
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)) {
cell.id = h->init.cell_id;
cell.nof_ports = h->init.nof_ports;
cell.nof_prb = h->init.nof_prb;
cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT;
if (chest_init_LTEDL(&h->obj, cell)) {
fprintf(stderr, "Error initializing equalizer\n");
return -1;
}
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 */
/** This function must be called in an subframe basis (1ms) 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;
}
chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx);
return 0;
}

@ -40,7 +40,7 @@
#define idx(x, y) (l*nof_refs_x_symbol+i)
int refsignal_v(int port_id, int ns, int symbol_id) {
int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) {
int v=-1;
switch(port_id) {
case 0:
@ -67,70 +67,80 @@ int refsignal_v(int port_id, int ns, int symbol_id) {
return v;
}
int refsignal_k(int m, int v, int cell_id) {
uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) {
return 6*m+((v+(cell_id%6))%6);
}
void refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
int i;
int fidx, tidx;
int refsignal_put(refsignal_t *q, cf_t *slot_symbols) {
uint32_t i;
uint32_t fidx, tidx;
if (q != NULL &&
slot_symbols != NULL)
{
for (i=0;i<q->nof_refs;i++) {
fidx = q->refs[i].freq_idx; // reference frequency index
tidx = q->refs[i].time_idx; // reference time index
slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol;
}
return LIBLTE_SUCCESS;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}
/** Initializes refsignal_t object according to 3GPP 36.211 6.10.1
*
*/
int refsignal_init_LTEDL(refsignal_t *q, 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;
int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot,
lte_cell_t cell) {
uint32_t c_init;
uint32_t ns, l, lp[2];
uint32_t N_cp;
uint32_t i;
int ret = LIBLTE_ERROR_INVALID_INPUTS;
sequence_t seq;
int v;
int mp;
int nof_refs_x_symbol, nof_ref_symbols;
uint32_t mp;
uint32_t nof_refs_x_symbol, nof_ref_symbols;
if (q != NULL &&
port_id < MAX_PORTS &&
nslot < NSLOTS_X_FRAME &&
lte_cell_isvalid(&cell))
{
bzero(q, sizeof(refsignal_t));
bzero(&seq, sizeof(sequence_t));
if (CP_ISNORM(cp)) {
if (CP_ISNORM(cell.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;
lp[1] = CP_NSYMB(cell.cp) - 3;
} else {
nof_ref_symbols = 1;
lp[0] = 1;
}
nof_refs_x_symbol = 2 * nof_prb;
nof_refs_x_symbol = 2 * cell.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;
q->voffset = cell.id%6;
q->nof_prb = cell.nof_prb;
q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols);
if (!q->symbols_ref) {
return -1;
perror("malloc");
goto free_and_exit;
}
memcpy(q->symbols_ref, lp, sizeof(int) * nof_ref_symbols);
memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols);
q->refs = vec_malloc(q->nof_refs * sizeof(ref_t));
if (!q->refs) {
@ -144,31 +154,34 @@ int refsignal_init_LTEDL(refsignal_t *q, int port_id, int nslot,
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)) {
c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1)
+ 2 * cell.id + N_cp;
ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init);
if (ret != LIBLTE_SUCCESS) {
goto free_and_exit;
}
v = refsignal_v(port_id, ns, lp[l]);
for (i = 0; i < nof_refs_x_symbol; i++) {
mp = i + MAX_PRB - nof_prb;
mp = i + MAX_PRB - cell.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)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id);
q->refs[idx(l,i)].time_idx = lp[l];
}
}
ret = 0;
ret = LIBLTE_SUCCESS;
}
free_and_exit:
if (ret != LIBLTE_ERROR_INVALID_INPUTS) {
sequence_free(&seq);
if (ret == -1) {
}
if (ret == LIBLTE_ERROR) {
refsignal_free(q);
}
return ret;

@ -33,19 +33,22 @@
#include "liblte/phy/phy.h"
int cell_id = -1;
int nof_prb = 6;
lte_cp_t cp = CPNORM;
lte_cell_t cell = {
6, // nof_prb
MAX_PORTS, // nof_ports
1000, // cell_id
CPNORM // cyclic prefix
};
char *output_matlab = NULL;
void usage(char *prog) {
printf("Usage: %s [recov]\n", prog);
printf("\t-r nof_prb [Default %d]\n", nof_prb);
printf("\t-r nof_prb [Default %d]\n", cell.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 (1000 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");
@ -56,13 +59,13 @@ void parse_args(int argc, char **argv) {
while ((opt = getopt(argc, argv, "recov")) != -1) {
switch(opt) {
case 'r':
nof_prb = atoi(argv[optind]);
cell.nof_prb = atoi(argv[optind]);
break;
case 'e':
cp = CPEXT;
cell.cp = CPEXT;
break;
case 'c':
cell_id = atoi(argv[optind]);
cell.id = atoi(argv[optind]);
break;
case 'o':
output_matlab = argv[optind];
@ -131,7 +134,7 @@ int main(int argc, char **argv) {
}
}
num_re = nof_prb * RE_X_RB * CP_NSYMB(cp);
num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp);
input = malloc(num_re * sizeof(cf_t));
if (!input) {
@ -149,28 +152,25 @@ int main(int argc, char **argv) {
goto do_exit;
}
if (cell_id == -1) {
if (cell.id == 1000) {
cid = 0;
max_cid = 504;
} else {
cid = cell_id;
max_cid = cell_id;
cid = cell.id;
max_cid = cell.id;
}
while(cid <= max_cid) {
if (chest_init(&eq, LINEAR, cp, nof_prb, MAX_PORTS)) {
cell.id = cid;
if (chest_init_LTEDL(&eq, cell)) {
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++) {
for (n_port=0;n_port<cell.nof_ports;n_port++) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cid, cp, nof_prb)) {
if (refsignal_init_LTEDL(&refs, n_port, n_slot, cell)) {
fprintf(stderr, "Error initiating CRS slot=%d\n", i);
return -1;
}
@ -185,13 +185,11 @@ int main(int argc, char **argv) {
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];
for (i=0;i<CP_NSYMB(cell.cp);i++) {
for (j=0;j<cell.nof_prb * RE_X_RB;j++) {
float x = -1+(float) i/CP_NSYMB(cell.cp) + cosf(2 * M_PI * (float) j/cell.nof_prb/RE_X_RB);
h[i*cell.nof_prb * RE_X_RB+j] = (3+x) * cexpf(I * x);
input[i*cell.nof_prb * RE_X_RB+j] *= h[i*cell.nof_prb * RE_X_RB+j];
}
}

@ -29,25 +29,31 @@
#include <complex.h>
#include <stdlib.h>
#include <strings.h>
#include <math.h>
#include "gauss.h"
#include "liblte/phy/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;
float ch_awgn_get_variance(float ebno_db, float rate) {
float esno_db = ebno_db + 10 * log10f(rate);
return sqrtf(1 / (powf(10, esno_db / 10)));
}
void ch_awgn_c(const cf_t* x, cf_t* y, float variance, uint32_t len) {
cf_t tmp;
uint32_t i;
for (i=0;i<buff_sz;i++) {
for (i=0;i<len;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;
void ch_awgn_f(const float* x, float* y, float variance, uint32_t len) {
uint32_t i;
for (i=0;i<buff_sz;i++) {
for (i=0;i<len;i++) {
y[i] = x[i] + variance * rand_gauss();
}
}

@ -35,10 +35,10 @@
#include "liblte/phy/utils/debug.h"
#include "liblte/phy/utils/vector.h"
int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb, dft_dir_t dir) {
int symbol_sz = lte_symbol_sz(nof_prb);
if (symbol_sz == -1) {
if (symbol_sz < 0) {
fprintf(stderr, "Error: Invalid nof_prb=%d\n", nof_prb);
return -1;
}
@ -46,7 +46,7 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
fprintf(stderr, "Error: Creating DFT plan\n");
return -1;
}
q->tmp = malloc(symbol_sz * sizeof(cf_t));
q->tmp = malloc((uint32_t) symbol_sz * sizeof(cf_t));
if (!q->tmp) {
perror("malloc");
return -1;
@ -56,15 +56,18 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp_type, int nof_prb, dft_dir_t dir) {
dft_plan_set_norm(&q->fft_plan, true);
dft_plan_set_dc(&q->fft_plan, true);
q->symbol_sz = symbol_sz;
q->nof_symbols = CP_NSYMB(cp_type);
q->cp_type = cp_type;
q->symbol_sz = (uint32_t) symbol_sz;
q->nof_symbols = CP_NSYMB(cp);
q->cp = cp;
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",
q->slot_sz = SLOT_LEN(symbol_sz);
DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%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->cp==CPNORM?"Normal":"Extended", q->nof_re, q->nof_guards);
return LIBLTE_SUCCESS;
}
void lte_fft_free_(lte_fft_t *q) {
@ -75,25 +78,28 @@ void lte_fft_free_(lte_fft_t *q) {
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);
int lte_fft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) {
return lte_fft_init_(q, cp, nof_prb, FORWARD);
}
void lte_fft_free(lte_fft_t *q) {
lte_fft_free_(q);
}
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp_type, int nof_prb) {
int i;
if (lte_fft_init_(q, cp_type, nof_prb, BACKWARD)) {
return -1;
}
int lte_ifft_init(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb) {
uint32_t i;
int ret;
ret = lte_fft_init_(q, cp, nof_prb, BACKWARD);
if (ret == LIBLTE_SUCCESS) {
/* 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;
}
return ret;
}
void lte_ifft_free(lte_fft_t *q) {
@ -103,10 +109,10 @@ void lte_ifft_free(lte_fft_t *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;
void lte_fft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t 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);
input += CP_ISNORM(q->cp)?CP_NORM(i, q->symbol_sz):CP_EXT(q->symbol_sz);
dft_run_c(&q->fft_plan, input, q->tmp);
memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t));
input += q->symbol_sz;
@ -114,13 +120,20 @@ void lte_fft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
}
}
void lte_fft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t n;
for (n=0;n<2;n++) {
lte_fft_run_slot(q, &input[n*q->slot_sz], &output[n*q->nof_re*q->nof_symbols]);
}
}
/* 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;
void lte_ifft_run_slot(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t 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);
cp_len = CP_ISNORM(q->cp)?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_c(&q->fft_plan, q->tmp, &output[cp_len]);
input += q->nof_re;
@ -130,3 +143,9 @@ void lte_ifft_run(lte_fft_t *q, cf_t *input, cf_t *output) {
}
}
void lte_ifft_run_sf(lte_fft_t *q, cf_t *input, cf_t *output) {
uint32_t n;
for (n=0;n<2;n++) {
lte_ifft_run_slot(q, &input[n*q->nof_re*q->nof_symbols], &output[n*q->slot_sz]);
}
}

@ -50,36 +50,115 @@ const int tc_cb_sizes[NOF_TC_CB_SIZES] = { 40, 48, 56, 64, 72, 80, 88, 96, 104,
4800, 4864, 4928, 4992, 5056, 5120, 5184, 5248, 5312, 5376, 5440, 5504,
5568, 5632, 5696, 5760, 5824, 5888, 5952, 6016, 6080, 6144 };
/* Returns true if the structure pointed by cell has valid parameters
*/
bool lte_cell_isvalid(lte_cell_t *cell) {
if (cell->id < 504 &&
cell->nof_ports > 0 &&
cell->nof_ports < MAX_PORTS+1 &&
cell->nof_prb > 5 &&
cell->nof_prb < MAX_PRB+1
) {
return true;
} else {
return false;
}
}
bool lte_N_id_2_isvalid(uint32_t N_id_2) {
if (N_id_2 < 3) {
return true;
} else {
return false;
}
}
bool lte_N_id_1_isvalid(uint32_t N_id_1) {
if (N_id_1 < 169) {
return true;
} else {
return false;
}
}
/*
* 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) {
int lte_cb_size(uint32_t index) {
if (index < NOF_TC_CB_SIZES) {
return tc_cb_sizes[index];
} else {
return -1;
return LIBLTE_ERROR;
}
}
char *lte_mod_string(lte_mod_t mod) {
switch (mod) {
case LTE_BPSK:
return "BPSK";
case LTE_QPSK:
return "QPSK";
case LTE_QAM16:
return "QAM16";
case LTE_QAM64:
return "QAM64";
default:
return "N/A";
}
}
uint32_t lte_mod_bits_x_symbol(lte_mod_t mod) {
switch (mod) {
case LTE_BPSK:
return 1;
case LTE_QPSK:
return 2;
case LTE_QAM16:
return 4;
case LTE_QAM64:
return 6;
default:
return 0;
}
}
char *lte_cp_string(lte_cp_t cp) {
if (cp == CPNORM) {
return "Normal";
} else {
return "Extended";
}
}
/*
* 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 lte_find_cb_index(uint32_t long_cb) {
int j = 0;
while (j < NOF_TC_CB_SIZES && tc_cb_sizes[j] < long_cb) {
j++;
}
if (j == NOF_TC_CB_SIZES) {
return -1;
return LIBLTE_ERROR;
} else {
return j;
}
}
const int lte_symbol_sz(int nof_prb) {
int lte_sampling_freq_hz(uint32_t nof_prb) {
int n = lte_symbol_sz(nof_prb);
if (n == -1) {
return LIBLTE_ERROR;
} else {
return 15000 * n;
}
}
int lte_symbol_sz(uint32_t nof_prb) {
if (nof_prb<=0) {
return -1;
return LIBLTE_ERROR;
}
if (nof_prb<=6) {
return 128;
@ -94,10 +173,22 @@ const int lte_symbol_sz(int nof_prb) {
} else if (nof_prb<=100) {
return 2048;
}
return -1;
return LIBLTE_ERROR;
}
bool lte_symbol_sz_isvalid(uint32_t symbol_sz) {
if (symbol_sz == 128 ||
symbol_sz == 256 ||
symbol_sz == 512 ||
symbol_sz == 1024 ||
symbol_sz == 2048) {
return true;
} else {
return false;
}
}
int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
uint32_t lte_voffset(uint32_t symbol_id, uint32_t cell_id, uint32_t nof_ports) {
if (nof_ports == 1 && symbol_id==0) {
return (cell_id+3) % 6;
} else {
@ -106,7 +197,7 @@ int lte_voffset(int symbol_id, int cell_id, int nof_ports) {
}
/* Returns the number of available RE per PRB */
int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
uint32_t lte_re_x_prb(uint32_t ns, uint32_t symbol, uint32_t nof_ports, uint32_t nof_symbols) {
if (symbol == 0) {
if (((ns % 2) == 0) || (ns == 1)) {
return RE_X_RB - 4;
@ -138,10 +229,10 @@ int lte_re_x_prb(int ns, int symbol, int nof_ports, int nof_symbols) {
struct lte_band {
int band;
uint32_t band;
float fd_low_mhz;
int earfcn_offset;
int earfcn_max;
uint32_t earfcn_offset;
uint32_t earfcn_max;
enum band_geographical_area area;
};
@ -186,9 +277,9 @@ int lte_str2mimotype(char *mimo_type_str, lte_mimo_type_t *type) {
} else if (!strcmp(mimo_type_str, "multiplex")) {
*type = SPATIAL_MULTIPLEX;
} else {
return -1;
return LIBLTE_ERROR;
}
return 0;
return LIBLTE_SUCCESS;
}
char *lte_mimotype2str(lte_mimo_type_t type) {
@ -203,12 +294,16 @@ char *lte_mimotype2str(lte_mimo_type_t type) {
return NULL;
}
float get_fd(struct lte_band *band, int earfcn) {
float get_fd(struct lte_band *band, uint32_t earfcn) {
if (earfcn >= band->earfcn_offset) {
return band->fd_low_mhz + 0.1*(earfcn - band->earfcn_offset);
} else {
return 0.0;
}
}
float lte_band_fd(int earfcn) {
int i;
float lte_band_fd(uint32_t earfcn) {
uint32_t i;
i=0;
while(i < NOF_LTE_BANDS && lte_bands[i].earfcn_offset<earfcn) {
i++;
@ -220,27 +315,27 @@ float lte_band_fd(int earfcn) {
return get_fd(&lte_bands[i], earfcn);
}
int lte_band_get_fd_band_all(int band, lte_earfcn_t *earfcn, int max_elems) {
int lte_band_get_fd_band_all(uint32_t band, lte_earfcn_t *earfcn, uint32_t 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;
int lte_band_get_fd_band(uint32_t band, lte_earfcn_t *earfcn, int start_earfcn, int end_earfcn, uint32_t max_elems) {
uint32_t i, j;
uint32_t 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;
return LIBLTE_ERROR;
}
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;
return LIBLTE_ERROR;
}
}
if (start_earfcn == -1) {
@ -248,7 +343,7 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e
} 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;
return LIBLTE_ERROR;
}
}
nof_earfcn = end_earfcn - start_earfcn;
@ -260,11 +355,11 @@ int lte_band_get_fd_band(int band, lte_earfcn_t *earfcn, int start_earfcn, int e
earfcn[j].id = j + start_earfcn;
earfcn[j].fd = get_fd(&lte_bands[i], earfcn[j].id);
}
return j;
return (int) j;
}
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, int max_elems) {
int i;
int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *earfcn, uint32_t max_elems) {
uint32_t i;
int n;
int nof_fd = 0;
for (i=0;i<NOF_LTE_BANDS && max_elems > 0;i++) {
@ -274,7 +369,7 @@ int lte_band_get_fd_region(enum band_geographical_area region, lte_earfcn_t *ear
nof_fd += n;
max_elems -= n;
} else {
return -1;
return LIBLTE_ERROR;
}
}
}

@ -41,17 +41,16 @@
* It follows the 3GPP Release 8 (LTE) 36.211
* Section 7.2
*/
void generate_prs_c(sequence_t *q, unsigned int seed) {
void generate_prs_c(sequence_t *q, uint32_t seed) {
int n;
unsigned int *x1;
unsigned int *x2;
uint32_t *x1, *x2;
x1 = calloc(Nc + q->len + 31, sizeof(unsigned int));
x1 = calloc(Nc + q->len + 31, sizeof(uint32_t));
if (!x1) {
perror("calloc");
return;
}
x2 = calloc(Nc + q->len + 31, sizeof(unsigned int));
x2 = calloc(Nc + q->len + 31, sizeof(uint32_t));
if (!x2) {
free(x1);
perror("calloc");
@ -76,26 +75,26 @@ void generate_prs_c(sequence_t *q, unsigned int seed) {
free(x2);
}
int sequence_LTEPRS(sequence_t *q, int len, int seed) {
int sequence_LTEPRS(sequence_t *q, uint32_t len, uint32_t seed) {
if (sequence_init(q, len)) {
return -1;
return LIBLTE_ERROR;
}
q->len = len;
generate_prs_c(q, seed);
return 0;
return LIBLTE_SUCCESS;
}
int sequence_init(sequence_t *q, int len) {
int sequence_init(sequence_t *q, uint32_t 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 LIBLTE_ERROR;
}
}
return 0;
return LIBLTE_SUCCESS;
}
void sequence_free(sequence_t *q) {

@ -87,7 +87,7 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb)));
outfft = malloc(sizeof(cf_t) * SLOT_LEN(lte_symbol_sz(n_prb)));
if (!outfft) {
perror("malloc");
exit(-1);
@ -111,8 +111,8 @@ int main(int argc, char **argv) {
input[i] = 100 * ((float) rand()/RAND_MAX + (float) I*rand()/RAND_MAX);
}
lte_ifft_run(&ifft, input, outfft);
lte_fft_run(&fft, outfft, outifft);
lte_ifft_run_slot(&ifft, input, outfft);
lte_fft_run_slot(&fft, outfft, outifft);
/* compute MSE */

@ -28,16 +28,22 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include "liblte/phy/fec/convcoder.h"
#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);
int convcoder_encode(convcoder_t *q, char *input, char *output, uint32_t frame_length) {
uint32_t sr;
uint32_t i,j;
uint32_t len = q->tail_biting ? frame_length : (frame_length + q->K - 1);
if (q != NULL &&
input != NULL &&
output != NULL &&
frame_length > q->K + 1)
{
if (q->tail_biting) {
sr = 0;
for (i=frame_length - q->K + 1; i<frame_length; i++) {
@ -47,14 +53,16 @@ int convcoder_encode(convcoder_t *q, char *input, char *output, int frame_length
sr = 0;
}
for (i = 0; i < len; i++) {
int bit = (i < frame_length) ? (input[i] & 1) : 0;
char 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;
} else {
return LIBLTE_ERROR_INVALID_INPUTS;
}
}

@ -114,7 +114,7 @@ int crc_init(crc_t *h, unsigned int crc_poly, int crc_order) {
return 0;
}
unsigned int crc_checksum(crc_t *h, char *data, int len) {
uint32_t crc_checksum(crc_t *h, char *data, int len) {
int i, k, len8, res8, a = 0;
unsigned int crc = 0;
char *pter;

@ -4,15 +4,16 @@
*/
#include <stdio.h>
#include <stdint.h>
unsigned char Partab[256];
int P_init;
uint8_t Partab[256];
uint32_t P_init;
/* Create 256-entry odd-parity lookup table
* Needed only on non-ia32 machines
*/
void partab_init(void) {
int i, cnt, ti;
uint32_t i, cnt, ti;
/* Initialize parity lookup table */
for (i = 0; i < 256; i++) {

@ -10,16 +10,16 @@
/* Determine parity of argument: 1 = odd, 0 = even */
#ifdef __i386__
static inline int parityb(unsigned char x){
static inline uint32_t parityb(uint8_t x){
__asm__ __volatile__ ("test %1,%1;setpo %0" : "=qhm" (x) : "qh" (x));
return x;
}
#else
void partab_init();
static inline int parityb(unsigned char x){
extern unsigned char Partab[256];
extern int P_init;
static inline uint32_t parityb(uint8_t x){
extern uint8_t Partab[256];
extern uint32_t P_init;
if(!P_init){
partab_init();
}
@ -28,7 +28,7 @@ static inline int parityb(unsigned char x){
#endif
static inline int parity(int x){
static inline uint32_t parity(int x){
/* Fold down to one byte */
x ^= (x >> 16);
x ^= (x >> 8);

@ -27,25 +27,27 @@
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "liblte/phy/fec/rm_conv.h"
#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,
uint8_t 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] =
uint8_t RM_PERM_CC_INV[NCOLS] =
{ 16, 0, 24, 8, 20, 4, 28, 12, 18, 2, 26, 10, 22, 6, 30, 14, 17, 1, 25, 9,
21, 5, 29, 13, 19, 3, 27, 11, 23, 7, 31, 15 };
int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
int rm_conv_tx(char *input, uint32_t in_len, char *output, uint32_t 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;
nrows = (uint32_t) (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);
@ -89,7 +91,7 @@ int rm_conv_tx(char *input, int in_len, char *output, int out_len) {
/* 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 rm_conv_rx(float *input, uint32_t in_len, float *output, uint32_t out_len) {
int nrows, ndummy, K_p;
int i, j, k;
@ -97,7 +99,7 @@ int rm_conv_rx(float *input, int in_len, float *output, int out_len) {
float tmp[3 * NCOLS * NROWS_MAX];
nrows = (int) (out_len / 3 - 1) / NCOLS + 1;
nrows = (uint32_t) (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);

@ -30,50 +30,43 @@
#include <math.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "liblte/phy/fec/rm_turbo.h"
#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,
uint8_t 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;
}
void rm_turbo_free(rm_turbo_t *q) {
if (q->buffer) {
free(q->buffer);
}
}
/* Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*
* If rv_idx==0, the circular buffer w_buff is filled with all redundancy versions and
* the corresponding version of length out_len is saved in the output buffer.
* Otherwise, the corresponding version is directly obtained from w_buff and saved into output.
*
* Note that calling this function with rv_idx!=0 without having called it first with rv_idx=0
* will produce unwanted results.
*
* 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) {
int rm_turbo_tx(char *w_buff, uint32_t w_buff_len, char *input, uint32_t in_len, char *output,
uint32_t out_len, uint32_t rv_idx) {
char *tmp = (char*) q->buffer;
int nrows, ndummy, K_p;
int ndummy, kidx;
int nrows, K_p;
int i, j, k, s, kidx, N_cb, k0;
int i, j, k, s, N_cb, k0;
nrows = (int) (in_len / 3 - 1) / NCOLS + 1;
nrows = (uint32_t) (in_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
if (3 * K_p > w_buff_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);
w_buff_len, nrows, in_len);
return -1;
}
@ -82,6 +75,7 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
ndummy = 0;
}
if (rv_idx == 0) {
/* Sub-block interleaver (5.1.4.1.1) and bit collection */
k = 0;
for (s = 0; s < 2; s++) {
@ -93,9 +87,9 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
kidx = K_p + 2 * (k % K_p);
}
if (i * NCOLS + RM_PERM_TC[j] < ndummy) {
tmp[kidx] = TX_NULL;
w_buff[kidx] = TX_NULL;
} else {
tmp[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
w_buff[kidx] = input[(i * NCOLS + RM_PERM_TC[j] - ndummy) * 3 + s];
}
k++;
}
@ -106,9 +100,10 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
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;
w_buff[K_p + 2 * k + 1] = TX_NULL;
} else {
tmp[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
w_buff[K_p + 2 * k + 1] = input[3 * (kidx - ndummy) + 2];
}
}
}
@ -116,13 +111,13 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
N_cb = 3 * K_p; // TODO: Soft buffer size limitation
k0 = nrows
* (2 * (int) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
* (2 * (uint32_t) 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];
if (w_buff[(k0 + j) % N_cb] != TX_NULL) {
output[k] = w_buff[(k0 + j) % N_cb];
k++;
}
j++;
@ -132,23 +127,24 @@ int rm_turbo_tx(rm_turbo_t *q, char *input, int in_len, char *output,
/* Undoes Turbo Code Rate Matching.
* 3GPP TS 36.212 v10.1.0 section 5.1.4.1
*
* If rv_idx==0, the w_buff circular buffer is initialized. Every subsequent call
* with rv_idx!=0 will soft-combine the LLRs from input with w_buff
*/
int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
int out_len, int rv_idx) {
int rm_turbo_rx(float *w_buff, uint32_t w_buff_len, float *input, uint32_t in_len, float *output,
uint32_t out_len, uint32_t 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;
nrows = (uint32_t) (out_len / 3 - 1) / NCOLS + 1;
K_p = nrows * NCOLS;
if (3 * K_p > q->buffer_len) {
if (3 * K_p > w_buff_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);
w_buff_len, nrows, out_len);
return -1;
}
@ -157,14 +153,16 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
ndummy = 0;
}
if (rv_idx == 0) {
for (i = 0; i < 3 * K_p; i++) {
tmp[i] = RX_NULL;
w_buff[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);
* (2 * (uint32_t) ceilf((float) N_cb / (float) (8 * nrows)) * rv_idx + 2);
k = 0;
j = 0;
@ -185,7 +183,7 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
isdummy = true;
}
} else {
int jpp = (jp - K_p - 1) / 2;
uint32_t jpp = (jp - K_p - 1) / 2;
kidx = (RM_PERM_TC[jpp / nrows] + NCOLS * (jpp % nrows) + 1) % K_p;
if ((kidx - ndummy) < 0) {
isdummy = true;
@ -195,10 +193,10 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
}
if (!isdummy) {
if (tmp[jp] == RX_NULL) {
tmp[jp] = input[k];
if (w_buff[jp] == RX_NULL) {
w_buff[jp] = input[k];
} else if (input[k] != RX_NULL) {
tmp[jp] += input[k]; /* soft combine LLRs */
w_buff[jp] += input[k]; /* soft combine LLRs */
}
k++;
}
@ -213,15 +211,14 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
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];
if (w_buff[kidx] != RX_NULL) {
output[i * 3 + j] = w_buff[kidx];
} else {
output[i * 3 + j] = 0;
}
@ -233,25 +230,15 @@ int rm_turbo_rx(rm_turbo_t *q, float *input, int in_len, float *output,
/** High-level API */
int rm_turbo_initialize(rm_turbo_hl* h) {
return rm_turbo_init(&h->q, 7000);
return 0;
}
/** 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;
}
int rm_turbo_stop(rm_turbo_hl* hl) {
rm_turbo_free(&hl->q);
return 0;
}

@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/fec/tc_interl.h"
@ -39,7 +40,7 @@
*
************************************************/
const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103,
const uint32_t 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,
@ -52,7 +53,7 @@ const int f1_list[NOF_TC_CB_SIZES] = { 3, 7, 19, 7, 7, 11, 5, 11, 7, 41, 103,
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,
const uint32_t 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,
@ -65,9 +66,9 @@ const int f2_list[NOF_TC_CB_SIZES] = { 10, 12, 42, 16, 18, 20, 22, 24, 26, 84,
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;
int tc_interl_LTE_gen(tc_interl_t *h, uint32_t long_cb) {
uint32_t cb_table_idx, f1, f2;
uint64_t i, j;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Interleaver initiated for max_long_cb=%d\n",
@ -90,8 +91,8 @@ int tc_interl_LTE_gen(tc_interl_t *h, int long_cb) {
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;
h->forward[i] = (uint32_t) j;
h->reverse[j] = (uint32_t) i;
}
return 0;

@ -28,13 +28,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <stdint.h>
#include "liblte/phy/fec/tc_interl.h"
#include "liblte/phy/fec/turbocoder.h"
#define TURBO_RATE 3
int mcd(int x, int y);
uint32_t mcd(uint32_t x, uint32_t y);
/************************************************
*
@ -53,14 +54,14 @@ 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 };
int tc_interl_init(tc_interl_t *h, int max_long_cb) {
int tc_interl_init(tc_interl_t *h, uint32_t max_long_cb) {
int ret = -1;
h->forward = malloc(sizeof(int) * max_long_cb);
h->forward = malloc(sizeof(uint32_t) * max_long_cb);
if (!h->forward) {
perror("malloc");
goto clean_exit;
}
h->reverse = malloc(sizeof(int) * max_long_cb);
h->reverse = malloc(sizeof(uint32_t) * max_long_cb);
if (!h->reverse) {
perror("malloc");
goto clean_exit;
@ -83,17 +84,17 @@ void tc_interl_free(tc_interl_t *h) {
bzero(h, sizeof(tc_interl_t));
}
int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) {
int tc_interl_UMTS_gen(tc_interl_t *h, uint32_t 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;
uint32_t i, j;
uint32_t res, prim, aux;
uint32_t kp, k;
uint32_t *per, *desper;
uint8_t v;
uint16_t p;
uint16_t s[MAX_COLS], q[MAX_ROWS], r[MAX_ROWS], T[MAX_ROWS];
uint16_t U[MAX_COLS * MAX_ROWS];
uint32_t M_Rows, M_Cols, M_long;
M_long = long_cb;
@ -260,8 +261,8 @@ int tc_interl_UMTS_gen(tc_interl_t *h, int long_cb) {
}
int mcd(int x, int y) {
int r = 1;
uint32_t mcd(uint32_t x, uint32_t y) {
uint32_t r = 1;
while (r) {
r = x % y;

@ -26,12 +26,14 @@
*/
#include "liblte/phy/fec/turbocoder.h"
#include <stdio.h>
#include <stdint.h>
#include "liblte/phy/fec/turbocoder.h"
#define NOF_REGS 3
int tcod_init(tcod_t *h, int max_long_cb) {
int tcod_init(tcod_t *h, uint32_t max_long_cb) {
if (tc_interl_init(&h->interl, max_long_cb)) {
return -1;
@ -45,13 +47,13 @@ void tcod_free(tcod_t *h) {
h->max_long_cb = 0;
}
int tcod_encode(tcod_t *h, char *input, char *output, int long_cb) {
int tcod_encode(tcod_t *h, char *input, char *output, uint32_t long_cb) {
char reg1_0, reg1_1, reg1_2, reg2_0, reg2_1, reg2_2;
int i, k = 0, j;
uint32_t i, k = 0, j;
char bit;
char in, out;
int *per;
uint32_t *per;
if (long_cb > h->max_long_cb) {
fprintf(stderr, "Turbo coder initiated for max_long_cb=%d\n",

@ -27,8 +27,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <math.h>
#include "liblte/phy/fec/turbodecoder.h"
@ -38,13 +40,15 @@
* Decoder
*
************************************************/
void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) {
void map_gen_beta(map_gen_t * s, llr_t * input, llr_t * parity,
uint32_t long_cb)
{
llr_t m_b[8], new[8], old[8];
llr_t x, y, xy;
int k;
int end = long_cb + RATE;
uint32_t end = long_cb + RATE;
llr_t *beta = s->beta;
int i;
uint32_t i;
for (i = 0; i < 8; i++) {
old[i] = beta[8 * (end) + i];
@ -84,15 +88,16 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, int long_cb) {
}
void map_gen_alpha(map_gen_t * s, llr_t * input, llr_t * parity, llr_t * output,
int long_cb) {
uint32_t 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;
uint32_t k;
uint32_t end = long_cb;
llr_t *beta = s->beta;
int i;
uint32_t i;
old[0] = 0;
for (i = 1; i < 8; i++) {
@ -149,7 +154,8 @@ void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output,
}
}
int map_gen_init(map_gen_t *h, int max_long_cb) {
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) {
@ -160,7 +166,8 @@ int map_gen_init(map_gen_t *h, int max_long_cb) {
return 0;
}
void map_gen_free(map_gen_t *h) {
void map_gen_free(map_gen_t * h)
{
if (h->beta) {
free(h->beta);
}
@ -168,8 +175,9 @@ void map_gen_free(map_gen_t *h) {
}
void map_gen_dec(map_gen_t * h, llr_t * input, llr_t * parity, llr_t * output,
int long_cb) {
int k;
uint32_t long_cb)
{
uint32_t k;
h->beta[(long_cb + TAIL) * NUMSTATES] = 0;
for (k = 1; k < NUMSTATES; k++)
@ -184,10 +192,11 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output,
* TURBO DECODER INTERFACE
*
************************************************/
int tdec_init(tdec_t *h, int max_long_cb) {
int tdec_init(tdec_t * h, uint32_t max_long_cb)
{
int ret = -1;
bzero(h, sizeof(tdec_t));
int len = max_long_cb + TOTALTAIL;
uint32_t len = max_long_cb + TOTALTAIL;
h->max_long_cb = max_long_cb;
@ -232,7 +241,8 @@ int tdec_init(tdec_t *h, int max_long_cb) {
return ret;
}
void tdec_free(tdec_t *h) {
void tdec_free(tdec_t * h)
{
if (h->llr1) {
free(h->llr1);
}
@ -256,8 +266,9 @@ void tdec_free(tdec_t *h) {
bzero(h, sizeof(tdec_t));
}
void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) {
int i;
void tdec_iteration(tdec_t * h, llr_t * input, uint32_t long_cb)
{
uint32_t i;
// Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) {
@ -295,26 +306,29 @@ void tdec_iteration(tdec_t *h, llr_t *input, int long_cb) {
}
int tdec_reset(tdec_t *h, int long_cb) {
memset(h->w, 0, sizeof(llr_t) * long_cb);
int tdec_reset(tdec_t * h, uint32_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;
}
memset(h->w, 0, sizeof(llr_t) * long_cb);
return tc_interl_LTE_gen(&h->interleaver, long_cb);
}
void tdec_decision(tdec_t *h, char *output, int long_cb) {
int i;
void tdec_decision(tdec_t * h, char *output, uint32_t long_cb)
{
uint32_t 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,
uint32_t nof_iterations, uint32_t long_cb)
{
uint32_t iter = 0;
tdec_reset(h, long_cb);
@ -325,4 +339,3 @@ void tdec_run_all(tdec_t *h, llr_t *input, char *output, int nof_iterations,
tdec_decision(h, output, long_cb);
}

@ -27,6 +27,8 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <string.h>
@ -38,11 +40,11 @@
#define DEB 0
int decode37(void *o, unsigned char *symbols, char *data, int frame_length) {
int decode37(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
viterbi_t *q = o;
int i;
uint32_t i;
int best_state;
uint32_t best_state;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
@ -73,7 +75,7 @@ int decode37(void *o, unsigned char *symbols, char *data, int frame_length) {
return q->framebits;
}
int decode39(void *o, unsigned char *symbols, char *data, int frame_length) {
int decode39(void *o, uint8_t *symbols, char *data, uint32_t frame_length) {
viterbi_t *q = o;
if (frame_length > q->framebits) {
@ -113,7 +115,7 @@ void free39(void *o) {
delete_viterbi39_port(q->ptr);
}
int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
int init37(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) {
q->K = 7;
q->R = 3;
q->framebits = framebits;
@ -145,7 +147,7 @@ int init37(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
}
}
int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
int init39(viterbi_t *q, uint32_t poly[3], uint32_t framebits, bool tail_biting) {
q->K = 9;
q->R = 3;
q->framebits = framebits;
@ -171,8 +173,8 @@ int init39(viterbi_t *q, int poly[3], int framebits, bool tail_biting) {
}
}
int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3],
int max_frame_length, bool tail_bitting) {
int viterbi_init(viterbi_t *q, viterbi_type_t type, uint32_t poly[3],
uint32_t max_frame_length, bool tail_bitting) {
switch (type) {
case viterbi_37:
return init37(q, poly, max_frame_length, tail_bitting);
@ -185,12 +187,14 @@ int viterbi_init(viterbi_t *q, viterbi_type_t type, int poly[3],
}
void viterbi_free(viterbi_t *q) {
if (q->free) {
q->free(q);
}
}
/* symbols are real-valued */
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length) {
int len;
int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, uint32_t frame_length) {
uint32_t len;
if (frame_length > q->framebits) {
fprintf(stderr, "Initialized decoder for max frame length %d bits\n",
q->framebits);
@ -205,13 +209,13 @@ int viterbi_decode_f(viterbi_t *q, float *symbols, char *data, int frame_length)
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) {
int viterbi_decode_uc(viterbi_t *q, uint8_t *symbols, char *data,
uint32_t frame_length) {
return q->decode(q, symbols, data, frame_length);
}
int viterbi_initialize(viterbi_hl* h) {
int poly[3];
uint32_t poly[3];
viterbi_type_t type;
if (h->init.rate == 2) {
if (h->init.constraint_length == 7) {
@ -241,7 +245,7 @@ int viterbi_initialize(viterbi_hl* h) {
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,
return viterbi_init(&h->obj, type, poly, (uint32_t) h->init.frame_length,
h->init.tail_bitting ? true : false);
}

@ -27,8 +27,20 @@
#include <stdbool.h>
void *create_viterbi37_port(int polys[3], int len);
int init_viterbi37_port(void *p, int starting_state);
int chainback_viterbi37_port(void *p, char *data, unsigned int nbits, unsigned int endstate);
void *create_viterbi37_port(uint32_t polys[3],
uint32_t len);
int init_viterbi37_port(void *p,
uint32_t starting_state);
int chainback_viterbi37_port(void *p,
char *data,
uint32_t nbits,
uint32_t endstate);
void delete_viterbi37_port(void *p);
int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state);
int update_viterbi37_blk_port(void *p,
unsigned char *syms,
uint32_t nbits,
uint32_t *best_state);

@ -4,6 +4,8 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include "viterbi37.h"
#include "parity.h"
@ -30,9 +32,9 @@ struct v37 {
};
/* Initialize Viterbi decoder for start of new frame */
int init_viterbi37_port(void *p, int starting_state) {
int init_viterbi37_port(void *p, uint32_t starting_state) {
struct v37 *vp = p;
int i;
uint32_t i;
if (p == NULL)
return -1;
@ -48,8 +50,8 @@ int init_viterbi37_port(void *p, int starting_state) {
return 0;
}
void set_viterbi37_polynomial_port(int polys[3]) {
int state;
void set_viterbi37_polynomial_port(uint32_t polys[3]) {
uint32_t state;
for (state = 0; state < 32; state++) {
Branchtab37[0].c[state] =
@ -62,7 +64,7 @@ void set_viterbi37_polynomial_port(int polys[3]) {
}
/* Create a new instance of a Viterbi decoder */
void *create_viterbi37_port(int polys[3], int len) {
void *create_viterbi37_port(uint32_t polys[3], uint32_t len) {
struct v37 *vp;
set_viterbi37_polynomial_port(polys);
@ -82,8 +84,8 @@ void *create_viterbi37_port(int polys[3], int len) {
/* 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 */
uint32_t nbits, /* Number of data bits */
uint32_t endstate) { /* Terminal encoder state */
struct v37 *vp = p;
decision_t *d;
@ -145,18 +147,18 @@ unsigned int metric,m0,m1,decision;\
* of symbols!
*/
int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best_state) {
int update_viterbi37_blk_port(void *p, uint8_t *syms, uint32_t nbits, uint32_t *best_state) {
struct v37 *vp = p;
decision_t *d;
if (p == NULL)
return -1;
int k=0;
uint32_t k=0;
d = (decision_t *) vp->dp;
while (nbits--) {
void *tmp;
unsigned char sym0, sym1, sym2;
int i;
uint8_t sym0, sym1, sym2;
uint32_t i;
d->w[0] = d->w[1] = 0;
@ -174,8 +176,8 @@ int update_viterbi37_blk_port(void *p, unsigned char *syms, int nbits, int *best
vp->new_metrics = tmp;
}
if (best_state) {
int i, bst=0;
unsigned int minmetric=UINT_MAX;
uint32_t i, bst=0;
uint32_t minmetric=UINT_MAX;
for (i=0;i<64;i++) {
if (vp->old_metrics->w[i] < minmetric) {
bst = i;

@ -27,10 +27,19 @@
#include <stdbool.h>
void *create_viterbi39_port(int polys[3], int len);
int init_viterbi39_port(void *p, int starting_state);
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */
unsigned int endstate);
void *create_viterbi39_port(uint32_t polys[3],
uint32_t len);
int init_viterbi39_port(void *p,
uint32_t starting_state);
int chainback_viterbi39_port(void *p,
char *data, /* Decoded output data */
uint32_t nbits, /* Number of data bits */
uint32_t endstate);
void delete_viterbi39_port(void *p);
int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits);
int update_viterbi39_blk_port(void *p,
uint8_t *syms,
uint32_t nbits);

@ -4,6 +4,7 @@
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <memory.h>
#include "viterbi39.h"
#include "parity.h"
@ -29,9 +30,9 @@ struct v39 {
};
/* Initialize Viterbi decoder for start of new frame */
int init_viterbi39_port(void *p, int starting_state) {
int init_viterbi39_port(void *p, uint32_t starting_state) {
struct v39 *vp = p;
int i;
uint32_t i;
if (p == NULL)
return -1;
@ -45,8 +46,8 @@ int init_viterbi39_port(void *p, int starting_state) {
return 0;
}
void set_viterbi39_polynomial_port(int polys[3]) {
int state;
void set_viterbi39_polynomial_port(uint32_t polys[3]) {
uint32_t state;
for (state = 0; state < 128; state++) {
Branchtab39[0].c[state] =
@ -59,7 +60,7 @@ void set_viterbi39_polynomial_port(int polys[3]) {
}
/* Create a new instance of a Viterbi decoder */
void *create_viterbi39_port(int polys[3], int len) {
void *create_viterbi39_port(uint32_t polys[3], uint32_t len) {
struct v39 *vp;
set_viterbi39_polynomial_port(polys);
@ -79,8 +80,8 @@ void *create_viterbi39_port(int polys[3], int len) {
/* Viterbi chainback */
int chainback_viterbi39_port(void *p, char *data, /* Decoded output data */
unsigned int nbits, /* Number of data bits */
unsigned int endstate) { /* Terminal encoder state */
uint32_t nbits, /* Number of data bits */
uint32_t endstate) { /* Terminal encoder state */
struct v39 *vp = p;
decision_t *d;
@ -140,7 +141,7 @@ unsigned int metric,m0,m1,decision;\
* of symbols!
*/
int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) {
int update_viterbi39_blk_port(void *p, uint8_t *syms, uint32_t nbits) {
struct v39 *vp = p;
decision_t *d;
@ -150,8 +151,8 @@ int update_viterbi39_blk_port(void *p, unsigned char *syms, int nbits) {
d = (decision_t *) vp->dp;
while (nbits--) {
void *tmp;
unsigned char sym0, sym1, sym2;
int i;
uint8_t sym0, sym1, sym2;
uint32_t i;
for (i = 0; i < 8; i++)
d->w[i] = 0;

@ -73,10 +73,9 @@ void parse_args(int argc, char **argv) {
int main(int argc, char **argv) {
int i;
char *bits, *rm_bits;
float *rm_symbols, *unrm_symbols;
char *bits, *rm_bits, *w_buff_c;
float *rm_symbols, *unrm_symbols, *w_buff_f;
int nof_errors;
rm_turbo_t rm_turbo;
parse_args(argc, argv);
@ -85,6 +84,11 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
w_buff_c = malloc(sizeof(char) * nof_tx_bits * 10);
if (!w_buff_c) {
perror("malloc");
exit(-1);
}
rm_bits = malloc(sizeof(char) * nof_rx_bits);
if (!rm_bits) {
perror("malloc");
@ -95,6 +99,11 @@ int main(int argc, char **argv) {
perror("malloc");
exit(-1);
}
w_buff_f = malloc(sizeof(float) * nof_rx_bits * 10);
if (!w_buff_c) {
perror("malloc");
exit(-1);
}
unrm_symbols = malloc(sizeof(float) * nof_tx_bits);
if (!unrm_symbols) {
perror("malloc");
@ -105,15 +114,13 @@ int main(int argc, char **argv) {
bits[i] = rand() % 2;
}
rm_turbo_init(&rm_turbo, 2000);
rm_turbo_tx(&rm_turbo, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
rm_turbo_tx(w_buff_c, nof_tx_bits * 10, bits, nof_tx_bits, rm_bits, nof_rx_bits, rv_idx);
for (i = 0; i < nof_rx_bits; i++) {
rm_symbols[i] = (float) rm_bits[i] ? 1 : -1;
}
rm_turbo_rx(&rm_turbo, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits,
rm_turbo_rx(w_buff_f, nof_rx_bits * 10, rm_symbols, nof_rx_bits, unrm_symbols, nof_tx_bits,
rv_idx);
nof_errors = 0;
@ -123,8 +130,6 @@ int main(int argc, char **argv) {
}
}
rm_turbo_free(&rm_turbo);
free(bits);
free(rm_bits);
free(rm_symbols);

@ -41,9 +41,9 @@
typedef _Complex float cf_t;
int frame_length = 1000, nof_frames = 100;
uint32_t frame_length = 1000, nof_frames = 100;
float ebno_db = 100.0;
unsigned int seed = 0;
uint32_t seed = 0;
int K = -1;
#define MAX_ITERATIONS 4
@ -127,16 +127,16 @@ void output_matlab(float ber[MAX_ITERATIONS][SNR_POINTS], int snr_points) {
}
int main(int argc, char **argv) {
int frame_cnt;
uint32_t frame_cnt;
float *llr;
unsigned char *llr_c;
char *data_tx, *data_rx, *symbols;
int i, j;
uint32_t i, j;
float var[SNR_POINTS];
int snr_points;
uint32_t snr_points;
float ber[MAX_ITERATIONS][SNR_POINTS];
unsigned int errors[100];
int coded_length;
uint32_t errors[100];
uint32_t coded_length;
struct timeval tdata[3];
float mean_usec;
tdec_t tdec;
@ -247,7 +247,7 @@ int main(int argc, char **argv) {
/* decoder */
tdec_reset(&tdec, frame_length);
int t;
uint32_t t;
if (nof_iterations == -1) {
t = MAX_ITERATIONS;
} else {

@ -124,6 +124,11 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers,
/* ZF detector */
int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) {
for (int i=0;i<nof_symbols;i++) {
if (ce[i] == 0) {
ce[i] = 0.01;
}
}
vec_div_ccc(y, ce, x, nof_symbols);
return nof_symbols;
}
@ -143,6 +148,9 @@ int predecoding_diversity_zf(cf_t *y, cf_t *ce[MAX_PORTS], cf_t *x[MAX_LAYERS],
+ crealf(h1) * crealf(h1) + cimagf(h1) * cimagf(h1);
r0 = y[2 * i];
r1 = y[2 * i + 1];
if (hh == 0) {
hh = 1e-2;
}
x[0][i] = (conjf(h0) * r0 + h1 * conjf(r1)) / hh * sqrt(2);
x[1][i] = (-h1 * conj(r0) + conj(h0) * r1) / hh * sqrt(2);
}

@ -37,14 +37,14 @@ void demod_hard_init(demod_hard_t* q) {
bzero((void*) q, sizeof(demod_hard_t));
}
void demod_hard_table_set(demod_hard_t* q, enum modem_std table) {
q->table = table;
void demod_hard_table_set(demod_hard_t* q, lte_mod_t mod) {
q->mod = mod;
}
int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, int nsymbols) {
int demod_hard_demodulate(demod_hard_t* q, cf_t* symbols, char *bits, uint32_t nsymbols) {
int nbits=-1;
switch(q->table) {
switch(q->mod) {
case LTE_BPSK:
hard_bpsk_demod(symbols,bits,nsymbols);
nbits=nsymbols;

@ -36,6 +36,7 @@
void demod_soft_init(demod_soft_t *q) {
bzero((void*)q,sizeof(demod_soft_t));
q->sigma = 1.0;
}
void demod_soft_table_set(demod_soft_t *q, modem_table_t *table) {
@ -57,8 +58,10 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int
q->table->symbol_table, q->table->soft_table.idx, q->sigma);
break;
case APPROX:
llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
/* llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
q->table->symbol_table, q->table->soft_table.idx, q->sigma);
*/ llr_approx(symbols, llr, nsymbols, q->table->nsymbols, q->table->nbits_x_symbol,
q->table->symbol_table, q->table->soft_table.idx, q->table->soft_table.d_idx, q->table->soft_table.min_idx, q->sigma);
break;
}
return nsymbols*q->table->nbits_x_symbol;
@ -69,7 +72,7 @@ int demod_soft_demodulate(demod_soft_t *q, const cf_t* symbols, float* llr, int
/* High-Level API */
int demod_soft_initialize(demod_soft_hl* hl) {
modem_table_init(&hl->table);
if (modem_table_std(&hl->table,hl->init.std,true)) {
if (modem_table_lte(&hl->table,hl->init.std,true)) {
return -1;
}
demod_soft_init(&hl->obj);

@ -33,6 +33,7 @@
#include "liblte/phy/modem/demod_hard.h"
#include "hard_demod_lte.h"
/**
* @ingroup Hard BPSK demodulator
*
@ -46,9 +47,9 @@
* \param N Number of input symbols
* \param modulation Modulation type
*/
inline void hard_bpsk_demod(const cf_t* in, char* out, int N)
inline void hard_bpsk_demod(const cf_t* in, char* out, uint32_t N)
{
int s;
uint32_t s;
for (s=0; s<N; s++) { /* received symbols */
if (__real__ in[s] > 0) {
@ -81,9 +82,9 @@ inline void hard_bpsk_demod(const cf_t* in, char* out, int N)
* \param N Number of input symbols
* \param modulation Modulation type
*/
inline void hard_qpsk_demod(const cf_t* in, char* out, int N)
inline void hard_qpsk_demod(const cf_t* in, char* out, uint32_t N)
{
int s;
uint32_t s;
for (s=0; s<N; s++) {
if (__real__ in[s] > 0) {
@ -115,9 +116,9 @@ inline void hard_qpsk_demod(const cf_t* in, char* out, int N)
* \param N Number of input symbols
* \param modulation Modulation type
*/
inline void hard_qam16_demod(const cf_t* in, char* out, int N)
inline void hard_qam16_demod(const cf_t* in, char* out, uint32_t N)
{
int s;
uint32_t s;
for (s=0; s<N; s++) {
if (__real__ in[s] > 0) {
@ -157,9 +158,9 @@ inline void hard_qam16_demod(const cf_t* in, char* out, int N)
* \param N Number of input symbols
* \param modulation Modulation type
*/
inline void hard_qam64_demod(const cf_t* in, char* out, int N)
inline void hard_qam64_demod(const cf_t* in, char* out, uint32_t N)
{
int s;
uint32_t s;
for (s=0; s<N; s++) {
/* bits associated with/obtained from in-phase component: b0, b2, b4 */

@ -25,7 +25,6 @@
*
*/
/* Thresholds for Demodulation */
/* Assume perfect amplitude and phase alignment.
* Check threshold values for real case
@ -35,7 +34,18 @@
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
void hard_bpsk_demod(const cf_t* in, char* out, int N);
void hard_qpsk_demod(const cf_t* in, char* out, int N);
void hard_qam16_demod(const cf_t* in, char* out, int N);
void hard_qam64_demod(const cf_t* in, char* out, int N);
void hard_bpsk_demod(const cf_t* in,
char* out,
uint32_t N);
void hard_qpsk_demod(const cf_t* in,
char* out,
uint32_t N);
void hard_qam16_demod(const cf_t* in,
char* out,
uint32_t N);
void hard_qam64_demod(const cf_t* in,
char* out,
uint32_t N);

@ -34,6 +34,8 @@
#include "liblte/phy/modem/modem_table.h"
#include "lte_tables.h"
void LLR_approx_params(const cf_t* table, soft_table_t *soft_table, int B);
/**
* Set the BPSK modulation table */
void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
@ -53,13 +55,25 @@ void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demo
/* BSPK symbols containing a '0' and a '1' (only two symbols, 1 bit) */
soft_table->idx[0][0][0] = 0;
soft_table->idx[1][0][0] = 1;
/* set two matrices for LLR approx. calculation */
soft_table->min_idx[0][0][0] = 0;
soft_table->min_idx[0][1][0] = 0;
soft_table->min_idx[1][0][0] = 1;
soft_table->min_idx[1][1][0] = 1;
soft_table->d_idx[0][0] = 0;
soft_table->d_idx[0][1] = 1;
soft_table->d_idx[1][0] = 0;
soft_table->d_idx[1][1] = 1;
}
/**
* Set the QPSK modulation table */
void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
int i,j;
uint32_t i,j;
// LTE-QPSK constellation:
// Q
@ -91,13 +105,15 @@ void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demo
soft_table->idx[1][0][1] = 3;
soft_table->idx[1][1][0] = 1;
soft_table->idx[1][1][1] = 3;
LLR_approx_params(table, soft_table, 2); /* last param indicating B (bits per symbol) */
}
/**
* Set the 16QAM modulation table */
void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
int i,j;
uint32_t i,j;
// LTE-16QAM constellation:
// Q
// 1011 1001 | 0001 0011
@ -156,13 +172,15 @@ void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_dem
soft_table->idx[0][3][i] = 2*i;
soft_table->idx[1][3][i] = 2*i+1;
}
LLR_approx_params(table, soft_table, 4); /* last param indication B (bits per symbol) */
}
/**
* Set the 64QAM modulation table */
void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod)
{
int i,j;
uint32_t i,j;
// LTE-64QAM constellation:
// see [3GPP TS 36.211 version 10.5.0 Release 10, Section 7.1.4]
table[0] = QAM64_LEVEL_2 + QAM64_LEVEL_2*_Complex_I;
@ -277,4 +295,96 @@ void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_dem
soft_table->idx[0][5][i] = 2*i;
soft_table->idx[1][5][i] = 2*i+1;
}
LLR_approx_params(table, soft_table, 6); /* last param indication modulation */
}
/* Precompute two tables for calculating the distances based on the received symbol location relative to the constellation points */
void LLR_approx_params(const cf_t* table, soft_table_t *soft_table, int B) {
int i, j, b, k;
float x, y, d0, d1, min_d0, min_d1;
int M, D;
uint32_t min_idx0[64][6], min_idx1[64][6];
uint32_t count;
int flag;
D = B+1; /* number of different distances to be computed */
//M = pow(2,B); /* number of constellation points */
switch (B) {
case 1: {M = 2; break;} /* BPSK */
case 2: {M = 4; break;} /* QPSK */
case 4: {M = 16; break;} /* 16QAM */
case 6: {M = 64; break;} /* 64QAM */
default: {M = 4; break;} /* QPSK */
}
for (i=0;i<M;i++) { /* constellation points */
for (b=0;b<B;b++) { /* bits per symbol */
min_d0 = 100;
min_d1 = 100;
for (j=0;j<M/2;j++) { /* half the symbols have a '0', the other half a '1' at any bit position of modulation symbol */
x = __real__ table[i] - __real__ table[soft_table->idx[0][b][j]];
y = __imag__ table[i] - __imag__ table[soft_table->idx[0][b][j]];
d0 = x*x + y*y;
if (d0 < min_d0) {
min_d0 = d0;
min_idx0[i][b] = soft_table->idx[0][b][j];
}
x = __real__ table[i] - __real__ table[soft_table->idx[1][b][j]];
y = __imag__ table[i] - __imag__ table[soft_table->idx[1][b][j]];
d1 = x*x + y*y;
if (d1 < min_d1) {
min_d1 = d1;
min_idx1[i][b] = soft_table->idx[1][b][j];
}
}
}
}
for (i=0;i<M;i++) {
for (j=0;j<D;j++) {
soft_table->d_idx[i][j] = -1; /* intialization */
}
}
for (i=0;i<M;i++) {
count = 0;
for (b=0;b<B;b++) { /* bit(b) = 0 */
flag = 0;
for (k=0;k<count;k++) {
if (min_idx0[i][b] == soft_table->d_idx[i][k]) {
soft_table->min_idx[0][i][b] = k;
flag = 1; /* no new entry to idxdx */
break;
}
}
if (flag == 0) { /* new entry to min and d_idx */
soft_table->d_idx[i][count] = min_idx0[i][b];
soft_table->min_idx[0][i][b] = count;
count++;
}
}
for (b=0;b<B;b++) { /* bit(b) = 1 */
flag = 0;
for (k=0;k<count;k++) {
if (min_idx1[i][b] == soft_table->d_idx[i][k]) {
soft_table->min_idx[1][i][b] = k;
flag = 1; /* no new entry to d_idx */
break;
}
}
if (flag == 0) { /* new entry to min and d_idx */
soft_table->d_idx[i][count] = min_idx1[i][b];
soft_table->min_idx[1][i][b] = count;
count++;
}
}
}
}

@ -38,6 +38,14 @@
#define QAM64_LEVEL_3 5/sqrt(42)
#define QAM64_LEVEL_4 7/sqrt(42)
//////////////// NUEVO //////////////////////
/* HARD DEMODULATION Thresholds, necessary for obtaining the zone of received symbol for optimized LLR approx implementation */
#define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
//=========================================//
#define QAM64_LEVEL_x 2/sqrt(42)
/* this is not an QAM64 level, but, rather, an auxiliary value that can be used for computing the
* symbol from the bit sequence */
@ -45,7 +53,18 @@
void set_BPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod);
void set_QPSKtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod);
void set_16QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod);
void set_64QAMtable(cf_t* table, soft_table_t *soft_table, bool compute_soft_demod);
void set_BPSKtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);
void set_QPSKtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);
void set_16QAMtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);
void set_64QAMtable(cf_t* table,
soft_table_t *soft_table,
bool compute_soft_demod);

@ -35,14 +35,17 @@
/** Low-level API */
int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) {
int i,j,idx;
int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, uint32_t nbits) {
uint32_t i,j,idx;
char *b_ptr=(char*) bits;
j=0;
for (i=0;i<nbits;i+=q->nbits_x_symbol) {
idx = bit_unpack(&b_ptr,q->nbits_x_symbol);
assert(idx >= 0 && idx < q->nsymbols);
if (idx < q->nsymbols) {
symbols[j] = q->symbol_table[idx];
} else {
return LIBLTE_ERROR;
}
j++;
}
return j;
@ -52,7 +55,7 @@ int mod_modulate(modem_table_t* q, const char *bits, cf_t* symbols, int nbits) {
/* High-Level API */
int mod_initialize(mod_hl* hl) {
modem_table_init(&hl->obj);
if (modem_table_std(&hl->obj,hl->init.std,false)) {
if (modem_table_lte(&hl->obj,hl->init.std,false)) {
return -1;
}

@ -33,6 +33,7 @@
#include <string.h>
#include <strings.h>
#include "liblte/phy/common/phy_common.h"
#include "liblte/phy/modem/modem_table.h"
#include "lte_tables.h"
@ -56,27 +57,27 @@ void modem_table_reset(modem_table_t* q) {
modem_table_init(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_set(modem_table_t* q, cf_t* table, soft_table_t *soft_table, uint32_t nsymbols, uint32_t nbits_x_symbol) {
if (q->nsymbols) {
return -1;
return LIBLTE_ERROR;
}
q->nsymbols = nsymbols;
if (table_create(q)) {
return -1;
return LIBLTE_ERROR;
}
memcpy(q->symbol_table,table,q->nsymbols*sizeof(cf_t));
memcpy(&q->soft_table,soft_table,sizeof(soft_table_t));
q->nbits_x_symbol = nbits_x_symbol;
return 0;
return LIBLTE_SUCCESS;
}
int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_demod) {
switch(std) {
int modem_table_lte(modem_table_t* q, lte_mod_t modulation, bool compute_soft_demod) {
switch(modulation) {
case LTE_BPSK:
q->nbits_x_symbol = 1;
q->nsymbols = 2;
if (table_create(q)) {
return -1;
return LIBLTE_ERROR;
}
set_BPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break;
@ -84,7 +85,7 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem
q->nbits_x_symbol = 2;
q->nsymbols = 4;
if (table_create(q)) {
return -1;
return LIBLTE_ERROR;
}
set_QPSKtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break;
@ -92,7 +93,7 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem
q->nbits_x_symbol = 4;
q->nsymbols = 16;
if (table_create(q)) {
return -1;
return LIBLTE_ERROR;
}
set_16QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break;
@ -100,10 +101,10 @@ int modem_table_std(modem_table_t* q, enum modem_std std, bool compute_soft_dem
q->nbits_x_symbol = 6;
q->nsymbols = 64;
if (table_create(q)) {
return -1;
return LIBLTE_ERROR;
}
set_64QAMtable(q->symbol_table, &q->soft_table, compute_soft_demod);
break;
}
return 0;
return LIBLTE_SUCCESS;
}

@ -31,8 +31,560 @@
#include <math.h>
#include <complex.h>
#include <stdint.h>
#include <string.h>
#include "soft_algs.h"
#include "liblte/phy/utils/vector.h"
#define QAM16_THRESHOLD 2/sqrt(10)
#define QAM64_THRESHOLD_1 2/sqrt(42)
#define QAM64_THRESHOLD_2 4/sqrt(42)
#define QAM64_THRESHOLD_3 6/sqrt(42)
typedef _Complex float cf_t;
// There are 3 implemenations: 1 - based on zones; 2 - using volk, 3 - straightforward C
#define LLR_APPROX_IMPLEMENTATION 1
#if LLR_APPROX_IMPLEMENTATION == 1
float dd[10000][7]; // 7 distances that are needed to compute LLR approx for 64QAM
uint32_t zone[10000]; // Zone of received symbol with respect to grid of QAM constellation diagram
/**
* @ingroup Received modulation symbol zone
* Determine location of received modulation symbol
*
* \param in input symbol (_Complex float)
* \param z associated zone in constellation diagram (int)
* \param N number of symbols
*/
static void zone_QPSK(const cf_t * in, uint32_t * z, int N)
{
int s;
float re, im;
for (s = 0; s < N; s++) {
re = __real__ in[s];
im = __imag__ in[s];
if (re > 0) {
if (im > 0) { /* 1st Quadrand (upper-right) */
z[s] = 0;
} else { /* 4th Quadrand (lower-right) */
z[s] = 1;
}
} else {
if (im > 0) { /* 2nd Quadrand (upper-left) */
z[s] = 2;
} else { /* 3rd Quadrand (lower-left) */
z[s] = 3;
}
}
}
}
/**
* @ingroup Received modulation symbol zone
* Determine location of received modulation symbol
*
* \param in input symbol (_Complex float)
* \param z associated zone in constellation diagram (int)
* \param N number of symbols
*/
static void zone_QAM16(const cf_t * in, uint32_t * z, int N)
{
int s;
float re, im;
for (s = 0; s < N; s++) {
re = __real__ in[s];
im = __imag__ in[s];
if (re > 0) {
if (im > 0) { /* 1st Quadrand (upper-right) */
if (re > QAM16_THRESHOLD) {
if (im > QAM16_THRESHOLD) {
z[s] = 3;
} else {
z[s] = 2;
}
} else {
if (im > QAM16_THRESHOLD) {
z[s] = 1;
} else {
z[s] = 0;
}
}
} else { /* 4th Quadrand (lower-right) */
if (re > QAM16_THRESHOLD) {
if (im < -QAM16_THRESHOLD) {
z[s] = 7;
} else {
z[s] = 6;
}
} else {
if (im < -QAM16_THRESHOLD) {
z[s] = 5;
} else {
z[s] = 4;
}
}
}
} else {
if (im > 0) { /* 2nd Quadrand (upper-left) */
if (re < -QAM16_THRESHOLD) {
if (im > QAM16_THRESHOLD) {
z[s] = 11;
} else {
z[s] = 10;
}
} else {
if (im > QAM16_THRESHOLD) {
z[s] = 9;
} else {
z[s] = 8;
}
}
} else { /* 3rd Quadrand (lower-left) */
if (re < -QAM16_THRESHOLD) {
if (im < -QAM16_THRESHOLD) {
z[s] = 15;
} else {
z[s] = 14;
}
} else {
if (im < -QAM16_THRESHOLD) {
z[s] = 13;
} else {
z[s] = 12;
}
}
}
}
}
}
/**
* @ingroup Received modulation symbol zone
* Determine location of received modulation symbol
*
* \param in input symbol (_Complex float)
* \param z associated zone in constellation diagram (int)
* \param N number of symbols
*/
static void zone_QAM64(const cf_t * in, uint32_t * z, int N)
{
int s;
float re, im;
for (s = 0; s < N; s++) {
re = __real__ in[s];
im = __imag__ in[s];
if (re > 0) {
if (im > 0) {
if (re > QAM64_THRESHOLD_2) {
if (re > QAM64_THRESHOLD_3) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 15;
} else {
z[s] = 14;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 10;
} else {
z[s] = 11;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 13;
} else {
z[s] = 12;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 8;
} else {
z[s] = 9;
}
}
} else if (re > QAM64_THRESHOLD_1) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 5;
} else {
z[s] = 4;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 0;
} else {
z[s] = 1;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 7;
} else {
z[s] = 6;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 2;
} else {
z[s] = 3;
}
}
} else { /* forth quadrant (lower-right) */
if (re > QAM64_THRESHOLD_2) {
if (re > QAM64_THRESHOLD_3) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 31;
} else {
z[s] = 30;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 26;
} else {
z[s] = 27;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 29;
} else {
z[s] = 28;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 24;
} else {
z[s] = 25;
}
}
} else if (re > QAM64_THRESHOLD_1) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 21;
} else {
z[s] = 20;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 16;
} else {
z[s] = 17;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 23;
} else {
z[s] = 22;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 18;
} else {
z[s] = 19;
}
}
}
} else { /* re < 0 */
if (im > 0) { /* second quadrant (upper-left) */
if (re < -QAM64_THRESHOLD_2) {
if (re < -QAM64_THRESHOLD_3) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 47;
} else {
z[s] = 46;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 42;
} else {
z[s] = 43;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 45;
} else {
z[s] = 44;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 40;
} else {
z[s] = 41;
}
}
} else if (re < -QAM64_THRESHOLD_1) {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 37;
} else {
z[s] = 36;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 32;
} else {
z[s] = 33;
}
} else {
if (im > QAM64_THRESHOLD_2) {
if (im > QAM64_THRESHOLD_3) {
z[s] = 39;
} else {
z[s] = 38;
}
} else if (im > QAM64_THRESHOLD_1) {
z[s] = 34;
} else {
z[s] = 35;
}
}
} else { /* third quadrant (lower-left) */
if (re < -QAM64_THRESHOLD_2) {
if (re < -QAM64_THRESHOLD_3) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 63;
} else {
z[s] = 62;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 58;
} else {
z[s] = 59;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 61;
} else {
z[s] = 60;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 56;
} else {
z[s] = 57;
}
}
} else if (re < -QAM64_THRESHOLD_1) {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 53;
} else {
z[s] = 52;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 48;
} else {
z[s] = 49;
}
} else {
if (im < -QAM64_THRESHOLD_2) {
if (im < -QAM64_THRESHOLD_3) {
z[s] = 55;
} else {
z[s] = 54;
}
} else if (im < -QAM64_THRESHOLD_1) {
z[s] = 50;
} else {
z[s] = 51;
}
}
}
}
}
}
static void compute_zone(const cf_t * in, uint32_t * z, int N, int B)
{
switch (B) {
case 1:{
memset(zone, 0, N * sizeof(int));
break;
} /* BPSK */
case 2:{
zone_QPSK(in, z, N);
break;
} /* QPSK */
case 4:{
zone_QAM16(in, z, N);
break;
} /* 16QAM */
case 6:{
zone_QAM64(in, z, N);
break;
} /* 64QAM */
}
}
static void compute_square_dist(const cf_t * in, cf_t * symbols,
uint32_t(*idx)[7], int N, int B)
{
int s, b;
float *d_ptr;
cf_t symbols_extract[7];
for (s = 0; s < N; s++) { /* N: number of received symbols */
d_ptr = dd[s];
for (b = 0; b < B + 1; b++) {
symbols_extract[b] = symbols[idx[zone[s]][b]]; /* only subset of distances to constellation points needed for LLR approx */
//x = __real__ in[s] - __real__ symbols[idx[zone[s]][b]];
//y = __imag__ in[s] - __imag__ symbols[idx[zone[s]][b]];
//dd[s][b] = x*x + y*y;
//printf("\n%f + j %f", __real__ symbols_extract[b], __imag__ symbols_extract[b]);
}
vec_square_dist(in[s], symbols_extract, d_ptr, B + 1); /* B+1 distances to be computed */
}
}
static void compute_llr(int N, int B, uint32_t(*min)[64][6], float sigma2,
float *out)
{
int s, b;
for (s = 0; s < N; s++) {
for (b = 0; b < B; b++) { /* bits per symbol */
out[s * B + b] =
(dd[s][min[0][zone[s]][b]] - dd[s][min[1][zone[s]][b]]) / sigma2;
}
}
}
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], uint32_t(*idx)[7],
uint32_t(*min)[64][6], float sigma2)
{
if ((M == 2) || (M == 4) || (M == 16) || (M == 64)) {
compute_zone(in, zone, N, B);
compute_square_dist(in, symbols, idx, N, B);
compute_llr(N, B, min, sigma2, out);
}
}
#elif LLR_APPROX_IMPLEMENTATION == 2
float d[10000][64];
float num[10000], den[10000];
static void compute_square_dist(const cf_t * in, cf_t * symbols, int N, int M)
{
int s;
float *d_ptr;
for (s = 0; s < N; s++) {
d_ptr = d[s];
vec_square_dist(in[s], symbols, d_ptr, M);
}
}
static void compute_min_dist(uint32_t(*S)[6][32], int N, int B, int M)
{
int s, b, i;
for (s = 0; s < N; s++) {
for (b = 0; b < B; b++) { /* bits per symbol */
/* initiate num[b] and den[b] */
num[s * B + b] = 1e10;
den[s * B + b] = 1e10;
for (i = 0; i < M / 2; i++) {
if (d[s][S[0][b][i]] < num[s * B + b]) {
num[s * B + b] = d[s][S[0][b][i]];
}
if (d[s][S[1][b][i]] < den[s * B + b]) {
den[s * B + b] = d[s][S[1][b][i]];
}
}
}
}
}
static void compute_llr(int N, int B, float sigma2, float *out)
{
int s, b;
for (s = 0; s < N; s++) {
for (b = 0; b < B; b++) { /* bits per symbol */
out[s * B + b] = (num[s * B + b] - den[s * B + b]) / sigma2;
}
}
}
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], float sigma2)
{
if (M <= 64) {
compute_square_dist(in, symbols, N, M);
compute_min_dist(S, N, B, M);
compute_llr(N, B, sigma2, out);
}
for (b = 0; b < B; b++) { /* bits per symbol */
out[s * B + b] = (num[s * B + b] - den[s * B + b]) / sigma2;
}
}
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, uint32_t(*S)[6][32], uint32_t(*idx)[7],
uint32_t(*min)[64][6], float sigma2)
{
if (M <= 64) {
compute_square_dist(in, symbols, N, M);
compute_min_dist(S, N, B, M);
compute_llr(N, B, sigma2, out);
}
}
#else
/**
* @ingroup Soft Modulation Demapping based on the approximate
@ -51,39 +603,35 @@
* \param sigma2 Noise vatiance
*/
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, int (*S)[6][32], float sigma2) {
_Complex float *symbols, uint32_t(*S)[6][32], uint32_t(*idx)[7],
uint32_t(*min)[64][6], float sigma2)
{
int i, s, b;
float num, den;
float new_num, new_den;
float idiff0, qdiff0, idiff1, qdiff1;
int change_sign = -1;
float x, y, d[64];
for (s = 0; s < N; s++) { /* recevied symbols */
/* Compute the distances squared d[i] between the received symbol and all constellation points */
for (i = 0; i < M; i++) {
x = __real__ in[s] - __real__ symbols[i];
y = __imag__ in[s] - __imag__ symbols[i];
d[i] = x * x + y * y;
}
for (b = 0; b < B; b++) { /* bits per symbol */
/* initiate num[b] and den[b] */
idiff0 = __real__ in[s] - __real__ symbols[S[0][b][0]];
qdiff0 = __imag__ in[s] - __imag__ symbols[S[0][b][0]];
num = idiff0*idiff0 + qdiff0*qdiff0;
idiff1 = __real__ in[s] - __real__ symbols[S[1][b][0]];
qdiff1 = __imag__ in[s] - __imag__ symbols[S[1][b][0]];
den = idiff1*idiff1 + qdiff1*qdiff1;
/* half the constellation symbols have '1'|'0' at any bit pos. */
for (i=1; i<M/2; i++) {
idiff0 = __real__ in[s] - __real__ symbols[S[0][b][i]];
qdiff0 = __imag__ in[s] - __imag__ symbols[S[0][b][i]];
new_num = idiff0*idiff0 + qdiff0*qdiff0;
idiff1 = __real__ in[s] - __real__ symbols[S[1][b][i]];
qdiff1 = __imag__ in[s] - __imag__ symbols[S[1][b][i]];
new_den = idiff1*idiff1 + qdiff1*qdiff1;
num = d[S[0][b][0]];
den = d[S[1][b][0]];
if (new_num < num) {
num = new_num;
/* Minimum distance squared search between recevied symbol and a constellation point with a
'1' and a '0' for each bit position */
for (i = 1; i < M / 2; i++) { /* half the constellation points have '1'|'0' at any given bit position */
if (d[S[0][b][i]] < num) {
num = d[S[0][b][i]];
}
if (new_den < den) {
den = new_den;
if (d[S[1][b][i]] < den) {
den = d[S[1][b][i]];
}
}
/* Theoretical LLR and approximate LLR values are positive if
@ -91,9 +639,16 @@ void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
* with '1' are closer.
* Change sign if mapping negative to '0' and positive to '1' */
out[s * B + b] = change_sign * (den - num) / sigma2;
if (s < 10)
printf("out[%d]=%f=%f/%f\n", s * B + b, out[s * B + b], num, den);
}
/* if (s<10)
printf("out[%d]=%f=%f/%f\n",s*B+b,out[s*B+b], num,den);
*/ }
}
}
#endif
/**
* @ingroup Soft Modulation Demapping based on the approximate
@ -112,26 +667,30 @@ void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
* \param sigma2 Noise vatiance
*/
void llr_exact(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, int (*S)[6][32], float sigma2) {
_Complex float *symbols, uint32_t(*S)[6][32], float sigma2)
{
int i, s, b;
float num, den;
float idiff0, qdiff0, idiff1, qdiff1;
int change_sign = -1;
float x, y, d[64];
for (s = 0; s < N; s++) { /* recevied symbols */
/* Compute exp{·} of the distances squared d[i] between the received symbol and all constellation points */
for (i = 0; i < M; i++) {
x = __real__ in[s] - __real__ symbols[i];
y = __imag__ in[s] - __imag__ symbols[i];
d[i] = exp(-1 * (x * x + y * y) / sigma2);
}
/* Sum up the corresponding d[i]'s for each bit position */
for (b = 0; b < B; b++) { /* bits per symbol */
/* initiate num[b] and den[b] */
num = 0;
den = 0;
/* half the constellation symbols have '1'|'0' at any bit pos. */
for (i=0; i<M/2; i++) {
idiff0 = __real__ in[s] - __real__ symbols[S[0][b][i]];
qdiff0 = __imag__ in[s] - __imag__ symbols[S[0][b][i]];
num += exp(-1*(idiff0*idiff0 + qdiff0*qdiff0)/sigma2);
idiff1 = __real__ in[s] - __real__ symbols[S[1][b][i]];
qdiff1 = __imag__ in[s] - __imag__ symbols[S[1][b][i]];
den += exp(-1*(idiff1*idiff1 + qdiff1*qdiff1)/sigma2);
for (i = 0; i < M / 2; i++) { /* half the constellation points have '1'|'0' at any given bit position */
num += d[S[0][b][i]];
den += d[S[1][b][i]];
}
/* Theoretical LLR and approximate LLR values are positive if
* symbol(s) with '0' is/are closer and negative if symbol(s)

@ -26,8 +26,32 @@
*/
void llr_approx(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, int (*S)[6][32], float sigma2);
/*void llr_approx(const _Complex float *in,
float *out,
int N,
int M,
int B,
_Complex float *symbols,
uint32_t (*S)[6][32],
float sigma2);
*/
void llr_approx(const _Complex float *in,
float *out,
int N,
int M,
int B,
_Complex float *symbols,
uint32_t (*S)[6][32],
uint32_t (*idx)[7], /*64x7 table of integers [0..63], indices to 7 distances to be computed */
uint32_t (*min)[64][6], /*2x64x6 table of integers [0..6], indices to 2x6 nearest symbols */
float sigma2);
void llr_exact(const _Complex float *in,
float *out,
int N,
int M,
int B,
_Complex float *symbols,
uint32_t (*S)[6][32],
float sigma2);
void llr_exact(const _Complex float *in, float *out, int N, int M, int B,
_Complex float *symbols, int (*S)[6][32], float sigma2);

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

Loading…
Cancel
Save