Refactored OFDM and added half CP window offset in UL Demodulator

master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent 4756319e8f
commit e6792cf9b7

@ -31,55 +31,62 @@
* Reference: 3GPP TS 36.211 version 10.0.0 Release 10 Sec. 6
*********************************************************************************************/
#include <stdlib.h>
#include <strings.h>
#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);

@ -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);
}
}

@ -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)

@ -26,13 +26,16 @@
#include <strings.h>
#include <unistd.h>
#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<n_re;i++) {
mse += cabsf(input[i] - outfft[i]);
}*/
printf(" Rx@%.1fMsps", (double)(sf_len * nof_repetitions) / elapsed_us(&start, &end));
// compute Mean Square Error
srslte_vec_sub_ccc(input, outfft, outfft, n_re);
mse = sqrtf(srslte_vec_avg_power_cf(outfft, n_re));
printf(" MSE=%.6f\n", mse);
if (mse >= 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);
}

@ -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));
}
}
}

@ -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");

@ -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;
}

@ -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;
}

@ -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;
}

@ -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;
}

@ -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);

@ -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;
}

@ -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");

@ -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()) {

Loading…
Cancel
Save