diff --git a/lib/include/srslte/phy/dft/ofdm.h b/lib/include/srslte/phy/dft/ofdm.h index f605aa9d4..b3a71fd30 100644 --- a/lib/include/srslte/phy/dft/ofdm.h +++ b/lib/include/srslte/phy/dft/ofdm.h @@ -31,55 +31,62 @@ * Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6 *********************************************************************************************/ -#include #include #include "srslte/config.h" #include "srslte/phy/common/phy_common.h" #include "srslte/phy/dft/dft.h" -/* This is common for both directions */ +/** + * @struct srslte_ofdm_cfg_t + * Contains the generic OFDM modulator configuration. The structure must be initialised to all zeros before being + * filled. Only compulsory parameters need to be filled prior initialization. + * + * This structure must be used with init functions srslte_ofdm_rx_init_cfg and srslte_ofdm_tx_init_cfg. These provide + * more flexible options. + */ +typedef struct SRSLTE_API { + // Compulsory parameters + uint32_t nof_prb; //< Number of Resource Block + cf_t* in_buffer; //< Input bnuffer pointer + cf_t* out_buffer; //< Output buffer pointer + srslte_cp_t cp; //< Cyclic prefix type + + // Optional parameters + srslte_sf_t sf_type; //< Subframe type, normal or MBSFN + bool normalize; //< Normalization flag, it divides the output by square root of the symbol size + float freq_shift_f; //< Frequency shift, normalised by sampling rate (used in UL) + float rx_window_offset; //< DFT Window offset in CP portion (0-1), RX only + uint32_t symbol_sz; //< Symbol size, forces a given symbol size for the number of PRB +} srslte_ofdm_cfg_t; + +/** + * @struct srslte_ofdm_t + * OFDM object, common for Tx and Rx + */ typedef struct SRSLTE_API { + srslte_ofdm_cfg_t cfg; srslte_dft_plan_t fft_plan; srslte_dft_plan_t fft_plan_sf[2]; uint32_t max_prb; uint32_t nof_symbols; - uint32_t symbol_sz; uint32_t nof_guards; uint32_t nof_re; uint32_t slot_sz; uint32_t sf_sz; - srslte_cp_t cp; cf_t* tmp; // for removing zero padding - cf_t* in_buffer; - cf_t* out_buffer; - - bool mbsfn_subframe; - uint32_t mbsfn_guard_len; - uint32_t nof_symbols_mbsfn; - uint8_t non_mbsfn_region; - - bool freq_shift; - float freq_shift_f; - cf_t* shift_buffer; + bool mbsfn_subframe; + uint32_t mbsfn_guard_len; + uint32_t nof_symbols_mbsfn; + uint8_t non_mbsfn_region; + uint32_t window_offset_n; + cf_t* shift_buffer; + cf_t* window_offset_buffer; } srslte_ofdm_t; -SRSLTE_API int srslte_ofdm_init_(srslte_ofdm_t* q, - srslte_cp_t cp, - cf_t* in_buffer, - cf_t* out_buffer, - int symbol_sz, - int nof_prb, - srslte_dft_dir_t dir); - -SRSLTE_API int srslte_ofdm_init_mbsfn_(srslte_ofdm_t* q, - srslte_cp_t cp, - cf_t* in_buffer, - cf_t* out_buffer, - int symbol_sz, - int nof_prb, - srslte_dft_dir_t dir, - srslte_sf_t sf_type); +SRSLTE_API int srslte_ofdm_rx_init_cfg(srslte_ofdm_t* q, srslte_ofdm_cfg_t* cfg); + +SRSLTE_API int srslte_ofdm_tx_init_cfg(srslte_ofdm_t* q, srslte_ofdm_cfg_t* cfg); SRSLTE_API int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t* q, srslte_cp_t cp_type, cf_t* in_buffer, cf_t* out_buffer, uint32_t max_prb); @@ -93,10 +100,6 @@ SRSLTE_API int srslte_ofdm_rx_set_prb(srslte_ofdm_t* q, srslte_cp_t cp, uint32_t SRSLTE_API void srslte_ofdm_rx_free(srslte_ofdm_t* q); -SRSLTE_API void srslte_ofdm_rx_slot(srslte_ofdm_t* q, int slot_in_sf); - -SRSLTE_API void srslte_ofdm_rx_slot_ng(srslte_ofdm_t* q, cf_t* input, cf_t* output); - SRSLTE_API void srslte_ofdm_rx_sf(srslte_ofdm_t* q); SRSLTE_API void srslte_ofdm_rx_sf_ng(srslte_ofdm_t* q, cf_t* input, cf_t* output); @@ -109,10 +112,6 @@ srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t* q, srslte_cp_t cp, cf_t* in_buffer, cf_ SRSLTE_API void srslte_ofdm_tx_free(srslte_ofdm_t* q); -SRSLTE_API void srslte_ofdm_tx_slot(srslte_ofdm_t* q, int slot_in_sf); - -SRSLTE_API void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t* q, cf_t* input, cf_t* output); - SRSLTE_API void srslte_ofdm_tx_sf(srslte_ofdm_t* q); SRSLTE_API int srslte_ofdm_set_freq_shift(srslte_ofdm_t* q, float freq_shift); diff --git a/lib/src/phy/dft/ofdm.c b/lib/src/phy/dft/ofdm.c index 797bbcd02..1acb7c437 100644 --- a/lib/src/phy/dft/ofdm.c +++ b/lib/src/phy/dft/ofdm.c @@ -35,61 +35,110 @@ /* Uncomment next line for avoiding Guru DFT call */ //#define AVOID_GURU -int srslte_ofdm_init_(srslte_ofdm_t* q, - srslte_cp_t cp, - cf_t* in_buffer, - cf_t* out_buffer, - int symbol_sz, - int nof_prb, - srslte_dft_dir_t dir) +static int ofdm_init_mbsfn_(srslte_ofdm_t* q, srslte_ofdm_cfg_t* cfg, srslte_dft_dir_t dir) { - return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, dir, SRSLTE_SF_NORM); -} -int srslte_ofdm_init_mbsfn_(srslte_ofdm_t* q, - srslte_cp_t cp, - cf_t* in_buffer, - cf_t* out_buffer, - int symbol_sz, - int nof_prb, - srslte_dft_dir_t dir, - srslte_sf_t sf_type) -{ + // If the symbol size is not given, calculate in function of the number of resource blocks + if (cfg->symbol_sz == 0) { + int symbol_sz_err = srslte_symbol_sz(cfg->nof_prb); + if (symbol_sz_err <= SRSLTE_SUCCESS) { + ERROR("Invalid number of PRB %d\n", cfg->nof_prb); + return SRSLTE_ERROR; + } + cfg->symbol_sz = (uint32_t)symbol_sz_err; + } + + if (q->max_prb > 0) { + // The object was already initialised, update only resizing params + q->cfg.cp = cfg->cp; + q->cfg.nof_prb = cfg->nof_prb; + q->cfg.symbol_sz = cfg->symbol_sz; + } else { + // Otherwise copy all parameters + q->cfg = *cfg; + } + + uint32_t symbol_sz = q->cfg.symbol_sz; + srslte_cp_t cp = q->cfg.cp; + srslte_sf_t sf_type = q->cfg.sf_type; - /* Set OFDM object attributes */ - q->symbol_sz = (uint32_t)symbol_sz; + // Set OFDM object attributes q->nof_symbols = SRSLTE_CP_NSYMB(cp); q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT); - q->cp = cp; - q->freq_shift = false; - q->nof_re = (uint32_t)nof_prb * SRSLTE_NRE; - q->nof_guards = ((symbol_sz - q->nof_re) / 2); - q->slot_sz = (uint32_t)SRSLTE_SLOT_LEN(symbol_sz); - q->sf_sz = (uint32_t)SRSLTE_SF_LEN(symbol_sz); - q->in_buffer = in_buffer; - q->out_buffer = out_buffer; - - if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) { - ERROR("Error: Creating DFT plan\n"); - return SRSLTE_ERROR; + q->nof_re = cfg->nof_prb * SRSLTE_NRE; + q->nof_guards = (q->cfg.symbol_sz - q->nof_re) / 2U; + q->slot_sz = (uint32_t)SRSLTE_SLOT_LEN(q->cfg.symbol_sz); + q->sf_sz = (uint32_t)SRSLTE_SF_LEN(q->cfg.symbol_sz); + + // Plan MBSFN + if (q->fft_plan.size) { + // Replan if it was initialised previously + if (srslte_dft_replan(&q->fft_plan, q->cfg.symbol_sz)) { + ERROR("Reeplaning DFT plan\n"); + return SRSLTE_ERROR; + } + } else { + // Create plan from zero otherwise + if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) { + ERROR("Creating DFT plan\n"); + return SRSLTE_ERROR; + } } + // Reallocate temporal buffer only if the new number of resource blocks is bigger than initial + if (q->cfg.nof_prb > q->max_prb) { + // Free before reallocating if allocted + if (q->tmp) { + free(q->tmp); + free(q->shift_buffer); + } + #ifdef AVOID_GURU - q->tmp = srslte_vec_cf_malloc(symbol_sz); - if (!q->tmp) { - perror("malloc"); - return SRSLTE_ERROR; + q->tmp = srslte_vec_cf_malloc(symbol_sz); +#else + q->tmp = srslte_vec_cf_malloc(q->sf_sz); +#endif /* AVOID_GURU */ + if (!q->tmp) { + perror("malloc"); + return SRSLTE_ERROR; + } + + q->shift_buffer = srslte_vec_cf_malloc(q->sf_sz); + if (!q->shift_buffer) { + perror("malloc"); + return SRSLTE_ERROR; + } + + q->window_offset_buffer = srslte_vec_cf_malloc(q->sf_sz); + if (!q->window_offset_buffer) { + perror("malloc"); + return SRSLTE_ERROR; + } + + q->max_prb = cfg->nof_prb; } + +#ifdef AVOID_GURU srslte_vec_cf_zero(q->tmp, symbol_sz); #else + uint32_t nof_prb = q->cfg.nof_prb; + cf_t* in_buffer = q->cfg.in_buffer; + cf_t* out_buffer = q->cfg.out_buffer; int cp1 = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(0, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); int cp2 = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(1, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); - q->tmp = srslte_vec_cf_malloc(q->sf_sz); - if (!q->tmp) { - perror("malloc"); - return SRSLTE_ERROR; + // Slides DFT window a fraction of cyclic prefix, it does not apply for the inverse-DFT + if (isnormal(cfg->rx_window_offset)) { + cfg->rx_window_offset = SRSLTE_MAX(0, cfg->rx_window_offset); // Needs to be positive + cfg->rx_window_offset = SRSLTE_MIN(100, cfg->rx_window_offset); // Needs to be below 100 + q->window_offset_n = (uint32_t)roundf((float)cp2 * cfg->rx_window_offset); + + for (uint32_t i = 0; i < symbol_sz; i++) { + q->window_offset_buffer[i] = cexpf(I * M_PI * 2.0f * (float)q->window_offset_n * (float)i / (float)symbol_sz); + } } + + // Zero temporal and input buffers always srslte_vec_cf_zero(q->tmp, q->sf_sz); if (dir == SRSLTE_DFT_BACKWARD) { @@ -99,52 +148,52 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t* q, } for (int slot = 0; slot < 2; slot++) { + // If Guru DFT was allocated, free + if (q->fft_plan_sf[slot].size) { + srslte_dft_plan_free(&q->fft_plan_sf[slot]); + } + + // Create Tx/Rx plans if (dir == SRSLTE_DFT_FORWARD) { if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], symbol_sz, dir, - in_buffer + cp1 + q->slot_sz * slot, - q->tmp + q->nof_symbols * q->symbol_sz * slot, + in_buffer + cp1 + q->slot_sz * slot - q->window_offset_n, + q->tmp, 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz + cp2, symbol_sz)) { - ERROR("Error: Creating DFT plan (1)\n"); - return -1; + ERROR("Creating Guru DFT plan (%d)\n", slot); + return SRSLTE_ERROR; } } else { if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], symbol_sz, dir, - q->tmp + q->nof_symbols * q->symbol_sz * slot, + q->tmp, out_buffer + cp1 + q->slot_sz * slot, 1, 1, SRSLTE_CP_NSYMB(cp), symbol_sz, symbol_sz + cp2)) { - ERROR("Error: Creating DFT plan (1)\n"); - return -1; + ERROR("Creating Guru inverse-DFT plan (%d)\n", slot); + return SRSLTE_ERROR; } } } #endif - q->shift_buffer = srslte_vec_cf_malloc(SRSLTE_SF_LEN(symbol_sz)); - if (!q->shift_buffer) { - perror("malloc"); - return -1; - } - srslte_dft_plan_set_mirror(&q->fft_plan, true); srslte_dft_plan_set_dc(&q->fft_plan, true); DEBUG("Init %s symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", dir == SRSLTE_DFT_FORWARD ? "FFT" : "iFFT", - q->symbol_sz, + q->cfg.symbol_sz, q->nof_symbols, - q->cp == SRSLTE_CP_NORM ? "Normal" : "Extended", + q->cfg.cp == SRSLTE_CP_NORM ? "Normal" : "Extended", q->nof_re, q->nof_guards); @@ -156,6 +205,10 @@ int srslte_ofdm_init_mbsfn_(srslte_ofdm_t* q, q->mbsfn_subframe = false; } + // Set other parameters + srslte_ofdm_set_freq_shift(q, q->cfg.freq_shift_f); + srslte_dft_plan_set_norm(&q->fft_plan, q->cfg.normalize); + return SRSLTE_SUCCESS; } @@ -164,98 +217,6 @@ void srslte_ofdm_set_non_mbsfn_region(srslte_ofdm_t* q, uint8_t non_mbsfn_region q->non_mbsfn_region = non_mbsfn_region; } -int srslte_ofdm_replan_(srslte_ofdm_t* q, srslte_cp_t cp, int symbol_sz, int nof_prb) -{ - - if (srslte_dft_replan_c(&q->fft_plan, symbol_sz)) { - ERROR("Error: Creating DFT plan\n"); - return -1; - } - - q->symbol_sz = (uint32_t)symbol_sz; - q->nof_symbols = SRSLTE_CP_NSYMB(cp); - q->nof_symbols_mbsfn = SRSLTE_CP_NSYMB(SRSLTE_CP_EXT); - q->cp = cp; - q->nof_re = (uint32_t)nof_prb * SRSLTE_NRE; - q->nof_guards = ((symbol_sz - q->nof_re) / 2); - q->slot_sz = (uint32_t)SRSLTE_SLOT_LEN(symbol_sz); - q->sf_sz = (uint32_t)SRSLTE_SF_LEN(symbol_sz); - -#ifndef AVOID_GURU - cf_t* in_buffer = q->in_buffer; - cf_t* out_buffer = q->out_buffer; - - int cp1 = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(0, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); - int cp2 = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(1, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); - - srslte_dft_dir_t dir = q->fft_plan_sf[0].dir; - - if (q->tmp) { - free(q->tmp); - } - - q->tmp = srslte_vec_cf_malloc(q->sf_sz); - if (!q->tmp) { - perror("malloc"); - return -1; - } - srslte_vec_cf_zero(q->tmp, q->sf_sz); - - if (dir == SRSLTE_DFT_BACKWARD) { - srslte_vec_cf_zero(in_buffer, SRSLTE_SF_LEN_RE(nof_prb, cp)); - } else { - srslte_vec_cf_zero(in_buffer, q->sf_sz); - } - - for (int slot = 0; slot < 2; slot++) { - srslte_dft_plan_free(&q->fft_plan_sf[slot]); - - if (dir == SRSLTE_DFT_FORWARD) { - if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], - symbol_sz, - dir, - in_buffer + cp1 + q->slot_sz * slot, - q->tmp + q->nof_symbols * q->symbol_sz * slot, - 1, - 1, - SRSLTE_CP_NSYMB(cp), - symbol_sz + cp2, - symbol_sz)) { - ERROR("Error: Creating DFT plan (1)\n"); - return -1; - } - } else { - if (srslte_dft_plan_guru_c(&q->fft_plan_sf[slot], - symbol_sz, - dir, - q->tmp + q->nof_symbols * q->symbol_sz * slot, - out_buffer + cp1 + q->slot_sz * slot, - 1, - 1, - SRSLTE_CP_NSYMB(cp), - symbol_sz, - symbol_sz + cp2)) { - ERROR("Error: Creating DFT plan (1)\n"); - return -1; - } - } - } -#endif /* AVOID_GURU */ - - if (q->freq_shift) { - srslte_ofdm_set_freq_shift(q, q->freq_shift_f); - } - - DEBUG("Replan symbol_sz=%d, nof_symbols=%d, cp=%s, nof_re=%d, nof_guards=%d\n", - q->symbol_sz, - q->nof_symbols, - q->cp == SRSLTE_CP_NORM ? "Normal" : "Extended", - q->nof_re, - q->nof_guards); - - return SRSLTE_SUCCESS; -} - void srslte_ofdm_free_(srslte_ofdm_t* q) { srslte_dft_plan_free(&q->fft_plan); @@ -274,154 +235,126 @@ void srslte_ofdm_free_(srslte_ofdm_t* q) if (q->shift_buffer) { free(q->shift_buffer); } + if (q->window_offset_buffer) { + free(q->window_offset_buffer); + } bzero(q, sizeof(srslte_ofdm_t)); } int srslte_ofdm_rx_init(srslte_ofdm_t* q, srslte_cp_t cp, cf_t* in_buffer, cf_t* out_buffer, uint32_t max_prb) { - int symbol_sz = srslte_symbol_sz(max_prb); - if (symbol_sz < 0) { - ERROR("Error: Invalid nof_prb=%d\n", max_prb); - return -1; - } - q->max_prb = max_prb; - return srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD); + bzero(q, sizeof(srslte_ofdm_t)); + + srslte_ofdm_cfg_t cfg = {}; + cfg.cp = cp; + cfg.in_buffer = in_buffer; + cfg.out_buffer = out_buffer; + cfg.nof_prb = max_prb; + cfg.sf_type = SRSLTE_SF_NORM; + + return ofdm_init_mbsfn_(q, &cfg, SRSLTE_DFT_FORWARD); } int srslte_ofdm_rx_init_mbsfn(srslte_ofdm_t* q, srslte_cp_t cp, cf_t* in_buffer, cf_t* out_buffer, uint32_t max_prb) { - int symbol_sz = srslte_symbol_sz(max_prb); - if (symbol_sz < 0) { - ERROR("Error: Invalid nof_prb=%d\n", max_prb); - return -1; - } - q->max_prb = max_prb; - return srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_FORWARD, SRSLTE_SF_MBSFN); + srslte_ofdm_cfg_t cfg = {}; + cfg.cp = cp; + cfg.in_buffer = in_buffer; + cfg.out_buffer = out_buffer; + cfg.nof_prb = max_prb; + cfg.sf_type = SRSLTE_SF_MBSFN; + + return ofdm_init_mbsfn_(q, &cfg, SRSLTE_DFT_FORWARD); } int srslte_ofdm_tx_init(srslte_ofdm_t* q, srslte_cp_t cp, cf_t* in_buffer, cf_t* out_buffer, uint32_t max_prb) { - uint32_t i; - int ret; - - int symbol_sz = srslte_symbol_sz(max_prb); - if (symbol_sz < 0) { - ERROR("Error: Invalid nof_prb=%d\n", max_prb); - return -1; - } - q->max_prb = max_prb; - ret = srslte_ofdm_init_(q, cp, in_buffer, out_buffer, symbol_sz, max_prb, SRSLTE_DFT_BACKWARD); + bzero(q, sizeof(srslte_ofdm_t)); - if (ret == SRSLTE_SUCCESS) { - srslte_dft_plan_set_norm(&q->fft_plan, false); + srslte_ofdm_cfg_t cfg = {}; + cfg.cp = cp; + cfg.in_buffer = in_buffer; + cfg.out_buffer = out_buffer; + cfg.nof_prb = max_prb; + cfg.sf_type = SRSLTE_SF_NORM; - /* set now zeros at CP */ - for (i = 0; i < q->nof_symbols; i++) { - srslte_vec_cf_zero(q->tmp, q->nof_guards); - srslte_vec_cf_zero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards); - } - } - return ret; + return ofdm_init_mbsfn_(q, &cfg, SRSLTE_DFT_BACKWARD); } -int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t* q, srslte_cp_t cp, cf_t* in_buffer, cf_t* out_buffer, uint32_t nof_prb) +int srslte_ofdm_tx_init_cfg(srslte_ofdm_t* q, srslte_ofdm_cfg_t* cfg) { - uint32_t i; - int ret; - - int symbol_sz = srslte_symbol_sz(nof_prb); - if (symbol_sz < 0) { - ERROR("Error: Invalid nof_prb=%d\n", nof_prb); - return -1; - } - q->max_prb = nof_prb; - ret = srslte_ofdm_init_mbsfn_(q, cp, in_buffer, out_buffer, symbol_sz, nof_prb, SRSLTE_DFT_BACKWARD, SRSLTE_SF_MBSFN); + return ofdm_init_mbsfn_(q, cfg, SRSLTE_DFT_BACKWARD); +} - if (ret == SRSLTE_SUCCESS) { - srslte_dft_plan_set_norm(&q->fft_plan, false); +int srslte_ofdm_rx_init_cfg(srslte_ofdm_t* q, srslte_ofdm_cfg_t* cfg) +{ + return ofdm_init_mbsfn_(q, cfg, SRSLTE_DFT_FORWARD); +} - /* set now zeros at CP */ - for (i = 0; i < q->nof_symbols; i++) { - srslte_vec_cf_zero(q->tmp, q->nof_guards); - srslte_vec_cf_zero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards); - } - } - return ret; +int srslte_ofdm_tx_init_mbsfn(srslte_ofdm_t* q, srslte_cp_t cp, cf_t* in_buffer, cf_t* out_buffer, uint32_t nof_prb) +{ + srslte_ofdm_cfg_t cfg = {}; + cfg.cp = cp; + cfg.in_buffer = in_buffer; + cfg.out_buffer = out_buffer; + cfg.nof_prb = nof_prb; + cfg.sf_type = SRSLTE_SF_MBSFN; + + return ofdm_init_mbsfn_(q, &cfg, SRSLTE_DFT_BACKWARD); } int srslte_ofdm_rx_set_prb(srslte_ofdm_t* q, srslte_cp_t cp, uint32_t nof_prb) { - if (nof_prb <= q->max_prb) { - int symbol_sz = srslte_symbol_sz(nof_prb); - if (symbol_sz < 0) { - ERROR("Error: Invalid nof_prb=%d\n", nof_prb); - return -1; - } - return srslte_ofdm_replan_(q, cp, symbol_sz, nof_prb); - } else { - ERROR("OFDM (Rx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", - nof_prb, - q->max_prb); - return -1; - } + srslte_ofdm_cfg_t cfg = {}; + cfg.cp = cp; + cfg.nof_prb = nof_prb; + return ofdm_init_mbsfn_(q, &cfg, SRSLTE_DFT_FORWARD); } int srslte_ofdm_tx_set_prb(srslte_ofdm_t* q, srslte_cp_t cp, uint32_t nof_prb) { - uint32_t i; - int ret; - - if (nof_prb <= q->max_prb) { - int symbol_sz = srslte_symbol_sz(nof_prb); - if (symbol_sz < 0) { - ERROR("Error: Invalid nof_prb=%d\n", nof_prb); - return -1; - } - - ret = srslte_ofdm_replan_(q, cp, symbol_sz, nof_prb); - - if (ret == SRSLTE_SUCCESS) { - /* set now zeros at CP */ - for (i = 0; i < q->nof_symbols; i++) { - srslte_vec_cf_zero(q->tmp, q->nof_guards); - srslte_vec_cf_zero(&q->tmp[q->nof_re + q->nof_guards], q->nof_guards); - } - } - return ret; - } else { - ERROR("OFDM (Tx): Error calling set_prb: nof_prb (%d) must be equal or lower initialized max_prb (%d)\n", - nof_prb, - q->max_prb); - return -1; - } + srslte_ofdm_cfg_t cfg = {}; + cfg.cp = cp; + cfg.nof_prb = nof_prb; + return ofdm_init_mbsfn_(q, &cfg, SRSLTE_DFT_BACKWARD); } void srslte_ofdm_rx_free(srslte_ofdm_t* q) { srslte_ofdm_free_(q); } + /* Shifts the signal after the iFFT or before the FFT. * Freq_shift is relative to inter-carrier spacing. * Caution: This function shall not be called during run-time */ int srslte_ofdm_set_freq_shift(srslte_ofdm_t* q, float freq_shift) { + q->cfg.freq_shift_f = freq_shift; + + // Check if fft shift is required + if (!isnormal(q->cfg.freq_shift_f)) { + srslte_dft_plan_set_dc(&q->fft_plan, true); + return SRSLTE_SUCCESS; + } + + uint32_t symbol_sz = q->cfg.symbol_sz; + srslte_cp_t cp = q->cfg.cp; + cf_t* ptr = q->shift_buffer; - for (uint32_t n = 0; n < 2; n++) { + for (uint32_t n = 0; n < SRSLTE_NOF_SLOTS_PER_SF; n++) { for (uint32_t i = 0; i < q->nof_symbols; i++) { - uint32_t cplen = SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_LEN_NORM(i, q->symbol_sz) : SRSLTE_CP_LEN_EXT(q->symbol_sz); - for (uint32_t t = 0; t < q->symbol_sz + cplen; t++) { - ptr[t] = cexpf(I * 2 * M_PI * ((float)t - (float)cplen) * freq_shift / q->symbol_sz); + uint32_t cplen = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(i, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); + for (uint32_t t = 0; t < symbol_sz + cplen; t++) { + ptr[t] = cexpf(I * 2 * M_PI * ((float)t - (float)cplen) * freq_shift / symbol_sz); } - ptr += q->symbol_sz + cplen; + ptr += symbol_sz + cplen; } } /* Disable DC carrier addition */ srslte_dft_plan_set_dc(&q->fft_plan, false); - q->freq_shift = true; - q->freq_shift_f = freq_shift; return SRSLTE_SUCCESS; } @@ -432,12 +365,15 @@ void srslte_ofdm_tx_free(srslte_ofdm_t* q) void srslte_ofdm_rx_slot_ng(srslte_ofdm_t* q, cf_t* input, cf_t* output) { - uint32_t i; - for (i = 0; i < q->nof_symbols; i++) { - input += SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_LEN_NORM(i, q->symbol_sz) : SRSLTE_CP_LEN_EXT(q->symbol_sz); + uint32_t symbol_sz = q->cfg.symbol_sz; + srslte_cp_t cp = q->cfg.cp; + + for (uint32_t i = 0; i < q->nof_symbols; i++) { + input += SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(i, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); + input -= q->window_offset_n; srslte_dft_run_c(&q->fft_plan, input, q->tmp); memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); - input += q->symbol_sz; + input += symbol_sz; output += q->nof_re; } } @@ -445,45 +381,54 @@ void srslte_ofdm_rx_slot_ng(srslte_ofdm_t* q, cf_t* input, cf_t* output) /* Transforms input samples into output OFDM symbols. * Performs FFT on a each symbol and removes CP. */ -void srslte_ofdm_rx_slot(srslte_ofdm_t* q, int slot_in_sf) +static void ofdm_rx_slot(srslte_ofdm_t* q, int slot_in_sf) { - cf_t* output = q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols; - #ifdef AVOID_GURU srslte_ofdm_rx_slot_ng( - q, q->in_buffer + slot_in_sf * q->slot_sz, q->out_buffer + slot_in_sf * q->nof_re * q->nof_symbols); + q, q->cfg.in_buffer + slot_in_sf * q->slot_sz, q->cfg.out_buffer + slot_in_sf * q->nof_re * q->nof_symbols); #else - float norm = 1.0f / sqrtf(q->fft_plan.size); - cf_t* tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; - uint32_t dc = (q->fft_plan.dc) ? 1 : 0; + uint32_t nof_symbols = q->nof_symbols; + uint32_t nof_re = q->nof_re; + cf_t* output = q->cfg.out_buffer + slot_in_sf * nof_re * nof_symbols; + uint32_t symbol_sz = q->cfg.symbol_sz; + float norm = 1.0f / sqrtf(q->fft_plan.size); + cf_t* tmp = q->tmp; + uint32_t dc = (q->fft_plan.dc) ? 1 : 0; srslte_dft_run_guru_c(&q->fft_plan_sf[slot_in_sf]); for (int i = 0; i < q->nof_symbols; i++) { - memcpy(output, tmp + q->symbol_sz - q->nof_re / 2, sizeof(cf_t) * q->nof_re / 2); - memcpy(output + q->nof_re / 2, &tmp[dc], sizeof(cf_t) * q->nof_re / 2); + // Apply frequency domain window offset + if (q->window_offset_n) { + srslte_vec_prod_ccc(tmp, q->window_offset_buffer, tmp, symbol_sz); + } + + // Perform FFT shift + memcpy(output, tmp + symbol_sz - nof_re / 2, sizeof(cf_t) * nof_re / 2); + memcpy(output + nof_re / 2, &tmp[dc], sizeof(cf_t) * nof_re / 2); + // Normalize output if (q->fft_plan.norm) { - srslte_vec_sc_prod_cfc(output, norm, output, q->nof_re); + srslte_vec_sc_prod_cfc(output, norm, output, nof_re); } - tmp += q->symbol_sz; - output += q->nof_re; + tmp += symbol_sz; + output += nof_re; } #endif } -void srslte_ofdm_rx_slot_mbsfn(srslte_ofdm_t* q, cf_t* input, cf_t* output) +static void ofdm_rx_slot_mbsfn(srslte_ofdm_t* q, cf_t* input, cf_t* output) { uint32_t i; for (i = 0; i < q->nof_symbols_mbsfn; i++) { if (i == q->non_mbsfn_region) { - input += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region, q->symbol_sz); + input += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region, q->cfg.symbol_sz); } - input += (i >= q->non_mbsfn_region) ? SRSLTE_CP_LEN_EXT(q->symbol_sz) : SRSLTE_CP_LEN_NORM(i, q->symbol_sz); + input += (i >= q->non_mbsfn_region) ? SRSLTE_CP_LEN_EXT(q->cfg.symbol_sz) : SRSLTE_CP_LEN_NORM(i, q->cfg.symbol_sz); srslte_dft_run_c(&q->fft_plan, input, q->tmp); memcpy(output, &q->tmp[q->nof_guards], q->nof_re * sizeof(cf_t)); - input += q->symbol_sz; + input += q->cfg.symbol_sz; output += q->nof_re; } } @@ -492,11 +437,12 @@ void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t* q, cf_t* input, cf_t* output) { uint32_t i; for (i = 0; i < q->nof_symbols; i++) { - input += SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_LEN_NORM(i, q->symbol_sz) : SRSLTE_CP_LEN_EXT(q->symbol_sz); + input += + SRSLTE_CP_ISNORM(q->cfg.cp) ? SRSLTE_CP_LEN_NORM(i, q->cfg.symbol_sz) : SRSLTE_CP_LEN_EXT(q->cfg.symbol_sz); srslte_dft_run_c_zerocopy(&q->fft_plan, input, q->tmp); - memcpy(output, &q->tmp[q->symbol_sz / 2 + q->nof_guards], sizeof(cf_t) * q->nof_re / 2); + memcpy(output, &q->tmp[q->cfg.symbol_sz / 2 + q->nof_guards], sizeof(cf_t) * q->nof_re / 2); memcpy(&output[q->nof_re / 2], &q->tmp[1], sizeof(cf_t) * q->nof_re / 2); - input += q->symbol_sz; + input += q->cfg.symbol_sz; output += q->nof_re; } } @@ -504,99 +450,105 @@ void srslte_ofdm_rx_slot_zerocopy(srslte_ofdm_t* q, cf_t* input, cf_t* output) void srslte_ofdm_rx_sf(srslte_ofdm_t* q) { uint32_t n; - if (q->freq_shift) { - srslte_vec_prod_ccc(q->in_buffer, q->shift_buffer, q->in_buffer, 2 * q->slot_sz); + if (isnormal(q->cfg.freq_shift_f)) { + srslte_vec_prod_ccc(q->cfg.in_buffer, q->shift_buffer, q->cfg.in_buffer, q->sf_sz); } if (!q->mbsfn_subframe) { - for (n = 0; n < 2; n++) { - srslte_ofdm_rx_slot(q, n); + for (n = 0; n < SRSLTE_NOF_SLOTS_PER_SF; n++) { + ofdm_rx_slot(q, n); } } else { - srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0 * q->slot_sz], &q->out_buffer[0 * q->nof_re * q->nof_symbols]); - srslte_ofdm_rx_slot(q, 1); + ofdm_rx_slot_mbsfn(q, q->cfg.in_buffer, q->cfg.out_buffer); + ofdm_rx_slot(q, 1); } } void srslte_ofdm_rx_sf_ng(srslte_ofdm_t* q, cf_t* input, cf_t* output) { uint32_t n; - if (q->freq_shift) { - srslte_vec_prod_ccc(input, q->shift_buffer, input, 2 * q->slot_sz); + if (isnormal(q->cfg.freq_shift_f)) { + srslte_vec_prod_ccc(input, q->shift_buffer, input, q->sf_sz); } if (!q->mbsfn_subframe) { - for (n = 0; n < 2; n++) { + for (n = 0; n < SRSLTE_NOF_SLOTS_PER_SF; n++) { srslte_ofdm_rx_slot_ng(q, &input[n * q->slot_sz], &output[n * q->nof_re * q->nof_symbols]); } } else { - srslte_ofdm_rx_slot_mbsfn(q, &q->in_buffer[0 * q->slot_sz], &q->out_buffer[0 * q->nof_re * q->nof_symbols]); - srslte_ofdm_rx_slot(q, 1); + ofdm_rx_slot_mbsfn(q, q->cfg.in_buffer, q->cfg.out_buffer); + ofdm_rx_slot(q, 1); } } /* Transforms input OFDM symbols into output samples. * Performs FFT on a each symbol and adds CP. */ -void srslte_ofdm_tx_slot(srslte_ofdm_t* q, int slot_in_sf) +static void ofdm_tx_slot(srslte_ofdm_t* q, int slot_in_sf) { - cf_t* input = q->in_buffer + slot_in_sf * q->nof_re * q->nof_symbols; - cf_t* output = q->out_buffer + slot_in_sf * q->slot_sz; + uint32_t symbol_sz = q->cfg.symbol_sz; + srslte_cp_t cp = q->cfg.cp; + + cf_t* input = q->cfg.in_buffer + slot_in_sf * q->nof_re * q->nof_symbols; + cf_t* output = q->cfg.out_buffer + slot_in_sf * q->slot_sz; #ifdef AVOID_GURU for (int i = 0; i < q->nof_symbols; i++) { - int cp_len = SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_LEN_NORM(i, q->symbol_sz) : SRSLTE_CP_LEN_EXT(q->symbol_sz); + int cp_len = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(i, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); srslte_dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); input += q->nof_re; /* add CP */ - memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); - output += q->symbol_sz + cp_len; + memcpy(output, &output[symbol_sz], cp_len * sizeof(cf_t)); + output += symbol_sz + cp_len; } #else - float norm = 1.0f / sqrtf(q->symbol_sz); - cf_t* tmp = q->tmp + slot_in_sf * q->symbol_sz * q->nof_symbols; + uint32_t nof_symbols = q->nof_symbols; + uint32_t nof_re = q->nof_re; + float norm = 1.0f / sqrtf(symbol_sz); + cf_t* tmp = q->tmp; bzero(tmp, q->slot_sz); uint32_t dc = (q->fft_plan.dc) ? 1 : 0; - for (int i = 0; i < q->nof_symbols; i++) { - memcpy(&tmp[dc], &input[q->nof_re / 2], q->nof_re / 2 * sizeof(cf_t)); - memcpy(&tmp[q->symbol_sz - q->nof_re / 2], &input[0], q->nof_re / 2 * sizeof(cf_t)); + for (int i = 0; i < nof_symbols; i++) { + memcpy(&tmp[dc], &input[nof_re / 2], nof_re / 2 * sizeof(cf_t)); + memcpy(&tmp[symbol_sz - nof_re / 2], &input[0], nof_re / 2 * sizeof(cf_t)); - input += q->nof_re; - tmp += q->symbol_sz; + input += nof_re; + tmp += symbol_sz; } srslte_dft_run_guru_c(&q->fft_plan_sf[slot_in_sf]); - for (int i = 0; i < q->nof_symbols; i++) { - int cp_len = SRSLTE_CP_ISNORM(q->cp) ? SRSLTE_CP_LEN_NORM(i, q->symbol_sz) : SRSLTE_CP_LEN_EXT(q->symbol_sz); + for (int i = 0; i < nof_symbols; i++) { + int cp_len = SRSLTE_CP_ISNORM(cp) ? SRSLTE_CP_LEN_NORM(i, symbol_sz) : SRSLTE_CP_LEN_EXT(symbol_sz); if (q->fft_plan.norm) { - srslte_vec_sc_prod_cfc(&output[cp_len], norm, &output[cp_len], q->symbol_sz); + srslte_vec_sc_prod_cfc(&output[cp_len], norm, &output[cp_len], symbol_sz); } /* add CP */ - memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); - output += q->symbol_sz + cp_len; + memcpy(output, &output[symbol_sz], cp_len * sizeof(cf_t)); + output += symbol_sz + cp_len; } #endif } -void srslte_ofdm_tx_slot_mbsfn(srslte_ofdm_t* q, cf_t* input, cf_t* output) +void ofdm_tx_slot_mbsfn(srslte_ofdm_t* q, cf_t* input, cf_t* output) { - uint32_t i, cp_len; - for (i = 0; i < q->nof_symbols_mbsfn; i++) { - cp_len = (i > (q->non_mbsfn_region - 1)) ? SRSLTE_CP_LEN_EXT(q->symbol_sz) : SRSLTE_CP_LEN_NORM(i, q->symbol_sz); + uint32_t symbol_sz = q->cfg.symbol_sz; + + for (uint32_t i = 0; i < q->nof_symbols_mbsfn; i++) { + int cp_len = (i > (q->non_mbsfn_region - 1)) ? SRSLTE_CP_LEN_EXT(symbol_sz) : SRSLTE_CP_LEN_NORM(i, symbol_sz); memcpy(&q->tmp[q->nof_guards], input, q->nof_re * sizeof(cf_t)); srslte_dft_run_c(&q->fft_plan, q->tmp, &output[cp_len]); input += q->nof_re; /* add CP */ - memcpy(output, &output[q->symbol_sz], cp_len * sizeof(cf_t)); - output += q->symbol_sz + cp_len; + memcpy(output, &output[symbol_sz], cp_len * sizeof(cf_t)); + output += symbol_sz + cp_len; /*skip the small section between the non mbms region and the mbms region*/ if (i == (q->non_mbsfn_region - 1)) - output += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region, q->symbol_sz); + output += SRSLTE_NON_MBSFN_REGION_GUARD_LENGTH(q->non_mbsfn_region, symbol_sz); } } @@ -609,14 +561,14 @@ void srslte_ofdm_tx_sf(srslte_ofdm_t* q) { uint32_t n; if (!q->mbsfn_subframe) { - for (n = 0; n < 2; n++) { - srslte_ofdm_tx_slot(q, n); + for (n = 0; n < SRSLTE_NOF_SLOTS_PER_SF; n++) { + ofdm_tx_slot(q, n); } } else { - srslte_ofdm_tx_slot_mbsfn(q, &q->in_buffer[0 * q->nof_re * q->nof_symbols], &q->out_buffer[0 * q->slot_sz]); - srslte_ofdm_tx_slot(q, 1); + ofdm_tx_slot_mbsfn(q, q->cfg.in_buffer, q->cfg.out_buffer); + ofdm_tx_slot(q, 1); } - if (q->freq_shift) { - srslte_vec_prod_ccc(q->out_buffer, q->shift_buffer, q->out_buffer, 2 * q->slot_sz); + if (isnormal(q->cfg.freq_shift_f)) { + srslte_vec_prod_ccc(q->cfg.out_buffer, q->shift_buffer, q->cfg.out_buffer, q->sf_sz); } } diff --git a/lib/src/phy/dft/test/CMakeLists.txt b/lib/src/phy/dft/test/CMakeLists.txt index d49a3e6cf..5420a8462 100644 --- a/lib/src/phy/dft/test/CMakeLists.txt +++ b/lib/src/phy/dft/test/CMakeLists.txt @@ -25,9 +25,9 @@ add_executable(ofdm_test ofdm_test.c) target_link_libraries(ofdm_test srslte_phy) -add_test(ofdm_normal ofdm_test) -add_test(ofdm_extended ofdm_test -e) - -add_test(ofdm_normal_single ofdm_test -n 6) -add_test(ofdm_extended_single ofdm_test -e -n 6) - +add_test(ofdm_normal ofdm_test -r 1) +add_test(ofdm_extended ofdm_test -e -r 1) +add_test(ofdm_shifted ofdm_test -s 0.5 -r 1) +add_test(ofdm_offset ofdm_test -o 0.5 -r 1) +add_test(ofdm_force ofdm_test -N 4096 -r 1) +add_test(ofdm_extended_shifted_offset_force ofdm_test -e -o 0.5 -s 0.5 -N 4096 -r 1) diff --git a/lib/src/phy/dft/test/ofdm_test.c b/lib/src/phy/dft/test/ofdm_test.c index 48d9ddc12..6af4247f4 100644 --- a/lib/src/phy/dft/test/ofdm_test.c +++ b/lib/src/phy/dft/test/ofdm_test.c @@ -26,13 +26,16 @@ #include #include +#include "srslte/phy/utils/random.h" #include "srslte/srslte.h" -int nof_prb = -1; -srslte_cp_t cp = SRSLTE_CP_NORM; -int nof_repetitions = 128; - -static double elapsed_us(struct timeval* ts_start, struct timeval* ts_end) +static int nof_prb = -1; +static srslte_cp_t cp = SRSLTE_CP_NORM; +static int nof_repetitions = 1; +static float rx_window_offset = 0.5f; +static float freq_shift_f = 0.0f; +static uint32_t force_symbol_sz = 0; +static double elapsed_us(struct timeval* ts_start, struct timeval* ts_end) { if (ts_end->tv_usec > ts_start->tv_usec) { return ((double)ts_end->tv_sec - (double)ts_start->tv_sec) * 1000000 + (double)ts_end->tv_usec - @@ -43,28 +46,40 @@ static double elapsed_us(struct timeval* ts_start, struct timeval* ts_end) } } -void usage(char* prog) +static void usage(char* prog) { printf("Usage: %s\n", prog); - printf("\t-n nof_prb [Default All]\n"); + printf("\t-N Force symbol size, 0 for auto [Default %d]\n", force_symbol_sz); + printf("\t-n Force number of Resource blocks [Default All]\n"); printf("\t-e extended cyclic prefix [Default Normal]\n"); printf("\t-r nof_repetitions [Default %d]\n", nof_repetitions); + printf("\t-o rx window offset (portion of CP length) [Default %.1f]\n", rx_window_offset); + printf("\t-s frequency shift (normalised with sampling rate) [Default %.1f]\n", freq_shift_f); } -void parse_args(int argc, char** argv) +static void parse_args(int argc, char** argv) { int opt; - while ((opt = getopt(argc, argv, "ner")) != -1) { + while ((opt = getopt(argc, argv, "Nneros")) != -1) { switch (opt) { case 'n': nof_prb = (int)strtol(argv[optind], NULL, 10); break; + case 'N': + force_symbol_sz = (uint32_t)strtol(argv[optind], NULL, 10); + break; case 'e': cp = SRSLTE_CP_EXT; break; case 'r': nof_repetitions = (int)strtol(argv[optind], NULL, 10); break; + case 'o': + rx_window_offset = SRSLTE_MIN(1.0f, SRSLTE_MAX(0.0f, strtof(argv[optind], NULL))); + break; + case 's': + freq_shift_f = SRSLTE_MIN(1.0f, SRSLTE_MAX(0.0f, strtof(argv[optind], NULL))); + break; default: usage(argv[0]); exit(-1); @@ -74,100 +89,91 @@ void parse_args(int argc, char** argv) int main(int argc, char** argv) { - struct timeval start, end; - srslte_ofdm_t fft, ifft; - cf_t * input, *outfft, *outifft; - float mse; - int n_prb, max_prb, n_re; - int i; + srslte_random_t random_gen = srslte_random_init(0); + struct timeval start, end; + srslte_ofdm_t fft = {}, ifft = {}; + cf_t * input, *outfft, *outifft; + float mse; + uint32_t n_prb, max_prb; parse_args(argc, argv); if (nof_prb == -1) { n_prb = 6; - max_prb = 100; + max_prb = SRSLTE_MAX_PRB; } else { - n_prb = nof_prb; - max_prb = nof_prb; + n_prb = (uint32_t)nof_prb; + max_prb = (uint32_t)nof_prb; } while (n_prb <= max_prb) { - n_re = SRSLTE_CP_NSYMB(cp) * n_prb * SRSLTE_NRE; + uint32_t symbol_sz = (force_symbol_sz) ? force_symbol_sz : (uint32_t)srslte_symbol_sz(n_prb); + uint32_t n_re = SRSLTE_CP_NSYMB(cp) * n_prb * SRSLTE_NRE * SRSLTE_NOF_SLOTS_PER_SF; + uint32_t sf_len = SRSLTE_SF_LEN(symbol_sz); printf("Running test for %d PRB, %d RE... ", n_prb, n_re); fflush(stdout); - input = srslte_vec_cf_malloc(n_re * 2U); - if (!input) { + input = srslte_vec_cf_malloc(n_re); + outfft = srslte_vec_cf_malloc(n_re); + outifft = srslte_vec_cf_malloc(sf_len); + if (!input || !outfft || !outifft) { perror("malloc"); exit(-1); } - outfft = srslte_vec_cf_malloc(n_re * 2U); - if (!outfft) { - perror("malloc"); - exit(-1); - } - outifft = srslte_vec_cf_malloc(SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * 2U); - if (!outifft) { - perror("malloc"); + srslte_vec_cf_zero(outifft, sf_len); + + srslte_ofdm_cfg_t ofdm_cfg = {}; + ofdm_cfg.cp = cp; + ofdm_cfg.in_buffer = input; + ofdm_cfg.out_buffer = outifft; + ofdm_cfg.nof_prb = n_prb; + ofdm_cfg.symbol_sz = symbol_sz; + ofdm_cfg.freq_shift_f = freq_shift_f; + ofdm_cfg.normalize = true; + if (srslte_ofdm_tx_init_cfg(&ifft, &ofdm_cfg)) { + ERROR("Error initializing iFFT\n"); exit(-1); } - srslte_vec_cf_zero(outifft, SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * 2); - if (srslte_ofdm_rx_init(&fft, cp, outifft, outfft, n_prb)) { + ofdm_cfg.in_buffer = outifft; + ofdm_cfg.out_buffer = outfft; + ofdm_cfg.rx_window_offset = rx_window_offset; + ofdm_cfg.freq_shift_f = -freq_shift_f; + if (srslte_ofdm_rx_init_cfg(&fft, &ofdm_cfg)) { ERROR("Error initializing FFT\n"); exit(-1); } - srslte_ofdm_set_normalize(&fft, true); - if (srslte_ofdm_tx_init(&ifft, cp, input, outifft, n_prb)) { - ERROR("Error initializing iFFT\n"); - exit(-1); + if (isnormal(freq_shift_f)) { + nof_repetitions = 1; } - srslte_ofdm_set_normalize(&ifft, true); - for (i = 0; i < n_re; i++) { - input[i] = 100 * ((float)rand() / (float)RAND_MAX + I * ((float)rand() / (float)RAND_MAX)); - // input[i] = 100; - } + // Generate Random data + srslte_random_uniform_complex_dist_vector(random_gen, input, n_re, -1.0f, +1.0f); + // Execute Tx gettimeofday(&start, NULL); - for (int i = 0; i < nof_repetitions; i++) { - srslte_ofdm_tx_slot(&ifft, 0); + for (uint32_t i = 0; i < nof_repetitions; i++) { + srslte_ofdm_tx_sf(&ifft); } gettimeofday(&end, NULL); - printf(" Tx@%.1fMsps", - (float)(SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * nof_repetitions) / elapsed_us(&start, &end)); + printf(" Tx@%.1fMsps", (float)(sf_len * nof_repetitions) / elapsed_us(&start, &end)); + // Execute Rx gettimeofday(&start, NULL); - for (int i = 0; i < nof_repetitions; i++) { - srslte_ofdm_rx_slot(&fft, 0); + for (uint32_t i = 0; i < nof_repetitions; i++) { + srslte_ofdm_rx_sf(&fft); } gettimeofday(&end, NULL); - printf(" Rx@%.1fMsps", - (float)(SRSLTE_SLOT_LEN(srslte_symbol_sz(n_prb)) * nof_repetitions) / elapsed_us(&start, &end)); - - /* compute MSE */ - mse = 0.0f; - for (i = 0; i < n_re; i++) { - cf_t error = input[i] - outfft[i]; - mse += (__real__ error * __real__ error + __imag__ error * __imag__ error) / cabsf(input[i]); - if (mse > 1.0f) - printf("%04d. %+.1f%+.1fi Vs. %+.1f%+.1f %+.1f%+.1f (mse=%f)\n", - i, - __real__ input[i], - __imag__ input[i], - __real__ outifft[i], - __imag__ outifft[i], - __real__ outfft[i], - __imag__ outfft[i], - mse); - } - /*for (i=0;i= 0.07) { + if (mse >= 0.0001) { printf("MSE too large\n"); exit(-1); } @@ -182,6 +188,7 @@ int main(int argc, char** argv) n_prb++; } + srslte_random_free(random_gen); exit(0); } diff --git a/lib/src/phy/enb/enb_dl.c b/lib/src/phy/enb/enb_dl.c index f16873853..c03e8af3d 100644 --- a/lib/src/phy/enb/enb_dl.c +++ b/lib/src/phy/enb/enb_dl.c @@ -51,14 +51,24 @@ int srslte_enb_dl_init(srslte_enb_dl_t* q, cf_t* out_buffer[SRSLTE_MAX_PORTS], u } } + srslte_ofdm_cfg_t ofdm_cfg = {}; + ofdm_cfg.nof_prb = max_prb; + ofdm_cfg.cp = SRSLTE_CP_NORM; + ofdm_cfg.normalize = false; for (int i = 0; i < SRSLTE_MAX_PORTS; i++) { - if (srslte_ofdm_tx_init(&q->ifft[i], SRSLTE_CP_NORM, q->sf_symbols[i], out_buffer[i], max_prb)) { + ofdm_cfg.in_buffer = q->sf_symbols[i]; + ofdm_cfg.out_buffer = out_buffer[i]; + ofdm_cfg.sf_type = SRSLTE_SF_NORM; + if (srslte_ofdm_tx_init_cfg(&q->ifft[i], &ofdm_cfg)) { ERROR("Error initiating FFT (%d)\n", i); goto clean_exit; } } - if (srslte_ofdm_tx_init_mbsfn(&q->ifft_mbsfn, SRSLTE_CP_EXT, q->sf_symbols[0], out_buffer[0], max_prb)) { + ofdm_cfg.in_buffer = q->sf_symbols[0]; + ofdm_cfg.out_buffer = out_buffer[0]; + ofdm_cfg.sf_type = SRSLTE_SF_MBSFN; + if (srslte_ofdm_tx_init_cfg(&q->ifft_mbsfn, &ofdm_cfg)) { ERROR("Error initiating FFT \n"); goto clean_exit; } @@ -402,13 +412,17 @@ void srslte_enb_dl_gen_signal(srslte_enb_dl_t* q) if (q->dl_sf.sf_type == SRSLTE_SF_MBSFN) { srslte_ofdm_tx_sf(&q->ifft_mbsfn); - srslte_vec_sc_prod_cfc( - q->ifft_mbsfn.out_buffer, norm_factor, q->ifft_mbsfn.out_buffer, (uint32_t)SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + srslte_vec_sc_prod_cfc(q->ifft_mbsfn.cfg.out_buffer, + norm_factor, + q->ifft_mbsfn.cfg.out_buffer, + (uint32_t)SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); } else { for (int i = 0; i < q->cell.nof_ports; i++) { srslte_ofdm_tx_sf(&q->ifft[i]); - srslte_vec_sc_prod_cfc( - q->ifft[i].out_buffer, norm_factor, q->ifft[i].out_buffer, (uint32_t)SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); + srslte_vec_sc_prod_cfc(q->ifft[i].cfg.out_buffer, + norm_factor, + q->ifft[i].cfg.out_buffer, + (uint32_t)SRSLTE_SF_LEN_PRB(q->cell.nof_prb)); } } } diff --git a/lib/src/phy/enb/enb_ul.c b/lib/src/phy/enb/enb_ul.c index 054215580..77779b227 100644 --- a/lib/src/phy/enb/enb_ul.c +++ b/lib/src/phy/enb/enb_ul.c @@ -47,12 +47,18 @@ int srslte_enb_ul_init(srslte_enb_ul_t* q, cf_t* in_buffer, uint32_t max_prb) goto clean_exit; } - if (srslte_ofdm_rx_init(&q->fft, SRSLTE_CP_NORM, in_buffer, q->sf_symbols, max_prb)) { + srslte_ofdm_cfg_t ofdm_cfg = {}; + ofdm_cfg.nof_prb = max_prb; + ofdm_cfg.in_buffer = in_buffer; + ofdm_cfg.out_buffer = q->sf_symbols; + ofdm_cfg.cp = SRSLTE_CP_NORM; + ofdm_cfg.freq_shift_f = -0.5f; + ofdm_cfg.normalize = false; + ofdm_cfg.rx_window_offset = 0.5f; + if (srslte_ofdm_rx_init_cfg(&q->fft, &ofdm_cfg)) { ERROR("Error initiating FFT\n"); goto clean_exit; } - srslte_ofdm_set_normalize(&q->fft, false); - srslte_ofdm_set_freq_shift(&q->fft, -0.5); if (srslte_pucch_init_enb(&q->pucch)) { ERROR("Error creating PUCCH object\n"); diff --git a/lib/src/phy/phch/test/pbch_file_test.c b/lib/src/phy/phch/test/pbch_file_test.c index 326f20729..c268467ef 100644 --- a/lib/src/phy/phch/test/pbch_file_test.c +++ b/lib/src/phy/phch/test/pbch_file_test.c @@ -137,13 +137,7 @@ int base_init() return -1; } - if (srslte_ofdm_init_(&fft, - cell.cp, - input_buffer, - fft_buffer[0], - srslte_symbol_sz(cell.nof_prb), - cell.nof_prb, - SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_rx_init(&fft, cell.cp, input_buffer, fft_buffer[0], cell.nof_prb)) { ERROR("Error initializing FFT\n"); return -1; } diff --git a/lib/src/phy/phch/test/pcfich_file_test.c b/lib/src/phy/phch/test/pcfich_file_test.c index 3d9c024f5..bd2c8b98a 100644 --- a/lib/src/phy/phch/test/pcfich_file_test.c +++ b/lib/src/phy/phch/test/pcfich_file_test.c @@ -148,13 +148,7 @@ int base_init() return -1; } - if (srslte_ofdm_init_(&fft, - cell.cp, - input_buffer, - fft_buffer[0], - srslte_symbol_sz(cell.nof_prb), - cell.nof_prb, - SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_rx_init(&fft, cell.cp, input_buffer, fft_buffer[0], cell.nof_prb)) { ERROR("Error initializing FFT\n"); return -1; } diff --git a/lib/src/phy/phch/test/pdcch_file_test.c b/lib/src/phy/phch/test/pdcch_file_test.c index d64c0487b..5819676e2 100644 --- a/lib/src/phy/phch/test/pdcch_file_test.c +++ b/lib/src/phy/phch/test/pdcch_file_test.c @@ -153,13 +153,7 @@ int base_init() return -1; } - if (srslte_ofdm_init_(&fft, - cell.cp, - input_buffer, - fft_buffer[0], - srslte_symbol_sz(cell.nof_prb), - cell.nof_prb, - SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_rx_init(&fft, cell.cp, input_buffer, fft_buffer[0], cell.nof_prb)) { ERROR("Error initializing FFT\n"); return -1; } diff --git a/lib/src/phy/phch/test/phich_file_test.c b/lib/src/phy/phch/test/phich_file_test.c index 3c534fd95..4a5138154 100644 --- a/lib/src/phy/phch/test/phich_file_test.c +++ b/lib/src/phy/phch/test/phich_file_test.c @@ -170,13 +170,7 @@ int base_init() return -1; } - if (srslte_ofdm_init_(&fft, - cell.cp, - input_buffer, - fft_buffer[0], - srslte_symbol_sz(cell.nof_prb), - cell.nof_prb, - SRSLTE_DFT_FORWARD)) { + if (srslte_ofdm_rx_init(&fft, cell.cp, input_buffer, fft_buffer[0], cell.nof_prb)) { ERROR("Error initializing FFT\n"); return -1; } diff --git a/lib/src/phy/sync/refsignal_dl_sync.c b/lib/src/phy/sync/refsignal_dl_sync.c index 377df079e..6f8c0a1ac 100644 --- a/lib/src/phy/sync/refsignal_dl_sync.c +++ b/lib/src/phy/sync/refsignal_dl_sync.c @@ -111,7 +111,7 @@ static inline void refsignal_dl_pss_sss_strength(srslte_refsignal_dl_sync_t* q, float* sss_strength, float* sss_strength_false) { - uint32_t symbol_sz = q->ifft.symbol_sz; + uint32_t symbol_sz = q->ifft.cfg.symbol_sz; uint32_t cp_len0 = SRSLTE_CP_LEN_NORM(0, symbol_sz); uint32_t cp_len1 = SRSLTE_CP_LEN_NORM(1, symbol_sz); @@ -528,7 +528,7 @@ void srslte_refsignal_dl_sync_measure_sf(srslte_refsignal_dl_sync_t* q, if (q) { cf_t* sf_sequence = q->sequences[sf_idx % SRSLTE_NOF_SF_X_FRAME]; - uint32_t symbol_sz = q->ifft.symbol_sz; + uint32_t symbol_sz = q->ifft.cfg.symbol_sz; uint32_t nsymbols = srslte_refsignal_cs_nof_symbols(&q->refsignal, &dl_sf_cfg, 0); uint32_t cp_len0 = SRSLTE_CP_LEN_NORM(0, symbol_sz); uint32_t cp_len1 = SRSLTE_CP_LEN_NORM(1, symbol_sz); diff --git a/lib/src/phy/ue/ue_dl.c b/lib/src/phy/ue/ue_dl.c index e5d9562d8..c6c8cb4ee 100644 --- a/lib/src/phy/ue/ue_dl.c +++ b/lib/src/phy/ue/ue_dl.c @@ -84,14 +84,26 @@ int srslte_ue_dl_init(srslte_ue_dl_t* q, cf_t* in_buffer[SRSLTE_MAX_PORTS], uint } } + srslte_ofdm_cfg_t ofdm_cfg = {}; + ofdm_cfg.nof_prb = max_prb; + ofdm_cfg.cp = SRSLTE_CP_NORM; + ofdm_cfg.rx_window_offset = 0.0f; + ofdm_cfg.normalize = false; for (int i = 0; i < nof_rx_antennas; i++) { - if (srslte_ofdm_rx_init(&q->fft[i], SRSLTE_CP_NORM, in_buffer[i], q->sf_symbols[i], max_prb)) { + ofdm_cfg.in_buffer = in_buffer[i]; + ofdm_cfg.out_buffer = q->sf_symbols[i]; + ofdm_cfg.sf_type = SRSLTE_SF_NORM; + + if (srslte_ofdm_rx_init_cfg(&q->fft[i], &ofdm_cfg)) { ERROR("Error initiating FFT\n"); goto clean_exit; } } - if (srslte_ofdm_rx_init_mbsfn(&q->fft_mbsfn, SRSLTE_CP_EXT, in_buffer[0], q->sf_symbols[0], max_prb)) { + ofdm_cfg.in_buffer = in_buffer[0]; + ofdm_cfg.out_buffer = q->sf_symbols[0]; + ofdm_cfg.sf_type = SRSLTE_SF_MBSFN; + if (srslte_ofdm_rx_init_cfg(&q->fft_mbsfn, &ofdm_cfg)) { ERROR("Error initiating FFT for MBSFN subframes \n"); goto clean_exit; } diff --git a/lib/src/phy/ue/ue_ul.c b/lib/src/phy/ue/ue_ul.c index 411e0855a..b2cb1c8d1 100644 --- a/lib/src/phy/ue/ue_ul.c +++ b/lib/src/phy/ue/ue_ul.c @@ -53,12 +53,17 @@ int srslte_ue_ul_init(srslte_ue_ul_t* q, cf_t* out_buffer, uint32_t max_prb) goto clean_exit; } - if (srslte_ofdm_tx_init(&q->fft, SRSLTE_CP_NORM, q->sf_symbols, out_buffer, max_prb)) { + srslte_ofdm_cfg_t ofdm_cfg = {}; + ofdm_cfg.nof_prb = max_prb; + ofdm_cfg.in_buffer = q->sf_symbols; + ofdm_cfg.out_buffer = out_buffer; + ofdm_cfg.cp = SRSLTE_CP_NORM; + ofdm_cfg.freq_shift_f = 0.5f; + ofdm_cfg.normalize = true; + if (srslte_ofdm_tx_init_cfg(&q->fft, &ofdm_cfg)) { ERROR("Error initiating FFT\n"); goto clean_exit; } - srslte_ofdm_set_freq_shift(&q->fft, 0.5); - srslte_ofdm_set_normalize(&q->fft, true); if (srslte_cfo_init(&q->cfo, MAX_SFLEN)) { ERROR("Error creating CFO object\n"); diff --git a/srsue/test/phy/scell_search_test.cc b/srsue/test/phy/scell_search_test.cc index 88cd9790e..86db578d3 100644 --- a/srsue/test/phy/scell_search_test.cc +++ b/srsue/test/phy/scell_search_test.cc @@ -197,7 +197,7 @@ public: } // Undo srslte_enb_dl_gen_signal scaling - float scale = sqrtf(cell_base.nof_prb) / 0.05f / enb_dl.ifft->symbol_sz; + float scale = sqrtf(cell_base.nof_prb) / 0.05f / enb_dl.ifft->cfg.symbol_sz; // Apply Neighbour cell attenuation if (enb_dl.cell.id != *pcis_to_simulate.begin()) {