From 243f23752dd4b3cf1c957cb85366e17468c6bca3 Mon Sep 17 00:00:00 2001 From: ismagom Date: Thu, 11 Dec 2014 23:04:21 +0000 Subject: [PATCH] Improved cell search algorithm. Using narrow correlation for cell acquisition and MIB decoding --- lte/examples/CMakeLists.txt | 6 +- lte/examples/cell_measurement.c | 35 ++- lte/examples/cell_search.c | 53 +++- lte/examples/cell_search_utils.c | 284 ------------------ lte/examples/cuhd_utils.c | 171 +++++++++++ .../{cell_search_utils.h => cuhd_utils.h} | 39 ++- lte/examples/pdsch_ue.c | 33 +- .../include/liblte/phy/common/phy_common.h | 2 + lte/phy/include/liblte/phy/phy.h | 2 +- .../include/liblte/phy/ue/ue_cell_search.h | 118 ++++++++ lte/phy/include/liblte/phy/ue/ue_celldetect.h | 132 -------- lte/phy/include/liblte/phy/ue/ue_mib.h | 57 ++-- lte/phy/include/liblte/phy/ue/ue_sync.h | 17 +- lte/phy/lib/mimo/src/precoding.c | 7 +- lte/phy/lib/phch/src/pbch.c | 4 - lte/phy/lib/phch/src/pdcch.c | 5 +- lte/phy/lib/phch/src/pdsch.c | 4 +- lte/phy/lib/sync/src/pss.c | 18 +- lte/phy/lib/sync/src/sss.c | 14 +- lte/phy/lib/sync/src/sync.c | 41 +-- lte/phy/lib/sync/test/pss_usrp.c | 3 + lte/phy/lib/sync/test/sync_test.c | 3 +- lte/phy/lib/ue/src/ue_cell_search.c | 275 +++++++++++++++++ lte/phy/lib/ue/src/ue_celldetect.c | 260 ---------------- lte/phy/lib/ue/src/ue_mib.c | 196 +++++------- lte/phy/lib/ue/src/ue_sync.c | 186 +++++++----- 26 files changed, 957 insertions(+), 1008 deletions(-) delete mode 100644 lte/examples/cell_search_utils.c create mode 100644 lte/examples/cuhd_utils.c rename lte/examples/{cell_search_utils.h => cuhd_utils.h} (59%) create mode 100644 lte/phy/include/liblte/phy/ue/ue_cell_search.h delete mode 100644 lte/phy/include/liblte/phy/ue/ue_celldetect.h create mode 100644 lte/phy/lib/ue/src/ue_cell_search.c delete mode 100644 lte/phy/lib/ue/src/ue_celldetect.c diff --git a/lte/examples/CMakeLists.txt b/lte/examples/CMakeLists.txt index 2f7374c2e..402f3b0f1 100644 --- a/lte/examples/CMakeLists.txt +++ b/lte/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 cell_search_utils.c) +add_executable(pdsch_ue pdsch_ue.c cuhd_utils.c) target_link_libraries(pdsch_ue lte_rrc lte_phy) add_executable(pdsch_enodeb pdsch_enodeb.c) @@ -81,10 +81,10 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1) IF(${CUHD_FIND} GREATER -1) - add_executable(cell_search cell_search.c cell_search_utils.c) + add_executable(cell_search cell_search.c cuhd_utils.c) target_link_libraries(cell_search lte_rrc lte_phy cuhd ) - add_executable(cell_measurement cell_measurement.c cell_search_utils.c) + add_executable(cell_measurement cell_measurement.c cuhd_utils.c) target_link_libraries(cell_measurement cuhd lte_rrc lte_phy) MESSAGE(STATUS " UHD examples will be installed.") diff --git a/lte/examples/cell_measurement.c b/lte/examples/cell_measurement.c index 40f905375..8c5a429f6 100644 --- a/lte/examples/cell_measurement.c +++ b/lte/examples/cell_measurement.c @@ -39,16 +39,16 @@ #include "liblte/rrc/rrc.h" #include "liblte/phy/phy.h" #include "liblte/cuhd/cuhd.h" -#include "cell_search_utils.h" +#include "cuhd_utils.h" #define B210_DEFAULT_GAIN 40.0 #define B210_DEFAULT_GAIN_CORREC 80.0 // Gain of the Rx chain when the gain is set to 40 float gain_offset = B210_DEFAULT_GAIN_CORREC; -cell_detect_cfg_t cell_detect_config = { - 100, // nof_frames_total - 6.0 // early-stops cell detection if mean PSR is above this value +cell_search_cfg_t cell_detect_config = { + 50, // nof_frames_total + 9.0 // early-stops cell detection if mean PSR is above this value }; /********************************************************************** @@ -170,15 +170,24 @@ int main(int argc, char **argv) { cuhd_rx_wait_lo_locked(uhd); printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000); - - - - - if (detect_and_decode_cell(&cell_detect_config, uhd, prog_args.force_N_id_2, &cell)) { - fprintf(stderr, "Cell not found\n"); + ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell); + if (ret < 0) { + fprintf(stderr, "Error searching cell\n"); exit(-1); + } else if (ret == 0) { + printf("Cell not found\n"); + exit(0); } + /* set sampling frequency */ + int srate = lte_sampling_freq_hz(cell.nof_prb); + if (srate != -1) { + cuhd_set_rx_srate(uhd, (double) srate); + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb); + return LIBLTE_ERROR; + } + INFO("Stopping UHD and flushing buffer...\n",0); cuhd_stop_rx_stream(uhd); cuhd_flush_buffer(uhd); @@ -191,7 +200,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating UE downlink processing module\n"); exit(-1); } - if (ue_mib_init(&ue_mib, cell, false)) { + if (ue_mib_init(&ue_mib, cell)) { fprintf(stderr, "Error initaiting UE MIB decoder\n"); exit(-1); } @@ -240,9 +249,7 @@ int main(int argc, char **argv) { case DECODE_MIB: if (ue_sync_get_sfidx(&ue_sync) == 0) { pbch_decode_reset(&ue_mib.pbch); - n = ue_mib_decode_aligned_frame(&ue_mib, - sf_buffer, bch_payload_unpacked, - NULL, &sfn_offset); + n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); exit(-1); diff --git a/lte/examples/cell_search.c b/lte/examples/cell_search.c index d8b0f759d..20e0df925 100644 --- a/lte/examples/cell_search.c +++ b/lte/examples/cell_search.c @@ -37,7 +37,7 @@ #include "liblte/phy/phy.h" -#include "cell_search_utils.h" +#include "cuhd_utils.h" #ifndef DISABLE_UHD @@ -55,7 +55,7 @@ int band = -1; int earfcn_start=-1, earfcn_end = -1; -cell_detect_cfg_t config = {50, 1.1}; +cell_search_cfg_t config = {50, 1.1}; float uhd_gain = 60.0; @@ -111,15 +111,19 @@ void parse_args(int argc, char **argv) { } } +int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { + DEBUG(" ---- Receive %d samples ---- \n", nsamples); + return cuhd_recv(h, data, nsamples, 1); +} + int main(int argc, char **argv) { int n; void *uhd; - ue_celldetect_result_t found_cells[3]; + ue_cell_search_t cs; + ue_cell_search_result_t found_cells[3]; int nof_freqs; lte_earfcn_t channels[MAX_EARFCN]; uint32_t freq; - uint8_t bch_payload[BCH_PAYLOAD_LEN]; - uint32_t nof_tx_ports; parse_args(argc, argv); @@ -150,21 +154,44 @@ int main(int argc, char **argv) { if (VERBOSE_ISINFO()) { printf("\n"); } + + bzero(found_cells, 3*sizeof(ue_cell_search_result_t)); + + if (ue_cell_search_init(&cs, cuhd_recv_wrapper, uhd)) { + fprintf(stderr, "Error initiating UE cell detect\n"); + exit(-1); + } + + if (config.nof_frames_total) { + ue_cell_search_set_nof_frames_to_scan(&cs, config.nof_frames_total); + } + if (config.threshold) { + ue_cell_search_set_threshold(&cs, config.threshold); + } + + INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000); + cuhd_set_rx_srate(uhd, CS_SAMP_FREQ); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); - n = detect_all_cells(&config, uhd, found_cells); + n = ue_cell_search_scan(&cs, found_cells, NULL); if (n < 0) { fprintf(stderr, "Error searching cell\n"); exit(-1); - } - if (n == CS_CELL_DETECTED) { + } else if (n == 1) { for (int i=0;i<3;i++) { if (found_cells[i].peak > config.threshold/2) { - if (decode_pbch(uhd, &found_cells[i], config.nof_frames_total, bch_payload, &nof_tx_ports, NULL)) { - fprintf(stderr, "Error decoding PBCH\n"); + lte_cell_t cell; + cell.id = found_cells[i].cell_id; + cell.cp = found_cells[i].cp; + int ret = cuhd_mib_decoder(uhd, 100, &cell); + if (ret < 0) { + fprintf(stderr, "Error decoding MIB\n"); exit(-1); - } else { - printf("Cell found with %d ports. Decoded MIB: \n", nof_tx_ports); - vec_fprint_hex(stdout, bch_payload, BCH_PAYLOAD_LEN); + } + if (ret == MIB_FOUND) { + printf("Found CELL ID %d. %d PRB, %d ports\n", + cell.id, cell.nof_prb, cell.nof_ports); } } } diff --git a/lte/examples/cell_search_utils.c b/lte/examples/cell_search_utils.c deleted file mode 100644 index e2aa5164c..000000000 --- a/lte/examples/cell_search_utils.c +++ /dev/null @@ -1,284 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * A copy of the GNU Lesser General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "liblte/phy/phy.h" -#include "liblte/rrc/rrc.h" -#include "cell_search_utils.h" - - -#ifndef DISABLE_UHD -#include "liblte/cuhd/cuhd.h" - -int decode_pbch(void *uhd, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, - uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset) -{ - ue_mib_t uemib; - int n; - int ret = LIBLTE_ERROR; - - uint32_t nof_frames = 0; - uint32_t flen = MIB_FRAME_SIZE_SEARCH; - - cf_t *buffer = vec_malloc(sizeof(cf_t) * flen); - if (!buffer) { - perror("malloc"); - goto free_and_exit; - } - - if (ue_mib_init_1_92(&uemib, found_cell->cell_id, found_cell->cp)) { - fprintf(stderr, "Error initiating PBCH decoder\n"); - goto free_and_exit; - } - - 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"); - goto free_and_exit; - } - - DEBUG("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total); - - n = ue_mib_sync_and_decode_1_92(&uemib, buffer, flen); - if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) { - fprintf(stderr, "Error calling ue_mib_decode()\n"); - goto free_and_exit; - } - if (n == MIB_FRAME_UNALIGNED) { - INFO("Realigning frame\n",0); - // Receive some randon number of samples to try to resynchronise the frame. - if (cuhd_recv(uhd, buffer, 1500, 1)<0) { - fprintf(stderr, "Error receiving from USRP\n"); - goto free_and_exit; - } - bzero(buffer, flen * sizeof(cf_t)); - } - 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); - ue_mib_get_payload(&uemib, bch_payload, nof_tx_ports, sfn_offset); - ret = LIBLTE_SUCCESS; - } else { - ret = LIBLTE_ERROR; - } - -free_and_exit: - free(buffer); - - cuhd_stop_rx_stream(uhd); - cuhd_flush_buffer(uhd); - - ue_mib_free(&uemib); - - return ret; -} - -int detect_cell(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t *found_cell, uint32_t N_id_2) -{ - int ret = LIBLTE_ERROR; - ue_celldetect_t cd; - - cf_t *buffer = vec_malloc(sizeof(cf_t) * CS_FLEN); - if (!buffer) { - perror("malloc"); - goto free_and_exit; - } - - if (ue_celldetect_init(&cd)) { - fprintf(stderr, "Error initiating UE cell detect\n"); - goto free_and_exit; - } - - if (config->nof_frames_total) { - ue_celldetect_set_nof_frames_total(&cd, config->nof_frames_total); - } - if (config->threshold) { - ue_celldetect_set_threshold(&cd, config->threshold); - } - - INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000); - cuhd_set_rx_srate(uhd, CS_SAMP_FREQ); - INFO("Starting receiver...\n", 0); - cuhd_start_rx_stream(uhd); - - uint32_t flen = CS_FLEN; - int n; - - bzero(found_cell, sizeof(ue_celldetect_result_t)); - - ue_celldetect_set_N_id_2(&cd, N_id_2); - - do { - if (cuhd_recv(uhd, buffer, flen, 1)<0) { - fprintf(stderr, "Error receiving from USRP\n"); - goto free_and_exit; - } - - DEBUG("Scanning cell at N_id_2=%d\n",N_id_2); - - n = ue_celldetect_scan(&cd, buffer, flen); - switch(n) { - case CS_FRAME_UNALIGNED: - INFO("Realigning frame\n",0); - if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { - fprintf(stderr, "Error receiving from USRP\n"); - goto free_and_exit; - } - break; - case CS_CELL_DETECTED: - ue_celldetect_get_cell(&cd, found_cell); - if (found_cell->peak > 0) { - printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %.0f%%\n", - found_cell->cell_id, - lte_cp_string(found_cell->cp), - found_cell->peak, found_cell->mode*100); - } - - ret = 1; - INFO("Cell found at N_id_2=%d\n",N_id_2); - break; - case CS_CELL_NOT_DETECTED: - ret = 0; - printf("No cell found at N_id_2=%d. Mean PSR: %.2f\n",N_id_2, sync_get_peak_value(&cd.sfind)); - break; - case LIBLTE_ERROR: - case LIBLTE_ERROR_INVALID_INPUTS: - ret = LIBLTE_ERROR; - fprintf(stderr, "Error calling cellsearch_scan()\n"); - goto free_and_exit; - } - - } while(n == 0 || n == CS_FRAME_UNALIGNED); - -free_and_exit: - free(buffer); - ue_celldetect_free(&cd); - INFO("Stopping receiver...\n", 0); - cuhd_stop_rx_stream(uhd); - cuhd_flush_buffer(uhd); - - return ret; -} - - -int detect_all_cells(cell_detect_cfg_t *config, void *uhd, ue_celldetect_result_t found_cell[3]) -{ - - uint32_t N_id_2; - int ret; - int nof_detected_cells = 0; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - ret = detect_cell(config, uhd, &found_cell[N_id_2], N_id_2); - if (ret == 1) { - nof_detected_cells++; - } else if (ret == LIBLTE_ERROR) { - return LIBLTE_ERROR; - } - } - return nof_detected_cells; -} - -int detect_and_decode_cell(cell_detect_cfg_t *config, void *uhd, int force_N_id_2, lte_cell_t *cell) -{ - int ret; - uint32_t nof_tx_ports; - uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN]; - - ue_celldetect_result_t found_cells[3]; - bzero(found_cells, 3*sizeof(ue_celldetect_result_t)); - - if (force_N_id_2 >= 0) { - ret = detect_cell(config, uhd, &found_cells[force_N_id_2], force_N_id_2); - } else { - ret = detect_all_cells(config, uhd, found_cells); - } - if (ret < 0) { - fprintf(stderr, "Error searching cell\n"); - exit(-1); - } - - int max_peak_cell = 0; - float max_peak_value = -1.0; - if (ret > 0) { - if (force_N_id_2 >= 0) { - max_peak_cell = force_N_id_2; - } else { - 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; - } - } - } - - printf("Decoding PBCH for cell %d (N_id_2=%d)\n", found_cells[max_peak_cell].cell_id, max_peak_cell); - if (decode_pbch(uhd, &found_cells[max_peak_cell], 400, bch_payload, &nof_tx_ports, NULL)) { - 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; - } - - cell->cp = found_cells[max_peak_cell].cp; - cell->id = found_cells[max_peak_cell].cell_id; - cell->nof_ports = nof_tx_ports; - - bit_unpack_vector(bch_payload, bch_payload_unpacked, BCH_PAYLOAD_LEN); - bcch_bch_unpack(bch_payload_unpacked, BCH_PAYLOAD_LEN, cell, NULL); - - /* set sampling frequency */ - int srate = lte_sampling_freq_hz(cell->nof_prb); - if (srate != -1) { - cuhd_set_rx_srate(uhd, (double) srate); - } else { - fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb); - return LIBLTE_ERROR; - } - return LIBLTE_SUCCESS; -} - - -#endif diff --git a/lte/examples/cuhd_utils.c b/lte/examples/cuhd_utils.c new file mode 100644 index 000000000..1ccf5e0c4 --- /dev/null +++ b/lte/examples/cuhd_utils.c @@ -0,0 +1,171 @@ +/** + * + * \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" +#include "liblte/rrc/rrc.h" +#include "cuhd_utils.h" + + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" + +int cuhd_recv_wrapper_cs(void *h, void *data, uint32_t nsamples) { + DEBUG(" ---- Receive %d samples ---- \n", nsamples); + return cuhd_recv(h, data, nsamples, 1); +} + +/** This function is simply a wrapper to the ue_cell_search module for cuhd devices + * Return 1 if the MIB is decoded, 0 if not or -1 on error. + */ +int cuhd_mib_decoder(void *uhd, uint32_t max_nof_frames, lte_cell_t *cell) { + int ret = LIBLTE_ERROR; + ue_mib_sync_t ue_mib; + uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN]; + + if (ue_mib_sync_init(&ue_mib, cell->id, cell->cp, cuhd_recv_wrapper_cs, uhd)) { + fprintf(stderr, "Error initiating ue_mib_sync\n"); + goto clean_exit; + } + + int srate = lte_sampling_freq_hz(MIB_NOF_PRB); + INFO("Setting sampling frequency %.2f MHz for PSS search\n", (float) srate/1000000); + cuhd_set_rx_srate(uhd, (float) srate); + + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + /* Find and decody MIB */ + ret = ue_mib_sync_decode(&ue_mib, max_nof_frames, bch_payload, &cell->nof_ports, NULL); + if (ret < 0) { + fprintf(stderr, "Error decoding MIB\n"); + goto clean_exit; + } + if (ret == 1) { + bit_unpack_vector(bch_payload, bch_payload_unpacked, BCH_PAYLOAD_LEN); + bcch_bch_unpack(bch_payload_unpacked, BCH_PAYLOAD_LEN, cell, NULL); + } + +clean_exit: + + cuhd_stop_rx_stream(uhd); + ue_mib_sync_free(&ue_mib); + + return ret; +} + +/** This function is simply a wrapper to the ue_cell_search module for cuhd devices + */ +int cuhd_cell_search(void *uhd, cell_search_cfg_t *config, + int force_N_id_2, lte_cell_t *cell) +{ + int ret = LIBLTE_ERROR; + ue_cell_search_t cs; + ue_cell_search_result_t found_cells[3]; + + bzero(found_cells, 3*sizeof(ue_cell_search_result_t)); + + if (ue_cell_search_init(&cs, cuhd_recv_wrapper_cs, uhd)) { + fprintf(stderr, "Error initiating UE cell detect\n"); + return LIBLTE_ERROR; + } + + if (config->nof_frames_total) { + ue_cell_search_set_nof_frames_to_scan(&cs, config->nof_frames_total); + } + if (config->threshold) { + ue_cell_search_set_threshold(&cs, config->threshold); + } + + INFO("Setting sampling frequency %.2f MHz for PSS search\n", CS_SAMP_FREQ/1000000); + cuhd_set_rx_srate(uhd, CS_SAMP_FREQ); + + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + /* Find a cell in the given N_id_2 or go through the 3 of them to find the strongest */ + uint32_t max_peak_cell = 0; + if (force_N_id_2 >= 0) { + ret = ue_cell_search_scan_N_id_2(&cs, force_N_id_2, &found_cells[force_N_id_2]); + max_peak_cell = force_N_id_2; + } else { + ret = ue_cell_search_scan(&cs, found_cells, &max_peak_cell); + } + if (ret < 0) { + fprintf(stderr, "Error searching cell\n"); + return LIBLTE_ERROR; + } else if (ret == 0) { + fprintf(stderr, "Could not find any cell in this frequency\n"); + return LIBLTE_SUCCESS; + } + + // Save result + if (cell) { + cell->id = found_cells[max_peak_cell].cell_id; + cell->cp = found_cells[max_peak_cell].cp; + } + + cuhd_stop_rx_stream(uhd); + ue_cell_search_free(&cs); + + return ret; +} + + +/* Finds a cell and decodes MIB from the PBCH. + * Returns 1 if the cell is found and MIB is decoded successfully. + * 0 if no cell was found or MIB could not be decoded, + * -1 on error + */ +int cuhd_search_and_decode_mib(void *uhd, cell_search_cfg_t *config, int force_N_id_2, lte_cell_t *cell) +{ + int ret = LIBLTE_ERROR; + + printf("Searching for cell...\n"); + ret = cuhd_cell_search(uhd, config, force_N_id_2, cell); + if (ret > 0) { + printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3); + ret = cuhd_mib_decoder(uhd, 50, cell); + if (ret < 0) { + fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id); + return LIBLTE_ERROR; + } + } + return ret; +} + + +#endif diff --git a/lte/examples/cell_search_utils.h b/lte/examples/cuhd_utils.h similarity index 59% rename from lte/examples/cell_search_utils.h rename to lte/examples/cuhd_utils.h index ad8875e3d..fed662ca0 100644 --- a/lte/examples/cell_search_utils.h +++ b/lte/examples/cuhd_utils.h @@ -31,25 +31,20 @@ typedef struct LIBLTE_API { uint32_t nof_frames_total; // maximum number of 5ms frames to capture float threshold; // early-stops cell detection if mean PSR is above this value -}cell_detect_cfg_t; - -int decode_pbch(void *uhd, - ue_celldetect_result_t *found_cell, - uint32_t nof_frames_total, - uint8_t bch_payload[BCH_PAYLOAD_LEN], - uint32_t *nof_tx_ports, - uint32_t *sfn_offset); - -int detect_all_cells(cell_detect_cfg_t *config, - void *uhd, - ue_celldetect_result_t found_cell[3]); - -int detect_cell(cell_detect_cfg_t *config, - void *uhd, - ue_celldetect_result_t *found_cell, - uint32_t N_id_2); - -int detect_and_decode_cell(cell_detect_cfg_t *config, - void *uhd, - int force_N_id_2, - lte_cell_t *cell); \ No newline at end of file +}cell_search_cfg_t; + +int cuhd_mib_decoder(void *uhd, + uint32_t max_nof_frames, + lte_cell_t *cell); + +int cuhd_cell_search(void *uhd, + cell_search_cfg_t *config, + int force_N_id_2, + lte_cell_t *cell); + +int cuhd_search_and_decode_mib(void *uhd, + cell_search_cfg_t *config, + int force_N_id_2, + lte_cell_t *cell); + + diff --git a/lte/examples/pdsch_ue.c b/lte/examples/pdsch_ue.c index 07b6e587c..01f4196bd 100644 --- a/lte/examples/pdsch_ue.c +++ b/lte/examples/pdsch_ue.c @@ -39,7 +39,7 @@ #include "liblte/rrc/rrc.h" #include "liblte/phy/phy.h" #include "liblte/cuhd/cuhd.h" -#include "cell_search_utils.h" +#include "cuhd_utils.h" #ifndef DISABLE_GRAPHICS void init_plots(); @@ -53,7 +53,7 @@ void do_plots(ue_dl_t *q, uint32_t sf_idx, ue_sync_t *qs); float gain_offset = B210_DEFAULT_GAIN_CORREC; -cell_detect_cfg_t cell_detect_config = { +cell_search_cfg_t cell_detect_config = { 100, // nof_frames_total 4.0 // threshold }; @@ -188,10 +188,24 @@ int main(int argc, char **argv) { cuhd_rx_wait_lo_locked(uhd); printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000); - if (detect_and_decode_cell(&cell_detect_config, uhd, prog_args.force_N_id_2, &cell)) { - fprintf(stderr, "Cell not found\n"); + ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell); + if (ret < 0) { + fprintf(stderr, "Error searching for cell\n"); exit(-1); + } else if (ret == 0) { + printf("Cell not found\n"); + exit(0); } + + /* set sampling frequency */ + int srate = lte_sampling_freq_hz(cell.nof_prb); + if (srate != -1) { + cuhd_set_rx_srate(uhd, (double) srate); + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb); + return LIBLTE_ERROR; + } + INFO("Stopping UHD and flushing buffer...\r",0); cuhd_stop_rx_stream(uhd); @@ -205,7 +219,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error initiating UE downlink processing module\n"); exit(-1); } - if (ue_mib_init(&ue_mib, cell, false)) { + if (ue_mib_init(&ue_mib, cell)) { fprintf(stderr, "Error initaiting UE MIB decoder\n"); exit(-1); } @@ -247,9 +261,7 @@ int main(int argc, char **argv) { case DECODE_MIB: if (ue_sync_get_sfidx(&ue_sync) == 0) { pbch_decode_reset(&ue_mib.pbch); - n = ue_mib_decode_aligned_frame(&ue_mib, - sf_buffer, bch_payload_unpacked, - NULL, &sfn_offset); + n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); exit(-1); @@ -393,7 +405,10 @@ void do_plots(ue_dl_t *q, uint32_t sf_idx, ue_sync_t *qs) { plot_real_setNewData(&poutfft, tmp_plot, nof_re); plot_real_setNewData(&pce, tmp_plot2, REFSIGNAL_NUM_SF(q->cell.nof_prb,0)); int max = vec_max_fi(qs->strack.pss.conv_output_avg, qs->strack.pss.frame_size+qs->strack.pss.fft_size-1); - vec_sc_prod_fff(qs->strack.pss.conv_output_avg, 1/qs->strack.pss.conv_output_avg[max], tmp_plot2, qs->strack.pss.frame_size+qs->strack.pss.fft_size-1); + vec_sc_prod_fff(qs->strack.pss.conv_output_avg, + 1/qs->strack.pss.conv_output_avg[max], + tmp_plot2, + qs->strack.pss.frame_size+qs->strack.pss.fft_size-1); plot_real_setNewData(&p_sync, tmp_plot2, qs->strack.pss.frame_size); plot_scatter_setNewData(&pscatequal, q->pdsch.pdsch_d, nof_symbols); diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index b57f84d48..a01f6e5ef 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -60,6 +60,8 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define PRNTI 0xFFFE #define MRNTI 0xFFFD +#define CELL_ID_UNKNOWN 1000 + #define MAX_NSYMB 7 #define MAX_PRB 110 diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index 5709496f0..4e145614a 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -95,7 +95,7 @@ #include "liblte/phy/ue/ue_sync.h" #include "liblte/phy/ue/ue_mib.h" -#include "liblte/phy/ue/ue_celldetect.h" +#include "liblte/phy/ue/ue_cell_search.h" #include "liblte/phy/ue/ue_dl.h" #include "liblte/phy/scrambling/scrambling.h" diff --git a/lte/phy/include/liblte/phy/ue/ue_cell_search.h b/lte/phy/include/liblte/phy/ue/ue_cell_search.h new file mode 100644 index 000000000..6ad4bc419 --- /dev/null +++ b/lte/phy/include/liblte/phy/ue/ue_cell_search.h @@ -0,0 +1,118 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef UE_CELLSEARCH_ +#define UE_CELLSEARCH_ + +#include + +#include "liblte/config.h" +#include "liblte/phy/ue/ue_sync.h" +#include "liblte/phy/ue/ue_mib.h" +#include "liblte/phy/sync/cfo.h" +#include "liblte/phy/ch_estimation/chest_dl.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/common/fft.h" + +/************************************************************ + * + * This object is a wrapper to the ue_sync object. It receives + * several synchronized frames and obtains the most common cell_id + * and cp length. + * + * The I/O stream device sampling frequency must be set to 1.92 MHz (CS_SAMP_FREQ constant) + * before calling to ue_cell_search_scan() functions. + * + ************************************************************/ + +/** + * TODO: Check also peak offset + */ + +#define CS_DEFAULT_MAXFRAMES_TOTAL 500 +#define CS_DEFAULT_MAXFRAMES_DETECTED 50 + +#define CS_DEFAULT_NOFFRAMES_TOTAL 50 +#define CS_DEFAULT_NOFFRAMES_DETECTED 10 + +#define CS_NOF_PRB 6 +#define CS_SAMP_FREQ 1920000.0 + +typedef struct LIBLTE_API { + uint32_t cell_id; + lte_cp_t cp; + float peak; + float mode; +} ue_cell_search_result_t; + + +typedef struct LIBLTE_API { + ue_sync_t ue_sync; + + uint32_t max_frames; + uint32_t nof_frames_to_scan; // number of 5 ms frames to scan + float detect_threshold; // early-stops scan if mean PSR above this threshold + + uint32_t *mode_ntimes; + uint8_t *mode_counted; + + ue_cell_search_result_t *candidates; +} ue_cell_search_t; + + +LIBLTE_API int ue_cell_search_init(ue_cell_search_t *q, + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); + +LIBLTE_API int ue_cell_search_init_max(ue_cell_search_t *q, + uint32_t max_frames_total, + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); + +LIBLTE_API void ue_cell_search_free(ue_cell_search_t *q); + +LIBLTE_API int ue_cell_search_scan_N_id_2(ue_cell_search_t *q, + uint32_t N_id_2, + ue_cell_search_result_t *found_cell); + +LIBLTE_API int ue_cell_search_scan(ue_cell_search_t * q, + ue_cell_search_result_t found_cells[3], + uint32_t *max_N_id_2); + +LIBLTE_API int ue_cell_search_set_nof_frames_to_scan(ue_cell_search_t *q, + uint32_t nof_frames); + +LIBLTE_API void ue_cell_search_set_threshold(ue_cell_search_t *q, + float threshold); + + + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/ue/ue_celldetect.h b/lte/phy/include/liblte/phy/ue/ue_celldetect.h deleted file mode 100644 index e68e2ea47..000000000 --- a/lte/phy/include/liblte/phy/ue/ue_celldetect.h +++ /dev/null @@ -1,132 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * A copy of the GNU Lesser General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#ifndef UE_CELLSEARCH_ -#define UE_CELLSEARCH_ - -#include - -#include "liblte/config.h" -#include "liblte/phy/sync/sync.h" -#include "liblte/phy/sync/cfo.h" -#include "liblte/phy/ch_estimation/chest_dl.h" -#include "liblte/phy/phch/pbch.h" -#include "liblte/phy/common/fft.h" - -/************************************************************ - * - * This object scans a signal for LTE cells using the known PSS - * and SSS sequences. - * - * The function ue_celldetect_scan() shall be called multiple times, - * each passing a number of samples multiple of 4800, sampled at 960 KHz - * (that is, 5 ms of samples). - * - * The function returns 0 until a signal is found nof_frames_detected times or - * after nof_frames_total with no signal detected. - * - * See ue_cell_detect.c for an example. - * - ************************************************************/ - -/** - * TODO: Check also peak offset - */ - -#define CS_DEFAULT_MAXFRAMES_TOTAL 500 -#define CS_DEFAULT_MAXFRAMES_DETECTED 50 - -#define CS_DEFAULT_NOFFRAMES_TOTAL 100 -#define CS_DEFAULT_NOFFRAMES_DETECTED 10 - -#define CS_FRAME_UNALIGNED -3 -#define CS_CELL_DETECTED 2 -#define CS_CELL_NOT_DETECTED 3 - -#define CS_FFTSIZE 128 -#define CS_SAMP_FREQ (960000*(CS_FFTSIZE/64)) -#define CS_FLEN (4800*(CS_FFTSIZE/64)) - -typedef struct LIBLTE_API { - uint32_t cell_id; - lte_cp_t cp; - float peak; - float mode; -} ue_celldetect_result_t; - - -typedef struct LIBLTE_API { - sync_t sfind; - - uint32_t max_frames_total; - uint32_t nof_frames_total; // number of 5 ms frames to scan - float detect_threshold; // early-stops scan if mean PSR above this threshold - - uint32_t current_nof_detected; - uint32_t current_nof_total; - - uint32_t *mode_ntimes; - uint8_t *mode_counted; - - ue_celldetect_result_t *candidates; -} ue_celldetect_t; - - -LIBLTE_API int ue_celldetect_init(ue_celldetect_t *q); - -LIBLTE_API int ue_celldetect_init_max(ue_celldetect_t *q, - uint32_t max_frames_total); - -LIBLTE_API void ue_celldetect_free(ue_celldetect_t *q); - -LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q); - -LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q, - cf_t *signal, - uint32_t nsamples); - -LIBLTE_API int ue_celldetect_set_N_id_2(ue_celldetect_t *q, - uint32_t N_id_2); - -LIBLTE_API void ue_celldetect_get_cell(ue_celldetect_t * q, - ue_celldetect_result_t *found_cell); - -LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q, - uint32_t nof_frames); - -LIBLTE_API void ue_celldetect_set_threshold(ue_celldetect_t *q, - float threshold); - -LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q); - - - - - - -#endif // SYNC_FRAME_ - diff --git a/lte/phy/include/liblte/phy/ue/ue_mib.h b/lte/phy/include/liblte/phy/ue/ue_mib.h index 0b85bbb75..836f014c8 100644 --- a/lte/phy/include/liblte/phy/ue/ue_mib.h +++ b/lte/phy/include/liblte/phy/ue/ue_mib.h @@ -49,7 +49,7 @@ #include #include "liblte/config.h" -#include "liblte/phy/sync/sync.h" +#include "liblte/phy/ue/ue_sync.h" #include "liblte/phy/sync/cfo.h" #include "liblte/phy/ch_estimation/chest_dl.h" #include "liblte/phy/phch/pbch.h" @@ -57,10 +57,8 @@ #define MIB_MAX_PORTS 4 -#define MIB_FRAME_SIZE_SEARCH 9600 -#define MIB_FFT_SIZE 128 +#define MIB_NOF_PRB 6 -#define MIB_FRAME_UNALIGNED -3 #define MIB_FOUND 1 #define MIB_NOTFOUND 0 @@ -70,7 +68,6 @@ typedef struct LIBLTE_API { cf_t *sf_symbols; cf_t *ce[MIB_MAX_PORTS]; - cfo_t cfocorr; lte_fft_t fft; chest_dl_t chest; pbch_t pbch; @@ -80,43 +77,45 @@ typedef struct LIBLTE_API { uint32_t sfn_offset; uint32_t frame_cnt; - uint32_t last_frame_trial; } ue_mib_t; - -LIBLTE_API int ue_mib_init_1_92(ue_mib_t *q, - uint32_t cell_id, - lte_cp_t cp); - LIBLTE_API int ue_mib_init(ue_mib_t *q, - lte_cell_t cell, - bool do_sync); + lte_cell_t cell); LIBLTE_API void ue_mib_free(ue_mib_t *q); -LIBLTE_API void ue_mib_reset(ue_mib_t *q); +LIBLTE_API void ue_mib_reset(ue_mib_t * q); -LIBLTE_API int ue_mib_sync_and_decode_1_92(ue_mib_t *q, - cf_t *signal, - uint32_t nsamples); +LIBLTE_API int ue_mib_decode(ue_mib_t * q, + cf_t *input, + uint8_t bch_payload[BCH_PAYLOAD_LEN], + uint32_t *nof_tx_ports, + uint32_t *sfn_offset); -LIBLTE_API int ue_mib_decode_aligned_frame(ue_mib_t * q, - cf_t *input, - uint8_t bch_payload[BCH_PAYLOAD_LEN], - uint32_t *nof_tx_ports, - uint32_t *sfn_offset); -LIBLTE_API void ue_mib_get_payload(ue_mib_t *q, - uint8_t bch_payload[BCH_PAYLOAD_LEN], - uint32_t *nof_tx_ports, - uint32_t *sfn_offset); +/* This interface uses ue_mib and ue_sync to first get synchronized subframes + * and then decode MIB +*/ +typedef struct { + ue_mib_t ue_mib; + ue_sync_t ue_sync; +} ue_mib_sync_t; -LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q, - float threshold); +LIBLTE_API int ue_mib_sync_init(ue_mib_sync_t *q, + uint32_t cell_id, + lte_cp_t cp, + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); -LIBLTE_API void ue_mib_reset(ue_mib_t *q); +LIBLTE_API void ue_mib_sync_free(ue_mib_sync_t *q); +LIBLTE_API void ue_mib_sync_reset(ue_mib_sync_t * q); +LIBLTE_API int ue_mib_sync_decode(ue_mib_sync_t * q, + uint32_t max_frames_timeout, + uint8_t bch_payload[BCH_PAYLOAD_LEN], + uint32_t *nof_tx_ports, + uint32_t *sfn_offset); diff --git a/lte/phy/include/liblte/phy/ue/ue_sync.h b/lte/phy/include/liblte/phy/ue/ue_sync.h index 3e7e92356..0ea31dad0 100644 --- a/lte/phy/include/liblte/phy/ue/ue_sync.h +++ b/lte/phy/include/liblte/phy/ue/ue_sync.h @@ -66,6 +66,13 @@ typedef struct LIBLTE_API { cf_t *input_buffer; + uint32_t frame_len; + uint32_t fft_size; + uint32_t nof_recv_sf; // Number of subframes received each call to ue_sync_get_buffer + uint32_t nof_avg_find_frames; + uint32_t frame_find_cnt; + uint32_t sf_len; + /* These count half frames (5ms) */ uint64_t frame_ok_cnt; uint32_t frame_no_cnt; @@ -82,6 +89,7 @@ typedef struct LIBLTE_API { uint32_t peak_idx; int time_offset; float mean_time_offset; + #ifdef MEASURE_EXEC_TIME float mean_exec_time; #endif @@ -89,9 +97,9 @@ typedef struct LIBLTE_API { LIBLTE_API int ue_sync_init(ue_sync_t *q, - lte_cell_t cell, - int (recv_callback)(void*, void*, uint32_t), - void *stream_handler); + lte_cell_t cell, + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler); LIBLTE_API void ue_sync_free(ue_sync_t *q); @@ -102,6 +110,9 @@ LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q, LIBLTE_API void ue_sync_reset(ue_sync_t *q); +LIBLTE_API void ue_sync_set_N_id_2(ue_sync_t *q, + uint32_t N_id_2); + LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled); diff --git a/lte/phy/lib/mimo/src/precoding.c b/lte/phy/lib/mimo/src/precoding.c index f3dd41af5..b45b6fcb3 100644 --- a/lte/phy/lib/mimo/src/precoding.c +++ b/lte/phy/lib/mimo/src/precoding.c @@ -138,7 +138,9 @@ int predecoding_single(precoding_t *q, cf_t *y, cf_t *h, cf_t *x, int nof_symbol /* ZF/MMSE STBC equalizer x=y(H'H+n0·I)^(-1)H' (ZF is n0=0.0) */ -int predecoding_diversity(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[MAX_LAYERS], int nof_ports, int nof_symbols, float noise_estimate) { +int predecoding_diversity(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[MAX_LAYERS], + int nof_ports, int nof_symbols, float noise_estimate) +{ int i; if (nof_ports == 2) { @@ -171,8 +173,7 @@ int predecoding_diversity(precoding_t *q, cf_t *y, cf_t *h[MAX_PORTS], cf_t *x[M // (H'H + n0) vec_sc_add_fff(modhh, noise_estimate, modhh, nof_symbols/2); } - //vec_sc_prod_fff(modhh, 1.0/sqrt(2), modhh, nof_symbols/2); - + // x[0] = r0·h0*/(|h0|+|h1|)+r1*·h1/(|h0|+|h1|) vec_prod_conj_ccc(r0,h0,q->tmp1, nof_symbols/2); vec_prod_conj_ccc(h1,r1,q->tmp2, nof_symbols/2); diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index 15e419f9c..5beaf56d8 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -382,10 +382,6 @@ int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], float demod_soft_demodulate(&q->demod, q->pbch_d, &q->pbch_llr[nof_bits * (q->frame_idx - 1)], q->nof_symbols); - if (nant == 2) { - vec_save_file("d",q->pbch_d, q->nof_symbols*sizeof(cf_t)); - } - /* We don't know where the 40 ms begin, so we try all combinations. E.g. if we received * 4 frames, try 1,2,3,4 individually, 12, 23, 34 in pairs, 123, 234 and finally 1234. * We know they are ordered. diff --git a/lte/phy/lib/phch/src/pdcch.c b/lte/phy/lib/phch/src/pdcch.c index 353a2c8f3..af38fb4b9 100644 --- a/lte/phy/lib/phch/src/pdcch.c +++ b/lte/phy/lib/phch/src/pdcch.c @@ -46,9 +46,6 @@ #define PDCCH_FORMAT_NOF_REGS(i) ((1<b)?b:a) - static void set_cfi(pdcch_t *q, uint32_t cfi) { if (cfi > 0 && cfi < 4) { q->nof_regs = (regs_pdcch_nregs(q->regs, cfi) / 9) * 9; @@ -420,7 +417,7 @@ int pdcch_extract_llr(pdcch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float n } /* demodulate symbols */ - demod_soft_sigma_set(&q->demod, sqrtf(2/q->cell.nof_ports)); + demod_soft_sigma_set(&q->demod, 1.0); demod_soft_demodulate(&q->demod, q->pdcch_d, q->pdcch_llr, nof_symbols); /* descramble */ diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 3881d7246..8d7ebc433 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -702,12 +702,12 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], float noise_ layerdemap_diversity(x, q->pdsch_d, q->cell.nof_ports, nof_symbols / q->cell.nof_ports); } - + /* demodulate symbols * The MAX-log-MAP algorithm used in turbo decoding is unsensitive to SNR estimation, * thus we don't need tot set it in the LLRs normalization */ - demod_soft_sigma_set(&q->demod, 1);//q->mod[harq_process->mcs.mod - 1].nbits_x_symbol); + demod_soft_sigma_set(&q->demod, sqrt(q->mod[harq_process->mcs.mod - 1].nbits_x_symbol/2)); 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); diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index b183e24b2..ac27ca59b 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -121,18 +121,22 @@ int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } + bzero(q->conv_output, sizeof(cf_t) * buffer_size); q->conv_output_avg = vec_malloc(buffer_size * sizeof(float)); if (!q->conv_output_avg) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } + bzero(q->conv_output_avg, sizeof(float) * buffer_size); #ifdef PSS_ACCUMULATE_ABS q->conv_output_abs = vec_malloc(buffer_size * sizeof(float)); if (!q->conv_output_abs) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } + bzero(q->conv_output_abs, sizeof(float) * buffer_size); #endif + for (N_id_2=0;N_id_2<3;N_id_2++) { q->pss_signal_freq[N_id_2] = vec_malloc(buffer_size * sizeof(cf_t)); if (!q->pss_signal_freq[N_id_2]) { @@ -286,22 +290,22 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value) fprintf(stderr, "Error finding PSS peak, Must set N_id_2 first\n"); return LIBLTE_ERROR; } - - memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); /* Correlate input with PSS sequence */ if (q->frame_size >= q->fft_size) { #ifdef CONVOLUTION_FFT + memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); + conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_freq[q->N_id_2], q->conv_output); #else conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif } else { - for (int i=0;iframe_size;i++) { - q->conv_output[i] = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], &input[i], q->fft_size); - } - conv_output_len = q->frame_size; + for (int i=q->fft_size;ifft_size+q->frame_size-1;i++) { + q->conv_output[i] = vec_dot_prod_ccc(q->pss_signal_freq[q->N_id_2], &input[i-q->fft_size], q->fft_size); + } + conv_output_len = q->fft_size+q->frame_size-1; } @@ -351,7 +355,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value) *corr_peak_value = q->conv_output_avg[corr_peak_pos]/side_lobe_value; if (*corr_peak_value < 2.0) { - INFO("pl_ub=%d, pl_lb=%d, sl_right: %d (%.2f), sl_left: %d (%.2f), PSR: %.2f/%.2f=%.2f\n", pl_ub, pl_lb, + DEBUG("pl_ub=%d, pl_lb=%d, sl_right: %d (%.2f), sl_left: %d (%.2f), PSR: %.2f/%.2f=%.2f\n", pl_ub, pl_lb, sl_right, 1000000*q->conv_output_avg[sl_right], sl_left, 1000000*q->conv_output_avg[sl_left], 1000000*q->conv_output_avg[corr_peak_pos], 1000000*side_lobe_value,*corr_peak_value diff --git a/lte/phy/lib/sync/src/sss.c b/lte/phy/lib/sync/src/sss.c index c33f13822..fbbd517e2 100644 --- a/lte/phy/lib/sync/src/sss.c +++ b/lte/phy/lib/sync/src/sss.c @@ -143,11 +143,21 @@ int sss_synch_N_id_1(sss_synch_t *q, uint32_t m0, uint32_t m1) { if (m0==m1 || m0 > 29 || m1 > 29) { return LIBLTE_ERROR; } + int N_id_1; if (m1 > m0) { - return q->N_id_1_table[m0][m1 - 1]; + N_id_1 = q->N_id_1_table[m0][m1 - 1]; } else { - return q->N_id_1_table[m1][m0 - 1]; + N_id_1 = q->N_id_1_table[m1][m0 - 1]; } + if (N_id_1 == 0) { + if (m0 == 0 && m1 == 1) { + return N_id_1; + } else { + return LIBLTE_ERROR; + } + } else { + return N_id_1; + } } /** High-level API */ diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 5048c8f4f..61de9203c 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -59,9 +59,11 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) { bzero(q, sizeof(sync_t)); q->detect_cp = true; + q->cp = CPNORM; q->mean_peak_value = 0.0; q->sss_en = true; q->correct_cfo = true; + q->mean_cfo = 0; q->N_id_2 = 1000; q->N_id_1 = 1000; q->fft_size = fft_size; @@ -120,8 +122,7 @@ int sync_get_cell_id(sync_t *q) { if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { return q->N_id_1*3 + q->N_id_2; } else { - fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); - return LIBLTE_ERROR; + return -1; } } @@ -200,16 +201,18 @@ lte_cp_t sync_detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos) M_norm += R_norm/C_norm; } - q->M_norm_avg = VEC_EMA(M_norm, q->M_norm_avg, CP_EMA_ALPHA); + q->M_norm_avg = VEC_EMA(M_norm/2, q->M_norm_avg, CP_EMA_ALPHA); for (int i=0;i<2;i++) { R_ext = crealf(vec_dot_prod_conj_ccc(&input_cp_ext[q->fft_size], input_cp_ext, cp_ext_len)); C_ext = cp_ext_len * vec_avg_power_cf(input_cp_ext, cp_ext_len); input_cp_ext += q->fft_size+cp_ext_len; - M_ext += R_ext/C_ext; + if (C_ext > 0) { + M_ext += R_ext/C_ext; + } } - q->M_ext_avg = VEC_EMA(M_ext, q->M_ext_avg, CP_EMA_ALPHA); + q->M_ext_avg = VEC_EMA(M_ext/2, q->M_ext_avg, CP_EMA_ALPHA); if (q->M_norm_avg > q->M_ext_avg) { return CPNORM; @@ -227,26 +230,18 @@ lte_cp_t sync_detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos) /* Returns 1 if the SSS is found, 0 if not and -1 if there is not enough space * to correlate */ -int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { +int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, lte_cp_t cp) { int sss_idx, ret; sss_synch_set_N_id_2(&q->sss, q->N_id_2); - if (q->detect_cp) { - if (peak_pos >= 2*(q->fft_size + CP_EXT(q->fft_size))) { - q->cp = sync_detect_cp(q, input, peak_pos); - } else { - INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos); - return LIBLTE_ERROR; - } - } - /* Make sure we have enough room to find SSS sequence */ sss_idx = (int) peak_pos-2*q->fft_size-CP(q->fft_size, (CP_ISNORM(q->cp)?CPNORM_LEN:CPEXT_LEN)); if (sss_idx < 0) { INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos); return LIBLTE_ERROR; } + DEBUG("Searching SSS around sss_idx: %d, peak_pos: %d\n", sss_idx, peak_pos); switch(q->sss_alg) { case SSS_DIFF: @@ -325,7 +320,15 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit } else { INFO("No space for CFO computation. Frame starts at \n",peak_pos); } - + + if (q->detect_cp) { + if (peak_pos + find_offset >= 2*(q->fft_size + CP_EXT(q->fft_size))) { + q->cp = sync_detect_cp(q, input, peak_pos + find_offset); + } else { + INFO("Not enough room to detect CP length. Peak position: %d\n", peak_pos); + } + } + // Try to detect SSS if (q->sss_en) { /* Correct CFO with the averaged CFO estimation */ @@ -336,7 +339,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit // Set an invalid N_id_1 indicating SSS is yet to be detected q->N_id_1 = 1000; - if (sync_sss(q, input, find_offset + peak_pos) < 0) { + if (sync_sss(q, input, find_offset + peak_pos, q->cp) < 0) { INFO("No space for SSS processing. Frame starts at %d\n", peak_pos); } } @@ -346,8 +349,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit ret = 0; } - INFO("SYNC ret=%d N_id_2=%d frame_size=%d pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n", - ret, q->N_id_2, q->frame_size, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo); + INFO("SYNC ret=%d N_id_2=%d find_offset=%d pos=%d peak=%.2f threshold=%.2f sf_idx=%d, CFO=%.3f KHz\n", + ret, q->N_id_2, find_offset, peak_pos, q->peak_value, q->threshold, q->sf_idx, 15*q->mean_cfo); } else if (lte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Must call sync_set_N_id_2() first!\n"); diff --git a/lte/phy/lib/sync/test/pss_usrp.c b/lte/phy/lib/sync/test/pss_usrp.c index ea87d887c..fac32e19e 100644 --- a/lte/phy/lib/sync/test/pss_usrp.c +++ b/lte/phy/lib/sync/test/pss_usrp.c @@ -245,14 +245,17 @@ int main(int argc, char **argv) { if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { sss_error2++; } + INFO("Partial N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1)); sss_synch_m0m1_diff(&sss, &buffer[sss_idx], &m0, &m0_value, &m1, &m1_value); if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { sss_error3++; } + INFO("Diff N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1)); sss_synch_m0m1_partial(&sss, &buffer[sss_idx], 1, NULL, &m0, &m0_value, &m1, &m1_value); if (sss_synch_N_id_1(&sss, m0, m1) != N_id_1) { sss_error1++; } + INFO("Full N_id_1: %d\n", sss_synch_N_id_1(&sss, m0, m1)); } // Estimate CP diff --git a/lte/phy/lib/sync/test/sync_test.c b/lte/phy/lib/sync/test/sync_test.c index 27ed917f2..d007485d6 100644 --- a/lte/phy/lib/sync/test/sync_test.c +++ b/lte/phy/lib/sync/test/sync_test.c @@ -121,7 +121,8 @@ int main(int argc, char **argv) { } /* Set a very high threshold to make sure the correlation is ok */ - sync_set_threshold(&sync, 1.4); + sync_set_threshold(&sync, 5.0); + sync_set_sss_algorithm(&sync, SSS_PARTIAL_3); if (cell_id == -1) { cid = 0; diff --git a/lte/phy/lib/ue/src/ue_cell_search.c b/lte/phy/lib/ue/src/ue_cell_search.c new file mode 100644 index 000000000..c8b05e217 --- /dev/null +++ b/lte/phy/lib/ue/src/ue_cell_search.c @@ -0,0 +1,275 @@ +/** + * + * \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 "liblte/phy/ue/ue_cell_search.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +float tmp_pss_corr[32*10000]; +float tmp_sss_corr[31*10000]; + +int ue_cell_search_init(ue_cell_search_t * q, int (recv_callback)(void*, void*, uint32_t), void *stream_handler) +{ + return ue_cell_search_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL, recv_callback, stream_handler); +} + +int ue_cell_search_init_max(ue_cell_search_t * q, uint32_t max_frames, + int (recv_callback)(void*, void*, uint32_t), void *stream_handler) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = LIBLTE_ERROR; + lte_cell_t cell; + + bzero(q, sizeof(ue_cell_search_t)); + + bzero(&cell, sizeof(lte_cell_t)); + cell.id = CELL_ID_UNKNOWN; + cell.nof_prb = CS_NOF_PRB; + + if (ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) { + fprintf(stderr, "Error initiating ue_sync\n"); + goto clean_exit; + } + + q->candidates = calloc(sizeof(ue_cell_search_result_t), max_frames); + if (!q->candidates) { + perror("malloc"); + goto clean_exit; + } + q->mode_ntimes = calloc(sizeof(uint32_t), max_frames); + if (!q->mode_ntimes) { + perror("malloc"); + goto clean_exit; + } + q->mode_counted = calloc(sizeof(uint8_t), max_frames); + if (!q->mode_counted) { + perror("malloc"); + goto clean_exit; + } + + q->max_frames = max_frames; + q->nof_frames_to_scan = CS_DEFAULT_NOFFRAMES_TOTAL; + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_cell_search_free(q); + } + return ret; +} + +void ue_cell_search_free(ue_cell_search_t * q) +{ + if (q->candidates) { + free(q->candidates); + } + if (q->mode_counted) { + free(q->mode_counted); + } + if (q->mode_ntimes) { + free(q->mode_ntimes); + } + ue_sync_free(&q->ue_sync); + + bzero(q, sizeof(ue_cell_search_t)); + +} + +void ue_cell_search_set_threshold(ue_cell_search_t * q, float threshold) +{ + q->detect_threshold = threshold; +} + +int ue_cell_search_set_nof_frames_to_scan(ue_cell_search_t * q, uint32_t nof_frames) +{ + if (nof_frames <= q->max_frames) { + q->nof_frames_to_scan = nof_frames; + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR; + } +} + +/* Decide the most likely cell based on the mode */ +static void get_cell(ue_cell_search_t * q, uint32_t nof_detected_frames, ue_cell_search_result_t *found_cell) +{ + uint32_t i, j; + + bzero(q->mode_counted, nof_detected_frames); + bzero(q->mode_ntimes, sizeof(uint32_t) * nof_detected_frames); + + /* First find mode of CELL IDs */ + for (i = 0; i < nof_detected_frames; i++) { + uint32_t cnt = 1; + for (j=i+1;jcandidates[j].cell_id == q->candidates[i].cell_id && !q->mode_counted[j]) { + q->mode_counted[j]=1; + cnt++; + } + } + q->mode_ntimes[i] = cnt; + } + uint32_t max_times=0, mode_pos=0; + for (i=0;imode_ntimes[i] > max_times) { + max_times = q->mode_ntimes[i]; + mode_pos = i; + } + } + found_cell->cell_id = q->candidates[mode_pos].cell_id; + /* Now in all these cell IDs, find most frequent CP */ + uint32_t nof_normal = 0; + for (i=0;icandidates[i].cell_id == found_cell->cell_id) { + if (CP_ISNORM(q->candidates[i].cp)) { + nof_normal++; + } + } + } + if (nof_normal > q->mode_ntimes[mode_pos]/2) { + found_cell->cp = CPNORM; + } else { + found_cell->cp = CPEXT; + } + found_cell->mode = (float) q->mode_ntimes[mode_pos]/nof_detected_frames; + found_cell->peak = q->candidates[nof_detected_frames-1].peak; +} + +/** Finds up to 3 cells, one per each N_id_2=0,1,2 and stores ID and CP in the structure pointed by found_cell. + * Each position in found_cell corresponds to a different N_id_2. + * Saves in the pointer max_N_id_2 the N_id_2 index of the cell with the highest PSR + * Returns the number of found cells or a negative number if error + */ +int ue_cell_search_scan(ue_cell_search_t * q, ue_cell_search_result_t found_cells[3], uint32_t *max_N_id_2) +{ + int ret = 0; + float max_peak_value = -1.0; + uint32_t nof_detected_cells = 0; + for (uint32_t N_id_2=0;N_id_2<3 && ret >= 0;N_id_2++) { + ret = ue_cell_search_scan_N_id_2(q, N_id_2, &found_cells[N_id_2]); + if (ret < 0) { + fprintf(stderr, "Error searching cell\n"); + return ret; + } + nof_detected_cells += ret; + if (max_N_id_2) { + if (found_cells[N_id_2].peak > max_peak_value) { + max_peak_value = found_cells[N_id_2].peak; + *max_N_id_2 = N_id_2; + } + } + } + return nof_detected_cells; +} + +/** Finds a cell for a given N_id_2 and stores ID and CP in the structure pointed by found_cell. + * Returns 1 if the cell is found, 0 if not or -1 on error + */ +int ue_cell_search_scan_N_id_2(ue_cell_search_t * q, uint32_t N_id_2, ue_cell_search_result_t *found_cell) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + cf_t *sf_buffer = NULL; + uint32_t nof_detected_frames = 0; + uint32_t nof_scanned_frames = 0; + + if (q != NULL) + { + ret = LIBLTE_SUCCESS; + + ue_sync_set_N_id_2(&q->ue_sync, N_id_2); + + do { + + ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer); + if (ret < 0) { + fprintf(stderr, "Error calling ue_sync_work()\n"); + break; + } else if (ret == 1) { + /* This means a peak was found and ue_sync is now in tracking state */ + ret = sync_get_cell_id(&q->ue_sync.strack); + if (ret >= 0) { + /* Save cell id, cp and peak */ + q->candidates[nof_detected_frames].cell_id = (uint32_t) ret; + q->candidates[nof_detected_frames].cp = sync_get_cp(&q->ue_sync.strack); + q->candidates[nof_detected_frames].peak = sync_get_peak_value(&q->ue_sync.strack); + INFO + ("CELL SEARCH: [%3d/%3d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s\n", + nof_detected_frames, nof_scanned_frames, q->nof_frames_to_scan, + q->candidates[nof_detected_frames].peak, q->candidates[nof_detected_frames].cell_id, + lte_cp_string(q->candidates[nof_detected_frames].cp)); + memcpy(&tmp_pss_corr[nof_detected_frames*32], + &q->ue_sync.strack.pss.conv_output_avg[128], 32*sizeof(float)); + memcpy(&tmp_sss_corr[nof_detected_frames*31], + &q->ue_sync.strack.sss.corr_output_m0, 31*sizeof(float)); + nof_detected_frames++; + } + } else if (ret == 0) { + /* This means a peak is not yet found and ue_sync is in find state + * Do nothing, just wait and increase nof_scanned_frames counter. + */ + } + + nof_scanned_frames++; + + } while ((sync_get_peak_value(&q->ue_sync.strack) < q->detect_threshold || + nof_detected_frames < 4) && + nof_scanned_frames < q->nof_frames_to_scan); + + /* + vec_save_file("sss_corr",tmp_sss_corr, nof_detected_frames*sizeof(float)*31); + vec_save_file("track_corr",tmp_pss_corr, nof_detected_frames*sizeof(float)*32); + vec_save_file("find_corr",q->ue_sync.sfind.pss.conv_output_avg, + sizeof(float)*(9600+127)); + */ + + /* In either case, check if the mean PSR is above the minimum threshold */ + if (nof_detected_frames > 0) { + ret = 1; // A cell has been found. + if (found_cell) { + get_cell(q, nof_detected_frames, found_cell); + printf("Found CELL PHYID: %d, CP: %s, PSR: %.1f, Reliability: %.0f \%\n", + found_cell->cell_id, lte_cp_string(found_cell->cp), + found_cell->peak, 100*found_cell->mode); + } + } else { + ret = 0; // A cell was not found. + } + } + + return ret; +} diff --git a/lte/phy/lib/ue/src/ue_celldetect.c b/lte/phy/lib/ue/src/ue_celldetect.c deleted file mode 100644 index 62ae106e7..000000000 --- a/lte/phy/lib/ue/src/ue_celldetect.c +++ /dev/null @@ -1,260 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * A copy of the GNU Lesser General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include -#include -#include -#include -#include - -#include "liblte/phy/ue/ue_celldetect.h" - -#include "liblte/phy/utils/debug.h" -#include "liblte/phy/utils/vector.h" - -#define CS_CELL_DETECT_THRESHOLD 1.2 - -#define CS_SFLEN 5*SF_LEN(CS_FFTSIZE) - -int ue_celldetect_init(ue_celldetect_t * q) { - return ue_celldetect_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL); -} - -int ue_celldetect_init_max(ue_celldetect_t * q, uint32_t max_frames_total) { - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL) { - ret = LIBLTE_ERROR; - - bzero(q, sizeof(ue_celldetect_t)); - - q->candidates = calloc(sizeof(ue_celldetect_result_t), max_frames_total); - if (!q->candidates) { - perror("malloc"); - goto clean_exit; - } - if (sync_init(&q->sfind, CS_SFLEN, CS_FFTSIZE)) { - goto clean_exit; - } - q->mode_ntimes = calloc(sizeof(uint32_t), max_frames_total); - if (!q->mode_ntimes) { - perror("malloc"); - goto clean_exit; - } - q->mode_counted = calloc(sizeof(uint8_t), max_frames_total); - if (!q->mode_counted) { - perror("malloc"); - goto clean_exit; - } - - /* Accept all peaks because search space is 5 ms and there is always a peak */ - sync_set_threshold(&q->sfind, 1.0); - sync_sss_en(&q->sfind, true); - sync_set_sss_algorithm(&q->sfind, SSS_PARTIAL_3); - sync_set_em_alpha(&q->sfind, 0.01); - - q->max_frames_total = max_frames_total; - q->nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL; - - ue_celldetect_reset(q); - - ret = LIBLTE_SUCCESS; - } - -clean_exit: - if (ret == LIBLTE_ERROR) { - ue_celldetect_free(q); - } - return ret; -} - -void ue_celldetect_free(ue_celldetect_t * q) -{ - if (q->candidates) { - free(q->candidates); - } - if (q->mode_counted) { - free(q->mode_counted); - } - if (q->mode_ntimes) { - free(q->mode_ntimes); - } - sync_free(&q->sfind); - - bzero(q, sizeof(ue_celldetect_t)); - -} - -void ue_celldetect_reset(ue_celldetect_t * q) -{ - q->current_nof_detected = 0; - q->current_nof_total = 0; -} - -void ue_celldetect_set_threshold(ue_celldetect_t * q, float threshold) -{ - q->detect_threshold = threshold; -} - -int ue_celldetect_set_nof_frames_total(ue_celldetect_t * q, uint32_t nof_frames) -{ - if (nof_frames <= q->max_frames_total) { - q->nof_frames_total = nof_frames; - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR; - } -} - -/* Decide the most likely cell based on the mode */ -void ue_celldetect_get_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell) -{ - uint32_t i, j; - - if (!q->current_nof_detected) { - return; - } - - bzero(q->mode_counted, q->current_nof_detected); - bzero(q->mode_ntimes, sizeof(uint32_t) * q->current_nof_detected); - - /* First find mode of CELL IDs */ - for (i = 0; i < q->current_nof_detected; i++) { - uint32_t cnt = 1; - for (j=i+1;jcurrent_nof_detected;j++) { - if (q->candidates[j].cell_id == q->candidates[i].cell_id && !q->mode_counted[j]) { - q->mode_counted[j]=1; - cnt++; - } - } - q->mode_ntimes[i] = cnt; - } - uint32_t max_times=0, mode_pos=0; - for (i=0;icurrent_nof_detected;i++) { - if (q->mode_ntimes[i] > max_times) { - max_times = q->mode_ntimes[i]; - mode_pos = i; - } - } - found_cell->cell_id = q->candidates[mode_pos].cell_id; - /* Now in all these cell IDs, find most frequent CP */ - uint32_t nof_normal = 0; - for (i=0;icurrent_nof_detected;i++) { - if (q->candidates[i].cell_id == found_cell->cell_id) { - if (CP_ISNORM(q->candidates[i].cp)) { - nof_normal++; - } - } - } - if (nof_normal > q->mode_ntimes[mode_pos]/2) { - found_cell->cp = CPNORM; - } else { - found_cell->cp = CPEXT; - } - found_cell->mode = (float) q->mode_ntimes[mode_pos]/q->current_nof_detected; - found_cell->peak = q->candidates[q->current_nof_detected-1].peak; - q->current_nof_detected = q->current_nof_total = 0; -} - -int ue_celldetect_set_N_id_2(ue_celldetect_t *q, uint32_t N_id_2) { - return sync_set_N_id_2(&q->sfind, N_id_2); -} - -int ue_celldetect_scan(ue_celldetect_t * q, - cf_t *signal, - uint32_t nsamples) -{ - int ret = LIBLTE_ERROR_INVALID_INPUTS; - uint32_t peak_idx; - uint32_t nof_input_frames; - - - if (q != NULL && - signal != NULL && - nsamples >= CS_FLEN) - { - ret = LIBLTE_SUCCESS; - - if (nsamples % CS_FLEN) { - printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", CS_FLEN); - nsamples = (nsamples/CS_FLEN) * CS_FLEN; - } - nof_input_frames = nsamples/CS_FLEN; - - for (uint32_t nf=0;nfcurrent_nof_detected, q->current_nof_total, q->sfind.N_id_2, nof_input_frames); - - /* Find peak and cell id */ - ret = sync_find(&q->sfind, &signal[nf*CS_FLEN], 0, &peak_idx); - if (ret < 0) { - fprintf(stderr, "Error finding correlation peak (%d)\n", ret); - return LIBLTE_ERROR; - } - - /* Process the peak result */ - if (ret == 1) { - if (sync_sss_detected(&q->sfind)) { - ret = sync_get_cell_id(&q->sfind); - if (ret >= 0) { - /* Save cell id, cp and peak */ - q->candidates[q->current_nof_detected].cell_id = (uint32_t) ret; - q->candidates[q->current_nof_detected].cp = sync_get_cp(&q->sfind); - q->candidates[q->current_nof_detected].peak = sync_get_peak_value(&q->sfind); - } - INFO - ("[%3d/%3d]: Found peak at %4d, value %.3f, Cell_id: %d CP: %s\n", - q->current_nof_detected, q->current_nof_total, peak_idx, - q->candidates[q->current_nof_detected].peak, q->candidates[q->current_nof_detected].cell_id, - lte_cp_string(q->candidates[q->current_nof_detected].cp)); - q->current_nof_detected++; - } else { - /* If peak position does not allow to read SSS, return error -3 */ - return CS_FRAME_UNALIGNED; - } - } - q->current_nof_total++; - - /* Decide cell ID and CP if we detected up to nof_frames_detected */ - if (sync_get_peak_value(&q->sfind) > q->detect_threshold) { - ret = CS_CELL_DETECTED; - } else if (q->current_nof_total == q->nof_frames_total) { - if (sync_get_peak_value(&q->sfind) > CS_CELL_DETECT_THRESHOLD) { - ret = CS_CELL_DETECTED; - } else { - ret = CS_CELL_NOT_DETECTED; - q->current_nof_detected = q->current_nof_total = 0; - } - } else { - ret = 0; - } - } - } - - return ret; -} diff --git a/lte/phy/lib/ue/src/ue_mib.c b/lte/phy/lib/ue/src/ue_mib.c index 78a1228e5..b88fc20c9 100644 --- a/lte/phy/lib/ue/src/ue_mib.c +++ b/lte/phy/lib/ue/src/ue_mib.c @@ -36,21 +36,8 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/vector.h" -int ue_mib_init_1_92(ue_mib_t * q, - uint32_t cell_id, - lte_cp_t cp) -{ - lte_cell_t cell; - cell.nof_ports = MIB_MAX_PORTS; - cell.nof_prb = 6; - cell.id = cell_id; - cell.cp = cp; - return ue_mib_init(q, cell, true); -} - - int ue_mib_init(ue_mib_t * q, - lte_cell_t cell, - bool do_sync) +int ue_mib_init(ue_mib_t * q, + lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -58,8 +45,7 @@ int ue_mib_init_1_92(ue_mib_t * q, cell.nof_ports <= MIB_MAX_PORTS) { - ret = LIBLTE_ERROR; - + ret = LIBLTE_ERROR; bzero(q, sizeof(ue_mib_t)); q->sf_symbols = vec_malloc(SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); @@ -76,23 +62,6 @@ int ue_mib_init_1_92(ue_mib_t * q, } } - if (do_sync) { - if (sync_init(&q->sfind, 5*SF_LEN_PRB(cell.nof_prb), lte_symbol_sz(cell.nof_prb))) { - goto clean_exit; - } - - sync_set_threshold(&q->sfind, 1.0); // Because we are capturing 5 ms frames and there is always peak - sync_sss_en(&q->sfind, true); - sync_set_N_id_2(&q->sfind, cell.id % 3); - sync_cp_en(&q->sfind, false); - sync_set_cp(&q->sfind, cell.cp); - } - - if (cfo_init(&q->cfocorr, 5*SF_LEN_PRB(cell.nof_prb))) { - fprintf(stderr, "Error initiating CFO\n"); - goto clean_exit; - } - if (lte_fft_init(&q->fft, cell.cp, cell.nof_prb)) { fprintf(stderr, "Error initializing FFT\n"); goto clean_exit; @@ -127,7 +96,6 @@ void ue_mib_free(ue_mib_t * q) free(q->ce[i]); } } - cfo_free(&q->cfocorr); sync_free(&q->sfind); chest_dl_free(&q->chest); pbch_free(&q->pbch); @@ -140,19 +108,12 @@ void ue_mib_free(ue_mib_t * q) void ue_mib_reset(ue_mib_t * q) { - q->frame_cnt = 0; - q->last_frame_trial = 0; - + q->frame_cnt = 0; pbch_decode_reset(&q->pbch); } -void ue_mib_set_threshold(ue_mib_t * q, float threshold) -{ - sync_set_threshold(&q->sfind, threshold); -} - -int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input, - uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset) +int ue_mib_decode(ue_mib_t * q, cf_t *input, + uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset) { int ret = LIBLTE_SUCCESS; cf_t *ce_slot1[MAX_PORTS]; @@ -166,11 +127,8 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input, return LIBLTE_ERROR; } /* Reset decoder if we missed a frame */ - if ((q->last_frame_trial && (abs(q->frame_cnt - q->last_frame_trial) > 2)) || - q->frame_cnt > 16) - { - INFO("Resetting PBCH decoder: last trial %u, now is %u\n", - q->last_frame_trial, q->frame_cnt); + if (q->frame_cnt > 16) { + INFO("Resetting PBCH decoder after %d frames\n", q->frame_cnt); ue_mib_reset(q); } @@ -185,102 +143,90 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input, if (ret < 0) { fprintf(stderr, "Error decoding PBCH (%d)\n", ret); } else if (ret == 1) { - INFO("MIB decoded: %u\n", q->frame_cnt/2); + INFO("MIB decoded: %u\n", q->frame_cnt); ue_mib_reset(q); ret = MIB_FOUND; } else { - INFO("MIB not decoded: %u\n", q->frame_cnt / 2); - q->last_frame_trial = q->frame_cnt; - ret = LIBLTE_SUCCESS; + INFO("MIB not decoded: %u\n", q->frame_cnt); + q->frame_cnt++; + ret = MIB_NOTFOUND; } return ret; } -void ue_mib_get_payload(ue_mib_t *q, - uint8_t bch_payload[BCH_PAYLOAD_LEN], - uint32_t *nof_tx_ports, - uint32_t *sfn_offset) + + +int ue_mib_sync_init(ue_mib_sync_t *q, + uint32_t cell_id, + lte_cp_t cp, + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler) { - memcpy(bch_payload, q->bch_payload, sizeof(uint8_t) * BCH_PAYLOAD_LEN); - if (nof_tx_ports) { - *nof_tx_ports = q->nof_tx_ports; + lte_cell_t cell; + cell.nof_ports = MIB_MAX_PORTS; + cell.id = cell_id; + cell.cp = cp; + cell.nof_prb = MIB_NOF_PRB; + + if (ue_mib_init(&q->ue_mib, cell)) { + fprintf(stderr, "Error initiating ue_mib\n"); + return LIBLTE_ERROR; } - if (sfn_offset) { - *sfn_offset = q->sfn_offset; + if (ue_sync_init(&q->ue_sync, cell, recv_callback, stream_handler)) { + fprintf(stderr, "Error initiating ue_sync\n"); + ue_mib_free(&q->ue_mib); + return LIBLTE_ERROR; } + ue_sync_decode_sss_on_track(&q->ue_sync, true); + return LIBLTE_SUCCESS; } -int ue_mib_sync_and_decode_1_92(ue_mib_t * q, - cf_t *signal, - uint32_t nsamples) +void ue_mib_sync_free(ue_mib_sync_t *q) { + ue_mib_free(&q->ue_mib); + ue_sync_free(&q->ue_sync); +} + +void ue_mib_sync_reset(ue_mib_sync_t * q) { + ue_mib_reset(&q->ue_mib); + ue_sync_reset(&q->ue_sync); +} + +int ue_mib_sync_decode(ue_mib_sync_t * q, + uint32_t max_frames_timeout, + uint8_t bch_payload[BCH_PAYLOAD_LEN], + uint32_t *nof_tx_ports, + uint32_t *sfn_offset) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; - uint32_t peak_idx=0; - uint32_t nof_input_frames; - + cf_t *sf_buffer = NULL; + uint32_t nof_frames = 0; + int mib_ret; - if (q != NULL && - signal != NULL) + if (q != NULL) { - if (nsamples < MIB_FRAME_SIZE_SEARCH) { - fprintf(stderr, "Error: nsamples must be greater than %d\n", MIB_FRAME_SIZE_SEARCH); - return LIBLTE_ERROR; - } - - ret = LIBLTE_SUCCESS; - - if (nsamples % MIB_FRAME_SIZE_SEARCH) { - printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", MIB_FRAME_SIZE_SEARCH); - nsamples = (nsamples/MIB_FRAME_SIZE_SEARCH) * MIB_FRAME_SIZE_SEARCH; - } - nof_input_frames = nsamples/MIB_FRAME_SIZE_SEARCH; - - for (int nf=0;nfsfind, signal, nf*MIB_FRAME_SIZE_SEARCH, &peak_idx); + ret = LIBLTE_SUCCESS; + do { + mib_ret = MIB_NOTFOUND; + ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer); if (ret < 0) { - fprintf(stderr, "Error finding correlation peak (%d)\n", ret); - return -1; - } - - /* Check if we have space for reading the MIB and we are in Subframe #0 */ - if (ret == 1) - { - if (sync_sss_detected(&q->sfind)) - { - if (sync_get_sf_idx(&q->sfind) == 0) - { - if (nf*MIB_FRAME_SIZE_SEARCH + peak_idx + MIB_FRAME_SIZE_SEARCH/10 <= nsamples && - nf*MIB_FRAME_SIZE_SEARCH + peak_idx > MIB_FRAME_SIZE_SEARCH/10) - { - // PSS and SSS detected and we have space to decode the PBCH. - INFO("Trying to decode PBCH\n",0); - ret = ue_mib_decode_aligned_frame(q, - &signal[nf*MIB_FRAME_SIZE_SEARCH+peak_idx-MIB_FRAME_SIZE_SEARCH/10], - q->bch_payload, &q->nof_tx_ports, &q->sfn_offset); - } else { - printf("Not enough space for PBCH: PSS signal is at offset %d\n",peak_idx); - ret = MIB_FRAME_UNALIGNED; - } - } else { - // Wait for subframe 0 - ret = 0; - } + fprintf(stderr, "Error calling ue_sync_work()\n"); + break; + } else if (ue_sync_get_sfidx(&q->ue_sync) == 0) { + if (ret == 1) { + mib_ret = ue_mib_decode(&q->ue_mib, sf_buffer, bch_payload, nof_tx_ports, sfn_offset); } else { - INFO("SSS not detected\n",0); - ret = 0; // wait to detect it + INFO("Resetting PBCH decoder after %d frames\n", q->ue_mib.frame_cnt); + ue_mib_reset(&q->ue_mib); } - } else { - INFO("PSS not detected\n",0); - ret = 0; // wait to detect it? + nof_frames++; } - q->frame_cnt++; - } + } while (mib_ret == MIB_NOTFOUND && ret >= 0 && nof_frames < max_frames_timeout); + if (mib_ret < 0) { + ret = mib_ret; + } } - return ret; + return mib_ret; } - - diff --git a/lte/phy/lib/ue/src/ue_sync.c b/lte/phy/lib/ue/src/ue_sync.c index 3eb62a419..356ba20a1 100644 --- a/lte/phy/lib/ue/src/ue_sync.c +++ b/lte/phy/lib/ue/src/ue_sync.c @@ -40,17 +40,9 @@ #define MAX_TIME_OFFSET 128 cf_t dummy[MAX_TIME_OFFSET]; -#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) -#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE) - -#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) -#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) - -#define FIND_THRESHOLD 4.0 -#define TRACK_THRESHOLD 2.0 #define TRACK_MAX_LOST 10 #define TRACK_FRAME_SIZE 32 - +#define FIND_NOF_AVG_FRAMES 4 int ue_sync_init(ue_sync_t *q, lte_cell_t cell, @@ -59,43 +51,85 @@ int ue_sync_init(ue_sync_t *q, { int ret = LIBLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - stream_handler != NULL && - lte_cell_isvalid(&cell) && - recv_callback != NULL) + if (q != NULL && + stream_handler != NULL && + lte_nofprb_isvalid(cell.nof_prb) && + recv_callback != NULL) { ret = LIBLTE_ERROR; bzero(q, sizeof(ue_sync_t)); - q->decode_sss_on_track = false; q->stream = stream_handler; q->recv_callback = recv_callback; q->cell = cell; - - if(sync_init(&q->sfind, CURRENT_SFLEN, CURRENT_FFTSIZE)) { + q->fft_size = lte_symbol_sz(q->cell.nof_prb); + q->sf_len = SF_LEN(q->fft_size); + + if (cell.id == 1000) { + /* If the cell is unkown, decode SSS on track state */ + q->decode_sss_on_track = true; + + /* If the cell is unkown, we search PSS/SSS in 5 ms */ + q->nof_recv_sf = 5; + } else { + q->decode_sss_on_track = false; + + /* If the cell is known, we work on a 1ms basis */ + q->nof_recv_sf = 1; + } + + q->frame_len = q->nof_recv_sf*q->sf_len; + + if(sync_init(&q->sfind, q->frame_len, q->fft_size)) { fprintf(stderr, "Error initiating sync find\n"); goto clean_exit; } - if(sync_init(&q->strack, TRACK_FRAME_SIZE, CURRENT_FFTSIZE)) { + if(sync_init(&q->strack, TRACK_FRAME_SIZE, q->fft_size)) { 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_correct_cfo(&q->sfind, true); - sync_set_em_alpha(&q->sfind, 1); - - 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); - sync_correct_cfo(&q->strack, false); - - q->input_buffer = vec_malloc(5 * CURRENT_SFLEN * sizeof(cf_t)); + if (cell.id == 1000) { + /* If the cell id is unknown, enable CP detection on find */ + sync_cp_en(&q->sfind, true); + sync_cp_en(&q->strack, true); + + /* Correct CFO in all cases because both states are called always. + */ + sync_correct_cfo(&q->sfind, true); + sync_correct_cfo(&q->strack, true); + + sync_set_threshold(&q->sfind, 1.1); + sync_set_em_alpha(&q->sfind, 0.01); + q->nof_avg_find_frames = FIND_NOF_AVG_FRAMES; + sync_set_threshold(&q->strack, 2.0); + + } else { + sync_set_N_id_2(&q->sfind, cell.id%3); + sync_set_N_id_2(&q->strack, cell.id%3); + q->sfind.cp = cell.cp; + q->strack.cp = cell.cp; + sync_cp_en(&q->sfind, false); + sync_cp_en(&q->strack, false); + + /* In find phase and if the cell is known, do not average pss correlation + * because we only capture 1 subframe and do not know where the peak is. + */ + sync_set_em_alpha(&q->sfind, 1); + q->nof_avg_find_frames = 1; + sync_set_threshold(&q->sfind, 2.0); + sync_set_threshold(&q->strack, 6.0); + + /* Correct CFO in the find state but not in the track state, since is called only + * 1 every 5 subframes. Will do it in the ue_sync_get_buffer() function. + */ + sync_correct_cfo(&q->sfind, true); + sync_correct_cfo(&q->strack, false); + + } + + q->input_buffer = vec_malloc(2*q->frame_len * sizeof(cf_t)); if (!q->input_buffer) { perror("malloc"); goto clean_exit; @@ -114,7 +148,7 @@ clean_exit: } uint32_t ue_sync_sf_len(ue_sync_t *q) { - return CURRENT_SFLEN; + return q->frame_len; } void ue_sync_free(ue_sync_t *q) { @@ -150,33 +184,45 @@ void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { q->decode_sss_on_track = enabled; } +void ue_sync_set_N_id_2(ue_sync_t *q, uint32_t N_id_2) { + ue_sync_reset(q); + sync_set_N_id_2(&q->strack, N_id_2); + sync_set_N_id_2(&q->sfind, N_id_2); +} static int find_peak_ok(ue_sync_t *q) { - /* 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->nof_recv_sf; + } else { + INFO("Found peak at %d, SSS not detected\n", q->peak_idx); } - if (sync_sss_detected(&q->sfind)) { + q->frame_find_cnt++; + INFO("Found peak %d at %d, value %.3f, Cell_id: %d CP: %s\n", + q->frame_find_cnt, q->peak_idx, + sync_get_last_peak_value(&q->sfind), q->cell.id, lte_cp_string(q->cell.cp)); + + if (q->frame_find_cnt >= q->nof_avg_find_frames || q->peak_idx < 2*q->fft_size) { + INFO("Realigning frame, reading %d samples\n", q->peak_idx+q->sf_len/2); + /* Receive the rest of the subframe so that we are subframe aligned*/ + if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+q->sf_len/2) < 0) { + return LIBLTE_ERROR; + } - /* Get the subframe index (0 or 5) */ - q->sf_idx = sync_get_sf_idx(&q->sfind) + 1; - /* Reset variables */ q->frame_ok_cnt = 0; q->frame_no_cnt = 0; q->frame_total_cnt = 0; + q->frame_find_cnt = 0; /* Goto Tracking state */ - q->state = SF_TRACK; + q->state = SF_TRACK; + } - INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n", - q->peak_idx, sync_get_last_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); - } else { - INFO("Found peak at %d, SSS not detected\n", q->peak_idx); - } return 0; } @@ -191,7 +237,12 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { q->sf_idx = sync_get_sf_idx(&q->strack); } } else { - q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2); + // Adjust time offset + q->time_offset = ((int) track_idx - (int) q->strack.frame_size/2 - (int) q->strack.fft_size); + + if (q->time_offset) { + INFO("Time offset adjustment: %d samples\n", q->time_offset); + } /* If the PSS peak is beyond the frame (we sample too slowly), discard the offseted samples to align next frame */ @@ -205,7 +256,7 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { /* compute cumulative moving average time offset */ q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_total_cnt); - q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; + q->peak_idx = q->sf_len/2 + q->time_offset; q->frame_ok_cnt++; q->frame_no_cnt = 0; } @@ -218,7 +269,7 @@ int track_peak_no(ue_sync_t *q) { /* if we missed too many PSS go back to FIND */ q->frame_no_cnt++; if (q->frame_no_cnt >= TRACK_MAX_LOST) { - printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); + INFO("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); q->state = SF_FIND; } else { INFO("Tracking peak not found. Peak %.3f, %d lost\n", @@ -237,11 +288,8 @@ static int receive_samples(ue_sync_t *q) { q->time_offset = -q->time_offset; } - /* copy last part of the last subframe (use move since there could be overlapping) */ - //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], CURRENT_SFLEN - q->time_offset) < 0) { + /* Get N subframes 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], q->frame_len - q->time_offset) < 0) { return LIBLTE_ERROR; } @@ -251,6 +299,8 @@ static int receive_samples(ue_sync_t *q) { return LIBLTE_SUCCESS; } +bool first_track = true; + int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { int ret = LIBLTE_ERROR_INVALID_INPUTS; uint32_t track_idx; @@ -275,25 +325,14 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { if (ret == 1) { ret = find_peak_ok(q); - } else if (q->peak_idx != 0) { - uint32_t rlen; - if (q->peak_idx < CURRENT_SFLEN/2) { - rlen = CURRENT_SFLEN/2-q->peak_idx; - } else { - rlen = q->peak_idx; - } - if (q->recv_callback(q->stream, q->input_buffer, rlen) < 0) { - fprintf(stderr, "Error calling recv callback function\n"); - return LIBLTE_ERROR; - } - } + } break; case SF_TRACK: ret = 1; sync_sss_en(&q->strack, q->decode_sss_on_track); - q->sf_idx = (q->sf_idx + 1) % 10; + q->sf_idx = (q->sf_idx + q->nof_recv_sf) % 10; /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ if (q->sf_idx == 0 || q->sf_idx == 5) { @@ -305,8 +344,10 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { track_idx = 0; - /* track pss around the middle of the subframe, where the PSS is */ - ret = sync_find(&q->strack, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE-q->strack.frame_size/2, &track_idx); + /* track PSS/SSS around the expected PSS position */ + ret = sync_find(&q->strack, q->input_buffer, + q->frame_len - q->sf_len/2 - q->fft_size - q->strack.frame_size/2, + &track_idx); if (ret < 0) { fprintf(stderr, "Error tracking correlation peak\n"); return LIBLTE_ERROR; @@ -329,11 +370,13 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { return LIBLTE_SUCCESS; } - q->frame_total_cnt++; + q->frame_total_cnt++; } - /* Do CFO Correction and deliver the frame */ - cfo_correct(&q->sfind.cfocorr, q->input_buffer, q->input_buffer, -sync_get_cfo(&q->strack) / CURRENT_FFTSIZE); + /* Do CFO Correction if not done in track and deliver the frame */ + if (!q->strack.correct_cfo) { + cfo_correct(&q->sfind.cfocorr, q->input_buffer, q->input_buffer, -sync_get_cfo(&q->strack) / q->fft_size); + } *sf_symbols = q->input_buffer; break; @@ -350,6 +393,7 @@ void ue_sync_reset(ue_sync_t *q) { q->frame_total_cnt = 0; q->mean_time_offset = 0.0; q->time_offset = 0; + q->frame_find_cnt = 0; #ifdef MEASURE_EXEC_TIME q->mean_exec_time = 0; #endif