Fixed some bugs in UE PDSCH example: equalization with zero channel estimates, cell search, synchronization. CRC-based early stopping

master
ismagom 11 years ago
parent 182c9958bb
commit ce2abc06fe

@ -51,7 +51,7 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND)
# These two can be compiled without UHD or graphics support # These two can be compiled without UHD or graphics support
################################################################# #################################################################
add_executable(pdsch_ue pdsch_ue.c iodev.c) add_executable(pdsch_ue pdsch_ue.c iodev.c cell_search_utils.c)
target_link_libraries(pdsch_ue lte_phy) target_link_libraries(pdsch_ue lte_phy)
add_executable(pdsch_enodeb pdsch_enodeb.c) add_executable(pdsch_enodeb pdsch_enodeb.c)
@ -81,7 +81,7 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1)
IF(${CUHD_FIND} GREATER -1) IF(${CUHD_FIND} GREATER -1)
add_executable(cell_search cell_search.c) add_executable(cell_search cell_search.c cell_search_utils.c)
target_link_libraries(cell_search lte_phy cuhd ) target_link_libraries(cell_search lte_phy cuhd )
MESSAGE(STATUS " UHD examples will be installed.") MESSAGE(STATUS " UHD examples will be installed.")

@ -37,6 +37,9 @@
#include "liblte/phy/phy.h" #include "liblte/phy/phy.h"
#include "cell_search_utils.h"
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
#include "liblte/cuhd/cuhd.h" #include "liblte/cuhd/cuhd.h"
#endif #endif
@ -113,120 +116,6 @@ void parse_args(int argc, char **argv) {
} }
} }
int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell)
{
ue_mib_t uemib;
pbch_mib_t mib;
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;
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:
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 n;
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
int n; int n;
void *uhd; void *uhd;
@ -236,6 +125,7 @@ int main(int argc, char **argv) {
int nof_freqs; int nof_freqs;
lte_earfcn_t channels[MAX_EARFCN]; lte_earfcn_t channels[MAX_EARFCN];
uint32_t freq; uint32_t freq;
pbch_mib_t mib;
parse_args(argc, argv); parse_args(argc, argv);
@ -296,7 +186,7 @@ int main(int argc, char **argv) {
if (n == CS_CELL_DETECTED) { if (n == CS_CELL_DETECTED) {
for (int i=0;i<3;i++) { for (int i=0;i<3;i++) {
if (found_cells[i].peak > threshold/2) { if (found_cells[i].peak > threshold/2) {
if (decode_pbch(uhd, buffer, &found_cells[i])) { if (decode_pbch(uhd, buffer, &found_cells[i], nof_frames_total, &mib)) {
fprintf(stderr, "Error decoding PBCH\n"); fprintf(stderr, "Error decoding PBCH\n");
exit(-1); exit(-1);
} }

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

@ -29,6 +29,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "iodev.h" #include "iodev.h"
@ -41,6 +42,8 @@
#include "liblte/cuhd/cuhd.h" #include "liblte/cuhd/cuhd.h"
#endif #endif
#include "cell_search_utils.h"
int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
DEBUG(" ---- Receive %d samples ---- \n", nsamples); DEBUG(" ---- Receive %d samples ---- \n", nsamples);
@ -48,20 +51,36 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) {
} }
/* Setup USRP or input file */ /* Setup USRP or input file */
int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) { int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mib) {
if (config->input_file_name) { 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)) { if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
q->input_buffer_file = vec_malloc(SF_LEN_MAX * sizeof(cf_t)); 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) { if (!q->input_buffer_file) {
perror("malloc"); perror("malloc");
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
q->sf_idx = 9;
q->mode = FILESOURCE;
q->sf_len = file_sf_len;
} else { } else {
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
@ -71,18 +90,76 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
/* set uhd_freq */
cuhd_set_rx_gain(q->uhd, config->uhd_gain); cuhd_set_rx_gain(q->uhd, config->uhd_gain);
/* set receiver frequency */
cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq); cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq);
cuhd_rx_wait_lo_locked(q->uhd); cuhd_rx_wait_lo_locked(q->uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq); 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); DEBUG("Starting receiver...\n", 0);
cuhd_start_rx_stream(q->uhd); cuhd_start_rx_stream(q->uhd);
lte_cell_t cell; if (ue_sync_init(&q->sframe, *cell, cuhd_recv_wrapper, q->uhd)) {
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 // Here, the subframe length and input buffer is managed by ue_sync
q->mode = UHD; q->mode = UHD;
@ -114,7 +191,7 @@ void iodev_free(iodev_t *q) {
int iodev_receive(iodev_t *q, cf_t **buffer) { int iodev_receive(iodev_t *q, cf_t **buffer) {
int n; int n;
if (q->mode == FILESOURCE) { if (q->mode == FILESOURCE) {
DEBUG(" ----- READING %d SAMPLES ---- \n", q->sf_len); INFO(" ----- READING %d SAMPLES ---- \n", q->sf_len);
n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len);
*buffer = q->input_buffer_file; *buffer = q->input_buffer_file;
if (n == -1) { if (n == -1) {
@ -133,6 +210,11 @@ int iodev_receive(iodev_t *q, cf_t **buffer) {
} else { } else {
n = 1; n = 1;
} }
q->sf_idx++;
if (q->sf_idx == 10) {
q->sf_idx = 0;
}
usleep(5000);
} else { } else {
/* Use ue_sync_work which returns a synchronized buffer of subframe samples */ /* Use ue_sync_work which returns a synchronized buffer of subframe samples */
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
@ -161,4 +243,12 @@ bool iodev_isUSRP(iodev_t *q) {
return q->mode == UHD; 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);
}
}

@ -54,6 +54,10 @@ typedef _Complex float cf_t;
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
char *input_file_name; char *input_file_name;
uint32_t cell_id_file;
uint32_t nof_prb_file;
uint32_t nof_ports_file;
float uhd_freq; float uhd_freq;
float uhd_gain; float uhd_gain;
char *uhd_args; char *uhd_args;
@ -66,6 +70,7 @@ typedef struct LIBLTE_API {
ue_sync_t sframe; ue_sync_t sframe;
#endif #endif
uint32_t sf_len; 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 cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t
filesource_t fsrc; filesource_t fsrc;
iodev_cfg_t config; iodev_cfg_t config;
@ -75,7 +80,8 @@ typedef struct LIBLTE_API {
LIBLTE_API int iodev_init(iodev_t *q, LIBLTE_API int iodev_init(iodev_t *q,
iodev_cfg_t *config, iodev_cfg_t *config,
uint32_t file_sf_len); lte_cell_t *cell,
pbch_mib_t *mib);
LIBLTE_API void iodev_free(iodev_t *q); LIBLTE_API void iodev_free(iodev_t *q);
@ -84,6 +90,8 @@ LIBLTE_API int iodev_receive(iodev_t *q,
LIBLTE_API void* iodev_get_cuhd(iodev_t *q); 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_isfile(iodev_t *q);
LIBLTE_API bool iodev_isUSRP(iodev_t *q); LIBLTE_API bool iodev_isUSRP(iodev_t *q);

@ -53,8 +53,6 @@ void init_plots();
* Program arguments processing * Program arguments processing
***********************************************************************/ ***********************************************************************/
typedef struct { typedef struct {
uint32_t cell_id_file;
uint32_t nof_prb_file;
uint16_t rnti; uint16_t rnti;
int nof_subframes; int nof_subframes;
bool disable_plots; bool disable_plots;
@ -62,8 +60,9 @@ typedef struct {
}prog_args_t; }prog_args_t;
void args_default(prog_args_t *args) { void args_default(prog_args_t *args) {
args->cell_id_file = 1; args->io_config.cell_id_file = 195;
args->nof_prb_file = 6; args->io_config.nof_prb_file = 50;
args->io_config.nof_ports_file = 2;
args->rnti = SIRNTI; args->rnti = SIRNTI;
args->nof_subframes = -1; args->nof_subframes = -1;
args->disable_plots = false; args->disable_plots = false;
@ -71,13 +70,14 @@ void args_default(prog_args_t *args) {
args->io_config.input_file_name = NULL; args->io_config.input_file_name = NULL;
args->io_config.uhd_args = ""; args->io_config.uhd_args = "";
args->io_config.uhd_freq = -1.0; args->io_config.uhd_freq = -1.0;
args->io_config.uhd_gain = 20.0; args->io_config.uhd_gain = 60.0;
} }
void usage(prog_args_t *args, char *prog) { void usage(prog_args_t *args, char *prog) {
printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", 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->cell_id_file); 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->nof_prb_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); printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti);
#ifndef DISABLE_UHD #ifndef DISABLE_UHD
printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args); printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args);
@ -99,16 +99,19 @@ void usage(prog_args_t *args, char *prog) {
void parse_args(prog_args_t *args, int argc, char **argv) { void parse_args(prog_args_t *args, int argc, char **argv) {
int opt; int opt;
args_default(args); args_default(args);
while ((opt = getopt(argc, argv, "icagfndvtbpr")) != -1) { while ((opt = getopt(argc, argv, "icagfndvtbpro")) != -1) {
switch (opt) { switch (opt) {
case 'i': case 'i':
args->io_config.input_file_name = argv[optind]; args->io_config.input_file_name = argv[optind];
break; break;
case 'c': case 'c':
args->cell_id_file = atoi(argv[optind]); args->io_config.cell_id_file = atoi(argv[optind]);
break; break;
case 'p': case 'p':
args->nof_prb_file = atoi(argv[optind]); args->io_config.nof_prb_file = atoi(argv[optind]);
break;
case 'o':
args->io_config.nof_ports_file = atoi(argv[optind]);
break; break;
case 'a': case 'a':
args->io_config.uhd_args = argv[optind]; args->io_config.uhd_args = argv[optind];
@ -152,6 +155,8 @@ void sigintHandler(int x) {
/* TODO: Do something with the output data */ /* TODO: Do something with the output data */
char data[10000]; char data[10000];
extern float mean_exec_time;
int main(int argc, char **argv) { int main(int argc, char **argv) {
int ret; int ret;
cf_t *sf_buffer; cf_t *sf_buffer;
@ -159,27 +164,13 @@ int main(int argc, char **argv) {
prog_args_t prog_args; prog_args_t prog_args;
lte_cell_t cell; lte_cell_t cell;
ue_dl_t ue_dl; ue_dl_t ue_dl;
bool ue_dl_initiated = false;
int64_t sf_cnt; int64_t sf_cnt;
uint32_t sf_idx;
pbch_mib_t mib; pbch_mib_t mib;
bool printed_sib = false; bool printed_sib = false;
int rlen; int rlen;
int symbol_sz;
parse_args(&prog_args, argc, argv); parse_args(&prog_args, argc, argv);
symbol_sz = lte_symbol_sz(prog_args.nof_prb_file);
if (symbol_sz > 0) {
if (iodev_init(&iodev, &prog_args.io_config, SF_LEN(symbol_sz))) {
fprintf(stderr, "Error initiating input device\n");
exit(-1);
}
} else {
fprintf(stderr, "Invalid number of PRB %d\n", prog_args.nof_prb_file);
exit(-1);
}
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots) { if (!prog_args.disable_plots) {
init_plots(); init_plots();
@ -190,16 +181,22 @@ int main(int argc, char **argv) {
printf("\n --- Press Ctrl+C to exit --- \n"); printf("\n --- Press Ctrl+C to exit --- \n");
signal(SIGINT, sigintHandler); signal(SIGINT, sigintHandler);
/* Initialize frame and subframe counters */ /* Initialize subframe counter */
sf_cnt = 0; sf_cnt = 0;
sf_idx = 0;
/* Decodes the SSS signal during the tracking phase. Extra overhead, but makes sure we are in the correct subframe */ if (iodev_init(&iodev, &prog_args.io_config, &cell, &mib)) {
ue_sync_decode_sss_on_track(&iodev.sframe, true); 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 */ /* Main loop */
while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) {
ret = iodev_receive(&iodev, &sf_buffer); ret = iodev_receive(&iodev, &sf_buffer);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "Error reading from input device (%d)\n", ret); fprintf(stderr, "Error reading from input device (%d)\n", ret);
@ -207,81 +204,41 @@ int main(int argc, char **argv) {
} }
/* iodev_receive returns 1 if successfully read 1 aligned subframe */ /* iodev_receive returns 1 if successfully read 1 aligned subframe */
if (ret == 0) { if (ret == 1) {
printf("Finding PSS... Peak: %8.1f, Output level: %+.2f dB FrameCnt: %d, State: %d\r", rlen = ue_dl_decode(&ue_dl, sf_buffer, data, iodev_get_sfidx(&iodev), prog_args.rnti);
sync_get_peak_value(&iodev.sframe.sfind), if (rlen < 0) {
iodev.sframe.frame_total_cnt, iodev.sframe.state); fprintf(stderr, "\nError running receiver\n");fflush(stdout);
} else if (ret == 1) { exit(-1);
if (!ue_dl_initiated) {
if (iodev_isUSRP(&iodev)) {
//cell = ue_sync_get_cell(&iodev.sframe);
//mib = ue_sync_get_mib(&iodev.sframe);
} else {
cell.id = prog_args.cell_id_file;
cell.cp = CPNORM;
cell.nof_ports = 1; // TODO: Use prog_args
cell.nof_prb = prog_args.nof_prb_file;
mib.phich_resources = R_1;
mib.phich_length = PHICH_NORM;
}
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);
ue_dl_initiated = true;
} else {
if (iodev_isUSRP(&iodev)) {
sf_idx = ue_sync_get_sfidx(&iodev.sframe);
}
//rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti);
rlen=-1;
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;
}
if (!(sf_cnt % 10)) {
printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e\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, (float) ue_dl.pkt_errors / ue_dl.pkts_total);
fflush(stdout);
if (VERBOSE_ISINFO()) {
printf("\n");
}
}
#ifndef DISABLE_GRAPHICS
if (!prog_args.disable_plots && sf_idx == 5) {
do_plots(&ue_dl, sf_idx);
}
#endif
} }
if (iodev_isfile(&iodev)) { if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) {
sf_idx++; printf("\n\nDecoded SIB1 Message: ");
if (sf_idx == NSUBFRAMES_X_FRAME) { vec_fprint_hex(stdout, data, rlen);
sf_idx = 0; printf("\n");fflush(stdout);
} printed_sib = true;
} }
}
if (prog_args.nof_subframes > 0) { // Plot and Printf
sf_cnt++; if (!(sf_cnt % 10)) {
} printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e, Texec: %.2f\r",
if (iodev_isfile(&iodev)) { ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000,
usleep(5000); pdsch_average_noi(&ue_dl.pdsch),
(int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (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
if (ue_dl_initiated) { ue_dl_free(&ue_dl);
ue_dl_free(&ue_dl);
}
iodev_free(&iodev); iodev_free(&iodev);
printf("\nBye\n"); printf("\nBye\n");

@ -57,6 +57,7 @@
#define NOF_HARQ_PROCESSES 8 #define NOF_HARQ_PROCESSES 8
typedef struct LIBLTE_API { typedef struct LIBLTE_API {
pbch_t pbch;
pcfich_t pcfich; pcfich_t pcfich;
pdcch_t pdcch; pdcch_t pdcch;
pdsch_t pdsch; pdsch_t pdsch;
@ -74,6 +75,9 @@ typedef struct LIBLTE_API {
uint64_t pkts_total; uint64_t pkts_total;
uint64_t nof_trials; uint64_t nof_trials;
uint32_t sfn;
bool pbch_decoded;
uint16_t user_rnti; uint16_t user_rnti;
}ue_dl_t; }ue_dl_t;
@ -86,11 +90,10 @@ LIBLTE_API int ue_dl_init(ue_dl_t *q,
LIBLTE_API void ue_dl_free(ue_dl_t *q); LIBLTE_API void ue_dl_free(ue_dl_t *q);
LIBLTE_API int ue_dl_receive(ue_dl_t *q, LIBLTE_API int ue_dl_decode(ue_dl_t *q,
cf_t *sf_buffer, cf_t *sf_buffer,
char *data, char *data,
uint32_t sf_idx, uint32_t sf_idx,
uint32_t sfn,
uint16_t rnti); uint16_t rnti);
#endif #endif

@ -38,7 +38,7 @@
#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz)
#define SF_SZ(q) (2 * SLOT_SZ(q)) #define SF_SZ(q) (2 * SLOT_SZ(q))
//#define VOLK_INTERP #define VOLK_INTERP
void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) {
chest_ref_fprint(q, stream, nslot, port_id); chest_ref_fprint(q, stream, nslot, port_id);
@ -111,16 +111,18 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint
channel_ref = input[tidx * q->nof_re + fidx]; channel_ref = input[tidx * q->nof_re + fidx];
q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; 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, tidx * q->nof_re + 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)), 10*log10f(cabsf(channel_ref/known_ref)),
cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI, cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI,
cargf(channel_ref/known_ref)/M_PI); cargf(channel_ref/known_ref)/M_PI);
/* FIXME: compare with threshold */ /* FIXME: compare with threshold */
if (channel_ref != 0) { if (channel_ref != 0) {
q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref;
} else { } else {
q->refsignal[port_id][nslot].ch_est[nref] = 0; q->refsignal[port_id][nslot].ch_est[nref] = 1e-6;
} }
ret = LIBLTE_SUCCESS; ret = LIBLTE_SUCCESS;
} }
@ -182,7 +184,7 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32
for (j=0;j<MAX_NSYMB;j++) { for (j=0;j<MAX_NSYMB;j++) {
y[j] = ce[r->symbols_ref[0] * q->nof_re + i]; y[j] = ce[r->symbols_ref[0] * q->nof_re + i];
} }
} }
for (j=0;j<q->nof_symbols;j++) { for (j=0;j<q->nof_symbols;j++) {
ce[j * q->nof_re + i] = y[j]; ce[j * q->nof_re + i] = y[j];
} }
@ -321,8 +323,10 @@ void chest_free(chest_t *q) {
} }
} }
#ifdef VOLK_INTERP #ifdef VOLK_INTERP
interp_free(&q->interp_freq); for (p=0;p<MAX_PORTS;p++) {
interp_free(&q->interp_time); interp_free(&q->interp_freq[p]);
interp_free(&q->interp_time[p]);
}
#endif #endif
bzero(q, sizeof(chest_t)); bzero(q, sizeof(chest_t));
} }

@ -30,6 +30,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <math.h>
#include "liblte/phy/fec/turbodecoder.h" #include "liblte/phy/fec/turbodecoder.h"
@ -39,7 +40,9 @@
* Decoder * Decoder
* *
************************************************/ ************************************************/
void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, uint32_t 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 m_b[8], new[8], old[8];
llr_t x, y, xy; llr_t x, y, xy;
int k; int k;
@ -84,8 +87,9 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, uint32_t long_cb) {
} }
} }
void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, void map_gen_alpha(map_gen_t * s, llr_t * input, llr_t * parity, llr_t * output,
uint32_t long_cb) { uint32_t long_cb)
{
llr_t m_b[8], new[8], old[8], max1[8], max0[8]; llr_t m_b[8], new[8], old[8], max1[8], max0[8];
llr_t m1, m0; llr_t m1, m0;
llr_t x, y, xy; llr_t x, y, xy;
@ -150,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)); bzero(h, sizeof(map_gen_t));
h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1) * NUMSTATES); h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1) * NUMSTATES);
if (!h->beta) { if (!h->beta) {
@ -161,15 +166,17 @@ int map_gen_init(map_gen_t *h, int max_long_cb) {
return 0; return 0;
} }
void map_gen_free(map_gen_t *h) { void map_gen_free(map_gen_t * h)
{
if (h->beta) { if (h->beta) {
free(h->beta); free(h->beta);
} }
bzero(h, sizeof(map_gen_t)); bzero(h, sizeof(map_gen_t));
} }
void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, void map_gen_dec(map_gen_t * h, llr_t * input, llr_t * parity, llr_t * output,
uint32_t long_cb) { uint32_t long_cb)
{
uint32_t k; uint32_t k;
h->beta[(long_cb + TAIL) * NUMSTATES] = 0; h->beta[(long_cb + TAIL) * NUMSTATES] = 0;
@ -185,7 +192,8 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output,
* TURBO DECODER INTERFACE * TURBO DECODER INTERFACE
* *
************************************************/ ************************************************/
int tdec_init(tdec_t *h, uint32_t max_long_cb) { int tdec_init(tdec_t * h, uint32_t max_long_cb)
{
int ret = -1; int ret = -1;
bzero(h, sizeof(tdec_t)); bzero(h, sizeof(tdec_t));
uint32_t len = max_long_cb + TOTALTAIL; uint32_t len = max_long_cb + TOTALTAIL;
@ -227,13 +235,14 @@ int tdec_init(tdec_t *h, uint32_t max_long_cb) {
} }
ret = 0; ret = 0;
clean_and_exit: if (ret == -1) { clean_and_exit:if (ret == -1) {
tdec_free(h); tdec_free(h);
} }
return ret; return ret;
} }
void tdec_free(tdec_t *h) { void tdec_free(tdec_t * h)
{
if (h->llr1) { if (h->llr1) {
free(h->llr1); free(h->llr1);
} }
@ -257,7 +266,8 @@ void tdec_free(tdec_t *h) {
bzero(h, sizeof(tdec_t)); bzero(h, sizeof(tdec_t));
} }
void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) { void tdec_iteration(tdec_t * h, llr_t * input, uint32_t long_cb)
{
uint32_t i; uint32_t i;
// Prepare systematic and parity bits for MAP DEC #1 // Prepare systematic and parity bits for MAP DEC #1
@ -276,19 +286,19 @@ void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) {
// Prepare systematic and parity bits for MAP DEC #1 // Prepare systematic and parity bits for MAP DEC #1
for (i = 0; i < long_cb; i++) { for (i = 0; i < long_cb; i++) {
h->syst[i] = h->llr1[h->interleaver.forward[i]] h->syst[i] = h->llr1[h->interleaver.forward[i]]
- h->w[h->interleaver.forward[i]]; - h->w[h->interleaver.forward[i]];
h->parity[i] = input[RATE * i + 2]; h->parity[i] = input[RATE * i + 2];
} }
for (i = long_cb; i < long_cb + RATE; i++) { for (i = long_cb; i < long_cb + RATE; i++) {
h->syst[i] = h->syst[i] =
input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)]; input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)];
h->parity[i] = input[RATE * long_cb + NINPUTS * RATE h->parity[i] = input[RATE * long_cb + NINPUTS * RATE
+ NINPUTS * (i - long_cb) + 1]; + NINPUTS * (i - long_cb) + 1];
} }
// Run MAP DEC #1 // Run MAP DEC #1
map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb); map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb);
// Update a-priori LLR from the last iteration // Update a-priori LLR from the last iteration
for (i = 0; i < long_cb; i++) { for (i = 0; i < long_cb; i++) {
h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i]; h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i];
@ -296,25 +306,28 @@ void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) {
} }
int tdec_reset(tdec_t *h, uint32_t long_cb) { int tdec_reset(tdec_t * h, uint32_t long_cb)
memset(h->w, 0, sizeof(llr_t) * long_cb); {
if (long_cb > h->max_long_cb) { if (long_cb > h->max_long_cb) {
fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n",
h->max_long_cb); h->max_long_cb);
return -1; return -1;
} }
memset(h->w, 0, sizeof(llr_t) * long_cb);
return tc_interl_LTE_gen(&h->interleaver, long_cb); return tc_interl_LTE_gen(&h->interleaver, long_cb);
} }
void tdec_decision(tdec_t *h, char *output, uint32_t long_cb) { void tdec_decision(tdec_t * h, char *output, uint32_t long_cb)
{
uint32_t i; uint32_t i;
for (i = 0; i < long_cb; i++) { for (i = 0; i < long_cb; i++) {
output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0;
} }
} }
void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations, void tdec_run_all(tdec_t * h, llr_t * input, char *output,
uint32_t long_cb) { uint32_t nof_iterations, uint32_t long_cb)
{
uint32_t iter = 0; uint32_t iter = 0;
tdec_reset(h, long_cb); tdec_reset(h, long_cb);
@ -326,4 +339,3 @@ void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations
tdec_decision(h, output, long_cb); tdec_decision(h, output, long_cb);
} }

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

@ -517,6 +517,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e,
DEBUG("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i, DEBUG("CB#%d: cb_len: %d, rlen: %d, wp: %d, rp: %d, F: %d, E: %d\n", i,
cb_len, rlen - F, wp, rp, F, n_e); cb_len, rlen - F, wp, rp, F, n_e);
/* Rate Unmatching */ /* Rate Unmatching */
if (rm_turbo_rx(harq_process->pdsch_w_buff_f[i], harq_process->w_buff_size, if (rm_turbo_rx(harq_process->pdsch_w_buff_f[i], harq_process->w_buff_size,
&e_bits[rp], n_e, &e_bits[rp], n_e,
@ -532,7 +533,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e,
char *cb_in_ptr; char *cb_in_ptr;
crc_t *crc_ptr; crc_t *crc_ptr;
tdec_reset(&q->decoder, cb_len); tdec_reset(&q->decoder, cb_len);
do { do {
tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len); tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len);
@ -544,19 +545,20 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e,
crc_ptr = &q->crc_cb; crc_ptr = &q->crc_cb;
} else { } else {
len_crc = tbs+24; len_crc = tbs+24;
bzero(q->cb_in, F*sizeof(char));
cb_in_ptr = &q->cb_in[F]; cb_in_ptr = &q->cb_in[F];
crc_ptr = &q->crc_tb; crc_ptr = &q->crc_tb;
} }
tdec_decision(&q->decoder, q->cb_in, cb_len);
/* Check Codeblock CRC and stop early if incorrect */ /* Check Codeblock CRC and stop early if incorrect */
if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) { if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) {
early_stop = true; early_stop = true;
} }
} while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop); } while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop);
tdec_decision(&q->decoder, q->cb_in, cb_len);
q->average_nof_iterations = EXPAVERAGE((float) q->nof_iterations, q->average_nof_iterations = EXPAVERAGE((float) q->nof_iterations,
q->average_nof_iterations, q->average_nof_iterations,
q->average_nof_iterations_n); q->average_nof_iterations_n);
@ -588,7 +590,6 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e,
par_tx = bit_unpack(&p_parity, 24); par_tx = bit_unpack(&p_parity, 24);
if (!par_rx) { if (!par_rx) {
vec_fprint_hex(stdout, data, tbs);
printf("\n\tCAUTION!! Received all-zero transport block\n\n"); printf("\n\tCAUTION!! Received all-zero transport block\n\n");
} }
@ -672,10 +673,23 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data,
demod_soft_sigma_set(&q->demod, 2.0 / q->mod[harq_process->mcs.mod - 1].nbits_x_symbol); demod_soft_sigma_set(&q->demod, 2.0 / q->mod[harq_process->mcs.mod - 1].nbits_x_symbol);
demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]); demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]);
demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols); demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols);
/*
for (int j=0;j<nof_symbols;j++) {
if (isnan(crealf(q->pdsch_d[j])) || isnan(cimagf(q->pdsch_d[j]))) {
printf("\nerror in d[%d]=%f+%f symbols:%f+%f ce0:%f+%f ce1:%f+%f\n",j,
crealf(q->pdsch_d[j]), cimagf(q->pdsch_d[j]),
crealf(q->pdsch_symbols[0][j]), cimagf(q->pdsch_symbols[0][j]),
crealf(q->ce[0][j]), cimagf(q->ce[0][j]),
crealf(q->ce[1][j]), cimagf(q->ce[1][j])
);
}
}
*/
/* descramble */ /* descramble */
scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_e, 0, nof_bits_e); scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_e, 0, nof_bits_e);
return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx); return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx);
} else { } else {
return LIBLTE_ERROR_INVALID_INPUTS; return LIBLTE_ERROR_INVALID_INPUTS;

@ -73,7 +73,9 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) {
DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size); DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size);
ret = LIBLTE_SUCCESS; ret = LIBLTE_SUCCESS;
} } else {
fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size);
}
return ret; return ret;
} }
@ -238,9 +240,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit
peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &peak_unnormalized); peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &peak_unnormalized);
if (q->normalize_en && if (q->normalize_en &&
peak_pos + find_offset >= q->fft_size && peak_pos + find_offset >= q->fft_size)
peak_pos + find_offset + q->fft_size <= q->frame_size)
{ {
/* Compute the energy of the received PSS sequence to normalize */ /* Compute the energy of the received PSS sequence to normalize */
cf_t *pss_ptr = &input[find_offset+peak_pos-q->fft_size]; cf_t *pss_ptr = &input[find_offset+peak_pos-q->fft_size];

@ -27,6 +27,8 @@
#include "liblte/phy/ue/ue_dl.h" #include "liblte/phy/ue/ue_dl.h"
#include <complex.h>
#include <math.h>
#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) #define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1))
@ -54,6 +56,8 @@ int ue_dl_init(ue_dl_t *q,
q->pkt_errors = 0; q->pkt_errors = 0;
q->pkts_total = 0; q->pkts_total = 0;
q->nof_trials = 0; q->nof_trials = 0;
q->sfn = 0;
q->pbch_decoded = false;
if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) {
fprintf(stderr, "Error initiating FFT\n"); fprintf(stderr, "Error initiating FFT\n");
@ -67,7 +71,10 @@ int ue_dl_init(ue_dl_t *q,
fprintf(stderr, "Error initiating REGs\n"); fprintf(stderr, "Error initiating REGs\n");
goto clean_exit; goto clean_exit;
} }
if (pbch_init(&q->pbch, q->cell)) {
fprintf(stderr, "Error creating PBCH object\n");
goto clean_exit;
}
if (pcfich_init(&q->pcfich, &q->regs, q->cell)) { if (pcfich_init(&q->pcfich, &q->regs, q->cell)) {
fprintf(stderr, "Error creating PCFICH object\n"); fprintf(stderr, "Error creating PCFICH object\n");
goto clean_exit; goto clean_exit;
@ -119,6 +126,7 @@ void ue_dl_free(ue_dl_t *q) {
lte_fft_free(&q->fft); lte_fft_free(&q->fft);
chest_free(&q->chest); chest_free(&q->chest);
regs_free(&q->regs); regs_free(&q->regs);
pbch_free(&q->pbch);
pcfich_free(&q->pcfich); pcfich_free(&q->pcfich);
pdcch_free(&q->pdcch); pdcch_free(&q->pdcch);
pdsch_free(&q->pdsch); pdsch_free(&q->pdsch);
@ -136,7 +144,10 @@ void ue_dl_free(ue_dl_t *q) {
} }
} }
int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t sfn, uint16_t rnti) LIBLTE_API float mean_exec_time=0;
int frame_cnt=0;
int ue_dl_decode(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint16_t rnti)
{ {
uint32_t cfi, cfi_distance, i; uint32_t cfi, cfi_distance, i;
ra_pdsch_t ra_dl; ra_pdsch_t ra_dl;
@ -145,19 +156,49 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t
uint32_t nof_locations; uint32_t nof_locations;
uint16_t crc_rem; uint16_t crc_rem;
dci_format_t format; dci_format_t format;
pbch_mib_t mib;
int ret = LIBLTE_ERROR; int ret = LIBLTE_ERROR;
cf_t *ce_slot1[MAX_PORTS];
struct timeval t[3];
/* Run FFT for all subframe data */
lte_fft_run_sf(&q->fft, input, q->sf_symbols);
gettimeofday(&t[1], NULL);
/* Get channel estimates for each port */
chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx);
gettimeofday(&t[2], NULL);
get_time_interval(t);
mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, mean_exec_time, frame_cnt);
frame_cnt++;
for (int i=0;i<MAX_PORTS;i++) {
ce_slot1[i] = &q->ce[i][SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)];
}
/* Decode PBCH if not yet decoded to obtain the System Frame Number (SFN) */
if (sf_idx == 0) {
// FIXME: There is no need to do this every frame!
pbch_decode_reset(&q->pbch);
if (pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)], ce_slot1, &mib) == 1) {
q->sfn = mib.sfn;
q->pbch_decoded = true;
INFO("Decoded SFN: %d\n", q->sfn);
} else {
INFO("Not decoded MIB (SFN: %d)\n", q->sfn);
q->sfn++;
if (q->sfn == 1024) {
q->sfn = 0;
}
}
}
/* If we are looking for SI Blocks, search only in appropiate places */ /* If we are looking for SI Blocks, search only in appropiate places */
if ((rnti == SIRNTI && (sfn % 2) == 0 && sf_idx == 5) || if (((rnti == SIRNTI && (q->sfn % 2) == 0 && sf_idx == 5) ||
rnti != SIRNTI) rnti != SIRNTI))
{ {
/* Run FFT for all subframe data */
lte_fft_run_sf(&q->fft, input, q->sf_symbols);
/* Get channel estimates for each port */
chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx);
/* First decode PCFICH and obtain CFI */ /* First decode PCFICH and obtain CFI */
if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) { if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) {
fprintf(stderr, "Error decoding PCFICH\n"); fprintf(stderr, "Error decoding PCFICH\n");
@ -180,6 +221,7 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t
format = Format1; format = Format1;
} }
crc_rem = 0; crc_rem = 0;
for (i=0;i<nof_locations && crc_rem != rnti;i++) { for (i=0;i<nof_locations && crc_rem != rnti;i++) {
if (pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) { if (pdcch_extract_llr(&q->pdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) {
@ -192,8 +234,7 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t
} }
INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem); INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem);
} }
if (crc_rem == rnti) { if (crc_rem == rnti) {
if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) { if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) {
fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n");
@ -202,7 +243,7 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t
uint32_t rvidx; uint32_t rvidx;
if (rnti == SIRNTI) { if (rnti == SIRNTI) {
switch((sfn%8)/2) { switch((q->sfn%8)/2) {
case 0: case 0:
rvidx = 0; rvidx = 0;
break; break;
@ -251,11 +292,11 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t
} }
} }
} }
if (rnti == SIRNTI && (sfn%8) == 0) { if (rnti == SIRNTI && (q->sfn%8) == 0) {
q->nof_trials++; q->nof_trials++;
} }
} }
if (crc_rem == rnti && ret == LIBLTE_SUCCESS) { if (crc_rem == rnti && ret == LIBLTE_SUCCESS) {
return ra_dl.mcs.tbs; return ra_dl.mcs.tbs;
} else { } else {

@ -71,20 +71,27 @@ int ue_sync_init(ue_sync_t *q,
q->decode_sss_on_track = false; q->decode_sss_on_track = false;
q->stream = stream_handler; q->stream = stream_handler;
q->recv_callback = recv_callback; q->recv_callback = recv_callback;
q->cell = cell;
if(sync_init(&q->sfind, 5 * CURRENT_SFLEN, CURRENT_FFTSIZE)) { if(sync_init(&q->sfind, CURRENT_SFLEN, CURRENT_FFTSIZE)) {
fprintf(stderr, "Error initiating sync find\n");
goto clean_exit; goto clean_exit;
} }
if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) {
fprintf(stderr, "Error initiating sync track\n");
goto clean_exit; goto clean_exit;
} }
sync_set_N_id_2(&q->sfind, cell.id%3); sync_set_N_id_2(&q->sfind, cell.id%3);
sync_set_threshold(&q->sfind, FIND_THRESHOLD); sync_set_threshold(&q->sfind, FIND_THRESHOLD);
q->sfind.cp = cell.cp;
sync_cp_en(&q->sfind, false);
sync_set_N_id_2(&q->strack, cell.id%3); sync_set_N_id_2(&q->strack, cell.id%3);
sync_set_threshold(&q->strack, TRACK_THRESHOLD); sync_set_threshold(&q->strack, TRACK_THRESHOLD);
q->strack.cp = cell.cp;
sync_cp_en(&q->strack, false);
if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) { if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) {
fprintf(stderr, "Error initiating CFO\n"); fprintf(stderr, "Error initiating CFO\n");
goto clean_exit; goto clean_exit;
@ -140,18 +147,16 @@ void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) {
static int find_peak_ok(ue_sync_t *q) { static int find_peak_ok(ue_sync_t *q) {
int ret;
/* Receive the rest of the next subframe */
if (q->peak_idx < CURRENT_SFLEN) { if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+CURRENT_SFLEN/2) < 0) {
/* Receive the rest of the next subframe */ return LIBLTE_ERROR;
if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) {
return LIBLTE_ERROR;
}
} }
if (sync_sss_detected(&q->sfind)) { if (sync_sss_detected(&q->sfind)) {
/* Get the subframe index (0 or 5) */ /* Get the subframe index (0 or 5) */
q->sf_idx = sync_get_sf_idx(&q->sfind); q->sf_idx = sync_get_sf_idx(&q->sfind) + 1;
/* Reset variables */ /* Reset variables */
q->frame_ok_cnt = 0; q->frame_ok_cnt = 0;
@ -160,39 +165,35 @@ static int find_peak_ok(ue_sync_t *q) {
/* Goto Tracking state */ /* Goto Tracking state */
q->state = SF_TRACK; q->state = SF_TRACK;
ret = LIBLTE_SUCCESS;
INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n", INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n",
q->peak_idx, sync_get_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); q->peak_idx, sync_get_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp));
if (q->peak_idx < CURRENT_SFLEN) {
q->sf_idx++;
}
} else { } else {
INFO("Found peak at %d, SSS not detected\n", q->peak_idx); INFO("Found peak at %d, SSS not detected\n", q->peak_idx);
ret = 0;
} }
return ret; return 0;
} }
int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
int ret = LIBLTE_SUCCESS;
/* Make sure subframe idx is what we expect */ /* Make sure subframe idx is what we expect */
if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) { if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) {
INFO("\nWarning: Expected SF idx %d but got %d!\n", INFO("Warning: Expected SF idx %d but got %d!\n",
q->sf_idx, sync_get_sf_idx(&q->strack)); q->sf_idx, sync_get_sf_idx(&q->strack));
q->sf_idx = sync_get_sf_idx(&q->strack); q->sf_idx = sync_get_sf_idx(&q->strack);
q->state = SF_TRACK;
} else { } else {
q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE);
/* If the PSS peak is beyond the frame (we sample too slowly), /* If the PSS peak is beyond the frame (we sample too slowly),
discard the offseted samples to align next frame */ discard the offseted samples to align next frame */
if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) {
ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset) < 0) {
} else { fprintf(stderr, "Error receiving from USRP\n");
ret = LIBLTE_SUCCESS; return LIBLTE_ERROR;
} }
}
/* compute cumulative moving average CFO */ /* compute cumulative moving average CFO */
q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt); q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt);
@ -202,15 +203,10 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) {
q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; q->peak_idx = CURRENT_SFLEN/2 + q->time_offset;
q->frame_ok_cnt++; q->frame_ok_cnt++;
q->frame_no_cnt = 0; q->frame_no_cnt = 0;
if (ret >= LIBLTE_SUCCESS) {
ret = LIBLTE_SUCCESS;
}
} }
return ret; return 1;
} }
int track_peak_no(ue_sync_t *q) { int track_peak_no(ue_sync_t *q) {
@ -225,11 +221,10 @@ int track_peak_no(ue_sync_t *q) {
sync_get_peak_value(&q->strack), (int) q->frame_no_cnt); sync_get_peak_value(&q->strack), (int) q->frame_no_cnt);
} }
return LIBLTE_SUCCESS; return 1;
} }
static int receive_samples(ue_sync_t *q) { static int receive_samples(ue_sync_t *q) {
uint32_t read_len;
/* A negative time offset means there are samples in our buffer for the next subframe, /* A negative time offset means there are samples in our buffer for the next subframe,
because we are sampling too fast. because we are sampling too fast.
@ -237,18 +232,12 @@ static int receive_samples(ue_sync_t *q) {
if (q->time_offset < 0) { if (q->time_offset < 0) {
q->time_offset = -q->time_offset; q->time_offset = -q->time_offset;
} }
if (q->state == SF_FIND) {
read_len = 5 * CURRENT_SFLEN;
} else {
read_len = CURRENT_SFLEN;
}
/* copy last part of the last subframe (use move since there could be overlapping) */ /* copy last part of the last subframe (use move since there could be overlapping) */
memcpy(q->input_buffer, &q->input_buffer[read_len-q->time_offset], q->time_offset*sizeof(cf_t)); //memcpy(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t));
/* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */
if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], read_len - q->time_offset) < 0) { if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) {
return LIBLTE_ERROR; return LIBLTE_ERROR;
} }
@ -281,8 +270,6 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
return -1; return -1;
} }
DEBUG("Find PAR=%.2f\n", sync_get_last_peak_value(&q->sfind));
if (ret == 1) { if (ret == 1) {
ret = find_peak_ok(q); ret = find_peak_ok(q);
} else if (q->peak_idx != 0) { } else if (q->peak_idx != 0) {
@ -298,14 +285,12 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
} }
break; break;
case SF_TRACK: case SF_TRACK:
ret = LIBLTE_SUCCESS; ret = 1;
q->strack.sss_en = q->decode_sss_on_track; q->strack.sss_en = q->decode_sss_on_track;
q->sf_idx = (q->sf_idx + 1) % 10; q->sf_idx = (q->sf_idx + 1) % 10;
DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt);
/* Every SF idx 0 and 5, find peak around known position q->peak_idx */ /* Every SF idx 0 and 5, find peak around known position q->peak_idx */
if (q->sf_idx == 0 || q->sf_idx == 5) { if (q->sf_idx == 0 || q->sf_idx == 5) {
@ -333,31 +318,22 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) {
} else { } else {
ret = track_peak_no(q); ret = track_peak_no(q);
} }
INFO("TRACK %3d: Value=%.3f SF=%d Track_idx=%d Offset=%d CFO: %f\n",
(int) q->frame_total_cnt, sync_get_peak_value(&q->strack),
q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->strack));
q->frame_total_cnt++;
if (ret == LIBLTE_ERROR) { if (ret == LIBLTE_ERROR) {
fprintf(stderr, "Error processing tracking peak\n"); fprintf(stderr, "Error processing tracking peak\n");
q->state = SF_FIND; q->state = SF_FIND;
return LIBLTE_SUCCESS; return LIBLTE_SUCCESS;
} }
q->frame_total_cnt++;
} }
/* Do CFO Correction and deliver the frame */ /* Do CFO Correction and deliver the frame */
cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE);
*sf_symbols = q->input_buffer; *sf_symbols = q->input_buffer;
if (ret == LIBLTE_SUCCESS) {
ret = 1;
}
break; break;
} }
} }
DEBUG("UE SYNC returns %d\n", ret);
return ret; return ret;
} }

@ -49,16 +49,19 @@ plot_real_t poutfft;
int nof_frames = -1; int nof_frames = -1;
float threshold = -1.0; float threshold = -1.0;
int N_id_2 = -1;
uint32_t nof_prb = 6;
float uhd_freq = 0.0, uhd_gain = 20.0; float uhd_freq = 0.0, uhd_gain = 20.0;
char *uhd_args = ""; char *uhd_args = "";
int disable_plots = 0; int disable_plots = 0;
void usage(char *prog) { void usage(char *prog) {
printf("Usage: %s [agntdv] -f uhd_freq\n", prog); printf("Usage: %s [agntdpv] -f uhd_freq -i N_id_2\n", prog);
printf("\t-a UHD args [Default %s]\n", uhd_args); printf("\t-a UHD args [Default %s]\n", uhd_args);
printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain);
printf("\t-n nof_frames [Default infinite]\n"); printf("\t-n nof_frames [Default infinite]\n");
printf("\t-p nof_prb [Default %d]\n", nof_prb);
printf("\t-t threshold [Default %.2f]\n",threshold); printf("\t-t threshold [Default %.2f]\n",threshold);
#ifndef DISABLE_GRAPHICS #ifndef DISABLE_GRAPHICS
@ -69,8 +72,14 @@ void usage(char *prog) {
void parse_args(int argc, char **argv) { void parse_args(int argc, char **argv) {
int opt; int opt;
while ((opt = getopt(argc, argv, "agntdvf")) != -1) { while ((opt = getopt(argc, argv, "agntdvfip")) != -1) {
switch (opt) { switch (opt) {
case 'i':
N_id_2 = atoi(argv[optind]);
break;
case 'p':
nof_prb = atoi(argv[optind]);
break;
case 'n': case 'n':
nof_frames = atoi(argv[optind]); nof_frames = atoi(argv[optind]);
break; break;
@ -97,7 +106,7 @@ void parse_args(int argc, char **argv) {
exit(-1); exit(-1);
} }
} }
if (uhd_freq == 0.0) { if (uhd_freq == 0.0 || N_id_2 == -1) {
usage(argv[0]); usage(argv[0]);
exit(-1); exit(-1);
} }
@ -117,6 +126,12 @@ void input_init() {
cuhd_rx_wait_lo_locked(uhd); cuhd_rx_wait_lo_locked(uhd);
DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000); DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000);
int srate = lte_sampling_freq_hz(nof_prb);
if (srate > 0) {
cuhd_set_rx_srate(uhd, (double) srate);
} else {
fprintf(stderr, "Error invalid nof_prb=%d\n",nof_prb);
}
DEBUG("Starting receiver...\n", 0); DEBUG("Starting receiver...\n", 0);
cuhd_start_rx_stream(uhd); cuhd_start_rx_stream(uhd);
@ -152,7 +167,6 @@ int main(int argc, char **argv) {
float peak; float peak;
struct timeval t[3]; struct timeval t[3];
float mean_ce_time=0; float mean_ce_time=0;
bool signal_detected;
lte_fft_t fft; lte_fft_t fft;
lte_cell_t cell; lte_cell_t cell;
@ -169,16 +183,26 @@ int main(int argc, char **argv) {
input_init(); input_init();
cell.cp = CPNORM; cell.cp = CPNORM;
cell.id = 1; cell.id = N_id_2;
cell.nof_ports = 1; cell.nof_ports = 1;
cell.nof_prb = 6; cell.nof_prb = nof_prb;
if (ue_sync_init(&s, cell, cuhd_recv_wrapper, uhd)) { if (ue_sync_init(&s, cell, cuhd_recv_wrapper, uhd)) {
fprintf(stderr, "Error initiating UE sync module\n"); fprintf(stderr, "Error initiating UE sync module\n");
exit(-1); exit(-1);
} }
signal_detected = true; pss_synch_init_fft(&pss,
SF_LEN(lte_symbol_sz(cell.nof_prb)),
lte_symbol_sz(cell.nof_prb));
pss_synch_set_N_id_2(&pss, cell.id%3);
sf_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
if (!sf_symbols) {
perror("malloc");
exit(-1);
}
lte_fft_init(&fft, cell.cp, cell.nof_prb);
frame_cnt = 0; frame_cnt = 0;
mean_ce_time=0; mean_ce_time=0;
uint32_t valid_frames=0; uint32_t valid_frames=0;
@ -193,21 +217,6 @@ int main(int argc, char **argv) {
if (n == 1 && ue_sync_get_sfidx(&s) == 0) { if (n == 1 && ue_sync_get_sfidx(&s) == 0) {
if (signal_detected) {
pss_synch_init_fft(&pss,
SF_LEN(lte_symbol_sz(cell.nof_prb)),
lte_symbol_sz(cell.nof_prb));
pss_synch_set_N_id_2(&pss, cell.id%3);
sf_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t));
if (!sf_symbols) {
perror("malloc");
exit(-1);
}
lte_fft_init(&fft, cell.cp, cell.nof_prb);
signal_detected = false;
}
mean_ce_time = (float) (mean_ce_time + (float) t[0].tv_usec * valid_frames) / (valid_frames+1); mean_ce_time = (float) (mean_ce_time + (float) t[0].tv_usec * valid_frames) / (valid_frames+1);
valid_frames++; valid_frames++;
@ -230,12 +239,8 @@ int main(int argc, char **argv) {
#endif #endif
pos = pss_synch_find_pss(&pss, input_buffer, &peak); pos = pss_synch_find_pss(&pss, input_buffer, &peak);
/*if (pos > 962 || pos < 958) {
unaligned++;
}
*/
printf("CELL_ID: %3d CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Exec: %3.2f\r", printf("CELL_ID: %3d CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Exec: %3.2f\r",
cell.id, ue_sync_get_cfo(&s)/1000, ue_sync_get_sfo(&s)/1000, pos, sync_get_cell_id(&s.sfind), ue_sync_get_cfo(&s)/1000, ue_sync_get_sfo(&s)/1000, pos,
s.mean_exec_time); s.mean_exec_time);
fflush(stdout); fflush(stdout);
if (VERBOSE_ISINFO()) { if (VERBOSE_ISINFO()) {

Loading…
Cancel
Save