From f505a753823f0244ef3952203e8063414e28b527 Mon Sep 17 00:00:00 2001 From: ismagom Date: Tue, 11 Nov 2014 18:20:09 +0000 Subject: [PATCH] New equalizer working --- CMakeLists.txt | 2 +- cmake/modules/FindVolk.cmake | 7 +- lte/examples/cell_measurement.c | 18 +- lte/examples/pdsch_enodeb.c | 15 +- .../include/liblte/phy/ch_estimation/cheq.h | 57 ++ .../include/liblte/phy/ch_estimation/chest.h | 238 --------- .../liblte/phy/ch_estimation/chest_dl.h | 47 +- .../liblte/phy/ch_estimation/refsignal.h | 92 ---- .../liblte/phy/ch_estimation/refsignal_dl.h | 16 +- lte/phy/include/liblte/phy/phy.h | 2 - .../include/liblte/phy/resampling/interp.h | 107 ++-- lte/phy/include/liblte/phy/ue/ue_celldetect.h | 2 +- lte/phy/include/liblte/phy/ue/ue_dl.h | 4 +- lte/phy/include/liblte/phy/ue/ue_mib.h | 6 +- lte/phy/include/liblte/phy/ue/ue_sync.h | 2 +- .../include/liblte/phy/utils/convolution.h | 12 + lte/phy/include/liblte/phy/utils/vector.h | 6 +- lte/phy/lib/ch_estimation/src/cheq.c | 53 ++ lte/phy/lib/ch_estimation/src/chest.c | 503 ------------------ lte/phy/lib/ch_estimation/src/chest_dl.c | 325 +++++------ lte/phy/lib/ch_estimation/src/refsignal.c | 382 ------------- lte/phy/lib/ch_estimation/src/refsignal_dl.c | 177 +++--- lte/phy/lib/ch_estimation/src/refsignal_ul.c | 183 +++++++ .../lib/ch_estimation/test/chest_test_dl.c | 11 +- .../ch_estimation/test/chest_test_dl_mex.c | 53 +- lte/phy/lib/phch/test/pbch_file_test.c | 21 +- lte/phy/lib/phch/test/pcfich_file_test.c | 21 +- lte/phy/lib/phch/test/pdcch_file_test.c | 19 +- lte/phy/lib/phch/test/pdsch_file_test.c | 20 +- lte/phy/lib/phch/test/phich_file_test.c | 21 +- lte/phy/lib/resampling/src/interp.c | 302 +++++------ lte/phy/lib/resampling/test/CMakeLists.txt | 2 - .../lib/resampling/test/interp_test_volk.c | 92 ---- lte/phy/lib/ue/src/ue_dl.c | 6 +- lte/phy/lib/ue/src/ue_mib.c | 29 +- lte/phy/lib/utils/src/convolution.c | 39 +- lte/phy/lib/utils/src/vector.c | 34 +- matlab/tests/equalizer_test.m | 20 +- 38 files changed, 1012 insertions(+), 1934 deletions(-) create mode 100644 lte/phy/include/liblte/phy/ch_estimation/cheq.h delete mode 100644 lte/phy/include/liblte/phy/ch_estimation/chest.h delete mode 100644 lte/phy/include/liblte/phy/ch_estimation/refsignal.h create mode 100644 lte/phy/lib/ch_estimation/src/cheq.c delete mode 100644 lte/phy/lib/ch_estimation/src/chest.c delete mode 100644 lte/phy/lib/ch_estimation/src/refsignal.c create mode 100644 lte/phy/lib/ch_estimation/src/refsignal_ul.c delete mode 100644 lte/phy/lib/resampling/test/interp_test_volk.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c166e60e..610e96230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,7 +78,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX) ENDIF(CMAKE_COMPILER_IS_GNUCXX) IF(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-format-extra-args -Winline -Wno-unused-result -Wno-format -std=c99 -D_GNU_SOURCE -g") # IF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=implicit-function-declaration -Wno-error=unused-but-set-variable") # ENDIF(${CMAKE_BUILD_TYPE} STREQUAL "Debug") diff --git a/cmake/modules/FindVolk.cmake b/cmake/modules/FindVolk.cmake index eff504408..d1e554bf2 100644 --- a/cmake/modules/FindVolk.cmake +++ b/cmake/modules/FindVolk.cmake @@ -37,13 +37,15 @@ CHECK_FUNCTION_EXISTS_MATH(volk_32f_s32f_multiply_32f HAVE_VOLK_MULT_FLOAT_FUNCT CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_32f HAVE_VOLK_MAG_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_magnitude_square_32f HAVE_VOLK_MAG_SQUARE_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32f_x2_divide_32f HAVE_VOLK_DIVIDE_FUNCTION) -CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_dot_prod_32fc HAVE_VOLK_DOTPROD_FC_FUNCTION) +CHECK_FUNCTION_EXISTS_MATH(volk_32fc_32f_dot_prod_32fc HAVE_VOLK_DOTPROD_CFC_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_conjugate_dot_prod_32fc HAVE_VOLK_DOTPROD_CONJ_FC_FUNCTION) 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_32f_x2_add_32f HAVE_VOLK_ADD_FLOAT_FUNCTION) CHECK_FUNCTION_EXISTS_MATH(volk_32fc_x2_square_dist_32f HAVE_VOLK_SQUARE_DIST_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) @@ -66,6 +68,9 @@ ENDIF() IF(${HAVE_VOLK_SUB_FLOAT_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_SUB_FLOAT_FUNCTION") ENDIF() +IF(${HAVE_VOLK_ADD_FLOAT_FUNCTION}) + SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_ADD_FLOAT_FUNCTION") +ENDIF() IF(${HAVE_VOLK_MULT2_CONJ_FUNCTION}) SET(VOLK_DEFINITIONS "${VOLK_DEFINITIONS}; HAVE_VOLK_MULT2_CONJ_FUNCTION") ENDIF() diff --git a/lte/examples/cell_measurement.c b/lte/examples/cell_measurement.c index a26c68579..82c3dd41d 100644 --- a/lte/examples/cell_measurement.c +++ b/lte/examples/cell_measurement.c @@ -128,7 +128,7 @@ int main(int argc, char **argv) { void *uhd; ue_dl_t ue_dl; lte_fft_t fft; - chest_t chest; + chest_dl_t chest; uint32_t nframes=0; uint32_t nof_trials = 0; uint32_t sfn = 0; // system frame number @@ -136,6 +136,11 @@ int main(int argc, char **argv) { uint8_t bch_payload[BCH_PAYLOAD_LEN], bch_payload_unpacked[BCH_PAYLOAD_LEN]; uint32_t sfn_offset; float rssi=0, rsrp=0, rsrq=0; + cf_t *nullce[MAX_PORTS]; + + for (int i=0;i + +#include "liblte/config.h" +#include "liblte/phy/common/phy_common.h" + +typedef _Complex float cf_t; + +/** Generic OFDM channel equalizer +*/ + + +LIBLTE_API int cheq_zf(cf_t *input, + cf_t *ce, + cf_t *output, + uint32_t len); + +LIBLTE_API int cheq_mmse(cf_t *input, + cf_t *ce, + cf_t *output, + uint32_t len, + float noise_estimate); + + + +#endif \ No newline at end of file diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest.h b/lte/phy/include/liblte/phy/ch_estimation/chest.h deleted file mode 100644 index 0eb7a4401..000000000 --- a/lte/phy/include/liblte/phy/ch_estimation/chest.h +++ /dev/null @@ -1,238 +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/. - * - */ - - - -#ifndef CHEST_ -#define CHEST_ - -#include - -#include "liblte/config.h" - -#include "liblte/phy/resampling/interp.h" -#include "liblte/phy/ch_estimation/refsignal.h" -#include "liblte/phy/common/phy_common.h" - -typedef _Complex float cf_t; /* this is only a shortcut */ - -typedef void (*interpolate_fnc_t) (cf_t *input, - cf_t *output, - uint32_t M, - uint32_t len, - uint32_t off_st, - uint32_t off_end); - -/** This is an OFDM channel estimator. - * It works with any reference signal pattern, provided by the object - * refsignal_t - * A 2-D filter is used for freq and time channel interpolation. - * - */ - -/* Low-level API */ -typedef struct LIBLTE_API { - uint32_t nof_ports; - uint32_t nof_re; - uint32_t nof_symbols; - - refsignal_t refsignal[MAX_PORTS][NSLOTS_X_FRAME]; - interp_t interp_time[MAX_PORTS]; - interp_t interp_freq[MAX_PORTS]; - -}chest_t; - -LIBLTE_API int chest_init(chest_t *q, - uint32_t nof_re, - uint32_t nof_symbols, - uint32_t nof_ports); - -LIBLTE_API void chest_free(chest_t *q); - -LIBLTE_API int chest_set_nof_ports(chest_t *q, - uint32_t nof_ports); - - -LIBLTE_API float chest_rsrp(chest_t *q, - uint32_t nslot, - uint32_t port_id); - -LIBLTE_API float chest_rsrp_sf(chest_t *q, - uint32_t sf_idx); - -LIBLTE_API float chest_rssi(chest_t *q, - cf_t *input); - -LIBLTE_API float chest_rssi_sf(chest_t *q, - cf_t *input); - -LIBLTE_API float chest_rsrq(chest_t *q, - cf_t *input, - uint32_t nslot, - uint32_t port_id); - -LIBLTE_API float chest_rsrq_sf(chest_t *q, - cf_t *input, - uint32_t sf_idx); - -LIBLTE_API int chest_measure_ref(chest_t *q, - cf_t *input, - uint32_t nslot, - uint32_t port_id, - uint32_t nref); - -LIBLTE_API void chest_measure_slot(chest_t *q, - cf_t *input, - uint32_t nslot); - -LIBLTE_API void chest_measure_sf(chest_t *q, - cf_t *input, - uint32_t sf_idx); - -LIBLTE_API int chest_ce_slot_port(chest_t *q, - cf_t *input, - cf_t *ce, - uint32_t nslot, - uint32_t port_id); - -LIBLTE_API int chest_ce_sf_port(chest_t *q, - cf_t *input, - cf_t *ce, - uint32_t sf_idx, - uint32_t port_id); - -LIBLTE_API int chest_ce_slot(chest_t *q, - cf_t *input, - cf_t *ce[MAX_PORTS], - uint32_t nslot); - -LIBLTE_API int chest_ce_sf(chest_t *q, - cf_t *input, - cf_t *ce[MAX_PORTS], - uint32_t sf_idx); - -LIBLTE_API void chest_fprint(chest_t *q, - FILE *stream, - uint32_t nslot, - uint32_t port_id); - -LIBLTE_API void chest_ref_fprint(chest_t *q, - FILE *stream, - uint32_t nslot, - uint32_t port_id); - -LIBLTE_API void chest_recvsig_fprint(chest_t *q, - FILE *stream, - uint32_t nslot, - uint32_t port_id); - -LIBLTE_API void chest_ce_fprint(chest_t *q, - FILE *stream, - uint32_t nslot, - uint32_t port_id); - -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 */ - -/** TODO: The high-level API has N interfaces, one for each port */ - -typedef struct LIBLTE_API{ - chest_t obj; - struct chest_init { - int nof_symbols; // 7 for normal cp, 6 for extended - int nof_ports; - int nof_prb; - int cell_id; // set to -1 to init at runtime - } init; - cf_t *input; - int in_len; - struct chest_ctrl_in { - int sf_idx; // subframe id in the 10ms frame - } ctrl_in; - cf_t *output[MAX_PORTS]; - int out_len[MAX_PORTS]; -}chest_hl; - -#define DEFAULT_FRAME_SIZE 2048 - -LIBLTE_API int chest_initialize(chest_hl* h); -LIBLTE_API int chest_work(chest_hl* hl); -LIBLTE_API int chest_stop(chest_hl* hl); - -#endif - - - - - - - - diff --git a/lte/phy/include/liblte/phy/ch_estimation/chest_dl.h b/lte/phy/include/liblte/phy/ch_estimation/chest_dl.h index c1f3d23ca..799e40c00 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/chest_dl.h +++ b/lte/phy/include/liblte/phy/ch_estimation/chest_dl.h @@ -39,11 +39,6 @@ #include "liblte/phy/ch_estimation/refsignal_dl.h" #include "liblte/phy/common/phy_common.h" -#define CHEST_RS_AVERAGE_TIME 0 -#define CHEST_RS_AVERAGE_FREQ 3 - - - /** 3GPP LTE Downlink channel estimator and equalizer. * Estimates the channel in the resource elements transmitting references and interpolates for the rest * of the resource grid. @@ -53,19 +48,30 @@ * This object depends on the refsignal_t object for creating the LTE CSR signal. */ +#define CHEST_MAX_FILTER_FREQ_LEN 10 +#define CHEST_MAX_FILTER_TIME_LEN 4 + typedef struct { lte_cell_t cell; refsignal_cs_t csr_signal; cf_t *pilot_estimates[MAX_PORTS]; + cf_t *pilot_estimates_average[MAX_PORTS]; cf_t *pilot_recv_signal[MAX_PORTS]; - cf_t *pilot_symbol_avg; + + uint32_t filter_freq_len; + float filter_freq[CHEST_MAX_FILTER_FREQ_LEN]; + uint32_t filter_time_len; + float filter_time[CHEST_MAX_FILTER_TIME_LEN]; + + cf_t *tmp_freqavg; + cf_t *tmp_timeavg[CHEST_MAX_FILTER_TIME_LEN]; + + interp_linvec_t interp_linvec; + interp_lin_t interp_lin; - interp_t interp_time[MAX_PORTS]; - interp_t interp_freq[MAX_PORTS]; - float rssi; - float rsrq; - float rsrp; + float rsrp[MAX_PORTS]; + float noise_estimate[MAX_PORTS]; } chest_dl_t; @@ -74,6 +80,14 @@ LIBLTE_API int chest_dl_init(chest_dl_t *q, LIBLTE_API void chest_dl_free(chest_dl_t *q); +LIBLTE_API int chest_dl_set_filter_freq(chest_dl_t *q, + float *filter, + uint32_t filter_len); + +LIBLTE_API int chest_dl_set_filter_time(chest_dl_t *q, + float *filter, + uint32_t filter_len); + LIBLTE_API int chest_dl_estimate(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], @@ -85,16 +99,7 @@ LIBLTE_API int chest_dl_estimate_port(chest_dl_t *q, uint32_t sf_idx, uint32_t port_id); -LIBLTE_API int chest_dl_equalize_zf(chest_dl_t *q, - cf_t *input, - cf_t *ce[MAX_PORTS], - cf_t *output); - -LIBLTE_API int chest_dl_equalize_mmse(chest_dl_t *q, - cf_t *input, - cf_t *ce[MAX_PORTS], - float *noise_estimate, - cf_t *output); +LIBLTE_API float chest_dl_get_noise_estimate(chest_dl_t *q); LIBLTE_API float chest_dl_get_rssi(chest_dl_t *q); diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal.h deleted file mode 100644 index 6efb85fa9..000000000 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal.h +++ /dev/null @@ -1,92 +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/. - * - */ - - - -#ifndef REFSIGNAL_ -#define REFSIGNAL_ - - -/* Object to manage reference signals for OFDM channel equalization. - * - * It generates the reference signals for LTE. - * - */ - -#include "liblte/config.h" -#include "liblte/phy/common/phy_common.h" - -typedef _Complex float cf_t; - -typedef struct LIBLTE_API{ - uint32_t time_idx; - uint32_t freq_idx; - cf_t symbol; -}ref_t; - -typedef struct LIBLTE_API{ - uint32_t nof_refs; // number of reference signals - uint32_t *symbols_ref; // symbols with at least one reference - uint32_t nsymbols; // number of symbols with at least one reference - uint32_t voffset; // offset of the first reference in the freq domain - uint32_t nof_prb; - ref_t *refs; - cf_t *ch_est; - cf_t *recv_symbol; -} refsignal_t; - - -typedef struct LIBLTE_API { - float beta; // amplitude scaling - uint32_t delta_ss; // Set to 0 for PUCCH - uint32_t cyclic_shift; - uint32_t cyclic_shift_for_drms; /* From DCI 0. Set to 0 if no PDCCH with DCI 0 for the same TB - or if the initial PUSCH is semi-persisently scheduled or - if the initial PUSCH is scheduled by the RA response grant */ - bool group_hopping_en; - bool sequence_hopping_en; -} refsignal_ul_cfg_t; - - -LIBLTE_API int refsignal_init_LTEDL(refsignal_t *q, - uint32_t port_id, - uint32_t nslot, - lte_cell_t cell); - -LIBLTE_API int refsignal_init_LTEUL_drms_pusch(refsignal_t *q, - uint32_t nof_prb, - uint32_t prb_start, - uint32_t nslot, - lte_cell_t cell, - refsignal_ul_cfg_t *drms_cfg); - -LIBLTE_API void refsignal_free(refsignal_t *q); - -LIBLTE_API int refsignal_put(refsignal_t *q, - cf_t *slot_symbols); - -#endif diff --git a/lte/phy/include/liblte/phy/ch_estimation/refsignal_dl.h b/lte/phy/include/liblte/phy/ch_estimation/refsignal_dl.h index 6b8374572..176a36cf3 100644 --- a/lte/phy/include/liblte/phy/ch_estimation/refsignal_dl.h +++ b/lte/phy/include/liblte/phy/ch_estimation/refsignal_dl.h @@ -41,13 +41,13 @@ typedef _Complex float cf_t; #define REFSIGNAL_NUM_SF(nof_prb, port_id) (((port_id)<2?8:4)*(nof_prb)) #define REFSIGNAL_MAX_NUM_SF(nof_prb) REFSIGNAL_NUM_SF(nof_prb, 0) -#define REFSIGNAL_PILOT_IDX(i,l,ns,cell) (2*cell.nof_prb*((l)+2*((ns)%2))+(i)) +#define REFSIGNAL_PILOT_IDX(i,l,cell) (2*cell.nof_prb*(l)+(i)) /** Cell-Specific Reference Signal */ typedef struct LIBLTE_API { lte_cell_t cell; - cf_t *pilots[NSUBFRAMES_X_FRAME]; // save 2 reference symbols per slot + cf_t *pilots[2][NSUBFRAMES_X_FRAME]; // Saves the reference signal per subframe for ports 0,1 and ports 2,3 } refsignal_cs_t; @@ -58,29 +58,25 @@ LIBLTE_API void refsignal_cs_free(refsignal_cs_t *q); LIBLTE_API int refsignal_cs_put_sf(lte_cell_t cell, uint32_t port_id, - uint32_t sf_idx, cf_t *pilots, cf_t *sf_symbols); LIBLTE_API int refsignal_cs_get_sf(lte_cell_t cell, uint32_t port_id, - uint32_t sf_idx, cf_t *sf_symbols, cf_t *pilots); LIBLTE_API uint32_t refsignal_fidx(lte_cell_t cell, - uint32_t ns, uint32_t l, uint32_t port_id, uint32_t m); -LIBLTE_API uint32_t refsignal_nsymbol(lte_cell_t cell, - uint32_t ns, - uint32_t l); +LIBLTE_API uint32_t refsignal_nsymbol(uint32_t l, + lte_cp_t cp, + uint32_t port_id); LIBLTE_API uint32_t refsignal_cs_v(uint32_t port_id, - uint32_t ns, - uint32_t symbol_id); + uint32_t ref_symbol_idx); LIBLTE_API uint32_t refsignal_cs_nof_symbols(uint32_t port_id); diff --git a/lte/phy/include/liblte/phy/phy.h b/lte/phy/include/liblte/phy/phy.h index ed8152bd5..5709496f0 100644 --- a/lte/phy/include/liblte/phy/phy.h +++ b/lte/phy/include/liblte/phy/phy.h @@ -51,9 +51,7 @@ #include "liblte/phy/common/phy_common.h" #include "liblte/phy/common/fft.h" -#include "liblte/phy/ch_estimation/chest.h" #include "liblte/phy/ch_estimation/chest_dl.h" -#include "liblte/phy/ch_estimation/refsignal.h" #include "liblte/phy/ch_estimation/refsignal_dl.h" #include "liblte/phy/resampling/interp.h" diff --git a/lte/phy/include/liblte/phy/resampling/interp.h b/lte/phy/include/liblte/phy/resampling/interp.h index e2028b22b..64f4251f4 100644 --- a/lte/phy/include/liblte/phy/resampling/interp.h +++ b/lte/phy/include/liblte/phy/resampling/interp.h @@ -34,69 +34,70 @@ typedef _Complex float cf_t; -typedef enum LIBLTE_API {LINEAR} interp_type_t; - -typedef struct LIBLTE_API { - interp_type_t type; - - float *in_mag; - float *in_arg; - float *in_mag0; - float *in_arg0; - float *in_mag1; - float *in_arg1; - - float *out_mag; - float *out_arg; - float *out_arg2; - int16_t *table_idx; - - cf_t *out_cexp; - cf_t *out_prod; - - cf_t *cexptable; - - uint32_t len; - uint32_t M; - -}interp_t; -LIBLTE_API int interp_init(interp_t *q, - interp_type_t type, - uint32_t len, - uint32_t M); +/************* STATIC LINEAR INTERPOLATION FUNCTIONS */ + +LIBLTE_API cf_t interp_linear_onesample(cf_t input0, + cf_t input1); + +LIBLTE_API cf_t interp_linear_onesample_cabs(cf_t input0, + cf_t input1); + +LIBLTE_API void interp_linear_offset_cabs(cf_t *input, + cf_t *output, + uint32_t M, + uint32_t len, + uint32_t off_st, + uint32_t off_end); + +LIBLTE_API void interp_linear_f(float *input, + float *output, + uint32_t M, + uint32_t len); + + + +/* Interpolation between vectors */ + +typedef struct { + cf_t *diff_vec; + uint32_t vector_len; +} interp_linvec_t; -LIBLTE_API void interp_free(interp_t *q); +LIBLTE_API int interp_linear_vector_init(interp_linvec_t *q, + uint32_t vector_len); -LIBLTE_API void interp_run(interp_t *q, - cf_t *input, - cf_t *output); +LIBLTE_API void interp_linear_vector_free(interp_linvec_t *q); -LIBLTE_API void interp_run_offset(interp_t *q, - cf_t *input, - cf_t *output, - uint32_t off_st, - uint32_t off_end); +LIBLTE_API void interp_linear_vector(interp_linvec_t *q, + cf_t *in0, + cf_t *in1, + cf_t *between, + uint32_t M); -LIBLTE_API cf_t interp_linear_onesample(cf_t *input); -LIBLTE_API cf_t interp_linear_onesample2(cf_t *input); -LIBLTE_API void interp_linear_offset(cf_t *input, +/* Interpolation within a vector */ + +typedef struct { + cf_t *diff_vec; + cf_t *diff_vec2; + float *ramp; + uint32_t vector_len; + uint32_t M; +} interp_lin_t; + +LIBLTE_API int interp_linear_init(interp_lin_t *q, + uint32_t vector_len, + uint32_t M); + +LIBLTE_API void interp_linear_free(interp_lin_t *q); + +LIBLTE_API void interp_linear_offset(interp_lin_t *q, + cf_t *input, cf_t *output, - uint32_t M, - uint32_t len, uint32_t off_st, uint32_t off_end); -LIBLTE_API void interp_linear_c(cf_t *input, - cf_t *output, - uint32_t M, - uint32_t len); - -LIBLTE_API void interp_linear_f(float *input, - float *output, - uint32_t M, - uint32_t len); #endif // INTERP_H diff --git a/lte/phy/include/liblte/phy/ue/ue_celldetect.h b/lte/phy/include/liblte/phy/ue/ue_celldetect.h index 7ce2f86c9..83bd5fa42 100644 --- a/lte/phy/include/liblte/phy/ue/ue_celldetect.h +++ b/lte/phy/include/liblte/phy/ue/ue_celldetect.h @@ -33,7 +33,7 @@ #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/ch_estimation/chest_dl.h" #include "liblte/phy/phch/pbch.h" #include "liblte/phy/common/fft.h" diff --git a/lte/phy/include/liblte/phy/ue/ue_dl.h b/lte/phy/include/liblte/phy/ue/ue_dl.h index 17a144a1b..00f5b7f3b 100644 --- a/lte/phy/include/liblte/phy/ue/ue_dl.h +++ b/lte/phy/include/liblte/phy/ue/ue_dl.h @@ -36,7 +36,7 @@ -#include "liblte/phy/ch_estimation/chest.h" +#include "liblte/phy/ch_estimation/chest_dl.h" #include "liblte/phy/common/fft.h" #include "liblte/phy/common/phy_common.h" @@ -64,7 +64,7 @@ typedef struct LIBLTE_API { pdsch_harq_t harq_process[NOF_HARQ_PROCESSES]; regs_t regs; lte_fft_t fft; - chest_t chest; + chest_dl_t chest; lte_cell_t cell; diff --git a/lte/phy/include/liblte/phy/ue/ue_mib.h b/lte/phy/include/liblte/phy/ue/ue_mib.h index 3e3f2cb98..45c14e276 100644 --- a/lte/phy/include/liblte/phy/ue/ue_mib.h +++ b/lte/phy/include/liblte/phy/ue/ue_mib.h @@ -51,7 +51,7 @@ #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/ch_estimation/chest_dl.h" #include "liblte/phy/phch/pbch.h" #include "liblte/phy/common/fft.h" @@ -66,11 +66,11 @@ typedef struct LIBLTE_API { sync_t sfind; - cf_t *slot1_symbols; + cf_t *sf_symbols; cf_t *ce[MIB_MAX_PORTS]; lte_fft_t fft; - chest_t chest; + chest_dl_t chest; pbch_t pbch; uint8_t bch_payload[BCH_PAYLOAD_LEN]; diff --git a/lte/phy/include/liblte/phy/ue/ue_sync.h b/lte/phy/include/liblte/phy/ue/ue_sync.h index d1a02d72f..6a9c972d0 100644 --- a/lte/phy/include/liblte/phy/ue/ue_sync.h +++ b/lte/phy/include/liblte/phy/ue/ue_sync.h @@ -33,7 +33,7 @@ #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/ch_estimation/chest_dl.h" #include "liblte/phy/phch/pbch.h" #include "liblte/phy/common/fft.h" diff --git a/lte/phy/include/liblte/phy/utils/convolution.h b/lte/phy/include/liblte/phy/utils/convolution.h index ed9404738..84d2d8d17 100644 --- a/lte/phy/include/liblte/phy/utils/convolution.h +++ b/lte/phy/include/liblte/phy/utils/convolution.h @@ -64,4 +64,16 @@ LIBLTE_API uint32_t conv_cc(cf_t *input, uint32_t input_len, uint32_t filter_len); +LIBLTE_API uint32_t conv_same_cf(cf_t *input, + float *filter, + cf_t *output, + uint32_t input_len, + uint32_t filter_len); + +LIBLTE_API uint32_t conv_same_cc(cf_t *input, + cf_t *filter, + cf_t *output, + uint32_t input_len, + uint32_t filter_len); + #endif // CONVOLUTION_H_ diff --git a/lte/phy/include/liblte/phy/utils/vector.h b/lte/phy/include/liblte/phy/utils/vector.h index 27f3fcc19..81c82b4ce 100644 --- a/lte/phy/include/liblte/phy/utils/vector.h +++ b/lte/phy/include/liblte/phy/utils/vector.h @@ -63,10 +63,12 @@ LIBLTE_API void vec_save_file(char *filename, void *buffer, uint32_t len); /* sum two vectors */ LIBLTE_API void vec_sum_ch(uint8_t *x, uint8_t *y, char *z, uint32_t len); +LIBLTE_API void vec_sum_fff(float *x, float *y, float *z, uint32_t len); LIBLTE_API void vec_sum_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* substract two vectors z=x-y */ LIBLTE_API void vec_sub_fff(float *x, float *y, float *z, uint32_t len); +LIBLTE_API void vec_sub_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* Square distance */ LIBLTE_API void vec_square_dist(cf_t symbol, cf_t *points, float *distance, uint32_t npoints); @@ -91,6 +93,7 @@ LIBLTE_API void vec_prod_cfc(cf_t *x, float *y, cf_t *z, uint32_t len); LIBLTE_API void vec_prod_conj_ccc(cf_t *x, cf_t *y, cf_t *z, uint32_t len); /* Dot-product */ +LIBLTE_API cf_t vec_dot_prod_cfc(cf_t *x, float *y, uint32_t len); LIBLTE_API cf_t vec_dot_prod_ccc(cf_t *x, cf_t *y, uint32_t len); LIBLTE_API cf_t vec_dot_prod_conj_ccc(cf_t *x, cf_t *y, uint32_t len); LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len); @@ -98,9 +101,6 @@ LIBLTE_API float vec_dot_prod_fff(float *x, float *y, uint32_t len); /* z=x/y vector division (element-wise) */ LIBLTE_API void vec_div_ccc(cf_t *x, cf_t *y, float *y_mod, cf_t *z, uint32_t len); -/* z=x/y vector division with mod(y)=1 (element-wise) */ -LIBLTE_API void vec_div_ccc_mod1(cf_t *x, cf_t *y, cf_t *z, uint32_t len); - /* conjugate */ LIBLTE_API void vec_conj_cc(cf_t *x, cf_t *y, uint32_t len); diff --git a/lte/phy/lib/ch_estimation/src/cheq.c b/lte/phy/lib/ch_estimation/src/cheq.c new file mode 100644 index 000000000..c1719892a --- /dev/null +++ b/lte/phy/lib/ch_estimation/src/cheq.c @@ -0,0 +1,53 @@ +/** + * + * \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 "liblte/config.h" + +#include "liblte/phy/ch_estimation/cheq.h" +#include "liblte/phy/utils/vector.h" + + +int cheq_zf(cf_t *input, cf_t *ce, cf_t *output, uint32_t len) +{ + fprintf(stderr, "Not implemented\n"); + return -1; +} + +int cheq_mmse(cf_t *input, cf_t *ce, cf_t *output, uint32_t len, float noise_estimate) +{ + fprintf(stderr, "Not implemented\n"); + return -1; +} diff --git a/lte/phy/lib/ch_estimation/src/chest.c b/lte/phy/lib/ch_estimation/src/chest.c deleted file mode 100644 index 417695899..000000000 --- a/lte/phy/lib/ch_estimation/src/chest.c +++ /dev/null @@ -1,503 +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 "liblte/phy/ch_estimation/chest.h" -#include "liblte/phy/utils/vector.h" -#include "liblte/phy/utils/debug.h" - -#define SLOT_SZ(q) (q->nof_symbols * q->symbol_sz) -#define SF_SZ(q) (2 * SLOT_SZ(q)) - -#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); - chest_recvsig_fprint(q, stream, nslot, port_id); - chest_ce_fprint(q, stream, nslot, port_id); -} - -/* Sets the number of ports to estimate. nof_ports must be smaler than nof_ports - * used during the call to chest_init(). - */ -int chest_set_nof_ports(chest_t *q, uint32_t nof_ports) { - if (nof_ports < q->nof_ports) { - q->nof_ports = nof_ports; - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} - -void chest_ref_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { - int i; - fprintf(stream, "refs%d=[",port_id); - for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { - fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].refs[i].symbol, - __imag__ q->refsignal[port_id][nslot].refs[i].symbol); - } - fprintf(stream, "];\n"); -} - -void chest_recvsig_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { - int i; - fprintf(stream, "recvsig%d=[",port_id); - for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { - fprintf(stream, "%3.3f%+3.3fi, ", __real__ q->refsignal[port_id][nslot].recv_symbol[i], - __imag__ q->refsignal[port_id][nslot].recv_symbol[i]); - } - fprintf(stream, "];\n"); -} - -void chest_ce_fprint(chest_t *q, FILE *stream, uint32_t nslot, uint32_t port_id) { - int i; - fprintf(stream, "mag%d=[",port_id); - for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { - fprintf(stream, "%3.3f, ", cabsf(q->refsignal[port_id][nslot].ch_est[i])); - } - fprintf(stream, "];\nphase%d=[",port_id); - for (i=0;irefsignal[port_id][nslot].nof_refs;i++) { - fprintf(stream, "%3.3f, ", atan2f(__imag__ q->refsignal[port_id][nslot].ch_est[i], - __real__ q->refsignal[port_id][nslot].ch_est[i])); - } - fprintf(stream, "];\n"); -} - -float chest_rsrp(chest_t *q, uint32_t nslot, uint32_t port_id) { - int nof_refs = q->refsignal[port_id][nslot].nof_refs; - cf_t *ch_est = q->refsignal[port_id][nslot].ch_est; - return crealf(vec_dot_prod_conj_ccc(ch_est, ch_est, nof_refs))/nof_refs; -} - -float chest_rsrp_sf(chest_t *q, uint32_t sf_idx) { - int n,p; - float rsrp=0; - for (p=0;pnof_ports;p++) { - for (n=0;n<2;n++) { - rsrp+=chest_rsrp(q, 2*sf_idx+n, p)/(2*q->nof_ports); - } - } - return rsrp; -} - -float chest_rssi(chest_t *q, cf_t *input) { - float rssi = 0; - int i; - int l[2]; - if (q->nof_symbols == CPNORM_NSYMB) { - l[0] = 0; l[1] = 4; - } else { - l[0] = 0; l[1] = 3; - } - - for (i=0;i<2;i++) { - cf_t *tmp = &input[l[i]*q->nof_re]; - rssi += crealf(vec_dot_prod_conj_ccc(tmp, tmp, q->nof_re)); - } - return rssi; -} - -float chest_rssi_sf(chest_t *q, cf_t *input) { - int n; - int slotsz = q->nof_symbols*q->nof_re; - float rssi=0; - for (n=0;n<2;n++) { - rssi += chest_rssi(q, &input[n*slotsz]); - } - return rssi; -} - -float chest_rsrq(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id) { - return (q->nof_re/RE_X_RB) * chest_rsrp(q, nslot, port_id) / chest_rssi(q, input); -} - -float chest_rsrq_sf(chest_t *q, cf_t *input, uint32_t sf_idx) { - return (4*q->nof_ports*q->nof_re/RE_X_RB) * chest_rsrp_sf(q, sf_idx) / chest_rssi_sf(q, input); -} - -int chest_measure_ref(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id, uint32_t nref) { - int fidx, tidx; - cf_t known_ref, channel_ref; - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - input != NULL && - nslot < NSLOTS_X_FRAME && - port_id < q->nof_ports) - { - if (nref < q->refsignal[port_id][nslot].nof_refs) { - - fidx = q->refsignal[port_id][nslot].refs[nref].freq_idx; // reference frequency index - tidx = q->refsignal[port_id][nslot].refs[nref].time_idx; // reference time index - - known_ref = q->refsignal[port_id][nslot].refs[nref].symbol; - channel_ref = input[tidx * q->nof_re + fidx]; - q->refsignal[port_id][nslot].recv_symbol[nref] = channel_ref; - - DEBUG("Reference %2d pos (%2d,%2d)=%3d %.2f dB %.2f/%.2f=%.2f\n", nref, tidx, fidx, tidx * q->nof_re + fidx, - 10*log10f(cabsf(channel_ref/known_ref)), - 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] = 1e-6; - } - ret = LIBLTE_SUCCESS; - } - } - return ret; -} - -void chest_measure_slot_port(chest_t *q, cf_t *input, uint32_t nslot, uint32_t port_id) -{ - int i; - refsignal_t *r = &q->refsignal[port_id][nslot]; - - DEBUG("Estimating channel slot=%d port=%d using %d reference signals\n", - nslot, port_id, r->nof_refs); - - for (i=0;inof_refs;i++) { - chest_measure_ref(q, input, nslot, port_id, i); - } -} - -void chest_measure_slot(chest_t *q, cf_t *input, uint32_t nslot) { - int p; - for (p=0;pnof_ports;p++) { - chest_measure_slot_port(q, input, nslot, p); - } -} - -void chest_measure_sf(chest_t *q, cf_t *input, uint32_t sf_idx) { - int p, n, slotsz; - slotsz = q->nof_symbols*q->nof_re; - for (p=0;pnof_ports;p++) { - for (n=0;n<2;n++) { - chest_measure_slot_port(q, &input[n*slotsz], 2*sf_idx+n, p); - } - } -} - - -/* Computes channel estimates for each reference in a slot and port. - * Saves the nof_prb * 12 * nof_symbols channel estimates in the array ce - */ -int chest_ce_slot_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t nslot, uint32_t port_id) -{ - uint32_t i, j; - cf_t x[2], y[MAX_NSYMB]; - - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - input != NULL && - nslot < NSLOTS_X_FRAME && - port_id < q->nof_ports) - { - if (q->refsignal[port_id][nslot].nsymbols <= 2) { - refsignal_t *r = &q->refsignal[port_id][nslot]; - - chest_measure_slot_port(q, input, nslot, port_id); - - /* interpolate the symbols with references - * in the freq domain */ - for (i=0;insymbols;i++) { -#ifdef VOLK_INTERP - interp_run_offset(&q->interp_freq[port_id], - &r->ch_est[i * r->nof_refs/2], &ce[r->symbols_ref[i] * q->nof_re], - r->voffset, RE_X_RB/2-r->voffset); -#else - interp_linear_offset(&r->ch_est[i * r->nof_refs/2], - &ce[r->symbols_ref[i] * q->nof_re], RE_X_RB/2, - r->nof_refs/2, r->voffset, RE_X_RB/2-r->voffset); -#endif - } - /* now interpolate in the time domain */ - for (i=0;inof_re; i++) { - if (r->nsymbols > 1) { - for (j=0;jnsymbols;j++) { - x[j] = ce[r->symbols_ref[j] * q->nof_re + i]; - } -#ifdef VOLK_INTERP - interp_run_offset(&q->interp_time[port_id], x, y, - r->symbols_ref[0], 3); -#else - interp_linear_offset(x, y, r->symbols_ref[1]-r->symbols_ref[0], - 2, r->symbols_ref[0], 3); -#endif - } else { - for (j=0;jsymbols_ref[0] * q->nof_re + i]; - } - } - for (j=0;jnof_symbols;j++) { - ce[j * q->nof_re + i] = y[j]; - } - } - ret = LIBLTE_SUCCESS; - } - } - return ret; -} - - -/* Computes channel estimates for each reference in a subframe and port id. - */ -int chest_ce_sf_port(chest_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) { - int n, slotsz, ret; - slotsz = q->nof_symbols*q->nof_re; - for (n=0;n<2;n++) { - ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[n*slotsz], 2*sf_idx+n, port_id); - if (ret != LIBLTE_SUCCESS) { - return ret; - } - } - return LIBLTE_SUCCESS; -} - -/* Computes channel estimates for each reference in a slot for all ports. - */ -int chest_ce_slot(chest_t *q, cf_t *input, cf_t **ce, uint32_t nslot) { - int p, ret; - for (p=0;pnof_ports;p++) { - ret = chest_ce_slot_port(q, input, ce[p], nslot, p); - if (ret != LIBLTE_SUCCESS) { - return ret; - } - } - return LIBLTE_SUCCESS; -} - -/* Computes channel estimates for each reference in a subframe for all ports. - */ -int chest_ce_sf(chest_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t sf_idx) { - int p, n, slotsz, ret; - slotsz = q->nof_symbols*q->nof_re; - for (p=0;pnof_ports;p++) { - for (n=0;n<2;n++) { - ret = chest_ce_slot_port(q, &input[n*slotsz], &ce[p][n*slotsz], 2*sf_idx+n, p); - if (ret != LIBLTE_SUCCESS) { - return ret; - } - } - } - return LIBLTE_SUCCESS; -} - -int chest_init(chest_t *q, uint32_t nof_re, uint32_t nof_symbols, uint32_t nof_ports) { - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && - nof_ports <= MAX_PORTS) - { - bzero(q, sizeof(chest_t)); - - q->nof_ports = nof_ports; - q->nof_symbols = nof_symbols; - q->nof_re = nof_re; - - INFO("Initializing channel estimator size %dx%d, nof_ports=%d\n", - q->nof_symbols, q->nof_re, nof_ports); - - ret = LIBLTE_SUCCESS; - } - 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_set_LTEDL(q, 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 && - port_id < MAX_PORTS && - nslot < NSLOTS_X_FRAME) - { - 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); - if (ret == LIBLTE_SUCCESS) { - ret = interp_init(&q->interp_time[port_id], LINEAR, 2, - q->refsignal[port_id][nslot].symbols_ref[1] - q->refsignal[port_id][nslot].symbols_ref[0]); - } - } - } -#endif - } - return ret; -} - -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_set_LTEDL_slot_port(q, nslot, p, cell); - if (ret != LIBLTE_SUCCESS) { - return ret; - } - } - return LIBLTE_SUCCESS; -} - -int chest_ref_set_LTEDL(chest_t *q, lte_cell_t cell) { - int n, ret; - for (n=0;ninit.nof_symbols) { - h->init.nof_symbols = CPNORM_NSYMB; // Normal CP - } - if (!h->init.nof_prb) { - h->init.nof_prb = 6; - } - - cell.id = h->init.cell_id; - cell.nof_ports = h->init.nof_ports; - cell.nof_prb = h->init.nof_prb; - cell.cp = h->init.nof_symbols == CPNORM_NSYMB ? CPNORM : CPEXT; - - if (chest_init_LTEDL(&h->obj, cell)) { - fprintf(stderr, "Error initializing equalizer\n"); - return -1; - } - - return 0; -} - -/** This function must be called in an subframe basis (1ms) for LTE */ -int chest_work(chest_hl* hl) { - chest_t *q = &hl->obj; - chest_ce_sf(q, hl->input, hl->output, hl->ctrl_in.sf_idx); - return 0; -} - -int chest_stop(chest_hl* hl) { - chest_free(&hl->obj); - return 0; -} - - diff --git a/lte/phy/lib/ch_estimation/src/chest_dl.c b/lte/phy/lib/ch_estimation/src/chest_dl.c index d515fc413..c37afd308 100644 --- a/lte/phy/lib/ch_estimation/src/chest_dl.c +++ b/lte/phy/lib/ch_estimation/src/chest_dl.c @@ -32,13 +32,17 @@ #include #include #include +#include #include "liblte/config.h" #include "liblte/phy/ch_estimation/chest_dl.h" #include "liblte/phy/utils/vector.h" +#include "liblte/phy/utils/convolution.h" + +#define CHEST_RS_AVERAGE_TIME 2 +#define CHEST_RS_AVERAGE_FREQ 3 -//#define VOLK_INTERP /** 3GPP LTE Downlink channel estimator and equalizer. * Estimates the channel in the resource elements transmitting references and interpolates for the rest @@ -63,11 +67,19 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell) goto clean_exit; } - q->pilot_symbol_avg = vec_malloc(sizeof(cf_t) * 2*cell.nof_prb); - if (!q->pilot_symbol_avg) { + q->tmp_freqavg = vec_malloc(sizeof(cf_t) * 2*cell.nof_prb); + if (!q->tmp_freqavg) { perror("malloc"); goto clean_exit; } + for (int i=0;itmp_timeavg[i] = vec_malloc(sizeof(cf_t) * 2*cell.nof_prb); + if (!q->tmp_timeavg[i]) { + perror("malloc"); + goto clean_exit; + } + bzero(q->tmp_timeavg[i], sizeof(cf_t) * 2*cell.nof_prb); + } for (int i=0;ipilot_estimates[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); @@ -75,21 +87,34 @@ int chest_dl_init(chest_dl_t *q, lte_cell_t cell) perror("malloc"); goto clean_exit; } + q->pilot_estimates_average[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); + if (!q->pilot_estimates_average[i]) { + perror("malloc"); + goto clean_exit; + } q->pilot_recv_signal[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(cell.nof_prb)); if (!q->pilot_recv_signal[i]) { perror("malloc"); goto clean_exit; } - #ifdef VOLK_INTERP - ret = interp_init(&q->interp_freq[i], LINEAR, 2*cell.nof_prb, RE_X_RB/2); - if (ret == LIBLTE_SUCCESS) { - ret = interp_init(&q->interp_time[i], LINEAR, 2, CP_NSYMB(cell.cp) - 3); - } - #endif + } + + if (interp_linear_vector_init(&q->interp_linvec, RE_X_RB*cell.nof_prb)) { + fprintf(stderr, "Error initializing vector interpolator\n"); + goto clean_exit; + } + if (interp_linear_init(&q->interp_lin, 2*cell.nof_prb, RE_X_RB/2)) { + fprintf(stderr, "Error initializing interpolator\n"); + goto clean_exit; } - /* Init buffer for holding CE estimates averages */ + /* Set default time/freq filters */ + float f[3]={0.15, 0.7, 0.15}; + chest_dl_set_filter_freq(q, f, 3); + + float t[2]={0.1, 0.9}; + chest_dl_set_filter_time(q, t, 2); q->cell = cell; } @@ -107,10 +132,13 @@ void chest_dl_free(chest_dl_t *q) { refsignal_cs_free(&q->csr_signal); - if (q->pilot_symbol_avg) { - free(q->pilot_symbol_avg); + if (q->tmp_freqavg) { + free(q->tmp_freqavg); } + interp_linear_vector_free(&q->interp_linvec); + interp_linear_free(&q->interp_lin); + for (int i=0;ipilot_estimates[i]) { free(q->pilot_estimates[i]); @@ -118,166 +146,163 @@ void chest_dl_free(chest_dl_t *q) if (q->pilot_recv_signal[i]) { free(q->pilot_recv_signal[i]); } - #ifdef VOLK_INTERP - interp_free(&q->interp_freq[i]); - interp_free(&q->interp_time[i]); - #endif } } -#define pilot_est(idx) q->pilot_estimates[port_id][REFSIGNAL_PILOT_IDX(idx,l,ns,q->cell)] +int chest_dl_set_filter_freq(chest_dl_t *q, float *filter, uint32_t filter_len) { + if (filter_len <= CHEST_MAX_FILTER_FREQ_LEN) { + q->filter_freq_len = filter_len; + for (int i=0;ifilter_freq[i] = filter[i]; + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR; + } +} + +int chest_dl_set_filter_time(chest_dl_t *q, float *filter, uint32_t filter_len) { + if (filter_len <= CHEST_MAX_FILTER_TIME_LEN) { + q->filter_time_len = filter_len; + for (int i=0;ifilter_time[i] = filter[i]; + } + return LIBLTE_SUCCESS; + } else { + return LIBLTE_ERROR; + } +} -#if CHEST_RS_AVERAGE_TIME > 1 -cf_t timeavg[CHEST_RS_AVERAGE_TIME-1][12]; -int nof_timeavg=0; -#endif +#define pilot_est(idx) q->pilot_estimates[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)] +#define pilot_avg(idx) q->pilot_estimates_average[port_id][REFSIGNAL_PILOT_IDX(idx,l,q->cell)] -static void average_pilots(chest_dl_t *q, uint32_t sf_idx, uint32_t port_id) +static void average_pilots(chest_dl_t *q, uint32_t port_id) { - uint32_t ns, l; - int i; - /* For each symbol with pilots in a slot */ - for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - for (l=0;lpilot_symbol_avg, 2*q->cell.nof_prb); + int nref=2*q->cell.nof_prb; + uint32_t l, i; - /** Frequency average */ -#if CHEST_RS_AVERAGE_FREQ > 1 - const uint32_t M = CHEST_RS_AVERAGE_FREQ; - cf_t xint[CHEST_RS_AVERAGE_FREQ]; - int j, k; - /* Extrapolate first M/2 samples */ - for (i=M/2-1;i>=0;i--) { - k=0; - for (j=i+M/2;j>=0;j--) { - xint[k]=pilot_est(j); - k++; - } - for (;j>=i-M/2;j--) { - if (k>=2) { - xint[k] = interp_linear_onesample(&xint[k-2]); - k++; - } - } - q->pilot_symbol_avg[i] = vec_acc_cc(xint,M)/M; - //q->pilot_symbol_avg[i] = (pilot_est(0)+pilot_est(1))/2; - } + /* For each symbol with pilots in a slot */ + for (l=0;lfilter_freq_len > 0) { + /* Filter pilot estimates in frequency */ + conv_same_cf(&pilot_est(0), q->filter_freq, q->tmp_freqavg, nref, q->filter_freq_len); - for (i=M/2;i<2*q->cell.nof_prb-M/2;i++) { - q->pilot_symbol_avg[i] = vec_acc_cc(&pilot_est(i-M/2),M)/M; + /* Adjust extremes using linear interpolation */ + q->tmp_freqavg[0] += interp_linear_onesample(pilot_est(1), pilot_est(0)) + * q->filter_freq[q->filter_freq_len/2-1]; + q->tmp_freqavg[nref-1] += interp_linear_onesample(pilot_est(nref-2), pilot_est(nref-1)) + * q->filter_freq[q->filter_freq_len/2+1]; + } else { + memcpy(q->tmp_freqavg, &pilot_est(0), nref * sizeof(cf_t)); + } + + /* Filter in time domain. */ + if (q->filter_time_len > 0) { + /* Move last symbols */ + for (i=0;ifilter_time_len-1;i++) { + memcpy(q->tmp_timeavg[i], q->tmp_timeavg[i+1], nref*sizeof(cf_t)); } + /* Put last symbol to buffer */ + memcpy(q->tmp_timeavg[i], q->tmp_freqavg, nref*sizeof(cf_t)); - /* Extrapolate last M/2 samples */ - for (;i<2*q->cell.nof_prb;i++) { - k=0; - for (j=i-M/2;j<2*q->cell.nof_prb;j++) { - xint[k]=pilot_est(j); - k++; - } - for (;k=2) { - xint[k] = interp_linear_onesample(&xint[k-2]); - } - } - q->pilot_symbol_avg[i] = vec_acc_cc(xint,M)/M; - //q->pilot_symbol_avg[i] = (pilot_est(i)+pilot_est(i+1))/2; - + /* Multiply all symbols by filter and add them */ + bzero(&pilot_avg(0), nref * sizeof(cf_t)); + for (i=0;ifilter_time_len;i++) { + vec_sc_prod_cfc(q->tmp_timeavg[i], q->filter_time[i], q->tmp_timeavg[i], nref); + vec_sum_ccc(q->tmp_timeavg[i], &pilot_avg(0), &pilot_avg(0), nref); } -#else - memcpy(q->pilot_symbol_avg, &pilot_est(0), 2*q->cell.nof_prb*sizeof(cf_t)); -#endif - - /* Time average last symbols */ -#if CHEST_RS_AVERAGE_TIME > 1 - if (nof_timeavgpilot_symbol_avg, 2*q->cell.nof_prb * sizeof(cf_t)); - nof_timeavg++; - } else { - bzero(&pilot_est(0),2*q->cell.nof_prb*sizeof(cf_t)); - for (i=0;icell.nof_prb); - } - vec_sum_ccc(q->pilot_symbol_avg,&pilot_est(0),&pilot_est(0),2*q->cell.nof_prb); - vec_sc_prod_cfc(&pilot_est(0), 1.0/CHEST_RS_AVERAGE_TIME, &pilot_est(0), 2*q->cell.nof_prb); - for (i=0;icell.nof_prb*sizeof(cf_t)); - } - memcpy(timeavg[i],q->pilot_symbol_avg,2*q->cell.nof_prb*sizeof(cf_t)); - } -#else - memcpy(&pilot_est(0), q->pilot_symbol_avg, 2*q->cell.nof_prb * sizeof(cf_t)); -#endif - + } else { + memcpy(&pilot_avg(0), q->tmp_freqavg, nref * sizeof(cf_t)); } } - } -static void interpolate_pilots(chest_dl_t *q, cf_t *ce, uint32_t sf_idx, uint32_t port_id) +static float estimate_noise_port(chest_dl_t *q, uint32_t port_id) { + /* Use difference between averaged and noisy LS pilot estimates */ + vec_sub_fff((float*) q->pilot_estimates_average[port_id], (float*) q->pilot_estimates[port_id], + (float*) q->pilot_estimates[port_id], 2*REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + /* compute noise power */ + float noiseEst = vec_dot_prod_conj_ccc(q->pilot_estimates[port_id], + q->pilot_estimates[port_id], + REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); + + return noiseEst * sqrtf((float) q->filter_freq_len) / REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); +} + +#define cesymb(i) ce[SAMPLE_IDX(q->cell.nof_prb,i,0)] + +static void interpolate_pilots(chest_dl_t *q, cf_t *ce, uint32_t port_id) { /* interpolate the symbols with references in the freq domain */ - uint32_t ns, l, i,j; - cf_t x[2], y[MAX_NSYMB]; - - for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - for (l=0;lcell, ns, l, port_id, 0); -#ifdef VOLK_INTERP - interp_run_offset(&q->interp_freq[port_id], - &q->pilot_estimates[port_id][((ns%2)*2+l)*2*q->cell.nof_prb], - &ce[refsignal_nsymbol(q->cell,ns,l) * q->cell.nof_prb * RE_X_RB], - fidx_offset, RE_X_RB/2-fidx_offset); -#else - interp_linear_offset(&q->pilot_estimates[port_id][((ns%2)*2+l)*2*q->cell.nof_prb], - &ce[refsignal_nsymbol(q->cell,ns,l) * q->cell.nof_prb * RE_X_RB], RE_X_RB/2, - 2*q->cell.nof_prb, fidx_offset, RE_X_RB/2-fidx_offset); -#endif - } + uint32_t l; + uint32_t nsymbols = refsignal_cs_nof_symbols(port_id); + + /* Interpolate in the frequency domain */ + for (l=0;lcell, l, port_id, 0); + interp_linear_offset(&q->interp_lin, &pilot_avg(0), + &ce[refsignal_nsymbol(l,q->cell.cp, port_id) * q->cell.nof_prb * RE_X_RB], + fidx_offset, RE_X_RB/2-fidx_offset); } - /* now interpolate in the time domain */ - for (i=0;icell.nof_prb; i++) { - if (refsignal_cs_nof_symbols(port_id) > 1) { - for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - j=0; - for (l=0;lcell,ns,l) * q->cell.nof_prb * RE_X_RB + i]; - j++; - } - #ifdef VOLK_INTERP - interp_run_offset(&q->interp_time[port_id], x, y, - 0, CP_NSYMB(q->cell.cp) - 4); - #else - interp_linear_offset(x, y, CP_NSYMB(q->cell.cp) - 3, - 2, 0, CP_NSYMB(q->cell.cp) - 4); - #endif - for (j=0;jcell.cp);j++) { - ce[(j+((ns%2)*CP_NSYMB(q->cell.cp))) * q->cell.nof_prb*RE_X_RB + i] = y[j]; - } - } - } else { - fprintf(stderr, "3/4 Ports interpolator not implemented\n"); - exit(-1); - } + + /* Now interpolate in the time domain between symbols */ + if (nsymbols == 4) { + interp_linear_vector(&q->interp_linvec, &cesymb(0), &cesymb(4), &cesymb(1), 3); + interp_linear_vector(&q->interp_linvec, &cesymb(4), &cesymb(7), &cesymb(5), 2); + interp_linear_vector(&q->interp_linvec, &cesymb(7), &cesymb(11), &cesymb(8), 3); + interp_linear_vector(&q->interp_linvec, &cesymb(7), &cesymb(11), &cesymb(12), 2); + } else { + interp_linear_vector(&q->interp_linvec, &cesymb(8), &cesymb(1), &cesymb(0), 1); + interp_linear_vector(&q->interp_linvec, &cesymb(1), &cesymb(8), &cesymb(2), 6); + interp_linear_vector(&q->interp_linvec, &cesymb(1), &cesymb(8), &cesymb(9), 5); + } + +} + +float chest_dl_rssi(lte_cell_t cell, cf_t *input) { + float rssi = 0; + uint32_t l, p; + uint32_t loop_ports = cell.nof_ports>2?2:1; + + for (p=0;ppilot_estimates_average[port_id], + q->pilot_estimates_average[port_id], + REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id))) + / REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id); } int chest_dl_estimate_port(chest_dl_t *q, cf_t *input, cf_t *ce, uint32_t sf_idx, uint32_t port_id) { - //filter2d_reset(&q->filter); - /* Get references from the input signal */ - refsignal_cs_get_sf(q->cell, port_id, sf_idx, input, q->pilot_recv_signal[port_id]); + refsignal_cs_get_sf(q->cell, port_id, input, q->pilot_recv_signal[port_id]); /* Use the known CSR signal to compute Least-squares estimates */ - vec_div_ccc_mod1(q->pilot_recv_signal[port_id], q->csr_signal.pilots[sf_idx], + vec_prod_conj_ccc(q->pilot_recv_signal[port_id], q->csr_signal.pilots[port_id/2][sf_idx], q->pilot_estimates[port_id], REFSIGNAL_NUM_SF(q->cell.nof_prb, port_id)); /* Average pilot estimates */ - average_pilots(q, sf_idx, port_id); + average_pilots(q, port_id); - /* Interpolate to create channel estimates for all resource grid */ - interpolate_pilots(q, ce, sf_idx, port_id); + /* Compute RSRP for the references in this port */ + q->rsrp[port_id] = chest_dl_rsrp(q, port_id); + /* Interpolate to create channel estimates for all resource grid */ + if (ce != NULL) { + interpolate_pilots(q, ce, port_id); + } + + q->noise_estimate[port_id] = estimate_noise_port(q, port_id); + return 0; } @@ -288,19 +313,13 @@ int chest_dl_estimate(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], uint32_t for (port_id=0;port_idcell.nof_ports;port_id++) { chest_dl_estimate_port(q, input, ce[port_id], sf_idx, port_id); } + /* compute rssi */ + q->rssi = chest_dl_rssi(q->cell, input); return LIBLTE_SUCCESS; } -int chest_dl_equalize_zf(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], cf_t *output) -{ - fprintf(stderr, "Not implemented\n"); - return -1; -} - -int chest_dl_equalize_mmse(chest_dl_t *q, cf_t *input, cf_t *ce[MAX_PORTS], float *noise_estimate, cf_t *output) -{ - fprintf(stderr, "Not implemented\n"); - return -1; +float chest_dl_get_noise_estimate(chest_dl_t *q) { + return vec_acc_ff(q->noise_estimate, q->cell.nof_ports)/q->cell.nof_ports; } float chest_dl_get_rssi(chest_dl_t *q) { @@ -308,10 +327,10 @@ float chest_dl_get_rssi(chest_dl_t *q) { } float chest_dl_get_rsrq(chest_dl_t *q) { - return q->rsrq; + return (4*q->cell.nof_ports*q->cell.nof_prb) * chest_dl_get_rsrp(q) / q->rssi; } float chest_dl_get_rsrp(chest_dl_t *q) { - return q->rsrp; + return vec_acc_ff(q->rsrp, q->cell.nof_ports)/q->cell.nof_ports; } diff --git a/lte/phy/lib/ch_estimation/src/refsignal.c b/lte/phy/lib/ch_estimation/src/refsignal.c deleted file mode 100644 index 2002eb47a..000000000 --- a/lte/phy/lib/ch_estimation/src/refsignal.c +++ /dev/null @@ -1,382 +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/common/phy_common.h" -#include "liblte/phy/ch_estimation/refsignal.h" -#include "liblte/phy/utils/vector.h" -#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; - } - return v; -} - -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) -{ - uint32_t i; - uint32_t fidx, tidx; - if (q != NULL && slot_symbols != NULL) { - for (i = 0; i < q->nof_refs; i++) { - fidx = q->refs[i].freq_idx; // reference frequency index - tidx = q->refs[i].time_idx; // reference time index - slot_symbols[SAMPLE_IDX(q->nof_prb, tidx, fidx)] = q->refs[i].symbol; - } - return LIBLTE_SUCCESS; - } else { - return LIBLTE_ERROR_INVALID_INPUTS; - } -} - -/** 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) -{ - - uint32_t c_init; - uint32_t ns, l, lp[2]; - uint32_t N_cp; - uint32_t i; - int ret = LIBLTE_ERROR_INVALID_INPUTS; - sequence_t seq; - int v; - 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)) { - - bzero(q, sizeof(refsignal_t)); - bzero(&seq, sizeof(sequence_t)); - - if (CP_ISNORM(cell.cp)) { - N_cp = 1; - } else { - N_cp = 0; - } - - if (port_id < 2) { - nof_ref_symbols = 2; - lp[0] = 0; - lp[1] = CP_NSYMB(cell.cp) - 3; - } else { - nof_ref_symbols = 1; - lp[0] = 1; - } - nof_refs_x_symbol = 2 * cell.nof_prb; - - q->nof_refs = nof_refs_x_symbol * nof_ref_symbols; - q->nsymbols = nof_ref_symbols; - q->voffset = cell.id % 6; - q->nof_prb = cell.nof_prb; - - q->symbols_ref = malloc(sizeof(uint32_t) * nof_ref_symbols); - if (!q->symbols_ref) { - perror("malloc"); - goto free_and_exit; - } - - memcpy(q->symbols_ref, lp, sizeof(uint32_t) * nof_ref_symbols); - - 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; - } - - q->recv_symbol = vec_malloc(q->nof_refs * sizeof(cf_t)); - if (!q->recv_symbol) { - goto free_and_exit; - } - - ns = nslot; - for (l = 0; l < nof_ref_symbols; l++) { - - c_init = 1024 * (7 * (ns + 1) + lp[l] + 1) * (2 * cell.id + 1) - + 2 * cell.id + N_cp; - ret = sequence_LTE_pr(&seq, 2 * 2 * MAX_PRB, c_init); - if (ret != LIBLTE_SUCCESS) { - goto free_and_exit; - } - - v = refsignal_v(port_id, ns, lp[l]); - - for (i = 0; i < nof_refs_x_symbol; i++) { - mp = i + MAX_PRB - cell.nof_prb; - - /* generate signal */ - __real__ q->refs[idx(l, i)].symbol = - (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2); - __imag__ q->refs[idx(l, i)].symbol = - (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); - - /* mapping to resource elements */ - q->refs[idx(l, i)].freq_idx = refsignal_k(i, (uint32_t) v, cell.id); - q->refs[idx(l, i)].time_idx = lp[l]; - } - } - ret = LIBLTE_SUCCESS; - } -free_and_exit: - if (ret != LIBLTE_ERROR_INVALID_INPUTS) { - sequence_free(&seq); - } - if (ret == LIBLTE_ERROR) { - refsignal_free(q); - } - return ret; -} - -// n_drms_2 table 5.5.2.1.1-1 from 36.211 -uint32_t n_drms_2[8] = { 0, 6, 3, 4, 2, 8, 10, 9 }; - -// n_drms_1 table 5.5.2.1.1-2 from 36.211 -uint32_t n_drms_1[8] = { 0, 2, 3, 4, 6, 8, 9, 10 }; - - -/* Generation of the reference signal sequence according to Section 5.5.1 of 36.211 */ -int rs_sequence(ref_t * refs, uint32_t len, float alpha, uint32_t ns, uint32_t cell_id, - refsignal_ul_cfg_t * cfg) -{ - uint32_t i; - - // Calculate u and v - uint32_t u, v; - uint32_t f_ss = (((cell_id % 30) + cfg->delta_ss) % 30); - if (cfg->group_hopping_en) { - sequence_t seq; - sequence_LTE_pr(&seq, cell_id / 30, 160); - uint32_t f_gh = 0; - for (i = 0; i < 8; i++) { - f_gh += seq.c[8 * ns + i] << i; - } - sequence_free(&seq); - u = ((f_gh%30) + f_ss) % 30; - } else { - u = f_ss % 30; - } - - if (len < 6 * RE_X_RB) { - v = 0; - } else { - if (!cfg->group_hopping_en && cfg->sequence_hopping_en) { - sequence_t seq; - sequence_LTE_pr(&seq, ((cell_id / 30) << 5) + f_ss, 20); - v = seq.c[ns]; - sequence_free(&seq); - } else { - v = 0; - } - } - if (len >= 3 * RE_X_RB) { - uint32_t n_sz=0; - uint32_t q; - float q_hat; - /* get largest prime n_zc 0; i--) { - if (prime_numbers[i] < len) { - n_sz = prime_numbers[i]; - break; - } - } - q_hat = (float) n_sz *(u + 1) / 31; - if ((((uint32_t) (2 * q_hat)) % 2) == 0) { - q = (uint32_t) (q_hat + 0.5) + v; - } else { - q = (uint32_t) (q_hat + 0.5) - v; - } - cf_t *x_q = malloc(sizeof(cf_t) * n_sz); - if (!x_q) { - perror("malloc"); - return LIBLTE_ERROR; - } - for (i = 0; i < n_sz; i++) { - x_q[i] = - cexpf(-I * M_PI * (float) q * (float) i * ((float) i + 1) / n_sz); - } - for (i = 0; i < len; i++) { - refs[i].symbol = cfg->beta * cexpf(I * alpha * i) * x_q[i % n_sz]; - } - free(x_q); - } else { - if (len == RE_X_RB) { - for (i = 0; i < len; i++) { - refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_12[u][i] * M_PI / 4 + alpha * i)); - } - } else { - for (i = 0; i < len; i++) { - refs[i].symbol = cfg->beta * cexpf(I * (phi_M_sc_24[u][i] * M_PI / 4 + alpha * i)); - } - } - } - - return LIBLTE_SUCCESS; -} - -/** Initializes refsignal_t object according to 3GPP 36.211 5.5.2 - * - */ -int refsignal_init_LTEUL_drms_pusch(refsignal_t * q, uint32_t nof_prb, uint32_t prb_start, - uint32_t nslot, lte_cell_t cell, refsignal_ul_cfg_t * cfg) -{ - - uint32_t i; - int ret = LIBLTE_ERROR_INVALID_INPUTS; - uint32_t n_prs; - uint32_t M_sc; - float alpha; - - if (q != NULL && nslot < NSLOTS_X_FRAME && lte_cell_isvalid(&cell)) { - - bzero(q, sizeof(refsignal_t)); - - M_sc = nof_prb * RE_X_RB; - - q->nof_refs = M_sc; - q->nsymbols = 1; - q->voffset = cell.id % 6; - q->nof_prb = cell.nof_prb; - - q->symbols_ref = malloc(sizeof(uint32_t) * 1); - if (!q->symbols_ref) { - perror("malloc"); - goto free_and_exit; - } - - if (CP_ISNORM(cell.cp)) { - q->symbols_ref[0] = 3; - } else { - q->symbols_ref[0] = 2; - } - - q->refs = vec_malloc(q->nof_refs * sizeof(ref_t)); - if (!q->refs) { - goto free_and_exit; - } - q->ch_est = vec_malloc(q->nof_refs * sizeof(cf_t)); - if (!q->ch_est) { - goto free_and_exit; - } - - /* Calculate n_prs */ - uint32_t c_init; - sequence_t seq; - c_init = ((cell.id / 30) << 5) + (((cell.id % 30) + cfg->delta_ss) % 30); - ret = sequence_LTE_pr(&seq, 8 * CP_NSYMB(cell.cp) * 20, c_init); - if (ret != LIBLTE_SUCCESS) { - goto free_and_exit; - } - n_prs = 0; - for (i = 0; i < 8; i++) { - n_prs += (seq.c[8 * CP_NSYMB(cell.cp) * nslot + i] << i); - } - sequence_free(&seq); - - // Calculate cyclic shift alpha - uint32_t n_cs = - (n_drms_1[cfg->cyclic_shift] + - n_drms_2[cfg->cyclic_shift_for_drms] + n_prs) % 12; - alpha = 2 * M_PI * (n_cs) / 12; - - if (rs_sequence(q->refs, M_sc, alpha, cell.id, nslot, cfg)) { - fprintf(stderr, "Error generating RS sequence\n"); - goto free_and_exit; - } - /* mapping to resource elements */ - for (i=0;irefs[i].freq_idx = prb_start*RE_X_RB + i; - q->refs[i].time_idx = q->symbols_ref[0]; - } - - ret = LIBLTE_SUCCESS; - } -free_and_exit: - if (ret == LIBLTE_ERROR) { - refsignal_free(q); - } - return ret; -} - - -void refsignal_free(refsignal_t * q) -{ - if (q->symbols_ref) { - free(q->symbols_ref); - } - if (q->refs) { - free(q->refs); - } - if (q->ch_est) { - free(q->ch_est); - } - bzero(q, sizeof(refsignal_t)); -} diff --git a/lte/phy/lib/ch_estimation/src/refsignal_dl.c b/lte/phy/lib/ch_estimation/src/refsignal_dl.c index e9d927bc6..5d3d6d690 100644 --- a/lte/phy/lib/ch_estimation/src/refsignal_dl.c +++ b/lte/phy/lib/ch_estimation/src/refsignal_dl.c @@ -38,29 +38,37 @@ #include "liblte/phy/utils/debug.h" #include "liblte/phy/common/sequence.h" -uint32_t refsignal_cs_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) +uint32_t refsignal_cs_v(uint32_t port_id, uint32_t ref_symbol_idx) { uint32_t v = 0; switch (port_id) { case 0: - if (symbol_id == 0) { + if (!(ref_symbol_idx % 2)) { v = 0; } else { v = 3; } break; case 1: - if (symbol_id == 0) { + if (!(ref_symbol_idx % 2)) { v = 3; } else { v = 0; } break; case 2: - v = 3 * (ns % 2); + if (ref_symbol_idx < 2) { + v = 0; + } else { + v = 3; + } break; case 3: - v = 3 + 3 * (ns % 2); + if (ref_symbol_idx < 2) { + v = 3; + } else { + v = 6; + } break; } return v; @@ -68,21 +76,30 @@ uint32_t refsignal_cs_v(uint32_t port_id, uint32_t ns, uint32_t symbol_id) uint32_t refsignal_cs_nof_symbols(uint32_t port_id) { - if (port_id < 2) { - return 2; - } else { - return 1; - } + if (port_id < 2) { + return 4; + } else { + return 2; + } } -static uint32_t lp(uint32_t l, lte_cp_t cp) { - if (l == 1) { - return CP_NSYMB(cp) - 3; +inline uint32_t refsignal_fidx(lte_cell_t cell, uint32_t l, uint32_t port_id, uint32_t m) { + return 6*m + ((refsignal_cs_v(port_id, l) + (cell.id % 6)) % 6); +} + +inline uint32_t refsignal_nsymbol(uint32_t l, lte_cp_t cp, uint32_t port_id) { + if (port_id < 2) { + if (l % 2) { + return (l/2+1)*CP_NSYMB(cp) - 3; + } else { + return (l/2)*CP_NSYMB(cp); + } } else { - return 0; + return 1+l*CP_NSYMB(cp); } } + /** Allocates and precomputes the Cell-Specific Reference (CSR) signal for * the 20 slots in a subframe */ @@ -90,7 +107,7 @@ int refsignal_cs_generate(refsignal_cs_t * q, lte_cell_t cell) { uint32_t c_init; - uint32_t i, ns, l; + uint32_t i, ns, l, p; uint32_t N_cp, mp; sequence_t seq; int ret = LIBLTE_ERROR_INVALID_INPUTS; @@ -114,31 +131,38 @@ int refsignal_cs_generate(refsignal_cs_t * q, lte_cell_t cell) q->cell = cell; - for (i=0;ipilots[i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_MAX_NUM_SF(q->cell.nof_prb)); - if (!q->pilots[i]) { - perror("malloc"); - goto free_and_exit; - } + for (p=0;p<2;p++) { + for (i=0;ipilots[p][i] = vec_malloc(sizeof(cf_t) * REFSIGNAL_NUM_SF(q->cell.nof_prb, 2*p)); + if (!q->pilots[p][i]) { + perror("malloc"); + goto free_and_exit; + } + } } for (ns=0;nscell.nof_prb; i++) { + mp = i + MAX_PRB - cell.nof_prb; + /* save signal */ + q->pilots[p][ns/2][REFSIGNAL_PILOT_IDX(i,(ns%2)*nsymbols+l,q->cell)] = + (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) + + _Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); + } + } - /* generate sequence for this symbol and slot */ - sequence_set_LTE_pr(&seq, c_init); - - /* Compute signal */ - for (i = 0; i < 2*q->cell.nof_prb; i++) { - mp = i + MAX_PRB - cell.nof_prb; - /* save signal */ - q->pilots[ns/2][REFSIGNAL_PILOT_IDX(i,l,ns,q->cell)] = - (1 - 2 * (float) seq.c[2 * mp]) / sqrt(2) + - _Complex_I * (1 - 2 * (float) seq.c[2 * mp + 1]) / sqrt(2); - } } } sequence_free(&seq); @@ -155,51 +179,42 @@ free_and_exit: /** Deallocates a refsignal_cs_t object allocated with refsignal_cs_init */ void refsignal_cs_free(refsignal_cs_t * q) { - int i; + int i, p; - for (i=0;ipilots[i]) { - free(q->pilots[i]); - } - } + for (p=0;p<2;p++) { + for (i=0;ipilots[p][i]) { + free(q->pilots[p][i]); + } + } + } bzero(q, sizeof(refsignal_cs_t)); } -inline uint32_t refsignal_fidx(lte_cell_t cell, uint32_t ns, uint32_t l, uint32_t port_id, uint32_t m) { - return 6*m + ((refsignal_cs_v(port_id, ns, lp(l,cell.cp)) + (cell.id % 6)) % 6); -} - -inline uint32_t refsignal_nsymbol(lte_cell_t cell, uint32_t ns, uint32_t l) { - return (ns%2)*CP_NSYMB(cell.cp)+lp(l,cell.cp); -} - /* Maps a reference signal initialized with refsignal_cs_init() into an array of subframe symbols */ -int refsignal_cs_put_sf(lte_cell_t cell, uint32_t port_id, uint32_t sf_idx, - cf_t *pilots, cf_t *sf_symbols) +int refsignal_cs_put_sf(lte_cell_t cell, uint32_t port_id, cf_t *pilots, cf_t *sf_symbols) { - uint32_t i, l, ns; + uint32_t i, l; uint32_t fidx; if (lte_cell_isvalid(&cell) && - lte_sfidx_isvalid(sf_idx) && lte_portid_isvalid(port_id) && pilots != NULL && sf_symbols != NULL) { - for (ns=2*sf_idx;ns<2*(sf_idx+1);ns++) { - for (l=0;ldelta_ss) % 30); + printf("f_ss: %d\n", f_ss); + if (cfg->group_hopping_en) { + sequence_t seq; + bzero(&seq, sizeof(sequence_t)); + sequence_LTE_pr(&seq, 160, cell_id / 30); + uint32_t f_gh = 0; + for (i = 0; i < 8; i++) { + f_gh += (((uint32_t) seq.c[8 * ns + i]) << i); + } + printf("f_gh: %u\n", f_gh); + 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; + bzero(&seq, sizeof(sequence_t)); + sequence_LTE_pr(&seq, 20, ((cell_id / 30) << 5) + f_ss); + v = seq.c[ns]; + sequence_free(&seq); + } else { + v = 0; + } + } + printf("u: %d, v: %d\n", u, v); + 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; + } + } + printf("n_sz: %d\n", n_sz); + 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; + bzero(&seq, sizeof(sequence_t)); + 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; + + printf("alpha: %g\n", alpha); + + if (rs_sequence(q->refs, M_sc, alpha, nslot, cell.id, 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; +} + +#endif \ No newline at end of file diff --git a/lte/phy/lib/ch_estimation/test/chest_test_dl.c b/lte/phy/lib/ch_estimation/test/chest_test_dl.c index 83abb57f1..08cca66cc 100644 --- a/lte/phy/lib/ch_estimation/test/chest_test_dl.c +++ b/lte/phy/lib/ch_estimation/test/chest_test_dl.c @@ -177,7 +177,7 @@ int main(int argc, char **argv) { bzero(ce, sizeof(cf_t) * num_re); bzero(h, sizeof(cf_t) * num_re); - refsignal_cs_put_sf(cell, n_port, sf_idx, eq.csr_signal.pilots[sf_idx], input); + refsignal_cs_put_sf(cell, n_port, eq.csr_signal.pilots[n_port/2][sf_idx], input); for (i=0;i<2*CP_NSYMB(cell.cp);i++) { for (j=0;j NOF_INPUTS && nsubframes == 10) { + if (nrhs >= NOF_INPUTS + 1) { + filter_len = mxGetNumberOfElements(FREQ_FILTER); + filter = malloc(sizeof(float) * filter_len); + f = (double*) mxGetPr(FREQ_FILTER); + for (i=0;i= NOF_INPUTS + 2) { + filter_len = mxGetNumberOfElements(TIME_FILTER); + filter = malloc(sizeof(float) * filter_len); + f = (double*) mxGetPr(TIME_FILTER); + for (i=0;i= 2) { plhs[1] = mxCreateDoubleMatrix(REFSIGNAL_MAX_NUM_SF(cell.nof_prb)*nsubframes, cell.nof_ports, mxCOMPLEX); outr1 = mxGetPr(plhs[1]); outi1 = mxGetPi(plhs[1]); @@ -150,6 +180,9 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) mexErrMsgTxt("Error running channel estimator\n"); return; } + + noiseAverage[sf]=chest_dl_get_noise_estimate(&chest); + if (nlhs >= 1) { for (i=0;i= 2) { for (int j=0;j= 3) { + plhs[2] = mxCreateDoubleMatrix(1, 1, mxREAL); + outr1 = mxGetPr(plhs[2]); + *outr1 = vec_acc_ff(noiseAverage,10)/10; + } return; diff --git a/lte/phy/lib/phch/test/pbch_file_test.c b/lte/phy/lib/phch/test/pbch_file_test.c index e4d52b459..0ab0bdc7b 100644 --- a/lte/phy/lib/phch/test/pbch_file_test.c +++ b/lte/phy/lib/phch/test/pbch_file_test.c @@ -55,7 +55,7 @@ filesource_t fsrc; cf_t *input_buffer, *fft_buffer, *ce[MAX_PORTS]; pbch_t pbch; lte_fft_t fft; -chest_t chest; +chest_dl_t chest; void usage(char *prog) { printf("Usage: %s [vcoe] -i input_file\n", prog); @@ -121,14 +121,14 @@ int base_init() { exit(-1); } - fft_buffer = malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + fft_buffer = malloc(SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); if (!fft_buffer) { perror("malloc"); return -1; } for (i=0;i #include #include +#include #include "liblte/phy/resampling/interp.h" #include "liblte/phy/utils/vector.h" #include "liblte/phy/utils/debug.h" -#define TABLE_SIZE 1024 +/*************** STATIC FUNCTIONS ***********************/ - -#ifdef TABLE_SIZE - #define ARG2IDX(arg) ((uint32_t) ((1+(arg)/M_PI)*TABLE_SIZE/2)) - #define MYCEXP(arg) q->cexptable[ARG2IDX(arg)] -#else - #define MYCEXP(arg) (cosf(arg) + I*sinf(arg)) -#endif - -#define MAX_OFFSET 64 - -int interp_init(interp_t *q, interp_type_t type, uint32_t len, uint32_t M) { - int ret = LIBLTE_ERROR_INVALID_INPUTS; - - if (q != NULL && len > 0 && M > 0) { - ret = LIBLTE_ERROR; - - q->in_arg = vec_malloc(len * sizeof(float)); - if (!q->in_arg) { - goto clean_and_exit; - } - q->in_mag = vec_malloc(len * sizeof(float)); - if (!q->in_mag) { - goto clean_and_exit; - } - q->out_arg = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); - if (!q->out_arg) { - goto clean_and_exit; - } - q->out_arg2 = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); - if (!q->out_arg2) { - goto clean_and_exit; - } - q->table_idx = vec_malloc((MAX_OFFSET + M * len) * sizeof(int16_t)); - if (!q->table_idx) { - goto clean_and_exit; - } - q->out_mag = vec_malloc((MAX_OFFSET + M * len) * sizeof(float)); - if (!q->out_mag) { - goto clean_and_exit; - } - q->out_cexp = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); - if (!q->out_cexp) { - goto clean_and_exit; - } - q->out_prod = vec_malloc((MAX_OFFSET + M * len) * sizeof(cf_t)); - if (!q->out_prod) { - goto clean_and_exit; - } -#ifdef TABLE_SIZE - q->cexptable = vec_malloc(TABLE_SIZE * sizeof(cf_t)); - uint32_t i; - for (i=0;icexptable[i] = cexpf(I*M_PI*(2*((float) i/TABLE_SIZE) - 1)); - } -#endif - q->M = M; - q->len = len; - ret = LIBLTE_SUCCESS; - } - -clean_and_exit: - if (ret == LIBLTE_ERROR) { - interp_free(q); - } - return ret; -} - -void interp_free(interp_t *q) { - if (q) { - if (q->in_arg) { - free(q->in_arg); - } - if (q->in_mag) { - free(q->in_mag); - } - if (q->out_arg) { - free(q->out_arg); - } - if (q->out_cexp) { - free(q->out_cexp); - } - if (q->out_mag) { - free(q->out_mag); - } - - if (q->out_prod) { - free(q->out_prod); - } -#ifdef TABLE_SIZE - if (q->cexptable) { - free(q->cexptable); - } -#endif - } -} - -void interp_run_offset(interp_t *q, cf_t *input, cf_t *output, uint32_t off_st, uint32_t off_end) { - uint32_t i, j, n; - float mag0=0, mag1=0, arg0=0, arg1=0; - float dmag, darg; - uint32_t M = q->M; - uint32_t len1 = q->len-1; - - if (off_st + off_end < MAX_OFFSET) { - vec_abs_cf(input, q->in_mag, q->len); - vec_arg_cf(input, q->in_arg, q->len); - - mag0 = q->in_mag[0]; - mag1 = q->in_mag[1]; - arg0 = q->in_arg[0]; - arg1 = q->in_arg[1]; - dmag=(mag1-mag0)/M; - darg=(arg1-arg0)/M; - for (j=0;jout_mag[j] = mag0 - (j+1)*dmag; - q->out_arg[j] = arg0 - (j+1)*darg; - } - - for (i=0;iin_mag[i]; - mag1 = q->in_mag[i+1]; - arg0 = q->in_arg[i]; - arg1 = q->in_arg[i+1]; - dmag=(mag1-mag0)/M; - darg=(arg1-arg0)/M; - for (j=0;jout_mag[i*M+j+off_st] = mag0 + j*dmag; - q->out_arg[i*M+j+off_st] = arg0 + j*darg; - } - } - if (q->len > 1) { - for (j=0;jout_mag[i*M+j+off_st] = mag1 + j*dmag; - q->out_arg[i*M+j+off_st] = arg1 + j*darg; - } - } - uint32_t len=i*M+j+off_st; -#ifdef TABLE_SIZE - vec_convert_fi(q->out_arg, q->table_idx, (float) TABLE_SIZE/2/M_PI, len); - for (n=0;nout_cexp[n] = q->cexptable[q->table_idx[n]+TABLE_SIZE/2]; - } -#else - for (n=0;nout_cexp[n] = MYCEXP(q->out_arg[n]); - } -#endif - vec_prod_cfc(q->out_cexp, q->out_mag, output, len); - } - -} - -void interp_run(interp_t *q, cf_t *input, cf_t *output) { - interp_run_offset(q, input, output, 0, 1); -} - -cf_t interp_linear_onesample(cf_t *input) { +cf_t interp_linear_onesample(cf_t input0, cf_t input1) { float mag0=0, mag1=0, arg0=0, arg1=0, mag=0, arg=0; - mag0 = cabsf(input[0]); - mag1 = cabsf(input[1]); - arg0 = cargf(input[0]); - arg1 = cargf(input[1]); + mag0 = cabsf(input0); + mag1 = cabsf(input1); + arg0 = cargf(input0); + arg1 = cargf(input1); mag = 2*mag1 -mag0; arg = 2*arg1-arg0; return mag * cexpf(I * arg); } -cf_t interp_linear_onesample2(cf_t *input) { +cf_t interp_linear_onesample_cabs(cf_t input0, cf_t input1) { float re0=0, im0=0, re1=0, im1=0, re=0, im=0; - re0 = crealf(input[0]); - im0 = cimagf(input[1]); - re1 = crealf(input[0]); - im1 = cimagf(input[1]); + re0 = crealf(input0); + im0 = cimagf(input1); + re1 = crealf(input0); + im1 = cimagf(input1); re = 2*re1-re0; im = 2*im1-im0; return (re+im*_Complex_I); } + +/* Performs 1st order integer linear interpolation */ +void interp_linear_f(float *input, float *output, uint32_t M, uint32_t len) { + uint32_t i, j; + for (i=0;idiff_vec = vec_malloc(vector_len * sizeof(cf_t)); + if (!q->diff_vec) { + perror("malloc"); + return LIBLTE_ERROR; + } + q->vector_len = vector_len; + } + return ret; } +void interp_linear_vector_free(interp_linvec_t *q) { + if (q->diff_vec) { + free(q->diff_vec); + } +} -/* Performs 1st order uint32_teger linear interpolation */ -void interp_linear_f(float *input, float *output, uint32_t M, uint32_t len) { +void interp_linear_vector(interp_linvec_t *q, cf_t *in0, cf_t *in1, cf_t *between, uint32_t M) +{ + uint32_t i; + + vec_sub_ccc(in1, in0, q->diff_vec, q->vector_len); + vec_sc_prod_cfc(q->diff_vec, (float) 1/M, q->diff_vec, q->vector_len); + vec_sum_ccc(in0, q->diff_vec, between, q->vector_len); + for (i=0;idiff_vec, &between[q->vector_len], q->vector_len); + between += q->vector_len; + } +} + +int interp_linear_init(interp_lin_t *q, uint32_t vector_len, uint32_t M) +{ + int ret = LIBLTE_ERROR_INVALID_INPUTS; + if (q) { + bzero(q, sizeof(interp_lin_t)); + ret = LIBLTE_SUCCESS; + q->diff_vec = vec_malloc(vector_len * sizeof(cf_t)); + if (!q->diff_vec) { + perror("malloc"); + return LIBLTE_ERROR; + } + q->diff_vec2 = vec_malloc(M * vector_len * sizeof(cf_t)); + if (!q->diff_vec2) { + perror("malloc"); + free(q->diff_vec); + return LIBLTE_ERROR; + } + q->ramp = vec_malloc(M * sizeof(float)); + if (!q->ramp) { + perror("malloc"); + free(q->ramp); + free(q->diff_vec); + return LIBLTE_ERROR; + } + + for (int i=0;iramp[i] = (float) i; + } + + q->vector_len = vector_len; + q->M = M; + } + return ret; +} + +void interp_linear_free(interp_lin_t *q) { + if (q->diff_vec) { + free(q->diff_vec); + } +} + +void interp_linear_offset(interp_lin_t *q, cf_t *input, cf_t *output, + uint32_t off_st, uint32_t off_end) +{ uint32_t i, j; - for (i=0;iM; + } + vec_sub_ccc(&input[1], input, q->diff_vec, (q->vector_len-1)); + vec_sc_prod_cfc(q->diff_vec, (float) 1/q->M, q->diff_vec, q->vector_len-1); + for (i=0;ivector_len-1;i++) { + for (j=0;jM;j++) { + output[i*q->M+j+off_st] = input[i]; + q->diff_vec2[i*q->M+j] = q->diff_vec[i]; + } + vec_prod_cfc(&q->diff_vec2[i*q->M],q->ramp,&q->diff_vec2[i*q->M],q->M); + } + vec_sum_ccc(&output[off_st], q->diff_vec2, &output[off_st], q->M*(q->vector_len-1)); + + if (q->vector_len > 1) { + diff = input[q->vector_len-1]-input[q->vector_len-2]; + for (j=0;jM+j+off_st] = input[i] + j * diff / q->M; } } } + diff --git a/lte/phy/lib/resampling/test/CMakeLists.txt b/lte/phy/lib/resampling/test/CMakeLists.txt index e11d6e683..5deb366e8 100644 --- a/lte/phy/lib/resampling/test/CMakeLists.txt +++ b/lte/phy/lib/resampling/test/CMakeLists.txt @@ -31,7 +31,5 @@ TARGET_LINK_LIBRARIES(resample_arb_bench lte_phy) ADD_TEST(resample resample_arb_test) -ADD_EXECUTABLE(interp_test_volk interp_test_volk.c) -TARGET_LINK_LIBRARIES(interp_test_volk lte_phy) diff --git a/lte/phy/lib/resampling/test/interp_test_volk.c b/lte/phy/lib/resampling/test/interp_test_volk.c deleted file mode 100644 index cc97f3cef..000000000 --- a/lte/phy/lib/resampling/test/interp_test_volk.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "liblte/phy/phy.h" - -typedef _Complex float cf_t; - -int main(int argc, char **argv) { - uint32_t N = 1000; // Number of sinwave samples - interp_t interp; - struct timeval t[3]; - - if (argc < 3) { - printf("usage: %s upsampling_rate nof_trials\n", argv[0]); - exit(-1); - } - - uint32_t M = atoi(argv[1]); - uint32_t nof_trials = atoi(argv[2]); - - if (interp_init(&interp, LINEAR, N, M)) { - exit(-1); - } - - cf_t *in = vec_malloc(N*sizeof(cf_t)); - if(!in) { - perror("malloc"); - exit(-1); - } - cf_t *out = vec_malloc(M * N*sizeof(cf_t)); - if(!out) { - perror("malloc"); - exit(-1); - } - cf_t *out_volk = vec_malloc(M * N*sizeof(cf_t)); - if(!out_volk) { - perror("malloc"); - exit(-1); - } - - srand(time(NULL)); - for(uint32_t i=0;ichest, cell)) { + if (chest_dl_init(&q->chest, cell)) { fprintf(stderr, "Error initiating channel estimator\n"); goto clean_exit; } @@ -120,7 +120,7 @@ clean_exit: void ue_dl_free(ue_dl_t *q) { if (q) { lte_fft_free(&q->fft); - chest_free(&q->chest); + chest_dl_free(&q->chest); regs_free(&q->regs); pbch_free(&q->pbch); pcfich_free(&q->pcfich); @@ -161,7 +161,7 @@ int ue_dl_decode(ue_dl_t *q, cf_t *input, uint8_t *data, uint32_t sf_idx, uint32 gettimeofday(&t[1], NULL); /* Get channel estimates for each port */ - chest_ce_sf(&q->chest, q->sf_symbols, q->ce, sf_idx); + chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, sf_idx); gettimeofday(&t[2], NULL); get_time_interval(t); diff --git a/lte/phy/lib/ue/src/ue_mib.c b/lte/phy/lib/ue/src/ue_mib.c index 9530d48ba..c3c1f831d 100644 --- a/lte/phy/lib/ue/src/ue_mib.c +++ b/lte/phy/lib/ue/src/ue_mib.c @@ -64,14 +64,14 @@ int ue_mib_init(ue_mib_t * q, bzero(q, sizeof(ue_mib_t)); - q->slot1_symbols = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); - if (!q->slot1_symbols) { + q->sf_symbols = vec_malloc(SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + if (!q->sf_symbols) { perror("malloc"); goto clean_exit; } for (int i=0;ice[i] = vec_malloc(SLOT_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); + q->ce[i] = vec_malloc(SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); if (!q->ce[i]) { perror("malloc"); goto clean_exit; @@ -94,7 +94,7 @@ int ue_mib_init(ue_mib_t * q, fprintf(stderr, "Error initializing FFT\n"); goto clean_exit; } - if (chest_init_LTEDL(&q->chest, cell)) { + if (chest_dl_init(&q->chest, cell)) { fprintf(stderr, "Error initializing reference signal\n"); goto clean_exit; } @@ -116,8 +116,8 @@ clean_exit: void ue_mib_free(ue_mib_t * q) { - if (q->slot1_symbols) { - free(q->slot1_symbols); + if (q->sf_symbols) { + free(q->sf_symbols); } for (int i=0;ice[i]) { @@ -125,7 +125,7 @@ void ue_mib_free(ue_mib_t * q) } } sync_free(&q->sfind); - chest_free(&q->chest); + chest_dl_free(&q->chest); pbch_free(&q->pbch); lte_fft_free(&q->fft); } @@ -148,12 +148,13 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input, uint8_t bch_payload[BCH_PAYLOAD_LEN], uint32_t *nof_tx_ports, uint32_t *sfn_offset) { int ret = LIBLTE_SUCCESS; + cf_t *ce_slot1[MAX_PORTS]; /* Run FFT for the slot symbols */ - lte_fft_run_slot(&q->fft, input, q->slot1_symbols); + lte_fft_run_sf(&q->fft, input, q->sf_symbols); /* Get channel estimates of slot #1 for each port */ - ret = chest_ce_slot(&q->chest, q->slot1_symbols, q->ce, 1); + ret = chest_dl_estimate(&q->chest, q->sf_symbols, q->ce, 0); if (ret < 0) { return LIBLTE_ERROR; } @@ -167,8 +168,12 @@ int ue_mib_decode_aligned_frame(ue_mib_t * q, cf_t *input, ue_mib_reset(q); } + for (int i=0;ice[i][SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)]; + } + /* Decode PBCH */ - ret = pbch_decode(&q->pbch, q->slot1_symbols, q->ce, bch_payload, nof_tx_ports, sfn_offset); + ret = pbch_decode(&q->pbch, &q->sf_symbols[SLOT_LEN_RE(q->chest.cell.nof_prb, q->chest.cell.cp)], ce_slot1, bch_payload, nof_tx_ports, sfn_offset); if (ret < 0) { fprintf(stderr, "Error decoding PBCH (%d)\n", ret); } else if (ret == 1) { @@ -246,7 +251,9 @@ int ue_mib_sync_and_decode(ue_mib_t * q, sync_get_sf_idx(&q->sfind) == 0) { INFO("Trying to decode MIB\n",0); - ret = ue_mib_decode_aligned_frame(q, &signal[nf*MIB_FRAME_SIZE_SEARCH+peak_idx], q->bch_payload, &q->nof_tx_ports, &q->sfn_offset); + printf("caution here should pass begining of frame \n"); + exit(-1); + ret = ue_mib_decode_aligned_frame(q, &signal[nf*MIB_FRAME_SIZE_SEARCH+peak_idx-960], q->bch_payload, &q->nof_tx_ports, &q->sfn_offset); counter3++; } else if ((ret == LIBLTE_SUCCESS && peak_idx != 0) || (ret == 1 && nf*MIB_FRAME_SIZE_SEARCH + peak_idx + MIB_FRAME_SIZE_SEARCH/10 > nsamples)) diff --git a/lte/phy/lib/utils/src/convolution.c b/lte/phy/lib/utils/src/convolution.c index 76a26bdee..acf7f5c4d 100644 --- a/lte/phy/lib/utils/src/convolution.c +++ b/lte/phy/lib/utils/src/convolution.c @@ -91,7 +91,6 @@ uint32_t conv_cc(cf_t *input, cf_t *filter, cf_t *output, uint32_t input_len, ui uint32_t i,j; uint32_t output_len; output_len=input_len+filter_len-1; - memset(output,0,output_len*sizeof(cf_t)); for (i=0;i