diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index a5fe5d474..573a9772b 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -84,6 +84,9 @@ IF(${CUHD_FIND} GREATER -1) add_executable(cell_search cell_search.c cell_search_utils.c) target_link_libraries(cell_search lte_phy cuhd ) + add_executable(cell_measurement cell_measurement.c cell_search_utils.c) + target_link_libraries(cell_measurement cuhd lte_phy) + MESSAGE(STATUS " UHD examples will be installed.") ELSE(${CUHD_FIND} GREATER -1) diff --git a/lte/phy/examples/cell_measurement.c b/lte/phy/examples/cell_measurement.c new file mode 100644 index 000000000..1e2baf724 --- /dev/null +++ b/lte/phy/examples/cell_measurement.c @@ -0,0 +1,218 @@ +/** + * + * \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 +#include + +#include "liblte/phy/phy.h" +#include "liblte/cuhd/cuhd.h" +#include "cell_search_utils.h" + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + int nof_subframes; + bool disable_plots; + int force_N_id_2; + char *uhd_args; + float uhd_freq; + float uhd_gain; +}prog_args_t; + +void args_default(prog_args_t *args) { + args->nof_subframes = -1; + args->force_N_id_2 = -1; // Pick the best + args->uhd_args = ""; + args->uhd_freq = -1.0; + args->uhd_gain = 60.0; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [aglnv] -f rx_frequency (in Hz)\n", prog); + printf("\t-a UHD args [Default %s]\n", args->uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", args->uhd_gain); + printf("\t-l Force N_id_2 [Default best]\n"); + printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(prog_args_t *args, int argc, char **argv) { + int opt; + args_default(args); + while ((opt = getopt(argc, argv, "aglnvf")) != -1) { + switch (opt) { + case 'a': + args->uhd_args = argv[optind]; + break; + case 'g': + args->uhd_gain = atof(argv[optind]); + break; + case 'f': + args->uhd_freq = atof(argv[optind]); + break; + case 'n': + args->nof_subframes = atoi(argv[optind]); + break; + case 'l': + args->force_N_id_2 = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(args, argv[0]); + exit(-1); + } + } + if (args->uhd_freq < 0) { + usage(args, argv[0]); + exit(-1); + } +} +/**********************************************************************/ + +/* TODO: Do something with the output data */ +char data[10000]; + +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 ret; + cf_t *sf_buffer; + prog_args_t prog_args; + lte_cell_t cell; + int64_t sf_cnt; + pbch_mib_t mib; + ue_sync_t ue_sync; + void *uhd; + + parse_args(&prog_args, argc, argv); + + printf("Opening UHD device...\n"); + if (cuhd_open(prog_args.uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } + /* Set receiver gain */ + cuhd_set_rx_gain(uhd, prog_args.uhd_gain); + + /* set receiver frequency */ + cuhd_set_rx_freq(uhd, (double) prog_args.uhd_freq); + cuhd_rx_wait_lo_locked(uhd); + printf("Tunning receiver to %.3f MHz\n", (double ) prog_args.uhd_freq/1000000); + + if (cell_search(uhd, prog_args.force_N_id_2, &cell, &mib)) { + fprintf(stderr, "Cell not found\n"); + exit(-1); + } + + cuhd_start_rx_stream(uhd); + + if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + + /* Initialize subframe counter */ + sf_cnt = 0; + + lte_fft_t fft; + chest_t chest; + + if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + return -1; + } + if (chest_init_LTEDL(&chest, cell)) { + fprintf(stderr, "Error initiating channel estimator\n"); + return -1; + } + + int sf_re = SF_LEN_RE(cell.nof_prb, cell.cp); + cf_t *sf_symbols = vec_malloc(sf_re * sizeof(cf_t)); + unsigned int nframes=0; + + /* Main loop */ + while (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1) { + + ret = ue_sync_get_buffer(&ue_sync, &sf_buffer); + if (ret < 0) { + fprintf(stderr, "Error calling ue_sync_work()\n"); + } + + float rssi=0, rsrp=0, rsrq=0; + + /* iodev_receive returns 1 if successfully read 1 aligned subframe */ + if (ret == 1) { + + /* Run FFT for all subframe data */ + lte_fft_run_sf(&fft, sf_buffer, sf_symbols); + + chest_measure_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync)); + rssi = VEC_CMA(chest_rssi_sf(&chest, sf_symbols),rssi,nframes); + rsrq = VEC_CMA(chest_rsrq_sf(&chest, sf_symbols, ue_sync_get_sfidx(&ue_sync)),rsrq,nframes); + rsrp = VEC_CMA(chest_rsrp_sf(&chest, ue_sync_get_sfidx(&ue_sync)),rsrp,nframes); + nframes++; + + // Plot and Printf + if ((nframes%10) == 0) { + printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, RSSI: %+5.2f dBm, RSRP: %+4.2f dBm, RSRQ: %4.2f dB\r", + ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000, + 10*log10(rssi*1000/4/cell.nof_prb/12/2)-prog_args.uhd_gain, + 10*log10(rsrp*1000)-prog_args.uhd_gain, + 10*log10(rsrq)); + } + + } else if (ret == 0) { + printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", + sync_get_peak_value(&ue_sync.sfind), + ue_sync.frame_total_cnt, ue_sync.state); + } + sf_cnt++; + } // Main loop + + ue_sync_free(&ue_sync); + cuhd_close(uhd); + printf("\nBye\n"); + exit(0); +} + + + diff --git a/lte/phy/examples/cell_search.c b/lte/phy/examples/cell_search.c index 5f3306bd8..bf3d83112 100644 --- a/lte/phy/examples/cell_search.c +++ b/lte/phy/examples/cell_search.c @@ -121,7 +121,6 @@ int main(int argc, char **argv) { void *uhd; ue_celldetect_t s; ue_celldetect_result_t found_cells[3]; - cf_t *buffer; int nof_freqs; lte_earfcn_t channels[MAX_EARFCN]; uint32_t freq; @@ -142,12 +141,6 @@ int main(int argc, char **argv) { exit(-1); } - buffer = vec_malloc(sizeof(cf_t) * 96000); - if (!buffer) { - perror("malloc"); - return LIBLTE_ERROR; - } - if (ue_celldetect_init(&s)) { fprintf(stderr, "Error initiating UE sync module\n"); exit(-1); @@ -178,7 +171,7 @@ int main(int argc, char **argv) { printf("\n"); } - n = find_cell(uhd, &s, buffer, found_cells); + n = find_all_cells(uhd, found_cells); if (n < 0) { fprintf(stderr, "Error searching cell\n"); exit(-1); @@ -186,7 +179,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], nof_frames_total, &mib)) { + if (decode_pbch(uhd, &found_cells[i], nof_frames_total, &mib)) { fprintf(stderr, "Error decoding PBCH\n"); exit(-1); } @@ -194,6 +187,8 @@ int main(int argc, char **argv) { } } } + + printf("\nBye\n"); ue_celldetect_free(&s); cuhd_close(uhd); diff --git a/lte/phy/examples/cell_search_utils.c b/lte/phy/examples/cell_search_utils.c index a5bb30adc..f7a3d1d30 100644 --- a/lte/phy/examples/cell_search_utils.c +++ b/lte/phy/examples/cell_search_utils.c @@ -40,19 +40,26 @@ #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) +int decode_pbch(void *uhd, 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)); - + int ret = LIBLTE_ERROR; + uint32_t nof_frames = 0; uint32_t flen = MIB_FRAME_SIZE; + + cf_t *buffer = vec_malloc(sizeof(cf_t) * flen); + if (!buffer) { + perror("malloc"); + goto free_and_exit; + } + + bzero(mib, sizeof(pbch_mib_t)); if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) { fprintf(stderr, "Error initiating PBCH decoder\n"); - return LIBLTE_ERROR; + goto free_and_exit; } INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0); @@ -63,95 +70,203 @@ int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uin do { if (cuhd_recv(uhd, buffer, flen, 1)<0) { fprintf(stderr, "Error receiving from USRP\n"); - return LIBLTE_ERROR; + goto free_and_exit; } - INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total); + DEBUG("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; + goto free_and_exit; } if (n == MIB_FRAME_UNALIGNED) { printf("Realigning frame\n"); - if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { + if (cuhd_recv(uhd, buffer, 1500, 1)<0) { fprintf(stderr, "Error receiving from USRP\n"); - return LIBLTE_ERROR; + 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); pbch_mib_fprint(stdout, mib, found_cell->cell_id); + ret = LIBLTE_SUCCESS; } else { - printf("\nCould not decode MIB\n"); + ret = LIBLTE_ERROR; } +free_and_exit: + free(buffer); + cuhd_stop_rx_stream(uhd); cuhd_flush_buffer(uhd); ue_mib_free(&uemib); - return LIBLTE_SUCCESS; + return ret; } -int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3]) +int find_cell(void *uhd, ue_celldetect_result_t *found_cell, uint32_t N_id_2) { - int n; + int ret = LIBLTE_ERROR; + ue_celldetect_t cd; + + cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000); + 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; + } + + ue_celldetect_set_nof_frames_detected(&cd, 50); + ue_celldetect_set_nof_frames_total(&cd, 500); + 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; + int n; do { - if (cuhd_recv(uhd, buffer, flen, 1)<0) { fprintf(stderr, "Error receiving from USRP\n"); - return LIBLTE_ERROR; + goto free_and_exit; } + + DEBUG("Scanning cell at N_id_2=%d\n",N_id_2); - n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]); + n = ue_celldetect_scan(&cd, buffer, flen, found_cell, N_id_2); 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; + goto free_and_exit; } - return LIBLTE_ERROR; + /* FIXME: What should we do here?? */ + ret = -1; + goto free_and_exit; case CS_CELL_DETECTED: - nof_detected_cells++; - if (found_cell[nof_scanned_cells].peak > 0) { + if (found_cell->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); + found_cell->cell_id, + lte_cp_string(found_cell->cp), + found_cell->peak, found_cell->mode, + cd.nof_frames_detected); } - nof_scanned_cells++; + ret = 1; + INFO("Cell found at N_id_2=%d\n",N_id_2); break; case CS_CELL_NOT_DETECTED: - nof_scanned_cells++; + ret = 0; + DEBUG("No cell found at N_id_2=%d\n",N_id_2); break; case LIBLTE_ERROR: case LIBLTE_ERROR_INVALID_INPUTS: + ret = LIBLTE_ERROR; fprintf(stderr, "Error calling cellsearch_scan()\n"); - return LIBLTE_ERROR; + goto free_and_exit; } - } while(nof_scanned_cells < 3); - + + } while(n == 0); + +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 find_all_cells(void *uhd, ue_celldetect_result_t found_cell[3]) +{ + + uint32_t N_id_2; + int ret; + int nof_detected_cells = 0; - return nof_detected_cells; + for (N_id_2=0;N_id_2<3;N_id_2++) { + ret = find_cell(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 cell_search(void *uhd, int force_N_id_2, lte_cell_t *cell, pbch_mib_t *mib) +{ + int ret; + + ue_celldetect_result_t found_cells[3]; + bzero(found_cells, 3*sizeof(ue_celldetect_result_t)); + + if (force_N_id_2 >= 0) { + ret = find_cell(uhd, &found_cells[force_N_id_2], force_N_id_2); + } else { + ret = find_all_cells(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, 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; + } + + 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(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/phy/examples/cell_search_utils.h b/lte/phy/examples/cell_search_utils.h index 2fefed105..8d5d4f5dd 100644 --- a/lte/phy/examples/cell_search_utils.h +++ b/lte/phy/examples/cell_search_utils.h @@ -29,12 +29,18 @@ #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_all_cells(void *uhd, + ue_celldetect_result_t found_cell[3]); + 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 + ue_celldetect_result_t *found_cell, + uint32_t N_id_2); + +int cell_search(void *uhd, + int force_N_id_2, + lte_cell_t *cell, + pbch_mib_t *mib); \ No newline at end of file diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c index f311443f4..30b82ed4a 100644 --- a/lte/phy/examples/iodev.c +++ b/lte/phy/examples/iodev.c @@ -84,74 +84,27 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mi q->sf_idx = 9; } else { -#ifndef DISABLE_UHD + + #ifndef DISABLE_UHD + printf("Opening UHD device...\n"); if (cuhd_open(config->uhd_args, &q->uhd)) { fprintf(stderr, "Error opening uhd\n"); return LIBLTE_ERROR; } - + /* Set receiver gain */ 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; + if (cell_search(q->uhd, config->force_N_id_2, cell, mib)) { + fprintf(stderr, "Cell not found\n"); + return LIBLTE_ERROR; } - free(buffer); - cell->cp = found_cells[max_peak_cell].cp; - cell->id = found_cells[max_peak_cell].cell_id; - cell->nof_prb = mib->nof_prb; - cell->nof_ports = mib->nof_ports; - - /* set sampling frequency */ - int srate = lte_sampling_freq_hz(cell->nof_prb); - if (srate != -1) { - cuhd_set_rx_srate(q->uhd, (double) srate); - } else { - fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb); - return LIBLTE_ERROR; - } - - DEBUG("Starting receiver...\n", 0); cuhd_start_rx_stream(q->uhd); if (ue_sync_init(&q->sframe, *cell, cuhd_recv_wrapper, q->uhd)) { @@ -159,9 +112,6 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mi 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; diff --git a/lte/phy/examples/iodev.h b/lte/phy/examples/iodev.h index bc020222f..b6c36adc5 100644 --- a/lte/phy/examples/iodev.h +++ b/lte/phy/examples/iodev.h @@ -57,6 +57,7 @@ typedef struct LIBLTE_API { uint32_t cell_id_file; uint32_t nof_prb_file; uint32_t nof_ports_file; + int force_N_id_2; float uhd_freq; float uhd_gain; diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 634416ee0..6b47f1743 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -68,13 +68,14 @@ void args_default(prog_args_t *args) { args->disable_plots = false; args->io_config.find_threshold = -1.0; args->io_config.input_file_name = NULL; + args->io_config.force_N_id_2 = -1; // Pick the best args->io_config.uhd_args = ""; args->io_config.uhd_freq = -1.0; args->io_config.uhd_gain = 60.0; } void usage(prog_args_t *args, char *prog) { - printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog); + printf("Usage: %s [cargndvtbl] [-i input_file | -f rx_frequency (in Hz)]\n", prog); printf("\t-c cell_id if reading from file [Default %d]\n", args->io_config.cell_id_file); printf("\t-p nof_prb if reading from file [Default %d]\n", args->io_config.nof_prb_file); printf("\t-o nof_ports if reading from file [Default %d]\n", args->io_config.nof_ports_file); @@ -85,6 +86,7 @@ void usage(prog_args_t *args, char *prog) { #else printf("\t UHD is disabled. CUHD library not available\n"); #endif + printf("\t-l Force N_id_2 [Default best]\n"); printf("\t-b Decode PBCH only [Default All channels]\n"); printf("\t-n nof_subframes [Default %d]\n", args->nof_subframes); printf("\t-t PSS threshold [Default %f]\n", args->io_config.find_threshold); @@ -99,7 +101,7 @@ 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, "icagfndvtbpro")) != -1) { + while ((opt = getopt(argc, argv, "icagfndvtbprol")) != -1) { switch (opt) { case 'i': args->io_config.input_file_name = argv[optind]; @@ -128,6 +130,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'n': args->nof_subframes = atoi(argv[optind]); break; + case 'l': + args->io_config.force_N_id_2 = atoi(argv[optind]); + break; case 'r': args->rnti= atoi(argv[optind]); break; @@ -144,6 +149,7 @@ void parse_args(prog_args_t *args, int argc, char **argv) { } if (args->io_config.uhd_freq < 0 && args->io_config.input_file_name == NULL) { usage(args, argv[0]); + exit(-1); } } /**********************************************************************/ @@ -177,10 +183,6 @@ int main(int argc, char **argv) { } #endif - /* Setup SIGINT handler */ - printf("\n --- Press Ctrl+C to exit --- \n"); - signal(SIGINT, sigintHandler); - /* Initialize subframe counter */ sf_cnt = 0; diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h index 2e4434fab..0eb7a4401 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest.h @@ -76,27 +76,43 @@ LIBLTE_API void chest_free(chest_t *q); LIBLTE_API int chest_set_nof_ports(chest_t *q, uint32_t nof_ports); -LIBLTE_API int chest_init_LTEDL(chest_t *q, - lte_cell_t cell); -LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, - uint32_t nslot, - uint32_t port_id, - lte_cell_t cell); +LIBLTE_API float chest_rsrp(chest_t *q, + uint32_t nslot, + uint32_t port_id); -LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, - uint32_t nslot, - lte_cell_t cell); +LIBLTE_API float chest_rsrp_sf(chest_t *q, + uint32_t sf_idx); -LIBLTE_API int chest_ref_LTEDL(chest_t *q, - lte_cell_t cell); +LIBLTE_API float chest_rssi(chest_t *q, + cf_t *input); -LIBLTE_API int chest_ce_ref(chest_t *q, +LIBLTE_API float chest_rssi_sf(chest_t *q, + cf_t *input); + +LIBLTE_API float chest_rsrq(chest_t *q, + cf_t *input, + uint32_t nslot, + uint32_t port_id); + +LIBLTE_API float chest_rsrq_sf(chest_t *q, + cf_t *input, + uint32_t sf_idx); + +LIBLTE_API int chest_measure_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref); +LIBLTE_API void chest_measure_slot(chest_t *q, + cf_t *input, + uint32_t nslot); + +LIBLTE_API void chest_measure_sf(chest_t *q, + cf_t *input, + uint32_t sf_idx); + LIBLTE_API int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, @@ -139,10 +155,50 @@ LIBLTE_API void chest_ce_fprint(chest_t *q, uint32_t nslot, uint32_t port_id); -LIBLTE_API int chest_ref_symbols(chest_t *q, - uint32_t port_id, - uint32_t nslot, - uint32_t l[2]); +LIBLTE_API int chest_ref_get_symbols(chest_t *q, + uint32_t port_id, + uint32_t nslot, + uint32_t l[2]); + + + + +/********************************************************* + * + * Downlink Channel Estimator + * + *********************************************************/ +LIBLTE_API int chest_init_LTEDL(chest_t *q, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEDL_slot_port(chest_t *q, + uint32_t nslot, + uint32_t port_id, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEDL_slot(chest_t *q, + uint32_t nslot, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEDL(chest_t *q, + lte_cell_t cell); + + +/********************************************************* + * + * Uplink Channel Estimator + * + *********************************************************/ +LIBLTE_API int chest_init_LTEUL(chest_t *q, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEUL_slot(chest_t *q, + uint32_t nslot, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEUL(chest_t *q, + lte_cell_t cell); + /* High-level API */ diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h index 51ad505ff..e237c021a 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h +++ b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h @@ -45,8 +45,7 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API{ uint32_t time_idx; uint32_t freq_idx; - cf_t simbol; - cf_t recv_simbol; + cf_t symbol; }ref_t; typedef struct LIBLTE_API{ @@ -57,13 +56,34 @@ typedef struct LIBLTE_API{ uint32_t nof_prb; ref_t *refs; cf_t *ch_est; + cf_t *recv_symbol; } refsignal_t; + +typedef struct LIBLTE_API { + float beta; // amplitude scaling + uint32_t delta_ss; // Set to 0 for PUCCH + uint32_t cyclic_shift; + uint32_t cyclic_shift_for_drms; /* From DCI 0. Set to 0 if no PDCCH with DCI 0 for the same TB + or if the initial PUSCH is semi-persisently scheduled or + if the initial PUSCH is scheduled by the RA response grant */ + bool group_hopping_en; + bool sequence_hopping_en; +} refsignal_ul_cfg_t; + + LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, lte_cell_t cell); +LIBLTE_API int refsignal_init_LTEUL_drms_pusch(refsignal_t *q, + uint32_t nof_prb, + uint32_t prb_start, + uint32_t nslot, + lte_cell_t cell, + refsignal_ul_cfg_t *drms_cfg); + LIBLTE_API void refsignal_free(refsignal_t *q); LIBLTE_API int refsignal_put(refsignal_t *q, diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 4f7efc742..52dc3a3b6 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -92,7 +92,7 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SLOT_IDX_CPNORM(idx, symbol_sz) (idx==0?(CP(symbol_sz, CPNORM_0_LEN)):(CP(symbol_sz, CPNORM_0_LEN)+idx*(symbol_sz+CP(symbol_sz, CPNORM_LEN)))) #define SLOT_IDX_CPEXT(idx, symbol_sz) (idx*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) -#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) (symbol_idx*nof_prb*RE_X_RB + sample_idx) +#define SAMPLE_IDX(nof_prb, symbol_idx, sample_idx) ((symbol_idx)*(nof_prb)*(RE_X_RB) + sample_idx) #define RS_VSHIFT(cell_id) (cell_id%6) diff --git a/lte/phy/include/liblte/phy/common/sequence.h b/lte/phy/include/liblte/phy/common/sequence.h index 972a31ebf..a3dae142b 100644 --- a/lte/phy/include/liblte/phy/common/sequence.h +++ b/lte/phy/include/liblte/phy/common/sequence.h @@ -40,7 +40,7 @@ LIBLTE_API int sequence_init(sequence_t *q, uint32_t len); LIBLTE_API void sequence_free(sequence_t *q); -LIBLTE_API int sequence_LTEPRS(sequence_t *q, +LIBLTE_API int sequence_LTE_pr(sequence_t *q, uint32_t len, uint32_t seed); diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index 0cf86b7c9..917a031b1 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -69,6 +69,10 @@ typedef struct LIBLTE_API { bool sss_en; bool normalize_en; lte_cp_t cp; + uint32_t m0; + uint32_t m1; + float m0_value; + float m1_value; }sync_t; @@ -115,6 +119,9 @@ LIBLTE_API float sync_get_cfo(sync_t *q); /* Gets the CP length estimation from the last call to synch_run() */ LIBLTE_API lte_cp_t sync_get_cp(sync_t *q); +/* Sets the CP length estimation (must do it if disabled) */ +LIBLTE_API void sync_set_cp(sync_t *q, lte_cp_t cp); + /* Enables/Disables energy normalization every frame. If disabled, uses the mean */ LIBLTE_API void sync_normalize_en(sync_t *q, bool enable); diff --git a/lte/phy/include/liblte/phy/ue/ue_celldetect.h b/lte/phy/include/liblte/phy/ue/ue_celldetect.h index 778e17508..3478ee02f 100644 --- a/lte/phy/include/liblte/phy/ue/ue_celldetect.h +++ b/lte/phy/include/liblte/phy/ue/ue_celldetect.h @@ -57,8 +57,8 @@ * TODO: Check also peak offset */ -#define CS_DEFAULT_MAXFRAMES_TOTAL 300 -#define CS_DEFAULT_MAXFRAMES_DETECTED 30 +#define CS_DEFAULT_MAXFRAMES_TOTAL 500 +#define CS_DEFAULT_MAXFRAMES_DETECTED 50 #define CS_DEFAULT_NOFFRAMES_TOTAL 100 #define CS_DEFAULT_NOFFRAMES_DETECTED 10 @@ -87,8 +87,6 @@ typedef struct LIBLTE_API { uint32_t current_nof_detected; uint32_t current_nof_total; - uint32_t current_N_id_2; - uint32_t *mode_ntimes; char *mode_counted; @@ -109,7 +107,8 @@ LIBLTE_API void ue_celldetect_reset(ue_celldetect_t *q); LIBLTE_API int ue_celldetect_scan(ue_celldetect_t *q, cf_t *signal, uint32_t nsamples, - ue_celldetect_result_t *found_cell); + ue_celldetect_result_t *found_cell, + uint32_t N_id_2); LIBLTE_API int ue_celldetect_set_nof_frames_total(ue_celldetect_t *q, uint32_t nof_frames); diff --git a/lte/phy/include/liblte/phy/ue/ue_mib.h b/lte/phy/include/liblte/phy/ue/ue_mib.h index 31624d6f9..75f8c69bb 100644 --- a/lte/phy/include/liblte/phy/ue/ue_mib.h +++ b/lte/phy/include/liblte/phy/ue/ue_mib.h @@ -55,10 +55,8 @@ #include "liblte/phy/phch/pbch.h" #include "liblte/phy/common/fft.h" -#define MIB_FIND_THRESHOLD 0.6 #define MIB_NOF_PORTS 2 - #define MIB_FRAME_SIZE 9600 #define MIB_FRAME_UNALIGNED -3 diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 3989dd69d..a0e89471a 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -35,8 +35,11 @@ typedef _Complex float cf_t; -#define EXPAVERAGE(data, average, nframes) (((data) + (average) * (nframes)) / ((nframes) + 1)) +// Cumulative moving average +#define VEC_CMA(data, average, n) ((data) + ((data) - (average)) / ((n)+1)) +// Exponential moving average +#define VEC_EMA(data, average, alpha) ((factor)*(data)+(1-alpha)*(average)) /** Return the sum of all the elements */ LIBLTE_API int vec_acc_ii(int *x, uint32_t len); diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 293d3fe2b..b34471122 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); @@ -62,8 +62,8 @@ void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id int i; fprintf(stream, "refs%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { - fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].simbol, - __imag__ q->refsignal[port_id][nslot].refs[i].simbol); + fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].symbol, + __imag__ q->refsignal[port_id][nslot].refs[i].symbol); } fprintf(stream, "];\n"); } @@ -72,8 +72,8 @@ void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t por int i; fprintf(stream, "recvsig%d=[",port_id); for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { - fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].recv_simbol, - __imag__ q->refsignal[port_id][nslot].refs[i].recv_simbol); + fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].recv_symbol[i], + __imag__ q->refsignal[port_id][nslot].recv_symbol[i]); } fprintf(stream, "];\n"); } @@ -92,7 +92,59 @@ void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) fprintf(stream, "];\n"); } -int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) { +float chest_rsrp(chest_t *q, uint32_t nslot, uint32_t port_id) { + int nof_refs = q->refsignal[port_id][nslot].nof_refs; + cf_t *ch_est = q->refsignal[port_id][nslot].ch_est; + return crealf(vec_dot_prod_conj_ccc(ch_est, ch_est, nof_refs))/nof_refs; +} + +float chest_rsrp_sf(chest_t *q, uint32_t sf_idx) { + int n,p; + float rsrp=0; + for (p=0;pnof_ports;p++) { + for (n=0;n<2;n++) { + rsrp+=chest_rsrp(q, 2*sf_idx+n, p)/(2*q->nof_ports); + } + } + return rsrp; +} + +float chest_rssi(chest_t *q, cf_t *input) { + float rssi = 0; + int i; + int l[2]; + if (q->nof_symbols == CPNORM_NSYMB) { + l[0] = 0; l[1] = 4; + } else { + l[0] = 0; l[1] = 3; + } + + for (i=0;i<2;i++) { + cf_t *tmp = &input[l[i]*q->nof_re]; + rssi += crealf(vec_dot_prod_conj_ccc(tmp, tmp, q->nof_re)); + } + return rssi; +} + +float chest_rssi_sf(chest_t *q, cf_t *input) { + int n; + int slotsz = q->nof_symbols*q->nof_re; + float rssi=0; + for (n=0;n<2;n++) { + rssi += chest_rssi(q, &input[n*slotsz]); + } + return rssi; +} + +float chest_rsrq(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id) { + return (q->nof_re/RE_X_RB) * chest_rsrp(q, nslot, port_id) / chest_rssi(q, input); +} + +float chest_rsrq_sf(chest_t *q, cf_t *input, uint32_t sf_idx) { + return (4*q->nof_ports*q->nof_re/RE_X_RB) * chest_rsrp_sf(q, sf_idx) / chest_rssi_sf(q, input); +} + +int chest_measure_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) { int fidx, tidx; cf_t known_ref, channel_ref; int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -107,10 +159,9 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index - known_ref = q->refsignal[port_id][nslot].refs[nref].simbol; + known_ref = q->refsignal[port_id][nslot].refs[nref].symbol; channel_ref = input[tidx * q->nof_re + fidx]; - q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; - + q->refsignal[port_id][nslot].recv_symbol[nref] = 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)), @@ -130,10 +181,42 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint return ret; } +void chest_measure_slot_port(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id) +{ + int i; + refsignal_t *r = &q->refsignal[port_id][nslot]; + + DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n", + nslot, port_id, r->nof_refs); + + for (i=0;inof_refs;i++) { + chest_measure_ref(q, input, nslot, port_id, i); + } +} + +void chest_measure_slot(chest_t *q, cf_t *input, uint32_t nslot) { + int p; + for (p=0;pnof_ports;p++) { + chest_measure_slot_port(q, input, nslot, p); + } +} + +void chest_measure_sf(chest_t *q, cf_t *input, uint32_t sf_idx) { + int p, n, slotsz; + slotsz = q->nof_symbols*q->nof_re; + for (p=0;pnof_ports;p++) { + for (n=0;n<2;n++) { + chest_measure_slot_port(q, &input[n*slotsz], 2*sf_idx+n, p); + } + } +} + + /* Computes channel estimates for each reference in a slot and port. * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce */ -int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) { +int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) +{ uint32_t i, j; cf_t x[2], y[MAX_NSYMB]; @@ -147,13 +230,8 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32 if (q->refsignal[port_id][nslot].nsymbols <= 2) { refsignal_t *r = &q->refsignal[port_id][nslot]; - DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n", - nslot, port_id, r->nof_refs); - - for (i=0;inof_refs;i++) { - chest_ce_ref(q, input, nslot, port_id, i); - } - + chest_measure_slot_port(q, input, nslot, port_id); + /* interpolate the symbols with references * in the freq domain */ for (i=0;insymbols;i++) { @@ -259,17 +337,58 @@ int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_p return ret; } +void chest_free(chest_t *q) { + int p, n; + for (p=0;pnof_ports;p++) { + for (n=0;nrefsignal[p][n]); + } + } +#ifdef VOLK_INTERP + for (p=0;pinterp_freq[p]); + interp_free(&q->interp_time[p]); + } +#endif + bzero(q, sizeof(chest_t)); +} + +/* Fills l[2] with the symbols in the slot nslot that contain references. + * returns the number of symbols with references (in the slot) + */ +int chest_ref_get_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) { + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME) + { + memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols); + return q->refsignal[port_id][nslot].nsymbols; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } +} + + + + + +/********************************************************************* + * + * Downlink Channel estimator + * + *********************************************************************/ int chest_init_LTEDL(chest_t *q, lte_cell_t cell) { int ret; ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); if (ret != LIBLTE_SUCCESS) { return ret; } else { - return chest_ref_LTEDL(q, cell); + return chest_ref_set_LTEDL(q, cell); } } -int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) { +int chest_ref_set_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -293,10 +412,10 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ return ret; } -int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { +int chest_ref_set_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { int p, ret; for (p=0;pnof_ports;p++) { - ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell); + ret = chest_ref_set_LTEDL_slot_port(q, nslot, p, cell); if (ret != LIBLTE_SUCCESS) { return ret; } @@ -304,10 +423,10 @@ int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { return LIBLTE_SUCCESS; } -int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) { +int chest_ref_set_LTEDL(chest_t *q, lte_cell_t cell) { int n, ret; for (n=0;nnof_ports;p++) { - for (n=0;nrefsignal[p][n]); - } - } -#ifdef VOLK_INTERP - for (p=0;pinterp_freq[p]); - interp_free(&q->interp_time[p]); - } -#endif - bzero(q, sizeof(chest_t)); -} -/* Fills l[2] with the symbols in the slot nslot that contain references. - * returns the number of symbols with references (in the slot) - */ -int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) { - - if (q != NULL && - port_id < MAX_PORTS && - nslot < NSLOTS_X_FRAME) - { - memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols); - return q->refsignal[port_id][nslot].nsymbols; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} + + +/********************************************************************* + * + * TODO: Uplink Channel estimator + * + * + *********************************************************************/ + + + + + + + + + + + + + + + + + /** High-level API diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c index 0ecdb59c1..bec652743 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ b/lte/phy/lib/ch_estimation/src/refsignal.c @@ -38,49 +38,52 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/sequence.h" +#include "ul_rs_tables.h" + #define idx(x, y) (l*nof_refs_x_symbol+i) -int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) { - int v=-1; - switch(port_id) { - case 0: - if (symbol_id == 0) { - v=0; - } else { - v=3; - } - break; - case 1: - if (symbol_id == 0) { - v=3; - } else { - v=0; - } - break; - case 2: - v=3*(ns%2); - break; - case 3: - v=3+3*(ns%2); - break; +int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) +{ + int v = -1; + switch (port_id) { + case 0: + if (symbol_id == 0) { + v = 0; + } else { + v = 3; + } + break; + case 1: + if (symbol_id == 0) { + v = 3; + } else { + v = 0; + } + break; + case 2: + v = 3 * (ns % 2); + break; + case 3: + v = 3 + 3 * (ns % 2); + break; } return v; } -uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) { - return 6*m+((v+(cell_id%6))%6); +uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) +{ + return 6 * m + ((v + (cell_id % 6)) % 6); } -int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { +int refsignal_put(refsignal_t * q, cf_t * slot_symbols) +{ uint32_t i; uint32_t fidx, tidx; - if (q != NULL && - slot_symbols != NULL) - { - for (i=0;inof_refs;i++) { - fidx = q->refs[i].freq_idx; // reference frequency index - tidx = q->refs[i].time_idx; // reference time index - slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; + if (q != NULL && slot_symbols != NULL) { + for (i = 0; i < q->nof_refs; i++) { + fidx = q->refs[i].freq_idx; // reference frequency index + tidx = q->refs[i].time_idx; // reference time index + slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].symbol; } return LIBLTE_SUCCESS; } else { @@ -91,8 +94,9 @@ int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 * */ -int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, - lte_cell_t cell) { +int refsignal_init_LTEDL(refsignal_t * q, uint32_t port_id, uint32_t nslot, + lte_cell_t cell) +{ uint32_t c_init; uint32_t ns, l, lp[2]; @@ -104,12 +108,10 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, uint32_t mp; uint32_t nof_refs_x_symbol, nof_ref_symbols; - if (q != NULL && - port_id < MAX_PORTS && - nslot < NSLOTS_X_FRAME && - lte_cell_isvalid(&cell)) - { - + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) { + bzero(q, sizeof(refsignal_t)); bzero(&seq, sizeof(sequence_t)); @@ -131,7 +133,7 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; q->nsymbols = nof_ref_symbols; - q->voffset = cell.id%6; + q->voffset = cell.id % 6; q->nof_prb = cell.nof_prb; q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols); @@ -151,12 +153,17 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, goto free_and_exit; } + q->recv_symbol = vec_malloc(q->nof_refs * sizeof(cf_t)); + if (!q->recv_symbol) { + goto free_and_exit; + } + ns = nslot; for (l = 0; l < nof_ref_symbols; l++) { c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1) - + 2 * cell.id + N_cp; - ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init); + + 2 * cell.id + N_cp; + ret = sequence_LTE_pr(&seq, 2 * 2 * MAX_PRB, c_init); if (ret != LIBLTE_SUCCESS) { goto free_and_exit; } @@ -167,27 +174,201 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, mp = i + MAX_PRB - cell.nof_prb; /* generate signal */ - __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); - __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + __real__ q->refs[idx(l, i)].symbol = + (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); + __imag__ q->refs[idx(l, i)].symbol = + (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); /* mapping to resource elements */ - q->refs[idx(l,i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); - q->refs[idx(l,i)].time_idx = lp[l]; + q->refs[idx(l, i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); + q->refs[idx(l, i)].time_idx = lp[l]; } } ret = LIBLTE_SUCCESS; } free_and_exit: if (ret != LIBLTE_ERROR_INVALID_INPUTS) { - sequence_free(&seq); + sequence_free(&seq); + } + if (ret == LIBLTE_ERROR) { + refsignal_free(q); + } + return ret; +} + +// n_drms_2 table 5.5.2.1.1-1 from 36.211 +uint32_t n_drms_2[8] = { 0, 6, 3, 4, 2, 8, 10, 9 }; + +// n_drms_1 table 5.5.2.1.1-2 from 36.211 +uint32_t n_drms_1[8] = { 0, 2, 3, 4, 6, 8, 9, 10 }; + + +/* Generation of the reference signal sequence according to Section 5.5.1 of 36.211 */ +int rs_sequence(ref_t * refs, uint32_t len, float alpha, uint32_t ns, uint32_t cell_id, + refsignal_ul_cfg_t * cfg) +{ + uint32_t i; + + // Calculate u and v + uint32_t u, v; + uint32_t f_ss = (((cell_id % 30) + cfg->delta_ss) % 30); + if (cfg->group_hopping_en) { + sequence_t seq; + sequence_LTE_pr(&seq, cell_id / 30, 160); + uint32_t f_gh = 0; + for (i = 0; i < 8; i++) { + f_gh += seq.c[8 * ns + i] << i; + } + sequence_free(&seq); + u = ((f_gh%30) + f_ss) % 30; + } else { + u = f_ss % 30; + } + + if (len < 6 * RE_X_RB) { + v = 0; + } else { + if (!cfg->group_hopping_en && cfg->sequence_hopping_en) { + sequence_t seq; + sequence_LTE_pr(&seq, ((cell_id / 30) << 5) + f_ss, 20); + v = seq.c[ns]; + sequence_free(&seq); + } else { + v = 0; + } + } + if (len >= 3 * RE_X_RB) { + uint32_t n_sz; + uint32_t q; + float q_hat; + /* get largest prime n_zc 0; i--) { + if (prime_numbers[i] < len) { + n_sz = prime_numbers[i]; + break; + } + } + q_hat = (float) n_sz *(u + 1) / 31; + if ((((uint32_t) (2 * q_hat)) % 2) == 0) { + q = (uint32_t) (q_hat + 0.5) + v; + } else { + q = (uint32_t) (q_hat + 0.5) - v; + } + cf_t *x_q = malloc(sizeof(cf_t) * n_sz); + if (!x_q) { + perror("malloc"); + return LIBLTE_ERROR; + } + for (i = 0; i < n_sz; i++) { + x_q[i] = + cexpf(-I * M_PI * (float) q * (float) i * ((float) i + 1) / n_sz); + } + for (i = 0; i < len; i++) { + refs[i].symbol = cfg->beta * cexpf(I * alpha * i) * x_q[i % n_sz]; + } + free(x_q); + } else { + if (len == RE_X_RB) { + for (i = 0; i < len; i++) { + refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_12[u][i] * M_PI / 4 + alpha * i)); + } + } else { + for (i = 0; i < len; i++) { + refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_24[u][i] * M_PI / 4 + alpha * i)); + } + } + } + + return LIBLTE_SUCCESS; +} + +/** Initializes refsignal_t object according to 3GPP 36.211 5.5.2 + * + */ +int refsignal_init_LTEUL_drms_pusch(refsignal_t * q, uint32_t nof_prb, uint32_t prb_start, + uint32_t nslot, lte_cell_t cell, refsignal_ul_cfg_t * cfg) +{ + + uint32_t i; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t n_prs; + uint32_t M_sc; + float alpha; + + if (q != NULL && nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) { + + bzero(q, sizeof(refsignal_t)); + + M_sc = nof_prb * RE_X_RB; + + q->nof_refs = M_sc; + q->nsymbols = 1; + q->voffset = cell.id % 6; + q->nof_prb = cell.nof_prb; + + q->symbols_ref = malloc(sizeof(uint32_t) * 1); + if (!q->symbols_ref) { + perror("malloc"); + goto free_and_exit; + } + + if (CP_ISNORM(cell.cp)) { + q->symbols_ref[0] = 3; + } else { + q->symbols_ref[0] = 2; + } + + q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); + if (!q->refs) { + goto free_and_exit; + } + q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); + if (!q->ch_est) { + goto free_and_exit; + } + + /* Calculate n_prs */ + uint32_t c_init; + sequence_t seq; + c_init = ((cell.id / 30) << 5) + (((cell.id % 30) + cfg->delta_ss) % 30); + ret = sequence_LTE_pr(&seq, 8 * CP_NSYMB(cell.cp) * 20, c_init); + if (ret != LIBLTE_SUCCESS) { + goto free_and_exit; + } + n_prs = 0; + for (i = 0; i < 8; i++) { + n_prs += (seq.c[8 * CP_NSYMB(cell.cp) * nslot + i] << i); + } + sequence_free(&seq); + + // Calculate cyclic shift alpha + uint32_t n_cs = + (n_drms_1[cfg->cyclic_shift] + + n_drms_2[cfg->cyclic_shift_for_drms] + n_prs) % 12; + alpha = 2 * M_PI * (n_cs) / 12; + + if (rs_sequence(q->refs, M_sc, alpha, cell.id, nslot, cfg)) { + fprintf(stderr, "Error generating RS sequence\n"); + goto free_and_exit; + } + /* mapping to resource elements */ + for (i=0;irefs[i].freq_idx = prb_start*RE_X_RB + i; + q->refs[i].time_idx = q->symbols_ref[0]; + } + + ret = LIBLTE_SUCCESS; } +free_and_exit: if (ret == LIBLTE_ERROR) { refsignal_free(q); } return ret; } -void refsignal_free(refsignal_t *q) { + +void refsignal_free(refsignal_t * q) +{ if (q->symbols_ref) { free(q->symbols_ref); } @@ -199,5 +380,3 @@ void refsignal_free(refsignal_t *q) { } bzero(q, sizeof(refsignal_t)); } - - diff --git a/lte/phy/lib/ch_estimation/src/ul_rs_tables.h b/lte/phy/lib/ch_estimation/src/ul_rs_tables.h new file mode 100644 index 000000000..63f99d79b --- /dev/null +++ b/lte/phy/lib/ch_estimation/src/ul_rs_tables.h @@ -0,0 +1,127 @@ +/** + * + * \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 + +// Phi values for M_sc=12 Table 5.5.1.2-1 in 36.211 +int phi_M_sc_12[30][12] = {{-1, 1, 3,-3, 3, 3, 1, 1, 3, 1,-3, 3}, + { 1, 1, 3, 3, 3,-1, 1,-3,-3, 1,-3, 3}, + { 1, 1,-3,-3,-3,-1,-3,-3, 1,-3, 1,-1}, + {-1, 1, 1, 1, 1,-1,-3,-3, 1,-3, 3,-1}, + {-1, 3, 1,-1, 1,-1,-3,-1, 1,-1, 1, 3}, + { 1,-3, 3,-1,-1, 1, 1,-1,-1, 3,-3, 1}, + {-1, 3,-3,-3,-3, 3, 1,-1, 3, 3,-3, 1}, + {-3,-1,-1,-1, 1,-3, 3,-1, 1,-3, 3, 1}, + { 1,-3, 3, 1,-1,-1,-1, 1, 1, 3,-1, 1}, + { 1,-3,-1, 3, 3,-1,-3, 1, 1, 1, 1, 1}, + {-1, 3,-1, 1, 1,-3,-3,-1,-3,-3, 3,-1}, + { 3, 1,-1,-1, 3, 3,-3, 1, 3, 1, 3, 3}, + { 1,-3, 1, 1,-3, 1, 1, 1,-3,-3,-3, 1}, + { 3, 3,-3, 3,-3, 1, 1, 3,-1,-3, 3, 3}, + {-3, 1,-1,-3,-1, 3, 1, 3, 3, 3,-1, 1}, + { 3,-1, 1,-3,-1,-1, 1, 1, 3, 1,-1,-3}, + { 1, 3, 1,-1, 1, 3, 3, 3,-1,-1, 3,-1}, + {-3, 1, 1, 3,-3, 3,-3,-3, 3, 1, 3,-1}, + {-3, 3, 1, 1,-3, 1,-3,-3,-1,-1, 1,-3}, + {-1, 3, 1, 3, 1,-1,-1, 3,-3,-1,-3,-1}, + {-1,-3, 1, 1, 1, 1, 3, 1,-1, 1,-3,-1}, + {-1, 3,-1, 1,-3,-3,-3,-3,-3, 1,-1,-3}, + { 1, 1,-3,-3,-3,-3,-1, 3,-3, 1,-3, 3}, + { 1, 1,-1,-3,-1,-3, 1,-1, 1, 3,-1, 1}, + { 1, 1, 3, 1, 3, 3,-1, 1,-1,-3,-3, 1}, + { 1,-3, 3, 3, 1, 3, 3, 1,-3,-1,-1, 3}, + { 1, 3,-3,-3, 3,-3, 1,-1,-1, 3,-1,-3}, + {-3,-1,-3,-1,-3, 3, 1,-1, 1, 3,-3,-3}, + {-1, 3,-3, 3,-1, 3, 3,-3, 3, 3,-1,-1}, + { 3,-3,-3,-1,-1,-3,-1, 3,-3, 3, 1,-1}}; + +// Phi values for M_sc=24 Table 5.5.1.2-2 in 36.211 +int phi_M_sc_24[30][24] = {{-1, 3, 1,-3, 3,-1, 1, 3,-3, 3, 1, 3,-3, 3, 1, 1,-1, 1, 3,-3, 3,-3,-1,-3}, + {-3, 3,-3,-3,-3, 1,-3,-3, 3,-1, 1, 1, 1, 3, 1,-1, 3,-3,-3, 1, 3, 1, 1,-3}, + { 3,-1, 3, 3, 1, 1,-3, 3, 3, 3, 3, 1,-1, 3,-1, 1, 1,-1,-3,-1,-1, 1, 3, 3}, + {-1,-3, 1, 1, 3,-3, 1, 1,-3,-1,-1, 1, 3, 1, 3, 1,-1, 3, 1, 1,-3,-1,-3,-1}, + {-1,-1,-1,-3,-3,-1, 1, 1, 3, 3,-1, 3,-1, 1,-1,-3, 1,-1,-3,-3, 1,-3,-1,-1}, + {-3, 1, 1, 3,-1, 1, 3, 1,-3, 1,-3, 1, 1,-1,-1, 3,-1,-3, 3,-3,-3,-3, 1, 1}, + { 1, 1,-1,-1, 3,-3,-3, 3,-3, 1,-1,-1, 1,-1, 1, 1,-1,-3,-1, 1,-1, 3,-1,-3}, + {-3, 3, 3,-1,-1,-3,-1, 3, 1, 3, 1, 3, 1, 1,-1, 3, 1,-1, 1, 3,-3,-1,-1, 1}, + {-3, 1, 3,-3, 1,-1,-3, 3,-3, 3,-1,-1,-1,-1, 1,-3,-3,-3, 1,-3,-3,-3, 1,-3}, + { 1, 1,-3, 3, 3,-1,-3,-1, 3,-3, 3, 3, 3,-1, 1, 1,-3, 1,-1, 1, 1,-3, 1, 1}, + {-1, 1,-3,-3, 3,-1, 3,-1,-1,-3,-3,-3,-1,-3,-3, 1,-1, 1, 3, 3,-1, 1,-1, 3}, + { 1, 3, 3,-3,-3, 1, 3, 1,-1,-3,-3,-3, 3, 3,-3, 3, 3,-1,-3, 3,-1, 1,-3, 1}, + { 1, 3, 3, 1, 1, 1,-1,-1, 1,-3, 3,-1, 1, 1,-3, 3, 3,-1,-3, 3,-3,-1,-3,-1}, + { 3,-1,-1,-1,-1,-3,-1, 3, 3, 1,-1, 1, 3, 3, 3,-1, 1, 1,-3, 1, 3,-1,-3, 3}, + {-3,-3, 3, 1, 3, 1,-3, 3, 1, 3, 1, 1, 3, 3,-1,-1,-3, 1,-3,-1, 3, 1, 1, 3}, + {-1,-1, 1,-3, 1, 3,-3, 1,-1,-3,-1, 3, 1, 3, 1,-1,-3,-3,-1,-1,-3,-3,-3,-1}, + {-1,-3, 3,-1,-1,-1,-1, 1, 1,-3, 3, 1, 3, 3, 1,-1, 1,-3, 1,-3, 1, 1,-3,-1}, + { 1, 3,-1, 3, 3,-1,-3, 1,-1,-3, 3, 3, 3,-1, 1, 1, 3,-1,-3,-1, 3,-1,-1,-1}, + { 1, 1, 1, 1, 1,-1, 3,-1,-3, 1, 1, 3,-3, 1,-3,-1, 1, 1,-3,-3, 3, 1, 1,-3}, + { 1, 3, 3, 1,-1,-3, 3,-1, 3, 3, 3,-3, 1,-1, 1,-1,-3,-1, 1, 3,-1, 3,-3,-3}, + {-1,-3, 3,-3,-3,-3,-1,-1,-3,-1,-3, 3, 1, 3,-3,-1, 3,-1, 1,-1, 3,-3, 1,-1}, + {-3,-3, 1, 1,-1, 1,-1, 1,-1, 3, 1,-3,-1, 1,-1, 1,-1,-1, 3, 3,-3,-1, 1,-3}, + {-3,-1,-3, 3, 1,-1,-3,-1,-3,-3, 3,-3, 3,-3,-1, 1, 3, 1,-3, 1, 3, 3,-1,-3}, + {-1,-1,-1,-1, 3, 3, 3, 1, 3, 3,-3, 1, 3,-1, 3,-1, 3, 3,-3, 3, 1,-1, 3, 3}, + { 1,-1, 3, 3,-1,-3, 3,-3,-1,-1, 3,-1, 3,-1,-1, 1, 1, 1, 1,-1,-1,-3,-1, 3}, + { 1,-1, 1,-1, 3,-1, 3, 1, 1,-1,-1,-3, 1, 1,-3, 1, 3,-3, 1, 1,-3,-3,-1,-1}, + {-3,-1, 1, 3, 1, 1,-3,-1,-1,-3, 3,-3, 3, 1,-3, 3,-3, 1,-1, 1,-3, 1, 1, 1}, + {-1,-3, 3, 3, 1, 1, 3,-1,-3,-1,-1,-1, 3, 1,-3,-3,-1, 3,-3,-1,-3,-1,-3,-1}, + {-1,-3,-1,-1, 1,-3,-1,-1, 1,-1,-3, 1, 1,-3, 1,-3,-3, 3, 1, 1,-1, 3,-1,-1}, + { 1, 1,-1,-1,-3,-1, 3,-1, 3,-1, 1, 3, 1,-1, 3, 1, 3,-3,-3, 1,-1,-1, 1, 3}}; + +// Prime numbers used for Section 5.5.1.1 of 36.211 +#define NOF_PRIME_NUMBERS 309 +uint32_t prime_numbers[NOF_PRIME_NUMBERS] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997,1009,1013, + 1019,1021,1031,1033,1039,1049,1051,1061,1063,1069, + 1087,1091,1093,1097,1103,1109,1117,1123,1129,1151, + 1153,1163,1171,1181,1187,1193,1201,1213,1217,1223, + 1229,1231,1237,1249,1259,1277,1279,1283,1289,1291, + 1297,1301,1303,1307,1319,1321,1327,1361,1367,1373, + 1381,1399,1409,1423,1427,1429,1433,1439,1447,1451, + 1453,1459,1471,1481,1483,1487,1489,1493,1499,1511, + 1523,1531,1543,1549,1553,1559,1567,1571,1579,1583, + 1597,1601,1607,1609,1613,1619,1621,1627,1637,1657, + 1663,1667,1669,1693,1697,1699,1709,1721,1723,1733, + 1741,1747,1753,1759,1777,1783,1787,1789,1801,1811, + 1823,1831,1847,1861,1867,1871,1873,1877,1879,1889, + 1901,1907,1913,1931,1933,1949,1951,1973,1979,1987, + 1993,1997,1999,2003,2011,2017,2027,2029,2039}; + diff --git a/lte/phy/lib/ch_estimation/test/CMakeLists.txt b/lte/phy/lib/ch_estimation/test/CMakeLists.txt index 8ac180007..e0990fe53 100644 --- a/lte/phy/lib/ch_estimation/test/CMakeLists.txt +++ b/lte/phy/lib/ch_estimation/test/CMakeLists.txt @@ -20,13 +20,26 @@ # ######################################################################## -# Channel Estimation TEST +# Downlink Channel Estimation TEST ######################################################################## -ADD_EXECUTABLE(chest_test chest_test.c) -TARGET_LINK_LIBRARIES(chest_test lte_phy) +ADD_EXECUTABLE(chest_test_dl chest_test_dl.c) +TARGET_LINK_LIBRARIES(chest_test_dl lte_phy) + +ADD_TEST(chest_test_dl_cellid0 chest_test_dl -c 0) +ADD_TEST(chest_test_dl_cellid1 chest_test_dl -c 1) +ADD_TEST(chest_test_dl_cellid2 chest_test_dl -c 2) + +######################################################################## +# Uplink Channel Estimation TEST +######################################################################## + +#ADD_EXECUTABLE(chest_test_ul chest_test_ul.c) +#TARGET_LINK_LIBRARIES(chest_test_ul lte_phy) + +#ADD_TEST(chest_test_ul_cellid0 chest_ul_test -c 0) +#ADD_TEST(chest_test_ul_cellid1 chest_ul_test -c 1) +#ADD_TEST(chest_test_ul_cellid2 chest_ul_test -c 2) -ADD_TEST(chest_test_all_cellids chest_test) -ADD_TEST(chest_test_cellid chest_test -c 1) diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test_dl.c similarity index 100% rename from lte/phy/lib/ch_estimation/test/chest_test.c rename to lte/phy/lib/ch_estimation/test/chest_test_dl.c diff --git a/lte/phy/lib/ch_estimation/test/chest_test_ul.c b/lte/phy/lib/ch_estimation/test/chest_test_ul.c new file mode 100644 index 000000000..72ea85c80 --- /dev/null +++ b/lte/phy/lib/ch_estimation/test/chest_test_ul.c @@ -0,0 +1,249 @@ +/** + * + * \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/phy.h" + +lte_cell_t cell = { + 6, // nof_prb + MAX_PORTS, // nof_ports + 1000, // cell_id + CPNORM // cyclic prefix +}; + +char *output_matlab = NULL; + +void usage(char *prog) { + printf("Usage: %s [recov]\n", prog); + + printf("\t-r nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-e extended cyclic prefix [Default normal]\n"); + + printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id); + + printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None"); + printf("\t-v increase verbosity\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "recov")) != -1) { + switch(opt) { + case 'r': + cell.nof_prb = atoi(argv[optind]); + break; + case 'e': + cell.cp = CPEXT; + break; + case 'c': + cell.id = atoi(argv[optind]); + break; + case 'o': + output_matlab = argv[optind]; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int check_mse(float mod, float arg, int n_port) { + INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port); + switch(n_port) { + case 0: + if (mod > 0.029) { + return -1; + } + if (arg > 0.029) { + return -1; + } + break; + case 1: + if (mod > 0.012) { + return -1; + } + if (arg > 0.012) { + return -1; + } + break; + case 2: + case 3: + if (mod > 3.33) { + return -1; + } + if (arg > 0.63) { + return -1; + } + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char **argv) { + chest_t eq; + cf_t *input = NULL, *ce = NULL, *h = NULL; + refsignal_t refs; + int i, j, n_port, n_slot, cid, num_re; + int ret = -1; + int max_cid; + FILE *fmatlab = NULL; + float mse_mag, mse_phase; + + parse_args(argc,argv); + + if (output_matlab) { + fmatlab=fopen(output_matlab, "w"); + if (!fmatlab) { + perror("fopen"); + goto do_exit; + } + } + + num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp); + + input = malloc(num_re * sizeof(cf_t)); + if (!input) { + perror("malloc"); + goto do_exit; + } + h = malloc(num_re * sizeof(cf_t)); + if (!h) { + perror("malloc"); + goto do_exit; + } + ce = malloc(num_re * sizeof(cf_t)); + if (!ce) { + perror("malloc"); + goto do_exit; + } + + if (cell.id == 1000) { + cid = 0; + max_cid = 504; + } else { + cid = cell.id; + max_cid = cell.id; + } + + while(cid <= max_cid) { + cell.id = cid; + if (chest_init_LTEUL(&eq, cell)) { + fprintf(stderr, "Error initializing equalizer\n"); + goto do_exit; + } + + for (n_slot=0;n_slot #include #include #include +#include "liblte/phy/common/sequence.h" + #define Nc 1600 @@ -75,7 +74,7 @@ void generate_prs_c(sequence_t *q, uint32_t seed) { free(x2); } -int sequence_LTEPRS(sequence_t *q, uint32_t len, uint32_t seed) { +int sequence_LTE_pr(sequence_t *q, uint32_t len, uint32_t seed) { if (sequence_init(q, len)) { return LIBLTE_ERROR; } diff --git a/lte/phy/lib/modem/test/soft_demod_test.c b/lte/phy/lib/modem/test/soft_demod_test.c index 96b76c5b0..5849f4693 100644 --- a/lte/phy/lib/modem/test/soft_demod_test.c +++ b/lte/phy/lib/modem/test/soft_demod_test.c @@ -189,7 +189,7 @@ int main(int argc, char **argv) { /* compute exponentially averaged execution time */ if (n > 0) { - mean_texec = EXPAVERAGE((float) t[0].tv_usec, mean_texec, n-1); + mean_texec = VEC_CMA((float) t[0].tv_usec, mean_texec, n-1); } /* check MSE */ diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 2c21b7dd6..87d84f7c7 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -559,7 +559,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, } while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop); - q->average_nof_iterations = EXPAVERAGE((float) q->nof_iterations, + q->average_nof_iterations = VEC_CMA((float) q->nof_iterations, q->average_nof_iterations, q->average_nof_iterations_n); q->average_nof_iterations_n++; diff --git a/lte/phy/lib/phch/src/sequences.c b/lte/phy/lib/phch/src/sequences.c index 499eb1cd0..fe362e2fe 100644 --- a/lte/phy/lib/phch/src/sequences.c +++ b/lte/phy/lib/phch/src/sequences.c @@ -35,7 +35,7 @@ */ int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); + return sequence_LTE_pr(seq, CP_ISNORM(cp)?1920:1728, cell_id); } /** @@ -43,7 +43,7 @@ int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) { */ int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); + return sequence_LTE_pr(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -52,7 +52,7 @@ int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { */ int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); + return sequence_LTE_pr(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } /** @@ -60,7 +60,7 @@ int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { */ int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); + return sequence_LTE_pr(seq, len, (nslot/2) * 512 + cell_id); } /** @@ -68,5 +68,5 @@ int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t l */ int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); + return sequence_LTE_pr(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); } diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index 9cb7b53fa..3f42d7872 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -254,7 +254,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value) #endif /* Find maximum of the absolute value of the correlation */ - corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len); + corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len-1); if (corr_peak_value) { *corr_peak_value = cabsf(q->conv_output[corr_peak_pos]); } diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 34e4bd28e..cd99cf496 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -55,6 +55,7 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) { bzero(q, sizeof(sync_t)); q->detect_cp = true; q->normalize_en = true; + q->mean_energy = 1.0; q->sss_en = true; q->N_id_2 = 1000; q->N_id_1 = 1000; @@ -144,6 +145,9 @@ void sync_cp_en(sync_t *q, bool enabled) { lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } +void sync_set_cp(sync_t *q, lte_cp_t cp) { + q->cp = cp; +} /* CP detection algorithm taken from: * "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver" @@ -183,9 +187,7 @@ static lte_cp_t detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos) } int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { - uint32_t m0, m1; int sss_idx, ret; - float m0_value, m1_value; sss_synch_set_N_id_2(&q->sss, q->N_id_2); @@ -195,17 +197,15 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { /* Make sure we have enough room to find SSS sequence */ sss_idx = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, q->cp)); - 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_SUCCESS; } - /* try Normal CP length */ - sss_synch_m0m1(&q->sss, &input[sss_idx], &m0, &m0_value, &m1, &m1_value); + sss_synch_m0m1(&q->sss, &input[sss_idx], &q->m0, &q->m0_value, &q->m1, &q->m1_value); - q->sf_idx = sss_synch_subframe(m0, m1); - ret = sss_synch_N_id_1(&q->sss, m0, m1); + q->sf_idx = sss_synch_subframe(q->m0, q->m1); + ret = sss_synch_N_id_1(&q->sss, q->m0, q->m1); if (ret >= 0) { q->N_id_1 = (uint32_t) ret; } else { @@ -223,14 +223,14 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit int ret = LIBLTE_ERROR_INVALID_INPUTS; - float peak_unnormalized, energy; + float peak_unnormalized=0, energy=1; if (q != NULL && input != NULL && lte_N_id_2_isvalid(q->N_id_2) && fft_size_isvalid(q->fft_size)) { - uint32_t peak_pos; + int peak_pos; if (peak_position) { *peak_position = 0; @@ -239,14 +239,17 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit pss_synch_set_N_id_2(&q->pss, q->N_id_2); peak_pos = pss_synch_find_pss(&q->pss, &input[find_offset], &peak_unnormalized); - + if (peak_pos < 0) { + fprintf(stderr, "Error calling finding PSS sequence\n"); + return LIBLTE_ERROR; + } 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]; energy = sqrtf(crealf(vec_dot_prod_conj_ccc(pss_ptr, pss_ptr, q->fft_size)) / (q->fft_size)); - q->mean_energy = EXPAVERAGE(energy, q->mean_energy, q->frame_cnt); + q->mean_energy = VEC_CMA(energy, q->mean_energy, q->frame_cnt); } else { if (q->mean_energy == 0.0) { q->mean_energy = 1.0; @@ -256,7 +259,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit /* Normalize and compute mean peak value */ q->peak_value = peak_unnormalized/energy; - q->mean_peak_value = EXPAVERAGE(q->peak_value, q->mean_peak_value, q->frame_cnt); + q->mean_peak_value = VEC_CMA(q->peak_value, q->mean_peak_value, q->frame_cnt); q->frame_cnt++; /* If peak is over threshold, compute CFO and SSS */ @@ -264,25 +267,27 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit if (find_offset + peak_pos >= q->fft_size) { q->cfo = pss_synch_cfo_compute(&q->pss, &input[find_offset+peak_pos-q->fft_size]); if (q->sss_en) { - if (sync_sss(q, input, find_offset + peak_pos) < 0) { + ret = sync_sss(q, input, find_offset + peak_pos); + if (ret < 0) { fprintf(stderr, "Error synchronizing with SSS\n"); return LIBLTE_ERROR; - } - } + } + } else { + ret = 1; + } } else { INFO("Warning: no space for CFO computation\n",0); } if (peak_position) { - *peak_position = peak_pos; + *peak_position = (uint32_t) peak_pos; } - ret = 1; } else { ret = LIBLTE_SUCCESS; } - - INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f energy=%.3f threshold=%.2f sf_idx=%d\n", - ret, q->N_id_2, peak_pos, q->peak_value, energy, q->threshold, q->sf_idx); + + INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f/%.2f=%.2f threshold=%.2f sf_idx=%d offset=%d\n", + ret, q->N_id_2, peak_pos, peak_unnormalized,energy,q->peak_value, q->threshold, q->sf_idx, find_offset); } 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 176780edb..b91833d27 100644 --- a/lte/phy/lib/sync/test/pss_usrp.c +++ b/lte/phy/lib/sync/test/pss_usrp.c @@ -161,7 +161,7 @@ int main(int argc, char **argv) { fft_size); float x = peak_value/y; - mean_peak = EXPAVERAGE(x, mean_peak, frame_cnt); + mean_peak = VEC_CMA(x, mean_peak, frame_cnt); if (x >= threshold) { nof_det++; diff --git a/lte/phy/lib/ue/src/ue_celldetect.c b/lte/phy/lib/ue/src/ue_celldetect.c index fa4c75e82..ca20b38f1 100644 --- a/lte/phy/lib/ue/src/ue_celldetect.c +++ b/lte/phy/lib/ue/src/ue_celldetect.c @@ -109,7 +109,6 @@ void ue_celldetect_reset(ue_celldetect_t * q) { q->current_nof_detected = 0; q->current_nof_total = 0; - q->current_N_id_2 = 0; } void ue_celldetect_set_threshold(ue_celldetect_t * q, float threshold) @@ -189,7 +188,8 @@ void decide_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell) int ue_celldetect_scan(ue_celldetect_t * q, cf_t *signal, uint32_t nsamples, - ue_celldetect_result_t *found_cell) + ue_celldetect_result_t *found_cell, + uint32_t N_id_2) { int ret = LIBLTE_ERROR_INVALID_INPUTS; uint32_t peak_idx; @@ -198,7 +198,8 @@ int ue_celldetect_scan(ue_celldetect_t * q, if (q != NULL && signal != NULL && - nsamples >= 4800) + nsamples >= 4800 && + lte_N_id_2_isvalid(N_id_2)) { ret = LIBLTE_SUCCESS; @@ -209,16 +210,18 @@ int ue_celldetect_scan(ue_celldetect_t * q, nof_input_frames = nsamples/4800; for (uint32_t nf=0;nfsfind, q->current_N_id_2); + if (sync_set_N_id_2(&q->sfind, N_id_2)) { + return LIBLTE_ERROR; + } INFO("[%3d/%3d]: Searching cells with N_id_2=%d. %d frames\n", - q->current_nof_detected, q->current_nof_total, q->current_N_id_2, nof_input_frames); + q->current_nof_detected, q->current_nof_total, N_id_2, nof_input_frames); /* Find peak and cell id */ ret = sync_find(&q->sfind, &signal[nf*4800], 0, &peak_idx); if (ret < 0) { fprintf(stderr, "Error finding correlation peak (%d)\n", ret); - return -1; + return LIBLTE_ERROR; } /* If peak position does not allow to read SSS, return error -3 */ @@ -249,17 +252,13 @@ int ue_celldetect_scan(ue_celldetect_t * q, /* Decide cell ID and CP if we detected up to nof_frames_detected */ if (q->current_nof_detected == q->nof_frames_detected) { decide_cell(q, found_cell); - q->current_N_id_2++; q->current_nof_detected = q->current_nof_total = 0; ret = CS_CELL_DETECTED; - /* Or go to the next N_id_2 if we didn't detect the cell */ } else if (q->current_nof_total == q->nof_frames_total) { - q->current_N_id_2++; q->current_nof_detected = q->current_nof_total = 0; ret = CS_CELL_NOT_DETECTED; - } - if (q->current_N_id_2 == 3) { - q->current_N_id_2 = 0; + } else { + ret = 0; } } } diff --git a/lte/phy/lib/ue/src/ue_dl.c b/lte/phy/lib/ue/src/ue_dl.c index 0b98459ee..c6957cf55 100644 --- a/lte/phy/lib/ue/src/ue_dl.c +++ b/lte/phy/lib/ue/src/ue_dl.c @@ -169,7 +169,7 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint16_t gettimeofday(&t[2], NULL); get_time_interval(t); - mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, mean_exec_time, frame_cnt); + mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, mean_exec_time, frame_cnt); frame_cnt++; for (int i=0;isfind, MIB_FIND_THRESHOLD); 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, cp); if (lte_fft_init(&q->fft, cp, cell.nof_prb)) { fprintf(stderr, "Error initializing FFT\n"); @@ -137,39 +141,42 @@ void ue_mib_set_threshold(ue_mib_t * q, float threshold) static int mib_decoder_run(ue_mib_t * q, cf_t *input, pbch_mib_t *mib) { - int ret; + int ret = LIBLTE_SUCCESS; /* Run FFT for the slot symbols */ lte_fft_run_slot(&q->fft, input, q->slot1_symbols); /* Get channel estimates of slot #1 for each port */ ret = chest_ce_slot(&q->chest, q->slot1_symbols, q->ce, 1); - if (ret == LIBLTE_SUCCESS) { - - /* Reset decoder if we missed a frame */ - if ((q->last_frame_trial && (q->frame_cnt - q->last_frame_trial > 2)) || - q->frame_cnt > 10) - { - ue_mib_reset(q); - INFO("Resetting PBCH decoder: last trial %u, now is %u\n", - q->last_frame_trial, q->frame_cnt); - } - - /* Decode PBCH */ - ret = pbch_decode(&q->pbch, q->slot1_symbols, q->ce, mib); - if (ret < 0) { - fprintf(stderr, "Error decoding PBCH\n"); - } else if (ret == 1) { - INFO("MIB decoded: %u\n", q->frame_cnt/2); - ue_mib_reset(q); - ret = 1; - } else { - INFO("MIB not decoded: %u\n", q->frame_cnt / 2); - q->last_frame_trial = q->frame_cnt; - } + if (ret < 0) { + 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); + ue_mib_reset(q); + } + + /* Decode PBCH */ + ret = pbch_decode(&q->pbch, q->slot1_symbols, q->ce, mib); + if (ret < 0) { + fprintf(stderr, "Error decoding PBCH\n"); + } else if (ret == 1) { + INFO("MIB decoded: %u\n", q->frame_cnt/2); + 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; + } return ret; } +int counter1=0,counter2=0,counter3=0,counter4=0; int ue_mib_decode(ue_mib_t * q, cf_t *signal, @@ -177,13 +184,18 @@ int ue_mib_decode(ue_mib_t * q, pbch_mib_t *mib) { int ret = LIBLTE_ERROR_INVALID_INPUTS; - uint32_t peak_idx; + uint32_t peak_idx=0; uint32_t nof_input_frames; if (q != NULL && signal != NULL) { + if (nsamples < MIB_FRAME_SIZE) { + fprintf(stderr, "Error: nsamples must be greater than %d\n", MIB_FRAME_SIZE); + return LIBLTE_ERROR; + } + ret = LIBLTE_SUCCESS; if (nsamples % MIB_FRAME_SIZE) { @@ -200,26 +212,41 @@ int ue_mib_decode(ue_mib_t * q, fprintf(stderr, "Error finding correlation peak (%d)\n", ret); return -1; } - - /* If peak position does not allow to read SSS, return error -3 */ + + if (ret == 0) { + counter2++; + } else if (ret == 1) { + counter4++; + } + + /* Check if we have space for reading the MIB and we are in Subframe #0 */ if (ret == 1 && nf*MIB_FRAME_SIZE + peak_idx + 960 <= nsamples && sync_sss_detected(&q->sfind) && sync_get_sf_idx(&q->sfind) == 0) { - + INFO("Trying to decode MIB\n",0); ret = mib_decoder_run(q, &signal[nf*MIB_FRAME_SIZE+peak_idx], mib); - + counter3++; } else if ((ret == LIBLTE_SUCCESS && peak_idx != 0) || (ret == 1 && nf*MIB_FRAME_SIZE + peak_idx + 960 > nsamples)) { + printf("Not enough space for PBCH\n",0); ret = MIB_FRAME_UNALIGNED; } else { + INFO("SSS not detected\n",0); ret = 0; } + counter1++; + INFO("Total: %3d - Sync0: %3d - Sync1: %3d - Tried: %3d - Peak: %4d - Ret: %d\n",counter1,counter2,counter4, counter3, peak_idx, ret); + q->frame_cnt++; } } return ret; } + + + + diff --git a/lte/phy/lib/ue/src/ue_sync.c b/lte/phy/lib/ue/src/ue_sync.c index 714a6212f..9122794f5 100644 --- a/lte/phy/lib/ue/src/ue_sync.c +++ b/lte/phy/lib/ue/src/ue_sync.c @@ -46,7 +46,7 @@ cf_t dummy[MAX_TIME_OFFSET]; #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 1.0 +#define FIND_THRESHOLD 1.2 #define TRACK_THRESHOLD 0.2 @@ -138,7 +138,7 @@ float ue_sync_get_cfo(ue_sync_t *q) { } float ue_sync_get_sfo(ue_sync_t *q) { - return 1000*q->mean_time_offset/5; + return 1000*q->mean_time_offset; } void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { @@ -179,8 +179,9 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { /* Make sure subframe idx is what we expect */ if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) { - INFO("Warning: Expected SF idx %d but got %d!\n", - q->sf_idx, sync_get_sf_idx(&q->strack)); + INFO("Warning: Expected SF idx %d but got %d (%d,%g - %d,%g)!\n", + q->sf_idx, sync_get_sf_idx(&q->strack), q->strack.m0, q->strack.m1, q->strack.m0_value, q->strack.m1_value); + /* FIXME: What should we do in this case? */ q->sf_idx = sync_get_sf_idx(&q->strack); q->state = SF_TRACK; } else { @@ -196,10 +197,9 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { } /* compute cumulative moving average CFO */ - q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt); - + q->cur_cfo = VEC_CMA(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt); /* compute cumulative moving average time offset */ - q->mean_time_offset = (float) EXPAVERAGE((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt); + q->mean_time_offset = (float) VEC_CMA((float) q->time_offset, q->mean_time_offset, q->frame_ok_cnt); q->peak_idx = CURRENT_SFLEN/2 + q->time_offset; q->frame_ok_cnt++; @@ -310,7 +310,7 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { #ifdef MEASURE_EXEC_TIME gettimeofday(&t[2], NULL); get_time_interval(t); - q->mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); + q->mean_exec_time = (float) VEC_CMA((float) t[0].tv_usec, q->mean_exec_time, q->frame_total_cnt); #endif if (ret == 1) { diff --git a/lte/phy/lib/ue/test/ue_celldetect_mib_test.c b/lte/phy/lib/ue/test/ue_celldetect_mib_test.c index c3921aba4..027f9b33e 100644 --- a/lte/phy/lib/ue/test/ue_celldetect_mib_test.c +++ b/lte/phy/lib/ue/test/ue_celldetect_mib_test.c @@ -169,7 +169,7 @@ int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_ return LIBLTE_ERROR; } - n = ue_celldetect_scan(s, buffer, flen, found_cell); + n = ue_celldetect_scan(s, buffer, flen, found_cell, nof_scanned_cells); switch(n) { case CS_FRAME_UNALIGNED: printf("Realigning frame\n");