From 856a899ff00a4474d6af17f72f57129686ac6024 Mon Sep 17 00:00:00 2001 From: ismagom Date: Fri, 12 Dec 2014 01:03:32 +0000 Subject: [PATCH] Added cell_scanner API and test example --- lte/examples/CMakeLists.txt | 2 + lte/examples/cell_measurement.c | 29 +- lte/examples/cell_scanner/CMakeLists.txt | 28 ++ lte/examples/cell_scanner/cell_scanner.c | 282 ++++++++++++++++++ lte/examples/cell_scanner/cell_scanner.h | 63 ++++ lte/examples/cell_scanner/cell_scanner_test.c | 139 +++++++++ lte/examples/cuhd_utils.c | 2 +- .../include/liblte/phy/common/phy_common.h | 2 + lte/phy/include/liblte/phy/sync/pss.h | 1 + .../include/liblte/phy/ue/ue_cell_search.h | 1 + lte/phy/lib/sync/src/pss.c | 3 + lte/phy/lib/ue/src/ue_cell_search.c | 18 +- matlab/tests/neighbour_cell_search.m | 61 ++++ 13 files changed, 612 insertions(+), 19 deletions(-) create mode 100644 lte/examples/cell_scanner/CMakeLists.txt create mode 100644 lte/examples/cell_scanner/cell_scanner.c create mode 100644 lte/examples/cell_scanner/cell_scanner.h create mode 100644 lte/examples/cell_scanner/cell_scanner_test.c create mode 100644 matlab/tests/neighbour_cell_search.m diff --git a/lte/examples/CMakeLists.txt b/lte/examples/CMakeLists.txt index 402f3b0f1..72bcda270 100644 --- a/lte/examples/CMakeLists.txt +++ b/lte/examples/CMakeLists.txt @@ -92,3 +92,5 @@ IF(${CUHD_FIND} GREATER -1) ELSE(${CUHD_FIND} GREATER -1) MESSAGE(STATUS " UHD examples NOT INSTALLED: CUHD library not compiled.") ENDIF(${CUHD_FIND} GREATER -1) + +add_subdirectory(cell_scanner) \ No newline at end of file diff --git a/lte/examples/cell_measurement.c b/lte/examples/cell_measurement.c index 8c5a429f6..e5c9991a9 100644 --- a/lte/examples/cell_measurement.c +++ b/lte/examples/cell_measurement.c @@ -80,7 +80,7 @@ void usage(prog_args_t *args, char *prog) { printf("\t-v [set verbose to debug, default none]\n"); } -void parse_args(prog_args_t *args, int argc, char **argv) { +int parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); while ((opt = getopt(argc, argv, "aglnvf")) != -1) { @@ -105,13 +105,14 @@ void parse_args(prog_args_t *args, int argc, char **argv) { break; default: usage(args, argv[0]); - exit(-1); + return -1; } } if (args->uhd_freq < 0) { usage(args, argv[0]); - exit(-1); + return -1; } + return 0; } /**********************************************************************/ @@ -155,12 +156,14 @@ int main(int argc, char **argv) { uint32_t neighbour_cell_ids[MAX_NEIGHBOUR_CELLS]; cf_t *ce[MAX_PORTS]; - parse_args(&prog_args, argc, argv); + if (parse_args(&prog_args, argc, argv)) { + exit(-1); + } printf("Opening UHD device...\n"); if (cuhd_open(prog_args.uhd_args, &uhd)) { fprintf(stderr, "Error opening uhd\n"); - exit(-1); + return -1; } /* Set receiver gain */ cuhd_set_rx_gain(uhd, prog_args.uhd_gain); @@ -173,7 +176,7 @@ int main(int argc, char **argv) { ret = cuhd_search_and_decode_mib(uhd, &cell_detect_config, prog_args.force_N_id_2, &cell); if (ret < 0) { fprintf(stderr, "Error searching cell\n"); - exit(-1); + return -1; } else if (ret == 0) { printf("Cell not found\n"); exit(0); @@ -194,15 +197,15 @@ int main(int argc, char **argv) { if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, uhd)) { fprintf(stderr, "Error initiating ue_sync\n"); - exit(-1); + return -1; } if (ue_dl_init(&ue_dl, cell, 1234)) { fprintf(stderr, "Error initiating UE downlink processing module\n"); - exit(-1); + return -1; } if (ue_mib_init(&ue_mib, cell)) { fprintf(stderr, "Error initaiting UE MIB decoder\n"); - exit(-1); + return -1; } /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ @@ -252,7 +255,7 @@ int main(int argc, char **argv) { n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset); if (n < 0) { fprintf(stderr, "Error decoding UE MIB\n"); - exit(-1); + return -1; } else if (n == MIB_FOUND) { bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN); bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn); @@ -269,7 +272,7 @@ int main(int argc, char **argv) { ((int) ceilf((float)3*(((sfn)/2)%4)/2))%4); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); - exit(-1); + return -1; } else if (n == 0) { printf("CFO: %+6.4f KHz, SFO: %+6.4f Khz, ExecTime: %5.1f us, NOI: %.2f, PDCCH-Det: %.3f\r", ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000, @@ -322,7 +325,7 @@ int main(int argc, char **argv) { ((int) ceilf((float)3*sib4_window_cnt/2))%4); if (n < 0) { fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); - exit(-1); + return -1; } else if (n == 0) { nof_trials++; } else { @@ -340,7 +343,7 @@ int main(int argc, char **argv) { sib4_window_cnt++; if (sib4_window_cnt == si_window_length) { sib4_window_start = false; - exit(-1); + return -1; } } diff --git a/lte/examples/cell_scanner/CMakeLists.txt b/lte/examples/cell_scanner/CMakeLists.txt new file mode 100644 index 000000000..502745fe1 --- /dev/null +++ b/lte/examples/cell_scanner/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# 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/. +# + + +################################################################# +# CELL SCANNER TEST +################################################################# + +add_executable(cell_scanner_test cell_scanner_test.c cell_scanner.c ../cuhd_utils.c) +target_link_libraries(cell_scanner_test lte_phy lte_rrc cuhd) diff --git a/lte/examples/cell_scanner/cell_scanner.c b/lte/examples/cell_scanner/cell_scanner.c new file mode 100644 index 000000000..4b6ef4e4a --- /dev/null +++ b/lte/examples/cell_scanner/cell_scanner.c @@ -0,0 +1,282 @@ +/** + * + * \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/rrc/rrc.h" +#include "liblte/phy/phy.h" +#include "liblte/cuhd/cuhd.h" +#include "../cuhd_utils.h" +#include "cell_scanner.h" + +#define B210_DEFAULT_GAIN 40.0 +#define B210_DEFAULT_GAIN_CORREC 80.0 // Gain of the Rx chain when the gain is set to 40 + +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 cell_scanner_init(cell_scanner_t *q, cell_scanner_config_t *config) +{ + bzero(q, sizeof(cell_scanner_t)); + + memcpy(&q->config, config, sizeof(cell_scanner_config_t)); + + printf("Opening UHD device...\n"); + if (cuhd_open(q->config.uhd_args, &q->uhd)) { + fprintf(stderr, "Error opening uhd\n"); + return -1; + } + /* Set receiver gain */ + cuhd_set_rx_gain(q->uhd, B210_DEFAULT_GAIN); + + return 0; +} + +void cell_scanner_close(cell_scanner_t *q) { + cuhd_close(q->uhd); +} + +int cell_scanner_all_cells(cell_scanner_t *q, float frequency, cell_scanner_result_t *result) +{ + return cell_scanner_cell(q, frequency, -1, result); +} + +#define MAX_SINFO 10 + +int cell_scanner_cell(cell_scanner_t *q, float frequency, int N_id_2, cell_scanner_result_t *result) +{ + int ret; + cf_t *sf_buffer; + lte_cell_t cell; + int64_t sf_cnt; + ue_sync_t ue_sync; + ue_mib_t ue_mib; + ue_dl_t ue_dl; + lte_fft_t fft; + chest_dl_t chest; + uint32_t nframes_measure=0; + uint32_t nof_trials = 0; + uint32_t sfn = 0; // system frame number + int n; + uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN]; + uint32_t sfn_offset; + uint8_t data[1024]; + uint8_t data_unpacked[1024]; + + bzero(result, sizeof(cell_scanner_result_t)); + + /* set receiver frequency */ + cuhd_set_rx_freq(q->uhd, (double) frequency); + cuhd_rx_wait_lo_locked(q->uhd); + printf("Tunning receiver to %.3f MHz\n", (double ) frequency/1000000); + + cell_search_cfg_t cfg; + cfg.nof_frames_total = q->config.cell_detect_max_frames; + cfg.threshold = q->config.cell_detect_early_stop_threshold; + + ret = cuhd_search_and_decode_mib(q->uhd, &cfg, N_id_2, &cell); + if (ret < 0) { + fprintf(stderr, "Error searching cell\n"); + exit(-1); + } else if (ret == 0) { + printf("Cell not found\n"); + exit(0); + } + + /* set sampling frequency */ + int srate = lte_sampling_freq_hz(cell.nof_prb); + if (srate != -1) { + cuhd_set_rx_srate(q->uhd, (double) srate); + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell.nof_prb); + return LIBLTE_ERROR; + } + + INFO("Stopping UHD and flushing buffer...\n",0); + cuhd_stop_rx_stream(q->uhd); + cuhd_flush_buffer(q->uhd); + + if (ue_sync_init(&ue_sync, cell, cuhd_recv_wrapper, q->uhd)) { + fprintf(stderr, "Error initiating ue_sync\n"); + exit(-1); + } + if (ue_dl_init(&ue_dl, cell, 1234)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + if (ue_mib_init(&ue_mib, cell)) { + fprintf(stderr, "Error initaiting UE MIB decoder\n"); + exit(-1); + } + + /* Configure downlink receiver for the SI-RNTI since will be the only one we'll use */ + ue_dl_set_rnti(&ue_dl, SIRNTI); + + /* Initialize subframe counter */ + sf_cnt = 0; + + if (lte_fft_init(&fft, cell.cp, cell.nof_prb)) { + fprintf(stderr, "Error initiating FFT\n"); + return -1; + } + if (chest_dl_init(&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)); + + cf_t *ce[MAX_PORTS]; + for (int i=0;iuhd); + + memcpy(&result->phy_cell, &cell, sizeof(lte_cell_t)); + + chest_dl_t *chest_ptr = &ue_dl.chest; + bool mib_decoded = false; + bool sib_decoded = false; + + /* Main loop */ + while (sf_cnt < q->config.measure_avg_nof_frames) { + + ret = ue_sync_get_buffer(&ue_sync, &sf_buffer); + if (ret < 0) { + fprintf(stderr, "Error calling ue_sync_work()\n"); + } + + /* ue_sync_get_buffer returns 1 if successfully read 1 aligned subframe */ + if (ret == 1) { + if (!mib_decoded) { + if (ue_sync_get_sfidx(&ue_sync) == 0) { + pbch_decode_reset(&ue_mib.pbch); + n = ue_mib_decode(&ue_mib, sf_buffer, bch_payload_unpacked, NULL, &sfn_offset); + if (n < 0) { + fprintf(stderr, "Error decoding UE MIB\n"); + exit(-1); + } else if (n == MIB_FOUND) { + bit_unpack_vector(bch_payload_unpacked, bch_payload, BCH_PAYLOAD_LEN); + bcch_bch_unpack(bch_payload, BCH_PAYLOAD_LEN, &cell, &sfn); + printf("Decoded MIB. SFN: %d, offset: %d\n", sfn, sfn_offset); + sfn = (sfn + sfn_offset)%1024; + mib_decoded = true; + } + } + } + + /* We are looking for SI Blocks, search only in appropiate places */ + if (mib_decoded && !sib_decoded && + (ue_sync_get_sfidx(&ue_sync) == 5 && (sfn%2)==0)) + { + n = ue_dl_decode_sib(&ue_dl, sf_buffer, data, ue_sync_get_sfidx(&ue_sync), + ((int) ceilf((float)3*(((sfn)/2)%4)/2))%4); + if (n < 0) { + fprintf(stderr, "Error decoding UE DL\n");fflush(stdout); + exit(-1); + } else if (n == 0) { + nof_trials++; + } else { + bit_unpack_vector(data, data_unpacked, n); + void *dlsch_msg = bcch_dlsch_unpack(data_unpacked, n); + if (dlsch_msg) { + printf("\n");fflush(stdout); + cell_access_info_t cell_info; + bcch_dlsch_sib1_get_cell_access_info(dlsch_msg, &cell_info); + printf("Decoded SIB1. Cell ID: 0x%x\n", cell_info.cell_id); + + result->cell_id = cell_info.cell_id; + + bcch_dlsch_fprint(dlsch_msg, stdout); + + sib_decoded = true; + } + } + } else { + chest_ptr = &chest; + /* Run FFT for all subframe data */ + lte_fft_run_sf(&fft, sf_buffer, sf_symbols); + chest_dl_estimate(&chest, sf_symbols, ce, ue_sync_get_sfidx(&ue_sync)); + } + + result->rssi = VEC_CMA(vec_avg_power_cf(sf_buffer,SF_LEN(lte_symbol_sz(cell.nof_prb))), + result->rssi,nframes_measure); + result->rsrq = VEC_EMA(chest_dl_get_rsrq(chest_ptr),result->rsrq,0.01); + result->rsrp = VEC_CMA(chest_dl_get_rsrp(chest_ptr),result->rsrp,nframes_measure); + result->snr = VEC_CMA(chest_dl_get_snr(chest_ptr),result->snr,nframes_measure); + nframes_measure++; + + // Plot and Printf + if ((nframes_measure%10) == 0) { + printf("CFO: %+8.4f KHz, SFO: %+8.4f Khz, RSSI: %5.1f dBm, " + "RSRP: %+5.1f dBm, RSRQ: %5.1f dB, SNR: %5.1f dB\r", + ue_sync_get_cfo(&ue_sync)/1000, ue_sync_get_sfo(&ue_sync)/1000, + 10*log10(result->rssi*1000)-B210_DEFAULT_GAIN_CORREC, + 10*log10(result->rsrp*1000)-B210_DEFAULT_GAIN_CORREC, + 10*log10(result->rsrq), 10*log10(result->snr)); + if (verbose != VERBOSE_NONE) { + printf("\n"); + } + } + if (ue_sync_get_sfidx(&ue_sync) == 9) { + sfn++; + if (sfn == 1024) { + sfn = 0; + } + } + } 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 + + // Correct RSRP and RSSI measurements + result->rssi /= pow(10, 8); + result->rsrp /= pow(10, 8); + + ue_sync_free(&ue_sync); + + return 0; +} + + + diff --git a/lte/examples/cell_scanner/cell_scanner.h b/lte/examples/cell_scanner/cell_scanner.h new file mode 100644 index 000000000..3856733e5 --- /dev/null +++ b/lte/examples/cell_scanner/cell_scanner.h @@ -0,0 +1,63 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "liblte/phy/phy.h" + +typedef struct { + int cell_detect_max_frames; + float cell_detect_early_stop_threshold; + int measure_avg_nof_frames; + char *uhd_args; +} cell_scanner_config_t; + +typedef struct { + lte_cell_t phy_cell; + uint32_t cell_id; + float rsrp; + float rsrq; + float rssi; + float snr; +} cell_scanner_result_t; + +typedef struct { + cell_scanner_config_t config; + void *uhd; +} cell_scanner_t; + +int cell_scanner_init(cell_scanner_t *q, + cell_scanner_config_t *config); + +void cell_scanner_close(cell_scanner_t *q); + +int cell_scanner_all_cells(cell_scanner_t *q, + float frequency, + cell_scanner_result_t *result); + +int cell_scanner_cell(cell_scanner_t *q, + float frequency, + int N_id_2, + cell_scanner_result_t *result); diff --git a/lte/examples/cell_scanner/cell_scanner_test.c b/lte/examples/cell_scanner/cell_scanner_test.c new file mode 100644 index 000000000..31d303bd9 --- /dev/null +++ b/lte/examples/cell_scanner/cell_scanner_test.c @@ -0,0 +1,139 @@ +/** + * + * \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/rrc/rrc.h" +#include "liblte/phy/phy.h" +#include "liblte/cuhd/cuhd.h" +#include "cell_scanner.h" + + +/********************************************************************** + * Program arguments processing + ***********************************************************************/ +typedef struct { + int nof_subframes; + int force_N_id_2; + char *uhd_args; + float uhd_freq; +}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; +} + +void usage(prog_args_t *args, char *prog) { + printf("Usage: %s [alnv] -f rx_frequency (in Hz)\n", prog); + printf("\t-a UHD args [Default %s]\n", args->uhd_args); + 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, "alnvf")) != -1) { + switch (opt) { + case 'a': + args->uhd_args = 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); + } +} +/**********************************************************************/ + +int main(int argc, char **argv) { + prog_args_t prog_args; + cell_scanner_result_t result; + cell_scanner_config_t cfg; + cell_scanner_t cs; + + parse_args(&prog_args, argc, argv); + + // Peak-to-sidelobe ratio (PSR) threshold for cell detection early stopping. + cfg.cell_detect_early_stop_threshold = 20.0; // This is a normal value. + // maximum 5 ms frames that will be scanned maximum in the case the threshold is not exceed + // ie for bad cells + cfg.cell_detect_max_frames = 50; // this is 250 ms + + // Number of 1 ms subframes that will be used to compute rsrp, rsrq, snr, etc average + cfg.measure_avg_nof_frames = 1000; // 1 sec + + cfg.uhd_args = prog_args.uhd_args; + + // Init USRP + if (cell_scanner_init(&cs, &cfg)) { + fprintf(stderr, "Error initiating cell scanner\n"); + exit(-1); + } + + // Scan for a frequency + if (prog_args.force_N_id_2 < 0) { + // We have 2 options, either we scan for the three possible N_id_2 root sequences... + cell_scanner_all_cells(&cs, prog_args.uhd_freq, &result); + } else { + // or we scan for a single one. + cell_scanner_cell(&cs, prog_args.uhd_freq, prog_args.force_N_id_2, &result); + } + + printf("\nResult: CellID: %d, PHYID: %d, RSRP: %.1f dBm, RSRQ: %.1f dB, SNR: %.1f dB\n", + result.cell_id, result.phy_cell.id, + 10*log10(result.rsrp*1000), 10*log10(result.rsrq), 10*log10(result.snr)); +} diff --git a/lte/examples/cuhd_utils.c b/lte/examples/cuhd_utils.c index 1ccf5e0c4..7c2c44923 100644 --- a/lte/examples/cuhd_utils.c +++ b/lte/examples/cuhd_utils.c @@ -158,7 +158,7 @@ int cuhd_search_and_decode_mib(void *uhd, cell_search_cfg_t *config, int force_N ret = cuhd_cell_search(uhd, config, force_N_id_2, cell); if (ret > 0) { printf("Decoding PBCH for cell %d (N_id_2=%d)\n", cell->id, cell->id%3); - ret = cuhd_mib_decoder(uhd, 50, cell); + ret = cuhd_mib_decoder(uhd, config->nof_frames_total, cell); if (ret < 0) { fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", cell->id); return LIBLTE_ERROR; diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index a01f6e5ef..4603019ea 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -116,6 +116,8 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define NOF_TC_CB_SIZES 188 +typedef _Complex float cf_t; + typedef enum LIBLTE_API { PHICH_NORM, PHICH_EXT} phich_length_t; typedef enum LIBLTE_API { R_1_6, R_1_2, R_1, R_2} phich_resources_t; diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index 9f5b435cf..7c0ed7044 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -84,6 +84,7 @@ typedef struct LIBLTE_API { float *conv_output_abs; float ema_alpha; float *conv_output_avg; + float peak_value; }pss_synch_t; typedef enum { PSS_TX, PSS_RX } pss_direction_t; diff --git a/lte/phy/include/liblte/phy/ue/ue_cell_search.h b/lte/phy/include/liblte/phy/ue/ue_cell_search.h index 6ad4bc419..644ed955a 100644 --- a/lte/phy/include/liblte/phy/ue/ue_cell_search.h +++ b/lte/phy/include/liblte/phy/ue/ue_cell_search.h @@ -67,6 +67,7 @@ typedef struct LIBLTE_API { lte_cp_t cp; float peak; float mode; + float psr; } ue_cell_search_result_t; diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index ac27ca59b..57937f3d6 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -323,6 +323,9 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value) /* Find maximum of the absolute value of the correlation */ corr_peak_pos = vec_max_fi(q->conv_output_avg, conv_output_len-1); + // save absolute value + q->peak_value = q->conv_output_avg[corr_peak_pos]; + #ifdef PSS_RETURN_PSR // Find second side lobe diff --git a/lte/phy/lib/ue/src/ue_cell_search.c b/lte/phy/lib/ue/src/ue_cell_search.c index c8b05e217..5cab42fb8 100644 --- a/lte/phy/lib/ue/src/ue_cell_search.c +++ b/lte/phy/lib/ue/src/ue_cell_search.c @@ -154,20 +154,27 @@ static void get_cell(ue_cell_search_t * q, uint32_t nof_detected_frames, ue_cell found_cell->cell_id = q->candidates[mode_pos].cell_id; /* Now in all these cell IDs, find most frequent CP */ uint32_t nof_normal = 0; + found_cell->peak = 0; for (i=0;icandidates[i].cell_id == found_cell->cell_id) { if (CP_ISNORM(q->candidates[i].cp)) { nof_normal++; } } + // average absolute peak value + found_cell->peak += q->candidates[i].peak; } + found_cell->peak /= nof_detected_frames; + if (nof_normal > q->mode_ntimes[mode_pos]/2) { found_cell->cp = CPNORM; } else { found_cell->cp = CPEXT; } found_cell->mode = (float) q->mode_ntimes[mode_pos]/nof_detected_frames; - found_cell->peak = q->candidates[nof_detected_frames-1].peak; + + // PSR is already averaged so take the last value + found_cell->psr = q->candidates[nof_detected_frames-1].psr; } /** Finds up to 3 cells, one per each N_id_2=0,1,2 and stores ID and CP in the structure pointed by found_cell. @@ -212,7 +219,7 @@ int ue_cell_search_scan_N_id_2(ue_cell_search_t * q, uint32_t N_id_2, ue_cell_se ret = LIBLTE_SUCCESS; ue_sync_set_N_id_2(&q->ue_sync, N_id_2); - + ue_sync_reset(&q->ue_sync); do { ret = ue_sync_get_buffer(&q->ue_sync, &sf_buffer); @@ -226,7 +233,8 @@ int ue_cell_search_scan_N_id_2(ue_cell_search_t * q, uint32_t N_id_2, ue_cell_se /* Save cell id, cp and peak */ q->candidates[nof_detected_frames].cell_id = (uint32_t) ret; q->candidates[nof_detected_frames].cp = sync_get_cp(&q->ue_sync.strack); - q->candidates[nof_detected_frames].peak = sync_get_peak_value(&q->ue_sync.strack); + q->candidates[nof_detected_frames].peak = q->ue_sync.strack.pss.peak_value; + q->candidates[nof_detected_frames].psr = sync_get_peak_value(&q->ue_sync.strack); INFO ("CELL SEARCH: [%3d/%3d/%d]: Found peak PSR=%.3f, Cell_id: %d CP: %s\n", nof_detected_frames, nof_scanned_frames, q->nof_frames_to_scan, @@ -262,9 +270,9 @@ int ue_cell_search_scan_N_id_2(ue_cell_search_t * q, uint32_t N_id_2, ue_cell_se ret = 1; // A cell has been found. if (found_cell) { get_cell(q, nof_detected_frames, found_cell); - printf("Found CELL PHYID: %d, CP: %s, PSR: %.1f, Reliability: %.0f \%\n", + printf("Found CELL PHYID: %d, CP: %s, PSR: %.1f, Absolute Peak: %.1f dBm, Reliability: %.0f \%\n", found_cell->cell_id, lte_cp_string(found_cell->cp), - found_cell->peak, 100*found_cell->mode); + found_cell->psr, 10*log10(found_cell->peak*1000), 100*found_cell->mode); } } else { ret = 0; // A cell was not found. diff --git a/matlab/tests/neighbour_cell_search.m b/matlab/tests/neighbour_cell_search.m new file mode 100644 index 000000000..881a53650 --- /dev/null +++ b/matlab/tests/neighbour_cell_search.m @@ -0,0 +1,61 @@ + +clear +NofENB = 1; + +for i=1:NofENB + enb = lteTestModel('1.1','5MHz'); + enb.TotSubframes = 10; + if (i == 1) + tx_signal = lteTestModelTool(enb); + else + tx_signal = tx_signal + lteTestModelTool(enb); + end +end + +corrcfg.PSS='On'; +corrcfg.SSS='On'; +corrcfg.CellRS='On'; + +cec = struct; % Channel estimation config structure +cec.PilotAverage = 'UserDefined'; % Type of pilot symbol averaging +cec.FreqWindow = 9; % Frequency window size +cec.TimeWindow = 9; % Time window size +cec.InterpType = 'Linear'; % 2D interpolation type +cec.InterpWindow = 'Centered'; % Interpolation window type +cec.InterpWinSize = 1; % Interpolation window size + + +addpath('../../debug/lte/phy/lib/sync/test') +addpath('../../debug/lte/phy/lib/ch_estimation/test') + +%tx_signal = signal; + +enb = struct('NDLRB',6,'CyclicPrefix','Normal','DuplexMode','FDD'); +[cellid, offset] = lteCellSearch(enb, tx_signal,1); + +enb.NCellID=cellid; +disp(offset) +enb.NSubframe = 0; + +rxWaveform = tx_signal(1+offset:end,:); +rxGrid = lteOFDMDemodulate(enb,rxWaveform); + +enb.CellRefP = 4; + +[hest, nest] = lteDLChannelEstimate(enb,cec,rxGrid); + +griddims = lteResourceGridSize(enb); % Resource grid dimensions +L = griddims(2); + +pbchIndices = ltePBCHIndices(enb); +[pbchRx, pbchHest] = lteExtractResources( ... + pbchIndices, rxGrid(:,1:L,:), hest(:,1:L,:,:)); + +% Decode PBCH +[bchBits, pbchSymbols, nfmod4, mib, enb.CellRefP] = ltePBCHDecode( ... + enb, pbchRx, pbchHest, nest); + +% Parse MIB bits +enb = lteMIB(mib, enb) + +%plot(angle(hest(:,[1 4],1,1)));