Exemplo n.º 1
0
Arquivo: uci.c Projeto: srsLTE/srsLTE
static uint32_t Q_prime_ri_ack(srslte_pusch_cfg_t *cfg, 
                               uint32_t O, uint32_t O_cqi, float beta) {

  if (beta < 0) {
    ERROR("Error beta is reserved\n");
    return -1; 
  }

  uint32_t K = cfg->K_segm;

  // If not carrying UL-SCH, get Q_prime according to 5.2.4.1
  if (K == 0) {
    if (O_cqi <= 11) {
      K = O_cqi;
    } else {
      K = O_cqi + 8;
    }
  }

  uint32_t x = (uint32_t)ceilf((float)O * cfg->grant.L_prb * SRSLTE_NRE * cfg->grant.nof_symb * beta / K);

  uint32_t Q_prime = SRSLTE_MIN(x, 4 * cfg->grant.L_prb * SRSLTE_NRE);

  return Q_prime;
}
Exemplo n.º 2
0
static uint32_t Q_prime_ri_ack(srslte_pusch_cfg_t *cfg, 
                               uint32_t O, uint32_t O_cqi, float beta) {
  
  if (beta < 0) {
    fprintf(stderr, "Error beta is reserved\n");
    return -1; 
  }

  uint32_t K = cfg->cb_segm.C1*cfg->cb_segm.K1 + cfg->cb_segm.C2*cfg->cb_segm.K2;
  
  // If not carrying UL-SCH, get Q_prime according to 5.2.4.1
  if (K == 0) {
    if (O_cqi <= 11) {
      K = O_cqi; 
    } else {
      K = O_cqi+8;     
    }
  }
    
  uint32_t x = (uint32_t) ceilf((float) O*cfg->grant.M_sc_init*cfg->nbits.nof_symb*beta/K);

  uint32_t Q_prime = SRSLTE_MIN(x, 4*cfg->grant.M_sc);

  return Q_prime; 
}
Exemplo n.º 3
0
int srslte_ue_dl_find_ul_dci(srslte_ue_dl_t*     q,
                             srslte_dl_sf_cfg_t* sf,
                             srslte_ue_dl_cfg_t* cfg,
                             uint16_t            rnti,
                             srslte_dci_ul_t     dci_ul[SRSLTE_MAX_DCI_MSG])
{
  srslte_dci_msg_t dci_msg[SRSLTE_MAX_DCI_MSG];
  uint32_t         nof_msg = 0;

  if (rnti) {
    /* Do not search if an UL DCI is already pending */
    if (q->pending_ul_dci_count) {
      nof_msg                 = SRSLTE_MIN(SRSLTE_MAX_DCI_MSG, q->pending_ul_dci_count);
      q->pending_ul_dci_count = 0;
      memcpy(dci_msg, q->pending_ul_dci_msg, sizeof(srslte_dci_msg_t) * nof_msg);
    } else {

      uint32_t sf_idx = sf->tti % 10;
      uint32_t cfi    = sf->cfi;

      set_mi_value(q, sf, cfg);

      // Configure and run DCI blind search
      dci_blind_search_t search_space;
      search_space.nof_locations     = 0;
      dci_blind_search_t* current_ss = &search_space;
      if (q->pregen_rnti == rnti) {
        current_ss = &q->current_ss_ue[MI_IDX(sf_idx)][cfi - 1][sf_idx];
      } else {
        // If locations are not pre-generated, generate them now
        current_ss->nof_locations = srslte_pdcch_ue_locations(&q->pdcch, sf, current_ss->loc, MAX_CANDIDATES_UE, rnti);
      }

      current_ss->format = SRSLTE_DCI_FORMAT0;
      INFO("Searching UL C-RNTI in %d ue locations\n", search_space.nof_locations);
      nof_msg = dci_blind_search(q, sf, rnti, current_ss, &cfg->dci_cfg, dci_msg);
    }

    // Unpack DCI messages
    for (uint32_t i = 0; i < nof_msg; i++) {
      if (srslte_dci_msg_unpack_pusch(&q->cell, sf, &cfg->dci_cfg, &dci_msg[i], &dci_ul[i])) {
        ERROR("Unpacking UL DCI\n");
        return SRSLTE_ERROR;
      }
    }

    return nof_msg;

  } else {
    return 0;
  }
}
Exemplo n.º 4
0
Arquivo: uci.c Projeto: srsLTE/srsLTE
static uint32_t Q_prime_cqi(srslte_pusch_cfg_t* cfg, uint32_t O, float beta, uint32_t Q_prime_ri)
{

  uint32_t K = cfg->K_segm;

  uint32_t Q_prime = 0;
  uint32_t L       = (O < 11) ? 0 : 8;
  uint32_t x = 999999;

  if (K > 0) {
    x = (uint32_t)ceilf((float)(O + L) * cfg->grant.L_prb * SRSLTE_NRE * cfg->grant.nof_symb * beta / K);
  }

  Q_prime = SRSLTE_MIN(x, cfg->grant.L_prb * SRSLTE_NRE * cfg->grant.nof_symb - Q_prime_ri);

  return Q_prime; 
}
Exemplo n.º 5
0
static int select_ri_pmi(srslte_ue_dl_t* q, uint32_t* ri, uint32_t* pmi, float* sinr_db)
{
  float    best_sinr_db = -INFINITY;
  uint32_t best_pmi = 0, best_ri = 0;
  uint32_t max_ri = SRSLTE_MIN(q->nof_rx_antennas, q->cell.nof_ports);

  if (q->cell.nof_ports < 2) {
    /* Do nothing */
    return SRSLTE_SUCCESS;
  } else {
    /* Select the best Rank indicator (RI) and Precoding Matrix Indicator (PMI) */
    for (uint32_t this_ri = 0; this_ri < max_ri; this_ri++) {
      uint32_t this_pmi     = 0;
      float    this_sinr_db = 0.0f;
      if (select_pmi(q, this_ri, &this_pmi, &this_sinr_db)) {
        DEBUG("SINR calculation error");
        return SRSLTE_ERROR;
      }

      /* Find best SINR, force maximum number of layers if SNR is higher than 30 dB */
      if (this_sinr_db > best_sinr_db + 0.1 || this_sinr_db > 20.0) {
        best_sinr_db = this_sinr_db;
        best_pmi     = this_pmi;
        best_ri      = this_ri;
      }
    }
  }

  /* Set RI */
  if (ri != NULL) {
    *ri = best_ri;
  }

  /* Set PMI */
  if (pmi != NULL) {
    *pmi = best_pmi;
  }

  /* Set SINR */
  if (sinr_db != NULL) {
    *sinr_db = best_sinr_db;
  }

  return SRSLTE_SUCCESS;
}
Exemplo n.º 6
0
static uint32_t Q_prime_cqi(srslte_pusch_cfg_t *cfg, 
                            uint32_t O, float beta, uint32_t Q_prime_ri) 
{
  
  uint32_t K = cfg->cb_segm.C1*cfg->cb_segm.K1 + cfg->cb_segm.C2*cfg->cb_segm.K2;
    
  uint32_t Q_prime = 0;
  uint32_t L = (O<11)?0:8;
  uint32_t x = 999999;
  
  if (K > 0) {
    x = (uint32_t) ceilf((float) (O+L)*cfg->grant.M_sc_init*cfg->nbits.nof_symb*beta/K);      
  }
  
  Q_prime = SRSLTE_MIN(x, cfg->grant.M_sc * cfg->nbits.nof_symb - Q_prime_ri);    

  return Q_prime; 
}
Exemplo n.º 7
0
Arquivo: uci.c Projeto: srsLTE/srsLTE
// For decoding the block-encoded CQI we use ML decoding
int decode_cqi_short(srslte_uci_cqi_pusch_t *q, int16_t *q_bits, uint32_t Q, uint8_t *data, uint32_t nof_bits)
{
  if (nof_bits          <= 11    &&
      nof_bits          > 0      && 
      q                 != NULL  &&
      data              != NULL  &&
      q_bits            != NULL) 
  {
    // Accumulate all copies of the 32-length sequence 
    if (Q>32) {
      int i=1; 
      for (;i<Q/32;i++) {
        srslte_vec_sum_sss(&q_bits[i*32], q_bits, q_bits, 32);
      }
      srslte_vec_sum_sss(&q_bits[i*32], q_bits, q_bits, Q%32);
    }
    
    uint32_t max_w = 0;
    int32_t max_corr = INT32_MIN;   
    for (uint32_t w=0;w<(1<<nof_bits);w++) {
          
      // Calculate correlation with pregenerated word and select maximum
      int32_t corr = srslte_vec_dot_prod_sss(&q->cqi_table_s[nof_bits-1][w*32], q_bits, SRSLTE_MIN(32, Q));
      if (corr > max_corr) {
        max_corr = corr; 
        max_w = w; 
      }
    }
    // Convert word to bits again
    uint8_t *ptr = data; 
    srslte_bit_unpack(max_w, &ptr, nof_bits);
    
    INFO("Decoded CQI: w=%d, corr=%d\n", max_w, max_corr);
    return SRSLTE_SUCCESS;
  } else {
    return SRSLTE_ERROR_INVALID_INPUTS;
  }  
}
Exemplo n.º 8
0
/* UE downlink procedure for reporting ACK/NACK, Section 7.3 36.213
 */
void srslte_ue_dl_gen_ack(srslte_ue_dl_t*     q,
                          srslte_dl_sf_cfg_t* sf,
                          srslte_pdsch_ack_t* ack_info,
                          srslte_uci_data_t*  uci_data)
{
  uint32_t V_dai_dl = 0;

  bool is_tdd_mode16 = sf->tdd_config.sf_config >= 1 && sf->tdd_config.sf_config <= 6;

  uint32_t nof_tb = 1;
  if (ack_info->transmission_mode > SRSLTE_TM2) {
    nof_tb = SRSLTE_MAX_CODEWORDS;
  }

  // Implementation 3GPP 36.213 V10.13.0. Section 7.3. 2nd Clause.
  if (q->cell.frame_type == SRSLTE_FDD) {
    if (ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS &&
        uci_data->value.scheduling_request && !ack_info->is_pusch_available) {
      for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
        uint32_t dtx_count      = 0;
        bool     bundle_spatial = true;

        for (uint32_t tb = 0; tb < nof_tb; tb++) {
          if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) {
            if (ack_info->cc[cc_idx].m[0].value[tb] != 1) {
              bundle_spatial = false;
            }
            if (cc_idx != 0) {
              uci_data->cfg.ack.has_scell_ack = true;
            }
          } else {
            dtx_count++;
          }
        }
        uci_data->value.ack.ack_value[cc_idx] = (uint8_t)((bundle_spatial && dtx_count != nof_tb) ? 1 : 0);
      }

      uci_data->cfg.ack.nof_acks  = ack_info->nof_cc;
      uci_data->cfg.ack.tdd_ack_M = 1;
      return;

    } else if ((ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_CS &&
                ack_info->is_pusch_available) ||
               ack_info->ack_nack_feedback_mode == SRSLTE_PUCCH_ACK_NACK_FEEDBACK_MODE_PUCCH3) {
      uint32_t tb_count = 0;
      uint32_t n        = 0;
      for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
        for (uint32_t tb = 0; tb < nof_tb; tb++, n++) {
          uci_data->value.ack.ack_value[n] = ack_info->cc[cc_idx].m[0].value[tb];
          if (ack_info->cc[cc_idx].m[0].present && ack_info->cc[cc_idx].m[0].value[tb] != 2) {
            tb_count++;
          }
        }
      }
      uci_data->cfg.ack.nof_acks = (tb_count != 0) ? n : 0;
      return;
    }
  }

  // Calculate U_dai and count number of ACK for this subframe by spatial bundling across codewords
  uint32_t nof_pos_acks   = 0;
  uint32_t nof_total_acks = 0;
  uint32_t U_dai          = 0;
  for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {
    for (uint32_t i = 0; i < ack_info->cc[cc_idx].M; i++) {
      bool bundle_spatial = false;
      bool first_bundle   = true;
      for (uint32_t j = 0; j < nof_tb; j++) {
        if (ack_info->cc[cc_idx].m[i].present) {
          if (first_bundle) {
            bundle_spatial = ack_info->cc[cc_idx].m[i].value[j] == 1;
            U_dai++;
            first_bundle = false;
          } else {
            bundle_spatial &= ack_info->cc[cc_idx].m[i].value[j] == 1;
          }
          if (bundle_spatial) {
            nof_pos_acks++;
          }
          if (ack_info->cc[cc_idx].m[i].value[j] != 2) {
            nof_total_acks++;
          }
        }
      }
    }
  }

  for (uint32_t cc_idx = 0; cc_idx < ack_info->nof_cc; cc_idx++) {

    // Arrange bits for FDD or TDD Bundling or Multiplexing
    srslte_pdsch_ack_cc_t* ack_value = &ack_info->cc[cc_idx];

    uint32_t min_k = 10;

    if (ack_info->cc[cc_idx].M > 0) {

      uci_data->cfg.ack.tdd_ack_M = ack_value->M;

      // ACK/NACK bundling or multiplexing and M=1
      if (ack_info->tdd_ack_bundle || ack_value->M == 1) {
        for (uint32_t tb = 0; tb < nof_tb; tb++) {
          bool first_in_bundle = true;
          for (uint32_t k = 0; k < ack_value->M; k++) {
            if (ack_value->m[k].present && ack_value->m[k].value[tb] != 2) {
              uci_data->cfg.ack.has_scell_ack |= (cc_idx != 0); // If a grant is detected in an scell

              // Bundle on time domain
              if (first_in_bundle) {
                uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] = ack_value->m[k].value[tb];
                first_in_bundle                                     = false;
              } else {
                uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] = (uint8_t)(
                    ((uci_data->value.ack.ack_value[nof_tb * cc_idx + tb] == 1) & (ack_value->m[k].value[tb])) ? 1 : 0);
              }
              // V_dai_dl is for the one with lowest k value
              if (ack_value->m[k].k < min_k || q->cell.frame_type == SRSLTE_FDD) {
                min_k    = ack_value->m[k].k;
                V_dai_dl = ack_value->m[k].resource.v_dai_dl + 1; // Table 7.3-X
                if (cc_idx == 0) {
                  uci_data->cfg.ack.ncce[0]   = ack_info->cc[cc_idx].m[k].resource.n_cce;
                  uci_data->cfg.ack.tdd_ack_m = k;
                }
              }
            }
          }
        }
        // ACK/NACK multiplexing and M > 1
      } else {
        for (uint32_t k = 0; k < ack_value->M; k++) {
          // Bundle spatial domain
          bool spatial_ack = true;
          for (uint32_t i = 0; i < nof_tb; i++) {
            if (ack_value->m[k].value[i] != 2) {
              spatial_ack &= (ack_value->m[k].value[i] == 1);
            }
          }
          // In multiplexing for pusch, sort them accordingly
          if (ack_value->m[k].present) {
            uint32_t p = k;
            if (q->cell.frame_type == SRSLTE_TDD && ack_info->is_pusch_available && ack_info->is_grant_available) {
              p = ack_value->m[k].resource.v_dai_dl;
            }
            uci_data->value.ack.ack_value[ack_value->M * cc_idx + p] = (uint8_t)(spatial_ack ? 1 : 0);
            uci_data->cfg.ack.ncce[ack_value->M * cc_idx + p]        = ack_info->cc[cc_idx].m[k].resource.n_cce;
          }
        }
      }
    }
  }

  bool missing_ack = false;

  // For TDD PUSCH
  if (q->cell.frame_type == SRSLTE_TDD && is_tdd_mode16) {

    ack_info->V_dai_ul++; // Table 7.3-x

    uci_data->cfg.ack.tdd_is_bundling = ack_info->tdd_ack_bundle;

    // Bundling or multiplexing and M=1
    if (ack_info->tdd_ack_bundle || ack_info->cc[0].M == 1) {
      // 1 or 2 ACK/NACK bits
      uci_data->cfg.ack.nof_acks = nof_tb;

      // Determine if there is any missing ACK/NACK in the set and N_bundle value

      // Case not transmitting on PUSCH
      if (!ack_info->is_pusch_available) {
        if ((V_dai_dl != (U_dai - 1) % 4 + 1 && U_dai > 0) || U_dai == 0) {
          // In ul procedure 10.2, skip ACK/NACK in bundling PUCCH
          uci_data->cfg.ack.nof_acks = 0;
          if (U_dai > 0) {
            missing_ack = true;
          }
        }
        // Transmitting on PUSCH and based on detected PDCCH
      } else if (ack_info->is_grant_available) {
        if (ack_info->V_dai_ul != (U_dai - 1) % 4 + 1) {
          bzero(uci_data->value.ack.ack_value, nof_tb);
          uci_data->cfg.ack.N_bundle = ack_info->V_dai_ul + 2;
        } else {
          uci_data->cfg.ack.N_bundle = ack_info->V_dai_ul;
        }
        // do not transmit case
        if (ack_info->V_dai_ul == 4 && U_dai == 0) {
          uci_data->cfg.ack.nof_acks = 0;
        }
        // Transmitting on PUSCH not based on grant
      } else {
        if (V_dai_dl != (U_dai - 1) % 4 + 1 && U_dai > 0) {
          bzero(uci_data->value.ack.ack_value, nof_tb);
        }
        uci_data->cfg.ack.N_bundle = U_dai;
        // do not transmit case
        if (U_dai == 0) {
          uci_data->cfg.ack.nof_acks = 0;
        }
      }

      // In PUSCH and MIMO, nack 2nd codeword if not received, in PUCCH do not transmit
      if (nof_tb == 2 && uci_data->value.ack.ack_value[1] == 2 && uci_data->cfg.ack.nof_acks == 2) {
        if (!ack_info->is_pusch_available) {
          uci_data->cfg.ack.nof_acks = 1;
        } else {
          uci_data->value.ack.ack_value[1] = 0;
        }
      }

      // Multiplexing and M>1
    } else {
      if (ack_info->is_pusch_available) {
        if (ack_info->is_grant_available) {
          // Do not transmit if...
          if (!(ack_info->V_dai_ul == 4 && U_dai == 0)) {
            uci_data->cfg.ack.nof_acks = ack_info->V_dai_ul;
          }
        } else {
          uci_data->cfg.ack.nof_acks = ack_info->cc[0].M;
        }

        // Set DTX bits to NACKs
        uint32_t count_acks = 0;
        for (uint32_t i = 0; i < uci_data->cfg.ack.nof_acks; i++) {
          if (uci_data->value.ack.ack_value[i] == 2) {
            uci_data->value.ack.ack_value[i] = 0;
          } else {
            count_acks++;
          }
        }
        if (!count_acks) {
          uci_data->cfg.ack.nof_acks = 0;
        }
      } else {
        uci_data->cfg.ack.nof_acks = ack_info->cc[0].M;
      }
    }
  } else {
    if (q->cell.frame_type == SRSLTE_TDD) { // And subframe config 0
      uci_data->cfg.ack.N_bundle = 1;
    }
    uci_data->cfg.ack.nof_acks = nof_total_acks;
  }

  // If no pending ACK/NACK
  if (uci_data->cfg.ack.nof_acks == 0) {
    return;
  }

  // Multiple ACK/NACK responses with SR and CQI
  if (q->cell.frame_type == SRSLTE_TDD && uci_data->cfg.ack.nof_acks && !ack_info->is_pusch_available &&
      (uci_data->value.scheduling_request ||
       ((uci_data->cfg.cqi.data_enable || uci_data->cfg.cqi.ri_len) && ack_info->simul_cqi_ack))) {
    if (missing_ack) {
      uci_data->value.ack.ack_value[0] = 0;
      uci_data->value.ack.ack_value[1] = 0;
    } else {
      nof_pos_acks                     = SRSLTE_MIN(9, nof_pos_acks);
      uci_data->value.ack.ack_value[0] = multiple_acknack[nof_pos_acks][0];
      uci_data->value.ack.ack_value[1] = multiple_acknack[nof_pos_acks][1];
    }
    uci_data->cfg.ack.nof_acks = 2;
  }
}