/** * Resets the PHICH symbols * * Returns the number of written symbols, or -1 on error */ int srslte_regs_phich_reset(srslte_regs_t *h, cf_t *slot_symbols) { uint32_t i; uint32_t ngroup, ng; for (ngroup = 0;ngroup < h->ngroups_phich;SRSLTE_CP_ISEXT(h->cell.cp)?ngroup+=2:ngroup++) { if (SRSLTE_CP_ISEXT(h->cell.cp)) { ng = ngroup/2; } else { ng = ngroup; } srslte_regs_ch_t *rch = &h->phich[ng]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { regs_reset_reg(rch->regs[i], slot_symbols, h->cell.nof_prb); } } return SRSLTE_SUCCESS; }
/* Calculates alpha for format 1/a/b according to 5.5.2.2.2 (is_dmrs=true) or 5.4.1 (is_dmrs=false) of 36.211 */ float srslte_pucch_alpha_format1(uint32_t n_cs_cell[SRSLTE_NSLOTS_X_FRAME][SRSLTE_CP_NORM_NSYMB], srslte_pucch_cfg_t *cfg, uint32_t n_pucch, srslte_cp_t cp, bool is_dmrs, uint32_t ns, uint32_t l, uint32_t *n_oc_ptr, uint32_t *n_prime_ns) { uint32_t c = SRSLTE_CP_ISNORM(cp)?3:2; uint32_t N_prime = (n_pucch < c*cfg->N_cs/cfg->delta_pucch_shift)?cfg->N_cs:SRSLTE_NRE; uint32_t n_prime = n_pucch; if (n_pucch >= c*cfg->N_cs/cfg->delta_pucch_shift) { n_prime = (n_pucch-c*cfg->N_cs/cfg->delta_pucch_shift)%(c*SRSLTE_NRE/cfg->delta_pucch_shift); } if (ns%2) { if (n_pucch >= c*cfg->N_cs/cfg->delta_pucch_shift) { n_prime = (c*(n_prime+1))%(c*SRSLTE_NRE/cfg->delta_pucch_shift+1)-1; } else { uint32_t d=SRSLTE_CP_ISNORM(cp)?2:0; uint32_t h=(n_prime+d)%(c*N_prime/cfg->delta_pucch_shift); n_prime = (h/c)+(h%c)*N_prime/cfg->delta_pucch_shift; } } if (n_prime_ns) { *n_prime_ns = n_prime; } uint32_t n_oc_div = (!is_dmrs && SRSLTE_CP_ISEXT(cp))?2:1; uint32_t n_oc = n_prime*cfg->delta_pucch_shift/N_prime; if (!is_dmrs && SRSLTE_CP_ISEXT(cp)) { n_oc *= 2; } if (n_oc_ptr) { *n_oc_ptr = n_oc; } uint32_t n_cs = 0; if (SRSLTE_CP_ISNORM(cp)) { n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+(n_oc%cfg->delta_pucch_shift))%N_prime)%SRSLTE_NRE; } else { n_cs = (n_cs_cell[ns][l]+(n_prime*cfg->delta_pucch_shift+n_oc/n_oc_div)%N_prime)%SRSLTE_NRE; } return 2 * M_PI * (n_cs) / SRSLTE_NRE; }
/** * Gets the PHICH symbols from the resource grid pointed by slot_symbols * * Returns the number of written symbols, or -1 on error */ int srslte_regs_phich_get(srslte_regs_t *h, cf_t *slot_symbols, cf_t symbols[REGS_PHICH_NSYM], uint32_t ngroup) { uint32_t i; if (ngroup >= h->ngroups_phich) { fprintf(stderr, "Error invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(h->cell.cp)) { ngroup /= 2; } srslte_regs_ch_t *rch = &h->phich[ngroup]; for (i = 0; i < rch->nof_regs && i*REGS_RE_X_REG < REGS_PHICH_NSYM; i++) { regs_get_reg(rch->regs[i], slot_symbols, &symbols[i*REGS_RE_X_REG], h->cell.nof_prb); } return i*REGS_RE_X_REG; }
void regs_phich_free(srslte_regs_t *h) { uint32_t i; if (h->phich) { if (SRSLTE_CP_ISEXT(h->cell.cp)) { h->ngroups_phich /= 2; } for (i=0;i<h->ngroups_phich;i++) { if (h->phich[i].regs) { free(h->phich[i].regs); h->phich[i].regs = NULL; } } free(h->phich); h->phich = NULL; } }
/** Initialize REGs for PHICH * 36.211 10.3 section 6.9.3 */ int regs_phich_init(srslte_regs_t *h) { float ng; uint32_t i, ni, li, n[3], nreg, mi; srslte_regs_reg_t **regs_phich[3]; int ret = SRSLTE_ERROR; switch(h->phich_res) { case SRSLTE_PHICH_SRSLTE_PHICH_R_1_6: ng = (float) 1/6; break; case SRSLTE_PHICH_SRSLTE_PHICH_R_1_2: ng = (float) 1/2; break; case SRSLTE_PHICH_R_1: ng = 1; break; case SRSLTE_PHICH_R_2: ng = 2; break; default: ng = 0; break; } h->ngroups_phich = (int) ceilf(ng * ((float) h->cell.nof_prb/8)); h->phich = malloc(sizeof(srslte_regs_ch_t) * h->ngroups_phich); if (!h->phich) { perror("malloc"); return -1; } INFO("Creating %d PHICH mapping units. %s length, Ng=%.2f\n",h->ngroups_phich, h->phich_len==SRSLTE_PHICH_EXT?"Extended":"Normal",ng); for (i=0;i<h->ngroups_phich;i++) { h->phich[i].nof_regs = REGS_PHICH_REGS_X_GROUP; h->phich[i].regs = malloc(sizeof(srslte_regs_reg_t*) * REGS_PHICH_REGS_X_GROUP); if (!h->phich[i].regs) { perror("malloc"); goto clean_and_exit; } } /** Here begins the mapping algorithm */ /* Step 2. Count REGs not assigned to PCFICH */ bzero(n, 3*sizeof(int)); for (i=0;i<h->nof_regs;i++) { if (h->regs[i].l < 3 && !h->regs[i].assigned) { n[h->regs[i].l]++; } } bzero(regs_phich, sizeof(srslte_regs_reg_t*) * 3); for (i=0;i<3;i++) { regs_phich[i] = malloc(n[i] * sizeof(srslte_regs_reg_t*)); if (!regs_phich[i]) { perror("malloc"); goto clean_and_exit; } } bzero(n, 3 * sizeof(int)); /* Step 3. Number REGs not assigned to PCFICH */ for (i=0;i<h->nof_regs;i++) { // they are already sorted starting from the REG with the lowest frequency-domain index if (h->regs[i].l < 3 && !h->regs[i].assigned) { regs_phich[h->regs[i].l][n[h->regs[i].l]++] = &h->regs[i]; } } nreg=0; for (mi=0;mi<h->ngroups_phich;mi++) { // here ngroups is the number of mapping units for (i=0;i<3;i++) { li=h->phich_len==SRSLTE_PHICH_EXT?i:0; // Step 7 ni=((h->cell.id*n[li]/n[0])+mi+i*n[li]/3) % n[li]; // Step 8 h->phich[mi].regs[i] = regs_phich[li][ni]; h->phich[mi].regs[i]->assigned = true; DEBUG("Assigned PHICH REG#%d (%d,%d)\n",nreg,h->phich[mi].regs[i]->k0,li); nreg++; } } // now the number of mapping units = number of groups for normal cp. For extended cp // ngroups = 2 * number mapping units if (SRSLTE_CP_ISEXT(h->cell.cp)) { h->ngroups_phich *= 2; } ret = SRSLTE_SUCCESS; clean_and_exit: if (ret == SRSLTE_ERROR) { if (h->phich) { for (i=0;i<h->ngroups_phich;i++) { if (h->phich[i].regs) { free(h->phich[i].regs); } } free(h->phich); } } for (i=0;i<3;i++) { if (regs_phich[i]) { free(regs_phich[i]); } } return ret; }
/** Encodes ACK/NACK bits, modulates and inserts into resource. * The parameter ack is an array of srslte_phich_ngroups() pointers to buffers of nof_sequences uint8_ts */ int srslte_phich_encode(srslte_phich_t *q, uint8_t ack, uint32_t ngroup, uint32_t nseq, uint32_t subframe, cf_t *slot_symbols[SRSLTE_MAX_PORTS]) { int i; if (q == NULL || slot_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } if (subframe >= SRSLTE_NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid nslot %d\n", subframe); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } else { if (nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= srslte_regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } /* Set pointers for layermapping & precoding */ cf_t *x[SRSLTE_MAX_LAYERS]; cf_t *symbols_precoding[SRSLTE_MAX_PORTS]; /* number of layers equals number of ports */ for (i = 0; i < q->cell.nof_ports; i++) { x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { symbols_precoding[i] = q->symbols[i]; } /* encode ACK/NACK bit */ srslte_phich_ack_encode(ack, q->data); srslte_mod_modulate(&q->mod, q->data, q->z, SRSLTE_PHICH_NBITS); DEBUG("data: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->z, SRSLTE_PHICH_NBITS); /* Spread with w */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB; i++) { q->d[i] = w_ext[nseq][i % SRSLTE_PHICH_EXT_NSF] * q->z[i / SRSLTE_PHICH_EXT_NSF]; } } else { for (i = 0; i < SRSLTE_PHICH_NORM_MSYMB; i++) { q->d[i] = w_normal[nseq][i % SRSLTE_PHICH_NORM_NSF] * q->z[i / SRSLTE_PHICH_NORM_NSF]; } } DEBUG("d: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d, SRSLTE_PHICH_EXT_MSYMB); srslte_scrambling_c(&q->seq[subframe], q->d); /* align to REG */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d0[4 * i + 0] = 0; q->d0[4 * i + 1] = 0; q->d0[4 * i + 2] = q->d[2 * i]; q->d0[4 * i + 3] = q->d[2 * i + 1]; } } else { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d0[4 * i + 0] = q->d[2 * i]; q->d0[4 * i + 1] = q->d[2 * i + 1]; q->d0[4 * i + 2] = 0; q->d0[4 * i + 3] = 0; } } } else { memcpy(q->d0, q->d, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } DEBUG("d0: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d0, SRSLTE_PHICH_MAX_NSYMB); /* layer mapping & precoding */ if (q->cell.nof_ports > 1) { srslte_layermap_diversity(q->d0, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB); srslte_precoding_diversity(&q->precoding, x, symbols_precoding, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); /**FIXME: According to 6.9.2, Precoding for 4 tx ports is different! */ } else { memcpy(q->symbols[0], q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } /* mapping to resource elements */ for (i = 0; i < q->cell.nof_ports; i++) { if (srslte_regs_phich_add(q->regs, q->symbols[i], ngroup, slot_symbols[i]) < 0) { fprintf(stderr, "Error putting PCHICH resource elements\n"); return SRSLTE_ERROR; } } return SRSLTE_SUCCESS; }
/* Decodes the phich channel and saves the CFI in the cfi pointer. * * Returns 1 if successfully decoded the CFI, 0 if not and -1 on error */ int srslte_phich_decode(srslte_phich_t *q, cf_t *slot_symbols, cf_t *ce[SRSLTE_MAX_PORTS], float noise_estimate, uint32_t ngroup, uint32_t nseq, uint32_t subframe, uint8_t *ack, float *distance) { /* Set pointers for layermapping & precoding */ int i, j; cf_t *x[SRSLTE_MAX_LAYERS]; cf_t *ce_precoding[SRSLTE_MAX_PORTS]; if (q == NULL || slot_symbols == NULL) { return SRSLTE_ERROR_INVALID_INPUTS; } if (subframe >= SRSLTE_NSUBFRAMES_X_FRAME) { fprintf(stderr, "Invalid nslot %d\n", subframe); return SRSLTE_ERROR_INVALID_INPUTS; } if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (nseq >= SRSLTE_PHICH_EXT_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } else { if (nseq >= SRSLTE_PHICH_NORM_NSEQUENCES) { fprintf(stderr, "Invalid nseq %d\n", nseq); return SRSLTE_ERROR_INVALID_INPUTS; } } if (ngroup >= srslte_regs_phich_ngroups(q->regs)) { fprintf(stderr, "Invalid ngroup %d\n", ngroup); return SRSLTE_ERROR_INVALID_INPUTS; } DEBUG("Decoding PHICH Ngroup: %d, Nseq: %d\n", ngroup, nseq); /* number of layers equals number of ports */ for (i = 0; i < SRSLTE_MAX_PORTS; i++) { x[i] = q->x[i]; } for (i = 0; i < SRSLTE_MAX_PORTS; i++) { ce_precoding[i] = q->ce[i]; } /* extract symbols */ if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, slot_symbols, q->symbols[0], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return SRSLTE_ERROR; } /* extract channel estimates */ for (i = 0; i < q->cell.nof_ports; i++) { if (SRSLTE_PHICH_MAX_NSYMB != srslte_regs_phich_get(q->regs, ce[i], q->ce[i], ngroup)) { fprintf(stderr, "There was an error getting the phich symbols\n"); return SRSLTE_ERROR; } } /* in control channels, only diversity is supported */ if (q->cell.nof_ports == 1) { /* no need for layer demapping */ srslte_predecoding_single(q->symbols[0], q->ce[0], q->d0, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); } else { srslte_predecoding_diversity(&q->precoding, q->symbols[0], ce_precoding, x, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB, noise_estimate); srslte_layerdemap_diversity(x, q->d0, q->cell.nof_ports, SRSLTE_PHICH_MAX_NSYMB / q->cell.nof_ports); } DEBUG("Recv!!: \n", 0); DEBUG("d0: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d0, SRSLTE_PHICH_MAX_NSYMB); if (SRSLTE_CP_ISEXT(q->cell.cp)) { if (ngroup % 2) { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d[2 * i + 0] = q->d0[4 * i + 2]; q->d[2 * i + 1] = q->d0[4 * i + 3]; } } else { for (i = 0; i < SRSLTE_PHICH_EXT_MSYMB / 2; i++) { q->d[2 * i + 0] = q->d0[4 * i]; q->d[2 * i + 1] = q->d0[4 * i + 1]; } } } else { memcpy(q->d, q->d0, SRSLTE_PHICH_MAX_NSYMB * sizeof(cf_t)); } DEBUG("d: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->d, SRSLTE_PHICH_EXT_MSYMB); srslte_scrambling_c(&q->seq[subframe], q->d); /* De-spreading */ if (SRSLTE_CP_ISEXT(q->cell.cp)) { for (i = 0; i < SRSLTE_PHICH_NBITS; i++) { q->z[i] = 0; for (j = 0; j < SRSLTE_PHICH_EXT_NSF; j++) { q->z[i] += conjf(w_ext[nseq][j]) * q->d[i * SRSLTE_PHICH_EXT_NSF + j] / SRSLTE_PHICH_EXT_NSF; } } } else { for (i = 0; i < SRSLTE_PHICH_NBITS; i++) { q->z[i] = 0; for (j = 0; j < SRSLTE_PHICH_NORM_NSF; j++) { q->z[i] += conjf(w_normal[nseq][j]) * q->d[i * SRSLTE_PHICH_NORM_NSF + j] / SRSLTE_PHICH_NORM_NSF; } } } DEBUG("z: ", 0); if (SRSLTE_VERBOSE_ISDEBUG()) srslte_vec_fprint_c(stdout, q->z, SRSLTE_PHICH_NBITS); srslte_demod_soft_demodulate(SRSLTE_MOD_BPSK, q->z, q->data_rx, SRSLTE_PHICH_NBITS); if (ack) { *ack = srslte_phich_ack_decode(q->data_rx, distance); } return SRSLTE_SUCCESS; }