int main(int argc, char **argv) { uint32_t cfi; float cfi_corr; int n; if (argc < 3) { usage(argv[0]); exit(-1); } parse_args(argc,argv); if (base_init()) { fprintf(stderr, "Error initializing receiver\n"); exit(-1); } n = srslte_filesource_read(&fsrc, input_buffer, flen); srslte_ofdm_rx_sf(&fft, input_buffer, fft_buffer); if (fmatlab) { fprintf(fmatlab, "infft="); srslte_vec_fprint_c(fmatlab, input_buffer, flen); fprintf(fmatlab, ";\n"); fprintf(fmatlab, "outfft="); srslte_vec_sc_prod_cfc(fft_buffer, 1000.0, fft_buffer, SRSLTE_CP_NSYMB(cell.cp) * cell.nof_prb * SRSLTE_NRE); srslte_vec_fprint_c(fmatlab, fft_buffer, SRSLTE_CP_NSYMB(cell.cp) * cell.nof_prb * SRSLTE_NRE); fprintf(fmatlab, ";\n"); srslte_vec_sc_prod_cfc(fft_buffer, 0.001, fft_buffer, SRSLTE_CP_NSYMB(cell.cp) * cell.nof_prb * SRSLTE_NRE); } /* Get channel estimates for each port */ srslte_chest_dl_estimate(&chest, fft_buffer, ce, 0); INFO("Decoding PCFICH\n", 0); n = srslte_pcfich_decode(&pcfich, fft_buffer, ce, srslte_chest_dl_get_noise_estimate(&chest), 0, &cfi, &cfi_corr); printf("cfi: %d, distance: %f\n", cfi, cfi_corr); base_free(); if (n < 0) { fprintf(stderr, "Error decoding PCFICH\n"); exit(-1); } else if (n == 0) { printf("Could not decode PCFICH\n"); exit(-1); } else { if (cfi_corr > 2.8 && cfi == 1) { exit(0); } else { exit(-1); } } }
int srslte_ofdm_init_(srslte_ofdm_t *q, srslte_cp_t cp, int symbol_sz, int nof_prb, srslte_dft_dir_t dir) { if (srslte_dft_plan_c(&q->fft_plan, symbol_sz, dir)) { fprintf(stderr, "Error: Creating DFT plan\n"); return -1; } q->tmp = srslte_vec_malloc((uint32_t) symbol_sz * sizeof(cf_t)); if (!q->tmp) { perror("malloc"); return -1; } srslte_dft_plan_set_mirror(&q->fft_plan, true); srslte_dft_plan_set_dc(&q->fft_plan, true); q->symbol_sz = (uint32_t) symbol_sz; q->nof_symbols = SRSLTE_CP_NSYMB(cp); q->cp = cp; q->freq_shift = false; q->shift_buffer = NULL; q->nof_re = nof_prb * SRSLTE_NRE; q->nof_guards = ((symbol_sz - q->nof_re) / 2); q->slot_sz = SRSLTE_SLOT_LEN(symbol_sz); 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->nof_symbols, q->cp==SRSLTE_CP_NORM?"Normal":"Extended", q->nof_re, q->nof_guards); return SRSLTE_SUCCESS; }
int srslte_ue_dl_decode_fft_estimate(srslte_ue_dl_t *q, cf_t *input, uint32_t sf_idx, uint32_t *cfi) { if (input && q && cfi && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ srslte_ofdm_rx_sf(&q->fft, input, q->sf_symbols); /* Correct SFO multiplying by complex exponential in the time domain */ if (q->sample_offset) { struct timeval t[3]; gettimeofday(&t[1], NULL); for (int i=0;i<2*SRSLTE_CP_NSYMB(q->cell.cp);i++) { srslte_cfo_correct(&q->sfo_correct, &q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols[i*q->cell.nof_prb*SRSLTE_NRE], q->sample_offset / q->fft.symbol_sz); } gettimeofday(&t[2], NULL); get_time_interval(t); } return srslte_ue_dl_decode_estimate(q, sf_idx, cfi); } else { return SRSLTE_ERROR_INVALID_INPUTS; } }
/** 36.211 10.3 section 6.11.1.2 */ void srslte_pss_put_slot(cf_t *pss_signal, cf_t *slot, uint32_t nof_prb, srslte_cp_t cp) { int k; k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); memcpy(&slot[k], pss_signal, SRSLTE_PSS_LEN * sizeof(cf_t)); memset(&slot[k + SRSLTE_PSS_LEN], 0, 5 * sizeof(cf_t)); }
void srslte_ue_dl_set_power_alloc(srslte_ue_dl_t *q, float rho_a, float rho_b) { if (q) { srslte_pdsch_set_power_allocation(&q->pdsch, rho_a); q->rho_b = rho_b; uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp); uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb; /* Apply rho_b if required according to 3GPP 36.213 Table 5.2-2 */ if (rho_b != 0.0f && rho_b != 1.0f) { float scaling = 1.0f / rho_b; for (uint32_t i = 0; i < q->nof_rx_antennas; i++) { for (uint32_t j = 0; j < 2; j++) { cf_t *ptr; ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 0); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); if (q->cell.cp == SRSLTE_CP_NORM) { ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 4); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } else { ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 3); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } if (q->cell.nof_ports == 4) { ptr = q->sf_symbols_m[i] + nof_re_symbol * (j * nof_symbols_slot + 1); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } } } } } }
void srslte_enb_dl_prepare_power_allocation(srslte_enb_dl_t *q) { uint32_t nof_symbols_slot = SRSLTE_CP_NSYMB(q->cell.cp); uint32_t nof_re_symbol = SRSLTE_NRE * q->cell.nof_prb; if (q->rho_b != 0.0f && q->rho_b != 1.0f) { float scaling = 1.0f / q->rho_b; for (uint32_t i = 0; i < q->cell.nof_ports; i++) { for (uint32_t j = 0; j < 2; j++) { cf_t *ptr; ptr = q->sf_symbols[i] + nof_re_symbol * (j * nof_symbols_slot + 0); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); if (q->cell.cp == SRSLTE_CP_NORM) { ptr = q->sf_symbols[i] + nof_re_symbol * (j * nof_symbols_slot + 4); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } else { ptr = q->sf_symbols[i] + nof_re_symbol * (j * nof_symbols_slot + 3); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } if (q->cell.nof_ports == 4) { ptr = q->sf_symbols[i] + nof_re_symbol * (j * nof_symbols_slot + 1); srslte_vec_sc_prod_cfc(ptr, scaling, ptr, nof_re_symbol); } } } } }
uint32_t srslte_sfidx_tdd_nof_dw_slot(srslte_tdd_config_t tdd_config, uint32_t slot, srslte_cp_t cp) { uint32_t n = srslte_sfidx_tdd_nof_dw(tdd_config); if (n < SRSLTE_CP_NSYMB(cp)) { if (slot == 1) { return 0; } else { return n; } } else { if (slot == 1) { return n - SRSLTE_CP_NSYMB(cp); } else { return SRSLTE_CP_NSYMB(cp); } } }
/* Generates n_cs_cell according to Sec 5.4 of 36.211 */ int srslte_pucch_n_cs_cell(srslte_cell_t cell, uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB]) { srslte_sequence_t seq; bzero(&seq, sizeof(srslte_sequence_t)); srslte_sequence_LTE_pr(&seq, 8*SRSLTE_CP_NSYMB(cell.cp)*SRSLTE_NSLOTS_X_FRAME, cell.id); for (uint32_t ns=0;ns<SRSLTE_NSLOTS_X_FRAME;ns++) { for (uint32_t l=0;l<SRSLTE_CP_NSYMB(cell.cp);l++) { n_cs_cell[ns][l] = 0; for (uint32_t i=0;i<8;i++) { n_cs_cell[ns][l] += seq.c[8*SRSLTE_CP_NSYMB(cell.cp)*ns+8*l+i]<<i; } } } srslte_sequence_free(&seq); return SRSLTE_SUCCESS; }
/** 36.211 10.3 section 6.11.2.2 */ void srslte_sss_put_slot(float *sss, cf_t *slot, uint32_t nof_prb, srslte_cp_t cp) { uint32_t i, k; k = (SRSLTE_CP_NSYMB(cp) - 2) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; if (k > 5) { memset(&slot[k - 5], 0, 5 * sizeof(cf_t)); for (i = 0; i < SRSLTE_SSS_LEN; i++) { __real__ slot[k + i] = sss[i]; __imag__ slot[k + i] = 0; } memset(&slot[k + SRSLTE_SSS_LEN], 0, 5 * sizeof(cf_t)); } }
static void interpolate_pilots(srslte_chest_ul_t *q, cf_t *ce, uint32_t nrefs, uint32_t n_prb[2]) { uint32_t L1 = SRSLTE_REFSIGNAL_UL_L(0, q->cell.cp); uint32_t L2 = SRSLTE_REFSIGNAL_UL_L(1, q->cell.cp); uint32_t NL = 2*SRSLTE_CP_NSYMB(q->cell.cp); /* Interpolate in the time domain between symbols */ srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L2), &cesymb(L1), &cesymb(L1), &cesymb(L1-1), (L2-L1), L1, false, nrefs); srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), NULL, &cesymb(L1+1), (L2-L1), (L2-L1)-1, true, nrefs); srslte_interp_linear_vector3(&q->srslte_interp_linvec, &cesymb(L1), &cesymb(L2), &cesymb(L2), &cesymb(L2+1), (L2-L1), (NL-L2)-1, true, nrefs); }
int srslte_ue_dl_decode_fft_estimate_noguru(srslte_ue_dl_t *q, cf_t *input[SRSLTE_MAX_PORTS], uint32_t sf_idx, uint32_t *cfi) { if (input && q && sf_idx < SRSLTE_NSUBFRAMES_X_FRAME) { /* Run FFT for all subframe data */ for (int j=0;j<q->nof_rx_antennas;j++) { srslte_ofdm_rx_sf_ng(&q->fft[j], input[j], q->sf_symbols_m[j]); /* Correct SFO multiplying by complex exponential in the time domain */ if (q->sample_offset) { int nsym = SRSLTE_CP_NSYMB(q->cell.cp); for (int i=0;i<2*nsym;i++) { srslte_cfo_correct(&q->sfo_correct, &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], &q->sf_symbols_m[j][i*q->cell.nof_prb*SRSLTE_NRE], q->sample_offset / q->fft[j].symbol_sz); } } } return srslte_ue_dl_decode_estimate_mbsfn(q, sf_idx, cfi, SRSLTE_SF_NORM); } else { return SRSLTE_ERROR_INVALID_INPUTS; } }
int srslte_chest_ul_estimate_pucch(srslte_chest_ul_t *q, cf_t *input, cf_t *ce, srslte_pucch_format_t format, uint32_t n_pucch, uint32_t sf_idx, uint8_t *pucch2_ack_bits) { if (!q->dmrs_signal_configured) { fprintf(stderr, "Error must call srslte_chest_ul_set_cfg() before using the UL estimator\n"); return SRSLTE_ERROR; } int n_rs = srslte_refsignal_dmrs_N_rs(format, q->cell.cp); if (!n_rs) { fprintf(stderr, "Error computing N_rs\n"); return SRSLTE_ERROR; } int nrefs_sf = SRSLTE_NRE*n_rs*2; /* Get references from the input signal */ srslte_refsignal_dmrs_pucch_get(&q->dmrs_signal, format, n_pucch, input, q->pilot_recv_signal); /* Generate known pilots */ uint8_t pucch2_bits[2] = {0, 0}; if (format == SRSLTE_PUCCH_FORMAT_2A || format == SRSLTE_PUCCH_FORMAT_2B) { float max = -1e9; int i_max = 0; int m = 0; if (format == SRSLTE_PUCCH_FORMAT_2A) { m = 2; } else { m = 4; } for (int i=0;i<m;i++) { pucch2_bits[0] = i%2; pucch2_bits[1] = i/2; srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal); srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates_tmp[i], nrefs_sf); float x = cabsf(srslte_vec_acc_cc(q->pilot_estimates_tmp[i], nrefs_sf)); if (x >= max) { max = x; i_max = i; } } memcpy(q->pilot_estimates, q->pilot_estimates_tmp[i_max], nrefs_sf*sizeof(cf_t)); pucch2_ack_bits[0] = i_max%2; pucch2_ack_bits[1] = i_max/2; } else { srslte_refsignal_dmrs_pucch_gen(&q->dmrs_signal, format, n_pucch, sf_idx, pucch2_bits, q->pilot_known_signal); /* Use the known DMRS signal to compute Least-squares estimates */ srslte_vec_prod_conj_ccc(q->pilot_recv_signal, q->pilot_known_signal, q->pilot_estimates, nrefs_sf); } if (ce != NULL) { /* FIXME: Currently averaging entire slot, performance good enough? */ for (int ns=0;ns<2;ns++) { // Average all slot for (int i=1;i<n_rs;i++) { srslte_vec_sum_ccc(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_estimates[(i+ns*n_rs)*SRSLTE_NRE], &q->pilot_estimates[ns*n_rs*SRSLTE_NRE], SRSLTE_NRE); } srslte_vec_sc_prod_ccc(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], (float) 1.0/n_rs, &q->pilot_estimates[ns*n_rs*SRSLTE_NRE], SRSLTE_NRE); // Average in freq domain srslte_chest_average_pilots(&q->pilot_estimates[ns*n_rs*SRSLTE_NRE], &q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE], q->smooth_filter, SRSLTE_NRE, 1, q->smooth_filter_len); // Determine n_prb uint32_t n_prb = srslte_pucch_n_prb(&q->dmrs_signal.pucch_cfg, format, n_pucch, q->cell.nof_prb, q->cell.cp, ns); // copy estimates to slot for (int i=0;i<SRSLTE_CP_NSYMB(q->cell.cp);i++) { memcpy(&ce[SRSLTE_RE_IDX(q->cell.nof_prb, i+ns*SRSLTE_CP_NSYMB(q->cell.cp), n_prb*SRSLTE_NRE)], &q->pilot_recv_signal[ns*n_rs*SRSLTE_NRE], sizeof(cf_t)*SRSLTE_NRE); } } } return 0; }
/* the gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int i; srslte_cell_t cell; srslte_pdsch_t pdsch; srslte_chest_dl_t chest; srslte_ofdm_t fft; cf_t *input_fft, *input_signal; int nof_re; srslte_pdsch_cfg_t cfg; srslte_softbuffer_rx_t softbuffer; uint32_t rnti32; uint32_t cfi; if (nrhs < NOF_INPUTS) { help(); return; } bzero(&cfg, sizeof(srslte_pdsch_cfg_t)); if (mexutils_read_cell(ENBCFG, &cell)) { help(); return; } if (mexutils_read_uint32_struct(PDSCHCFG, "RNTI", &rnti32)) { mexErrMsgTxt("Field RNTI not found in pdsch config\n"); return; } if (mexutils_read_uint32_struct(ENBCFG, "CFI", &cfi)) { help(); return; } if (mexutils_read_uint32_struct(ENBCFG, "NSubframe", &cfg.sf_idx)) { help(); return; } if (srslte_pdsch_init(&pdsch, cell)) { mexErrMsgTxt("Error initiating PDSCH\n"); return; } srslte_pdsch_set_rnti(&pdsch, (uint16_t) (rnti32 & 0xffff)); if (srslte_softbuffer_rx_init(&softbuffer, cell)) { mexErrMsgTxt("Error initiating soft buffer\n"); return; } if (srslte_chest_dl_init(&chest, cell)) { mexErrMsgTxt("Error initializing equalizer\n"); return; } if (srslte_ofdm_rx_init(&fft, cell.cp, cell.nof_prb)) { mexErrMsgTxt("Error initializing FFT\n"); return; } nof_re = 2 * SRSLTE_CP_NORM_NSYMB * cell.nof_prb * SRSLTE_NRE; cfg.grant.mcs.tbs = mxGetScalar(TBS); if (cfg.grant.mcs.tbs == 0) { mexErrMsgTxt("Error trblklen is zero\n"); return; } if (srslte_cbsegm(&cfg.cb_segm, cfg.grant.mcs.tbs)) { mexErrMsgTxt("Error computing CB segmentation\n"); return; } if (mexutils_read_uint32_struct(PDSCHCFG, "RV", &cfg.rv)) { mexErrMsgTxt("Field RV not found in pdsch config\n"); return; } char *mod_str = mexutils_get_char_struct(PDSCHCFG, "Modulation"); if (!strcmp(mod_str, "QPSK")) { cfg.grant.mcs.mod = SRSLTE_MOD_QPSK; } else if (!strcmp(mod_str, "16QAM")) { cfg.grant.mcs.mod = SRSLTE_MOD_16QAM; } else if (!strcmp(mod_str, "64QAM")) { cfg.grant.mcs.mod = SRSLTE_MOD_64QAM; } else { mexErrMsgTxt("Unknown modulation\n"); return; } mxFree(mod_str); float *prbset; mxArray *p; p = mxGetField(PDSCHCFG, 0, "PRBSet"); if (!p) { mexErrMsgTxt("Error field PRBSet not found\n"); return; } // Only localized PRB supported cfg.grant.nof_prb = mexutils_read_f(p, &prbset); for (i=0;i<cell.nof_prb;i++) { cfg.grant.prb_idx[0][i] = false; for (int j=0;j<cfg.grant.nof_prb && !cfg.grant.prb_idx[0][i];j++) { if ((int) prbset[j] == i) { cfg.grant.prb_idx[0][i] = true; } } } memcpy(&cfg.grant.prb_idx[1], &cfg.grant.prb_idx[0], SRSLTE_MAX_PRB*sizeof(bool)); free(prbset); srslte_dl_dci_to_grant_nof_re(&cfg.grant, cell, cfg.sf_idx, cell.nof_prb<10?(cfi+1):cfi); // Fill rest of grant structure cfg.grant.lstart = cell.nof_prb<10?(cfi+1):cfi; cfg.grant.nof_symb = 2*SRSLTE_CP_NSYMB(cell.cp)-cfg.grant.lstart; cfg.grant.Qm = srslte_mod_bits_x_symbol(cfg.grant.mcs.mod); cfg.grant.nof_bits = cfg.grant.nof_re * cfg.grant.Qm; /** Allocate input buffers */ if (mexutils_read_cf(INPUT, &input_signal) < 0) { mexErrMsgTxt("Error reading input signal\n"); return; } input_fft = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); cf_t *ce[SRSLTE_MAX_PORTS]; for (i=0;i<cell.nof_ports;i++) { ce[i] = srslte_vec_malloc(SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp) * sizeof(cf_t)); } srslte_ofdm_rx_sf(&fft, input_signal, input_fft); if (nrhs > NOF_INPUTS) { cf_t *cearray = NULL; nof_re = mexutils_read_cf(prhs[NOF_INPUTS], &cearray); cf_t *cearray_ptr = cearray; for (i=0;i<cell.nof_ports;i++) { for (int j=0;j<nof_re/cell.nof_ports;j++) { ce[i][j] = *cearray; cearray++; } } if (cearray_ptr) free(cearray_ptr); } else { srslte_chest_dl_estimate(&chest, input_fft, ce, cfg.sf_idx); } float noise_power; if (nrhs > NOF_INPUTS + 1) { noise_power = mxGetScalar(prhs[NOF_INPUTS+1]); } else { noise_power = srslte_chest_dl_get_noise_estimate(&chest); } uint8_t *data = malloc(sizeof(uint8_t) * cfg.grant.mcs.tbs); if (!data) { return; } int r = srslte_pdsch_decode(&pdsch, &cfg, &softbuffer, input_fft, ce, noise_power, data); if (nlhs >= 1) { plhs[0] = mxCreateLogicalScalar(r == 0); } if (nlhs >= 2) { mexutils_write_uint8(data, &plhs[1], cfg.grant.mcs.tbs, 1); } if (nlhs >= 3) { mexutils_write_cf(pdsch.symbols[0], &plhs[2], cfg.grant.nof_re, 1); } if (nlhs >= 4) { mexutils_write_cf(pdsch.d, &plhs[3], cfg.grant.nof_re, 1); } if (nlhs >= 5) { mexutils_write_f(pdsch.e, &plhs[4], cfg.grant.nof_bits, 1); } srslte_chest_dl_free(&chest); srslte_ofdm_rx_free(&fft); srslte_pdsch_free(&pdsch); for (i=0;i<cell.nof_ports;i++) { free(ce[i]); } free(data); free(input_signal); free(input_fft); return; }
void srslte_pss_get_slot(cf_t *slot, cf_t *pss_signal, uint32_t nof_prb, srslte_cp_t cp) { int k; k = (SRSLTE_CP_NSYMB(cp) - 1) * nof_prb * SRSLTE_NRE + nof_prb * SRSLTE_NRE / 2 - 31; memcpy(pss_signal, &slot[k], SRSLTE_PSS_LEN * sizeof(cf_t)); }
int srslte_pdsch_cp(srslte_pdsch_t *q, cf_t *input, cf_t *output, srslte_ra_dl_grant_t *grant, uint32_t lstart_grant, uint32_t nsubframe, bool put) { uint32_t s, n, l, lp, lstart, lend, nof_refs; bool is_pbch, is_sss; cf_t *in_ptr = input, *out_ptr = output; uint32_t offset = 0; #ifdef DEBUG_IDX indices_ptr = 0; if (put) { offset_original = output; } else { offset_original = input; } #endif if (q->cell.nof_ports == 1) { nof_refs = 2; } else { nof_refs = 4; } for (s = 0; s < 2; s++) { for (l = 0; l < SRSLTE_CP_NSYMB(q->cell.cp); l++) { for (n = 0; n < q->cell.nof_prb; n++) { // If this PRB is assigned if (grant->prb_idx[s][n]) { if (s == 0) { lstart = lstart_grant; } else { lstart = 0; } lend = SRSLTE_CP_NSYMB(q->cell.cp); is_pbch = is_sss = false; // Skip PSS/SSS signals if (s == 0 && (nsubframe == 0 || nsubframe == 5)) { if (n >= q->cell.nof_prb / 2 - 3 && n < q->cell.nof_prb / 2 + 3 + (q->cell.nof_prb%2)) { lend = SRSLTE_CP_NSYMB(q->cell.cp) - 2; is_sss = true; } } // Skip PBCH if (s == 1 && nsubframe == 0) { if (n >= q->cell.nof_prb / 2 - 3 && n < q->cell.nof_prb / 2 + 3 + (q->cell.nof_prb%2)) { lstart = 4; is_pbch = true; } } lp = l + s * SRSLTE_CP_NSYMB(q->cell.cp); if (put) { out_ptr = &output[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; } else { in_ptr = &input[(lp * q->cell.nof_prb + n) * SRSLTE_NRE]; } // This is a symbol in a normal PRB with or without references if (l >= lstart && l < lend) { if (SRSLTE_SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { if (nof_refs == 2) { if (l == 0) { offset = q->cell.id % 6; } else { offset = (q->cell.id + 3) % 6; } } else { offset = q->cell.id % 3; } prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs, put); } else { prb_cp(&in_ptr, &out_ptr, 1); } } // This is a symbol in a PRB with PBCH or Synch signals (SS). // If the number or total PRB is odd, half of the the PBCH or SS will fall into the symbol if ((q->cell.nof_prb % 2) && ((is_pbch && l < lstart) || (is_sss && l >= lend))) { if (n == q->cell.nof_prb / 2 - 3) { if (SRSLTE_SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); } else { prb_cp_half(&in_ptr, &out_ptr, 1); } } else if (n == q->cell.nof_prb / 2 + 3) { if (put) { out_ptr += 6; } else { in_ptr += 6; } if (SRSLTE_SYMBOL_HAS_REF(l, q->cell.cp, q->cell.nof_ports)) { prb_cp_ref(&in_ptr, &out_ptr, offset, nof_refs, nof_refs/2, put); } else { prb_cp_half(&in_ptr, &out_ptr, 1); } } } } } } } int r; if (put) { r = abs((int) (input - in_ptr)); } else { r = abs((int) (output - out_ptr)); } return r; }
static void compute_nof_re(srslte_pusch_grant_t* grant, srslte_cp_t cp, uint32_t N_srs) { grant->nof_symb = 2 * (SRSLTE_CP_NSYMB(cp) - 1) - N_srs; grant->nof_re = grant->nof_symb * grant->L_prb * SRSLTE_NRE; grant->tb.nof_bits = grant->nof_re * srslte_mod_bits_x_symbol(grant->tb.mod); }
/* the gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int i; srslte_cell_t cell; srslte_chest_dl_t chest; srslte_precoding_t cheq; cf_t *input_signal = NULL, *output_signal[SRSLTE_MAX_LAYERS]; cf_t *output_signal2 = NULL; cf_t *ce[SRSLTE_MAX_PORTS]; double *outr0=NULL, *outi0=NULL; double *outr1=NULL, *outi1=NULL; double *outr2=NULL, *outi2=NULL; if (!mxIsDouble(CELLID) && mxGetN(CELLID) != 1 && !mxIsDouble(PORTS) && mxGetN(PORTS) != 1 && mxGetM(CELLID) != 1) { help(); return; } cell.id = (uint32_t) *((double*) mxGetPr(CELLID)); cell.nof_prb = mxGetM(INPUT)/SRSLTE_NRE; cell.nof_ports = (uint32_t) *((double*) mxGetPr(PORTS)); if ((mxGetN(INPUT)%14) == 0) { cell.cp = SRSLTE_CP_NORM; } else if ((mxGetN(INPUT)%12)!=0) { cell.cp = SRSLTE_CP_EXT; } else { mexErrMsgTxt("Invalid number of symbols\n"); help(); return; } if (srslte_chest_dl_init(&chest, cell)) { mexErrMsgTxt("Error initiating channel estimator\n"); return; } int nsubframes; if (cell.cp == SRSLTE_CP_NORM) { nsubframes = mxGetN(INPUT)/14; } else { nsubframes = mxGetN(INPUT)/12; } uint32_t sf_idx=0; if (nsubframes == 1) { if (nrhs != NOF_INPUTS+1) { mexErrMsgTxt("Received 1 subframe. Need to provide subframe index.\n"); help(); return; } sf_idx = (uint32_t) *((double*) mxGetPr(SFIDX)); } if (nrhs > 5) { uint32_t filter_len = 0; float *filter; double *f; filter_len = mxGetNumberOfElements(FREQ_FILTER); filter = malloc(sizeof(float) * filter_len); f = (double*) mxGetPr(FREQ_FILTER); for (i=0;i<filter_len;i++) { filter[i] = (float) f[i]; } srslte_chest_dl_set_filter_freq(&chest, filter, filter_len); filter_len = mxGetNumberOfElements(TIME_FILTER); filter = malloc(sizeof(float) * filter_len); f = (double*) mxGetPr(TIME_FILTER); for (i=0;i<filter_len;i++) { filter[i] = (float) f[i]; } srslte_chest_dl_set_filter_time(&chest, filter, filter_len); } double *inr=(double *)mxGetPr(INPUT); double *ini=(double *)mxGetPi(INPUT); /** Allocate input buffers */ int nof_re = 2*SRSLTE_CP_NSYMB(cell.cp)*cell.nof_prb*SRSLTE_NRE; for (i=0;i<SRSLTE_MAX_PORTS;i++) { ce[i] = srslte_vec_malloc(nof_re * sizeof(cf_t)); } input_signal = srslte_vec_malloc(nof_re * sizeof(cf_t)); for (i=0;i<SRSLTE_MAX_PORTS;i++) { output_signal[i] = srslte_vec_malloc(nof_re * sizeof(cf_t)); } output_signal2 = srslte_vec_malloc(nof_re * sizeof(cf_t)); srslte_precoding_init(&cheq, nof_re); /* Create output values */ if (nlhs >= 1) { plhs[0] = mxCreateDoubleMatrix(nof_re * nsubframes, cell.nof_ports, mxCOMPLEX); outr0 = mxGetPr(plhs[0]); outi0 = mxGetPi(plhs[0]); } if (nlhs >= 2) { plhs[1] = mxCreateDoubleMatrix(SRSLTE_REFSIGNAL_MAX_NUM_SF(cell.nof_prb)*nsubframes, cell.nof_ports, mxCOMPLEX); outr1 = mxGetPr(plhs[1]); outi1 = mxGetPi(plhs[1]); } if (nlhs >= 3) { plhs[2] = mxCreateDoubleMatrix(nof_re * nsubframes, 1, mxCOMPLEX); outr2 = mxGetPr(plhs[2]); outi2 = mxGetPi(plhs[2]); } for (int sf=0;sf<nsubframes;sf++) { /* Convert input to C complex type */ for (i=0;i<nof_re;i++) { __real__ input_signal[i] = (float) *inr; if (ini) { __imag__ input_signal[i] = (float) *ini; } inr++; ini++; } if (nsubframes != 1) { sf_idx = sf%10; } if (srslte_chest_dl_estimate(&chest, input_signal, ce, sf_idx)) { mexErrMsgTxt("Error running channel estimator\n"); return; } if (cell.nof_ports == 1) { srslte_predecoding_single(input_signal, ce[0], output_signal2, nof_re, srslte_chest_dl_get_noise_estimate(&chest)); } else { srslte_predecoding_diversity(&cheq, input_signal, ce, output_signal, cell.nof_ports, nof_re, srslte_chest_dl_get_noise_estimate(&chest)); srslte_layerdemap_diversity(output_signal, output_signal2, cell.nof_ports, nof_re/cell.nof_ports); } if (nlhs >= 1) { for (int j=0;j<cell.nof_ports;j++) { for (i=0;i<nof_re;i++) { *outr0 = (double) crealf(ce[j][i]); if (outi0) { *outi0 = (double) cimagf(ce[j][i]); } outr0++; outi0++; } } } if (nlhs >= 2) { for (int j=0;j<cell.nof_ports;j++) { for (i=0;i<SRSLTE_REFSIGNAL_NUM_SF(cell.nof_prb,j);i++) { *outr1 = (double) crealf(chest.pilot_estimates_average[j][i]); if (outi1) { *outi1 = (double) cimagf(chest.pilot_estimates_average[j][i]); } outr1++; outi1++; } } } if (nlhs >= 3) { for (i=0;i<nof_re;i++) { *outr2 = (double) crealf(output_signal2[i]); if (outi2) { *outi2 = (double) cimagf(output_signal2[i]); } outr2++; outi2++; } } } if (nlhs >= 4) { plhs[3] = mxCreateDoubleScalar(srslte_chest_dl_get_noise_estimate(&chest)); } if (nlhs >= 5) { plhs[4] = mxCreateDoubleScalar(srslte_chest_dl_get_rsrp(&chest)); } srslte_chest_dl_free(&chest); srslte_precoding_free(&cheq); return; }
int main(int argc, char **argv) { srslte_pusch_t pusch; uint8_t *data = NULL; cf_t *sf_symbols = NULL; cf_t *ce = NULL; int ret = -1; struct timeval t[3]; srslte_pusch_cfg_t cfg; srslte_softbuffer_tx_t softbuffer_tx; srslte_softbuffer_rx_t softbuffer_rx; parse_args(argc,argv); bzero(&cfg, sizeof(srslte_pusch_cfg_t)); srslte_ra_ul_dci_t dci; dci.freq_hop_fl = freq_hop; if (riv < 0) { dci.type2_alloc.L_crb = L_prb; dci.type2_alloc.RB_start = n_prb; } else { dci.type2_alloc.riv = riv; } dci.mcs_idx = mcs_idx; srslte_ra_ul_grant_t grant; if (srslte_ra_ul_dci_to_grant(&dci, cell.nof_prb, 0, &grant, 0)) { fprintf(stderr, "Error computing resource allocation\n"); return ret; } srslte_pusch_hopping_cfg_t ul_hopping; ul_hopping.n_sb = 1; ul_hopping.hopping_offset = 0; ul_hopping.hop_mode = SRSLTE_PUSCH_HOP_MODE_INTER_SF; if (srslte_pusch_init(&pusch, cell)) { fprintf(stderr, "Error creating PDSCH object\n"); goto quit; } /* Configure PUSCH */ printf("Encoding rv_idx=%d\n",rv_idx); srslte_uci_cfg_t uci_cfg; uci_cfg.I_offset_cqi = 6; uci_cfg.I_offset_ri = 2; uci_cfg.I_offset_ack = 4; if (srslte_pusch_cfg(&pusch, &cfg, &grant, &uci_cfg, &ul_hopping, NULL, subframe, 0, 0)) { fprintf(stderr, "Error configuring PDSCH\n"); exit(-1); } srslte_pusch_set_rnti(&pusch, 1234); srslte_uci_data_t uci_data_tx; srslte_uci_data_t uci_data_rx; bzero(&uci_data_tx, sizeof(srslte_uci_data_t)); uci_data_tx.uci_cqi_len = 4; uci_data_tx.uci_ri_len = 0; uci_data_tx.uci_ack_len = 0; memcpy(&uci_data_rx, &uci_data_tx, sizeof(srslte_uci_data_t)); for (uint32_t i=0;i<20;i++) { uci_data_tx.uci_cqi [i] = 1; } uci_data_tx.uci_ri = 1; uci_data_tx.uci_ack = 1; uint32_t nof_re = SRSLTE_NRE*cell.nof_prb*2*SRSLTE_CP_NSYMB(cell.cp); sf_symbols = srslte_vec_malloc(sizeof(cf_t) * nof_re); if (!sf_symbols) { perror("malloc"); exit(-1); } data = srslte_vec_malloc(sizeof(uint8_t) * cfg.grant.mcs.tbs); if (!data) { perror("malloc"); exit(-1); } for (uint32_t i=0;i<cfg.grant.mcs.tbs/8;i++) { data[i] = 1; } if (srslte_softbuffer_tx_init(&softbuffer_tx, 100)) { fprintf(stderr, "Error initiating soft buffer\n"); goto quit; } if (srslte_softbuffer_rx_init(&softbuffer_rx, 100)) { fprintf(stderr, "Error initiating soft buffer\n"); goto quit; } uint32_t ntrials = 100; if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } if (rv_idx > 0) { cfg.rv = rv_idx; if (srslte_pusch_uci_encode(&pusch, &cfg, &softbuffer_tx, data, uci_data_tx, sf_symbols)) { fprintf(stderr, "Error encoding TB\n"); exit(-1); } } ce = srslte_vec_malloc(sizeof(cf_t) * SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp)); if (!ce) { perror("srslte_vec_malloc"); goto quit; } for (int j=0;j<SRSLTE_SF_LEN_RE(cell.nof_prb, cell.cp);j++) { ce[j] = 1; } gettimeofday(&t[1], NULL); int r = srslte_pusch_uci_decode(&pusch, &cfg, &softbuffer_rx, sf_symbols, ce, 0, data, &uci_data_rx); gettimeofday(&t[2], NULL); get_time_interval(t); if (r) { printf("Error decoding\n"); ret = -1; } else { ret = 0; printf("DECODED OK in %d:%d (TBS: %d bits, TX: %.2f Mbps, Processing: %.2f Mbps)\n", (int) t[0].tv_sec, (int) t[0].tv_usec/ntrials, cfg.grant.mcs.tbs, (float) cfg.grant.mcs.tbs/1000, (float) cfg.grant.mcs.tbs/t[0].tv_usec*ntrials); } if (uci_data_tx.uci_ack_len) { if (uci_data_tx.uci_ack != uci_data_rx.uci_ack) { printf("UCI ACK bit error: %d != %d\n", uci_data_tx.uci_ack, uci_data_rx.uci_ack); } } if (uci_data_tx.uci_ri_len) { if (uci_data_tx.uci_ri != uci_data_rx.uci_ri) { printf("UCI RI bit error: %d != %d\n", uci_data_tx.uci_ri, uci_data_rx.uci_ri); } } if (uci_data_tx.uci_cqi_len) { printf("cqi_tx="); srslte_vec_fprint_b(stdout, uci_data_tx.uci_cqi, uci_data_tx.uci_cqi_len); printf("cqi_rx="); srslte_vec_fprint_b(stdout, uci_data_rx.uci_cqi, uci_data_rx.uci_cqi_len); } quit: srslte_pusch_free(&pusch); srslte_softbuffer_tx_free(&softbuffer_tx); if (sf_symbols) { free(sf_symbols); } if (data) { free(data); } if (ce) { free(ce); } if (ret) { printf("Error\n"); } else { printf("Ok\n"); } exit(ret); }
/* the gateway function */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { srslte_sch_t ulsch; srslte_pusch_cfg_t cfg; srslte_softbuffer_tx_t softbuffer; srslte_uci_data_t uci_data; bzero(&uci_data, sizeof(srslte_uci_data_t)); uint32_t rv; if (nrhs < NOF_INPUTS) { help(); return; } bzero(&cfg, sizeof(srslte_pusch_cfg_t)); if (srslte_sch_init(&ulsch)) { mexErrMsgTxt("Error initiating ULSCH\n"); return; } srslte_cell_t cell; cell.nof_prb = 100; cell.id=1; cell.cp=SRSLTE_CP_NORM; if (srslte_softbuffer_tx_init(&softbuffer, cell.nof_prb)) { mexErrMsgTxt("Error initiating HARQ\n"); return; } uint8_t *trblkin_bits = NULL; cfg.grant.mcs.tbs = mexutils_read_uint8(TRBLKIN, &trblkin_bits); uint8_t *trblkin = srslte_vec_malloc(cfg.grant.mcs.tbs/8); srslte_bit_unpack_vector(trblkin_bits, trblkin, cfg.grant.mcs.tbs); free(trblkin_bits); uint8_t *tmp; uci_data.uci_cqi_len = mexutils_read_uint8(CQI, &tmp); memcpy(uci_data.uci_cqi, tmp, uci_data.uci_cqi_len); free(tmp); uci_data.uci_ri_len = mexutils_read_uint8(RI, &tmp); if (uci_data.uci_ri_len > 0) { uci_data.uci_ri = *tmp; } free(tmp); uci_data.uci_ack_len = mexutils_read_uint8(ACK, &tmp); if (uci_data.uci_ack_len > 0) { uci_data.uci_ack = *tmp; } free(tmp); mexPrintf("TRBL_len: %d, CQI_len: %d, ACK_len: %d, RI_len: %d\n", cfg.grant.mcs.tbs, uci_data.uci_cqi_len, uci_data.uci_ack_len, uci_data.uci_ri_len); if (mexutils_read_uint32_struct(PUSCHCFG, "RV", &rv)) { mexErrMsgTxt("Field RV not found in pdsch config\n"); return; } float beta; if (mexutils_read_float_struct(PUSCHCFG, "BetaCQI", &beta)) { cfg.uci_cfg.I_offset_cqi = 7; } else { cfg.uci_cfg.I_offset_cqi = srslte_sch_find_Ioffset_cqi(beta); } if (mexutils_read_float_struct(PUSCHCFG, "BetaRI", &beta)) { cfg.uci_cfg.I_offset_ri = 2; } else { cfg.uci_cfg.I_offset_ri = srslte_sch_find_Ioffset_ri(beta); } if (mexutils_read_float_struct(PUSCHCFG, "BetaACK", &beta)) { cfg.uci_cfg.I_offset_ack = 0; } else { cfg.uci_cfg.I_offset_ack = srslte_sch_find_Ioffset_ack(beta); } char *mod_str = mexutils_get_char_struct(PUSCHCFG, "Modulation"); if (!strcmp(mod_str, "QPSK")) { cfg.grant.mcs.mod = SRSLTE_MOD_QPSK; } else if (!strcmp(mod_str, "16QAM")) { cfg.grant.mcs.mod = SRSLTE_MOD_16QAM; } else if (!strcmp(mod_str, "64QAM")) { cfg.grant.mcs.mod = SRSLTE_MOD_64QAM; } else { mexErrMsgTxt("Unknown modulation\n"); return; } mxFree(mod_str); float *prbset; mxArray *p; p = mxGetField(PUSCHCFG, 0, "PRBSet"); if (!p) { mexErrMsgTxt("Error field PRBSet not found\n"); return; } uint32_t N_srs = 0; mexutils_read_uint32_struct(PUSCHCFG, "Shortened", &N_srs); cfg.grant.L_prb = mexutils_read_f(p, &prbset); cfg.grant.n_prb[0] = prbset[0]; cfg.grant.n_prb[1] = prbset[0]; free(prbset); cfg.grant.L_prb = mexutils_read_f(p, &prbset); cfg.grant.n_prb[0] = prbset[0]; cfg.grant.n_prb[1] = prbset[0]; cfg.nbits.lstart = 0; cfg.nbits.nof_symb = 2*(SRSLTE_CP_NSYMB(cell.cp)-1) - N_srs; cfg.grant.M_sc = cfg.grant.L_prb*SRSLTE_NRE; cfg.grant.M_sc_init = cfg.grant.M_sc; // FIXME: What should M_sc_init be? cfg.nbits.nof_re = cfg.nbits.nof_symb*cfg.grant.M_sc; cfg.grant.Qm = srslte_mod_bits_x_symbol(cfg.grant.mcs.mod); cfg.nbits.nof_bits = cfg.nbits.nof_re * cfg.grant.Qm; mexPrintf("Q_m: %d, NPRB: %d, RV: %d, Nsrs=%d\n", srslte_mod_bits_x_symbol(cfg.grant.mcs.mod), cfg.grant.L_prb, cfg.rv, N_srs); mexPrintf("I_cqi: %d, I_ri: %d, I_ack=%d\n", cfg.uci_cfg.I_offset_cqi, cfg.uci_cfg.I_offset_ri, cfg.uci_cfg.I_offset_ack); if (srslte_cbsegm(&cfg.cb_segm, cfg.grant.mcs.tbs)) { mexErrMsgTxt("Error configuring HARQ process\n"); return; } uint8_t *q_bits = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)); if (!q_bits) { return; } uint8_t *g_bits = srslte_vec_malloc(cfg.nbits.nof_bits * sizeof(uint8_t)); if (!g_bits) { return; } if (srslte_ulsch_uci_encode(&ulsch, &cfg, &softbuffer, trblkin, uci_data, g_bits, q_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; } if (rv > 0) { cfg.rv = rv; if (srslte_ulsch_uci_encode(&ulsch, &cfg, &softbuffer, trblkin, uci_data, g_bits, q_bits)) { mexErrMsgTxt("Error encoding TB\n"); return; } } if (nlhs >= 1) { mexutils_write_uint8(q_bits, &plhs[0], cfg.nbits.nof_bits, 1); } srslte_sch_free(&ulsch); srslte_softbuffer_tx_free(&softbuffer); free(trblkin); free(g_bits); free(q_bits); return; }