From ce2abc06fedf43d1a428c788bcbb1efb3a1da2dd Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 2 Aug 2014 23:55:12 +0200 Subject: [PATCH] Fixed some bugs in UE PDSCH example: equalization with zero channel estimates, cell search, synchronization. CRC-based early stopping --- lte/phy/examples/CMakeLists.txt | 4 +- lte/phy/examples/cell_search.c | 120 +------------------- lte/phy/examples/cell_search_utils.c | 157 ++++++++++++++++++++++++++ lte/phy/examples/cell_search_utils.h | 40 +++++++ lte/phy/examples/iodev.c | 108 ++++++++++++++++-- lte/phy/examples/iodev.h | 10 +- lte/phy/examples/pdsch_ue.c | 155 +++++++++---------------- lte/phy/include/liblte/phy/ue/ue_dl.h | 9 +- lte/phy/lib/ch_estimation/src/chest.c | 16 ++- lte/phy/lib/fec/src/turbodecoder.c | 58 ++++++---- lte/phy/lib/mimo/src/precoding.c | 8 ++ lte/phy/lib/phch/src/pdsch.c | 28 +++-- lte/phy/lib/sync/src/sync.c | 9 +- lte/phy/lib/ue/src/ue_dl.c | 71 +++++++++--- lte/phy/lib/ue/src/ue_sync.c | 90 ++++++--------- lte/phy/lib/ue/test/ue_sync_usrp.c | 61 +++++----- 16 files changed, 575 insertions(+), 369 deletions(-) create mode 100644 lte/phy/examples/cell_search_utils.c create mode 100644 lte/phy/examples/cell_search_utils.h diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index f798a23ac..a5fe5d474 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -51,7 +51,7 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) # 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) add_executable(pdsch_enodeb pdsch_enodeb.c) @@ -81,7 +81,7 @@ ENDIF(${GRAPHICS_FIND} EQUAL -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 ) MESSAGE(STATUS " UHD examples will be installed.") diff --git a/lte/phy/examples/cell_search.c b/lte/phy/examples/cell_search.c index 7d1feeaa2..5f3306bd8 100644 --- a/lte/phy/examples/cell_search.c +++ b/lte/phy/examples/cell_search.c @@ -37,6 +37,9 @@ #include "liblte/phy/phy.h" +#include "cell_search_utils.h" + + #ifndef DISABLE_UHD #include "liblte/cuhd/cuhd.h" #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 n; void *uhd; @@ -236,6 +125,7 @@ int main(int argc, char **argv) { int nof_freqs; lte_earfcn_t channels[MAX_EARFCN]; uint32_t freq; + pbch_mib_t mib; parse_args(argc, argv); @@ -296,7 +186,7 @@ int main(int argc, char **argv) { 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])) { + if (decode_pbch(uhd, buffer, &found_cells[i], nof_frames_total, &mib)) { fprintf(stderr, "Error decoding PBCH\n"); exit(-1); } diff --git a/lte/phy/examples/cell_search_utils.c b/lte/phy/examples/cell_search_utils.c new file mode 100644 index 000000000..a5bb30adc --- /dev/null +++ b/lte/phy/examples/cell_search_utils.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#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 diff --git a/lte/phy/examples/cell_search_utils.h b/lte/phy/examples/cell_search_utils.h new file mode 100644 index 000000000..2fefed105 --- /dev/null +++ b/lte/phy/examples/cell_search_utils.h @@ -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]); \ No newline at end of file diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c index 76b94997f..ce55b3a3a 100644 --- a/lte/phy/examples/iodev.c +++ b/lte/phy/examples/iodev.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "iodev.h" @@ -41,6 +42,8 @@ #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); @@ -48,20 +51,36 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { } /* 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) { + + 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->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) { perror("malloc"); return LIBLTE_ERROR; } - - q->mode = FILESOURCE; - q->sf_len = file_sf_len; + q->sf_idx = 9; } else { #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; } - /* set uhd_freq */ 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); - lte_cell_t cell; - ue_sync_init(&q->sframe, cell, cuhd_recv_wrapper, 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; @@ -114,7 +191,7 @@ void iodev_free(iodev_t *q) { int iodev_receive(iodev_t *q, cf_t **buffer) { int n; 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); *buffer = q->input_buffer_file; if (n == -1) { @@ -133,6 +210,11 @@ int iodev_receive(iodev_t *q, cf_t **buffer) { } 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 @@ -161,4 +243,12 @@ 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); + } +} + diff --git a/lte/phy/examples/iodev.h b/lte/phy/examples/iodev.h index 81f7a67ef..bc020222f 100644 --- a/lte/phy/examples/iodev.h +++ b/lte/phy/examples/iodev.h @@ -54,6 +54,10 @@ 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; @@ -66,6 +70,7 @@ typedef struct LIBLTE_API { 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; @@ -75,7 +80,8 @@ typedef struct LIBLTE_API { LIBLTE_API int iodev_init(iodev_t *q, 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); @@ -84,6 +90,8 @@ LIBLTE_API int iodev_receive(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_isUSRP(iodev_t *q); diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index b67a9b1de..09ff59c3f 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -53,8 +53,6 @@ void init_plots(); * Program arguments processing ***********************************************************************/ typedef struct { - uint32_t cell_id_file; - uint32_t nof_prb_file; uint16_t rnti; int nof_subframes; bool disable_plots; @@ -62,8 +60,9 @@ typedef struct { }prog_args_t; void args_default(prog_args_t *args) { - args->cell_id_file = 1; - args->nof_prb_file = 6; + 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; @@ -71,13 +70,14 @@ void args_default(prog_args_t *args) { args->io_config.input_file_name = NULL; args->io_config.uhd_args = ""; 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) { 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-p nof_prb if reading from file [Default %d]\n", args->nof_prb_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->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); @@ -99,16 +99,19 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "icagfndvtbpr")) != -1) { + while ((opt = getopt(argc, argv, "icagfndvtbpro")) != -1) { switch (opt) { case 'i': args->io_config.input_file_name = argv[optind]; break; case 'c': - args->cell_id_file = atoi(argv[optind]); + args->io_config.cell_id_file = atoi(argv[optind]); break; 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; case 'a': args->io_config.uhd_args = argv[optind]; @@ -152,6 +155,8 @@ void sigintHandler(int x) { /* 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; @@ -159,27 +164,13 @@ int main(int argc, char **argv) { prog_args_t prog_args; lte_cell_t cell; ue_dl_t ue_dl; - bool ue_dl_initiated = false; int64_t sf_cnt; - uint32_t sf_idx; pbch_mib_t mib; bool printed_sib = false; int rlen; - int symbol_sz; 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 if (!prog_args.disable_plots) { init_plots(); @@ -190,16 +181,22 @@ int main(int argc, char **argv) { printf("\n --- Press Ctrl+C to exit --- \n"); signal(SIGINT, sigintHandler); - /* Initialize frame and subframe counters */ + /* Initialize subframe counter */ 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 */ - ue_sync_decode_sss_on_track(&iodev.sframe, true); + 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); @@ -207,81 +204,41 @@ int main(int argc, char **argv) { } /* iodev_receive returns 1 if successfully read 1 aligned subframe */ - if (ret == 0) { - printf("Finding PSS... Peak: %8.1f, Output level: %+.2f dB FrameCnt: %d, State: %d\r", - sync_get_peak_value(&iodev.sframe.sfind), - iodev.sframe.frame_total_cnt, iodev.sframe.state); - } else if (ret == 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 (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 (iodev_isfile(&iodev)) { - sf_idx++; - if (sf_idx == NSUBFRAMES_X_FRAME) { - sf_idx = 0; - } + 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 (prog_args.nof_subframes > 0) { - sf_cnt++; - } - if (iodev_isfile(&iodev)) { - usleep(5000); + // Plot and Printf + if (!(sf_cnt % 10)) { + printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %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, (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); printf("\nBye\n"); diff --git a/lte/phy/include/liblte/phy/ue/ue_dl.h b/lte/phy/include/liblte/phy/ue/ue_dl.h index 22ecd718d..e38d0ebf0 100644 --- a/lte/phy/include/liblte/phy/ue/ue_dl.h +++ b/lte/phy/include/liblte/phy/ue/ue_dl.h @@ -57,6 +57,7 @@ #define NOF_HARQ_PROCESSES 8 typedef struct LIBLTE_API { + pbch_t pbch; pcfich_t pcfich; pdcch_t pdcch; pdsch_t pdsch; @@ -74,6 +75,9 @@ typedef struct LIBLTE_API { uint64_t pkts_total; uint64_t nof_trials; + uint32_t sfn; + bool pbch_decoded; + uint16_t user_rnti; }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 int ue_dl_receive(ue_dl_t *q, +LIBLTE_API int ue_dl_decode(ue_dl_t *q, cf_t *sf_buffer, char *data, - uint32_t sf_idx, - uint32_t sfn, + uint32_t sf_idx, uint16_t rnti); #endif \ No newline at end of file diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 7436b0ad9..293d3fe2b 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -38,7 +38,7 @@ #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #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) { 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]; 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, 10*log10f(cabsf(channel_ref/known_ref)), cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI, cargf(channel_ref/known_ref)/M_PI); - + + /* FIXME: compare with threshold */ if (channel_ref != 0) { q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; } else { - q->refsignal[port_id][nslot].ch_est[nref] = 0; + q->refsignal[port_id][nslot].ch_est[nref] = 1e-6; } 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;jsymbols_ref[0] * q->nof_re + i]; } - } + } for (j=0;jnof_symbols;j++) { ce[j * q->nof_re + i] = y[j]; } @@ -321,8 +323,10 @@ void chest_free(chest_t *q) { } } #ifdef VOLK_INTERP - interp_free(&q->interp_freq); - interp_free(&q->interp_time); + for (p=0;pinterp_freq[p]); + interp_free(&q->interp_time[p]); + } #endif bzero(q, sizeof(chest_t)); } diff --git a/lte/phy/lib/fec/src/turbodecoder.c b/lte/phy/lib/fec/src/turbodecoder.c index 250b078fd..171eefde3 100644 --- a/lte/phy/lib/fec/src/turbodecoder.c +++ b/lte/phy/lib/fec/src/turbodecoder.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "liblte/phy/fec/turbodecoder.h" @@ -39,7 +40,9 @@ * 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 x, y, xy; 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, - uint32_t long_cb) { +void map_gen_alpha(map_gen_t * s, llr_t * input, llr_t * parity, llr_t * output, + 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; @@ -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)); h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1) * NUMSTATES); if (!h->beta) { @@ -161,15 +166,17 @@ 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); } bzero(h, sizeof(map_gen_t)); } -void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, - uint32_t long_cb) { +void map_gen_dec(map_gen_t * h, llr_t * input, llr_t * parity, llr_t * output, + uint32_t long_cb) +{ uint32_t k; 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 * ************************************************/ -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; bzero(h, sizeof(tdec_t)); uint32_t len = max_long_cb + TOTALTAIL; @@ -227,13 +235,14 @@ int tdec_init(tdec_t *h, uint32_t max_long_cb) { } ret = 0; - clean_and_exit: if (ret == -1) { +clean_and_exit:if (ret == -1) { tdec_free(h); } return ret; } -void tdec_free(tdec_t *h) { +void tdec_free(tdec_t * h) +{ if (h->llr1) { free(h->llr1); } @@ -257,7 +266,8 @@ void tdec_free(tdec_t *h) { 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; // 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 for (i = 0; i < long_cb; 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]; } for (i = long_cb; i < long_cb + RATE; 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 - + NINPUTS * (i - long_cb) + 1]; + + NINPUTS * (i - long_cb) + 1]; } // Run MAP DEC #1 map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb); - + // Update a-priori LLR from the last iteration for (i = 0; i < long_cb; i++) { h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i]; @@ -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) { - 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); + 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, uint32_t long_cb) { +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; + 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, - uint32_t long_cb) { +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); @@ -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); } - diff --git a/lte/phy/lib/mimo/src/precoding.c b/lte/phy/lib/mimo/src/precoding.c index 036de038d..6c21ff21e 100644 --- a/lte/phy/lib/mimo/src/precoding.c +++ b/lte/phy/lib/mimo/src/precoding.c @@ -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;ipdsch_w_buff_f[i], harq_process->w_buff_size, &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; crc_t *crc_ptr; tdec_reset(&q->decoder, cb_len); - + do { 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; } else { len_crc = tbs+24; + bzero(q->cb_in, F*sizeof(char)); cb_in_ptr = &q->cb_in[F]; crc_ptr = &q->crc_tb; } - + + tdec_decision(&q->decoder, q->cb_in, cb_len); + /* Check Codeblock CRC and stop early if incorrect */ if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) { early_stop = true; } } 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, 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); if (!par_rx) { - vec_fprint_hex(stdout, data, tbs); 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_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]); demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols); + + /* + for (int j=0;jpdsch_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 */ 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); } else { return LIBLTE_ERROR_INVALID_INPUTS; diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 9d06a8616..34e4bd28e 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -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); ret = LIBLTE_SUCCESS; - } + } else { + fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); + } 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); - if (q->normalize_en && - peak_pos + find_offset >= q->fft_size && - peak_pos + find_offset + q->fft_size <= q->frame_size) + if (q->normalize_en && + peak_pos + find_offset >= q->fft_size) { /* Compute the energy of the received PSS sequence to normalize */ cf_t *pss_ptr = &input[find_offset+peak_pos-q->fft_size]; diff --git a/lte/phy/lib/ue/src/ue_dl.c b/lte/phy/lib/ue/src/ue_dl.c index 9bb914c58..203011776 100644 --- a/lte/phy/lib/ue/src/ue_dl.c +++ b/lte/phy/lib/ue/src/ue_dl.c @@ -27,6 +27,8 @@ #include "liblte/phy/ue/ue_dl.h" +#include +#include #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->pkts_total = 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)) { fprintf(stderr, "Error initiating FFT\n"); @@ -67,7 +71,10 @@ int ue_dl_init(ue_dl_t *q, fprintf(stderr, "Error initiating REGs\n"); 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)) { fprintf(stderr, "Error creating PCFICH object\n"); goto clean_exit; @@ -119,6 +126,7 @@ void ue_dl_free(ue_dl_t *q) { lte_fft_free(&q->fft); chest_free(&q->chest); regs_free(&q->regs); + pbch_free(&q->pbch); pcfich_free(&q->pcfich); pdcch_free(&q->pdcch); 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; 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; uint16_t crc_rem; dci_format_t format; + pbch_mib_t mib; 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;ice[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 ((rnti == SIRNTI && (sfn % 2) == 0 && sf_idx == 5) || - rnti != SIRNTI) + if (((rnti == SIRNTI && (q->sfn % 2) == 0 && sf_idx == 5) || + 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 */ if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) { 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; } + crc_rem = 0; for (i=0;ipdcch, 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); } - - + if (crc_rem == rnti) { 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"); @@ -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; if (rnti == SIRNTI) { - switch((sfn%8)/2) { + switch((q->sfn%8)/2) { case 0: rvidx = 0; 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++; } } - + if (crc_rem == rnti && ret == LIBLTE_SUCCESS) { return ra_dl.mcs.tbs; } else { diff --git a/lte/phy/lib/ue/src/ue_sync.c b/lte/phy/lib/ue/src/ue_sync.c index 600bc1ee7..714a6212f 100644 --- a/lte/phy/lib/ue/src/ue_sync.c +++ b/lte/phy/lib/ue/src/ue_sync.c @@ -71,20 +71,27 @@ int ue_sync_init(ue_sync_t *q, q->decode_sss_on_track = false; q->stream = stream_handler; 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; } if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + fprintf(stderr, "Error initiating sync track\n"); goto clean_exit; } sync_set_N_id_2(&q->sfind, cell.id%3); 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_threshold(&q->strack, TRACK_THRESHOLD); - + q->strack.cp = cell.cp; + sync_cp_en(&q->strack, false); + if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) { fprintf(stderr, "Error initiating CFO\n"); 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) { - int ret; - - if (q->peak_idx < CURRENT_SFLEN) { - /* Receive the rest of the next subframe */ - if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) { - return LIBLTE_ERROR; - } + + /* Receive the rest of the next subframe */ + if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+CURRENT_SFLEN/2) < 0) { + return LIBLTE_ERROR; } if (sync_sss_detected(&q->sfind)) { + /* 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 */ q->frame_ok_cnt = 0; @@ -160,39 +165,35 @@ static int find_peak_ok(ue_sync_t *q) { /* Goto Tracking state */ q->state = SF_TRACK; - ret = LIBLTE_SUCCESS; - + 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)); - if (q->peak_idx < CURRENT_SFLEN) { - q->sf_idx++; - } } else { 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 ret = LIBLTE_SUCCESS; /* Make sure subframe idx is what we expect */ 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->state = SF_TRACK; } else { q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); - + /* If the PSS peak is beyond the frame (we sample too slowly), discard the offseted samples to align next frame */ if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { - ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); - } else { - ret = LIBLTE_SUCCESS; - } + if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset) < 0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + } /* compute cumulative moving average CFO */ 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->frame_ok_cnt++; - q->frame_no_cnt = 0; - - - if (ret >= LIBLTE_SUCCESS) { - ret = LIBLTE_SUCCESS; - } + q->frame_no_cnt = 0; } - return ret; + return 1; } 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); } - return LIBLTE_SUCCESS; + return 1; } 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, because we are sampling too fast. @@ -237,18 +232,12 @@ static int receive_samples(ue_sync_t *q) { if (q->time_offset < 0) { 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) */ - 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 */ - 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; } @@ -281,8 +270,6 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { return -1; } - DEBUG("Find PAR=%.2f\n", sync_get_last_peak_value(&q->sfind)); - if (ret == 1) { ret = find_peak_ok(q); } else if (q->peak_idx != 0) { @@ -298,14 +285,12 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { } break; case SF_TRACK: - ret = LIBLTE_SUCCESS; + ret = 1; q->strack.sss_en = q->decode_sss_on_track; 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 */ 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 { 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) { fprintf(stderr, "Error processing tracking peak\n"); q->state = SF_FIND; return LIBLTE_SUCCESS; } + + q->frame_total_cnt++; } /* Do CFO Correction and deliver the frame */ cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); *sf_symbols = q->input_buffer; - if (ret == LIBLTE_SUCCESS) { - ret = 1; - } break; } } - DEBUG("UE SYNC returns %d\n", ret); return ret; } diff --git a/lte/phy/lib/ue/test/ue_sync_usrp.c b/lte/phy/lib/ue/test/ue_sync_usrp.c index caa667907..62bb1d7c5 100644 --- a/lte/phy/lib/ue/test/ue_sync_usrp.c +++ b/lte/phy/lib/ue/test/ue_sync_usrp.c @@ -49,16 +49,19 @@ plot_real_t poutfft; int nof_frames = -1; float threshold = -1.0; +int N_id_2 = -1; +uint32_t nof_prb = 6; float uhd_freq = 0.0, uhd_gain = 20.0; char *uhd_args = ""; int disable_plots = 0; 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-g UHD RX gain [Default %.2f dB]\n", uhd_gain); 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); #ifndef DISABLE_GRAPHICS @@ -69,8 +72,14 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agntdvf")) != -1) { + while ((opt = getopt(argc, argv, "agntdvfip")) != -1) { switch (opt) { + case 'i': + N_id_2 = atoi(argv[optind]); + break; + case 'p': + nof_prb = atoi(argv[optind]); + break; case 'n': nof_frames = atoi(argv[optind]); break; @@ -97,7 +106,7 @@ void parse_args(int argc, char **argv) { exit(-1); } } - if (uhd_freq == 0.0) { + if (uhd_freq == 0.0 || N_id_2 == -1) { usage(argv[0]); exit(-1); } @@ -117,6 +126,12 @@ void input_init() { cuhd_rx_wait_lo_locked(uhd); 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); cuhd_start_rx_stream(uhd); @@ -152,7 +167,6 @@ int main(int argc, char **argv) { float peak; struct timeval t[3]; float mean_ce_time=0; - bool signal_detected; lte_fft_t fft; lte_cell_t cell; @@ -169,16 +183,26 @@ int main(int argc, char **argv) { input_init(); cell.cp = CPNORM; - cell.id = 1; + cell.id = N_id_2; cell.nof_ports = 1; - cell.nof_prb = 6; + cell.nof_prb = nof_prb; if (ue_sync_init(&s, cell, cuhd_recv_wrapper, uhd)) { fprintf(stderr, "Error initiating UE sync module\n"); 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; mean_ce_time=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 (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); valid_frames++; @@ -230,12 +239,8 @@ int main(int argc, char **argv) { #endif 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", - 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); fflush(stdout); if (VERBOSE_ISINFO()) {