diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h index 2e4434fab..e182e684b 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest.h @@ -76,21 +76,6 @@ LIBLTE_API void chest_free(chest_t *q); LIBLTE_API int chest_set_nof_ports(chest_t *q, uint32_t nof_ports); -LIBLTE_API int chest_init_LTEDL(chest_t *q, - lte_cell_t cell); - -LIBLTE_API int chest_ref_LTEDL_slot_port(chest_t *q, - uint32_t nslot, - uint32_t port_id, - lte_cell_t cell); - -LIBLTE_API int chest_ref_LTEDL_slot(chest_t *q, - uint32_t nslot, - lte_cell_t cell); - -LIBLTE_API int chest_ref_LTEDL(chest_t *q, - lte_cell_t cell); - LIBLTE_API int chest_ce_ref(chest_t *q, cf_t *input, uint32_t nslot, @@ -139,10 +124,50 @@ LIBLTE_API void chest_ce_fprint(chest_t *q, uint32_t nslot, uint32_t port_id); -LIBLTE_API int chest_ref_symbols(chest_t *q, - uint32_t port_id, - uint32_t nslot, - uint32_t l[2]); +LIBLTE_API int chest_ref_get_symbols(chest_t *q, + uint32_t port_id, + uint32_t nslot, + uint32_t l[2]); + + + + +/********************************************************* + * + * Downlink Channel Estimator + * + *********************************************************/ +LIBLTE_API int chest_init_LTEDL(chest_t *q, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEDL_slot_port(chest_t *q, + uint32_t nslot, + uint32_t port_id, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEDL_slot(chest_t *q, + uint32_t nslot, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEDL(chest_t *q, + lte_cell_t cell); + + +/********************************************************* + * + * Uplink Channel Estimator + * + *********************************************************/ +LIBLTE_API int chest_init_LTEUL(chest_t *q, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEUL_slot(chest_t *q, + uint32_t nslot, + lte_cell_t cell); + +LIBLTE_API int chest_ref_set_LTEUL(chest_t *q, + lte_cell_t cell); + /* High-level API */ diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h index 51ad505ff..86342cc79 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h +++ b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h @@ -59,11 +59,31 @@ typedef struct LIBLTE_API{ cf_t *ch_est; } refsignal_t; + +typedef struct LIBLTE_API { + float beta; // amplitude scaling + uint32_t delta_ss; // Set to 0 for PUCCH + uint32_t cyclic_shift; + uint32_t cyclic_shift_for_drms; /* From DCI 0. Set to 0 if no PDCCH with DCI 0 for the same TB + or if the initial PUSCH is semi-persisently scheduled or + if the initial PUSCH is scheduled by the RA response grant */ + bool group_hopping_en; + bool sequence_hopping_en; +} refsignal_ul_cfg_t; + + LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, lte_cell_t cell); +LIBLTE_API int refsignal_init_LTEUL_drms_pusch(refsignal_t *q, + uint32_t nof_prb, + uint32_t prb_start, + uint32_t nslot, + lte_cell_t cell, + refsignal_ul_cfg_t *drms_cfg); + LIBLTE_API void refsignal_free(refsignal_t *q); LIBLTE_API int refsignal_put(refsignal_t *q, diff --git a/lte/phy/include/liblte/phy/common/sequence.h b/lte/phy/include/liblte/phy/common/sequence.h index 972a31ebf..a3dae142b 100644 --- a/lte/phy/include/liblte/phy/common/sequence.h +++ b/lte/phy/include/liblte/phy/common/sequence.h @@ -40,7 +40,7 @@ LIBLTE_API int sequence_init(sequence_t *q, uint32_t len); LIBLTE_API void sequence_free(sequence_t *q); -LIBLTE_API int sequence_LTEPRS(sequence_t *q, +LIBLTE_API int sequence_LTE_pr(sequence_t *q, uint32_t len, uint32_t seed); diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c index 293d3fe2b..37dabf82a 100644 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ b/lte/phy/lib/ch_estimation/src/chest.c @@ -259,17 +259,58 @@ int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_p return ret; } +void chest_free(chest_t *q) { + int p, n; + for (p=0;pnof_ports;p++) { + for (n=0;nrefsignal[p][n]); + } + } +#ifdef VOLK_INTERP + for (p=0;pinterp_freq[p]); + interp_free(&q->interp_time[p]); + } +#endif + bzero(q, sizeof(chest_t)); +} + +/* Fills l[2] with the symbols in the slot nslot that contain references. + * returns the number of symbols with references (in the slot) + */ +int chest_ref_get_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) { + + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME) + { + memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols); + return q->refsignal[port_id][nslot].nsymbols; + } else { + return LIBLTE_ERROR_INVALID_INPUTS; + } +} + + + + + +/********************************************************************* + * + * Downlink Channel estimator + * + *********************************************************************/ int chest_init_LTEDL(chest_t *q, lte_cell_t cell) { int ret; ret = chest_init(q, cell.nof_prb * RE_X_RB, CP_NSYMB(cell.cp), cell.nof_ports); if (ret != LIBLTE_SUCCESS) { return ret; } else { - return chest_ref_LTEDL(q, cell); + return chest_ref_set_LTEDL(q, cell); } } -int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) { +int chest_ref_set_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_cell_t cell) { int ret = LIBLTE_ERROR_INVALID_INPUTS; if (q != NULL && @@ -293,10 +334,10 @@ int chest_ref_LTEDL_slot_port(chest_t *q, uint32_t nslot, uint32_t port_id, lte_ return ret; } -int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { +int chest_ref_set_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { int p, ret; for (p=0;pnof_ports;p++) { - ret = chest_ref_LTEDL_slot_port(q, nslot, p, cell); + ret = chest_ref_set_LTEDL_slot_port(q, nslot, p, cell); if (ret != LIBLTE_SUCCESS) { return ret; } @@ -304,10 +345,10 @@ int chest_ref_LTEDL_slot(chest_t *q, uint32_t nslot, lte_cell_t cell) { return LIBLTE_SUCCESS; } -int chest_ref_LTEDL(chest_t *q, lte_cell_t cell) { +int chest_ref_set_LTEDL(chest_t *q, lte_cell_t cell) { int n, ret; for (n=0;nnof_ports;p++) { - for (n=0;nrefsignal[p][n]); - } - } -#ifdef VOLK_INTERP - for (p=0;pinterp_freq[p]); - interp_free(&q->interp_time[p]); - } -#endif - bzero(q, sizeof(chest_t)); -} -/* Fills l[2] with the symbols in the slot nslot that contain references. - * returns the number of symbols with references (in the slot) - */ -int chest_ref_symbols(chest_t *q, uint32_t port_id, uint32_t nslot, uint32_t l[2]) { - - if (q != NULL && - port_id < MAX_PORTS && - nslot < NSLOTS_X_FRAME) - { - memcpy(l, q->refsignal[port_id][nslot].symbols_ref, sizeof(uint32_t) * q->refsignal[port_id][nslot].nsymbols); - return q->refsignal[port_id][nslot].nsymbols; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} + + +/********************************************************************* + * + * TODO: Uplink Channel estimator + * + * + *********************************************************************/ + + + + + + + + + + + + + + + + + /** High-level API diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c index 0ecdb59c1..037b45edb 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ b/lte/phy/lib/ch_estimation/src/refsignal.c @@ -38,48 +38,51 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/sequence.h" +#include "ul_rs_tables.h" + #define idx(x, y) (l*nof_refs_x_symbol+i) -int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) { - int v=-1; - switch(port_id) { - case 0: - if (symbol_id == 0) { - v=0; - } else { - v=3; - } - break; - case 1: - if (symbol_id == 0) { - v=3; - } else { - v=0; - } - break; - case 2: - v=3*(ns%2); - break; - case 3: - v=3+3*(ns%2); - break; +int refsignal_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) +{ + int v = -1; + switch (port_id) { + case 0: + if (symbol_id == 0) { + v = 0; + } else { + v = 3; + } + break; + case 1: + if (symbol_id == 0) { + v = 3; + } else { + v = 0; + } + break; + case 2: + v = 3 * (ns % 2); + break; + case 3: + v = 3 + 3 * (ns % 2); + break; } return v; } -uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) { - return 6*m+((v+(cell_id%6))%6); +uint32_t refsignal_k(uint32_t m, uint32_t v, uint32_t cell_id) +{ + return 6 * m + ((v + (cell_id % 6)) % 6); } -int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { +int refsignal_put(refsignal_t * q, cf_t * slot_symbols) +{ uint32_t i; uint32_t fidx, tidx; - if (q != NULL && - slot_symbols != NULL) - { - for (i=0;inof_refs;i++) { - fidx = q->refs[i].freq_idx; // reference frequency index - tidx = q->refs[i].time_idx; // reference time index + if (q != NULL && slot_symbols != NULL) { + for (i = 0; i < q->nof_refs; i++) { + fidx = q->refs[i].freq_idx; // reference frequency index + tidx = q->refs[i].time_idx; // reference time index slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].simbol; } return LIBLTE_SUCCESS; @@ -91,8 +94,9 @@ int refsignal_put(refsignal_t *q, cf_t *slot_symbols) { /** Initializes refsignal_t object according to 3GPP 36.211 6.10.1 * */ -int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, - lte_cell_t cell) { +int refsignal_init_LTEDL(refsignal_t * q, uint32_t port_id, uint32_t nslot, + lte_cell_t cell) +{ uint32_t c_init; uint32_t ns, l, lp[2]; @@ -104,12 +108,10 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, uint32_t mp; uint32_t nof_refs_x_symbol, nof_ref_symbols; - if (q != NULL && - port_id < MAX_PORTS && - nslot < NSLOTS_X_FRAME && - lte_cell_isvalid(&cell)) - { - + if (q != NULL && + port_id < MAX_PORTS && + nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) { + bzero(q, sizeof(refsignal_t)); bzero(&seq, sizeof(sequence_t)); @@ -131,7 +133,7 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; q->nsymbols = nof_ref_symbols; - q->voffset = cell.id%6; + q->voffset = cell.id % 6; q->nof_prb = cell.nof_prb; q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols); @@ -155,8 +157,8 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, for (l = 0; l < nof_ref_symbols; l++) { c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1) - + 2 * cell.id + N_cp; - ret = sequence_LTEPRS(&seq, 2 * 2 * MAX_PRB, c_init); + + 2 * cell.id + N_cp; + ret = sequence_LTE_pr(&seq, 2 * 2 * MAX_PRB, c_init); if (ret != LIBLTE_SUCCESS) { goto free_and_exit; } @@ -167,19 +169,21 @@ int refsignal_init_LTEDL(refsignal_t *q, uint32_t port_id, uint32_t nslot, mp = i + MAX_PRB - cell.nof_prb; /* generate signal */ - __real__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); - __imag__ q->refs[idx(l,i)].simbol = (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + __real__ q->refs[idx(l, i)].simbol = + (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); + __imag__ q->refs[idx(l, i)].simbol = + (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); /* mapping to resource elements */ - q->refs[idx(l,i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); - q->refs[idx(l,i)].time_idx = lp[l]; + q->refs[idx(l, i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); + q->refs[idx(l, i)].time_idx = lp[l]; } } ret = LIBLTE_SUCCESS; } free_and_exit: if (ret != LIBLTE_ERROR_INVALID_INPUTS) { - sequence_free(&seq); + sequence_free(&seq); } if (ret == LIBLTE_ERROR) { refsignal_free(q); @@ -187,7 +191,179 @@ free_and_exit: return ret; } -void refsignal_free(refsignal_t *q) { +// n_drms_2 table 5.5.2.1.1-1 from 36.211 +uint32_t n_drms_2[8] = { 0, 6, 3, 4, 2, 8, 10, 9 }; + +// n_drms_1 table 5.5.2.1.1-2 from 36.211 +uint32_t n_drms_1[8] = { 0, 2, 3, 4, 6, 8, 9, 10 }; + + +/* Generation of the reference signal sequence according to Section 5.5.1 of 36.211 */ +int rs_sequence(ref_t * refs, uint32_t len, float alpha, uint32_t ns, uint32_t cell_id, + refsignal_ul_cfg_t * cfg) +{ + uint32_t i; + + // Calculate u and v + uint32_t u, v; + uint32_t f_ss = (((cell_id % 30) + cfg->delta_ss) % 30); + if (cfg->group_hopping_en) { + sequence_t seq; + sequence_LTE_pr(&seq, cell_id / 30, 160); + uint32_t f_gh = 0; + for (i = 0; i < 8; i++) { + f_gh += seq.c[8 * ns + i] << i; + } + sequence_free(&seq); + u = ((f_gh%30) + f_ss) % 30; + } else { + u = f_ss % 30; + } + + if (len < 6 * RE_X_RB) { + v = 0; + } else { + if (!cfg->group_hopping_en && cfg->sequence_hopping_en) { + sequence_t seq; + sequence_LTE_pr(&seq, ((cell_id / 30) << 5) + f_ss, 20); + v = seq.c[ns]; + sequence_free(&seq); + } else { + v = 0; + } + } + if (len >= 3 * RE_X_RB) { + uint32_t n_sz; + uint32_t q; + float q_hat; + /* get largest prime n_zc 0; i--) { + if (prime_numbers[i] < len) { + n_sz = prime_numbers[i]; + break; + } + } + q_hat = (float) n_sz *(u + 1) / 31; + if ((((uint32_t) (2 * q_hat)) % 2) == 0) { + q = (uint32_t) (q_hat + 0.5) + v; + } else { + q = (uint32_t) (q_hat + 0.5) - v; + } + cf_t *x_q = malloc(sizeof(cf_t) * n_sz); + if (!x_q) { + perror("malloc"); + return LIBLTE_ERROR; + } + for (i = 0; i < n_sz; i++) { + x_q[i] = + cexpf(-I * M_PI * (float) q * (float) i * ((float) i + 1) / n_sz); + } + for (i = 0; i < len; i++) { + refs[i].simbol = cfg->beta * cexpf(I * alpha * i) * x_q[i % n_sz]; + } + free(x_q); + } else { + if (len == RE_X_RB) { + for (i = 0; i < len; i++) { + refs[i].simbol = cfg->beta * cexpf(I * (phi_M_sc_12[u][i] * M_PI / 4 + alpha * i)); + } + } else { + for (i = 0; i < len; i++) { + refs[i].simbol = cfg->beta * cexpf(I * (phi_M_sc_24[u][i] * M_PI / 4 + alpha * i)); + } + } + } + + return LIBLTE_SUCCESS; +} + +/** Initializes refsignal_t object according to 3GPP 36.211 5.5.2 + * + */ +int refsignal_init_LTEUL_drms_pusch(refsignal_t * q, uint32_t nof_prb, uint32_t prb_start, + uint32_t nslot, lte_cell_t cell, refsignal_ul_cfg_t * cfg) +{ + + uint32_t i; + int ret = LIBLTE_ERROR_INVALID_INPUTS; + uint32_t n_prs; + uint32_t M_sc; + float alpha; + + if (q != NULL && nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) { + + bzero(q, sizeof(refsignal_t)); + + M_sc = nof_prb * RE_X_RB; + + q->nof_refs = M_sc; + q->nsymbols = 1; + q->voffset = cell.id % 6; + q->nof_prb = cell.nof_prb; + + q->symbols_ref = malloc(sizeof(uint32_t) * 1); + if (!q->symbols_ref) { + perror("malloc"); + goto free_and_exit; + } + + if (CP_ISNORM(cell.cp)) { + q->symbols_ref[0] = 3; + } else { + q->symbols_ref[0] = 2; + } + + q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); + if (!q->refs) { + goto free_and_exit; + } + q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); + if (!q->ch_est) { + goto free_and_exit; + } + + /* Calculate n_prs */ + uint32_t c_init; + sequence_t seq; + c_init = ((cell.id / 30) << 5) + (((cell.id % 30) + cfg->delta_ss) % 30); + ret = sequence_LTE_pr(&seq, 8 * CP_NSYMB(cell.cp) * 20, c_init); + if (ret != LIBLTE_SUCCESS) { + goto free_and_exit; + } + n_prs = 0; + for (i = 0; i < 8; i++) { + n_prs += (seq.c[8 * CP_NSYMB(cell.cp) * nslot + i] << i); + } + sequence_free(&seq); + + // Calculate cyclic shift alpha + uint32_t n_cs = + (n_drms_1[cfg->cyclic_shift] + + n_drms_2[cfg->cyclic_shift_for_drms] + n_prs) % 12; + alpha = 2 * M_PI * (n_cs) / 12; + + if (rs_sequence(q->refs, M_sc, alpha, cell.id, nslot, cfg)) { + fprintf(stderr, "Error generating RS sequence\n"); + goto free_and_exit; + } + /* mapping to resource elements */ + for (i=0;irefs[i].freq_idx = prb_start*RE_X_RB + i; + q->refs[i].time_idx = q->symbols_ref[0]; + } + + ret = LIBLTE_SUCCESS; + } +free_and_exit: + if (ret == LIBLTE_ERROR) { + refsignal_free(q); + } + return ret; +} + + +void refsignal_free(refsignal_t * q) +{ if (q->symbols_ref) { free(q->symbols_ref); } @@ -199,5 +375,3 @@ void refsignal_free(refsignal_t *q) { } bzero(q, sizeof(refsignal_t)); } - - diff --git a/lte/phy/lib/ch_estimation/src/ul_rs_tables.h b/lte/phy/lib/ch_estimation/src/ul_rs_tables.h new file mode 100644 index 000000000..63f99d79b --- /dev/null +++ b/lte/phy/lib/ch_estimation/src/ul_rs_tables.h @@ -0,0 +1,127 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include + +// Phi values for M_sc=12 Table 5.5.1.2-1 in 36.211 +int phi_M_sc_12[30][12] = {{-1, 1, 3,-3, 3, 3, 1, 1, 3, 1,-3, 3}, + { 1, 1, 3, 3, 3,-1, 1,-3,-3, 1,-3, 3}, + { 1, 1,-3,-3,-3,-1,-3,-3, 1,-3, 1,-1}, + {-1, 1, 1, 1, 1,-1,-3,-3, 1,-3, 3,-1}, + {-1, 3, 1,-1, 1,-1,-3,-1, 1,-1, 1, 3}, + { 1,-3, 3,-1,-1, 1, 1,-1,-1, 3,-3, 1}, + {-1, 3,-3,-3,-3, 3, 1,-1, 3, 3,-3, 1}, + {-3,-1,-1,-1, 1,-3, 3,-1, 1,-3, 3, 1}, + { 1,-3, 3, 1,-1,-1,-1, 1, 1, 3,-1, 1}, + { 1,-3,-1, 3, 3,-1,-3, 1, 1, 1, 1, 1}, + {-1, 3,-1, 1, 1,-3,-3,-1,-3,-3, 3,-1}, + { 3, 1,-1,-1, 3, 3,-3, 1, 3, 1, 3, 3}, + { 1,-3, 1, 1,-3, 1, 1, 1,-3,-3,-3, 1}, + { 3, 3,-3, 3,-3, 1, 1, 3,-1,-3, 3, 3}, + {-3, 1,-1,-3,-1, 3, 1, 3, 3, 3,-1, 1}, + { 3,-1, 1,-3,-1,-1, 1, 1, 3, 1,-1,-3}, + { 1, 3, 1,-1, 1, 3, 3, 3,-1,-1, 3,-1}, + {-3, 1, 1, 3,-3, 3,-3,-3, 3, 1, 3,-1}, + {-3, 3, 1, 1,-3, 1,-3,-3,-1,-1, 1,-3}, + {-1, 3, 1, 3, 1,-1,-1, 3,-3,-1,-3,-1}, + {-1,-3, 1, 1, 1, 1, 3, 1,-1, 1,-3,-1}, + {-1, 3,-1, 1,-3,-3,-3,-3,-3, 1,-1,-3}, + { 1, 1,-3,-3,-3,-3,-1, 3,-3, 1,-3, 3}, + { 1, 1,-1,-3,-1,-3, 1,-1, 1, 3,-1, 1}, + { 1, 1, 3, 1, 3, 3,-1, 1,-1,-3,-3, 1}, + { 1,-3, 3, 3, 1, 3, 3, 1,-3,-1,-1, 3}, + { 1, 3,-3,-3, 3,-3, 1,-1,-1, 3,-1,-3}, + {-3,-1,-3,-1,-3, 3, 1,-1, 1, 3,-3,-3}, + {-1, 3,-3, 3,-1, 3, 3,-3, 3, 3,-1,-1}, + { 3,-3,-3,-1,-1,-3,-1, 3,-3, 3, 1,-1}}; + +// Phi values for M_sc=24 Table 5.5.1.2-2 in 36.211 +int phi_M_sc_24[30][24] = {{-1, 3, 1,-3, 3,-1, 1, 3,-3, 3, 1, 3,-3, 3, 1, 1,-1, 1, 3,-3, 3,-3,-1,-3}, + {-3, 3,-3,-3,-3, 1,-3,-3, 3,-1, 1, 1, 1, 3, 1,-1, 3,-3,-3, 1, 3, 1, 1,-3}, + { 3,-1, 3, 3, 1, 1,-3, 3, 3, 3, 3, 1,-1, 3,-1, 1, 1,-1,-3,-1,-1, 1, 3, 3}, + {-1,-3, 1, 1, 3,-3, 1, 1,-3,-1,-1, 1, 3, 1, 3, 1,-1, 3, 1, 1,-3,-1,-3,-1}, + {-1,-1,-1,-3,-3,-1, 1, 1, 3, 3,-1, 3,-1, 1,-1,-3, 1,-1,-3,-3, 1,-3,-1,-1}, + {-3, 1, 1, 3,-1, 1, 3, 1,-3, 1,-3, 1, 1,-1,-1, 3,-1,-3, 3,-3,-3,-3, 1, 1}, + { 1, 1,-1,-1, 3,-3,-3, 3,-3, 1,-1,-1, 1,-1, 1, 1,-1,-3,-1, 1,-1, 3,-1,-3}, + {-3, 3, 3,-1,-1,-3,-1, 3, 1, 3, 1, 3, 1, 1,-1, 3, 1,-1, 1, 3,-3,-1,-1, 1}, + {-3, 1, 3,-3, 1,-1,-3, 3,-3, 3,-1,-1,-1,-1, 1,-3,-3,-3, 1,-3,-3,-3, 1,-3}, + { 1, 1,-3, 3, 3,-1,-3,-1, 3,-3, 3, 3, 3,-1, 1, 1,-3, 1,-1, 1, 1,-3, 1, 1}, + {-1, 1,-3,-3, 3,-1, 3,-1,-1,-3,-3,-3,-1,-3,-3, 1,-1, 1, 3, 3,-1, 1,-1, 3}, + { 1, 3, 3,-3,-3, 1, 3, 1,-1,-3,-3,-3, 3, 3,-3, 3, 3,-1,-3, 3,-1, 1,-3, 1}, + { 1, 3, 3, 1, 1, 1,-1,-1, 1,-3, 3,-1, 1, 1,-3, 3, 3,-1,-3, 3,-3,-1,-3,-1}, + { 3,-1,-1,-1,-1,-3,-1, 3, 3, 1,-1, 1, 3, 3, 3,-1, 1, 1,-3, 1, 3,-1,-3, 3}, + {-3,-3, 3, 1, 3, 1,-3, 3, 1, 3, 1, 1, 3, 3,-1,-1,-3, 1,-3,-1, 3, 1, 1, 3}, + {-1,-1, 1,-3, 1, 3,-3, 1,-1,-3,-1, 3, 1, 3, 1,-1,-3,-3,-1,-1,-3,-3,-3,-1}, + {-1,-3, 3,-1,-1,-1,-1, 1, 1,-3, 3, 1, 3, 3, 1,-1, 1,-3, 1,-3, 1, 1,-3,-1}, + { 1, 3,-1, 3, 3,-1,-3, 1,-1,-3, 3, 3, 3,-1, 1, 1, 3,-1,-3,-1, 3,-1,-1,-1}, + { 1, 1, 1, 1, 1,-1, 3,-1,-3, 1, 1, 3,-3, 1,-3,-1, 1, 1,-3,-3, 3, 1, 1,-3}, + { 1, 3, 3, 1,-1,-3, 3,-1, 3, 3, 3,-3, 1,-1, 1,-1,-3,-1, 1, 3,-1, 3,-3,-3}, + {-1,-3, 3,-3,-3,-3,-1,-1,-3,-1,-3, 3, 1, 3,-3,-1, 3,-1, 1,-1, 3,-3, 1,-1}, + {-3,-3, 1, 1,-1, 1,-1, 1,-1, 3, 1,-3,-1, 1,-1, 1,-1,-1, 3, 3,-3,-1, 1,-3}, + {-3,-1,-3, 3, 1,-1,-3,-1,-3,-3, 3,-3, 3,-3,-1, 1, 3, 1,-3, 1, 3, 3,-1,-3}, + {-1,-1,-1,-1, 3, 3, 3, 1, 3, 3,-3, 1, 3,-1, 3,-1, 3, 3,-3, 3, 1,-1, 3, 3}, + { 1,-1, 3, 3,-1,-3, 3,-3,-1,-1, 3,-1, 3,-1,-1, 1, 1, 1, 1,-1,-1,-3,-1, 3}, + { 1,-1, 1,-1, 3,-1, 3, 1, 1,-1,-1,-3, 1, 1,-3, 1, 3,-3, 1, 1,-3,-3,-1,-1}, + {-3,-1, 1, 3, 1, 1,-3,-1,-1,-3, 3,-3, 3, 1,-3, 3,-3, 1,-1, 1,-3, 1, 1, 1}, + {-1,-3, 3, 3, 1, 1, 3,-1,-3,-1,-1,-1, 3, 1,-3,-3,-1, 3,-3,-1,-3,-1,-3,-1}, + {-1,-3,-1,-1, 1,-3,-1,-1, 1,-1,-3, 1, 1,-3, 1,-3,-3, 3, 1, 1,-1, 3,-1,-1}, + { 1, 1,-1,-1,-3,-1, 3,-1, 3,-1, 1, 3, 1,-1, 3, 1, 3,-3,-3, 1,-1,-1, 1, 3}}; + +// Prime numbers used for Section 5.5.1.1 of 36.211 +#define NOF_PRIME_NUMBERS 309 +uint32_t prime_numbers[NOF_PRIME_NUMBERS] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997,1009,1013, + 1019,1021,1031,1033,1039,1049,1051,1061,1063,1069, + 1087,1091,1093,1097,1103,1109,1117,1123,1129,1151, + 1153,1163,1171,1181,1187,1193,1201,1213,1217,1223, + 1229,1231,1237,1249,1259,1277,1279,1283,1289,1291, + 1297,1301,1303,1307,1319,1321,1327,1361,1367,1373, + 1381,1399,1409,1423,1427,1429,1433,1439,1447,1451, + 1453,1459,1471,1481,1483,1487,1489,1493,1499,1511, + 1523,1531,1543,1549,1553,1559,1567,1571,1579,1583, + 1597,1601,1607,1609,1613,1619,1621,1627,1637,1657, + 1663,1667,1669,1693,1697,1699,1709,1721,1723,1733, + 1741,1747,1753,1759,1777,1783,1787,1789,1801,1811, + 1823,1831,1847,1861,1867,1871,1873,1877,1879,1889, + 1901,1907,1913,1931,1933,1949,1951,1973,1979,1987, + 1993,1997,1999,2003,2011,2017,2027,2029,2039}; + diff --git a/lte/phy/lib/ch_estimation/test/CMakeLists.txt b/lte/phy/lib/ch_estimation/test/CMakeLists.txt index 8ac180007..859d0c519 100644 --- a/lte/phy/lib/ch_estimation/test/CMakeLists.txt +++ b/lte/phy/lib/ch_estimation/test/CMakeLists.txt @@ -20,13 +20,26 @@ # ######################################################################## -# Channel Estimation TEST +# Downlink Channel Estimation TEST ######################################################################## -ADD_EXECUTABLE(chest_test chest_test.c) -TARGET_LINK_LIBRARIES(chest_test lte_phy) +ADD_EXECUTABLE(chest_test_dl chest_test_dl.c) +TARGET_LINK_LIBRARIES(chest_test_dl lte_phy) + +ADD_TEST(chest_test_dl_cellid0 chest_dl_test -c 0) +ADD_TEST(chest_test_dl_cellid1 chest_dl_test -c 1) +ADD_TEST(chest_test_dl_cellid2 chest_dl_test -c 2) + +######################################################################## +# Uplink Channel Estimation TEST +######################################################################## + +ADD_EXECUTABLE(chest_test_ul chest_test_ul.c) +TARGET_LINK_LIBRARIES(chest_test_ul lte_phy) + +#ADD_TEST(chest_test_ul_cellid0 chest_ul_test -c 0) +#ADD_TEST(chest_test_ul_cellid1 chest_ul_test -c 1) +#ADD_TEST(chest_test_ul_cellid2 chest_ul_test -c 2) -ADD_TEST(chest_test_all_cellids chest_test) -ADD_TEST(chest_test_cellid chest_test -c 1) diff --git a/lte/phy/lib/ch_estimation/test/chest_test.c b/lte/phy/lib/ch_estimation/test/chest_test_dl.c similarity index 100% rename from lte/phy/lib/ch_estimation/test/chest_test.c rename to lte/phy/lib/ch_estimation/test/chest_test_dl.c diff --git a/lte/phy/lib/ch_estimation/test/chest_test_ul.c b/lte/phy/lib/ch_estimation/test/chest_test_ul.c new file mode 100644 index 000000000..72ea85c80 --- /dev/null +++ b/lte/phy/lib/ch_estimation/test/chest_test_ul.c @@ -0,0 +1,249 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include +#include +#include + +#include "liblte/phy/phy.h" + +lte_cell_t cell = { + 6, // nof_prb + MAX_PORTS, // nof_ports + 1000, // cell_id + CPNORM // cyclic prefix +}; + +char *output_matlab = NULL; + +void usage(char *prog) { + printf("Usage: %s [recov]\n", prog); + + printf("\t-r nof_prb [Default %d]\n", cell.nof_prb); + printf("\t-e extended cyclic prefix [Default normal]\n"); + + printf("\t-c cell_id (1000 tests all). [Default %d]\n", cell.id); + + printf("\t-o output matlab file [Default %s]\n",output_matlab?output_matlab:"None"); + printf("\t-v increase verbosity\n"); +} + +void parse_args(int argc, char **argv) { + int opt; + while ((opt = getopt(argc, argv, "recov")) != -1) { + switch(opt) { + case 'r': + cell.nof_prb = atoi(argv[optind]); + break; + case 'e': + cell.cp = CPEXT; + break; + case 'c': + cell.id = atoi(argv[optind]); + break; + case 'o': + output_matlab = argv[optind]; + break; + case 'v': + verbose++; + break; + default: + usage(argv[0]); + exit(-1); + } + } +} + +int check_mse(float mod, float arg, int n_port) { + INFO("mod=%.4f, arg=%.4f, n_port=%d\n", mod, arg, n_port); + switch(n_port) { + case 0: + if (mod > 0.029) { + return -1; + } + if (arg > 0.029) { + return -1; + } + break; + case 1: + if (mod > 0.012) { + return -1; + } + if (arg > 0.012) { + return -1; + } + break; + case 2: + case 3: + if (mod > 3.33) { + return -1; + } + if (arg > 0.63) { + return -1; + } + break; + default: + return -1; + } + return 0; +} + +int main(int argc, char **argv) { + chest_t eq; + cf_t *input = NULL, *ce = NULL, *h = NULL; + refsignal_t refs; + int i, j, n_port, n_slot, cid, num_re; + int ret = -1; + int max_cid; + FILE *fmatlab = NULL; + float mse_mag, mse_phase; + + parse_args(argc,argv); + + if (output_matlab) { + fmatlab=fopen(output_matlab, "w"); + if (!fmatlab) { + perror("fopen"); + goto do_exit; + } + } + + num_re = cell.nof_prb * RE_X_RB * CP_NSYMB(cell.cp); + + input = malloc(num_re * sizeof(cf_t)); + if (!input) { + perror("malloc"); + goto do_exit; + } + h = malloc(num_re * sizeof(cf_t)); + if (!h) { + perror("malloc"); + goto do_exit; + } + ce = malloc(num_re * sizeof(cf_t)); + if (!ce) { + perror("malloc"); + goto do_exit; + } + + if (cell.id == 1000) { + cid = 0; + max_cid = 504; + } else { + cid = cell.id; + max_cid = cell.id; + } + + while(cid <= max_cid) { + cell.id = cid; + if (chest_init_LTEUL(&eq, cell)) { + fprintf(stderr, "Error initializing equalizer\n"); + goto do_exit; + } + + for (n_slot=0;n_slot #include #include #include +#include "liblte/phy/common/sequence.h" + #define Nc 1600 @@ -75,7 +74,7 @@ void generate_prs_c(sequence_t *q, uint32_t seed) { free(x2); } -int sequence_LTEPRS(sequence_t *q, uint32_t len, uint32_t seed) { +int sequence_LTE_pr(sequence_t *q, uint32_t len, uint32_t seed) { if (sequence_init(q, len)) { return LIBLTE_ERROR; } diff --git a/lte/phy/lib/phch/src/sequences.c b/lte/phy/lib/phch/src/sequences.c index 499eb1cd0..fe362e2fe 100644 --- a/lte/phy/lib/phch/src/sequences.c +++ b/lte/phy/lib/phch/src/sequences.c @@ -35,7 +35,7 @@ */ int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, CP_ISNORM(cp)?1920:1728, cell_id); + return sequence_LTE_pr(seq, CP_ISNORM(cp)?1920:1728, cell_id); } /** @@ -43,7 +43,7 @@ int sequence_pbch(sequence_t *seq, lte_cp_t cp, uint32_t cell_id) { */ int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); + return sequence_LTE_pr(seq, 32, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } @@ -52,7 +52,7 @@ int sequence_pcfich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { */ int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); + return sequence_LTE_pr(seq, 12, (nslot/2+1) * (2*cell_id + 1) * 512 + cell_id); } /** @@ -60,7 +60,7 @@ int sequence_phich(sequence_t *seq, uint32_t nslot, uint32_t cell_id) { */ int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, len, (nslot/2) * 512 + cell_id); + return sequence_LTE_pr(seq, len, (nslot/2) * 512 + cell_id); } /** @@ -68,5 +68,5 @@ int sequence_pdcch(sequence_t *seq, uint32_t nslot, uint32_t cell_id, uint32_t l */ int sequence_pdsch(sequence_t *seq, unsigned short rnti, int q, uint32_t nslot, uint32_t cell_id, uint32_t len) { bzero(seq, sizeof(sequence_t)); - return sequence_LTEPRS(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); + return sequence_LTE_pr(seq, len, (rnti<<14) + (q<<13) + ((nslot/2)<<9) + cell_id); }