diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 363e5fb84..7b2242287 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -44,10 +44,14 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTI CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_32f_x2 HAVE_VOLK_DEINTERLEAVE_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_subtract_32f HAVE_VOLK_SUB_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_deinterleave_real_32f HAVE_VOLK_DEINTERLEAVE_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_index_max_16u HAVE_VOLK_MAX_ABS_FUNCTION) SET(VOLK_DEFINITIONS "HAVE_VOLK") +IF(${HAVE_VOLK_MAX_ABS_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MAX_ABS_FUNCTION") +ENDIF() IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") ENDIF() diff --git a/cuhd/include/liblte/cuhd/cuhd.h b/cuhd/include/liblte/cuhd/cuhd.h index 48da5883d..e1604b93d 100644 --- a/cuhd/include/liblte/cuhd/cuhd.h +++ b/cuhd/include/liblte/cuhd/cuhd.h @@ -48,6 +48,8 @@ LIBLTE_API int cuhd_start_rx_stream_nsamples(void *h, LIBLTE_API int cuhd_stop_rx_stream(void *h); +LIBLTE_API void cuhd_flush_buffer(void *h); + LIBLTE_API bool cuhd_rx_wait_lo_locked(void *h); LIBLTE_API double cuhd_set_rx_srate(void *h, diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp index b0f9baf61..9608c94a3 100644 --- a/cuhd/lib/cuhd_imp.cpp +++ b/cuhd/lib/cuhd_imp.cpp @@ -95,6 +95,15 @@ int cuhd_stop_rx_stream(void *h) return 0; } +void cuhd_flush_buffer(void *h) +{ + int n; + _Complex float tmp[1024]; + do { + n = cuhd_recv(h, tmp, 1024, 0); + } while (n > 0); +} + int cuhd_start_rx_stream_nsamples(void *h, uint32_t nsamples) { cuhd_handler *handler = static_cast < cuhd_handler * >(h); diff --git a/lte/phy/examples/cell_search.c b/lte/phy/examples/cell_search.c index d0670df32..4b35684c3 100644 --- a/lte/phy/examples/cell_search.c +++ b/lte/phy/examples/cell_search.c @@ -32,6 +32,7 @@ #include #include #include + #include #include "liblte/phy/phy.h" @@ -118,6 +119,7 @@ int main(int argc, char **argv) { ue_sync_t uesync; void *uhd; cf_t *buffer; + lte_cell_t cell; if (argc < 3) { usage(argv[0]); @@ -148,13 +150,12 @@ int main(int argc, char **argv) { cuhd_set_rx_freq(uhd, (double) channels[freq].fd * MHZ); cuhd_rx_wait_lo_locked(uhd); - if (ue_sync_init(&uesync, cuhd_set_rx_srate, cuhd_recv_wrapper, uhd)) { + if (ue_sync_init(&uesync, cell, cuhd_recv_wrapper, uhd)) { fprintf(stderr, "Error initiating UE sync\n"); exit(-1); } - ue_sync_set_nof_pbch_decodes(&uesync, 1); + ue_sync_decode_sss_on_track(&uesync, true); - ue_sync_change_srate(&uesync, false); DEBUG("Starting receiver...\n",0); cuhd_start_rx_stream(uhd); @@ -165,7 +166,6 @@ int main(int argc, char **argv) { frame_cnt = 0; ret = 0; ue_sync_reset(&uesync); - agc_reset(&uesync.agc); while(frame_cnt < nof_frames_find && ret == 0) { ret = ue_sync_get_buffer(&uesync, &buffer); @@ -174,8 +174,8 @@ int main(int argc, char **argv) { exit(-1); } frame_cnt++; - printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz looking for PSS. RSSI: %+2.2f dB...\r", freq, nof_freqs, - channels[freq].id, channels[freq].fd, 20*log10f(agc_get_rssi(&uesync.agc)));fflush(stdout); + printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz looking for PSS. \r", freq, nof_freqs, + channels[freq].id, channels[freq].fd);fflush(stdout); if (VERBOSE_ISINFO()) { printf("\n"); } @@ -185,8 +185,7 @@ int main(int argc, char **argv) { printf("[%3d/%d]: EARFCN %d Freq. %.2f MHz FOUND MIB ", freq, nof_freqs, channels[freq].id, channels[freq].fd); } - printf("RSSI: %+.2f dBm, CFO: %+.4f KHz\n", - 20*log10f(agc_get_rssi(&uesync.agc)), ue_sync_get_cfo(&uesync)); + printf("CFO: %+.4f KHz\n", ue_sync_get_cfo(&uesync)); printf("\n");fflush(stdout); } diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c index 41d6e6a48..76b94997f 100644 --- a/lte/phy/examples/iodev.c +++ b/lte/phy/examples/iodev.c @@ -33,7 +33,7 @@ #include "iodev.h" #include "liblte/phy/io/filesource.h" -#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/ue/ue_sync.h" #include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/vector.h" @@ -80,8 +80,9 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) { DEBUG("Starting receiver...\n", 0); cuhd_start_rx_stream(q->uhd); - - ue_sync_init(&q->sframe, cuhd_set_rx_srate, cuhd_recv_wrapper, q->uhd); + + lte_cell_t cell; + ue_sync_init(&q->sframe, cell, cuhd_recv_wrapper, q->uhd); // 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 3164f91c5..81f7a67ef 100644 --- a/lte/phy/examples/iodev.h +++ b/lte/phy/examples/iodev.h @@ -30,7 +30,7 @@ #include "liblte/config.h" -#include "liblte/phy/phch/ue_sync.h" +#include "liblte/phy/ue/ue_sync.h" #include "liblte/phy/io/filesource.h" #ifndef DISABLE_UHD diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index f761b043b..b0b9ffc95 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -257,7 +257,7 @@ int main(int argc, char **argv) { N_id_2 = cell.id % 3; sf_n_re = 2 * CPNORM_NSYMB * cell.nof_prb * RE_X_RB; - sf_n_samples = 2 * SLOT_LEN_CPNORM(lte_symbol_sz(cell.nof_prb)); + sf_n_samples = 2 * SLOT_LEN(lte_symbol_sz(cell.nof_prb)); /* this *must* be called after setting slot_len_* */ base_init(); diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 2af627e65..b67a9b1de 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -171,7 +171,7 @@ int main(int argc, char **argv) { symbol_sz = lte_symbol_sz(prog_args.nof_prb_file); if (symbol_sz > 0) { - if (iodev_init(&iodev, &prog_args.io_config, SF_LEN(symbol_sz, CPNORM))) { + if (iodev_init(&iodev, &prog_args.io_config, SF_LEN(symbol_sz))) { fprintf(stderr, "Error initiating input device\n"); exit(-1); } @@ -197,9 +197,6 @@ int main(int argc, char **argv) { /* Decodes the SSS signal during the tracking phase. Extra overhead, but makes sure we are in the correct subframe */ ue_sync_decode_sss_on_track(&iodev.sframe, true); - /* Decodes the PBCH on each frame. Around 10% more overhead, but makes sure we are in the current System Frame Number (SFN) */ - ue_sync_pbch_always(&iodev.sframe, false); - /* Main loop */ while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { @@ -212,13 +209,13 @@ int main(int argc, char **argv) { /* iodev_receive returns 1 if successfully read 1 aligned subframe */ if (ret == 0) { printf("Finding PSS... Peak: %8.1f, Output level: %+.2f dB FrameCnt: %d, State: %d\r", - sync_get_peak_value(&iodev.sframe.s), 20*log10f(agc_get_output_level(&iodev.sframe.agc)), + sync_get_peak_value(&iodev.sframe.sfind), iodev.sframe.frame_total_cnt, iodev.sframe.state); } else if (ret == 1) { if (!ue_dl_initiated) { if (iodev_isUSRP(&iodev)) { - cell = ue_sync_get_cell(&iodev.sframe); - mib = ue_sync_get_mib(&iodev.sframe); + //cell = ue_sync_get_cell(&iodev.sframe); + //mib = ue_sync_get_mib(&iodev.sframe); } else { cell.id = prog_args.cell_id_file; cell.cp = CPNORM; @@ -237,7 +234,8 @@ int main(int argc, char **argv) { if (iodev_isUSRP(&iodev)) { sf_idx = ue_sync_get_sfidx(&iodev.sframe); } - rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti); + //rlen = ue_dl_receive(&ue_dl, sf_buffer, data, sf_idx, ue_sync_get_mib(&iodev.sframe).sfn, prog_args.rnti); + rlen=-1; if (rlen < 0) { fprintf(stderr, "\nError running receiver\n");fflush(stdout); exit(-1); @@ -249,8 +247,7 @@ int main(int argc, char **argv) { printed_sib = true; } if (!(sf_cnt % 10)) { - printf("RSSI: %+.2f dBm, CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e\r", - 20*log10f(agc_get_rssi(&iodev.sframe.agc))+30, + printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e\r", ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000, pdsch_average_noi(&ue_dl.pdsch), (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (float) ue_dl.pkt_errors / ue_dl.pkts_total); diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 29e8c233e..7304ddb77 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -82,17 +82,12 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define CP_NORM(symbol, symbol_sz) (symbol==0)?CP(symbol_sz,CPNORM_0_LEN):CP(symbol_sz,CPNORM_LEN) #define CP_EXT(symbol_sz) CP(symbol_sz,CPEXT_LEN) -#define SLOT_LEN_CPNORM(symbol_sz) (symbol_sz+CP(symbol_sz,CPNORM_0_LEN)+(CPNORM_NSYMB-1)*(symbol_sz+CP(symbol_sz,CPNORM_LEN))) -#define SLOT_LEN_CPEXT(symbol_sz) (CPEXT_NSYMB*(symbol_sz+CP(symbol_sz, CPEXT_LEN))) -#define SLOT_LEN(symbol_sz, cp) (CP_ISNORM(cp)?SLOT_LEN_CPNORM(symbol_sz):SLOT_LEN_CPEXT(symbol_sz)) +#define SLOT_LEN(symbol_sz) (480*((symbol_sz)/64)) +#define SF_LEN(symbol_sz) (2*SLOT_LEN(symbol_sz)) +#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX) -#define SF_LEN_CPNORM(symbol_sz) (2*SLOT_LEN_CPNORM(symbol_sz)) -#define SF_LEN_CPEXT(symbol_sz) (2*SLOT_LEN_CPEXT(symbol_sz)) -#define SF_LEN(symbol_sz, cp) (2*SLOT_LEN(symbol_sz, cp)) -#define SF_LEN_MAX SF_LEN(SYMBOL_SZ_MAX, CPNORM) - -#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp)) -#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp)) +#define SLOT_LEN_RE(nof_prb, cp) (nof_prb*RE_X_RB*CP_NSYMB(cp)) +#define SF_LEN_RE(nof_prb, cp) (2*SLOT_LEN_RE(nof_prb, cp)) #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))) diff --git a/lte/phy/include/liblte/phy/phch/pbch.h b/lte/phy/include/liblte/phy/phch/pbch.h index 9769f66cf..e8a79b513 100644 --- a/lte/phy/include/liblte/phy/phch/pbch.h +++ b/lte/phy/include/liblte/phy/phch/pbch.h @@ -89,13 +89,13 @@ LIBLTE_API int pbch_init(pbch_t *q, LIBLTE_API void pbch_free(pbch_t *q); LIBLTE_API int pbch_decode(pbch_t *q, - cf_t *sf_symbols, - cf_t *ce[MAX_PORTS], + cf_t *slot1_symbols, + cf_t *ce_slot1[MAX_PORTS], pbch_mib_t *mib); LIBLTE_API int pbch_encode(pbch_t *q, pbch_mib_t *mib, - cf_t *sf_symbols[MAX_PORTS]); + cf_t *slot1_symbols[MAX_PORTS]); LIBLTE_API void pbch_decode_reset(pbch_t *q); diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index 3de436895..5b558a705 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -92,8 +92,11 @@ #include "liblte/phy/phch/pbch.h" #include "liblte/phy/phch/pcfich.h" #include "liblte/phy/phch/phich.h" -#include "liblte/phy/phch/ue_sync.h" -#include "liblte/phy/phch/ue_dl.h" + +#include "liblte/phy/ue/ue_sync.h" +#include "liblte/phy/ue/ue_mib.h" +#include "liblte/phy/ue/ue_cellsearch.h" +#include "liblte/phy/ue/ue_dl.h" #include "liblte/phy/scrambling/scrambling.h" diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index bdf298223..22828240e 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -72,7 +72,6 @@ typedef struct LIBLTE_API { cf_t *pss_signal_freq[3]; // One sequence for each N_id_2 cf_t *tmp_input; - float *conv_real; cf_t *conv_output; }pss_synch_t; diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index c86d389ff..0cf86b7c9 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -52,65 +52,59 @@ */ typedef struct LIBLTE_API { - pss_synch_t pss_find; - pss_synch_t pss_track; + pss_synch_t pss; sss_synch_t sss; - float find_threshold; - float track_threshold; + float threshold; + float mean_energy; float peak_value; + float mean_peak_value; uint32_t N_id_2; uint32_t N_id_1; - uint32_t slot_id; + uint32_t sf_idx; uint32_t fft_size; - uint32_t find_frame_size; + uint32_t frame_size; + uint64_t frame_cnt; float cfo; bool detect_cp; bool sss_en; + bool normalize_en; lte_cp_t cp; }sync_t; LIBLTE_API int sync_init(sync_t *q, - uint32_t find_frame_size, - uint32_t track_frame_size, + uint32_t frame_size, uint32_t fft_size); LIBLTE_API void sync_free(sync_t *q); -LIBLTE_API int sync_realloc(sync_t *q, - uint32_t find_frame_size, - uint32_t track_frame_size, - uint32_t fft_size); +LIBLTE_API void sync_reset(sync_t *q); -/* Finds a correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be - subframe_size long at least */ +/* Finds a correlation peak in the input signal around position find_offset */ LIBLTE_API int sync_find(sync_t *q, cf_t *input, + uint32_t find_offset, uint32_t *peak_position); -/* Tracks the correlation peak in the input signal. The signal must be sampled at 1.92 MHz and should be - TRACK_LEN long at least */ -LIBLTE_API int sync_track(sync_t *q, - cf_t *input, - uint32_t offset, - uint32_t *peak_position); - /* Sets the threshold for peak comparison */ LIBLTE_API void sync_set_threshold(sync_t *q, - float find_threshold, - float track_threshold); + float threshold); -/* Gets the slot id (0 or 10) */ -LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); +/* Gets the subframe idx (0 or 5) */ +LIBLTE_API uint32_t sync_get_sf_idx(sync_t *q); -/* Gets the last peak-to-average ratio */ +/* Gets the last peak value */ +LIBLTE_API float sync_get_last_peak_value(sync_t *q); + +/* Gets the mean peak value */ LIBLTE_API float sync_get_peak_value(sync_t *q); -/* Gets the N_id_2 from the last call to synch_run() */ -LIBLTE_API uint32_t sync_get_N_id_2(sync_t *q); +/* Gets the last input signal energy estimation value */ +LIBLTE_API float sync_get_input_energy(sync_t *q); -/* Gets the N_id_1 from the last call to synch_run() */ -LIBLTE_API uint32_t sync_get_N_id_1(sync_t *q); +/* Sets the N_id_2 to search for */ +LIBLTE_API int sync_set_N_id_2(sync_t *q, + uint32_t N_id_2); /* Gets the Physical CellId from the last call to synch_run() */ LIBLTE_API int sync_get_cell_id(sync_t *q); @@ -121,6 +115,10 @@ 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); +/* Enables/Disables energy normalization every frame. If disabled, uses the mean */ +LIBLTE_API void sync_normalize_en(sync_t *q, + bool enable); + /* Enables/Disables SSS detection */ LIBLTE_API void sync_sss_en(sync_t *q, bool enabled); diff --git a/lte/phy/include/liblte/phy/ue/ue_cellsearch.h b/lte/phy/include/liblte/phy/ue/ue_cellsearch.h new file mode 100644 index 000000000..03f694fd0 --- /dev/null +++ b/lte/phy/include/liblte/phy/ue/ue_cellsearch.h @@ -0,0 +1,131 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef UE_CELLSEARCH_ +#define UE_CELLSEARCH_ + +#include + +#include "liblte/config.h" +#include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/cfo.h" +#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/phch/pbch.h" +#include "liblte/phy/common/fft.h" + +/************************************************************ + * + * This object scans a signal for LTE cells using the known PSS + * and SSS sequences. + * + * The function ue_cellsearch_scan() shall be called multiple times, + * each passing a number of samples multiple of 4800, sampled at 960 KHz + * (that is, 5 ms of samples). + * + * The function returns 0 until a signal is found nof_frames_detected times or + * after nof_frames_total with no signal detected. + * + * See ue_cell_detect.c for an example. + * + ************************************************************/ + +/** + * TODO: Check also peak offset + */ + +#define CS_DEFAULT_MAXFRAMES_TOTAL 300 +#define CS_DEFAULT_MAXFRAMES_DETECTED 30 + +#define CS_DEFAULT_NOFFRAMES_TOTAL 100 +#define CS_DEFAULT_NOFFRAMES_DETECTED 10 + +#define CS_FIND_THRESHOLD 0.6 + +#define CS_FRAME_UNALIGNED -3 +#define CS_CELL_DETECTED 2 +#define CS_CELL_NOT_DETECTED 1 + +typedef struct LIBLTE_API { + uint32_t cell_id; + lte_cp_t cp; + float peak; + uint32_t mode; +} ue_cellsearch_result_t; + + +typedef struct LIBLTE_API { + sync_t sfind; + uint32_t max_frames_total; + uint32_t max_frames_detected; + uint32_t nof_frames_total; + uint32_t nof_frames_detected; + + uint32_t current_nof_detected; + uint32_t current_nof_total; + + uint32_t current_N_id_2; + + uint32_t *mode_ntimes; + char *mode_counted; + + ue_cellsearch_result_t *candidates; +} ue_cellsearch_t; + + +LIBLTE_API int ue_cellsearch_init(ue_cellsearch_t *q); + +LIBLTE_API int ue_cellsearch_init_max(ue_cellsearch_t *q, + uint32_t max_frames_total, + uint32_t max_frames_detected); + +LIBLTE_API void ue_cellsearch_free(ue_cellsearch_t *q); + +LIBLTE_API void ue_cellsearch_reset(ue_cellsearch_t *q); + +LIBLTE_API int ue_cellsearch_scan(ue_cellsearch_t *q, + cf_t *signal, + uint32_t nsamples, + ue_cellsearch_result_t *found_cell); + +LIBLTE_API int ue_cellsearch_set_nof_frames_total(ue_cellsearch_t *q, + uint32_t nof_frames); + +LIBLTE_API int ue_cellsearch_set_nof_frames_detected(ue_cellsearch_t *q, + uint32_t nof_frames); + +LIBLTE_API void ue_cellsearch_set_threshold(ue_cellsearch_t *q, + float threshold); + +LIBLTE_API void ue_cellsearch_reset(ue_cellsearch_t *q); + + + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/phch/ue_dl.h b/lte/phy/include/liblte/phy/ue/ue_dl.h similarity index 100% rename from lte/phy/include/liblte/phy/phch/ue_dl.h rename to lte/phy/include/liblte/phy/ue/ue_dl.h diff --git a/lte/phy/include/liblte/phy/ue/ue_mib.h b/lte/phy/include/liblte/phy/ue/ue_mib.h new file mode 100644 index 000000000..31624d6f9 --- /dev/null +++ b/lte/phy/include/liblte/phy/ue/ue_mib.h @@ -0,0 +1,109 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef UE_MIB_ +#define UE_MIB_ + + +/************************************************************ + * + * This object decodes the MIB from the PBCH of an LTE signal. + * + * The function ue_mib_decode() shall be called multiple times, + * each passing a number of samples multiple of 19200, sampled at 1.92 MHz + * (that is, 10 ms of samples). + * + * The function uses the sync_t object to find the PSS sequence and + * decode the PBCH to obtain the MIB. + * + * The function returns 0 until the MIB is decoded. + * + * See ue_cell_detect.c for an example. + * + ************************************************************/ + +#include + +#include "liblte/config.h" +#include "liblte/phy/sync/sync.h" +#include "liblte/phy/sync/cfo.h" +#include "liblte/phy/ch_estimation/chest.h" +#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 +#define MIB_FOUND 1 +#define MIB_NOTFOUND 0 + +typedef struct LIBLTE_API { + sync_t sfind; + + uint32_t cell_id; + + cf_t *slot1_symbols; + cf_t *ce[MIB_NOF_PORTS]; + + lte_fft_t fft; + chest_t chest; + pbch_t pbch; + + uint32_t frame_cnt; + uint32_t last_frame_trial; +} ue_mib_t; + + +LIBLTE_API int ue_mib_init(ue_mib_t *q, + uint32_t cell_id, + lte_cp_t cp); + +LIBLTE_API void ue_mib_free(ue_mib_t *q); + +LIBLTE_API void ue_mib_reset(ue_mib_t *q); + +LIBLTE_API int ue_mib_decode(ue_mib_t *q, + cf_t *signal, + uint32_t nsamples, + pbch_mib_t *mib); + +LIBLTE_API void ue_mib_set_threshold(ue_mib_t *q, + float threshold); + +LIBLTE_API void ue_mib_reset(ue_mib_t *q); + + + + + + +#endif // SYNC_FRAME_ + diff --git a/lte/phy/include/liblte/phy/phch/ue_sync.h b/lte/phy/include/liblte/phy/ue/ue_sync.h similarity index 62% rename from lte/phy/include/liblte/phy/phch/ue_sync.h rename to lte/phy/include/liblte/phy/ue/ue_sync.h index d26b9a8b2..1e608ebbf 100644 --- a/lte/phy/include/liblte/phy/phch/ue_sync.h +++ b/lte/phy/include/liblte/phy/ue/ue_sync.h @@ -36,57 +36,36 @@ #include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/phch/pbch.h" #include "liblte/phy/common/fft.h" -#include "liblte/phy/agc/agc.h" /************************************************************** * - * This object automatically manages the cell association and - * synchronization procedure. By default, it associates with the - * CELL whose correlation peak to average ratio is the highest. - * - * TODO: Associate with arbitrary CELL ID + * This object automatically manages the cell synchronization procedure. * * The main function is ue_sync_get_buffer(), which returns a pointer * to the aligned subframe of samples (before FFT). This function * should be called regularly, returning every 1 ms. It reads from the * USRP, aligns the samples to the subframe and performs time/freq synch. * - * The function returns 0 during the cell association procedure, which includes - * PSS/SSS synchronization, MIB decoding from the PBCH and sampling frequency - * adjustment (according to signal bandwidth) and resynchronization. - * * The function returns 1 when the signal is correctly acquired and the * returned buffer is aligned with the subframe. * - * *************************************************************/ -typedef enum LIBLTE_API { SF_AGC, SF_FIND, SF_TRACK} ue_sync_state_t; - -#define SYNC_PBCH_NOF_PRB 6 -#define SYNC_PBCH_NOF_PORTS 2 +typedef enum LIBLTE_API { SF_FIND, SF_TRACK} ue_sync_state_t; #define TRACK_MAX_LOST 10 - -#define DEFAULT_NOF_MIB_DECODES 10 - -#define AGC_NOF_FRAMES 100 - #define MEASURE_EXEC_TIME typedef struct LIBLTE_API { - sync_t s; + sync_t sfind; + sync_t strack; void *stream; - double (*set_rate_callback)(void*, double); int (*recv_callback)(void*, void*, uint32_t); ue_sync_state_t state; cf_t *input_buffer; - cf_t *receive_buffer; - cf_t *sf_symbols; - cf_t *ce[SYNC_PBCH_NOF_PORTS]; /* These count half frames (5ms) */ uint64_t frame_ok_cnt; @@ -101,21 +80,7 @@ typedef struct LIBLTE_API { cfo_t cfocorr; float cur_cfo; - - /* Variables for PBCH decoding */ - agc_t agc; - pbch_mib_t mib; - lte_fft_t fft; - chest_t chest; - pbch_t pbch; - bool pbch_initialized; - uint32_t pbch_decoded; - bool pbch_decode_always; - bool pbch_decoder_enabled; - uint32_t pbch_last_trial; - bool change_srate; - uint32_t nof_mib_decodes; - + bool decode_sss_on_track; uint32_t peak_idx; @@ -128,7 +93,7 @@ typedef struct LIBLTE_API { LIBLTE_API int ue_sync_init(ue_sync_t *q, - double (set_rate_callback)(void*, double), + lte_cell_t cell, int (recv_callback)(void*, void*, uint32_t), void *stream_handler); @@ -137,34 +102,15 @@ LIBLTE_API void ue_sync_free(ue_sync_t *q); LIBLTE_API int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols); -LIBLTE_API void ue_sync_set_nof_pbch_decodes(ue_sync_t *q, - uint32_t nof_pbch_decodes); - - LIBLTE_API void ue_sync_reset(ue_sync_t *q); LIBLTE_API void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled); -LIBLTE_API void ue_sync_pbch_enable(ue_sync_t *q, - bool enabled); - -LIBLTE_API void ue_sync_change_srate(ue_sync_t *q, - bool enabled); - -LIBLTE_API void ue_sync_pbch_always(ue_sync_t *q, - bool enabled); - LIBLTE_API ue_sync_state_t ue_sync_get_state(ue_sync_t *q); LIBLTE_API uint32_t ue_sync_get_sfidx(ue_sync_t *q); -LIBLTE_API lte_cell_t ue_sync_get_cell(ue_sync_t *q); - -LIBLTE_API pbch_mib_t ue_sync_get_mib(ue_sync_t *q); - -LIBLTE_API bool ue_sync_is_mib_decoded(ue_sync_t *q); - LIBLTE_API float ue_sync_get_cfo(ue_sync_t *q); LIBLTE_API float ue_sync_get_sfo(ue_sync_t *q); diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 5a65a0d30..06a57b0cc 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -99,6 +99,7 @@ LIBLTE_API float vec_avg_power_cf(cf_t *x, uint32_t len); /* return the index of the maximum value in the vector */ LIBLTE_API uint32_t vec_max_fi(float *x, uint32_t len); +LIBLTE_API uint32_t vec_max_abs_ci(cf_t *x, uint32_t len); /* quantify vector of floats and convert to unsigned char */ LIBLTE_API void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len); diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 843266d7f..7436b0ad9 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -145,7 +145,7 @@ 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]; - INFO("Estimating channel slot=%d port=%d using %d reference signals\n", + DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n", nslot, port_id, r->nof_refs); for (i=0;inof_refs;i++) { @@ -276,6 +276,7 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ { ret = refsignal_init_LTEDL(&q->refsignal[port_id][nslot], port_id, nslot, cell); +#ifdef VOLK_INTERP if (ret == LIBLTE_SUCCESS) { if (nslot == 0) { ret = interp_init(&q->interp_freq[port_id], LINEAR, q->refsignal[port_id][nslot].nof_refs/2, RE_X_RB/2); @@ -285,6 +286,7 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ } } } +#endif } return ret; } @@ -318,6 +320,10 @@ void chest_free(chest_t *q) { refsignal_free(&q->refsignal[p][n]); } } +#ifdef VOLK_INTERP + interp_free(&q->interp_freq); + interp_free(&q->interp_time); +#endif bzero(q, sizeof(chest_t)); } diff --git a/lte/phy/lib/common/src/fft.c b/lte/phy/lib/common/src/fft.c index a21aa2c15..b5818c979 100644 --- a/lte/phy/lib/common/src/fft.c +++ b/lte/phy/lib/common/src/fft.c @@ -61,7 +61,7 @@ int lte_fft_init_(lte_fft_t *q, lte_cp_t cp, uint32_t nof_prb, dft_dir_t dir) { q->cp = cp; q->nof_re = nof_prb * RE_X_RB; q->nof_guards = ((symbol_sz - q->nof_re) / 2); - q->slot_sz = SLOT_LEN(symbol_sz, cp); + q->slot_sz = SLOT_LEN(symbol_sz); DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir==FORWARD?"FFT":"iFFT", q->symbol_sz, q->nof_symbols, diff --git a/lte/phy/lib/common/test/fft_test.c b/lte/phy/lib/common/test/fft_test.c index 8d6f883bf..74f14f311 100644 --- a/lte/phy/lib/common/test/fft_test.c +++ b/lte/phy/lib/common/test/fft_test.c @@ -87,7 +87,7 @@ int main(int argc, char **argv) { perror("malloc"); exit(-1); } - outfft = malloc(sizeof(cf_t) * SLOT_LEN_CPNORM(lte_symbol_sz(n_prb))); + outfft = malloc(sizeof(cf_t) * SLOT_LEN(lte_symbol_sz(n_prb))); if (!outfft) { perror("malloc"); exit(-1); diff --git a/lte/phy/lib/phch/src/pbch.c b/lte/phy/lib/phch/src/pbch.c index 1fe2c8e87..d2f5ca450 100644 --- a/lte/phy/lib/phch/src/pbch.c +++ b/lte/phy/lib/phch/src/pbch.c @@ -453,30 +453,25 @@ int pbch_decode_frame(pbch_t *q, pbch_mib_t *mib, uint32_t src, uint32_t dst, ui * * Returns 1 if successfully decoded MIB, 0 if not and -1 on error */ -int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mib) { +int pbch_decode(pbch_t *q, cf_t *slot1_symbols, cf_t *ce_slot1[MAX_PORTS], pbch_mib_t *mib) { uint32_t src, dst, nb; uint32_t nant_[3] = { 1, 2, 4 }; uint32_t na, nant; - cf_t *slot1_symbols; int i; int nof_bits; cf_t *x[MAX_LAYERS]; - cf_t *ce_slot[MAX_PORTS]; int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && - sf_symbols != NULL && + slot1_symbols != NULL && mib != NULL) { for (i=0;icell.nof_ports;i++) { - if (ce[i] == NULL) { + if (ce_slot1[i] == NULL) { return LIBLTE_ERROR_INVALID_INPUTS; - } else { - ce_slot[i] = &ce[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; - } + } } - slot1_symbols = &sf_symbols[q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; /* Set pointers for layermapping & precoding */ nof_bits = 2 * q->nof_symbols; @@ -495,7 +490,7 @@ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mi /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { - if (q->nof_symbols != pbch_get(ce_slot[i], q->ce[i], q->cell)) { + if (q->nof_symbols != pbch_get(ce_slot1[i], q->ce[i], q->cell)) { fprintf(stderr, "There was an error getting the PBCH symbols\n"); return LIBLTE_ERROR; } @@ -508,7 +503,7 @@ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mi for (na = 0; na < q->cell.nof_ports && !ret; na++) { nant = nant_[na]; - INFO("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); + DEBUG("Trying %d TX antennas with %d frames\n", nant, q->frame_idx); /* in conctrol channels, only diversity is supported */ if (nant == 1) { @@ -554,21 +549,18 @@ int pbch_decode(pbch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], pbch_mib_t *mi /** Converts the MIB message to symbols mapped to SLOT #1 ready for transmission */ -int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *sf_symbols[MAX_PORTS]) { +int pbch_encode(pbch_t *q, pbch_mib_t *mib, cf_t *slot1_symbols[MAX_PORTS]) { int i; int nof_bits; - cf_t *slot1_symbols[MAX_PORTS]; cf_t *x[MAX_LAYERS]; if (q != NULL && mib != NULL) { for (i=0;icell.nof_ports;i++) { - if (sf_symbols[i] == NULL) { + if (slot1_symbols[i] == NULL) { return LIBLTE_ERROR_INVALID_INPUTS; - } else { - slot1_symbols[i] = &sf_symbols[i][q->cell.nof_prb * RE_X_RB * CP_NSYMB(q->cell.cp)]; - } + } } /* Set pointers for layermapping & precoding */ nof_bits = 2 * q->nof_symbols; diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c deleted file mode 100644 index 8a4a45bdf..000000000 --- a/lte/phy/lib/phch/src/ue_sync.c +++ /dev/null @@ -1,627 +0,0 @@ -/** - * - * \section COPYRIGHT - * - * Copyright 2013-2014 The libLTE Developers. See the - * COPYRIGHT file at the top-level directory of this distribution. - * - * \section LICENSE - * - * This file is part of the libLTE library. - * - * libLTE is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. - * - * libLTE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * A copy of the GNU Lesser General Public License can be found in - * the LICENSE file in the top-level directory of this distribution - * and at http://www.gnu.org/licenses/. - * - */ - -#include -#include -#include -#include -#include - - -#include "liblte/phy/phch/ue_sync.h" - -#include "liblte/phy/utils/debug.h" -#include "liblte/phy/utils/vector.h" - -#define MAX_TIME_OFFSET 128 -cf_t dummy[MAX_TIME_OFFSET]; - -#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) -#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) - -#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 MAXIMUM_SFLEN SF_LEN(2048, CPNORM) -#define MAXIMUM_SFLEN_RE SF_LEN_RE(110, CPNORM) - -static int mib_decoder_initialize(ue_sync_t *q); -static void mib_decoder_free(ue_sync_t *q); - - -static void update_threshold(ue_sync_t *q) { - int symbol_sz = lte_symbol_sz(q->cell.nof_prb); - if (symbol_sz > 0) { - switch (symbol_sz) { - case 128: - sync_set_threshold(&q->s, 10000, 1000); - break; - case 256: - sync_set_threshold(&q->s, 20000, 2000); - break; - case 512: - sync_set_threshold(&q->s, 30000, 3000); - break; - case 1024: - sync_set_threshold(&q->s, 40000, 4000); - break; - case 2048: - sync_set_threshold(&q->s, 50000, 5000); - } - } -} - -int ue_sync_init(ue_sync_t *q, - double (set_rate_callback)(void*, double), - int (recv_callback)(void*, void*, uint32_t), - void *stream_handler) -{ - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - stream_handler != NULL && - set_rate_callback != NULL && - recv_callback != NULL) - { - ret = LIBLTE_ERROR; - - bzero(q, sizeof(ue_sync_t)); - - ue_sync_reset(q); - - q->cell.nof_prb = SYNC_PBCH_NOF_PRB; - q->cell.nof_ports = SYNC_PBCH_NOF_PORTS; - q->cell.id = 0; - q->cell.cp = CPNORM; - - q->pbch_decoded = false; - q->pbch_initialized = false; - q->pbch_decoder_enabled = true; - q->pbch_decode_always = false; - q->decode_sss_on_track = false; - q->change_srate = true; - q->nof_mib_decodes = DEFAULT_NOF_MIB_DECODES; - q->stream = stream_handler; - q->recv_callback = recv_callback; - q->set_rate_callback = set_rate_callback; - - INFO("Setting sampling frequency 1.92 MHz\n",0); - q->set_rate_callback(q->stream, 1920000.0); - - if (agc_init(&q->agc)) { - goto clean_exit; - } - - if(sync_init(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { - goto clean_exit; - } - - if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) { - fprintf(stderr, "Error initiating CFO\n"); - goto clean_exit; - } - - q->input_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); - if (!q->input_buffer) { - perror("malloc"); - goto clean_exit; - } - - q->receive_buffer = vec_malloc(3 * MAXIMUM_SFLEN * sizeof(cf_t)); - if (!q->receive_buffer) { - perror("malloc"); - goto clean_exit; - } - - q->sf_symbols = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); - if (!q->sf_symbols) { - perror("malloc"); - goto clean_exit; - } - for (int i=0;ice[i] = vec_malloc(MAXIMUM_SFLEN_RE * sizeof(cf_t)); - if (!q->ce[i]) { - perror("malloc"); - goto clean_exit; - } - } - - update_threshold(q); - - ret = LIBLTE_SUCCESS; - } - -clean_exit: - if (ret == LIBLTE_ERROR) { - ue_sync_free(q); - } - return ret; -} - -void ue_sync_free(ue_sync_t *q) { - if (q->input_buffer) { - free(q->input_buffer); - } - if (q->receive_buffer) { - free(q->receive_buffer); - } - if (q->sf_symbols) { - free(q->sf_symbols); - } - for (int i=0;ice[i]) { - free(q->ce[i]); - } - } - mib_decoder_free(q); - cfo_free(&q->cfocorr); - sync_free(&q->s); - agc_free(&q->agc); -} - -lte_cell_t ue_sync_get_cell(ue_sync_t *q) { - return q->cell; -} - -pbch_mib_t ue_sync_get_mib(ue_sync_t *q) { - return q->mib; -} - -uint32_t ue_sync_peak_idx(ue_sync_t *q) { - return q->peak_idx; -} - -ue_sync_state_t ue_sync_get_state(ue_sync_t *q) { - return q->state; -} - -void ue_sync_change_srate(ue_sync_t *q, bool enabled) { - q->change_srate = enabled; -} - -static int update_srate(ue_sync_t *q) { - struct timeval t[3]; - - gettimeofday(&t[1], NULL); - if (sync_realloc(&q->s, CURRENT_SFLEN, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { - fprintf(stderr, "Error realloc'ing SYNC\n"); - return LIBLTE_ERROR; - } - gettimeofday(&t[2], NULL); - get_time_interval(t); - - if (q->nof_mib_decodes > 1) { - mib_decoder_free(q); - if (mib_decoder_initialize(q)) { - fprintf(stderr, "Error reinitializing MIB decoder\n"); - return LIBLTE_ERROR; - } - } - - // Finally set the new sampling rate - q->set_rate_callback(q->stream, (float) lte_sampling_freq_hz(q->cell.nof_prb)); - - update_threshold(q); - - ue_sync_reset(q); - INFO("Set sampling rate %.2f MHz, fft_size=%d, sf_len=%d Threshold=%.2f/%.2f Texec=%d us\n", - (float) lte_sampling_freq_hz(q->cell.nof_prb)/1000000, - CURRENT_FFTSIZE, CURRENT_SFLEN, q->s.find_threshold, q->s.track_threshold, (int) t[0].tv_usec); - - return LIBLTE_SUCCESS; -} - -uint32_t ue_sync_get_sfidx(ue_sync_t *q) { - return q->sf_idx; -} - -float ue_sync_get_cfo(ue_sync_t *q) { - return 15000 * q->cur_cfo; -} - -float ue_sync_get_sfo(ue_sync_t *q) { - return 1000*q->mean_time_offset/5; -} - -bool ue_sync_is_mib_decoded(ue_sync_t *q) { - return q->pbch_decoded; -} - -void ue_sync_pbch_enable(ue_sync_t *q, bool enabled) { - q->pbch_decoder_enabled = enabled; -} - -void ue_sync_pbch_always(ue_sync_t *q, bool enabled) { - q->pbch_decode_always = enabled; -} - -void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { - q->decode_sss_on_track = enabled; -} - -void ue_sync_set_nof_pbch_decodes(ue_sync_t *q, uint32_t nof_pbch_decodes) { - q->nof_mib_decodes = nof_pbch_decodes; -} - -static int mib_decoder_initialize(ue_sync_t *q) { - - if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { - fprintf(stderr, "Error initializing FFT\n"); - return -1; - } - if (chest_init_LTEDL(&q->chest, q->cell)) { - fprintf(stderr, "Error initializing reference signal\n"); - return -1; - } - if (pbch_init(&q->pbch, q->cell)) { - fprintf(stderr, "Error initiating PBCH\n"); - return -1; - } - q->pbch_initialized = 1; - DEBUG("PBCH initiated cell_id=%d\n", q->cell.id); - - return 0; -} - -static void mib_decoder_free(ue_sync_t *q) { - chest_free(&q->chest); - pbch_free(&q->pbch); - lte_fft_free(&q->fft); -} - -static int mib_decoder_run(ue_sync_t *q) { - int ret; - - /* Run FFT for the second slot */ - lte_fft_run_sf(&q->fft, q->input_buffer, q->sf_symbols); - - /* Get channel estimates of slot #1 for each port */ - chest_ce_sf(&q->chest, q->sf_symbols, q->ce, 0); - - if (q->pbch_last_trial && - (q->frame_total_cnt - q->pbch_last_trial > 2)) - { - pbch_decode_reset(&q->pbch); - INFO("Resetting PBCH decoder: last trial %d, now is %d\n", - q->pbch_last_trial, q->frame_total_cnt); - q->pbch_last_trial = 0; - } - - if (pbch_decode(&q->pbch, q->sf_symbols, q->ce, &q->mib) == 1) { - q->frame_number = q->mib.sfn; - q->cell.nof_ports = q->mib.nof_ports; - - if (!q->pbch_decoded) { - printf("\n\nMIB decoded:\n"); - pbch_mib_fprint(stdout, &q->mib, q->cell.id); - - if (q->cell.nof_prb != q->mib.nof_prb) { - q->cell.nof_prb = q->mib.nof_prb; - if (q->change_srate) { - ret = update_srate(q); - } - } - } else { - INFO("MIB decoded #%d SFN: %d\n", q->pbch_decoded, q->mib.sfn); - } - q->pbch_decoded++; - - pbch_decode_reset(&q->pbch); - - } else { - INFO("MIB not decoded: %d\n", q->frame_total_cnt/2); - q->pbch_last_trial = q->frame_total_cnt; - } - - return ret; -} - -static int find_peak_ok(ue_sync_t *q) { - int ret; - - if (q->peak_idx < CURRENT_SFLEN) { - /* Receive the rest of the next subframe */ - if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) { - return LIBLTE_ERROR; - } - } - - if (sync_sss_detected(&q->s)) { - ret = sync_get_cell_id(&q->s); - if (ret >= 0) { - q->cell.id = (uint32_t) ret; - q->cell.cp = sync_get_cp(&q->s); - } - - /* Get the subframe index (0 or 5) */ - q->sf_idx = sync_get_slot_id(&q->s)/2; - - /* Reset variables */ - q->frame_ok_cnt = 0; - q->frame_no_cnt = 0; - q->frame_total_cnt = 0; - - /* Goto Tracking state */ - q->state = SF_TRACK; - ret = LIBLTE_SUCCESS; - - INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n", - q->peak_idx, sync_get_peak_value(&q->s), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); - - if (q->peak_idx < CURRENT_SFLEN) { - q->sf_idx++; - } - - return ret; - } else { - INFO("Found peak at %d, SSS not detected\n", q->peak_idx); - return 0; - } -} - -int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { - int ret = LIBLTE_SUCCESS; - - /* Make sure subframe idx is what we expect */ - if ((q->sf_idx != sync_get_slot_id(&q->s)/2) && q->decode_sss_on_track) { - INFO("\nWarning: Expected SF idx %d but got %d!\n", - q->sf_idx, sync_get_slot_id(&q->s)/2); - q->sf_idx = sync_get_slot_id(&q->s)/2; - } else { - q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); - - /* If the PSS peak is beyond the frame (we sample too slowly), - discard the offseted samples to align next frame */ - if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { - ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); - } else { - ret = LIBLTE_SUCCESS; - } - - /* compute cumulative moving average CFO */ - q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->s), 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->peak_idx = CURRENT_SFLEN/2 + q->time_offset; - q->frame_ok_cnt++; - q->frame_no_cnt = 0; - - - if (ret >= LIBLTE_SUCCESS) { - ret = LIBLTE_SUCCESS; - } - } - - return ret; -} - -int track_peak_no(ue_sync_t *q) { - - /* if we missed too many PSS go back to FIND */ - q->frame_no_cnt++; - if (q->frame_no_cnt >= TRACK_MAX_LOST) { - printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); - q->state = SF_FIND; - } else { - INFO("Tracking peak not found. Peak %.3f, %d lost\n", sync_get_peak_value(&q->s), (int) q->frame_no_cnt); - } - - return LIBLTE_SUCCESS; -} - -static int receive_samples(ue_sync_t *q) { - - if (q->cell.nof_prb >= 6 && q->cell.nof_prb <= 100) { - /* A negative time offset means there are samples in our buffer for the next subframe, - because we are sampling too fast. - */ - if (q->time_offset < 0) { - q->time_offset = -q->time_offset; - } - /* copy last part of the last subframe (use move since there could be overlapping) */ - memcpy(q->receive_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); - - /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ - if (q->recv_callback(q->stream, &q->receive_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { - return LIBLTE_ERROR; - } - - /* reset time offset */ - q->time_offset = 0; - - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} - -int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { - int ret = LIBLTE_ERROR_INVALID_INPUTS; - uint32_t track_idx; - struct timeval t[3]; - - if (q != NULL && - sf_symbols != NULL && - q->input_buffer != NULL) - { - - if (receive_samples(q)) { - fprintf(stderr, "Error receiving samples\n"); - return -1; - } - - agc_process(&q->agc, q->receive_buffer, q->input_buffer, CURRENT_SFLEN); - - switch (q->state) { - case SF_AGC: - q->frame_total_cnt++; - if (q->frame_total_cnt >= AGC_NOF_FRAMES) { - q->state = SF_FIND; - q->frame_total_cnt = 0; - } - ret = 0; - break; - case SF_FIND: - q->s.sss_en = true; - - /* Find peak and cell id */ - ret = sync_find(&q->s, q->input_buffer, &q->peak_idx); - if (ret < 0) { - fprintf(stderr, "Error finding correlation peak (%d)\n", ret); - return -1; - } - - DEBUG("Find PAR=%.2f\n", sync_get_peak_value(&q->s)); - - if (ret == 1) { - ret = find_peak_ok(q); - /* Initialize PBCH decoder */ - if (ret == LIBLTE_SUCCESS) { - if (!q->pbch_initialized && q->pbch_decoder_enabled) { - ret = mib_decoder_initialize(q); - if (ret < 0) { - fprintf(stderr, "Error initializing MIB decoder\n"); - } - } - } else if (ret < 0) { - if (ret < 0) { - fprintf(stderr, "Error processing find peak \n"); - } - } - } else if (q->peak_idx != 0) { - uint32_t rlen; - if (q->peak_idx < CURRENT_SFLEN/2) { - rlen = CURRENT_SFLEN/2-q->peak_idx; - } else { - rlen = q->peak_idx; - } - if (q->recv_callback(q->stream, q->receive_buffer, rlen) < 0) { - return LIBLTE_ERROR; - } - } - break; - case SF_TRACK: - ret = LIBLTE_SUCCESS; - - q->s.sss_en = q->decode_sss_on_track; - - q->sf_idx = (q->sf_idx + 1) % 10; - - DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt); - - /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ - if (q->sf_idx == 0 || q->sf_idx == 5) { - - #ifdef MEASURE_EXEC_TIME - gettimeofday(&t[1], NULL); - #endif - - track_idx = 0; - - /* track pss around the middle of the subframe, where the PSS is */ - ret = sync_track(&q->s, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx); - if (ret < 0) { - fprintf(stderr, "Error tracking correlation peak\n"); - return -1; - } - - #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); - #endif - - if (ret == 1) { - ret = track_peak_ok(q, track_idx); - } else { - ret = track_peak_no(q); - } - - INFO("TRACK %3d: Value=%.3f SF=%d Track_idx=%d Offset=%d CFO: %f\n", - (int) q->frame_total_cnt, sync_get_peak_value(&q->s), q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->s)); - - q->frame_total_cnt++; - - if (ret == LIBLTE_ERROR) { - fprintf(stderr, "Error processing tracking peak\n"); - q->state = SF_FIND; - return LIBLTE_SUCCESS; - } - } - - /* Do CFO Correction and deliver the frame */ - cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); - *sf_symbols = q->input_buffer; - - /* At subframe 0, try to decode PBCH if not yet decoded */ - if (q->sf_idx == 0) { - if(q->pbch_decoder_enabled && - (q->pbch_decoded < q->nof_mib_decodes || q->pbch_decode_always)) - { - mib_decoder_run(q); - } else { - q->mib.sfn = (q->mib.sfn + 1) % 1024; - } - } - - if (ret == LIBLTE_SUCCESS) { - if (q->pbch_decoder_enabled) { - if (q->pbch_decoded >= q->nof_mib_decodes) { - ret = 1; - } else { - ret = 0; - } - } else { - ret = 1; - } - } - break; - } - } - DEBUG("UE SYNC returns %d\n", ret); - return ret; -} - -void ue_sync_reset(ue_sync_t *q) { - q->state = SF_AGC; - - q->pbch_last_trial = 0; - q->frame_ok_cnt = 0; - q->frame_no_cnt = 0; - q->frame_total_cnt = 0; - q->cur_cfo = 0; - q->mean_time_offset = 0; - q->time_offset = 0; - #ifdef MEASURE_EXEC_TIME - q->mean_exec_time = 0; - #endif - - pbch_decode_reset(&q->pbch); -} - diff --git a/lte/phy/lib/phch/test/CMakeLists.txt b/lte/phy/lib/phch/test/CMakeLists.txt index eb8b8dd1e..328d8128a 100644 --- a/lte/phy/lib/phch/test/CMakeLists.txt +++ b/lte/phy/lib/phch/test/CMakeLists.txt @@ -19,23 +19,6 @@ # and at http://www.gnu.org/licenses/. # -######################################################################## -# UE SYNC TEST (Only compiled if CUHD is available) -######################################################################## -LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND) -LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) -IF(${CUHD_FIND} GREATER -1) - ADD_EXECUTABLE(ue_sync_usrp ue_sync_usrp.c) - TARGET_LINK_LIBRARIES(ue_sync_usrp lte_phy cuhd) -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) - - ######################################################################## # PBCH TEST ######################################################################## diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index 5a243856f..78e2b982a 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -117,14 +117,14 @@ int base_init() { exit(-1); } - fft_buffer = malloc(2 * CP_NSYMB(cell.cp) * cell.nof_prb * RE_X_RB * sizeof(cf_t)); + fft_buffer = malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; } for (i=0;iconv_real = vec_malloc(buffer_size * sizeof(float)); - if (!q->conv_real) { - fprintf(stderr, "Error allocating memory\n"); - goto clean_and_exit; - } q->tmp_input = vec_malloc(buffer_size * sizeof(cf_t)); if (!q->tmp_input) { fprintf(stderr, "Error allocating memory\n"); @@ -161,9 +157,6 @@ void pss_synch_free(pss_synch_t *q) { if (q->conv_output) { free(q->conv_output); } - if (q->conv_real) { - free(q->conv_real); - } bzero(q, sizeof(pss_synch_t)); } @@ -260,16 +253,11 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value) conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif - /* Take the real part of the convolution result and normalize */ - vec_deinterleave_real_cf(q->conv_output, q->conv_real, conv_output_len); - vec_sc_prod_fff(q->conv_real, 1.0/62.0, q->conv_real, conv_output_len); - - /* Find maximum */ - corr_peak_pos = vec_max_fi(q->conv_real, conv_output_len); + /* Find maximum of the absolute value of the correlation */ + corr_peak_pos = vec_max_abs_ci(q->conv_output, conv_output_len); if (corr_peak_value) { - *corr_peak_value = q->conv_real[corr_peak_pos]; + *corr_peak_value = cabsf(q->conv_output[corr_peak_pos]); } - DEBUG("PSS correlation peak %.3f position %5d\n", q->conv_real[corr_peak_pos], corr_peak_pos); ret = (int) corr_peak_pos; } return ret; diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 61d3bc36c..45a6fb08e 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -26,6 +26,8 @@ */ #include +#include +#include #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/phy_common.h" @@ -41,24 +43,25 @@ static bool fft_size_isvalid(uint32_t fft_size) { } } -int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, uint32_t fft_size) { +int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && - find_frame_size > fft_size && - find_frame_size < 307200 && + frame_size >= fft_size && + frame_size <= 307200 && fft_size_isvalid(fft_size)) { bzero(q, sizeof(sync_t)); q->detect_cp = true; + q->normalize_en = true; q->sss_en = true; q->N_id_2 = 1000; q->N_id_1 = 1000; q->fft_size = fft_size; - q->find_frame_size = find_frame_size; + q->frame_size = frame_size; - if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { + if (pss_synch_init_fft(&q->pss, frame_size, fft_size)) { fprintf(stderr, "Error initializing PSS object\n"); return LIBLTE_ERROR; } @@ -66,112 +69,72 @@ int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, ui fprintf(stderr, "Error initializing SSS object\n"); return LIBLTE_ERROR; } - if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { - fprintf(stderr, "Error initializing PSS track object\n"); - return LIBLTE_ERROR; - } - DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); + DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size); ret = LIBLTE_SUCCESS; } return ret; } -int sync_realloc(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, - uint32_t fft_size) -{ - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - find_frame_size > fft_size && - find_frame_size < 307200 && - fft_size_isvalid(fft_size)) - { - q->N_id_2 = 1000; - q->N_id_1 = 1000; - q->fft_size = fft_size; - q->find_frame_size = find_frame_size; - - pss_synch_free(&q->pss_find); - if (pss_synch_init_fft(&q->pss_find, find_frame_size, fft_size)) { - fprintf(stderr, "Error initializing PSS object\n"); - return LIBLTE_ERROR; - } - - pss_synch_free(&q->pss_track); - if (pss_synch_init_fft(&q->pss_track, track_frame_size, fft_size)) { - fprintf(stderr, "Error initializing PSS track object\n"); - return LIBLTE_ERROR; - } - - if (sss_synch_realloc(&q->sss, fft_size)) { - fprintf(stderr, "Error realloc'ing SSS object\n"); - return LIBLTE_ERROR; - } - - DEBUG("SYNC init with find_frame_size=%d and fft_size=%d\n", find_frame_size, fft_size); - - ret = LIBLTE_SUCCESS; - } - return ret; -} - void sync_free(sync_t *q) { if (q) { - pss_synch_free(&q->pss_track); - pss_synch_free(&q->pss_find); + pss_synch_free(&q->pss); sss_synch_free(&q->sss); } } -void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold) { - q->find_threshold = find_threshold; - q->track_threshold = track_threshold; +void sync_set_threshold(sync_t *q, float threshold) { + q->threshold = threshold; } void sync_sss_en(sync_t *q, bool enabled) { q->sss_en = enabled; } +void sync_normalize_en(sync_t *q, bool enable) { + q->normalize_en = enable; +} + bool sync_sss_detected(sync_t *q) { return lte_N_id_1_isvalid(q->N_id_1); } int sync_get_cell_id(sync_t *q) { - if (q->N_id_2 != 10) { - if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { - return q->N_id_1*3 + q->N_id_2; - } else { - fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); - return LIBLTE_ERROR; - } + if (lte_N_id_2_isvalid(q->N_id_2) && lte_N_id_1_isvalid(q->N_id_1)) { + return q->N_id_1*3 + q->N_id_2; } else { - fprintf(stderr, "Error getting cell_id, N_id_2 not set\n"); + fprintf(stderr, "Error getting cell_id, invalid N_id_1 or N_id_2\n"); return LIBLTE_ERROR; } } -uint32_t sync_get_N_id_1(sync_t *q) { - return q->N_id_1; +int sync_set_N_id_2(sync_t *q, uint32_t N_id_2) { + if (lte_N_id_2_isvalid(N_id_2)) { + q->N_id_2 = N_id_2; + return LIBLTE_SUCCESS; + } else { + fprintf(stderr, "Invalid N_id_2=%d\n", N_id_2); + return LIBLTE_ERROR_INVALID_INPUTS; + } } -uint32_t sync_get_N_id_2(sync_t *q) { - return q->N_id_2; -} - -uint32_t sync_get_slot_id(sync_t *q) { - return q->slot_id; +uint32_t sync_get_sf_idx(sync_t *q) { + return q->sf_idx; } float sync_get_cfo(sync_t *q) { return q->cfo; } -float sync_get_peak_value(sync_t *q) { +float sync_get_last_peak_value(sync_t *q) { return q->peak_value; } +float sync_get_peak_value(sync_t *q) { + return q->mean_peak_value; +} + void sync_cp_en(sync_t *q, bool enabled) { q->detect_cp = enabled; } @@ -180,11 +143,11 @@ lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } -int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { +int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { uint32_t m0, m1; int sss_idx_n, sss_idx_e, ret; float m0_value_e, m1_value_e,m0_value_n, m1_value_n; - uint32_t slot_id_e, N_id_1_e, slot_id_n, N_id_1_n; + uint32_t sf_idx_e, N_id_1_e, sf_idx_n, N_id_1_n; sss_synch_set_N_id_2(&q->sss, q->N_id_2); @@ -192,7 +155,7 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { sss_idx_n = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPNORM_LEN)); sss_idx_e = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, CPEXT_LEN)); - if (en_cp) { + if (q->detect_cp) { if (sss_idx_n < 0 || sss_idx_e < 0) { INFO("Not enough room to decode SSS (%d, %d)\n", sss_idx_n, sss_idx_e); return LIBLTE_SUCCESS; @@ -211,16 +174,16 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { } } - slot_id_n = 0; - slot_id_e = 0; + sf_idx_n = 0; + sf_idx_e = 0; N_id_1_n = 0; N_id_1_e = 0; /* try Normal CP length */ - if (en_cp || CP_ISNORM(q->cp)) { + if (q->detect_cp || CP_ISNORM(q->cp)) { sss_synch_m0m1(&q->sss, &input[sss_idx_n], &m0, &m0_value_n, &m1, &m1_value_n); - slot_id_n = 2 * sss_synch_subframe(m0, m1); + sf_idx_n = sss_synch_subframe(m0, m1); ret = sss_synch_N_id_1(&q->sss, m0, m1); if (ret >= 0) { N_id_1_n = (uint32_t) ret; @@ -229,11 +192,11 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { } } - if (en_cp || CP_ISEXT(q->cp)) { + if (q->detect_cp || CP_ISEXT(q->cp)) { /* Now try Extended CP length */ sss_synch_m0m1(&q->sss, &input[sss_idx_e], &m0, &m0_value_e, &m1, &m1_value_e); - slot_id_e = 2 * sss_synch_subframe(m0, m1); + sf_idx_e = sss_synch_subframe(m0, m1); ret = sss_synch_N_id_1(&q->sss, m0, m1); if (ret >= 0) { N_id_1_e = (uint32_t) ret; @@ -243,46 +206,71 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos, bool en_cp) { } /* Correlation with extended CP hypoteshis is greater than with normal? */ - if ((en_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) + if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) || CP_ISEXT(q->cp)) { q->cp = CPEXT; - q->slot_id = slot_id_e; + q->sf_idx = sf_idx_e; q->N_id_1 = N_id_1_e; /* otherwise is normal CP */ } else { q->cp = CPNORM; - q->slot_id = slot_id_n; + q->sf_idx = sf_idx_n; q->N_id_1 = N_id_1_n; } - DEBUG("SSS detected N_id_1=%d, slot_idx=%d, position=%d/%d %s CP\n", - q->N_id_1, q->slot_id, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended"); + DEBUG("SSS detected N_id_1=%d, sf_idx=%d, position=%d/%d %s CP\n", + q->N_id_1, q->sf_idx, sss_idx_n, sss_idx_e, CP_ISNORM(q->cp)?"Normal":"Extended"); return 1; } -int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) { +int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_position) { int ret = LIBLTE_ERROR_INVALID_INPUTS; - if (q != NULL && - input != NULL && + float peak_unnormalized, energy; + + if (q != NULL && + input != NULL && + lte_N_id_2_isvalid(q->N_id_2) && fft_size_isvalid(q->fft_size)) { uint32_t peak_pos; - - pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); - - peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &q->peak_value); - - DEBUG("PSS possible tracking peak pos=%d peak=%.2f threshold=%.2f\n", - peak_pos, q->peak_value, q->track_threshold); - if (q->peak_value > q->track_threshold) { - if (offset + peak_pos > q->fft_size) { - q->cfo = pss_synch_cfo_compute(&q->pss_track, &input[offset+peak_pos-q->fft_size]); + if (peak_position) { + *peak_position = 0; + } + + 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 (q->normalize_en && + peak_pos + find_offset >= q->fft_size && + peak_pos + find_offset + q->fft_size <= q->frame_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); + } else { + if (q->mean_energy == 0.0) { + q->mean_energy = 1.0; + } + energy = q->mean_energy; + } + + /* 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->frame_cnt++; + + /* If peak is over threshold, compute CFO and SSS */ + if (q->peak_value >= q->threshold) { + 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, offset + peak_pos, false) < 0) { + if (sync_sss(q, input, find_offset + peak_pos) < 0) { fprintf(stderr, "Error synchronizing with SSS\n"); return LIBLTE_ERROR; } @@ -290,6 +278,7 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) } else { printf("Warning: no space for CFO computation\n"); } + if (peak_position) { *peak_position = peak_pos; } @@ -297,67 +286,17 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) } else { ret = LIBLTE_SUCCESS; } + + INFO("SYNC ret=%d pos=%d peak=%.2f energy=%.3f threshold=%.2f sf_idx=%d\n", + ret, peak_pos, q->peak_value, energy, q->threshold, q->sf_idx); + + } else if (lte_N_id_2_isvalid(q->N_id_2)) { + fprintf(stderr, "Must call sync_set_N_id_2() first!\n"); } return ret; } -int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { - uint32_t N_id_2, peak_pos[3]; - float peak_value[3]; - float max=-999; - uint32_t i; - int ret; - - for (N_id_2=0;N_id_2<3;N_id_2++) { - pss_synch_set_N_id_2(&q->pss_find, N_id_2); - ret = pss_synch_find_pss(&q->pss_find, input, &peak_value[N_id_2]); - if (ret < 0) { - fprintf(stderr, "Error finding PSS for N_id_2=%d\n", N_id_2); - return LIBLTE_ERROR; - } - peak_pos[N_id_2] = (uint32_t) ret; - - } - for (i=0;i<3;i++) { - if (peak_value[i] > max) { - max = peak_value[i]; - N_id_2 = i; - } - } - - q->peak_value = peak_value[N_id_2]; - - if (peak_position) { - *peak_position = 0; - } - - /* If peak detected */ - if (q->peak_value > q->find_threshold) { - if (peak_pos[N_id_2] > q->fft_size && - peak_pos[N_id_2] + q->fft_size < q->find_frame_size) - { - q->N_id_2 = N_id_2; - pss_synch_set_N_id_2(&q->pss_find, q->N_id_2); - q->cfo = pss_synch_cfo_compute(&q->pss_find, &input[peak_pos[N_id_2]-q->fft_size]); - - DEBUG("PSS peak detected N_id_2=%d, pos=%d peak=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], q->peak_value, q->find_threshold, q->cfo); - - if (q->sss_en) { - if (sync_sss(q, input, peak_pos[q->N_id_2], q->detect_cp) < 0) { - fprintf(stderr, "Error synchronizing with SSS\n"); - return LIBLTE_ERROR; - } - } - } - - if (peak_position) { - *peak_position = peak_pos[N_id_2]; - } - - return 1; - } else { - return LIBLTE_SUCCESS; - } +void sync_reset(sync_t *q) { + q->frame_cnt = 0; } diff --git a/lte/phy/lib/sync/test/CMakeLists.txt b/lte/phy/lib/sync/test/CMakeLists.txt index 4a552f87f..d9f8c49b3 100644 --- a/lte/phy/lib/sync/test/CMakeLists.txt +++ b/lte/phy/lib/sync/test/CMakeLists.txt @@ -19,6 +19,15 @@ # and at http://www.gnu.org/licenses/. # +######################################################################## +# PROGRAM TO DEBUG PSS FROM USRP +######################################################################## + +LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND) +IF(${CUHD_FIND} GREATER -1) + ADD_EXECUTABLE(pss_usrp pss_usrp.c) + TARGET_LINK_LIBRARIES(pss_usrp lte_phy cuhd) +ENDIF(${CUHD_FIND} GREATER -1) ######################################################################## # SYNC TEST @@ -27,15 +36,15 @@ ADD_EXECUTABLE(sync_test sync_test.c) TARGET_LINK_LIBRARIES(sync_test lte_phy) -ADD_TEST(sync_test_100 sync_test -o 100) -ADD_TEST(sync_test_400 sync_test -o 400) -ADD_TEST(sync_test_100_e sync_test -o 100 -e) -ADD_TEST(sync_test_400_e sync_test -o 400 -e) +ADD_TEST(sync_test_100 sync_test -o 100 -c 501) +ADD_TEST(sync_test_400 sync_test -o 400 -c 2) +ADD_TEST(sync_test_100_e sync_test -o 100 -e -c 150) +ADD_TEST(sync_test_400_e sync_test -o 400 -e -c 151) -ADD_TEST(sync_test_100 sync_test -o 100 -p 50) -ADD_TEST(sync_test_400 sync_test -o 400 -p 50) -ADD_TEST(sync_test_100_e sync_test -o 100 -e -p 50) -ADD_TEST(sync_test_400_e sync_test -o 400 -e -p 50) +ADD_TEST(sync_test_100 sync_test -o 100 -p 50 -c 501) +ADD_TEST(sync_test_400 sync_test -o 400 -p 50 -c 500) +ADD_TEST(sync_test_100_e sync_test -o 100 -e -p 50 -c 133) +ADD_TEST(sync_test_400_e sync_test -o 400 -e -p 50 -c 123) ######################################################################## # CFO TEST diff --git a/lte/phy/lib/sync/test/pss_usrp.c b/lte/phy/lib/sync/test/pss_usrp.c new file mode 100644 index 000000000..176780edb --- /dev/null +++ b/lte/phy/lib/sync/test/pss_usrp.c @@ -0,0 +1,208 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "liblte/phy/phy.h" +#include "liblte/cuhd/cuhd.h" + +uint32_t N_id_2 = 100; +char *uhd_args=""; +float uhd_gain=40.0, uhd_freq=-1.0; +int nof_frames = -1; +uint32_t fft_size=64; +float threshold = 0.4; + +void usage(char *prog) { + printf("Usage: %s [agtvnp] -f rx_frequency_hz -i N_id_2\n", prog); + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD Gain [Default %.2f dB]\n", uhd_gain); + printf("\t-n nof_frames [Default %d]\n", nof_frames); + printf("\t-s symbol_sz [Default %d]\n", fft_size); + printf("\t-t threshold [Default %.2f]\n", threshold); + printf("\t-v verbose\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agtvsfi")) != -1) { + switch (opt) { + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 't': + threshold = atof(argv[optind]); + break; + case 'i': + N_id_2 = atoi(argv[optind]); + break; + case 's': + fft_size = atoi(argv[optind]); + break; + case 'n': + nof_frames = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (N_id_2 > 2 || uhd_freq < 0) { + usage(argv[0]); + exit(-1); + } +} + +int main(int argc, char **argv) { + cf_t *buffer; + int frame_cnt, n; + void *uhd; + pss_synch_t pss; + int32_t flen; + int peak_idx, last_peak; + float peak_value; + float mean_peak; + uint32_t nof_det, nof_nodet, nof_nopeak, nof_nopeakdet; + + parse_args(argc, argv); + + flen = 4800*(fft_size/64); + + buffer = malloc(sizeof(cf_t) * flen); + if (!buffer) { + perror("malloc"); + exit(-1); + } + + if (pss_synch_init_fft(&pss, flen, fft_size)) { + fprintf(stderr, "Error initiating PSS\n"); + exit(-1); + } + if (pss_synch_set_N_id_2(&pss, N_id_2)) { + fprintf(stderr, "Error setting N_id_2=%d\n",N_id_2); + exit(-1); + } + + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } + printf("Set RX rate: %.2f MHz\n", cuhd_set_rx_srate(uhd, flen*2*100) / 1000000); + printf("Set RX gain: %.1f dB\n", cuhd_set_rx_gain(uhd, uhd_gain)); + printf("Set RX freq: %.2f MHz\n", cuhd_set_rx_freq(uhd, uhd_freq) / 1000000); + cuhd_rx_wait_lo_locked(uhd); + cuhd_start_rx_stream(uhd); + + printf("Frame length %d samples\n", flen); + printf("PSS detection threshold: %.2f\n", threshold); + + nof_det = nof_nodet = nof_nopeak = nof_nopeakdet = 0; + frame_cnt = 0; + last_peak = 0; + mean_peak = 0; + while(frame_cnt < nof_frames || nof_frames == -1) { + n = cuhd_recv(uhd, buffer, flen, 1); + if (n < 0) { + fprintf(stderr, "Error receiving samples\n"); + exit(-1); + } + + peak_idx = pss_synch_find_pss(&pss, buffer, &peak_value); + if (peak_idx < 0) { + fprintf(stderr, "Error finding PSS peak\n"); + exit(-1); + } + + float y = sqrtf(crealf(vec_dot_prod_conj_ccc(&buffer[peak_idx-fft_size], + &buffer[peak_idx-fft_size], + fft_size)) / + fft_size); + float x = peak_value/y; + + mean_peak = EXPAVERAGE(x, mean_peak, frame_cnt); + + if (x >= threshold) { + nof_det++; + } else { + nof_nodet++; + } + + if (frame_cnt > 100) { + if (abs(last_peak-peak_idx) > 10) { + if (x >= threshold) { + nof_nopeakdet++; + } else { + if (nof_nodet > 0) { + nof_nodet--; + } + } + nof_nopeak++; + } + } + + frame_cnt++; + + printf("[%5d]: Pos: %5d, En: %.4f Val: %.3f MeanVal: %.3f, Det: %.3f, No-Det: %.3f, NoPeak: %.3f, NoPeakDet: %.3f\r", + frame_cnt, + peak_idx, y, x, mean_peak, + (float) nof_det/frame_cnt, (float) nof_nodet/frame_cnt, + (float) nof_nopeak/frame_cnt, (float) nof_nopeakdet/nof_nopeak); + + if (VERBOSE_ISINFO()) { + printf("\n"); + } + + last_peak = peak_idx; + + } + + pss_synch_free(&pss); + free(buffer); + cuhd_close(uhd); + + printf("Ok\n"); + exit(0); +} + diff --git a/lte/phy/lib/sync/test/sync_test.c b/lte/phy/lib/sync/test/sync_test.c index e74dba6aa..b3f3133ae 100644 --- a/lte/phy/lib/sync/test/sync_test.c +++ b/lte/phy/lib/sync/test/sync_test.c @@ -41,7 +41,7 @@ int cell_id = -1, offset = 0; lte_cp_t cp = CPNORM; uint32_t nof_prb=6; -#define FLEN SF_LEN(fft_size, cp) +#define FLEN SF_LEN(fft_size) void usage(char *prog) { printf("Usage: %s [cpoev]\n", prog); @@ -115,13 +115,13 @@ int main(int argc, char **argv) { exit(-1); } - if (sync_init(&sync, FLEN, fft_size, fft_size)) { + if (sync_init(&sync, FLEN, fft_size)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } /* Set a very high threshold to make sure the correlation is ok */ - sync_set_threshold(&sync, 0.99, 0.99); + sync_set_threshold(&sync, 1.4); if (cell_id == -1) { cid = 0; @@ -137,6 +137,8 @@ int main(int argc, char **argv) { pss_generate(pss_signal, N_id_2); sss_generate(sss_signal0, sss_signal5, cid); + sync_set_N_id_2(&sync, N_id_2); + for (ns=0;ns<2;ns++) { memset(buffer, 0, sizeof(cf_t) * FLEN); pss_put_slot(pss_signal, buffer, nof_prb, cp); @@ -148,8 +150,11 @@ int main(int argc, char **argv) { vec_save_file("input", fft_buffer, sizeof(cf_t) * FLEN); - sync_find(&sync, fft_buffer, &find_idx); - find_ns = sync_get_slot_id(&sync); + if (sync_find(&sync, fft_buffer, 0, &find_idx) < 0) { + fprintf(stderr, "Error running sync_find\n"); + exit(-1); + } + find_ns = 2*sync_get_sf_idx(&sync); printf("cell_id: %d find: %d, offset: %d, ns=%d find_ns=%d\n", cid, find_idx, offset, ns, find_ns); if (find_idx != offset + FLEN/2) { diff --git a/lte/phy/lib/ue/src/ue_cellsearch.c b/lte/phy/lib/ue/src/ue_cellsearch.c new file mode 100644 index 000000000..8bb6701d1 --- /dev/null +++ b/lte/phy/lib/ue/src/ue_cellsearch.c @@ -0,0 +1,268 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "liblte/phy/ue/ue_cellsearch.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#define FIND_FFTSIZE 64 +#define FIND_SFLEN 5*SF_LEN(FIND_FFTSIZE) + +int ue_cellsearch_init(ue_cellsearch_t * q) { + return ue_cellsearch_init_max(q, CS_DEFAULT_MAXFRAMES_TOTAL, CS_DEFAULT_MAXFRAMES_DETECTED); +} + +int ue_cellsearch_init_max(ue_cellsearch_t * q, uint32_t max_frames_total, uint32_t max_frames_detected) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(ue_cellsearch_t)); + + q->candidates = malloc(sizeof(ue_cellsearch_result_t) * max_frames_detected); + if (!q->candidates) { + perror("malloc"); + goto clean_exit; + } + if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) { + goto clean_exit; + } + q->mode_ntimes = malloc(sizeof(uint32_t) * max_frames_detected); + if (!q->mode_ntimes) { + perror("malloc"); + goto clean_exit; + } + q->mode_counted = malloc(sizeof(char) * max_frames_detected); + if (!q->mode_counted) { + perror("malloc"); + goto clean_exit; + } + + sync_set_threshold(&q->sfind, CS_FIND_THRESHOLD); + sync_sss_en(&q->sfind, true); + + q->max_frames_total = max_frames_total; + q->max_frames_detected = max_frames_detected; + q->nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL; + q->nof_frames_detected = CS_DEFAULT_NOFFRAMES_DETECTED; + + ue_cellsearch_reset(q); + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_cellsearch_free(q); + } + return ret; +} + +void ue_cellsearch_free(ue_cellsearch_t * q) +{ + if (q->candidates) { + free(q->candidates); + } + if (q->mode_counted) { + free(q->mode_counted); + } + if (q->mode_ntimes) { + free(q->mode_ntimes); + } + sync_free(&q->sfind); +} + + +void ue_cellsearch_reset(ue_cellsearch_t * q) +{ + q->current_nof_detected = 0; + q->current_nof_total = 0; + q->current_N_id_2 = 0; +} + +void ue_cellsearch_set_threshold(ue_cellsearch_t * q, float threshold) +{ + sync_set_threshold(&q->sfind, threshold); +} + +int ue_cellsearch_set_nof_frames_total(ue_cellsearch_t * q, uint32_t nof_frames) +{ + if (nof_frames > q->max_frames_total) { + q->nof_frames_total = nof_frames; + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR; + } +} + +int ue_cellsearch_set_nof_frames_detected(ue_cellsearch_t * q, uint32_t nof_frames) +{ + if (nof_frames > q->max_frames_detected) { + q->nof_frames_detected = nof_frames; + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR; + } +} + +/* Decide the most likely cell based on the mode */ +void decide_cell(ue_cellsearch_t * q, ue_cellsearch_result_t *found_cell) +{ + uint32_t i, j; + + bzero(q->mode_counted, q->nof_frames_detected); + bzero(q->mode_ntimes, sizeof(uint32_t) * q->nof_frames_detected); + + /* First find mode of CELL IDs */ + for (i = 0; i < q->nof_frames_detected; i++) { + uint32_t cnt = 1; + for (j=i+1;jnof_frames_detected;j++) { + if (q->candidates[j].cell_id == q->candidates[i].cell_id && !q->mode_counted[j]) { + q->mode_counted[j]=1; + cnt++; + } + } + q->mode_ntimes[i] = cnt; + } + uint32_t max_times=0, mode_pos=0; + for (i=0;inof_frames_detected;i++) { + if (q->mode_ntimes[i] > 0) { + DEBUG("ntimes[%d]=%d (CID: %d)\n",i,q->mode_ntimes[i],q->candidates[i].cell_id); + } + if (q->mode_ntimes[i] > max_times) { + max_times = q->mode_ntimes[i]; + mode_pos = i; + } + } + found_cell->cell_id = q->candidates[mode_pos].cell_id; + /* Now in all these cell IDs, find most frequent CP */ + uint32_t nof_normal = 0; + found_cell->peak = 0; + for (i=0;inof_frames_detected;i++) { + if (q->candidates[i].cell_id == found_cell->cell_id) { + if (CP_ISNORM(q->candidates[i].cp)) { + nof_normal++; + } + found_cell->peak += q->candidates[i].peak/q->mode_ntimes[mode_pos]; + } + } + if (nof_normal > q->mode_ntimes[mode_pos]/2) { + found_cell->cp = CPNORM; + } else { + found_cell->cp = CPEXT; + } + found_cell->mode = q->mode_ntimes[mode_pos]; +} + +int ue_cellsearch_scan(ue_cellsearch_t * q, + cf_t *signal, + uint32_t nsamples, + ue_cellsearch_result_t *found_cell) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t peak_idx; + uint32_t nof_input_frames; + + + if (q != NULL && + signal != NULL && + nsamples >= 4800) + { + ret = LIBLTE_SUCCESS; + + if (nsamples % 4800) { + printf("Warning: nsamples must be a multiple of 4800. Some samples will be ignored\n"); + nsamples = (nsamples/4800) * 4800; + } + nof_input_frames = nsamples/4800; + + for (uint32_t nf=0;nfsfind, q->current_N_id_2); + + DEBUG("[%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); + + /* 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; + } + + /* If peak position does not allow to read SSS, return error -3 */ + if (ret == LIBLTE_SUCCESS && peak_idx != 0) { + return CS_FRAME_UNALIGNED; + } + + /* Process the peak result */ + if (ret == 1) { + if (sync_sss_detected(&q->sfind)) { + ret = sync_get_cell_id(&q->sfind); + if (ret >= 0) { + /* Save cell id, cp and peak */ + q->candidates[q->current_nof_detected].cell_id = (uint32_t) ret; + q->candidates[q->current_nof_detected].cp = sync_get_cp(&q->sfind); + q->candidates[q->current_nof_detected].peak = sync_get_last_peak_value(&q->sfind); + } + INFO + ("[%3d/%3d]: Found peak at %4d, value %.3f, Cell_id: %d CP: %s\n", + q->current_nof_detected, q->current_nof_total, peak_idx, + q->candidates[q->current_nof_detected].peak, q->candidates[q->current_nof_detected].cell_id, + lte_cp_string(q->candidates[q->current_nof_detected].cp)); + q->current_nof_detected++; + } + } + q->current_nof_total++; + + /* 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; + } + } + } + + return ret; +} diff --git a/lte/phy/lib/phch/src/ue_dl.c b/lte/phy/lib/ue/src/ue_dl.c similarity index 99% rename from lte/phy/lib/phch/src/ue_dl.c rename to lte/phy/lib/ue/src/ue_dl.c index e9aad4520..9bb914c58 100644 --- a/lte/phy/lib/phch/src/ue_dl.c +++ b/lte/phy/lib/ue/src/ue_dl.c @@ -25,7 +25,7 @@ * */ -#include "liblte/phy/phch/ue_dl.h" +#include "liblte/phy/ue/ue_dl.h" #define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) diff --git a/lte/phy/lib/ue/src/ue_mib.c b/lte/phy/lib/ue/src/ue_mib.c new file mode 100644 index 000000000..9652e75c8 --- /dev/null +++ b/lte/phy/lib/ue/src/ue_mib.c @@ -0,0 +1,225 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "liblte/phy/ue/ue_mib.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#define FIND_FFTSIZE 128 +#define FIND_SFLEN 10*SF_LEN(FIND_FFTSIZE) + +int ue_mib_init(ue_mib_t * q, + uint32_t cell_id, + lte_cp_t cp) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL) { + + ret = LIBLTE_ERROR; + + lte_cell_t cell; + cell.nof_ports = MIB_NOF_PORTS; + cell.nof_prb = 6; + cell.id = cell_id; + cell.cp = cp; + + q->cell_id = cell_id; + + bzero(q, sizeof(ue_mib_t)); + + q->slot1_symbols = malloc(SLOT_LEN_RE(6, cp) * sizeof(cf_t)); + if (!q->slot1_symbols) { + perror("malloc"); + goto clean_exit; + } + + for (int i=0;ice[i] = malloc(SLOT_LEN_RE(6, cp) * sizeof(cf_t)); + if (!q->ce[i]) { + perror("malloc"); + goto clean_exit; + } + } + + if (sync_init(&q->sfind, FIND_SFLEN, FIND_FFTSIZE)) { + goto clean_exit; + } + + sync_set_threshold(&q->sfind, MIB_FIND_THRESHOLD); + sync_sss_en(&q->sfind, true); + sync_set_N_id_2(&q->sfind, cell_id % 3); + + if (lte_fft_init(&q->fft, cp, cell.nof_prb)) { + fprintf(stderr, "Error initializing FFT\n"); + goto clean_exit; + } + if (chest_init_LTEDL(&q->chest, cell)) { + fprintf(stderr, "Error initializing reference signal\n"); + goto clean_exit; + } + if (pbch_init(&q->pbch, cell)) { + fprintf(stderr, "Error initiating PBCH\n"); + goto clean_exit; + } + ue_mib_reset(q); + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_mib_free(q); + } + return ret; +} + +void ue_mib_free(ue_mib_t * q) +{ + if (q->slot1_symbols) { + free(q->slot1_symbols); + } + for (int i=0;ice[i]) { + free(q->ce[i]); + } + } + sync_free(&q->sfind); + chest_free(&q->chest); + pbch_free(&q->pbch); + lte_fft_free(&q->fft); +} + + +void ue_mib_reset(ue_mib_t * q) +{ + q->frame_cnt = 0; + q->last_frame_trial = 0; + + pbch_decode_reset(&q->pbch); +} + +void ue_mib_set_threshold(ue_mib_t * q, float threshold) +{ + sync_set_threshold(&q->sfind, threshold); +} + +static int mib_decoder_run(ue_mib_t * q, cf_t *input, pbch_mib_t *mib) +{ + int ret; + + /* 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; + } + } + return ret; +} + +int ue_mib_decode(ue_mib_t * q, + cf_t *signal, + uint32_t nsamples, + pbch_mib_t *mib) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t peak_idx; + uint32_t nof_input_frames; + + + if (q != NULL && + signal != NULL) + { + ret = LIBLTE_SUCCESS; + + if (nsamples % MIB_FRAME_SIZE) { + printf("Warning: nsamples must be a multiple of %d. Some samples will be ignored\n", MIB_FRAME_SIZE); + nsamples = (nsamples/MIB_FRAME_SIZE) * MIB_FRAME_SIZE; + } + nof_input_frames = nsamples/MIB_FRAME_SIZE; + + for (uint32_t nf=0;nfsfind, signal, nf*MIB_FRAME_SIZE, &peak_idx); + if (ret < 0) { + 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 == 1 && + nf*MIB_FRAME_SIZE + peak_idx + 960 <= nsamples && + sync_sss_detected(&q->sfind) && + sync_get_sf_idx(&q->sfind) == 0) + { + + ret = mib_decoder_run(q, &signal[nf*MIB_FRAME_SIZE+peak_idx], mib); + + } else if ((ret == LIBLTE_SUCCESS && peak_idx != 0) || + (ret == 1 && nf*MIB_FRAME_SIZE + peak_idx + 960 > nsamples)) + { + ret = MIB_FRAME_UNALIGNED; + } else { + ret = 0; + } + + 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 new file mode 100644 index 000000000..600bc1ee7 --- /dev/null +++ b/lte/phy/lib/ue/src/ue_sync.c @@ -0,0 +1,377 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + + +#include "liblte/phy/ue/ue_sync.h" + +#include "liblte/phy/utils/debug.h" +#include "liblte/phy/utils/vector.h" + +#define MAX_TIME_OFFSET 128 +cf_t dummy[MAX_TIME_OFFSET]; + +#define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) +#define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE) + +#define CURRENT_SLOTLEN_RE SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp) +#define CURRENT_SFLEN_RE SF_LEN_RE(q->cell.nof_prb, q->cell.cp) + +#define FIND_THRESHOLD 1.0 +#define TRACK_THRESHOLD 0.2 + + +int ue_sync_init(ue_sync_t *q, + lte_cell_t cell, + int (recv_callback)(void*, void*, uint32_t), + void *stream_handler) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + + if (q != NULL && + stream_handler != NULL && + lte_cell_isvalid(&cell) && + recv_callback != NULL) + { + ret = LIBLTE_ERROR; + + bzero(q, sizeof(ue_sync_t)); + + ue_sync_reset(q); + + q->decode_sss_on_track = false; + q->stream = stream_handler; + q->recv_callback = recv_callback; + + if(sync_init(&q->sfind, 5 * CURRENT_SFLEN, CURRENT_FFTSIZE)) { + goto clean_exit; + } + if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + goto clean_exit; + } + + sync_set_N_id_2(&q->sfind, cell.id%3); + sync_set_threshold(&q->sfind, FIND_THRESHOLD); + + sync_set_N_id_2(&q->strack, cell.id%3); + sync_set_threshold(&q->strack, TRACK_THRESHOLD); + + if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) { + fprintf(stderr, "Error initiating CFO\n"); + goto clean_exit; + } + + q->input_buffer = vec_malloc(5 * CURRENT_SFLEN * sizeof(cf_t)); + if (!q->input_buffer) { + perror("malloc"); + goto clean_exit; + } + + ret = LIBLTE_SUCCESS; + } + +clean_exit: + if (ret == LIBLTE_ERROR) { + ue_sync_free(q); + } + return ret; +} + +void ue_sync_free(ue_sync_t *q) { + if (q->input_buffer) { + free(q->input_buffer); + } + cfo_free(&q->cfocorr); + sync_free(&q->sfind); + sync_free(&q->strack); +} + +uint32_t ue_sync_peak_idx(ue_sync_t *q) { + return q->peak_idx; +} + +ue_sync_state_t ue_sync_get_state(ue_sync_t *q) { + return q->state; +} +uint32_t ue_sync_get_sfidx(ue_sync_t *q) { + return q->sf_idx; +} + +float ue_sync_get_cfo(ue_sync_t *q) { + return 15000 * q->cur_cfo; +} + +float ue_sync_get_sfo(ue_sync_t *q) { + return 1000*q->mean_time_offset/5; +} + +void ue_sync_decode_sss_on_track(ue_sync_t *q, bool enabled) { + q->decode_sss_on_track = enabled; +} + + +static int find_peak_ok(ue_sync_t *q) { + int ret; + + if (q->peak_idx < CURRENT_SFLEN) { + /* Receive the rest of the next subframe */ + if (q->recv_callback(q->stream, &q->input_buffer[CURRENT_SFLEN], q->peak_idx+CURRENT_SFLEN/2) < 0) { + return LIBLTE_ERROR; + } + } + + if (sync_sss_detected(&q->sfind)) { + /* Get the subframe index (0 or 5) */ + q->sf_idx = sync_get_sf_idx(&q->sfind); + + /* Reset variables */ + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + + /* Goto Tracking state */ + q->state = SF_TRACK; + ret = LIBLTE_SUCCESS; + + INFO("Found peak at %d, value %.3f, SF_idx: %d, Cell_id: %d CP: %s\n", + q->peak_idx, sync_get_peak_value(&q->sfind), q->sf_idx, q->cell.id, lte_cp_string(q->cell.cp)); + + if (q->peak_idx < CURRENT_SFLEN) { + q->sf_idx++; + } + } else { + INFO("Found peak at %d, SSS not detected\n", q->peak_idx); + ret = 0; + } + return ret; +} + +int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { + int ret = LIBLTE_SUCCESS; + + /* Make sure subframe idx is what we expect */ + if ((q->sf_idx != sync_get_sf_idx(&q->strack)) && q->decode_sss_on_track) { + INFO("\nWarning: Expected SF idx %d but got %d!\n", + q->sf_idx, sync_get_sf_idx(&q->strack)); + q->sf_idx = sync_get_sf_idx(&q->strack); + } else { + q->time_offset = ((int) track_idx - (int) CURRENT_FFTSIZE); + + /* If the PSS peak is beyond the frame (we sample too slowly), + discard the offseted samples to align next frame */ + if (q->time_offset > 0 && q->time_offset < MAX_TIME_OFFSET) { + ret = q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset); + } else { + ret = LIBLTE_SUCCESS; + } + + /* compute cumulative moving average CFO */ + q->cur_cfo = EXPAVERAGE(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->peak_idx = CURRENT_SFLEN/2 + q->time_offset; + q->frame_ok_cnt++; + q->frame_no_cnt = 0; + + + if (ret >= LIBLTE_SUCCESS) { + ret = LIBLTE_SUCCESS; + } + } + + return ret; +} + +int track_peak_no(ue_sync_t *q) { + + /* if we missed too many PSS go back to FIND */ + q->frame_no_cnt++; + if (q->frame_no_cnt >= TRACK_MAX_LOST) { + printf("\n%d frames lost. Going back to FIND\n", (int) q->frame_no_cnt); + q->state = SF_FIND; + } else { + INFO("Tracking peak not found. Peak %.3f, %d lost\n", + sync_get_peak_value(&q->strack), (int) q->frame_no_cnt); + } + + return LIBLTE_SUCCESS; +} + +static int receive_samples(ue_sync_t *q) { + uint32_t read_len; + + /* A negative time offset means there are samples in our buffer for the next subframe, + because we are sampling too fast. + */ + if (q->time_offset < 0) { + q->time_offset = -q->time_offset; + } + + if (q->state == SF_FIND) { + read_len = 5 * CURRENT_SFLEN; + } else { + read_len = CURRENT_SFLEN; + } + + /* copy last part of the last subframe (use move since there could be overlapping) */ + memcpy(q->input_buffer, &q->input_buffer[read_len-q->time_offset], q->time_offset*sizeof(cf_t)); + + /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ + if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], read_len - q->time_offset) < 0) { + return LIBLTE_ERROR; + } + + /* reset time offset */ + q->time_offset = 0; + + return LIBLTE_SUCCESS; +} + +int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t track_idx; + struct timeval t[3]; + + if (q != NULL && + sf_symbols != NULL && + q->input_buffer != NULL) + { + + if (receive_samples(q)) { + fprintf(stderr, "Error receiving samples\n"); + return -1; + } + + switch (q->state) { + case SF_FIND: + ret = sync_find(&q->sfind, q->input_buffer, 0, &q->peak_idx); + if (ret < 0) { + fprintf(stderr, "Error finding correlation peak (%d)\n", ret); + return -1; + } + + DEBUG("Find PAR=%.2f\n", sync_get_last_peak_value(&q->sfind)); + + if (ret == 1) { + ret = find_peak_ok(q); + } else if (q->peak_idx != 0) { + uint32_t rlen; + if (q->peak_idx < CURRENT_SFLEN/2) { + rlen = CURRENT_SFLEN/2-q->peak_idx; + } else { + rlen = q->peak_idx; + } + if (q->recv_callback(q->stream, q->input_buffer, rlen) < 0) { + return LIBLTE_ERROR; + } + } + break; + case SF_TRACK: + ret = LIBLTE_SUCCESS; + + q->strack.sss_en = q->decode_sss_on_track; + + q->sf_idx = (q->sf_idx + 1) % 10; + + DEBUG("TRACK: SF=%d FrameCNT: %d\n", q->sf_idx, q->frame_total_cnt); + + /* Every SF idx 0 and 5, find peak around known position q->peak_idx */ + if (q->sf_idx == 0 || q->sf_idx == 5) { + + #ifdef MEASURE_EXEC_TIME + gettimeofday(&t[1], NULL); + #endif + + track_idx = 0; + + /* track pss around the middle of the subframe, where the PSS is */ + ret = sync_find(&q->strack, q->input_buffer, CURRENT_SFLEN/2-CURRENT_FFTSIZE, &track_idx); + if (ret < 0) { + fprintf(stderr, "Error tracking correlation peak\n"); + return -1; + } + + #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); + #endif + + if (ret == 1) { + ret = track_peak_ok(q, track_idx); + } else { + ret = track_peak_no(q); + } + + INFO("TRACK %3d: Value=%.3f SF=%d Track_idx=%d Offset=%d CFO: %f\n", + (int) q->frame_total_cnt, sync_get_peak_value(&q->strack), + q->sf_idx, track_idx, q->time_offset, sync_get_cfo(&q->strack)); + + q->frame_total_cnt++; + + if (ret == LIBLTE_ERROR) { + fprintf(stderr, "Error processing tracking peak\n"); + q->state = SF_FIND; + return LIBLTE_SUCCESS; + } + } + + /* Do CFO Correction and deliver the frame */ + cfo_correct(&q->cfocorr, q->input_buffer, q->input_buffer, -q->cur_cfo / CURRENT_FFTSIZE); + *sf_symbols = q->input_buffer; + + if (ret == LIBLTE_SUCCESS) { + ret = 1; + } + break; + } + } + DEBUG("UE SYNC returns %d\n", ret); + return ret; +} + +void ue_sync_reset(ue_sync_t *q) { + q->state = SF_FIND; + + q->frame_ok_cnt = 0; + q->frame_no_cnt = 0; + q->frame_total_cnt = 0; + q->cur_cfo = 0; + q->mean_time_offset = 0; + q->time_offset = 0; + #ifdef MEASURE_EXEC_TIME + q->mean_exec_time = 0; + #endif +} + diff --git a/lte/phy/lib/ue/test/CMakeLists.txt b/lte/phy/lib/ue/test/CMakeLists.txt new file mode 100644 index 000000000..e44f12b70 --- /dev/null +++ b/lte/phy/lib/ue/test/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# 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/. +# + +######################################################################## +# UE SYNC TEST (Only compiled if CUHD is available) +######################################################################## +LIST(FIND OPTIONAL_LIBS cuhd CUHD_FIND) +LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) + +IF(${CUHD_FIND} GREATER -1) + ADD_EXECUTABLE(ue_sync_usrp ue_sync_usrp.c) + TARGET_LINK_LIBRARIES(ue_sync_usrp lte_phy cuhd) + + ADD_EXECUTABLE(ue_cell_detect ue_cell_detect.c) + TARGET_LINK_LIBRARIES(ue_cell_detect lte_phy cuhd) +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) + diff --git a/lte/phy/lib/ue/test/ue_cell_detect.c b/lte/phy/lib/ue/test/ue_cell_detect.c new file mode 100644 index 000000000..6ef13f707 --- /dev/null +++ b/lte/phy/lib/ue/test/ue_cell_detect.c @@ -0,0 +1,246 @@ +/** + * + * \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 + +#include "liblte/phy/phy.h" + +#include "liblte/cuhd/cuhd.h" +void *uhd; + +int nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL; +int nof_frames_detected = CS_DEFAULT_NOFFRAMES_DETECTED; +float threshold = -1; + +float uhd_freq = 0.0, uhd_gain = 20.0; +char *uhd_args = ""; + +void usage(char *prog) { + printf("Usage: %s [agntdv] -f uhd_freq\n", prog); + printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-g UHD RX gain [Default %.2f dB]\n", uhd_gain); + printf("\t-n nof_frames_total [Default 100]\n"); + printf("\t-d nof_frames_detected [Default 10]\n"); + printf("\t-t threshold [Default %.2f]\n",threshold); + printf("\t-v [set verbose to debug, default none]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "agndtvf")) != -1) { + switch (opt) { + case 'n': + nof_frames_total = atoi(argv[optind]); + break; + case 'd': + nof_frames_detected = atoi(argv[optind]); + break; + case 'a': + uhd_args = argv[optind]; + break; + case 'g': + uhd_gain = atof(argv[optind]); + break; + case 'f': + uhd_freq = atof(argv[optind]); + break; + case 't': + threshold = atof(argv[optind]); + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (uhd_freq == 0.0) { + usage(argv[0]); + exit(-1); + } +} + +void input_init() { + + printf("Opening UHD device...\n"); + if (cuhd_open(uhd_args, &uhd)) { + fprintf(stderr, "Error opening uhd\n"); + exit(-1); + } + cuhd_set_rx_gain(uhd, uhd_gain); + + /* set uhd_freq */ + cuhd_set_rx_freq(uhd, (double) uhd_freq); + cuhd_rx_wait_lo_locked(uhd); + DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000); + + INFO("Setting sampling frequency 960 KHz for PSS search\n", 0); + cuhd_set_rx_srate(uhd, 960000.0); + + DEBUG("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + +} + +int main(int argc, char **argv) { + ue_cellsearch_t s; + ue_mib_t uemib; + ue_cellsearch_result_t found_cell; + pbch_mib_t mib; + uint32_t flen; + cf_t *buffer; + int n; + + parse_args(argc, argv); + + input_init(); + + // allocate for the maximum size (10 ms at 1.92 MHz for PBCH decoding) + buffer = vec_malloc(sizeof(cf_t) * 19200*30); + if (!buffer) { + perror("malloc"); + exit(-1); + } + + if (ue_cellsearch_init(&s)) { + fprintf(stderr, "Error initiating UE sync module\n"); + exit(-1); + } + if (threshold > 0) { + ue_cellsearch_set_threshold(&s, threshold); + } + + if (nof_frames_total > 0) { + ue_cellsearch_set_nof_frames_total(&s, nof_frames_total); + } + if (nof_frames_detected > 0) { + ue_cellsearch_set_nof_frames_detected(&s, nof_frames_detected); + } + + uint32_t nof_scanned_cells = 0; + flen = 4800; + + do { + + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + exit(-1); + } + + n = ue_cellsearch_scan(&s, buffer, flen, &found_cell); + switch(n) { + case CS_FRAME_UNALIGNED: + fprintf(stderr, "Unaliged frame!! Exiting\n"); + exit(-1); + case CS_CELL_DETECTED: + printf("\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n", + found_cell.cell_id, lte_cp_string(found_cell.cp), + found_cell.peak, found_cell.mode, s.nof_frames_detected); + + nof_scanned_cells++; + break; + case CS_CELL_NOT_DETECTED: + nof_scanned_cells++; + break; + case LIBLTE_ERROR: + case LIBLTE_ERROR_INVALID_INPUTS: + fprintf(stderr, "Error calling cellsearch_scan()\n"); + exit(-1); + } + } while(nof_scanned_cells < 3 && n != CS_CELL_DETECTED); + + if (n == CS_CELL_DETECTED) { + INFO("Stopping receiver...\n", 0); + cuhd_stop_rx_stream(uhd); + + cuhd_flush_buffer(uhd); + + if (ue_mib_init(&uemib, found_cell.cell_id, found_cell.cp)) { + fprintf(stderr, "Error initiating PBCH decoder\n"); + exit(-1); + } + + INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0); + cuhd_set_rx_srate(uhd, 1920000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + usleep(50000); + + uint32_t nof_frames = 0; + flen = MIB_FRAME_SIZE; + + do { + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + exit(-1); + } + + INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total); + + n = ue_mib_decode(&uemib, buffer, flen, &mib); + if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) { + fprintf(stderr, "Error calling ue_mib_decode()\n"); + exit(-1); + } + if (n == MIB_FRAME_UNALIGNED) { + printf("Realigning frame\n"); + if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + exit(-1); + } + } + nof_frames++; + } while (n != MIB_FOUND && nof_frames < nof_frames_total); + if (n == MIB_FOUND) { + printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames); + pbch_mib_fprint(stdout, &mib, found_cell.cell_id); + } else { + printf("\nCould not decode MIB\n"); + } + } + + + + ue_mib_free(&uemib); + ue_cellsearch_free(&s); + cuhd_close(uhd); + exit(0); +} + + diff --git a/lte/phy/lib/phch/test/ue_sync_usrp.c b/lte/phy/lib/ue/test/ue_sync_usrp.c similarity index 96% rename from lte/phy/lib/phch/test/ue_sync_usrp.c rename to lte/phy/lib/ue/test/ue_sync_usrp.c index 50ee9bbec..caa667907 100644 --- a/lte/phy/lib/phch/test/ue_sync_usrp.c +++ b/lte/phy/lib/ue/test/ue_sync_usrp.c @@ -167,14 +167,17 @@ int main(int argc, char **argv) { #endif input_init(); + + cell.cp = CPNORM; + cell.id = 1; + cell.nof_ports = 1; + cell.nof_prb = 6; - if (ue_sync_init(&s, cuhd_set_rx_srate, cuhd_recv_wrapper, uhd)) { + if (ue_sync_init(&s, cell, cuhd_recv_wrapper, uhd)) { fprintf(stderr, "Error initiating UE sync module\n"); exit(-1); } - ue_sync_pbch_enable(&s, true); - signal_detected = true; frame_cnt = 0; mean_ce_time=0; @@ -191,9 +194,8 @@ int main(int argc, char **argv) { if (n == 1 && ue_sync_get_sfidx(&s) == 0) { if (signal_detected) { - cell = ue_sync_get_cell(&s); pss_synch_init_fft(&pss, - SF_LEN(lte_symbol_sz(cell.nof_prb), cell.cp), + SF_LEN(lte_symbol_sz(cell.nof_prb)), lte_symbol_sz(cell.nof_prb)); pss_synch_set_N_id_2(&pss, cell.id%3); diff --git a/lte/phy/lib/utils/src/vector.c b/lte/phy/lib/utils/src/vector.c index e8839df69..c85b7b99e 100644 --- a/lte/phy/lib/utils/src/vector.c +++ b/lte/phy/lib/utils/src/vector.c @@ -424,6 +424,29 @@ uint32_t vec_max_fi(float *x, uint32_t len) { #endif } + +uint32_t vec_max_abs_ci(cf_t *x, uint32_t len) { +#ifdef HAVE_VOLK_MAX_ABS_FUNCTION + uint32_t target=0; + volk_32fc_index_max_16u(&target,x,len); + return target; + +#else + uint32_t i; + float m=-FLT_MAX; + uint32_t p=0; + float tmp; + for (i=0;im) { + m=tmp; + p=i; + } + } + return p; +#endif +} + void vec_quant_fuc(float *in, unsigned char *out, float gain, float offset, float clip, uint32_t len) { int i; int tmp; diff --git a/matlab/sync/find_peaks.m b/matlab/sync/find_peaks.m new file mode 100644 index 000000000..7f9b27bf5 --- /dev/null +++ b/matlab/sync/find_peaks.m @@ -0,0 +1,13 @@ +function [peaks] = find_peaks(x, N_id_2, fft_size) + +flen=4800*(ceil(fft_size/64)); + +n=floor(length(x)/flen)*flen; +xf=reshape(x(1:n),flen,[]); + +[n m] = size(xf); + +peaks=zeros(m,1); +for i=1:m + [w, peaks(i)]= find_pss2(xf(:,i),N_id_2,fft_size); +end diff --git a/matlab/sync/find_pss2.m b/matlab/sync/find_pss2.m index 084f48fe6..478a47cdb 100644 --- a/matlab/sync/find_pss2.m +++ b/matlab/sync/find_pss2.m @@ -1,16 +1,14 @@ -function [ w2] = find_pss2( x, N_id_2, fft_size) +function [w2, m, idx] = find_pss2( x, N_id_2, fft_size) c=lte_pss_zc(N_id_2); cc=[zeros(fft_size/2-31,1); c; zeros(fft_size/2-31,1)]; ccd=[0; cc(fft_size/2+1:fft_size); cc(2:fft_size/2)]; ccf=sqrt(fft_size)*conj(ifft(ccd)); - w2=real(conv(x,ccf))/62; + w2=abs(conv(x,ccf/62)).^2/var(x,1)/sqrt(2); plot(w2) - [m i]=max(w2); - en=var(x,1); - p_m = m/en; + [m, idx]=max(w2); - fprintf('Frame starts at %d, energy=%g, p=%g, p/en=%g dB\n',i, ... - en, m, m/en); + %fprintf('Frame starts at %d, energy=%g, p=%g, p/en=%g dB\n',i, ... + % en, m, m/en); end