From ecf140a4e9f25469c8ef533dc2ba6984f4c586cd Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 22 Jul 2014 18:13:24 +0200 Subject: [PATCH 01/11] Added Test and Benchmark for soft_demodulation approximation algorithms --- lte/phy/include/liblte/phy/channel/ch_awgn.h | 8 +- lte/phy/include/liblte/phy/utils/vector.h | 3 + lte/phy/lib/channel/src/ch_awgn.c | 20 +- lte/phy/lib/modem/src/demod_soft.c | 1 + lte/phy/lib/modem/src/soft_algs.c | 112 ++++----- lte/phy/lib/modem/test/CMakeLists.txt | 8 + lte/phy/lib/modem/test/soft_demod_test.c | 229 +++++++++++++++++++ lte/phy/lib/phch/src/ue_sync.c | 2 - 8 files changed, 318 insertions(+), 65 deletions(-) create mode 100644 lte/phy/lib/modem/test/soft_demod_test.c diff --git a/lte/phy/include/liblte/phy/channel/ch_awgn.h b/lte/phy/include/liblte/phy/channel/ch_awgn.h index fa209dfe3..940ad332d 100644 --- a/lte/phy/include/liblte/phy/channel/ch_awgn.h +++ b/lte/phy/include/liblte/phy/channel/ch_awgn.h @@ -27,6 +27,8 @@ #include +#include + #include "liblte/config.h" #ifndef CH_AWGN_ @@ -37,13 +39,15 @@ typedef _Complex float cf_t; LIBLTE_API void ch_awgn_c(const cf_t* input, cf_t* output, float variance, - int buff_sz); + uint32_t len); LIBLTE_API void ch_awgn_f(const float* x, float* y, float variance, - int buff_sz); + uint32_t len); +LIBLTE_API float ch_awgn_get_variance(float ebno_db, + float rate); /* High-level API */ diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 369428fb9..0e6b5a041 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -35,6 +35,9 @@ typedef _Complex float cf_t; +#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) + + /** Return the sum of all the elements */ LIBLTE_API int vec_acc_ii(int *x, uint32_t len); LIBLTE_API float vec_acc_ff(float *x, uint32_t len); diff --git a/lte/phy/lib/channel/src/ch_awgn.c b/lte/phy/lib/channel/src/ch_awgn.c index 54a70b482..05dadf975 100644 --- a/lte/phy/lib/channel/src/ch_awgn.c +++ b/lte/phy/lib/channel/src/ch_awgn.c @@ -29,25 +29,31 @@ #include #include #include +#include #include "gauss.h" #include "liblte/phy/channel/ch_awgn.h" -void ch_awgn_c(const cf_t* x, cf_t* y, float variance, int buff_sz) { - _Complex float tmp; - int i; +float ch_awgn_get_variance(float ebno_db, float rate) { + float esno_db = ebno_db + 10 * log10f(rate); + return sqrtf(1 / (powf(10, esno_db / 10))); +} + +void ch_awgn_c(const cf_t* x, cf_t* y, float variance, uint32_t len) { + cf_t tmp; + uint32_t i; - for (i=0;isigma = 1.0; } void demod_soft_table_set(demod_soft_t *q, modem_table_t *table) { diff --git a/lte/phy/lib/modem/src/soft_algs.c b/lte/phy/lib/modem/src/soft_algs.c index 12e12591c..cb8d4e40b 100644 --- a/lte/phy/lib/modem/src/soft_algs.c +++ b/lte/phy/lib/modem/src/soft_algs.c @@ -50,42 +50,44 @@ * \param S Soft demapping auxiliary matrix * \param sigma2 Noise vatiance */ -void llr_approx(const _Complex float *in, float *out, int N, int M, int B, - _Complex float *symbols, uint32_t (*S)[6][32], float sigma2) { +void +llr_approx(const _Complex float *in, float *out, int N, int M, int B, + _Complex float *symbols, uint32_t(*S)[6][32], float sigma2) +{ int i, s, b; float num, den; int change_sign = -1; float x, y, d[64]; - for (s=0; s +#include +#include +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +int nof_frames = 10; +int num_bits = 1000; +lte_mod_t modulation = 0; + +void usage(char *prog) { + printf("Usage: %s [nfv] -m modulation (1: BPSK, 2: QPSK, 4: QAM16, 6: QAM64)\n", prog); + printf("\t-n num_bits [Default %d]\n", num_bits); + printf("\t-f nof_frames [Default %d]\n", nof_frames); + printf("\t-v verbose [Default None]\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "nmvf")) != -1) { + switch (opt) { + case 'n': + num_bits = atoi(argv[optind]); + break; + case 'f': + nof_frames = atoi(argv[optind]); + break; + case 'v': + verbose++; + break; + case 'm': + switch(atoi(argv[optind])) { + case 1: + modulation = LTE_BPSK; + break; + case 2: + modulation = LTE_QPSK; + break; + case 4: + modulation = LTE_QAM16; + break; + case 6: + modulation = LTE_QAM64; + break; + default: + fprintf(stderr, "Invalid modulation %d. Possible values: " + "(1: BPSK, 2: QPSK, 4: QAM16, 6: QAM64)\n", atoi(argv[optind])); + break; + } + break; + default: + usage(argv[0]); + exit(-1); + } + } + if (modulation == 0) { + usage(argv[0]); + exit(-1); + } +} + +float mse_threshold() { + switch(modulation) { + case LTE_BPSK: + return 1.0e-6; + case LTE_QPSK: + return 1.0e-6; + case LTE_QAM16: + return 0.11; + case LTE_QAM64: + return 0.18; + default: + return -1.0; + } +} + +int main(int argc, char **argv) { + int i; + modem_table_t mod; + demod_soft_t demod_soft; + char *input, *output; + cf_t *symbols; + float *llr_exact, *llr_approx; + + parse_args(argc, argv); + + /* initialize objects */ + if (modem_table_lte(&mod, modulation, true)) { + fprintf(stderr, "Error initializing modem table\n"); + exit(-1); + } + + /* check that num_bits is multiple of num_bits x symbol */ + num_bits = mod.nbits_x_symbol * (num_bits / mod.nbits_x_symbol); + + demod_soft_init(&demod_soft); + demod_soft_table_set(&demod_soft, &mod); + demod_soft_sigma_set(&demod_soft, 2.0 / mod.nbits_x_symbol); + + /* allocate buffers */ + input = malloc(sizeof(char) * num_bits); + if (!input) { + perror("malloc"); + exit(-1); + } + output = malloc(sizeof(char) * num_bits); + if (!output) { + perror("malloc"); + exit(-1); + } + symbols = malloc(sizeof(cf_t) * num_bits / mod.nbits_x_symbol); + if (!symbols) { + perror("malloc"); + exit(-1); + } + + llr_exact = malloc(sizeof(float) * num_bits); + if (!llr_exact) { + perror("malloc"); + exit(-1); + } + + llr_approx = malloc(sizeof(float) * num_bits); + if (!llr_approx) { + perror("malloc"); + exit(-1); + } + + /* generate random data */ + srand(time(NULL)); + + int ret = -1; + double mse; + struct timeval t[3]; + float mean_texec = 0.0; + for (int n=0;n %f)\n", mse, mse_threshold()); + } + exit(ret); +} diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c index b877cf3b8..c62739da9 100644 --- a/lte/phy/lib/phch/src/ue_sync.c +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -40,8 +40,6 @@ #define MAX_TIME_OFFSET 128 cf_t dummy[MAX_TIME_OFFSET]; -#define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) - #define CURRENT_FFTSIZE lte_symbol_sz(q->cell.nof_prb) #define CURRENT_SFLEN SF_LEN(CURRENT_FFTSIZE, q->cell.cp) From a7ef0baecbc580ad2d6e63a8d3c65cc4392ebe5c Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 22 Jul 2014 18:38:25 +0200 Subject: [PATCH 02/11] Added volk'ed version of llr_approx --- lte/phy/lib/modem/src/soft_algs.c | 53 +++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/lte/phy/lib/modem/src/soft_algs.c b/lte/phy/lib/modem/src/soft_algs.c index cb8d4e40b..589c24824 100644 --- a/lte/phy/lib/modem/src/soft_algs.c +++ b/lte/phy/lib/modem/src/soft_algs.c @@ -34,6 +34,54 @@ #include "soft_algs.h" +#define LLR_APPROX_USE_VOLK + + +#ifdef LLR_APPROX_USE_VOLK +void +llr_approx(const _Complex float *in, float *out, int N, int M, int B, + _Complex float *symbols, uint32_t(*S)[6][32], float sigma2) +{ + int i, s, b; + float num, den; + int change_sign = -1; + float x, y, d[64]; + + for (s = 0; s < N; s++) { /* recevied symbols */ + /* Compute the distances squared d[i] between the received symbol and all constellation points */ + for (i = 0; i < M; i++) { + x = __real__ in[s] - __real__ symbols[i]; + y = __imag__ in[s] - __imag__ symbols[i]; + d[i] = x * x + y * y; + } + + for (b = 0; b < B; b++) { /* bits per symbol */ + /* initiate num[b] and den[b] */ + num = d[S[0][b][0]]; + den = d[S[1][b][0]]; + + /* Minimum distance squared search between recevied symbol and a constellation point with a + '1' and a '0' for each bit position */ + for (i = 1; i < M / 2; i++) { /* half the constellation points have '1'|'0' at any given bit position */ + if (d[S[0][b][i]] < num) { + num = d[S[0][b][i]]; + } + if (d[S[1][b][i]] < den) { + den = d[S[1][b][i]]; + } + } + /* Theoretical LLR and approximate LLR values are positive if + * symbol(s) with '0' is/are closer and negative if symbol(s) + * with '1' are closer. + * Change sign if mapping negative to '0' and positive to '1' */ + out[s * B + b] = change_sign * (den - num) / sigma2; + } + } + +} + +#else + /** * @ingroup Soft Modulation Demapping based on the approximate * log-likelihood algorithm @@ -92,6 +140,8 @@ llr_approx(const _Complex float *in, float *out, int N, int M, int B, } +#endif + /** * @ingroup Soft Modulation Demapping based on the approximate * log-likelihood ratio algorithm @@ -108,8 +158,7 @@ llr_approx(const _Complex float *in, float *out, int N, int M, int B, * \param S Soft demapping auxiliary matrix * \param sigma2 Noise vatiance */ -void -llr_exact(const _Complex float *in, float *out, int N, int M, int B, +void llr_exact(const _Complex float *in, float *out, int N, int M, int B, _Complex float *symbols, uint32_t(*S)[6][32], float sigma2) { int i, s, b; From 66c6862f7d5fb69e49e98e51ad7d49f0d0c08f23 Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 22 Jul 2014 19:12:59 +0200 Subject: [PATCH 03/11] Test wasn't added --- lte/phy/lib/modem/test/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lte/phy/lib/modem/test/CMakeLists.txt b/lte/phy/lib/modem/test/CMakeLists.txt index 24ebc1986..0804c5d56 100644 --- a/lte/phy/lib/modem/test/CMakeLists.txt +++ b/lte/phy/lib/modem/test/CMakeLists.txt @@ -39,10 +39,10 @@ ADD_TEST(modem_qam64_soft modem_test -n 1020 -m 6 -s) ADD_EXECUTABLE(soft_demod_test soft_demod_test.c) TARGET_LINK_LIBRARIES(soft_demod_test lte_phy) -ADD_TEST(modem_bpsk_soft modem_test -n 1020 -m 1) -ADD_TEST(modem_qpsk_soft modem_test -n 1020 -m 2) -ADD_TEST(modem_qam16_soft modem_test -n 1020 -m 4) -ADD_TEST(modem_qam64_soft modem_test -n 1020 -m 6) +ADD_TEST(modem_bpsk_soft_approx soft_demod_test -n 1020 -m 1) +ADD_TEST(modem_qpsk_soft_approx soft_demod_test -n 1020 -m 2) +ADD_TEST(modem_qam16_soft_approx soft_demod_test -n 1020 -m 4) +ADD_TEST(modem_qam64_soft_approx soft_demod_test -n 1020 -m 6) From ad004c58d854bb65ca62a392569bc3ef8c673097 Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 22 Jul 2014 20:11:48 +0200 Subject: [PATCH 04/11] Adjusted PSS find thresholds for loaded cells --- cuhd/lib/cuhd_imp.cpp | 1 + lte/phy/examples/pdsch_enodeb.c | 8 ++++++-- lte/phy/examples/pdsch_ue.c | 10 +++++++--- lte/phy/include/liblte/phy/phch/pdsch.h | 2 +- lte/phy/lib/phch/src/ue_sync.c | 19 +++++++++++-------- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/cuhd/lib/cuhd_imp.cpp b/cuhd/lib/cuhd_imp.cpp index 3baed47a5..b0f9baf61 100644 --- a/cuhd/lib/cuhd_imp.cpp +++ b/cuhd/lib/cuhd_imp.cpp @@ -112,6 +112,7 @@ int cuhd_open(char *args, void **h) std::string _args = std::string(args); handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=30720000" + ", num_recv_frames=512"); +// handler->usrp = uhd::usrp::multi_usrp::make(_args + ", master_clock_rate=50000000" + ", num_recv_frames=512"); handler->usrp->set_clock_source("internal"); std::string otw, cpu; diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 7aeb435f2..88f87864a 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -52,7 +52,7 @@ uint32_t mcs_idx = 12; int nof_frames = -1; char *uhd_args = ""; -float uhd_amp = 0.25, uhd_gain = 10.0, uhd_freq = 2400000000; +float uhd_amp = 0.01, uhd_gain = 10.0, uhd_freq = 2400000000; filesink_t fsink; lte_fft_t ifft; @@ -70,6 +70,7 @@ void usage(char *prog) { printf("Usage: %s [agmfoncvp]\n", prog); #ifndef DISABLE_UHD printf("\t-a UHD args [Default %s]\n", uhd_args); + printf("\t-l UHD amplitude [Default %.2f]\n", uhd_amp); printf("\t-g UHD TX gain [Default %.2f dB]\n", uhd_gain); printf("\t-f UHD TX frequency [Default %.1f MHz]\n", uhd_freq / 1000000); #else @@ -85,7 +86,7 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agfmoncpv")) != -1) { + while ((opt = getopt(argc, argv, "aglfmoncpv")) != -1) { switch (opt) { case 'a': uhd_args = argv[optind]; @@ -93,6 +94,9 @@ void parse_args(int argc, char **argv) { case 'g': uhd_gain = atof(argv[optind]); break; + case 'l': + uhd_amp = atof(argv[optind]); + break; case 'f': uhd_freq = atof(argv[optind]); break; diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index eeed8e276..951bc7393 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -99,7 +99,7 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "icagfndvtbp")) != -1) { + while ((opt = getopt(argc, argv, "icagfndvtbpr")) != -1) { switch (opt) { case 'i': args->io_config.input_file_name = argv[optind]; @@ -125,6 +125,9 @@ void parse_args(prog_args_t *args, int argc, char **argv) { case 'n': args->nof_subframes = atoi(argv[optind]); break; + case 'r': + args->rnti= atoi(argv[optind]); + break; case 'd': args->disable_plots = true; break; @@ -201,8 +204,9 @@ 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\r", - sync_get_peak_value(&iodev.sframe.s), 10*log10f(agc_get_gain(&iodev.sframe.agc))); + 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)), + iodev.sframe.frame_total_cnt, iodev.sframe.state); } else if (ret == 1) { if (!ue_dl_initiated) { if (iodev_isUSRP(&iodev)) { diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index 44717689b..e844ffb8a 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -43,7 +43,7 @@ #include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/regs.h" -#define TDEC_ITERATIONS 6 +#define TDEC_ITERATIONS 3 typedef _Complex float cf_t; diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c index b877cf3b8..a1b2d485a 100644 --- a/lte/phy/lib/phch/src/ue_sync.c +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -60,19 +60,19 @@ static void update_threshold(ue_sync_t *q) { if (symbol_sz > 0) { switch (symbol_sz) { case 128: - sync_set_threshold(&q->s, 20000, 2000); + sync_set_threshold(&q->s, 10000, 1000); break; case 256: - sync_set_threshold(&q->s, 25000, 2500); + sync_set_threshold(&q->s, 20000, 2000); break; case 512: - sync_set_threshold(&q->s, 38000, 3800); + sync_set_threshold(&q->s, 30000, 3000); break; case 1024: - sync_set_threshold(&q->s, 50000, 5000); + sync_set_threshold(&q->s, 40000, 4000); break; case 2048: - sync_set_threshold(&q->s, 80000, 4000); + sync_set_threshold(&q->s, 50000, 5000); } } } @@ -318,13 +318,16 @@ static int mib_decoder_run(ue_sync_t *q) { 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; - q->cell.nof_prb = q->mib.nof_prb; if (!q->pbch_decoded) { printf("\n\nMIB decoded:\n"); pbch_mib_fprint(stdout, &q->mib, q->cell.id); - if (q->change_srate) { - ret = update_srate(q); + + 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); From 3dfb1824b40a8ff86fb730aeec8c65f5fbb2f479 Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 22 Jul 2014 23:17:30 +0200 Subject: [PATCH 05/11] Added CRC-based early stopping to Turbo decoder --- lte/phy/examples/iodev.c | 4 +- lte/phy/examples/iodev.h | 3 +- lte/phy/examples/pdsch_enodeb.c | 5 ++- lte/phy/examples/pdsch_ue.c | 16 +++++-- lte/phy/include/liblte/phy/phch/pdsch.h | 9 +++- lte/phy/lib/phch/src/pdsch.c | 56 ++++++++++++++++++++----- 6 files changed, 74 insertions(+), 19 deletions(-) diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c index af6916105..41d6e6a48 100644 --- a/lte/phy/examples/iodev.c +++ b/lte/phy/examples/iodev.c @@ -48,7 +48,7 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { } /* Setup USRP or input file */ -int iodev_init(iodev_t *q, iodev_cfg_t *config) { +int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) { if (config->input_file_name) { if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) { @@ -61,7 +61,7 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config) { } q->mode = FILESOURCE; - q->sf_len = 1920; + q->sf_len = file_sf_len; } else { #ifndef DISABLE_UHD diff --git a/lte/phy/examples/iodev.h b/lte/phy/examples/iodev.h index 87264eda6..3164f91c5 100644 --- a/lte/phy/examples/iodev.h +++ b/lte/phy/examples/iodev.h @@ -74,7 +74,8 @@ typedef struct LIBLTE_API { LIBLTE_API int iodev_init(iodev_t *q, - iodev_cfg_t *config); + iodev_cfg_t *config, + uint32_t file_sf_len); LIBLTE_API void iodev_free(iodev_t *q); diff --git a/lte/phy/examples/pdsch_enodeb.c b/lte/phy/examples/pdsch_enodeb.c index 88f87864a..f761b043b 100644 --- a/lte/phy/examples/pdsch_enodeb.c +++ b/lte/phy/examples/pdsch_enodeb.c @@ -359,7 +359,10 @@ int main(int argc, char **argv) { exit(-1); } - pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx); + if (pdsch_encode(&pdsch, data, sf_symbols, sf_idx, &harq_process, ra_dl.rv_idx)) { + fprintf(stderr, "Error encoding PDSCH\n"); + exit(-1); + } /* Transform to OFDM symbols */ lte_ifft_run_sf(&ifft, sf_buffer, output_buffer); diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index 951bc7393..2af627e65 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -165,11 +165,18 @@ int main(int argc, char **argv) { pbch_mib_t mib; bool printed_sib = false; int rlen; + int symbol_sz; parse_args(&prog_args, argc, argv); - if (iodev_init(&iodev, &prog_args.io_config)) { - fprintf(stderr, "Error initiating input device\n"); + 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))) { + fprintf(stderr, "Error initiating input device\n"); + exit(-1); + } + } else { + fprintf(stderr, "Invalid number of PRB %d\n", prog_args.nof_prb_file); exit(-1); } @@ -242,9 +249,10 @@ int main(int argc, char **argv) { printed_sib = true; } if (!(sf_cnt % 10)) { - printf("RSSI: %+.2f dBm, CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Errors: %4d/%4d, BLER: %.1e\r", + 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, - ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000, iodev.sframe.peak_idx, + 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); fflush(stdout); diff --git a/lte/phy/include/liblte/phy/phch/pdsch.h b/lte/phy/include/liblte/phy/phch/pdsch.h index e844ffb8a..173837b98 100644 --- a/lte/phy/include/liblte/phy/phch/pdsch.h +++ b/lte/phy/include/liblte/phy/phch/pdsch.h @@ -43,7 +43,7 @@ #include "liblte/phy/phch/dci.h" #include "liblte/phy/phch/regs.h" -#define TDEC_ITERATIONS 3 +#define TDEC_MAX_ITERATIONS 6 typedef _Complex float cf_t; @@ -75,6 +75,9 @@ typedef struct LIBLTE_API { uint32_t max_symbols; bool rnti_is_set; uint16_t rnti; + uint32_t nof_iterations; + uint64_t average_nof_iterations_n; + float average_nof_iterations; /* buffers */ // void buffers are shared for tx and rx @@ -128,6 +131,10 @@ LIBLTE_API int pdsch_decode(pdsch_t *q, pdsch_harq_t *harq_process, uint32_t rv_idx); +LIBLTE_API float pdsch_average_noi(pdsch_t *q); + +LIBLTE_API uint32_t pdsch_last_noi(pdsch_t *q); + LIBLTE_API int pdsch_get(pdsch_t *q, cf_t *sf_symbols, cf_t *pdsch_symbols, diff --git a/lte/phy/lib/phch/src/pdsch.c b/lte/phy/lib/phch/src/pdsch.c index 0f5a508d4..54892bd72 100644 --- a/lte/phy/lib/phch/src/pdsch.c +++ b/lte/phy/lib/phch/src/pdsch.c @@ -183,7 +183,7 @@ int pdsch_init(pdsch_t *q, lte_cell_t cell) { ret = LIBLTE_ERROR; q->cell = cell; - + q->average_nof_iterations_n = 0; q->max_symbols = q->cell.nof_prb * MAX_PDSCH_RE(q->cell.cp); INFO("Init PDSCH: %d ports %d PRBs, max_symbols: %d\n", q->cell.nof_ports, @@ -459,6 +459,15 @@ int pdsch_harq_setup(pdsch_harq_t *p, ra_mcs_t mcs, ra_prb_t *prb_alloc) { } +float pdsch_average_noi(pdsch_t *q) { + return q->average_nof_iterations; +} + +uint32_t pdsch_last_noi(pdsch_t *q) { + return q->nof_iterations; +} + + /* Decode a transport block according to 36.212 5.3.2 * */ @@ -516,17 +525,42 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, return LIBLTE_ERROR; } - /* Turbo Decoding */ - tdec_run_all(&q->decoder, (float*) q->cb_out, q->cb_in, TDEC_ITERATIONS, - cb_len); - - if (harq_process->cb_segm.C > 1) { + /* Turbo Decoding with CRC-based early stopping */ + q->nof_iterations = 0; + bool early_stop = false; + uint32_t len_crc; + char *cb_in_ptr; + crc_t *crc_ptr; + tdec_reset(&q->decoder, cb_len); + + do { + + tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len); + q->nof_iterations++; + + if (harq_process->cb_segm.C > 1) { + len_crc = cb_len; + cb_in_ptr = q->cb_in; + crc_ptr = &q->crc_cb; + } else { + len_crc = tbs+24; + cb_in_ptr = &q->cb_in[F]; + crc_ptr = &q->crc_tb; + } + /* Check Codeblock CRC and stop early if incorrect */ - if (crc_checksum(&q->crc_cb, q->cb_in, cb_len)) { - INFO("Error in CB#%d\n",i); - return LIBLTE_ERROR; + if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) { + early_stop = true; } - } + + } while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop); + + tdec_decision(&q->decoder, q->cb_in, cb_len); + + q->average_nof_iterations = EXPAVERAGE((float) q->nof_iterations, + q->average_nof_iterations, + q->average_nof_iterations_n); + q->average_nof_iterations_n++; /* Copy data to another buffer, removing the Codeblock CRC */ if (i < harq_process->cb_segm.C - 1) { @@ -534,6 +568,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, } else { DEBUG("Last CB, appending parity: %d to %d from %d and 24 from %d\n", rlen - F - 24, wp, F, rlen - 24); + /* Append Transport Block parity bits to the last CB */ memcpy(&data[wp], &q->cb_in[F], (rlen - F - 24) * sizeof(char)); memcpy(parity, &q->cb_in[rlen - 24], 24 * sizeof(char)); @@ -553,6 +588,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, par_tx = bit_unpack(&p_parity, 24); if (!par_rx) { + vec_fprint_hex(stdout, data, tbs); printf("\n\tCAUTION!! Received all-zero transport block\n\n"); } From 7658ced99d01d5fb5e37efee13c4ebd61866bc45 Mon Sep 17 00:00:00 2001 From: ismagom Date: Wed, 30 Jul 2014 12:05:17 +0200 Subject: [PATCH 06/11] Normalized PSS correlation result. Use real part only. Extended sync_test to more bandwidth --- cmake/modules/FindVolk.cmake | 6 +- lte/phy/examples/CMakeLists.txt | 4 +- .../examples/{scan_mib.c => cell_search.c} | 0 lte/phy/examples/synch_file.c | 9 ++- lte/phy/include/liblte/phy/sync/pss.h | 5 +- lte/phy/include/liblte/phy/sync/sync.h | 9 --- lte/phy/include/liblte/phy/utils/vector.h | 1 + lte/phy/lib/phch/src/ue_sync.c | 2 - lte/phy/lib/phch/test/ue_sync_usrp.c | 2 +- lte/phy/lib/sync/src/pss.c | 37 +++++++------ lte/phy/lib/sync/src/sss.c | 4 +- lte/phy/lib/sync/src/sync.c | 55 ++++--------------- lte/phy/lib/sync/test/CMakeLists.txt | 7 ++- lte/phy/lib/sync/test/sync_test.c | 44 ++++++++++----- lte/phy/lib/utils/src/convolution.c | 5 +- lte/phy/lib/utils/src/dft.c | 14 ++--- lte/phy/lib/utils/src/vector.c | 11 ++++ matlab/sync/addnoise.m | 6 ++ matlab/sync/find_pss2.m | 24 ++++---- 19 files changed, 119 insertions(+), 126 deletions(-) rename lte/phy/examples/{scan_mib.c => cell_search.c} (100%) create mode 100644 matlab/sync/addnoise.m diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index 7a3660f18..363e5fb84 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -42,14 +42,18 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_dot_prod_32f HAVE_VOLK_DOTPROD_F_FUNCTION CHECK_FUNCTION_EXISTS_MATH(volk_32fc_s32f_atan2_32f HAVE_VOLK_ATAN_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_convert_16i HAVE_VOLK_CONVERT_FI_FUNCTION) 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) + SET(VOLK_DEFINITIONS "HAVE_VOLK") IF(${HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION") ENDIF() +IF(${HAVE_VOLK_DEINTERLEAVE_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_DEINTERLEAVE_FUNCTION") +ENDIF() IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") ENDIF() diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index 988815d29..f798a23ac 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -81,8 +81,8 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1) IF(${CUHD_FIND} GREATER -1) - add_executable(scan_mib scan_mib.c) - target_link_libraries(scan_mib lte_phy cuhd ) + add_executable(cell_search cell_search.c) + target_link_libraries(cell_search lte_phy cuhd ) MESSAGE(STATUS " UHD examples will be installed.") diff --git a/lte/phy/examples/scan_mib.c b/lte/phy/examples/cell_search.c similarity index 100% rename from lte/phy/examples/scan_mib.c rename to lte/phy/examples/cell_search.c diff --git a/lte/phy/examples/synch_file.c b/lte/phy/examples/synch_file.c index 4bd746f87..fad7478f8 100644 --- a/lte/phy/examples/synch_file.c +++ b/lte/phy/examples/synch_file.c @@ -109,7 +109,6 @@ int main(int argc, char **argv) { int peak_pos[3]; float *cfo; float peak_value[3]; - float mean_value[3]; int frame_cnt; cf_t *input; uint32_t m0, m1; @@ -201,10 +200,10 @@ int main(int argc, char **argv) { if (force_N_id_2 != -1) { N_id_2 = force_N_id_2; - peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]); + peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } else { for (N_id_2=0;N_id_2<3;N_id_2++) { - peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2], &mean_value[N_id_2]); + peak_pos[N_id_2] = pss_synch_find_pss(&pss[N_id_2], input, &peak_value[N_id_2]); } float max_value=-99999; N_id_2=-1; @@ -218,7 +217,7 @@ int main(int argc, char **argv) { } /* If peak detected */ - if (peak_value[N_id_2]/mean_value[N_id_2] > corr_peak_threshold) { + if (peak_value[N_id_2] > corr_peak_threshold) { sss_idx = peak_pos[N_id_2]-2*(symbol_sz+CP(symbol_sz,CPNORM_LEN)); if (sss_idx >= 0) { @@ -228,7 +227,7 @@ int main(int argc, char **argv) { cfo[frame_cnt] = pss_synch_cfo_compute(&pss[N_id_2], &input[peak_pos[N_id_2]-128]); printf("\t%d\t%d\t%d\t%d\t%.3f\t\t%3d\t%d\t%d\t%.3f\n", frame_cnt,N_id_2, sss_synch_N_id_1(&sss[N_id_2], m0, m1), - sss_synch_subframe(m0, m1), peak_value[N_id_2]/mean_value[N_id_2], + sss_synch_subframe(m0, m1), peak_value[N_id_2], peak_pos[N_id_2], m0, m1, cfo[frame_cnt]); } diff --git a/lte/phy/include/liblte/phy/sync/pss.h b/lte/phy/include/liblte/phy/sync/pss.h index a27f92f6b..bdf298223 100644 --- a/lte/phy/include/liblte/phy/sync/pss.h +++ b/lte/phy/include/liblte/phy/sync/pss.h @@ -72,7 +72,7 @@ typedef struct LIBLTE_API { cf_t *pss_signal_freq[3]; // One sequence for each N_id_2 cf_t *tmp_input; - float *conv_abs; + float *conv_real; cf_t *conv_output; }pss_synch_t; @@ -102,8 +102,7 @@ LIBLTE_API int pss_synch_set_N_id_2(pss_synch_t *q, LIBLTE_API int pss_synch_find_pss(pss_synch_t *q, cf_t *input, - float *corr_peak_value, - float *corr_mean_value); + float *corr_peak_value); LIBLTE_API float pss_synch_cfo_compute(pss_synch_t* q, cf_t *pss_recv); diff --git a/lte/phy/include/liblte/phy/sync/sync.h b/lte/phy/include/liblte/phy/sync/sync.h index 8dddbc7b5..c86d389ff 100644 --- a/lte/phy/include/liblte/phy/sync/sync.h +++ b/lte/phy/include/liblte/phy/sync/sync.h @@ -51,13 +51,10 @@ * functions sync_pss_det_absolute() and sync_pss_det_peakmean(). */ -enum sync_pss_det { ABSOLUTE, PEAK_MEAN}; - typedef struct LIBLTE_API { pss_synch_t pss_find; pss_synch_t pss_track; sss_synch_t sss; - enum sync_pss_det pss_mode; float find_threshold; float track_threshold; float peak_value; @@ -103,12 +100,6 @@ LIBLTE_API void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold); -/* Set peak comparison to absolute value */ -LIBLTE_API void sync_pss_det_absolute(sync_t *q); - -/* Set peak comparison to relative to the mean */ -LIBLTE_API void sync_pss_det_peak_to_avg(sync_t *q); - /* Gets the slot id (0 or 10) */ LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 0e6b5a041..5a65a0d30 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -72,6 +72,7 @@ LIBLTE_API void vec_sc_prod_fff(float *x, float h, float *z, uint32_t len); LIBLTE_API void vec_convert_fi(float *x, int16_t *z, float scale, uint32_t len); LIBLTE_API void vec_deinterleave_cf(cf_t *x, float *real, float *imag, uint32_t len); +LIBLTE_API void vec_deinterleave_real_cf(cf_t *x, float *real, uint32_t len); /* vector product (element-wise) */ LIBLTE_API void vec_prod_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); diff --git a/lte/phy/lib/phch/src/ue_sync.c b/lte/phy/lib/phch/src/ue_sync.c index 22f55f0f4..8a4a45bdf 100644 --- a/lte/phy/lib/phch/src/ue_sync.c +++ b/lte/phy/lib/phch/src/ue_sync.c @@ -120,8 +120,6 @@ int ue_sync_init(ue_sync_t *q, goto clean_exit; } - sync_pss_det_absolute(&q->s); - if (cfo_init(&q->cfocorr, MAXIMUM_SFLEN)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; diff --git a/lte/phy/lib/phch/test/ue_sync_usrp.c b/lte/phy/lib/phch/test/ue_sync_usrp.c index 115d2649b..50ee9bbec 100644 --- a/lte/phy/lib/phch/test/ue_sync_usrp.c +++ b/lte/phy/lib/phch/test/ue_sync_usrp.c @@ -227,7 +227,7 @@ int main(int argc, char **argv) { } #endif - pos = pss_synch_find_pss(&pss, input_buffer, &peak, NULL); + pos = pss_synch_find_pss(&pss, input_buffer, &peak); /*if (pos > 962 || pos < 958) { unaligned++; } diff --git a/lte/phy/lib/sync/src/pss.c b/lte/phy/lib/sync/src/pss.c index 4c8da1a26..63959b5fe 100644 --- a/lte/phy/lib/sync/src/pss.c +++ b/lte/phy/lib/sync/src/pss.c @@ -36,6 +36,7 @@ #include "liblte/phy/utils/dft.h" #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/convolution.h" +#include "liblte/phy/utils/debug.h" int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_size) { @@ -45,7 +46,7 @@ int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_s int ret = LIBLTE_ERROR_INVALID_INPUTS; if (lte_N_id_2_isvalid(N_id_2) && - fft_size < 2048) + fft_size <= 2048) { pss_generate(pss_signal_time, N_id_2); @@ -60,11 +61,11 @@ int pss_synch_init_N_id_2(cf_t *pss_signal_freq, uint32_t N_id_2, uint32_t fft_s dft_plan_set_mirror(&plan, true); dft_plan_set_dc(&plan, true); + dft_plan_set_norm(&plan, true); dft_run_c(&plan, pss_signal_pad, pss_signal_freq); - vec_sc_prod_cfc(pss_signal_freq, (float) 1 / (fft_size), pss_signal_pad, fft_size); - vec_conj_cc(pss_signal_pad, pss_signal_freq, fft_size); - + vec_conj_cc(pss_signal_freq, pss_signal_freq, fft_size); + dft_plan_free(&plan); ret = LIBLTE_SUCCESS; @@ -97,8 +98,8 @@ int pss_synch_init_fft(pss_synch_t *q, uint32_t frame_size, uint32_t fft_size) { buffer_size = fft_size + frame_size + 1; - q->conv_abs = vec_malloc(buffer_size * sizeof(float)); - if (!q->conv_abs) { + q->conv_real = vec_malloc(buffer_size * sizeof(float)); + if (!q->conv_real) { fprintf(stderr, "Error allocating memory\n"); goto clean_and_exit; } @@ -160,8 +161,8 @@ void pss_synch_free(pss_synch_t *q) { if (q->conv_output) { free(q->conv_output); } - if (q->conv_abs) { - free(q->conv_abs); + if (q->conv_real) { + free(q->conv_real); } bzero(q, sizeof(pss_synch_t)); @@ -231,8 +232,7 @@ int pss_synch_set_N_id_2(pss_synch_t *q, uint32_t N_id_2) { * * Input buffer must be subframe_size long. */ -int pss_synch_find_pss(pss_synch_t *q, cf_t *input, - float *corr_peak_value, float *corr_mean_value) +int pss_synch_find_pss(pss_synch_t *q, cf_t *input, float *corr_peak_value) { int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -252,6 +252,7 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, memcpy(q->tmp_input, input, q->frame_size * sizeof(cf_t)); bzero(&q->tmp_input[q->frame_size], q->fft_size * sizeof(cf_t)); + /* Correlate input with PSS sequence */ #ifdef CONVOLUTION_FFT conv_output_len = conv_fft_cc_run(&q->conv_fft, q->tmp_input, q->pss_signal_freq[q->N_id_2], q->conv_output); @@ -259,16 +260,16 @@ int pss_synch_find_pss(pss_synch_t *q, cf_t *input, conv_output_len = conv_cc(input, q->pss_signal_freq[q->N_id_2], q->conv_output, q->frame_size, q->fft_size); #endif - vec_abs_cf(q->conv_output, q->conv_abs, conv_output_len); - corr_peak_pos = vec_max_fi(q->conv_abs, conv_output_len); + /* 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); if (corr_peak_value) { - *corr_peak_value = q->conv_abs[corr_peak_pos]; + *corr_peak_value = q->conv_real[corr_peak_pos]; } - if (corr_mean_value) { - *corr_mean_value = vec_acc_ff(q->conv_abs, conv_output_len) - / conv_output_len; - } - + 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/sss.c b/lte/phy/lib/sync/src/sss.c index 6feef89da..5755ea18f 100644 --- a/lte/phy/lib/sync/src/sss.c +++ b/lte/phy/lib/sync/src/sss.c @@ -44,7 +44,7 @@ void generate_N_id_1_table(uint32_t table[30][30]); int sss_synch_init(sss_synch_t *q, uint32_t fft_size) { if (q != NULL && - fft_size < 2048) + fft_size <= 2048) { uint32_t N_id_2; struct sss_tables sss_tables; @@ -73,7 +73,7 @@ int sss_synch_init(sss_synch_t *q, uint32_t fft_size) { int sss_synch_realloc(sss_synch_t *q, uint32_t fft_size) { if (q != NULL && - fft_size < 2048) + fft_size <= 2048) { dft_plan_free(&q->dftp_input); if (dft_plan(&q->dftp_input, fft_size, FORWARD, COMPLEX)) { diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 1370dd066..61d3bc36c 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -51,7 +51,6 @@ int sync_init(sync_t *q, uint32_t find_frame_size, uint32_t track_frame_size, ui fft_size_isvalid(fft_size)) { bzero(q, sizeof(sync_t)); - q->pss_mode = PEAK_MEAN; q->detect_cp = true; q->sss_en = true; q->N_id_2 = 1000; @@ -126,13 +125,6 @@ void sync_free(sync_t *q) { } } -void sync_pss_det_absolute(sync_t *q) { - q->pss_mode = ABSOLUTE; -} -void sync_pss_det_peak_to_avg(sync_t *q) { - q->pss_mode = PEAK_MEAN; -} - void sync_set_threshold(sync_t *q, float find_threshold, float track_threshold) { q->find_threshold = find_threshold; q->track_threshold = track_threshold; @@ -277,29 +269,16 @@ int sync_track(sync_t *q, cf_t *input, uint32_t offset, uint32_t *peak_position) input != NULL && fft_size_isvalid(q->fft_size)) { - float peak_value, mean_value, *mean_ptr; uint32_t peak_pos; pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); - - if (q->pss_mode == ABSOLUTE) { - mean_ptr = NULL; - } else { - mean_ptr = &mean_value; - } - - peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &peak_value, mean_ptr); + + peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &q->peak_value); - if (q->pss_mode == ABSOLUTE) { - q->peak_value = peak_value; - } else { - q->peak_value = peak_value / mean_value; - } - DEBUG("PSS possible tracking peak pos=%d peak=%.2f threshold=%.2f\n", - peak_pos, peak_value, q->track_threshold); + peak_pos, q->peak_value, q->track_threshold); - if (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 (q->sss_en) { @@ -326,20 +305,13 @@ 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 *peak_position) { uint32_t N_id_2, peak_pos[3]; float peak_value[3]; - float mean_value[3]; float max=-999; uint32_t i; int ret; - float *mean_ptr; - for (N_id_2=0;N_id_2<3;N_id_2++) { - if (q->pss_mode == ABSOLUTE) { - mean_ptr = NULL; - } else { - mean_ptr = &mean_value[N_id_2]; - } + 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], mean_ptr); + 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; @@ -354,19 +326,12 @@ int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { } } - if (q->pss_mode == ABSOLUTE) { - q->peak_value = peak_value[N_id_2]; - } else { - q->peak_value = peak_value[N_id_2] / mean_value[N_id_2]; - } - + q->peak_value = peak_value[N_id_2]; + if (peak_position) { *peak_position = 0; } - DEBUG("PSS possible peak N_id_2=%d, pos=%d peak=%.2f threshold=%.2f\n", - N_id_2, peak_pos[N_id_2], peak_value[N_id_2], q->find_threshold); - /* If peak detected */ if (q->peak_value > q->find_threshold) { if (peak_pos[N_id_2] > q->fft_size && @@ -376,8 +341,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t *peak_position) { 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 par=%.2f th=%.2f cfo=%.4f\n", N_id_2, - peak_pos[N_id_2], peak_value[N_id_2], q->peak_value, q->find_threshold, q->cfo); + 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) { diff --git a/lte/phy/lib/sync/test/CMakeLists.txt b/lte/phy/lib/sync/test/CMakeLists.txt index 72b2ccb6a..4a552f87f 100644 --- a/lte/phy/lib/sync/test/CMakeLists.txt +++ b/lte/phy/lib/sync/test/CMakeLists.txt @@ -31,7 +31,12 @@ 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 -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) + ######################################################################## # CFO TEST ######################################################################## diff --git a/lte/phy/lib/sync/test/sync_test.c b/lte/phy/lib/sync/test/sync_test.c index b9414a304..e74dba6aa 100644 --- a/lte/phy/lib/sync/test/sync_test.c +++ b/lte/phy/lib/sync/test/sync_test.c @@ -32,18 +32,21 @@ #include #include #include + #include #include "liblte/phy/phy.h" int cell_id = -1, offset = 0; lte_cp_t cp = CPNORM; +uint32_t nof_prb=6; -#define FLEN 9600 +#define FLEN SF_LEN(fft_size, cp) void usage(char *prog) { - printf("Usage: %s [coev]\n", prog); + printf("Usage: %s [cpoev]\n", prog); printf("\t-c cell_id [Default check for all]\n"); + printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-o offset [Default %d]\n", offset); printf("\t-e extended CP [Default normal]\n"); printf("\t-v verbose\n"); @@ -51,11 +54,14 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "coev")) != -1) { + while ((opt = getopt(argc, argv, "cpoev")) != -1) { switch (opt) { case 'c': cell_id = atoi(argv[optind]); break; + case 'p': + nof_prb = atoi(argv[optind]); + break; case 'o': offset = atoi(argv[optind]); break; @@ -82,32 +88,40 @@ int main(int argc, char **argv) { uint32_t find_idx; sync_t sync; lte_fft_t ifft; - + int fft_size; + parse_args(argc, argv); + fft_size = lte_symbol_sz(nof_prb); + if (fft_size < 0) { + fprintf(stderr, "Invalid nof_prb=%d\n", nof_prb); + exit(-1); + } + buffer = malloc(sizeof(cf_t) * FLEN); if (!buffer) { perror("malloc"); exit(-1); } - fft_buffer = malloc(sizeof(cf_t) * 2 * FLEN); + fft_buffer = malloc(sizeof(cf_t) * FLEN); if (!fft_buffer) { perror("malloc"); exit(-1); } - - if (lte_ifft_init(&ifft, cp, 6)) { + + if (lte_ifft_init(&ifft, cp, nof_prb)) { fprintf(stderr, "Error creating iFFT object\n"); exit(-1); } - if (sync_init(&sync, FLEN, 128, 128)) { + if (sync_init(&sync, FLEN, fft_size, fft_size)) { fprintf(stderr, "Error initiating PSS/SSS\n"); return -1; } - sync_set_threshold(&sync, 1, 1); + /* Set a very high threshold to make sure the correlation is ok */ + sync_set_threshold(&sync, 0.99, 0.99); if (cell_id == -1) { cid = 0; @@ -125,19 +139,21 @@ int main(int argc, char **argv) { for (ns=0;ns<2;ns++) { memset(buffer, 0, sizeof(cf_t) * FLEN); - pss_put_slot(pss_signal, buffer, 6, cp); - sss_put_slot(ns?sss_signal5:sss_signal0, buffer, 6, cp); + pss_put_slot(pss_signal, buffer, nof_prb, cp); + sss_put_slot(ns?sss_signal5:sss_signal0, buffer, nof_prb, cp); /* Transform to OFDM symbols */ - memset(fft_buffer, 0, sizeof(cf_t) * 2 * FLEN); + memset(fft_buffer, 0, sizeof(cf_t) * FLEN); lte_ifft_run_slot(&ifft, buffer, &fft_buffer[offset]); + + vec_save_file("input", fft_buffer, sizeof(cf_t) * FLEN); sync_find(&sync, fft_buffer, &find_idx); find_ns = sync_get_slot_id(&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 + 960) { - printf("offset != find_offset: %d != %d\n", find_idx, offset + 960); + if (find_idx != offset + FLEN/2) { + printf("offset != find_offset: %d != %d\n", find_idx, offset + FLEN/2); exit(-1); } if (ns*10 != find_ns) { diff --git a/lte/phy/lib/utils/src/convolution.c b/lte/phy/lib/utils/src/convolution.c index 721595f80..76a26bdee 100644 --- a/lte/phy/lib/utils/src/convolution.c +++ b/lte/phy/lib/utils/src/convolution.c @@ -53,6 +53,9 @@ int conv_fft_cc_init(conv_fft_cc_t *q, uint32_t input_len, uint32_t filter_len) if (dft_plan(&q->output_plan,q->output_len,BACKWARD,COMPLEX)) { return LIBLTE_ERROR; } + dft_plan_set_norm(&q->input_plan, true); + dft_plan_set_norm(&q->filter_plan, true); + dft_plan_set_norm(&q->output_plan, false); return LIBLTE_SUCCESS; } @@ -80,7 +83,7 @@ uint32_t conv_fft_cc_run(conv_fft_cc_t *q, cf_t *input, cf_t *filter, cf_t *outp dft_run_c(&q->output_plan, q->output_fft, output); - return q->output_len; + return q->output_len-1; } diff --git a/lte/phy/lib/utils/src/dft.c b/lte/phy/lib/utils/src/dft.c index 6b4ddad48..babd0220b 100644 --- a/lte/phy/lib/utils/src/dft.c +++ b/lte/phy/lib/utils/src/dft.c @@ -32,6 +32,7 @@ #include #include "liblte/phy/utils/dft.h" +#include "liblte/phy/utils/vector.h" #define dft_ceil(a,b) ((a-1)/b+1) #define dft_floor(a,b) (a/b) @@ -144,11 +145,8 @@ void dft_run_c(dft_plan_t *plan, dft_c_t *in, dft_c_t *out) { plan->forward, plan->mirror, plan->dc); fftwf_execute(plan->p); if (plan->norm) { - /**FIXME: Use VOLK */ - norm = sqrtf(plan->size); - for (i=0;isize;i++) { - f_out[i] /= norm; - } + norm = 1.0/sqrtf(plan->size); + vec_sc_prod_cfc(f_out, norm, f_out, plan->size); } if (plan->db) { for (i=0;isize;i++) { @@ -168,10 +166,8 @@ void dft_run_r(dft_plan_t *plan, dft_r_t *in, dft_r_t *out) { memcpy(plan->in,in,sizeof(dft_r_t)*plan->size); fftwf_execute(plan->p); if (plan->norm) { - norm = plan->size; - for (i=0;isize; + vec_sc_prod_fff(f_out, norm, f_out, plan->size); } if (plan->db) { for (i=0;i Date: Fri, 1 Aug 2014 23:26:28 +0200 Subject: [PATCH 07/11] Added UE cell search object. Improved PSS detection --- cmake/modules/FindVolk.cmake | 4 + cuhd/include/liblte/cuhd/cuhd.h | 2 + cuhd/lib/cuhd_imp.cpp | 9 + lte/phy/examples/cell_search.c | 15 +- lte/phy/examples/iodev.c | 7 +- lte/phy/examples/iodev.h | 2 +- lte/phy/examples/pdsch_enodeb.c | 2 +- lte/phy/examples/pdsch_ue.c | 17 +- .../include/liblte/phy/common/phy_common.h | 15 +- lte/phy/include/liblte/phy/phch/pbch.h | 6 +- lte/phy/include/liblte/phy/phy.h | 7 +- lte/phy/include/liblte/phy/sync/pss.h | 1 - lte/phy/include/liblte/phy/sync/sync.h | 58 +- lte/phy/include/liblte/phy/ue/ue_cellsearch.h | 131 ++++ .../include/liblte/phy/{phch => ue}/ue_dl.h | 0 lte/phy/include/liblte/phy/ue/ue_mib.h | 109 +++ .../include/liblte/phy/{phch => ue}/ue_sync.h | 66 +- lte/phy/include/liblte/phy/utils/vector.h | 1 + lte/phy/lib/ch_estimation/src/chest.c | 8 +- lte/phy/lib/common/src/fft.c | 2 +- lte/phy/lib/common/test/fft_test.c | 2 +- lte/phy/lib/phch/src/pbch.c | 26 +- lte/phy/lib/phch/src/ue_sync.c | 627 ------------------ lte/phy/lib/phch/test/CMakeLists.txt | 17 - lte/phy/lib/phch/test/pbch_file_test.c | 8 +- lte/phy/lib/phch/test/pbch_test.c | 16 +- lte/phy/lib/phch/test/pcfich_file_test.c | 2 +- lte/phy/lib/phch/test/pdcch_file_test.c | 2 +- lte/phy/lib/phch/test/pdsch_file_test.c | 2 +- lte/phy/lib/phch/test/phich_file_test.c | 2 +- lte/phy/lib/sync/src/pss.c | 22 +- lte/phy/lib/sync/src/sync.c | 247 +++---- lte/phy/lib/sync/test/CMakeLists.txt | 25 +- lte/phy/lib/sync/test/pss_usrp.c | 208 ++++++ lte/phy/lib/sync/test/sync_test.c | 15 +- lte/phy/lib/ue/src/ue_cellsearch.c | 268 ++++++++ lte/phy/lib/{phch => ue}/src/ue_dl.c | 2 +- lte/phy/lib/ue/src/ue_mib.c | 225 +++++++ lte/phy/lib/ue/src/ue_sync.c | 377 +++++++++++ lte/phy/lib/ue/test/CMakeLists.txt | 41 ++ lte/phy/lib/ue/test/ue_cell_detect.c | 246 +++++++ lte/phy/lib/{phch => ue}/test/ue_sync_usrp.c | 12 +- lte/phy/lib/utils/src/vector.c | 23 + matlab/sync/find_peaks.m | 13 + matlab/sync/find_pss2.m | 12 +- 45 files changed, 1896 insertions(+), 1006 deletions(-) create mode 100644 lte/phy/include/liblte/phy/ue/ue_cellsearch.h rename lte/phy/include/liblte/phy/{phch => ue}/ue_dl.h (100%) create mode 100644 lte/phy/include/liblte/phy/ue/ue_mib.h rename lte/phy/include/liblte/phy/{phch => ue}/ue_sync.h (62%) delete mode 100644 lte/phy/lib/phch/src/ue_sync.c create mode 100644 lte/phy/lib/sync/test/pss_usrp.c create mode 100644 lte/phy/lib/ue/src/ue_cellsearch.c rename lte/phy/lib/{phch => ue}/src/ue_dl.c (99%) create mode 100644 lte/phy/lib/ue/src/ue_mib.c create mode 100644 lte/phy/lib/ue/src/ue_sync.c create mode 100644 lte/phy/lib/ue/test/CMakeLists.txt create mode 100644 lte/phy/lib/ue/test/ue_cell_detect.c rename lte/phy/lib/{phch => ue}/test/ue_sync_usrp.c (96%) create mode 100644 matlab/sync/find_peaks.m 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 subframe idx (0 or 5) */ +LIBLTE_API uint32_t sync_get_sf_idx(sync_t *q); -/* Gets the slot id (0 or 10) */ -LIBLTE_API uint32_t sync_get_slot_id(sync_t *q); +/* Gets the last peak value */ +LIBLTE_API float sync_get_last_peak_value(sync_t *q); -/* Gets the last peak-to-average ratio */ +/* 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; -} - -uint32_t sync_get_N_id_2(sync_t *q) { - return q->N_id_2; +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_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; + + if (peak_position) { + *peak_position = 0; + } - pss_synch_set_N_id_2(&q->pss_track, q->N_id_2); + pss_synch_set_N_id_2(&q->pss, q->N_id_2); - peak_pos = pss_synch_find_pss(&q->pss_track, &input[offset], &q->peak_value); + 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; + } - DEBUG("PSS possible tracking peak pos=%d peak=%.2f threshold=%.2f\n", - peak_pos, q->peak_value, q->track_threshold); + /* 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 (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 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 From dbc31958306f82eff1477ce12fd3e25bd85a8d34 Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 2 Aug 2014 01:36:34 +0200 Subject: [PATCH 08/11] Improved cell search program --- lte/phy/examples/cell_search.c | 254 +++++++++++++----- lte/phy/include/liblte/phy/phy.h | 2 +- .../ue/{ue_cellsearch.h => ue_celldetect.h} | 28 +- lte/phy/lib/sync/src/sync.c | 90 ++----- .../src/{ue_cellsearch.c => ue_celldetect.c} | 36 +-- lte/phy/lib/ue/test/CMakeLists.txt | 4 +- ...cell_detect.c => ue_celldetect_mib_test.c} | 239 ++++++++-------- 7 files changed, 369 insertions(+), 284 deletions(-) rename lte/phy/include/liblte/phy/ue/{ue_cellsearch.h => ue_celldetect.h} (79%) rename lte/phy/lib/ue/src/{ue_cellsearch.c => ue_celldetect.c} (88%) rename lte/phy/lib/ue/test/{ue_cell_detect.c => ue_celldetect_mib_test.c} (60%) diff --git a/lte/phy/examples/cell_search.c b/lte/phy/examples/cell_search.c index 4b35684c3..501568bd5 100644 --- a/lte/phy/examples/cell_search.c +++ b/lte/phy/examples/cell_search.c @@ -46,32 +46,34 @@ #define FLEN 9600 #define FLEN_PERIOD 0.005 +#define MAX_EARFCN 1000 + int band = -1; int earfcn_start=-1, earfcn_end = -1; -int nof_frames_find=200; +int nof_frames_total = 50; +int nof_frames_detected = 10; +float threshold = -1; float uhd_gain = 60.0; char *uhd_args=""; -#define MAX_EARFCN 1000 -lte_earfcn_t channels[MAX_EARFCN]; - - void usage(char *prog) { - printf("Usage: %s [asefgv] -b band\n", prog); + printf("Usage: %s [agsendtvb] -b band\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-s earfcn_start [Default All]\n"); printf("\t-e earfcn_end [Default All]\n"); - printf("\t-f nof_frames_find [Default %d]\n", nof_frames_find); + 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, "asefgvb")) != -1) { + while ((opt = getopt(argc, argv, "agsendtvb")) != -1) { switch(opt) { case 'a': uhd_args = argv[optind]; @@ -85,8 +87,14 @@ void parse_args(int argc, char **argv) { case 'e': earfcn_end = atoi(argv[optind]); break; - case 'f': - nof_frames_find = atoi(argv[optind]); + case 'n': + nof_frames_total = atoi(argv[optind]); + break; + case 'd': + nof_frames_detected = atoi(argv[optind]); + break; + case 't': + threshold = atof(argv[optind]); break; case 'g': uhd_gain = atof(argv[optind]); @@ -105,97 +113,195 @@ void parse_args(int argc, char **argv) { } } -int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { - DEBUG(" ---- Receive %d samples ---- \n", nsamples); - return cuhd_recv(h, data, nsamples, 1); +int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell) +{ + ue_mib_t uemib; + pbch_mib_t mib; + int n; + + bzero(&mib, sizeof(pbch_mib_t)); + + uint32_t nof_frames = 0; + uint32_t flen = MIB_FRAME_SIZE; + + if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) { + fprintf(stderr, "Error initiating PBCH decoder\n"); + return LIBLTE_ERROR; + } + + INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0); + cuhd_set_rx_srate(uhd, 1920000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + do { + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + + 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"); + return LIBLTE_ERROR; + } + 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"); + return LIBLTE_ERROR; + } + } + nof_frames++; + } while (n != MIB_FOUND && nof_frames < 2*nof_frames_total); + if (n == MIB_FOUND) { + printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames); + pbch_mib_fprint(stdout, &mib, found_cell->cell_id); + } else { + printf("\nCould not decode MIB\n"); + } + + cuhd_stop_rx_stream(uhd); + cuhd_flush_buffer(uhd); + + ue_mib_free(&uemib); + + return LIBLTE_SUCCESS; } +int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t *found_cell) +{ + int n; + + INFO("Setting sampling frequency 960 KHz for PSS search\n", 0); + cuhd_set_rx_srate(uhd, 960000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + uint32_t nof_scanned_cells = 0; + uint32_t flen = 4800; + + do { + + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + + n = ue_celldetect_scan(s, buffer, flen, found_cell); + switch(n) { + case CS_FRAME_UNALIGNED: + printf("Realigning frame\n"); + if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + return LIBLTE_ERROR; + case CS_CELL_DETECTED: + if (found_cell->peak > 0) { + printf("\n\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"); + return LIBLTE_ERROR; + } + } while(nof_scanned_cells < 3 && n != CS_CELL_DETECTED); + + INFO("Stopping receiver...\n", 0); + cuhd_stop_rx_stream(uhd); + cuhd_flush_buffer(uhd); + + return n; +} int main(int argc, char **argv) { - int ret; - int frame_cnt; - int nof_freqs; - uint32_t freq; - ue_sync_t uesync; + int n; void *uhd; + ue_celldetect_t s; + ue_celldetect_result_t found_cell; cf_t *buffer; - lte_cell_t cell; - - if (argc < 3) { - usage(argv[0]); - exit(-1); - } - - parse_args(argc,argv); - + int nof_freqs; + lte_earfcn_t channels[MAX_EARFCN]; + uint32_t freq; + + parse_args(argc, argv); + printf("Opening UHD device...\n"); if (cuhd_open(uhd_args, &uhd)) { fprintf(stderr, "Error opening uhd\n"); exit(-1); - } - - /* set uhd_gain */ + } cuhd_set_rx_gain(uhd, uhd_gain); - + nof_freqs = lte_band_get_fd_band(band, channels, earfcn_start, earfcn_end, MAX_EARFCN); if (nof_freqs < 0) { fprintf(stderr, "Error getting EARFCN list\n"); exit(-1); } + + buffer = vec_malloc(sizeof(cf_t) * 96000); + if (!buffer) { + perror("malloc"); + return LIBLTE_ERROR; + } + if (ue_celldetect_init(&s)) { + fprintf(stderr, "Error initiating UE sync module\n"); + exit(-1); + } + if (threshold > 0) { + ue_celldetect_set_threshold(&s, threshold); + } + + if (nof_frames_total > 0) { + ue_celldetect_set_nof_frames_total(&s, nof_frames_total); + } + if (nof_frames_detected > 0) { + ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected); + } - for (freq=0;freqcp; } +static lte_cp_t detect_cp(cf_t *input, uint32_t peak_pos) +{ + return CPNORM; +} + 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 sf_idx_e, N_id_1_e, sf_idx_n, N_id_1_n; + int sss_idx, ret; + float m0_value, m1_value; sss_synch_set_N_id_2(&q->sss, q->N_id_2); - - /* Make sure we have enough room to find SSS sequence */ - 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 (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; - } - } else { - if (CP_ISNORM(q->cp)) { - if (sss_idx_n < 0) { - INFO("Not enough room to decode normal CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_n, peak_pos); - return LIBLTE_SUCCESS; - } - } else { - if (sss_idx_e < 0) { - INFO("Not enough room to decode extended CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx_e, peak_pos); - return LIBLTE_SUCCESS; - } - } + q->cp = detect_cp(input, peak_pos); } - - sf_idx_n = 0; - sf_idx_e = 0; - N_id_1_n = 0; - N_id_1_e = 0; - /* try Normal CP length */ - 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); + /* Make sure we have enough room to find SSS sequence */ + sss_idx = (int) peak_pos - 2*(q->fft_size + CP(q->fft_size, q->cp)); - 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; - } else { - N_id_1_n = 1000; - } + if (sss_idx < 0) { + INFO("Not enough room to decode CP SSS (sss_idx=%d, peak_pos=%d)\n", sss_idx, peak_pos); + return LIBLTE_SUCCESS; } + + /* try Normal CP length */ + sss_synch_m0m1(&q->sss, &input[sss_idx], &m0, &m0_value, &m1, &m1_value); - 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); - - 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; - } else { - N_id_1_e = 1000; - } - } - - /* Correlation with extended CP hypoteshis is greater than with normal? */ - if ((q->detect_cp && m0_value_e * m1_value_e > m0_value_n * m1_value_n) - || CP_ISEXT(q->cp)) { - q->cp = CPEXT; - q->sf_idx = sf_idx_e; - q->N_id_1 = N_id_1_e; - /* otherwise is normal CP */ + q->sf_idx = sss_synch_subframe(m0, m1); + ret = sss_synch_N_id_1(&q->sss, m0, m1); + if (ret >= 0) { + q->N_id_1 = (uint32_t) ret; } else { - q->cp = CPNORM; - q->sf_idx = sf_idx_n; - q->N_id_1 = N_id_1_n; + q->N_id_1 = 1000; } - - 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"); + + DEBUG("SSS detected N_id_1=%d, sf_idx=%d, %s CP\n", + q->N_id_1, q->sf_idx, CP_ISNORM(q->cp)?"Normal":"Extended"); return 1; } @@ -276,7 +236,7 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit } } } else { - printf("Warning: no space for CFO computation\n"); + INFO("Warning: no space for CFO computation\n",0); } if (peak_position) { diff --git a/lte/phy/lib/ue/src/ue_cellsearch.c b/lte/phy/lib/ue/src/ue_celldetect.c similarity index 88% rename from lte/phy/lib/ue/src/ue_cellsearch.c rename to lte/phy/lib/ue/src/ue_celldetect.c index 8bb6701d1..27cd1b5f8 100644 --- a/lte/phy/lib/ue/src/ue_cellsearch.c +++ b/lte/phy/lib/ue/src/ue_celldetect.c @@ -31,7 +31,7 @@ #include #include -#include "liblte/phy/ue/ue_cellsearch.h" +#include "liblte/phy/ue/ue_celldetect.h" #include "liblte/phy/utils/debug.h" #include "liblte/phy/utils/vector.h" @@ -39,19 +39,19 @@ #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_celldetect_init(ue_celldetect_t * q) { + return ue_celldetect_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 ue_celldetect_init_max(ue_celldetect_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)); + bzero(q, sizeof(ue_celldetect_t)); - q->candidates = malloc(sizeof(ue_cellsearch_result_t) * max_frames_detected); + q->candidates = malloc(sizeof(ue_celldetect_result_t) * max_frames_detected); if (!q->candidates) { perror("malloc"); goto clean_exit; @@ -78,19 +78,19 @@ int ue_cellsearch_init_max(ue_cellsearch_t * q, uint32_t max_frames_total, uint3 q->nof_frames_total = CS_DEFAULT_NOFFRAMES_TOTAL; q->nof_frames_detected = CS_DEFAULT_NOFFRAMES_DETECTED; - ue_cellsearch_reset(q); + ue_celldetect_reset(q); ret = LIBLTE_SUCCESS; } clean_exit: if (ret == LIBLTE_ERROR) { - ue_cellsearch_free(q); + ue_celldetect_free(q); } return ret; } -void ue_cellsearch_free(ue_cellsearch_t * q) +void ue_celldetect_free(ue_celldetect_t * q) { if (q->candidates) { free(q->candidates); @@ -105,21 +105,21 @@ void ue_cellsearch_free(ue_cellsearch_t * q) } -void ue_cellsearch_reset(ue_cellsearch_t * q) +void ue_celldetect_reset(ue_celldetect_t * q) { q->current_nof_detected = 0; q->current_nof_total = 0; q->current_N_id_2 = 0; } -void ue_cellsearch_set_threshold(ue_cellsearch_t * q, float threshold) +void ue_celldetect_set_threshold(ue_celldetect_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) +int ue_celldetect_set_nof_frames_total(ue_celldetect_t * q, uint32_t nof_frames) { - if (nof_frames > q->max_frames_total) { + if (nof_frames <= q->max_frames_total) { q->nof_frames_total = nof_frames; return LIBLTE_SUCCESS; } else { @@ -127,9 +127,9 @@ int ue_cellsearch_set_nof_frames_total(ue_cellsearch_t * q, uint32_t nof_frames) } } -int ue_cellsearch_set_nof_frames_detected(ue_cellsearch_t * q, uint32_t nof_frames) +int ue_celldetect_set_nof_frames_detected(ue_celldetect_t * q, uint32_t nof_frames) { - if (nof_frames > q->max_frames_detected) { + if (nof_frames <= q->max_frames_detected) { q->nof_frames_detected = nof_frames; return LIBLTE_SUCCESS; } else { @@ -138,7 +138,7 @@ int ue_cellsearch_set_nof_frames_detected(ue_cellsearch_t * q, uint32_t nof_fram } /* Decide the most likely cell based on the mode */ -void decide_cell(ue_cellsearch_t * q, ue_cellsearch_result_t *found_cell) +void decide_cell(ue_celldetect_t * q, ue_celldetect_result_t *found_cell) { uint32_t i, j; @@ -186,10 +186,10 @@ void decide_cell(ue_cellsearch_t * q, ue_cellsearch_result_t *found_cell) found_cell->mode = q->mode_ntimes[mode_pos]; } -int ue_cellsearch_scan(ue_cellsearch_t * q, +int ue_celldetect_scan(ue_celldetect_t * q, cf_t *signal, uint32_t nsamples, - ue_cellsearch_result_t *found_cell) + ue_celldetect_result_t *found_cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; uint32_t peak_idx; diff --git a/lte/phy/lib/ue/test/CMakeLists.txt b/lte/phy/lib/ue/test/CMakeLists.txt index e44f12b70..dc376a5de 100644 --- a/lte/phy/lib/ue/test/CMakeLists.txt +++ b/lte/phy/lib/ue/test/CMakeLists.txt @@ -29,8 +29,8 @@ 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) + ADD_EXECUTABLE(ue_celldetect_mib_test ue_celldetect_mib_test.c) + TARGET_LINK_LIBRARIES(ue_celldetect_mib_test lte_phy cuhd) ENDIF(${CUHD_FIND} GREATER -1) IF(${GRAPHICS_FIND} EQUAL -1) diff --git a/lte/phy/lib/ue/test/ue_cell_detect.c b/lte/phy/lib/ue/test/ue_celldetect_mib_test.c similarity index 60% rename from lte/phy/lib/ue/test/ue_cell_detect.c rename to lte/phy/lib/ue/test/ue_celldetect_mib_test.c index 6ef13f707..c3921aba4 100644 --- a/lte/phy/lib/ue/test/ue_cell_detect.c +++ b/lte/phy/lib/ue/test/ue_celldetect_mib_test.c @@ -40,7 +40,6 @@ #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; @@ -95,83 +94,96 @@ void parse_args(int argc, char **argv) { } } -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; +int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell) +{ 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); + uint32_t nof_frames = 0; + uint32_t flen = MIB_FRAME_SIZE; + + if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) { + fprintf(stderr, "Error initiating PBCH decoder\n"); + return LIBLTE_ERROR; + } + + INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0); + cuhd_set_rx_srate(uhd, 1920000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + do { + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } - input_init(); + INFO("Calling ue_mib_decode() %d/%d\n", nof_frames, nof_frames_total); - // 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); + n = ue_mib_decode(&uemib, buffer, flen, &mib); + if (n == LIBLTE_ERROR || n == LIBLTE_ERROR_INVALID_INPUTS) { + fprintf(stderr, "Error calling ue_mib_decode()\n"); + return LIBLTE_ERROR; + } + 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"); + return LIBLTE_ERROR; + } + } + 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"); } + + cuhd_stop_rx_stream(uhd); + cuhd_flush_buffer(uhd); + + ue_mib_free(&uemib); - 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); - } + return LIBLTE_SUCCESS; +} + +int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t *found_cell) +{ + int n; + + INFO("Setting sampling frequency 960 KHz for PSS search\n", 0); + cuhd_set_rx_srate(uhd, 960000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); uint32_t nof_scanned_cells = 0; - flen = 4800; - + uint32_t flen = 4800; + do { if (cuhd_recv(uhd, buffer, flen, 1)<0) { fprintf(stderr, "Error receiving from USRP\n"); - exit(-1); + return LIBLTE_ERROR; } - n = ue_cellsearch_scan(&s, buffer, flen, &found_cell); + n = ue_celldetect_scan(s, buffer, flen, found_cell); switch(n) { case CS_FRAME_UNALIGNED: - fprintf(stderr, "Unaliged frame!! Exiting\n"); - exit(-1); + printf("Realigning frame\n"); + if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + return LIBLTE_ERROR; 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); - + if (found_cell->peak > 0) { + 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: @@ -180,65 +192,72 @@ int main(int argc, char **argv) { case LIBLTE_ERROR: case LIBLTE_ERROR_INVALID_INPUTS: fprintf(stderr, "Error calling cellsearch_scan()\n"); - exit(-1); + return LIBLTE_ERROR; } } while(nof_scanned_cells < 3 && n != CS_CELL_DETECTED); + + INFO("Stopping receiver...\n", 0); + cuhd_stop_rx_stream(uhd); + cuhd_flush_buffer(uhd); - 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); - } + return n; +} - 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; +int main(int argc, char **argv) { + int n; + void *uhd; + ue_celldetect_t s; + ue_celldetect_result_t found_cell; + cf_t *buffer; + + parse_args(argc, argv); - 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"); - } - } + 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); + buffer = vec_malloc(sizeof(cf_t) * 96000); + if (!buffer) { + perror("malloc"); + return LIBLTE_ERROR; + } - ue_mib_free(&uemib); - ue_cellsearch_free(&s); + if (ue_celldetect_init(&s)) { + fprintf(stderr, "Error initiating UE sync module\n"); + exit(-1); + } + if (threshold > 0) { + ue_celldetect_set_threshold(&s, threshold); + } + + if (nof_frames_total > 0) { + ue_celldetect_set_nof_frames_total(&s, nof_frames_total); + } + if (nof_frames_detected > 0) { + ue_celldetect_set_nof_frames_detected(&s, nof_frames_detected); + } + + n = find_cell(uhd, &s, buffer, &found_cell); + if (n < 0) { + fprintf(stderr, "Error searching cell\n"); + exit(-1); + } + if (n == CS_CELL_DETECTED) { + if (decode_pbch(uhd, buffer, &found_cell)) { + fprintf(stderr, "Error decoding PBCH\n"); + exit(-1); + } + } + + ue_celldetect_free(&s); cuhd_close(uhd); exit(0); } From 3844d19916310fbc3b8d91cbc43eb75aaf673689 Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 2 Aug 2014 02:38:47 +0200 Subject: [PATCH 09/11] Changed CP detection algorithm --- .../include/liblte/phy/common/phy_common.h | 12 +++--- lte/phy/lib/sync/src/sync.c | 41 +++++++++++++++++-- lte/phy/lib/ue/src/ue_celldetect.c | 2 +- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/lte/phy/include/liblte/phy/common/phy_common.h b/lte/phy/include/liblte/phy/common/phy_common.h index 7304ddb77..4f7efc742 100644 --- a/lte/phy/include/liblte/phy/common/phy_common.h +++ b/lte/phy/include/liblte/phy/common/phy_common.h @@ -65,12 +65,12 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define SYMBOL_SZ_MAX 2048 #define CPNORM_NSYMB 7 -#define CPNORM_SF_NSYMB 2*CPNORM_NSYMB +#define CPNORM_SF_NSYMB (2*CPNORM_NSYMB) #define CPNORM_0_LEN 160 #define CPNORM_LEN 144 #define CPEXT_NSYMB 6 -#define CPEXT_SF_NSYMB 2*CPEXT_NSYMB +#define CPEXT_SF_NSYMB (2*CPEXT_NSYMB) #define CPEXT_LEN 512 #define CPEXT_7_5_LEN 1024 @@ -78,13 +78,13 @@ typedef enum {CPNORM, CPEXT} lte_cp_t; #define CP_ISEXT(cp) (cp==CPEXT) #define CP_NSYMB(cp) (CP_ISNORM(cp)?CPNORM_NSYMB:CPEXT_NSYMB) -#define CP(symbol_sz, c) (c*symbol_sz/2048) -#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 CP(symbol_sz, c) ((c*symbol_sz)/2048) +#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(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_MAX (SF_LEN(SYMBOL_SZ_MAX)) #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)) diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index c79fd1bfc..ba9b1194b 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -143,9 +143,41 @@ lte_cp_t sync_get_cp(sync_t *q) { return q->cp; } -static lte_cp_t detect_cp(cf_t *input, uint32_t peak_pos) +/* CP detection algorithm taken from: + * "SSS Detection Method for Initial Cell Search in 3GPP LTE FDD/TDD Dual Mode Receiver" + * by Jung-In Kim et al. + */ +static lte_cp_t detect_cp(sync_t *q, cf_t *input, uint32_t peak_pos) { - return CPNORM; + float R_norm, R_ext, C_norm, C_ext; + float M_norm, M_ext; + + R_norm = crealf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_NORM(7, q->fft_size)], + &input[peak_pos-CP_NORM(7, q->fft_size)], + CP_NORM(7, q->fft_size))); + C_norm = cabsf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_NORM(7, q->fft_size)], + &input[peak_pos-q->fft_size-CP_NORM(7, q->fft_size)], + CP_NORM(7, q->fft_size))); + R_ext = crealf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_EXT(q->fft_size)], + &input[peak_pos-CP_EXT(q->fft_size)], + CP_EXT(q->fft_size))); + C_ext = cabsf(vec_dot_prod_conj_ccc(&input[peak_pos-q->fft_size-CP_EXT(q->fft_size)], + &input[peak_pos-q->fft_size-CP_EXT(q->fft_size)], + CP_EXT(q->fft_size))); + M_norm = R_norm/C_norm; + M_ext = R_ext/C_ext; + + if (M_norm > M_ext) { + return CPNORM; + } else if (M_norm < M_ext) { + return CPEXT; + } else { + if (R_norm > R_ext) { + return CPNORM; + } else { + return CPEXT; + } + } } int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { @@ -156,7 +188,7 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { sss_synch_set_N_id_2(&q->sss, q->N_id_2); if (q->detect_cp) { - q->cp = detect_cp(input, peak_pos); + q->cp = detect_cp(q, input, peak_pos); } /* Make sure we have enough room to find SSS sequence */ @@ -184,7 +216,8 @@ int sync_sss(sync_t *q, cf_t *input, uint32_t peak_pos) { return 1; } -int sync_find(sync_t *q, cf_t *input, uint32_t find_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; diff --git a/lte/phy/lib/ue/src/ue_celldetect.c b/lte/phy/lib/ue/src/ue_celldetect.c index 27cd1b5f8..fbb61c2cc 100644 --- a/lte/phy/lib/ue/src/ue_celldetect.c +++ b/lte/phy/lib/ue/src/ue_celldetect.c @@ -211,7 +211,7 @@ int ue_celldetect_scan(ue_celldetect_t * q, for (uint32_t nf=0;nfsfind, q->current_N_id_2); - DEBUG("[%3d/%3d]: Searching cells with N_id_2=%d. %d frames\n", + printf("[%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 */ From 182c9958bbf21dc2824157d4f2ec016f4f06296e Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 2 Aug 2014 03:05:54 +0200 Subject: [PATCH 10/11] Cell search example looks for 3 cells per frequency --- lte/phy/examples/cell_search.c | 30 ++++++++++++++++++------------ lte/phy/lib/sync/src/sync.c | 4 ++-- lte/phy/lib/ue/src/ue_celldetect.c | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/lte/phy/examples/cell_search.c b/lte/phy/examples/cell_search.c index 501568bd5..7d1feeaa2 100644 --- a/lte/phy/examples/cell_search.c +++ b/lte/phy/examples/cell_search.c @@ -53,7 +53,7 @@ int band = -1; int earfcn_start=-1, earfcn_end = -1; int nof_frames_total = 50; int nof_frames_detected = 10; -float threshold = -1; +float threshold = CS_FIND_THRESHOLD; float uhd_gain = 60.0; @@ -171,7 +171,7 @@ int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell) return LIBLTE_SUCCESS; } -int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t *found_cell) +int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3]) { int n; @@ -190,7 +190,7 @@ int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_ return LIBLTE_ERROR; } - n = ue_celldetect_scan(s, buffer, flen, found_cell); + n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]); switch(n) { case CS_FRAME_UNALIGNED: printf("Realigning frame\n"); @@ -200,10 +200,12 @@ int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_ } return LIBLTE_ERROR; case CS_CELL_DETECTED: - if (found_cell->peak > 0) { + if (found_cell[nof_scanned_cells].peak > 0) { printf("\n\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); + found_cell[nof_scanned_cells].cell_id, + lte_cp_string(found_cell[nof_scanned_cells].cp), + found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode, + s->nof_frames_detected); } nof_scanned_cells++; @@ -216,7 +218,7 @@ int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_ fprintf(stderr, "Error calling cellsearch_scan()\n"); return LIBLTE_ERROR; } - } while(nof_scanned_cells < 3 && n != CS_CELL_DETECTED); + } while(nof_scanned_cells < 3); INFO("Stopping receiver...\n", 0); cuhd_stop_rx_stream(uhd); @@ -229,7 +231,7 @@ int main(int argc, char **argv) { int n; void *uhd; ue_celldetect_t s; - ue_celldetect_result_t found_cell; + ue_celldetect_result_t found_cells[3]; cf_t *buffer; int nof_freqs; lte_earfcn_t channels[MAX_EARFCN]; @@ -286,15 +288,19 @@ int main(int argc, char **argv) { printf("\n"); } - n = find_cell(uhd, &s, buffer, &found_cell); + n = find_cell(uhd, &s, buffer, found_cells); if (n < 0) { fprintf(stderr, "Error searching cell\n"); exit(-1); } if (n == CS_CELL_DETECTED) { - if (decode_pbch(uhd, buffer, &found_cell)) { - fprintf(stderr, "Error decoding PBCH\n"); - exit(-1); + for (int i=0;i<3;i++) { + if (found_cells[i].peak > threshold/2) { + if (decode_pbch(uhd, buffer, &found_cells[i])) { + fprintf(stderr, "Error decoding PBCH\n"); + exit(-1); + } + } } } } diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index ba9b1194b..9d06a8616 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -280,8 +280,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit 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); + INFO("SYNC ret=%d N_id_2=%d pos=%d peak=%.2f energy=%.3f threshold=%.2f sf_idx=%d\n", + ret, q->N_id_2, peak_pos, q->peak_value, energy, q->threshold, q->sf_idx); } else if (lte_N_id_2_isvalid(q->N_id_2)) { fprintf(stderr, "Must call sync_set_N_id_2() first!\n"); diff --git a/lte/phy/lib/ue/src/ue_celldetect.c b/lte/phy/lib/ue/src/ue_celldetect.c index fbb61c2cc..27cd1b5f8 100644 --- a/lte/phy/lib/ue/src/ue_celldetect.c +++ b/lte/phy/lib/ue/src/ue_celldetect.c @@ -211,7 +211,7 @@ int ue_celldetect_scan(ue_celldetect_t * q, for (uint32_t nf=0;nfsfind, q->current_N_id_2); - printf("[%3d/%3d]: Searching cells with N_id_2=%d. %d frames\n", + 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 */ From ce2abc06fedf43d1a428c788bcbb1efb3a1da2dd Mon Sep 17 00:00:00 2001 From: ismagom Date: Sat, 2 Aug 2014 23:55:12 +0200 Subject: [PATCH 11/11] Fixed some bugs in UE PDSCH example: equalization with zero channel estimates, cell search, synchronization. CRC-based early stopping --- lte/phy/examples/CMakeLists.txt | 4 +- lte/phy/examples/cell_search.c | 120 +------------------- lte/phy/examples/cell_search_utils.c | 157 ++++++++++++++++++++++++++ lte/phy/examples/cell_search_utils.h | 40 +++++++ lte/phy/examples/iodev.c | 108 ++++++++++++++++-- lte/phy/examples/iodev.h | 10 +- lte/phy/examples/pdsch_ue.c | 155 +++++++++---------------- lte/phy/include/liblte/phy/ue/ue_dl.h | 9 +- lte/phy/lib/ch_estimation/src/chest.c | 16 ++- lte/phy/lib/fec/src/turbodecoder.c | 58 ++++++---- lte/phy/lib/mimo/src/precoding.c | 8 ++ lte/phy/lib/phch/src/pdsch.c | 28 +++-- lte/phy/lib/sync/src/sync.c | 9 +- lte/phy/lib/ue/src/ue_dl.c | 71 +++++++++--- lte/phy/lib/ue/src/ue_sync.c | 90 ++++++--------- lte/phy/lib/ue/test/ue_sync_usrp.c | 61 +++++----- 16 files changed, 575 insertions(+), 369 deletions(-) create mode 100644 lte/phy/examples/cell_search_utils.c create mode 100644 lte/phy/examples/cell_search_utils.h diff --git a/lte/phy/examples/CMakeLists.txt b/lte/phy/examples/CMakeLists.txt index f798a23ac..a5fe5d474 100644 --- a/lte/phy/examples/CMakeLists.txt +++ b/lte/phy/examples/CMakeLists.txt @@ -51,7 +51,7 @@ LIST(FIND OPTIONAL_LIBS graphics GRAPHICS_FIND) # These two can be compiled without UHD or graphics support ################################################################# -add_executable(pdsch_ue pdsch_ue.c iodev.c) +add_executable(pdsch_ue pdsch_ue.c iodev.c cell_search_utils.c) target_link_libraries(pdsch_ue lte_phy) add_executable(pdsch_enodeb pdsch_enodeb.c) @@ -81,7 +81,7 @@ ENDIF(${GRAPHICS_FIND} EQUAL -1) IF(${CUHD_FIND} GREATER -1) - add_executable(cell_search cell_search.c) + add_executable(cell_search cell_search.c cell_search_utils.c) target_link_libraries(cell_search lte_phy cuhd ) MESSAGE(STATUS " UHD examples will be installed.") diff --git a/lte/phy/examples/cell_search.c b/lte/phy/examples/cell_search.c index 7d1feeaa2..5f3306bd8 100644 --- a/lte/phy/examples/cell_search.c +++ b/lte/phy/examples/cell_search.c @@ -37,6 +37,9 @@ #include "liblte/phy/phy.h" +#include "cell_search_utils.h" + + #ifndef DISABLE_UHD #include "liblte/cuhd/cuhd.h" #endif @@ -113,120 +116,6 @@ void parse_args(int argc, char **argv) { } } -int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell) -{ - ue_mib_t uemib; - pbch_mib_t mib; - int n; - - bzero(&mib, sizeof(pbch_mib_t)); - - uint32_t nof_frames = 0; - uint32_t flen = MIB_FRAME_SIZE; - - if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) { - fprintf(stderr, "Error initiating PBCH decoder\n"); - return LIBLTE_ERROR; - } - - INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0); - cuhd_set_rx_srate(uhd, 1920000.0); - INFO("Starting receiver...\n", 0); - cuhd_start_rx_stream(uhd); - - do { - if (cuhd_recv(uhd, buffer, flen, 1)<0) { - fprintf(stderr, "Error receiving from USRP\n"); - return LIBLTE_ERROR; - } - - 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"); - return LIBLTE_ERROR; - } - 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"); - return LIBLTE_ERROR; - } - } - nof_frames++; - } while (n != MIB_FOUND && nof_frames < 2*nof_frames_total); - if (n == MIB_FOUND) { - printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames); - pbch_mib_fprint(stdout, &mib, found_cell->cell_id); - } else { - printf("\nCould not decode MIB\n"); - } - - cuhd_stop_rx_stream(uhd); - cuhd_flush_buffer(uhd); - - ue_mib_free(&uemib); - - return LIBLTE_SUCCESS; -} - -int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3]) -{ - int n; - - INFO("Setting sampling frequency 960 KHz for PSS search\n", 0); - cuhd_set_rx_srate(uhd, 960000.0); - INFO("Starting receiver...\n", 0); - cuhd_start_rx_stream(uhd); - - uint32_t nof_scanned_cells = 0; - uint32_t flen = 4800; - - do { - - if (cuhd_recv(uhd, buffer, flen, 1)<0) { - fprintf(stderr, "Error receiving from USRP\n"); - return LIBLTE_ERROR; - } - - n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]); - switch(n) { - case CS_FRAME_UNALIGNED: - printf("Realigning frame\n"); - if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { - fprintf(stderr, "Error receiving from USRP\n"); - return LIBLTE_ERROR; - } - return LIBLTE_ERROR; - case CS_CELL_DETECTED: - if (found_cell[nof_scanned_cells].peak > 0) { - printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n", - found_cell[nof_scanned_cells].cell_id, - lte_cp_string(found_cell[nof_scanned_cells].cp), - found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode, - s->nof_frames_detected); - } - - 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"); - return LIBLTE_ERROR; - } - } while(nof_scanned_cells < 3); - - INFO("Stopping receiver...\n", 0); - cuhd_stop_rx_stream(uhd); - cuhd_flush_buffer(uhd); - - return n; -} - int main(int argc, char **argv) { int n; void *uhd; @@ -236,6 +125,7 @@ int main(int argc, char **argv) { int nof_freqs; lte_earfcn_t channels[MAX_EARFCN]; uint32_t freq; + pbch_mib_t mib; parse_args(argc, argv); @@ -296,7 +186,7 @@ int main(int argc, char **argv) { if (n == CS_CELL_DETECTED) { for (int i=0;i<3;i++) { if (found_cells[i].peak > threshold/2) { - if (decode_pbch(uhd, buffer, &found_cells[i])) { + if (decode_pbch(uhd, buffer, &found_cells[i], nof_frames_total, &mib)) { fprintf(stderr, "Error decoding PBCH\n"); exit(-1); } diff --git a/lte/phy/examples/cell_search_utils.c b/lte/phy/examples/cell_search_utils.c new file mode 100644 index 000000000..a5bb30adc --- /dev/null +++ b/lte/phy/examples/cell_search_utils.c @@ -0,0 +1,157 @@ +/** + * + * \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" + +#ifndef DISABLE_UHD +#include "liblte/cuhd/cuhd.h" + +int decode_pbch(void *uhd, cf_t *buffer, ue_celldetect_result_t *found_cell, uint32_t nof_frames_total, pbch_mib_t *mib) +{ + ue_mib_t uemib; + int n; + + bzero(mib, sizeof(pbch_mib_t)); + + uint32_t nof_frames = 0; + uint32_t flen = MIB_FRAME_SIZE; + + if (ue_mib_init(&uemib, found_cell->cell_id, found_cell->cp)) { + fprintf(stderr, "Error initiating PBCH decoder\n"); + return LIBLTE_ERROR; + } + + INFO("Setting sampling frequency 1.92 MHz for PBCH decoding\n", 0); + cuhd_set_rx_srate(uhd, 1920000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + do { + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + + 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"); + return LIBLTE_ERROR; + } + 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"); + return LIBLTE_ERROR; + } + } + nof_frames++; + } while (n != MIB_FOUND && nof_frames < 2*nof_frames_total); + if (n == MIB_FOUND) { + printf("\n\nMIB decoded in %d ms (%d half frames)\n", nof_frames*5, nof_frames); + pbch_mib_fprint(stdout, mib, found_cell->cell_id); + } else { + printf("\nCould not decode MIB\n"); + } + + cuhd_stop_rx_stream(uhd); + cuhd_flush_buffer(uhd); + + ue_mib_free(&uemib); + + return LIBLTE_SUCCESS; +} + +int find_cell(void *uhd, ue_celldetect_t *s, cf_t *buffer, ue_celldetect_result_t found_cell[3]) +{ + int n; + + INFO("Setting sampling frequency 960 KHz for PSS search\n", 0); + cuhd_set_rx_srate(uhd, 960000.0); + INFO("Starting receiver...\n", 0); + cuhd_start_rx_stream(uhd); + + uint32_t nof_scanned_cells = 0; + uint32_t flen = 4800; + int nof_detected_cells = 0; + + do { + + if (cuhd_recv(uhd, buffer, flen, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + + n = ue_celldetect_scan(s, buffer, flen, &found_cell[nof_scanned_cells]); + switch(n) { + case CS_FRAME_UNALIGNED: + printf("Realigning frame\n"); + if (cuhd_recv(uhd, buffer, flen/2, 1)<0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + return LIBLTE_ERROR; + case CS_CELL_DETECTED: + nof_detected_cells++; + if (found_cell[nof_scanned_cells].peak > 0) { + printf("\n\tCELL ID: %d, CP: %s, Peak: %.2f, Mode: %d/%d\n", + found_cell[nof_scanned_cells].cell_id, + lte_cp_string(found_cell[nof_scanned_cells].cp), + found_cell[nof_scanned_cells].peak, found_cell[nof_scanned_cells].mode, + s->nof_frames_detected); + } + + 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"); + return LIBLTE_ERROR; + } + } while(nof_scanned_cells < 3); + + INFO("Stopping receiver...\n", 0); + cuhd_stop_rx_stream(uhd); + cuhd_flush_buffer(uhd); + + return nof_detected_cells; +} +#endif diff --git a/lte/phy/examples/cell_search_utils.h b/lte/phy/examples/cell_search_utils.h new file mode 100644 index 000000000..2fefed105 --- /dev/null +++ b/lte/phy/examples/cell_search_utils.h @@ -0,0 +1,40 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + + +#include "liblte/phy/phy.h" + +int decode_pbch(void *uhd, + cf_t *buffer, + ue_celldetect_result_t *found_cell, + uint32_t nof_frames_total, + pbch_mib_t *mib); + +int find_cell(void *uhd, + ue_celldetect_t *s, + cf_t *buffer, + ue_celldetect_result_t found_cell[3]); \ No newline at end of file diff --git a/lte/phy/examples/iodev.c b/lte/phy/examples/iodev.c index 76b94997f..ce55b3a3a 100644 --- a/lte/phy/examples/iodev.c +++ b/lte/phy/examples/iodev.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "iodev.h" @@ -41,6 +42,8 @@ #include "liblte/cuhd/cuhd.h" #endif +#include "cell_search_utils.h" + int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { DEBUG(" ---- Receive %d samples ---- \n", nsamples); @@ -48,20 +51,36 @@ int cuhd_recv_wrapper(void *h, void *data, uint32_t nsamples) { } /* Setup USRP or input file */ -int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) { +int iodev_init(iodev_t *q, iodev_cfg_t *config, lte_cell_t *cell, pbch_mib_t *mib) { if (config->input_file_name) { + + mib->phich_resources = R_1; + mib->phich_length = PHICH_NORM; + + cell->id = config->cell_id_file; + cell->cp = CPNORM; + cell->nof_ports = config->nof_ports_file; + cell->nof_prb = config->nof_prb_file; + if (filesource_init(&q->fsrc, config->input_file_name, COMPLEX_FLOAT_BIN)) { return LIBLTE_ERROR; } - q->input_buffer_file = vec_malloc(SF_LEN_MAX * sizeof(cf_t)); + q->mode = FILESOURCE; + int symbol_sz = lte_symbol_sz(cell->nof_prb); + if (symbol_sz > 0) { + q->sf_len = SF_LEN(symbol_sz); + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb); + return LIBLTE_ERROR; + } + + q->input_buffer_file = vec_malloc(q->sf_len * sizeof(cf_t)); if (!q->input_buffer_file) { perror("malloc"); return LIBLTE_ERROR; } - - q->mode = FILESOURCE; - q->sf_len = file_sf_len; + q->sf_idx = 9; } else { #ifndef DISABLE_UHD @@ -71,18 +90,76 @@ int iodev_init(iodev_t *q, iodev_cfg_t *config, uint32_t file_sf_len) { return LIBLTE_ERROR; } - /* set uhd_freq */ cuhd_set_rx_gain(q->uhd, config->uhd_gain); + + /* set receiver frequency */ cuhd_set_rx_freq(q->uhd, (double) config->uhd_freq); cuhd_rx_wait_lo_locked(q->uhd); DEBUG("Set uhd_freq to %.3f MHz\n", (double ) config->uhd_freq); + int n; + ue_celldetect_t cd; + ue_celldetect_result_t found_cells[3]; + + cf_t *buffer = vec_malloc(sizeof(cf_t) * 96000); + if (!buffer) { + perror("malloc"); + return LIBLTE_ERROR; + } + if (ue_celldetect_init(&cd)) { + fprintf(stderr, "Error initiating UE cell detect\n"); + exit(-1); + } + n = find_cell(q->uhd, &cd, buffer, found_cells); + if (n < 0) { + fprintf(stderr, "Error searching cell\n"); + exit(-1); + } + + int max_peak_cell = 0; + float max_peak_value = -1.0; + if (n > 0) { + for (int i=0;i<3;i++) { + if (found_cells[i].peak > max_peak_value) { + max_peak_value = found_cells[i].peak; + max_peak_cell = i; + } + } + if (decode_pbch(q->uhd, buffer, &found_cells[max_peak_cell], 400, mib)) { + fprintf(stderr, "Could not decode PBCH from CELL ID %d\n", found_cells[max_peak_cell].cell_id); + return LIBLTE_ERROR; + } + } else { + fprintf(stderr, "Could not find any cell in this frequency\n"); + return LIBLTE_ERROR; + } + + free(buffer); + cell->cp = found_cells[max_peak_cell].cp; + cell->id = found_cells[max_peak_cell].cell_id; + cell->nof_prb = mib->nof_prb; + cell->nof_ports = mib->nof_ports; + + /* set sampling frequency */ + int srate = lte_sampling_freq_hz(cell->nof_prb); + if (srate != -1) { + cuhd_set_rx_srate(q->uhd, (double) srate); + } else { + fprintf(stderr, "Invalid number of PRB %d\n", cell->nof_prb); + return LIBLTE_ERROR; + } + DEBUG("Starting receiver...\n", 0); cuhd_start_rx_stream(q->uhd); - lte_cell_t cell; - ue_sync_init(&q->sframe, cell, cuhd_recv_wrapper, q->uhd); + if (ue_sync_init(&q->sframe, *cell, cuhd_recv_wrapper, q->uhd)) { + fprintf(stderr, "Error initiating ue_sync\n"); + return LIBLTE_ERROR; + } + + /* Decodes the SSS signal during the tracking phase. Extra overhead, but makes sure we are in the correct subframe */ + ue_sync_decode_sss_on_track(&q->sframe, true); // Here, the subframe length and input buffer is managed by ue_sync q->mode = UHD; @@ -114,7 +191,7 @@ void iodev_free(iodev_t *q) { int iodev_receive(iodev_t *q, cf_t **buffer) { int n; if (q->mode == FILESOURCE) { - DEBUG(" ----- READING %d SAMPLES ---- \n", q->sf_len); + INFO(" ----- READING %d SAMPLES ---- \n", q->sf_len); n = filesource_read(&q->fsrc, q->input_buffer_file, q->sf_len); *buffer = q->input_buffer_file; if (n == -1) { @@ -133,6 +210,11 @@ int iodev_receive(iodev_t *q, cf_t **buffer) { } else { n = 1; } + q->sf_idx++; + if (q->sf_idx == 10) { + q->sf_idx = 0; + } + usleep(5000); } else { /* Use ue_sync_work which returns a synchronized buffer of subframe samples */ #ifndef DISABLE_UHD @@ -161,4 +243,12 @@ bool iodev_isUSRP(iodev_t *q) { return q->mode == UHD; } +uint32_t iodev_get_sfidx(iodev_t *q) { + if (iodev_isfile(q)) { + return q->sf_idx; + } else { + return ue_sync_get_sfidx(&q->sframe); + } +} + diff --git a/lte/phy/examples/iodev.h b/lte/phy/examples/iodev.h index 81f7a67ef..bc020222f 100644 --- a/lte/phy/examples/iodev.h +++ b/lte/phy/examples/iodev.h @@ -54,6 +54,10 @@ typedef _Complex float cf_t; typedef struct LIBLTE_API { char *input_file_name; + uint32_t cell_id_file; + uint32_t nof_prb_file; + uint32_t nof_ports_file; + float uhd_freq; float uhd_gain; char *uhd_args; @@ -66,6 +70,7 @@ typedef struct LIBLTE_API { ue_sync_t sframe; #endif uint32_t sf_len; + uint32_t sf_idx; cf_t *input_buffer_file; // for UHD mode, the input buffer is managed by sync_frame_t filesource_t fsrc; iodev_cfg_t config; @@ -75,7 +80,8 @@ typedef struct LIBLTE_API { LIBLTE_API int iodev_init(iodev_t *q, iodev_cfg_t *config, - uint32_t file_sf_len); + lte_cell_t *cell, + pbch_mib_t *mib); LIBLTE_API void iodev_free(iodev_t *q); @@ -84,6 +90,8 @@ LIBLTE_API int iodev_receive(iodev_t *q, LIBLTE_API void* iodev_get_cuhd(iodev_t *q); +LIBLTE_API uint32_t iodev_get_sfidx(iodev_t *q); + LIBLTE_API bool iodev_isfile(iodev_t *q); LIBLTE_API bool iodev_isUSRP(iodev_t *q); diff --git a/lte/phy/examples/pdsch_ue.c b/lte/phy/examples/pdsch_ue.c index b67a9b1de..09ff59c3f 100644 --- a/lte/phy/examples/pdsch_ue.c +++ b/lte/phy/examples/pdsch_ue.c @@ -53,8 +53,6 @@ void init_plots(); * Program arguments processing ***********************************************************************/ typedef struct { - uint32_t cell_id_file; - uint32_t nof_prb_file; uint16_t rnti; int nof_subframes; bool disable_plots; @@ -62,8 +60,9 @@ typedef struct { }prog_args_t; void args_default(prog_args_t *args) { - args->cell_id_file = 1; - args->nof_prb_file = 6; + args->io_config.cell_id_file = 195; + args->io_config.nof_prb_file = 50; + args->io_config.nof_ports_file = 2; args->rnti = SIRNTI; args->nof_subframes = -1; args->disable_plots = false; @@ -71,13 +70,14 @@ void args_default(prog_args_t *args) { args->io_config.input_file_name = NULL; args->io_config.uhd_args = ""; args->io_config.uhd_freq = -1.0; - args->io_config.uhd_gain = 20.0; + args->io_config.uhd_gain = 60.0; } void usage(prog_args_t *args, char *prog) { printf("Usage: %s [cargfndvtb] [-i input_file | -f rx_frequency (in Hz)]\n", prog); - printf("\t-c cell_id if reading from file [Default %d]\n", args->cell_id_file); - printf("\t-p nof_prb if reading from file [Default %d]\n", args->nof_prb_file); + printf("\t-c cell_id if reading from file [Default %d]\n", args->io_config.cell_id_file); + printf("\t-p nof_prb if reading from file [Default %d]\n", args->io_config.nof_prb_file); + printf("\t-o nof_ports if reading from file [Default %d]\n", args->io_config.nof_ports_file); printf("\t-r RNTI to look for [Default 0x%x]\n", args->rnti); #ifndef DISABLE_UHD printf("\t-a UHD args [Default %s]\n", args->io_config.uhd_args); @@ -99,16 +99,19 @@ void usage(prog_args_t *args, char *prog) { void parse_args(prog_args_t *args, int argc, char **argv) { int opt; args_default(args); - while ((opt = getopt(argc, argv, "icagfndvtbpr")) != -1) { + while ((opt = getopt(argc, argv, "icagfndvtbpro")) != -1) { switch (opt) { case 'i': args->io_config.input_file_name = argv[optind]; break; case 'c': - args->cell_id_file = atoi(argv[optind]); + args->io_config.cell_id_file = atoi(argv[optind]); break; case 'p': - args->nof_prb_file = atoi(argv[optind]); + args->io_config.nof_prb_file = atoi(argv[optind]); + break; + case 'o': + args->io_config.nof_ports_file = atoi(argv[optind]); break; case 'a': args->io_config.uhd_args = argv[optind]; @@ -152,6 +155,8 @@ void sigintHandler(int x) { /* TODO: Do something with the output data */ char data[10000]; +extern float mean_exec_time; + int main(int argc, char **argv) { int ret; cf_t *sf_buffer; @@ -159,27 +164,13 @@ int main(int argc, char **argv) { prog_args_t prog_args; lte_cell_t cell; ue_dl_t ue_dl; - bool ue_dl_initiated = false; int64_t sf_cnt; - uint32_t sf_idx; pbch_mib_t mib; bool printed_sib = false; int rlen; - int symbol_sz; parse_args(&prog_args, argc, 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))) { - fprintf(stderr, "Error initiating input device\n"); - exit(-1); - } - } else { - fprintf(stderr, "Invalid number of PRB %d\n", prog_args.nof_prb_file); - exit(-1); - } - #ifndef DISABLE_GRAPHICS if (!prog_args.disable_plots) { init_plots(); @@ -190,16 +181,22 @@ int main(int argc, char **argv) { printf("\n --- Press Ctrl+C to exit --- \n"); signal(SIGINT, sigintHandler); - /* Initialize frame and subframe counters */ + /* Initialize subframe counter */ sf_cnt = 0; - sf_idx = 0; - /* 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); + if (iodev_init(&iodev, &prog_args.io_config, &cell, &mib)) { + exit(-1); + } + + if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) { + fprintf(stderr, "Error initiating UE downlink processing module\n"); + exit(-1); + } + pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti); /* Main loop */ while (!go_exit && (sf_cnt < prog_args.nof_subframes || prog_args.nof_subframes == -1)) { - + ret = iodev_receive(&iodev, &sf_buffer); if (ret < 0) { fprintf(stderr, "Error reading from input device (%d)\n", ret); @@ -207,81 +204,41 @@ 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.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); - } else { - cell.id = prog_args.cell_id_file; - cell.cp = CPNORM; - cell.nof_ports = 1; // TODO: Use prog_args - cell.nof_prb = prog_args.nof_prb_file; - mib.phich_resources = R_1; - mib.phich_length = PHICH_NORM; - } - if (ue_dl_init(&ue_dl, cell, mib.phich_resources, mib.phich_length, 1234)) { - fprintf(stderr, "Error initiating UE downlink processing module\n"); - exit(-1); - } - pdsch_set_rnti(&ue_dl.pdsch, prog_args.rnti); - ue_dl_initiated = true; - } else { - 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=-1; - if (rlen < 0) { - fprintf(stderr, "\nError running receiver\n");fflush(stdout); - exit(-1); - } - if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) { - printf("\n\nDecoded SIB1 Message: "); - vec_fprint_hex(stdout, data, rlen); - printf("\n");fflush(stdout); - printed_sib = true; - } - if (!(sf_cnt % 10)) { - 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); - - fflush(stdout); - if (VERBOSE_ISINFO()) { - printf("\n"); - } - } - #ifndef DISABLE_GRAPHICS - if (!prog_args.disable_plots && sf_idx == 5) { - do_plots(&ue_dl, sf_idx); - } - #endif + if (ret == 1) { + rlen = ue_dl_decode(&ue_dl, sf_buffer, data, iodev_get_sfidx(&iodev), prog_args.rnti); + if (rlen < 0) { + fprintf(stderr, "\nError running receiver\n");fflush(stdout); + exit(-1); } - if (iodev_isfile(&iodev)) { - sf_idx++; - if (sf_idx == NSUBFRAMES_X_FRAME) { - sf_idx = 0; - } + if (prog_args.rnti == SIRNTI && !printed_sib && rlen > 0) { + printf("\n\nDecoded SIB1 Message: "); + vec_fprint_hex(stdout, data, rlen); + printf("\n");fflush(stdout); + printed_sib = true; } - } - if (prog_args.nof_subframes > 0) { - sf_cnt++; - } - if (iodev_isfile(&iodev)) { - usleep(5000); + // Plot and Printf + if (!(sf_cnt % 10)) { + printf("CFO: %+.4f KHz, SFO: %+.4f Khz, NOI: %.2f Errors: %4d/%4d, BLER: %.1e, Texec: %.2f\r", + ue_sync_get_cfo(&iodev.sframe)/1000, ue_sync_get_sfo(&iodev.sframe)/1000, + pdsch_average_noi(&ue_dl.pdsch), + (int) ue_dl.pkt_errors, (int) ue_dl.pkts_total, (float) ue_dl.pkt_errors / ue_dl.pkts_total, + mean_exec_time); + } + #ifndef DISABLE_GRAPHICS + if (!prog_args.disable_plots && iodev_get_sfidx(&iodev) == 5) { + do_plots(&ue_dl, 5); + } + #endif + } else if (ret == 0) { + printf("Finding PSS... Peak: %8.1f, FrameCnt: %d, State: %d\r", + sync_get_peak_value(&iodev.sframe.sfind), + iodev.sframe.frame_total_cnt, iodev.sframe.state); } - } + sf_cnt++; + } // Main loop - if (ue_dl_initiated) { - ue_dl_free(&ue_dl); - } + ue_dl_free(&ue_dl); iodev_free(&iodev); printf("\nBye\n"); diff --git a/lte/phy/include/liblte/phy/ue/ue_dl.h b/lte/phy/include/liblte/phy/ue/ue_dl.h index 22ecd718d..e38d0ebf0 100644 --- a/lte/phy/include/liblte/phy/ue/ue_dl.h +++ b/lte/phy/include/liblte/phy/ue/ue_dl.h @@ -57,6 +57,7 @@ #define NOF_HARQ_PROCESSES 8 typedef struct LIBLTE_API { + pbch_t pbch; pcfich_t pcfich; pdcch_t pdcch; pdsch_t pdsch; @@ -74,6 +75,9 @@ typedef struct LIBLTE_API { uint64_t pkts_total; uint64_t nof_trials; + uint32_t sfn; + bool pbch_decoded; + uint16_t user_rnti; }ue_dl_t; @@ -86,11 +90,10 @@ LIBLTE_API int ue_dl_init(ue_dl_t *q, LIBLTE_API void ue_dl_free(ue_dl_t *q); -LIBLTE_API int ue_dl_receive(ue_dl_t *q, +LIBLTE_API int ue_dl_decode(ue_dl_t *q, cf_t *sf_buffer, char *data, - uint32_t sf_idx, - uint32_t sfn, + uint32_t sf_idx, uint16_t rnti); #endif \ No newline at end of file diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 7436b0ad9..293d3fe2b 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -38,7 +38,7 @@ #define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) #define SF_SZ(q) (2 * SLOT_SZ(q)) -//#define VOLK_INTERP +#define VOLK_INTERP void chest_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { chest_ref_fprint(q, stream, nslot, port_id); @@ -111,16 +111,18 @@ int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint channel_ref = input[tidx * q->nof_re + fidx]; q->refsignal[port_id][nslot].refs[nref].recv_simbol = channel_ref; + DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx, 10*log10f(cabsf(channel_ref/known_ref)), cargf(channel_ref)/M_PI,cargf(known_ref)/M_PI, cargf(channel_ref/known_ref)/M_PI); - + + /* FIXME: compare with threshold */ if (channel_ref != 0) { q->refsignal[port_id][nslot].ch_est[nref] = channel_ref/known_ref; } else { - q->refsignal[port_id][nslot].ch_est[nref] = 0; + q->refsignal[port_id][nslot].ch_est[nref] = 1e-6; } ret = LIBLTE_SUCCESS; } @@ -182,7 +184,7 @@ int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32 for (j=0;jsymbols_ref[0] * q->nof_re + i]; } - } + } for (j=0;jnof_symbols;j++) { ce[j * q->nof_re + i] = y[j]; } @@ -321,8 +323,10 @@ void chest_free(chest_t *q) { } } #ifdef VOLK_INTERP - interp_free(&q->interp_freq); - interp_free(&q->interp_time); + for (p=0;pinterp_freq[p]); + interp_free(&q->interp_time[p]); + } #endif bzero(q, sizeof(chest_t)); } diff --git a/lte/phy/lib/fec/src/turbodecoder.c b/lte/phy/lib/fec/src/turbodecoder.c index 250b078fd..171eefde3 100644 --- a/lte/phy/lib/fec/src/turbodecoder.c +++ b/lte/phy/lib/fec/src/turbodecoder.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "liblte/phy/fec/turbodecoder.h" @@ -39,7 +40,9 @@ * Decoder * ************************************************/ -void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, uint32_t long_cb) { +void map_gen_beta(map_gen_t * s, llr_t * input, llr_t * parity, + uint32_t long_cb) +{ llr_t m_b[8], new[8], old[8]; llr_t x, y, xy; int k; @@ -84,8 +87,9 @@ void map_gen_beta(map_gen_t *s, llr_t *input, llr_t *parity, uint32_t long_cb) { } } -void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, - uint32_t long_cb) { +void map_gen_alpha(map_gen_t * s, llr_t * input, llr_t * parity, llr_t * output, + uint32_t long_cb) +{ llr_t m_b[8], new[8], old[8], max1[8], max0[8]; llr_t m1, m0; llr_t x, y, xy; @@ -150,7 +154,8 @@ void map_gen_alpha(map_gen_t *s, llr_t *input, llr_t *parity, llr_t *output, } } -int map_gen_init(map_gen_t *h, int max_long_cb) { +int map_gen_init(map_gen_t * h, int max_long_cb) +{ bzero(h, sizeof(map_gen_t)); h->beta = malloc(sizeof(llr_t) * (max_long_cb + TOTALTAIL + 1) * NUMSTATES); if (!h->beta) { @@ -161,15 +166,17 @@ int map_gen_init(map_gen_t *h, int max_long_cb) { return 0; } -void map_gen_free(map_gen_t *h) { +void map_gen_free(map_gen_t * h) +{ if (h->beta) { free(h->beta); } bzero(h, sizeof(map_gen_t)); } -void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, - uint32_t long_cb) { +void map_gen_dec(map_gen_t * h, llr_t * input, llr_t * parity, llr_t * output, + uint32_t long_cb) +{ uint32_t k; h->beta[(long_cb + TAIL) * NUMSTATES] = 0; @@ -185,7 +192,8 @@ void map_gen_dec(map_gen_t *h, llr_t *input, llr_t *parity, llr_t *output, * TURBO DECODER INTERFACE * ************************************************/ -int tdec_init(tdec_t *h, uint32_t max_long_cb) { +int tdec_init(tdec_t * h, uint32_t max_long_cb) +{ int ret = -1; bzero(h, sizeof(tdec_t)); uint32_t len = max_long_cb + TOTALTAIL; @@ -227,13 +235,14 @@ int tdec_init(tdec_t *h, uint32_t max_long_cb) { } ret = 0; - clean_and_exit: if (ret == -1) { +clean_and_exit:if (ret == -1) { tdec_free(h); } return ret; } -void tdec_free(tdec_t *h) { +void tdec_free(tdec_t * h) +{ if (h->llr1) { free(h->llr1); } @@ -257,7 +266,8 @@ void tdec_free(tdec_t *h) { bzero(h, sizeof(tdec_t)); } -void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) { +void tdec_iteration(tdec_t * h, llr_t * input, uint32_t long_cb) +{ uint32_t i; // Prepare systematic and parity bits for MAP DEC #1 @@ -276,19 +286,19 @@ void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) { // Prepare systematic and parity bits for MAP DEC #1 for (i = 0; i < long_cb; i++) { h->syst[i] = h->llr1[h->interleaver.forward[i]] - - h->w[h->interleaver.forward[i]]; + - h->w[h->interleaver.forward[i]]; h->parity[i] = input[RATE * i + 2]; } for (i = long_cb; i < long_cb + RATE; i++) { h->syst[i] = - input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)]; + input[RATE * long_cb + NINPUTS * RATE + NINPUTS * (i - long_cb)]; h->parity[i] = input[RATE * long_cb + NINPUTS * RATE - + NINPUTS * (i - long_cb) + 1]; + + NINPUTS * (i - long_cb) + 1]; } // Run MAP DEC #1 map_gen_dec(&h->dec, h->syst, h->parity, h->llr2, long_cb); - + // Update a-priori LLR from the last iteration for (i = 0; i < long_cb; i++) { h->w[i] += h->llr2[h->interleaver.reverse[i]] - h->llr1[i]; @@ -296,25 +306,28 @@ void tdec_iteration(tdec_t *h, llr_t *input, uint32_t long_cb) { } -int tdec_reset(tdec_t *h, uint32_t long_cb) { - memset(h->w, 0, sizeof(llr_t) * long_cb); +int tdec_reset(tdec_t * h, uint32_t long_cb) +{ if (long_cb > h->max_long_cb) { fprintf(stderr, "TDEC was initialized for max_long_cb=%d\n", - h->max_long_cb); + h->max_long_cb); return -1; } + memset(h->w, 0, sizeof(llr_t) * long_cb); return tc_interl_LTE_gen(&h->interleaver, long_cb); } -void tdec_decision(tdec_t *h, char *output, uint32_t long_cb) { +void tdec_decision(tdec_t * h, char *output, uint32_t long_cb) +{ uint32_t i; for (i = 0; i < long_cb; i++) { - output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; + output[i] = (h->llr2[h->interleaver.reverse[i]] > 0) ? 1 : 0; } } -void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations, - uint32_t long_cb) { +void tdec_run_all(tdec_t * h, llr_t * input, char *output, + uint32_t nof_iterations, uint32_t long_cb) +{ uint32_t iter = 0; tdec_reset(h, long_cb); @@ -326,4 +339,3 @@ void tdec_run_all(tdec_t *h, llr_t *input, char *output, uint32_t nof_iterations tdec_decision(h, output, long_cb); } - diff --git a/lte/phy/lib/mimo/src/precoding.c b/lte/phy/lib/mimo/src/precoding.c index 036de038d..6c21ff21e 100644 --- a/lte/phy/lib/mimo/src/precoding.c +++ b/lte/phy/lib/mimo/src/precoding.c @@ -124,6 +124,11 @@ int precoding_type(cf_t *x[MAX_LAYERS], cf_t *y[MAX_PORTS], int nof_layers, /* ZF detector */ int predecoding_single_zf(cf_t *y, cf_t *ce, cf_t *x, int nof_symbols) { + for (int i=0;ipdsch_w_buff_f[i], harq_process->w_buff_size, &e_bits[rp], n_e, @@ -532,7 +533,7 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, char *cb_in_ptr; crc_t *crc_ptr; tdec_reset(&q->decoder, cb_len); - + do { tdec_iteration(&q->decoder, (float*) q->cb_out, cb_len); @@ -544,19 +545,20 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, crc_ptr = &q->crc_cb; } else { len_crc = tbs+24; + bzero(q->cb_in, F*sizeof(char)); cb_in_ptr = &q->cb_in[F]; crc_ptr = &q->crc_tb; } - + + tdec_decision(&q->decoder, q->cb_in, cb_len); + /* Check Codeblock CRC and stop early if incorrect */ if (!crc_checksum(crc_ptr, cb_in_ptr, len_crc)) { early_stop = true; } } while (q->nof_iterations < TDEC_MAX_ITERATIONS && !early_stop); - - tdec_decision(&q->decoder, q->cb_in, cb_len); - + q->average_nof_iterations = EXPAVERAGE((float) q->nof_iterations, q->average_nof_iterations, q->average_nof_iterations_n); @@ -588,7 +590,6 @@ int pdsch_decode_tb(pdsch_t *q, char *data, uint32_t tbs, uint32_t nb_e, par_tx = bit_unpack(&p_parity, 24); if (!par_rx) { - vec_fprint_hex(stdout, data, tbs); printf("\n\tCAUTION!! Received all-zero transport block\n\n"); } @@ -672,10 +673,23 @@ int pdsch_decode(pdsch_t *q, cf_t *sf_symbols, cf_t *ce[MAX_PORTS], char *data, demod_soft_sigma_set(&q->demod, 2.0 / q->mod[harq_process->mcs.mod - 1].nbits_x_symbol); demod_soft_table_set(&q->demod, &q->mod[harq_process->mcs.mod - 1]); demod_soft_demodulate(&q->demod, q->pdsch_d, q->pdsch_e, nof_symbols); + + /* + for (int j=0;jpdsch_d[j])) || isnan(cimagf(q->pdsch_d[j]))) { + printf("\nerror in d[%d]=%f+%f symbols:%f+%f ce0:%f+%f ce1:%f+%f\n",j, + crealf(q->pdsch_d[j]), cimagf(q->pdsch_d[j]), + crealf(q->pdsch_symbols[0][j]), cimagf(q->pdsch_symbols[0][j]), + crealf(q->ce[0][j]), cimagf(q->ce[0][j]), + crealf(q->ce[1][j]), cimagf(q->ce[1][j]) + ); + } + } + */ /* descramble */ scrambling_f_offset(&q->seq_pdsch[subframe], q->pdsch_e, 0, nof_bits_e); - + return pdsch_decode_tb(q, data, nof_bits, nof_bits_e, harq_process, rv_idx); } else { return LIBLTE_ERROR_INVALID_INPUTS; diff --git a/lte/phy/lib/sync/src/sync.c b/lte/phy/lib/sync/src/sync.c index 9d06a8616..34e4bd28e 100644 --- a/lte/phy/lib/sync/src/sync.c +++ b/lte/phy/lib/sync/src/sync.c @@ -73,7 +73,9 @@ int sync_init(sync_t *q, uint32_t frame_size, uint32_t fft_size) { DEBUG("SYNC init with frame_size=%d and fft_size=%d\n", frame_size, fft_size); ret = LIBLTE_SUCCESS; - } + } else { + fprintf(stderr, "Invalid parameters frame_size: %d, fft_size: %d\n", frame_size, fft_size); + } return ret; } @@ -238,9 +240,8 @@ int sync_find(sync_t *q, cf_t *input, uint32_t find_offset, uint32_t *peak_posit 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) + if (q->normalize_en && + peak_pos + find_offset >= q->fft_size) { /* Compute the energy of the received PSS sequence to normalize */ cf_t *pss_ptr = &input[find_offset+peak_pos-q->fft_size]; diff --git a/lte/phy/lib/ue/src/ue_dl.c b/lte/phy/lib/ue/src/ue_dl.c index 9bb914c58..203011776 100644 --- a/lte/phy/lib/ue/src/ue_dl.c +++ b/lte/phy/lib/ue/src/ue_dl.c @@ -27,6 +27,8 @@ #include "liblte/phy/ue/ue_dl.h" +#include +#include #define EXPAVERAGE(data, average, nframes) ((data + average * nframes) / (nframes + 1)) @@ -54,6 +56,8 @@ int ue_dl_init(ue_dl_t *q, q->pkt_errors = 0; q->pkts_total = 0; q->nof_trials = 0; + q->sfn = 0; + q->pbch_decoded = false; if (lte_fft_init(&q->fft, q->cell.cp, q->cell.nof_prb)) { fprintf(stderr, "Error initiating FFT\n"); @@ -67,7 +71,10 @@ int ue_dl_init(ue_dl_t *q, fprintf(stderr, "Error initiating REGs\n"); goto clean_exit; } - + if (pbch_init(&q->pbch, q->cell)) { + fprintf(stderr, "Error creating PBCH object\n"); + goto clean_exit; + } if (pcfich_init(&q->pcfich, &q->regs, q->cell)) { fprintf(stderr, "Error creating PCFICH object\n"); goto clean_exit; @@ -119,6 +126,7 @@ void ue_dl_free(ue_dl_t *q) { lte_fft_free(&q->fft); chest_free(&q->chest); regs_free(&q->regs); + pbch_free(&q->pbch); pcfich_free(&q->pcfich); pdcch_free(&q->pdcch); pdsch_free(&q->pdsch); @@ -136,7 +144,10 @@ void ue_dl_free(ue_dl_t *q) { } } -int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t sfn, uint16_t rnti) +LIBLTE_API float mean_exec_time=0; +int frame_cnt=0; + +int ue_dl_decode(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint16_t rnti) { uint32_t cfi, cfi_distance, i; ra_pdsch_t ra_dl; @@ -145,19 +156,49 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t uint32_t nof_locations; uint16_t crc_rem; dci_format_t format; + pbch_mib_t mib; int ret = LIBLTE_ERROR; + cf_t *ce_slot1[MAX_PORTS]; + struct timeval t[3]; + + /* Run FFT for all subframe data */ + lte_fft_run_sf(&q->fft, input, q->sf_symbols); + + gettimeofday(&t[1], NULL); + + /* Get channel estimates for each port */ + chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx); + + gettimeofday(&t[2], NULL); + get_time_interval(t); + mean_exec_time = (float) EXPAVERAGE((float) t[0].tv_usec, mean_exec_time, frame_cnt); + frame_cnt++; + for (int i=0;ice[i][SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)]; + } + + /* Decode PBCH if not yet decoded to obtain the System Frame Number (SFN) */ + if (sf_idx == 0) { + // FIXME: There is no need to do this every frame! + pbch_decode_reset(&q->pbch); + if (pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->cell.nof_prb, q->cell.cp)], ce_slot1, &mib) == 1) { + q->sfn = mib.sfn; + q->pbch_decoded = true; + INFO("Decoded SFN: %d\n", q->sfn); + } else { + INFO("Not decoded MIB (SFN: %d)\n", q->sfn); + q->sfn++; + if (q->sfn == 1024) { + q->sfn = 0; + } + } + } /* If we are looking for SI Blocks, search only in appropiate places */ - if ((rnti == SIRNTI && (sfn % 2) == 0 && sf_idx == 5) || - rnti != SIRNTI) + if (((rnti == SIRNTI && (q->sfn % 2) == 0 && sf_idx == 5) || + rnti != SIRNTI)) { - /* Run FFT for all subframe data */ - lte_fft_run_sf(&q->fft, input, q->sf_symbols); - - /* Get channel estimates for each port */ - chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx); - /* First decode PCFICH and obtain CFI */ if (pcfich_decode(&q->pcfich, q->sf_symbols, q->ce, sf_idx, &cfi, &cfi_distance)<0) { fprintf(stderr, "Error decoding PCFICH\n"); @@ -180,6 +221,7 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t format = Format1; } + crc_rem = 0; for (i=0;ipdcch, q->sf_symbols, q->ce, locations[i], sf_idx, cfi)) { @@ -192,8 +234,7 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t } INFO("Decoded DCI message RNTI: 0x%x\n", crc_rem); } - - + if (crc_rem == rnti) { if (dci_msg_to_ra_dl(&dci_msg, rnti, q->user_rnti, q->cell, cfi, &ra_dl)) { fprintf(stderr, "Error unpacking PDSCH scheduling DCI message\n"); @@ -202,7 +243,7 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t uint32_t rvidx; if (rnti == SIRNTI) { - switch((sfn%8)/2) { + switch((q->sfn%8)/2) { case 0: rvidx = 0; break; @@ -251,11 +292,11 @@ int ue_dl_receive(ue_dl_t *q, cf_t *input, char *data, uint32_t sf_idx, uint32_t } } } - if (rnti == SIRNTI && (sfn%8) == 0) { + if (rnti == SIRNTI && (q->sfn%8) == 0) { q->nof_trials++; } } - + if (crc_rem == rnti && ret == LIBLTE_SUCCESS) { return ra_dl.mcs.tbs; } else { diff --git a/lte/phy/lib/ue/src/ue_sync.c b/lte/phy/lib/ue/src/ue_sync.c index 600bc1ee7..714a6212f 100644 --- a/lte/phy/lib/ue/src/ue_sync.c +++ b/lte/phy/lib/ue/src/ue_sync.c @@ -71,20 +71,27 @@ int ue_sync_init(ue_sync_t *q, q->decode_sss_on_track = false; q->stream = stream_handler; q->recv_callback = recv_callback; + q->cell = cell; - if(sync_init(&q->sfind, 5 * CURRENT_SFLEN, CURRENT_FFTSIZE)) { + if(sync_init(&q->sfind, CURRENT_SFLEN, CURRENT_FFTSIZE)) { + fprintf(stderr, "Error initiating sync find\n"); goto clean_exit; } if(sync_init(&q->strack, CURRENT_FFTSIZE, CURRENT_FFTSIZE)) { + fprintf(stderr, "Error initiating sync track\n"); goto clean_exit; } sync_set_N_id_2(&q->sfind, cell.id%3); sync_set_threshold(&q->sfind, FIND_THRESHOLD); + q->sfind.cp = cell.cp; + sync_cp_en(&q->sfind, false); sync_set_N_id_2(&q->strack, cell.id%3); sync_set_threshold(&q->strack, TRACK_THRESHOLD); - + q->strack.cp = cell.cp; + sync_cp_en(&q->strack, false); + if (cfo_init(&q->cfocorr, CURRENT_SFLEN)) { fprintf(stderr, "Error initiating CFO\n"); goto clean_exit; @@ -140,18 +147,16 @@ void ue_sync_decode_sss_on_track(ue_sync_t *q, bool 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; - } + + /* Receive the rest of the next subframe */ + if (q->recv_callback(q->stream, q->input_buffer, q->peak_idx+CURRENT_SFLEN/2) < 0) { + return LIBLTE_ERROR; } if (sync_sss_detected(&q->sfind)) { + /* Get the subframe index (0 or 5) */ - q->sf_idx = sync_get_sf_idx(&q->sfind); + q->sf_idx = sync_get_sf_idx(&q->sfind) + 1; /* Reset variables */ q->frame_ok_cnt = 0; @@ -160,39 +165,35 @@ static int find_peak_ok(ue_sync_t *q) { /* 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; + 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_sf_idx(&q->strack)) && q->decode_sss_on_track) { - INFO("\nWarning: Expected SF idx %d but got %d!\n", + INFO("Warning: 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); + q->state = SF_TRACK; } 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; - } + if (q->recv_callback(q->stream, dummy, (uint32_t) q->time_offset) < 0) { + fprintf(stderr, "Error receiving from USRP\n"); + return LIBLTE_ERROR; + } + } /* compute cumulative moving average CFO */ q->cur_cfo = EXPAVERAGE(sync_get_cfo(&q->strack), q->cur_cfo, q->frame_ok_cnt); @@ -202,15 +203,10 @@ int track_peak_ok(ue_sync_t *q, uint32_t track_idx) { 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; - } + q->frame_no_cnt = 0; } - return ret; + return 1; } int track_peak_no(ue_sync_t *q) { @@ -225,11 +221,10 @@ int track_peak_no(ue_sync_t *q) { sync_get_peak_value(&q->strack), (int) q->frame_no_cnt); } - return LIBLTE_SUCCESS; + return 1; } 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. @@ -237,18 +232,12 @@ static int receive_samples(ue_sync_t *q) { 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)); + //memcpy(q->input_buffer, &q->input_buffer[CURRENT_SFLEN-q->time_offset], q->time_offset*sizeof(cf_t)); /* Get 1 subframe from the USRP getting more samples and keeping the previous samples, if any */ - if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], read_len - q->time_offset) < 0) { + if (q->recv_callback(q->stream, &q->input_buffer[q->time_offset], CURRENT_SFLEN - q->time_offset) < 0) { return LIBLTE_ERROR; } @@ -281,8 +270,6 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { 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) { @@ -298,14 +285,12 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { } break; case SF_TRACK: - ret = LIBLTE_SUCCESS; + ret = 1; 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) { @@ -333,31 +318,22 @@ int ue_sync_get_buffer(ue_sync_t *q, cf_t **sf_symbols) { } 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; } + + q->frame_total_cnt++; } /* 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; } diff --git a/lte/phy/lib/ue/test/ue_sync_usrp.c b/lte/phy/lib/ue/test/ue_sync_usrp.c index caa667907..62bb1d7c5 100644 --- a/lte/phy/lib/ue/test/ue_sync_usrp.c +++ b/lte/phy/lib/ue/test/ue_sync_usrp.c @@ -49,16 +49,19 @@ plot_real_t poutfft; int nof_frames = -1; float threshold = -1.0; +int N_id_2 = -1; +uint32_t nof_prb = 6; float uhd_freq = 0.0, uhd_gain = 20.0; char *uhd_args = ""; int disable_plots = 0; void usage(char *prog) { - printf("Usage: %s [agntdv] -f uhd_freq\n", prog); + printf("Usage: %s [agntdpv] -f uhd_freq -i N_id_2\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 [Default infinite]\n"); + printf("\t-p nof_prb [Default %d]\n", nof_prb); printf("\t-t threshold [Default %.2f]\n",threshold); #ifndef DISABLE_GRAPHICS @@ -69,8 +72,14 @@ void usage(char *prog) { void parse_args(int argc, char **argv) { int opt; - while ((opt = getopt(argc, argv, "agntdvf")) != -1) { + while ((opt = getopt(argc, argv, "agntdvfip")) != -1) { switch (opt) { + case 'i': + N_id_2 = atoi(argv[optind]); + break; + case 'p': + nof_prb = atoi(argv[optind]); + break; case 'n': nof_frames = atoi(argv[optind]); break; @@ -97,7 +106,7 @@ void parse_args(int argc, char **argv) { exit(-1); } } - if (uhd_freq == 0.0) { + if (uhd_freq == 0.0 || N_id_2 == -1) { usage(argv[0]); exit(-1); } @@ -117,6 +126,12 @@ void input_init() { cuhd_rx_wait_lo_locked(uhd); DEBUG("Set uhd_freq to %.3f MHz\n", (double ) uhd_freq/1000000); + int srate = lte_sampling_freq_hz(nof_prb); + if (srate > 0) { + cuhd_set_rx_srate(uhd, (double) srate); + } else { + fprintf(stderr, "Error invalid nof_prb=%d\n",nof_prb); + } DEBUG("Starting receiver...\n", 0); cuhd_start_rx_stream(uhd); @@ -152,7 +167,6 @@ int main(int argc, char **argv) { float peak; struct timeval t[3]; float mean_ce_time=0; - bool signal_detected; lte_fft_t fft; lte_cell_t cell; @@ -169,16 +183,26 @@ int main(int argc, char **argv) { input_init(); cell.cp = CPNORM; - cell.id = 1; + cell.id = N_id_2; cell.nof_ports = 1; - cell.nof_prb = 6; + cell.nof_prb = nof_prb; if (ue_sync_init(&s, cell, cuhd_recv_wrapper, uhd)) { fprintf(stderr, "Error initiating UE sync module\n"); exit(-1); } - - signal_detected = true; + + pss_synch_init_fft(&pss, + SF_LEN(lte_symbol_sz(cell.nof_prb)), + lte_symbol_sz(cell.nof_prb)); + pss_synch_set_N_id_2(&pss, cell.id%3); + sf_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + if (!sf_symbols) { + perror("malloc"); + exit(-1); + } + lte_fft_init(&fft, cell.cp, cell.nof_prb); + frame_cnt = 0; mean_ce_time=0; uint32_t valid_frames=0; @@ -193,21 +217,6 @@ int main(int argc, char **argv) { if (n == 1 && ue_sync_get_sfidx(&s) == 0) { - if (signal_detected) { - pss_synch_init_fft(&pss, - SF_LEN(lte_symbol_sz(cell.nof_prb)), - lte_symbol_sz(cell.nof_prb)); - pss_synch_set_N_id_2(&pss, cell.id%3); - - sf_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - if (!sf_symbols) { - perror("malloc"); - exit(-1); - } - lte_fft_init(&fft, cell.cp, cell.nof_prb); - signal_detected = false; - } - mean_ce_time = (float) (mean_ce_time + (float) t[0].tv_usec * valid_frames) / (valid_frames+1); valid_frames++; @@ -230,12 +239,8 @@ int main(int argc, char **argv) { #endif pos = pss_synch_find_pss(&pss, input_buffer, &peak); - /*if (pos > 962 || pos < 958) { - unaligned++; - } - */ printf("CELL_ID: %3d CFO: %+.4f KHz, SFO: %+.4f Khz, TimeOffset: %4d, Exec: %3.2f\r", - cell.id, ue_sync_get_cfo(&s)/1000, ue_sync_get_sfo(&s)/1000, pos, + sync_get_cell_id(&s.sfind), ue_sync_get_cfo(&s)/1000, ue_sync_get_sfo(&s)/1000, pos, s.mean_exec_time); fflush(stdout); if (VERBOSE_ISINFO()) {