Exemple #1
0
/**
 * 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;
}
Exemple #2
0
/* 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;
}
Exemple #3
0
/**
 * 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;
}
Exemple #4
0
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; 
  }
}
Exemple #5
0
/** 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;
}
Exemple #6
0
/** 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;
}
Exemple #7
0
/* 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;
}