From 0943f3263a682d0b24afdcded9d6dc03c70ab397 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Tue, 5 Aug 2014 13:50:26 +0100 Subject: [PATCH 1/6] Fix for building without VOLK --- cmake/modules/FindVolk.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 5861f1232..d3a5ceba1 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -25,7 +25,7 @@ FIND_LIBRARY( ) # Some functions are not defined in old volk versions -SET(CMAKE_REQUIRED_LIBRARIES ${VOLK_LIBRARIES} m) +SET(CMAKE_REQUIRED_LIBRARIES volk m) CHECK_FUNCTION_EXISTS_MATH(volk_32f_index_max_16u HAVE_VOLK_MAX_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_accumulator_s32f HAVE_VOLK_ACC_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32fc_multiply_32fc HAVE_VOLK_MULT_FUNCTION) From 8f95fef3af1ef119c1f8ae113e088837ba9840f4 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Wed, 6 Aug 2014 14:02:00 +0100 Subject: [PATCH 2/6] Fix for building without uhd --- lte/phy/lib/ue/test/CMakeLists.txt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lte/phy/lib/ue/test/CMakeLists.txt b/lte/phy/lib/ue/test/CMakeLists.txt index dc376a5de..44a2361da 100644 --- a/lte/phy/lib/ue/test/CMakeLists.txt +++ b/lte/phy/lib/ue/test/CMakeLists.txt @@ -31,11 +31,13 @@ IF(${CUHD_FIND} GREATER -1) ADD_EXECUTABLE(ue_celldetect_mib_test ue_celldetect_mib_test.c) TARGET_LINK_LIBRARIES(ue_celldetect_mib_test lte_phy cuhd) + + IF(${GRAPHICS_FIND} EQUAL -1) + SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") + ELSE(${GRAPHICS_FIND} EQUAL -1) + target_link_libraries(ue_sync_usrp graphics) + ENDIF(${GRAPHICS_FIND} EQUAL -1) + ENDIF(${CUHD_FIND} GREATER -1) -IF(${GRAPHICS_FIND} EQUAL -1) - SET_TARGET_PROPERTIES(ue_sync_usrp PROPERTIES COMPILE_DEFINITIONS "DISABLE_GRAPHICS") -ELSE(${GRAPHICS_FIND} EQUAL -1) - target_link_libraries(ue_sync_usrp graphics) -ENDIF(${GRAPHICS_FIND} EQUAL -1) From f12a42b9802500cdc4110bc00406499ba106df03 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Fri, 8 Aug 2014 14:19:20 +0100 Subject: [PATCH 3/6] Fix for building without uhd --- lte/phy/examples/iodev.c | 20 ++++++++++++-------- lte/phy/examples/pdsch_ue.c | 17 ++++++++++++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c index ce55b3a3a..f311443f4 100644 --- a/lte/phy/examples/iodev.c +++ b/lte/phy/examples/iodev.c @@ -44,11 +44,12 @@ #include "cell_search_utils.h" - +#ifndef DISABLE_UHD int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); return cuhd_recv(h, data, nsamples, 1); } +#endif /* Setup USRP or input file */ int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mib) { @@ -178,7 +179,6 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mi void iodev_free(iodev_t *q) { - if (q->mode == FILESOURCE) { filesource_free(&q->fsrc); } else { @@ -187,9 +187,10 @@ void iodev_free(iodev_t *q) { #endif } } + /* Receive samples from the USRP or read from file */ int iodev_receive(iodev_t *q, cf_t **buffer) { - int n; + int n=0; if (q->mode == FILESOURCE) { INFO(" ----- READING %d SAMPLES ---- \n", q->sf_len); n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); @@ -229,10 +230,12 @@ int iodev_receive(iodev_t *q, cf_t **buffer) { void* iodev_get_cuhd(iodev_t *q) { if (q->mode == UHD) { +#ifndef DISABLE_UHD return q->uhd; - } else { - return NULL; +#endif } + return NULL; + } bool iodev_isfile(iodev_t *q) { @@ -244,11 +247,12 @@ bool iodev_isUSRP(iodev_t *q) { } uint32_t iodev_get_sfidx(iodev_t *q) { - if (iodev_isfile(q)) { - return q->sf_idx; - } else { + if (iodev_isUSRP(q)) { +#ifndef DISABLE_UHD return ue_sync_get_sfidx(&q->sframe); +#endif } + return q->sf_idx; } diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index adf3c8f4b..634416ee0 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -218,13 +218,22 @@ int main(int argc, char **argv) { } // Plot and Printf - if (!(sf_cnt % 10)) { + if (!(sf_cnt % 10)) { +#ifndef DISABLE_UHD printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d/%4d, BLER: %.1e, Texec: %.2f\r", ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000, pdsch_average_noi(&ue_dl.pdsch), (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (int) ue_dl.nof_trials, (float) ue_dl.pkt_errors / ue_dl.pkts_total, - mean_exec_time); + mean_exec_time); +#else + printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d/%4d, BLER: %.1e, Texec: %.2f\r", + 0.0, 0.0, + pdsch_average_noi(&ue_dl.pdsch), + (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (int) ue_dl.nof_trials, + (float) ue_dl.pkt_errors / ue_dl.pkts_total, + mean_exec_time); +#endif } #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots && iodev_get_sfidx(&iodev) == 5) { @@ -232,9 +241,11 @@ int main(int argc, char **argv) { } #endif } else if (ret == 0) { +#ifndef DISABLE_UHD printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", sync_get_peak_value(&iodev.sframe.sfind), - iodev.sframe.frame_total_cnt, iodev.sframe.state); + iodev.sframe.frame_total_cnt, iodev.sframe.state); +#endif } sf_cnt++; } // Main loop From cc364f7dfa8cf6c40c4f4e7f9287c25a51d9b4cd Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 14 Oct 2014 13:56:18 +0100 Subject: [PATCH 4/6] Merged with #51 --- lte/phy/examples/CMakeLists.txt | 3 + lte/phy/examples/cell_measurement.c | 218 ++++++++++++++ lte/phy/examples/cell_search.c | 13 +- lte/phy/examples/cell_search_utils.c | 181 +++++++++-- lte/phy/examples/cell_search_utils.h | 14 +- lte/phy/examples/iodev.c | 64 +--- lte/phy/examples/iodev.h | 1 + lte/phy/examples/pdsch_ue.c | 14 +- .../include/liblte/phy/ch_estimation/chest.h | 88 +++++- .../liblte/phy/ch_estimation/refsignal.h | 24 +- .../include/liblte/phy/common/phy_common.h | 2 +- lte/phy/include/liblte/phy/common/sequence.h | 2 +- lte/phy/include/liblte/phy/sync/sync.h | 7 + lte/phy/include/liblte/phy/ue/ue_celldetect.h | 9 +- lte/phy/include/liblte/phy/ue/ue_mib.h | 2 - lte/phy/include/liblte/phy/utils/vector.h | 5 +- lte/phy/lib/ch_estimation/src/chest.c | 220 ++++++++++---- lte/phy/lib/ch_estimation/src/refsignal.c | 283 ++++++++++++++---- lte/phy/lib/ch_estimation/src/ul_rs_tables.h | 127 ++++++++ lte/phy/lib/ch_estimation/test/CMakeLists.txt | 23 +- .../test/{chest_test.c => chest_test_dl.c} | 0 .../lib/ch_estimation/test/chest_test_ul.c | 249 +++++++++++++++ lte/phy/lib/common/src/sequence.c | 7 +- lte/phy/lib/modem/test/soft_demod_test.c | 2 +- lte/phy/lib/phch/src/pdsch.c | 2 +- lte/phy/lib/phch/src/sequences.c | 10 +- lte/phy/lib/sync/src/pss.c | 2 +- lte/phy/lib/sync/src/sync.c | 45 +-- lte/phy/lib/sync/test/pss_usrp.c | 2 +- lte/phy/lib/ue/src/ue_celldetect.c | 23 +- lte/phy/lib/ue/src/ue_dl.c | 2 +- lte/phy/lib/ue/src/ue_mib.c | 91 ++++-- lte/phy/lib/ue/src/ue_sync.c | 16 +- lte/phy/lib/ue/test/ue_celldetect_mib_test.c | 2 +- 34 files changed, 1419 insertions(+), 334 deletions(-) create mode 100644 lte/phy/examples/cell_measurement.c create mode 100644 lte/phy/lib/ch_estimation/src/ul_rs_tables.h rename lte/phy/lib/ch_estimation/test/{chest_test.c => chest_test_dl.c} (100%) create mode 100644 lte/phy/lib/ch_estimation/test/chest_test_ul.c 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"); From a551853df584d938329eeafa2bfc5158aca2fe8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20G=C3=B3mez-Miguelez?= Date: Thu, 18 Dec 2014 22:09:59 +0000 Subject: [PATCH 5/6] Update README.md --- README.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/README.md b/README.md index f783db483..932bf0386 100644 --- a/README.md +++ b/README.md @@ -71,22 +71,6 @@ The SIB1 message is decoded and shown on the console, for example: Decoded SIB1 Message: [40 48 50 03 02 0b 14 4a 30 18 28 20 90 81 84 79 a0 00 ]; ``` -Then, you can use any ASN.1 SIB decoder to read the message. This site http://www.marben-products.com/asn.1/services/decoder-asn1-lte.html is a good example. - - -If you don't have a pair of USRP, you can also test the demo by writing the samples to a file and then reading them: - -From the eNodeB, type - -``` -lte/phy/examples/pdsch_enodeb -o [output_file] -c [cell_id] [-h for more commands] -``` - -From the UE, type -``` -lte/phy/examples/pdsch_ue -i [input_file] -c [cell_id] [-h for more commands] -``` - * Cell Search Example From 3d62e7dd9596850865049948ae354bc81004469c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismael=20G=C3=B3mez-Miguelez?= Date: Mon, 22 Dec 2014 19:45:50 +0100 Subject: [PATCH 6/6] Update README.md --- README.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/README.md b/README.md index 932bf0386..cd373789c 100644 --- a/README.md +++ b/README.md @@ -72,18 +72,6 @@ Decoded SIB1 Message: [40 48 50 03 02 0b 14 4a 30 18 28 20 90 81 84 79 a0 00 ]; ``` -* Cell Search Example - -This program uses any hardware supported by the UHD driver to scan an LTE band for active cells. See http://niviuk.free.fr/lte_band.php for a list of available bands. The program first obtains a power spectral density of the entire band. For all frequencies with an RSSI higher than a threshold, it tries to find the LTE Primary Synchronization Signal (PSS) and then identifies the CELL ID using the Secondary Synchronization Signal (SSS). Finally, it estimates the Carrier Frequency Offset (CFO) and Sampling Frequency Offset (SFO) and decodes the Master Information Block (MIB) from the PBCH. - -For instance, the command: - -``` lte/phy/examples/scan_mib -b 3 ``` - - -Scans the LTE band 3 (1805 to 1880 MHz). Note that you need a hardware supporting these frequencies (e.g. SBX daughterboard for USRP). For more command arguments, type ``` examples/mib_scan_usrp -h ``` - - Support ========