Skip to content
Snippets Groups Projects
lte_mcs.c 11 KiB
Newer Older
/*******************************************************************************
ghaddab's avatar
ghaddab committed
    OpenAirInterface 
    Copyright(c) 1999 - 2014 Eurecom
ghaddab's avatar
ghaddab committed
    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
ghaddab's avatar
ghaddab committed
    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
ghaddab's avatar
ghaddab committed
    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is 
   included in this distribution in the file called "COPYING". If not, 
   see <http://www.gnu.org/licenses/>.
ghaddab's avatar
ghaddab committed
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@eurecom.fr
  
ghaddab's avatar
ghaddab committed
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
ghaddab's avatar
ghaddab committed
 *******************************************************************************/

/*! \file PHY/LTE_TRANSPORT/lte_mcs.c
* \brief Some support routines for MCS computations
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/

#include "PHY/defs.h"
#include "PHY/extern.h"
#include "PHY/LTE_TRANSPORT/proto.h"

unsigned char get_Qm(unsigned char I_MCS) {

  if (I_MCS < 10)
    return(2);
  else if (I_MCS < 17)
    return(4);
  else
    return(6);
    
}

unsigned char get_Qm_ul(unsigned char I_MCS) {

  if (I_MCS < 11)
    return(2);
  else if (I_MCS < 21)
    return(4);
  else
    return(6);
    
}

unsigned char get_I_TBS(unsigned char I_MCS) {

  if (I_MCS < 10)
    return(I_MCS);
  else if (I_MCS == 10)
    return(9);
  else if (I_MCS < 17)
    return(I_MCS-1);
  else if (I_MCS == 17)
    return(15);
  else return(I_MCS-2);

}

unsigned char get_I_TBS_UL(unsigned char I_MCS) {

  if (I_MCS <= 10)
    return(I_MCS);
  else if (I_MCS == 10)
    return(10);
  else if (I_MCS < 21)
    return(I_MCS-1);
  else return(I_MCS-2);

}

unsigned char I_TBS2I_MCS(unsigned char I_TBS) {
  unsigned char I_MCS = -1;
  ///note: change from <= to < to go from choosing higher modulation rather than high code-rate
	  if (I_TBS <= 9)
	    I_MCS = I_TBS;
	  else if (I_TBS <= 15)
	    I_MCS = I_TBS + 1;
	  else if (I_TBS > 15 && I_TBS <= 26)
	    I_MCS = I_TBS + 2;
#ifdef OUTPUT_DEBUG
  printf("I_MCS: %d, from mod_order %d and I_TBS %d\n",I_MCS,modOrder(I_MCS,I_TBS),I_TBS);
  if (I_MCS == 0xFF) getchar();
#endif
  return I_MCS;
}

uint32_t get_TBS_DL(uint8_t mcs, uint16_t nb_rb) {
  uint32_t TBS;

  if ((nb_rb > 0) && (mcs < 29)) {
#ifdef TBS_FIX
    TBS = 3*TBStable[get_I_TBS(mcs)][nb_rb-1]/4;
    TBS = TBS>>3;
#else
    TBS = TBStable[get_I_TBS(mcs)][nb_rb-1];
    TBS = TBS>>3;
#endif
    return(TBS);
  }
  else {
    return(uint32_t)0;
uint32_t get_TBS_UL(uint8_t mcs, uint16_t nb_rb) {
  uint32_t TBS = 0;

  if ((nb_rb > 0) && (mcs < 29)) {
#ifdef TBS_FIX
    TBS = 3*TBStable[get_I_TBS_UL(mcs)][nb_rb-1]/4;
    TBS = TBS>>3;
#else
    TBS = TBStable[get_I_TBS_UL(mcs)][nb_rb-1];
    TBS = TBS>>3;
#endif
    return(TBS);
  }
  else {
    return(uint32_t)0;
int adjust_G2(LTE_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_order,uint8_t subframe,uint8_t symbol) {

  int rb,re_pbch_sss=0;
  int rb_alloc_ind,nsymb;

knopp's avatar
 
knopp committed
  nsymb = (frame_parms->Ncp==NORMAL) ? 14 : 12;

  //      printf("adjust_G2 : symbol %d, subframe %d\n",symbol,subframe);
  if ((subframe!=0) && (subframe!=5) && (subframe!=6))  // if not PBCH/SSS or SSS
    return(0);

  //first half of slot and TDD (no adjustments in first slot except for subframe 6 - PSS)
  if ((symbol<(nsymb>>1))&&
      (frame_parms->frame_type == TDD)&&
      (subframe!=6))
    return(0);

  // after PBCH
  if (frame_parms->frame_type==TDD) { //TDD 
    if ((symbol>((nsymb>>1)+3)) && 
	(symbol!=(nsymb-1)))  ///SSS
      return(0);

    if ((subframe==5) && (symbol!=(nsymb-1))) ///SSS
      return(0);
    if ((subframe==6) && (symbol!=2)) /// PSS
      return(0);
  }
  else {  // FDD
    if ((symbol>((nsymb>>1)+3)) || 
	(symbol<((nsymb>>1)-2))) 
      return(0);

    if ((subframe==5) && (symbol!=((nsymb>>1)-1))&& (symbol!=((nsymb>>1)-2)))
      return(0);
    
    if (subframe==6)
      return(0);
  }

  if ((frame_parms->N_RB_DL&1) == 1) { // ODD N_RB_DL

    for (rb=((frame_parms->N_RB_DL>>1)-3);
	 rb<=((frame_parms->N_RB_DL>>1)+3);
	 rb++) {
    
      if (rb < 32)
	rb_alloc_ind = (rb_alloc[0]>>rb) & 1;
      else if (rb < 64)
	rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1;
      else if (rb < 96)
	rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1;
      else if (rb < 100)
	rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1;
      else
	rb_alloc_ind = 0;
      
      if (rb_alloc_ind==1) {
	if ((rb==(frame_parms->N_RB_DL>>1)-3) || 
	    (rb==((frame_parms->N_RB_DL>>1)+3))) {
	  re_pbch_sss += 6;
	}
	else
	  re_pbch_sss += 12;
      }
    }
  }
  else {
    for (rb=((frame_parms->N_RB_DL>>1)-3);
	 rb<((frame_parms->N_RB_DL>>1)+3);
	 rb++) {
    
      if (rb < 32)
	rb_alloc_ind = (rb_alloc[0]>>rb) & 1;
      else if (rb < 64)
	rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1;
      else if (rb < 96)
	rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1;
      else if (rb < 100)
	rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1;
      else
	rb_alloc_ind = 0;
      
      if (rb_alloc_ind==1) {
	  re_pbch_sss += 12;
      }
    }
  }
  //    printf("re_pbch_sss %d\n",re_pbch_sss);
  return(re_pbch_sss);
}

int adjust_G(LTE_DL_FRAME_PARMS *frame_parms,uint32_t *rb_alloc,uint8_t mod_order,uint8_t subframe) {
  uint8_t rb_alloc_ind;

  if ((subframe!=0) && (subframe!=5) && (subframe!=6))  // if not PBCH/SSS/PSS or SSS/PSS
    return(0);


  if ((frame_parms->N_RB_DL&1) == 1) { // ODD N_RB_DL

    for (rb=((frame_parms->N_RB_DL>>1)-3);
	 rb<=((frame_parms->N_RB_DL>>1)+3);
	 rb++) {
    
      if (rb < 32)
	rb_alloc_ind = (rb_alloc[0]>>rb) & 1;
      else if (rb < 64)
	rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1;
      else if (rb < 96)
	rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1;
      else if (rb < 100)
	rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1;
      else
	rb_alloc_ind = 0;
      
      if (rb_alloc_ind==1) {
	if ((rb==(frame_parms->N_RB_DL>>1)-3) || 
	    (rb==((frame_parms->N_RB_DL>>1)+3))) {  //rb taken by PBCH/SSS
	  re_pbch_sss += 6;
	}
	else
	  re_pbch_sss += 12;
      }
    }
  }
  else {
    for (rb=((frame_parms->N_RB_DL>>1)-3);
	 rb<((frame_parms->N_RB_DL>>1)+3);
	 rb++) {
    
      if (rb < 32)
	rb_alloc_ind = (rb_alloc[0]>>rb) & 1;
      else if (rb < 64)
	rb_alloc_ind = (rb_alloc[1]>>(rb-32)) & 1;
      else if (rb < 96)
	rb_alloc_ind = (rb_alloc[2]>>(rb-64)) & 1;
      else if (rb < 100)
	rb_alloc_ind = (rb_alloc[3]>>(rb-96)) & 1;
      else
	rb_alloc_ind = 0;
      
      if (rb_alloc_ind==1) {
	  re_pbch_sss += 12;
      }
    }
  }
  //    printf("re_pbch_sss %d\n",re_pbch_sss);
  if (subframe==0) {  //PBCH+SSS+PSS
knopp's avatar
 
knopp committed
    if (frame_parms->frame_type == TDD) { // TDD
      if (frame_parms->mode1_flag==0)
	//2ant so PBCH 3+2/3 symbols, SSS 1 symbol * REs => (14/3)*re_pbch_sss for normal CP,  
	// 2+4/3 symbols, SSS 1 symbol => (13/3)*re_pbch_sss for ext. CP
	return((-frame_parms->Ncp+14)*re_pbch_sss * mod_order/3);
      else
	//SISO so PBCH 3+(5/6) symbols, SSS 1 symbol * REs => (29/6)*re_pbch_sss for normal CP,  
	// 2+10/6 symbols, SSS 1 symbol => (28/6)*re_pbch_sss for ext. CP
	return((-frame_parms->Ncp+29)*re_pbch_sss * mod_order/6);
    }
    else {  // FDD
      if (frame_parms->mode1_flag==0)
	//2ant so PBCH 3+2/3 symbols, PSS+SSS 2 symbols * REs => (17/3)*re_pbch_sss for normal CP,  
	// 2+4/3 symbols, PSS+SSS 2 symbols => (16/3)*re_pbch_sss for ext. CP
	return((-frame_parms->Ncp+17)*re_pbch_sss * mod_order/3);
      else
	//SISO so PBCH 3+(5/6) symbols, PSS+SSS 2symbols REs => (35/6)*re_pbch_sss for normal CP,  
	// 2+10/6 symbols, SSS+PSS 2 symbols => (34/6)*re_pbch_sss for ext. CP
	return((-frame_parms->Ncp+35)*re_pbch_sss * mod_order/6);
 
    }
  }
  else if (subframe == 5)  // SSS+PSS for FDD, SSS for TDD
knopp's avatar
 
knopp committed
    return(((frame_parms->frame_type==FDD)?2:1)*re_pbch_sss * 1 * mod_order);
  else if ((subframe == 6)&&(frame_parms->frame_type == TDD)) // PSS for TDD
knopp's avatar
 
knopp committed
int get_G(LTE_DL_FRAME_PARMS *frame_parms,uint16_t nb_rb,uint32_t *rb_alloc,uint8_t mod_order,uint8_t Nl,uint8_t num_pdcch_symbols,int frame,uint8_t subframe) {

  

  int G_adj;

  if (is_pmch_subframe(frame,subframe,frame_parms) == 0) {
    G_adj= adjust_G(frame_parms,rb_alloc,mod_order,subframe);
    
    //    printf("get_G subframe %d mod_order %d, nb_rb %d: rb_alloc %x,%x,%x,%x, G_adj %d\n",subframe,mod_order,nb_rb,rb_alloc[3],rb_alloc[2],rb_alloc[1],rb_alloc[0], G_adj);
knopp's avatar
 
knopp committed
    if (frame_parms->Ncp==NORMAL) { // normal prefix
      // PDDDPDD PDDDPDD - 13 PDSCH symbols, 10 full, 3 w/ pilots = 10*12 + 3*8
      // PCDDPDD PDDDPDD - 12 PDSCH symbols, 9 full, 3 w/ pilots = 9*12 + 3*8
      // PCCDPDD PDDDPDD - 11 PDSCH symbols, 8 full, 3 w/pilots = 8*12 + 3*8
      if (frame_parms->mode1_flag==0) // SISO 
knopp's avatar
 
knopp committed
	return((((int)nb_rb * mod_order * ((11-num_pdcch_symbols)*12 + 3*8)) - G_adj)*Nl);
      else
	return(((int)nb_rb * mod_order * ((11-num_pdcch_symbols)*12 + 3*10)) - G_adj);
    }
    else {
      // PDDPDD PDDPDD - 11 PDSCH symbols, 8 full, 3 w/ pilots = 8*12 + 3*8
      // PCDPDD PDDPDD - 10 PDSCH symbols, 7 full, 3 w/ pilots = 7*12 + 3*8
      // PCCPDD PDDPDD - 9 PDSCH symbols, 6 full, 3 w/pilots = 6*12 + 3*8
      if (frame_parms->mode1_flag==0)
knopp's avatar
 
knopp committed
	return((((int)nb_rb * mod_order * ((9-num_pdcch_symbols)*12 + 3*8)) - G_adj)*Nl);
      else
	return(((int)nb_rb * mod_order * ((9-num_pdcch_symbols)*12 + 3*10)) - G_adj);
    }
  }
  else { // This is an MBSFN subframe
    return((int)frame_parms->N_RB_DL * mod_order * 102);
  }
}

// following function requires dlsch_tbs_full.h
#include "PHY/LTE_TRANSPORT/dlsch_tbs_full.h"

unsigned char SE2I_TBS(float SE,
		       unsigned char N_PRB,
		       unsigned char symbPerRB) {
  unsigned char I_TBS= -1;
  int throughPutGoal = 0;
  short diffOld = abs(TBStable[0][N_PRB-1] - throughPutGoal);
  short diffNew = diffOld;
  int i = 0;
  throughPutGoal = (int)(((SE*1024)*N_PRB*symbPerRB*12)/1024);
#ifdef OUTPUT_DEBUG
  printf("Throughput goal = %d, from SE = %f\n",throughPutGoal,SE);
#endif
  I_TBS = 0;
  for (i = 0; i<TBStable_rowCnt; i++) {
    diffNew = abs(TBStable[i][N_PRB-1] - throughPutGoal);
    if (diffNew <= diffOld) {
      diffOld = diffNew;
      I_TBS = i;
    } else {
#ifdef OUTPUT_DEBUG
      printf("diff neglected: %d\n",diffNew);
#endif
      break; // no need to continue, strictly increasing function...
    }
#ifdef OUTPUT_DEBUG
    printf("abs(%d - %d) = %d, --> I_TBS = %d\n",TBStable[i][N_PRB-1],throughPutGoal,diffNew,I_TBS);
#endif
  }
  return I_TBS;
}

//added for ALU icic purpose

uint8_t Get_SB_size(uint8_t n_rb_dl){

	if(n_rb_dl<27)
		return 4;
	else
		if(n_rb_dl<64)
			return 6;
		else
			return 8;
	}


//end ALU's algo