nr_prach.c 30.9 KB
Newer Older
Agustin's avatar
Agustin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

/*! \file PHY/LTE_TRANSPORT/prach_common.c
 * \brief Common routines for UE/eNB PRACH physical channel V8.6 2009-03
 * \author R. Knopp
 * \date 2011
 * \version 0.1
 * \company Eurecom
 * \email: knopp@eurecom.fr
 * \note
 * \warning
 */
#include "PHY/sse_intrin.h"
#include "common/utils/LOG/vcd_signal_dumper.h"

#include "PHY/impl_defs_nr.h"
#include "PHY/defs_nr_UE.h"
37
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
Agustin's avatar
Agustin committed
38 39 40

#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"
laurent's avatar
laurent committed
41
#include <openair1/PHY/NR_TRANSPORT/nr_transport_proto_common.h>
Agustin's avatar
Agustin committed
42 43

#include "T.h"
laurent's avatar
laurent committed
44
#include <openair1/PHY/NR_TRANSPORT/nr_transport_proto_common.h>
Agustin's avatar
Agustin committed
45 46 47 48




49 50 51 52 53 54 55 56 57 58 59 60 61 62
extern uint16_t NCS_unrestricted_delta_f_RA_125[16];
extern uint16_t NCS_restricted_TypeA_delta_f_RA_125[15];
extern uint16_t NCS_restricted_TypeB_delta_f_RA_125[13];
extern uint16_t NCS_unrestricted_delta_f_RA_5[16];
extern uint16_t NCS_restricted_TypeA_delta_f_RA_5[16];
extern uint16_t NCS_restricted_TypeB_delta_f_RA_5[14];
extern uint16_t NCS_unrestricted_delta_f_RA_15[16];
extern uint16_t prach_root_sequence_map_0_3[838];
extern uint16_t prach_root_sequence_map_abc[138];
extern int64_t table_6_3_3_2_2_prachConfig_Index [256][9];
extern int64_t table_6_3_3_2_3_prachConfig_Index [256][9];
extern int64_t table_6_3_3_2_4_prachConfig_Index [256][10];
extern uint16_t nr_du[838];
extern int16_t nr_ru[2*839];
Agustin's avatar
Agustin committed
63 64 65 66 67 68 69 70 71 72 73 74 75








int32_t generate_nr_prach( PHY_VARS_NR_UE *ue, uint8_t eNB_id, uint8_t subframe, uint16_t Nf )
{

  //lte_frame_type_t frame_type         = ue->frame_parms.frame_type;
  //uint8_t tdd_config         = ue->frame_parms.tdd_config;
76 77 78 79 80
  NR_DL_FRAME_PARMS *fp=&ue->frame_parms;
  uint16_t rootSequenceIndex = fp->prach_config_common.rootSequenceIndex;
  uint8_t prach_ConfigIndex  = fp->prach_config_common.prach_ConfigInfo.prach_ConfigIndex;
  uint8_t Ncs_config         = fp->prach_config_common.prach_ConfigInfo.zeroCorrelationZoneConfig;
  uint8_t restricted_set     = fp->prach_config_common.prach_ConfigInfo.highSpeedFlag;
Agustin's avatar
Agustin committed
81
  uint8_t preamble_index     = ue->prach_resources[eNB_id]->ra_PreambleIndex;
yilmazt's avatar
yilmazt committed
82
  //uint8_t tdd_mapindex       = ue->prach_resources[eNB_id]->ra_TDD_map_index;
Agustin's avatar
Agustin committed
83
  int16_t *prachF           = ue->prach_vars[eNB_id]->prachF;
84
  int16_t prach_tmp[98304*2*4] __attribute__((aligned(32)));
Agustin's avatar
Agustin committed
85 86 87 88
  int16_t *prach            = prach_tmp;
  int16_t *prach2;
  int16_t amp               = ue->prach_vars[eNB_id]->amp;
  int16_t Ncp;
89
  uint16_t NCS=0;
Agustin's avatar
Agustin committed
90 91 92
  uint16_t *prach_root_sequence_map;
  uint16_t preamble_offset,preamble_shift;
  uint16_t preamble_index0,n_shift_ra,n_shift_ra_bar;
93
  uint16_t d_start=-1,numshift;
Agustin's avatar
Agustin committed
94

95
  uint16_t prach_fmt = get_nr_prach_fmt(prach_ConfigIndex,fp->frame_type,fp->freq_range);
Agustin's avatar
Agustin committed
96 97 98 99 100 101 102 103 104
  //uint8_t Nsp=2;
  //uint8_t f_ra,t1_ra;
  uint16_t N_ZC = (prach_fmt<4)?839:139;
  uint8_t not_found;
  int16_t *Xu;
  uint16_t u;
  int32_t Xu_re,Xu_im;
  uint16_t offset,offset2;
  int prach_start;
105
  int i, prach_len=0;
Agustin's avatar
Agustin committed
106 107
  uint16_t first_nonzero_root_idx=0;

108
#if defined(OAI_USRP)
109
  prach_start =  (ue->rx_offset+subframe*fp->samples_per_subframe-ue->hw_timing_advance-ue->N_TA_offset);
110
#ifdef NR_PRACH_DEBUG
Agustin's avatar
Agustin committed
111 112 113 114 115 116 117 118
    LOG_I(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id,
        prach_start,
        ue->rx_offset,
        ue->hw_timing_advance,
        ue->N_TA_offset);
#endif

  if (prach_start<0)
119
    prach_start+=(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
Agustin's avatar
Agustin committed
120

121 122
  if (prach_start>=(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME))
    prach_start-=(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME);
Agustin's avatar
Agustin committed
123 124

#else //normal case (simulation)
125
  prach_start = subframe*fp->samples_per_subframe-ue->N_TA_offset;
126
  LOG_D(PHY,"[UE %d] prach_start %d, rx_offset %d, hw_timing_advance %d, N_TA_offset %d\n", ue->Mod_id,
Agustin's avatar
Agustin committed
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    prach_start,
    ue->rx_offset,
    ue->hw_timing_advance,
    ue->N_TA_offset);

#endif


  // First compute physical root sequence
  /************************************************************************
  * 4G and NR NCS tables are slightly different and depend on prach format
  * Table 6.3.3.1-5:  for preamble formats with delta_f_RA = 1.25 Khz (formats 0,1,2)
  * Table 6.3.3.1-6:  for preamble formats with delta_f_RA = 5 Khz (formats 3)
  * NOTE: Restricted set type B is not implemented
  *************************************************************************/

  int restricted_Type = 0; //this is hardcoded ('0' for restricted_TypeA; and '1' for restricted_TypeB). FIXME
  if (prach_fmt<3){
    if (restricted_set == 0) {
      NCS = NCS_unrestricted_delta_f_RA_125[Ncs_config];
    } else {
      if (restricted_Type == 0) NCS = NCS_restricted_TypeA_delta_f_RA_125[Ncs_config]; // for TypeA, this is hardcoded. FIXME
      if (restricted_Type == 1) NCS = NCS_restricted_TypeB_delta_f_RA_125[Ncs_config]; // for TypeB, this is hardcoded. FIXME
    }
  }
  if (prach_fmt==3){
    if (restricted_set == 0) {
      NCS = NCS_unrestricted_delta_f_RA_5[Ncs_config];
    } else {
      if (restricted_Type == 0) NCS = NCS_restricted_TypeA_delta_f_RA_5[Ncs_config]; // for TypeA, this is hardcoded. FIXME
      if (restricted_Type == 1) NCS = NCS_restricted_TypeB_delta_f_RA_5[Ncs_config]; // for TypeB, this is hardcoded. FIXME
    }
  }
  if (prach_fmt>3){
    NCS = NCS_unrestricted_delta_f_RA_15[Ncs_config];
  }

  prach_root_sequence_map = (prach_fmt<4) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc;

  // This is the relative offset (for unrestricted case) in the root sequence table (5.7.2-4 from 36.211) for the given preamble index
  preamble_offset = ((NCS==0)? preamble_index : (preamble_index/(N_ZC/NCS)));

  if (restricted_set == 0) {
    // This is the \nu corresponding to the preamble index
    preamble_shift  = (NCS==0)? 0 : (preamble_index % (N_ZC/NCS));
    preamble_shift *= NCS;
  } else { // This is the high-speed case

175
#ifdef NR_PRACH_DEBUG
Agustin's avatar
Agustin committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
    LOG_I(PHY,"[UE %d] High-speed mode, NCS_config %d\n",ue->Mod_id,Ncs_config);
#endif

    not_found = 1;
    preamble_index0 = preamble_index;
    // set preamble_offset to initial rootSequenceIndex and look if we need more root sequences for this
    // preamble index and find the corresponding cyclic shift
    preamble_offset = 0; // relative rootSequenceIndex;

    while (not_found == 1) {
      // current root depending on rootSequenceIndex and preamble_offset
      int index = (rootSequenceIndex + preamble_offset) % N_ZC;

      if (prach_fmt<4) {
        // prach_root_sequence_map points to prach_root_sequence_map0_3
        DevAssert( index < sizeof(prach_root_sequence_map_0_3) / sizeof(prach_root_sequence_map_0_3[0]) );
      } else {
        // prach_root_sequence_map points to prach_root_sequence_map4
        DevAssert( index < sizeof(prach_root_sequence_map_abc) / sizeof(prach_root_sequence_map_abc[0]) );
      }

      u = prach_root_sequence_map[index];

      uint16_t n_group_ra = 0;

      if ( (nr_du[u]<(N_ZC/3)) && (nr_du[u]>=NCS) ) {
        n_shift_ra     = nr_du[u]/NCS;
        d_start        = (nr_du[u]<<1) + (n_shift_ra * NCS);
        n_group_ra     = N_ZC/d_start;
        n_shift_ra_bar = max(0,(N_ZC-(nr_du[u]<<1)-(n_group_ra*d_start))/N_ZC);
      } else if  ( (nr_du[u]>=(N_ZC/3)) && (nr_du[u]<=((N_ZC - NCS)>>1)) ) {
        n_shift_ra     = (N_ZC - (nr_du[u]<<1))/NCS;
        d_start        = N_ZC - (nr_du[u]<<1) + (n_shift_ra * NCS);
        n_group_ra     = nr_du[u]/d_start;
        n_shift_ra_bar = min(n_shift_ra,max(0,(nr_du[u]- (n_group_ra*d_start))/NCS));
      } else {
        n_shift_ra     = 0;
        n_shift_ra_bar = 0;
      }

      // This is the number of cyclic shifts for the current root u
      numshift = (n_shift_ra*n_group_ra) + n_shift_ra_bar;

      if (numshift>0 && preamble_index0==preamble_index)
        first_nonzero_root_idx = preamble_offset;

      if (preamble_index0 < numshift) {
        not_found      = 0;
        preamble_shift = (d_start * (preamble_index0/n_shift_ra)) + ((preamble_index0%n_shift_ra)*NCS);

      } else { // skip to next rootSequenceIndex and recompute parameters
        preamble_offset++;
        preamble_index0 -= numshift;
      }
    }
  }

  // now generate PRACH signal
234
#ifdef NR_PRACH_DEBUG
Agustin's avatar
Agustin committed
235 236

  if (NCS>0)
237 238
    LOG_D(PHY,"Generate PRACH for RootSeqIndex %d, Preamble Index %d, PRACH Format %x, prach_ConfigIndex %d, NCS %d (NCS_config %d, N_ZC/NCS %d): Preamble_offset %d, Preamble_shift %d\n",
          rootSequenceIndex,preamble_index,prach_fmt,prach_ConfigIndex,NCS,Ncs_config,N_ZC/NCS,
Agustin's avatar
Agustin committed
239 240 241 242 243 244
          preamble_offset,preamble_shift);

#endif

  //  nsymb = (frame_parms->Ncp==0) ? 14:12;
  //  subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*subframe*nsymb;
245 246 247 248 249 250 251 252 253 254 255 256 257
  int kbar = 1;
  int K    = 24;
  if (prach_fmt == 3) { 
    K=4;
    kbar=10;
  }
  else if (prach_fmt > 3) {
    // Note: Assumes that PRACH SCS is same as PUSCH SCS
    K=1;
    kbar=2;
  }
  int n_ra_prb            = fp->prach_config_common.prach_ConfigInfo.msg1_frequencystart;
  int k                   = (12*n_ra_prb) - 6*fp->N_RB_UL;
Agustin's avatar
Agustin committed
258

259
  k = (12*n_ra_prb) - 6*fp->N_RB_UL;
Agustin's avatar
Agustin committed
260

261
  if (k<0) k+=fp->ofdm_symbol_size;
Agustin's avatar
Agustin committed
262

263 264
  k*=K;
  k+=kbar;
Agustin's avatar
Agustin committed
265

266 267
  LOG_D(PHY,"placing prach in position %d\n",k);
  k*=2;
Agustin's avatar
Agustin committed
268 269 270

  Xu = (int16_t*)ue->X_u[preamble_offset-first_nonzero_root_idx];

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
  /********************************************************
   *
   * In function init_prach_tables:
   * to compute quantized roots of unity ru(n) = 32767 * exp j*[ (2 * PI * n) / N_ZC ]
   *
   * In compute_prach_seq:
   * to calculate Xu = DFT xu = xu (inv_u*k) * Xu[0] (This is a Zadoff-Chou sequence property: DFT ZC sequence is another ZC sequence)
   *
   * In generate_prach:
   * to do the cyclic-shifted DFT by multiplying Xu[k] * ru[k*preamble_shift] as:
   * If X[k] = DFT x(n) -> X_shifted[k] = DFT x(n+preamble_shift) = X[k] * exp -j*[ (2*PI*k*preamble_shift) / N_ZC ]
   *
   *********************************************************/

  AssertFatal(prach_fmt>3,"prach_fmt<=3: Fix this for other formats\n");
  int dftlen=2048;
  if (fp->N_RB_UL >= 137) dftlen=4096;
  if (fp->threequarter_fs==1) dftlen=(3*dftlen)/4;
Agustin's avatar
Agustin committed
289

290 291 292 293 294 295 296 297 298 299 300
  for (offset=0,offset2=0; offset<N_ZC; offset++,offset2+=preamble_shift) {

    if (offset2 >= N_ZC)
      offset2 -= N_ZC;

    Xu_re = (((int32_t)Xu[offset<<1]*amp)>>15);
    Xu_im = (((int32_t)Xu[1+(offset<<1)]*amp)>>15);
    prachF[k++]= ((Xu_re*nr_ru[offset2<<1]) - (Xu_im*nr_ru[1+(offset2<<1)]))>>15;
    prachF[k++]= ((Xu_im*nr_ru[offset2<<1]) + (Xu_re*nr_ru[1+(offset2<<1)]))>>15;
    if (k==dftlen) k=0;
  }
Agustin's avatar
Agustin committed
301

302
  switch (fp->N_RB_UL) {
Agustin's avatar
Agustin committed
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
  case 6:
    memset((void*)prachF,0,4*1536);
    break;

  case 15:
    memset((void*)prachF,0,4*3072);
    break;

  case 25:
    memset((void*)prachF,0,4*6144);
    break;

  case 50:
    memset((void*)prachF,0,4*12288);
    break;

  case 75:
    memset((void*)prachF,0,4*18432);
    break;

  case 100:
324
    if (fp->threequarter_fs == 0)
Agustin's avatar
Agustin committed
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
      memset((void*)prachF,0,4*24576);
    else
      memset((void*)prachF,0,4*18432);
    break;

  case 106:
    memset((void*)prachF,0,4*24576);
    break;
}

  int mu = 1; // numerology is hardcoded. FIXME!!!
  switch (prach_fmt) {
  case 0:
    Ncp = 3168;
    break;

  case 1:
342
    Ncp = 2*21024;
Agustin's avatar
Agustin committed
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
    break;

  case 2:
    Ncp = 4688;
    break;

  case 3:
    Ncp = 3168;
    break;

  case 0xa1:
    Ncp = 288/(1<<mu);
    break;

  case 0xa2:
    Ncp = 576/(1<<mu);
    break;

  case 0xa3:
    Ncp = 864/(1<<mu);
    break;

  case 0xb1:
    Ncp = 216/(1<<mu);
    break;

  case 0xb2:
    Ncp = 360/(1<<mu);
    break;

  case 0xb3:
    Ncp = 504/(1<<mu);
    break;

  case 0xb4:
    Ncp = 936/(1<<mu);
    break;

  case 0xc0:
    Ncp = 1240/(1<<mu);
    break;

  case 0xc2:
    Ncp = 2048/(1<<mu);
    break;

  default:
    Ncp = 3168;
    break;
  }


395 396 397 398
  if (fp->N_RB_UL <= 100)
    AssertFatal(1==0,"N_RB_UL %d not supported for NR PRACH yet\n",fp->N_RB_UL);
  else if (fp->N_RB_UL < 137) { // 46.08 or 61.44 Ms/s
    if (fp->threequarter_fs==0) { //61.44 Ms/s  
399
      Ncp<<=1;
400 401 402
      // This is after cyclic prefix (Ncp<<1 samples for 30.72 Ms/s, Ncp<<2 samples for 61.44 Ms/s
      prach2 = prach+(Ncp<<1);
      if (prach_fmt == 0) { //24576 samples @ 30.72 Ms/s, 49152 samples @ 61.44 Ms/s
frtabu's avatar
frtabu committed
403
	idft(IDFT_49152,prachF,prach2,1);
404 405 406
	// here we have |empty | Prach49152|
	memmove(prach,prach+(49152<<1),(Ncp<<3));
	// here we have |Prefix | Prach49152|
407 408
	prach_len = 49152+Ncp;
	dftlen=49152;
Agustin's avatar
Agustin committed
409
      }
410
      else if (prach_fmt == 1) { //24576 samples @ 30.72 Ms/s, 49152 samples @ 61.44 Ms/s
frtabu's avatar
frtabu committed
411
	idft(IDFT_49152,prachF,prach2,1);
412 413 414 415
	memmove(prach2+(49152<<1),prach2,(49152<<2));
	// here we have |empty | Prach49152 | Prach49152|
	memmove(prach,prach+(49152<<2),(Ncp<<3));
	// here we have |Prefix | Prach49152 | Prach49152|
416 417
	prach_len = (49152*2)+Ncp;
	dftlen=49152;
Agustin's avatar
Agustin committed
418
      }
419
      else if (prach_fmt == 2) { //24576 samples @ 30.72 Ms/s, 49152 samples @ 61.44 Ms/s
frtabu's avatar
frtabu committed
420
	idft(IDFT_49152,prachF,prach2,1);
421 422 423 424 425 426
	memmove(prach2+(49152<<1),prach2,(49152<<2));
	// here we have |empty | Prach49152 | Prach49152| empty49152 | empty49152
	memmove(prach2+(49152<<2),prach2,(49152<<3));
	// here we have |empty | Prach49152 | Prach49152| Prach49152 | Prach49152
	memmove(prach,prach+(49152<<3),(Ncp<<3));
	// here we have |Prefix | Prach49152 | Prach49152| Prach49152 | Prach49152
427 428
	prach_len = (49152*4)+Ncp;
	dftlen=49152;
Agustin's avatar
Agustin committed
429
      }
430
      else if (prach_fmt == 3) { // //6144 samples @ 30.72 Ms/s, 12288 samples @ 61.44 Ms/s
frtabu's avatar
frtabu committed
431
	idft(IDFT_12288,prachF,prach2,1);
432 433 434 435 436 437
	memmove(prach2+(12288<<1),prach2,(12288<<2));
	// here we have |empty | Prach12288 | Prach12288| empty12288 | empty12288
	memmove(prach2+(12288<<2),prach2,(12288<<3));
	// here we have |empty | Prach12288 | Prach12288| Prach12288 | Prach12288
	memmove(prach,prach+(12288<<3),(Ncp<<3));
	// here we have |Prefix | Prach12288 | Prach12288| Prach12288 | Prach12288
438 439
	prach_len = (12288*4)+Ncp;
	dftlen=12288;
Agustin's avatar
Agustin committed
440
      }
441
      else if (prach_fmt == 0xa1 || prach_fmt == 0xb1 || prach_fmt == 0xc0) {
442
	prach2 = prach+(Ncp<<1);
frtabu's avatar
frtabu committed
443
	idft(IDFT_2048,prachF,prach2,1);
444
	dftlen=2048;
445
	// here we have |empty | Prach2048 |
446
	if (prach_fmt != 0xc0) {
447
	  memmove(prach2+(2048<<1),prach2,(2048<<2));
448 449 450
	  prach_len = (2048*2)+Ncp;
	}
	else prach_len = (2048*1)+Ncp;
451 452
	memmove(prach,prach+(2048<<1),(Ncp<<2));
	// here we have |Prefix | Prach2048 | Prach2048 (if ! 0xc0)  | 
Agustin's avatar
Agustin committed
453
      }
454
      else if (prach_fmt == 0xa2 || prach_fmt == 0xb2) { // 6x2048
frtabu's avatar
frtabu committed
455
	idft(IDFT_2048,prachF,prach2,1);
456 457 458 459 460 461 462 463 464 465
	dftlen=2048;
	// here we have |empty | Prach2048 |
	memmove(prach2+(2048<<1),prach2,(2048<<2));
	// here we have |empty | Prach2048 | Prach2048| empty2048 | empty2048 | 
	memmove(prach2+(2048<<2),prach2,(2048<<3));
	// here we have |empty | Prach2048 | Prach2048| Prach2048 | Prach2048 | 
	memmove(prach,prach+(2048<<1),(Ncp<<2));
	// here we have |Prefix | Prach2048 |
	prach_len = (2048*4)+Ncp; 
      }
466
      else if (prach_fmt == 0xa3 || prach_fmt == 0xb3) { // 6x2048
467
	prach2 = prach+(Ncp<<1);
frtabu's avatar
frtabu committed
468
	idft(IDFT_2048,prachF,prach2,1);
469
	dftlen=2048;
470 471 472 473 474 475 476 477
	// here we have |empty | Prach2048 |
	memmove(prach2+(2048<<1),prach2,(2048<<2));
	// here we have |empty | Prach2048 | Prach2048| empty2048 | empty2048 | empty2048 | empty2048
	memmove(prach2+(2048<<2),prach2,(2048<<3));
	// here we have |empty | Prach2048 | Prach2048| Prach2048 | Prach2048 | empty2048 | empty2048
	memmove(prach2+((2048<<1)*3),prach2,(2048<<3));
	// here we have |empty | Prach2048 | Prach2048| Prach2048 | Prach2048 | Prach2048 | Prach2048
	memmove(prach,prach+(2048<<1),(Ncp<<2));
478 479
	// here we have |Prefix | Prach2048 |
	prach_len = (2048*6)+Ncp; 
Agustin's avatar
Agustin committed
480
      }
481
      else if (prach_fmt == 0xb4) { // 12x2048
frtabu's avatar
frtabu committed
482
	idft(IDFT_2048,prachF,prach2,1);
483
	dftlen=2048;
484 485 486 487 488 489 490 491 492 493 494
	// here we have |empty | Prach2048 |
	memmove(prach2+(2048<<1),prach2,(2048<<2));
	// here we have |empty | Prach2048 | Prach2048| empty2048 | empty2048 | empty2048 | empty2048
	memmove(prach2+(2048<<2),prach2,(2048<<3));
	// here we have |empty | Prach2048 | Prach2048| Prach2048 | Prach2048 | empty2048 | empty2048
	memmove(prach2+(2048<<3),prach2,(2048<<3));
	// here we have |empty | Prach2048 | Prach2048| Prach2048 | Prach2048 | Prach2048 | Prach2048
	memmove(prach2+(2048<<1)*6,prach2,(2048<<2)*6);
	// here we have |empty | Prach2048 | Prach2048| Prach2048 | Prach2048 | Prach2048 | Prach2048 | Prach2048 | Prach2048| Prach2048 | Prach2048 | Prach2048 | Prach2048|
	memmove(prach,prach+(2048<<1),(Ncp<<2));
	// here we have |Prefix | Prach2048 | Prach2048| Prach2048 | Prach2048 | Prach2048 | Prach2048 | Prach2048 | Prach2048| Prach2048 | Prach2048 | Prach2048 | Prach2048|
495
	prach_len = (2048*12)+Ncp;
Agustin's avatar
Agustin committed
496
      }
497 498 499
      
    }
    else {     // 46.08 Ms/s
500 501
      Ncp = (Ncp*3)/2;
      prach2 = prach+(Ncp<<1);
502
      if (prach_fmt == 0) {
frtabu's avatar
frtabu committed
503
	idft(IDFT_36864,prachF,prach2,1);
504
	dftlen=36864;
505 506 507
	// here we have |empty | Prach73728|
	memmove(prach,prach+(36864<<1),(Ncp<<2));
	// here we have |Prefix | Prach73728|
508
	prach_len = (36864*1)+Ncp;
509 510
      }
      else if (prach_fmt == 1) {
frtabu's avatar
frtabu committed
511
	idft(IDFT_36864,prachF,prach2,1);
512
	dftlen=36864;
513 514
	memmove(prach2+(36864<<1),prach2,(36864<<2));
	// here we have |empty | Prach73728 | Prach73728|
515
	memmove(prach,prach+(36864<<2),(Ncp<<2));
516
	// here we have |Prefix | Prach73728 | Prach73728|
517
	prach_len = (36864*2)+Ncp;
518 519
      }
      if (prach_fmt == 2) {
frtabu's avatar
frtabu committed
520
	idft(IDFT_36864,prachF,prach2,1);
521
	dftlen=36864;
522 523 524 525
	memmove(prach2+(36864<<1),prach2,(36864<<2));
	// here we have |empty | Prach73728 | Prach73728| empty73728 | empty73728
	memmove(prach2+(36864<<2),prach2,(36864<<3));
	// here we have |empty | Prach73728 | Prach73728| Prach73728 | Prach73728
526
	memmove(prach,prach+(36864<<3),(Ncp<<2));
527
	// here we have |Prefix | Prach73728 | Prach73728| Prach73728 | Prach73728
528
	prach_len = (36864*4)+Ncp;
529 530
      }
      else if (prach_fmt == 3) {
frtabu's avatar
frtabu committed
531
	idft(IDFT_9216,prachF,prach2,1);
532
	dftlen=36864;
533 534 535 536
	memmove(prach2+(9216<<1),prach2,(9216<<2));
	// here we have |empty | Prach9216 | Prach9216| empty9216 | empty9216
	memmove(prach2+(9216<<2),prach2,(9216<<3));
	// here we have |empty | Prach9216 | Prach9216| Prach9216 | Prach9216
537
	memmove(prach,prach+(9216<<3),(Ncp<<2));
538
	// here we have |Prefix | Prach9216 | Prach9216| Prach9216 | Prach9216
539
	prach_len = (9216*4)+Ncp;
540 541
      }
      else if (prach_fmt == 0xa1 || prach_fmt == 0xb1 || prach_fmt == 0xc0) {
frtabu's avatar
frtabu committed
542
	idft(IDFT_1536,prachF,prach2,1);
543
	dftlen=1536;
544 545 546 547 548
	// here we have |empty | Prach1536 |
	if (prach_fmt != 0xc0)
	  memmove(prach2+(1536<<1),prach2,(1536<<2));
	memmove(prach,prach+(1536<<1),(Ncp<<2));
	// here we have |Prefix | Prach1536 | Prach1536 (if ! 0xc0)  | 
549
	prach_len = (1536*2)+Ncp;
Agustin's avatar
Agustin committed
550
      }
551
      else if (prach_fmt == 0xa2 || prach_fmt == 0xb2) { // 6x1536
frtabu's avatar
frtabu committed
552
	idft(IDFT_1536,prachF,prach2,1);
553 554 555 556 557 558 559 560 561
	dftlen=1536;
	// here we have |empty | Prach1536 |
	memmove(prach2+(1536<<1),prach2,(1536<<2));
	// here we have |empty | Prach1536 | Prach1536| empty1536 | empty1536 |
	memmove(prach2+(1536<<2),prach2,(1536<<3));
	// here we have |empty | Prach1536 | Prach1536| Prach1536 | Prach1536 |
	memmove(prach,prach+(1536<<1),(Ncp<<2));
	// here we have |Prefix | Prach1536 |
	prach_len = (1536*4)+Ncp; 
562 563
      }
      else if (prach_fmt == 0xa3 || prach_fmt == 0xb3) { // 6x1536
frtabu's avatar
frtabu committed
564
	idft(IDFT_1536,prachF,prach2,1);
565
	dftlen=1536;
566 567 568 569 570 571 572 573 574
	// here we have |empty | Prach1536 |
	memmove(prach2+(1536<<1),prach2,(1536<<2));
	// here we have |empty | Prach1536 | Prach1536| empty1536 | empty1536 | empty1536 | empty1536
	memmove(prach2+(1536<<2),prach2,(1536<<3));
	// here we have |empty | Prach1536 | Prach1536| Prach1536 | Prach1536 | empty1536 | empty1536
	memmove(prach2+((1536<<1)*3),prach2,(1536<<3));
	// here we have |empty | Prach1536 | Prach1536| Prach1536 | Prach1536 | Prach1536 | Prach1536
	memmove(prach,prach+(1536<<1),(Ncp<<2));
	// here we have |Prefix | Prach1536 | 
575
	prach_len = (1536*6)+Ncp; 
576 577
      }
      else if (prach_fmt == 0xb4) { // 12x1536
frtabu's avatar
frtabu committed
578
	idft(IDFT_1536,prachF,prach2,1);
579
	dftlen=1536;
580 581 582 583 584 585 586 587 588 589 590
	// here we have |empty | Prach1536 |
	memmove(prach2+(1536<<1),prach2,(1536<<2));
	// here we have |empty | Prach1536 | Prach1536| empty1536 | empty1536 | empty1536 | empty1536
	memmove(prach2+(1536<<2),prach2,(1536<<3));
	// here we have |empty | Prach1536 | Prach1536| Prach1536 | Prach1536 | empty1536 | empty1536
	memmove(prach2+(1536<<3),prach2,(1536<<3));
	// here we have |empty | Prach1536 | Prach1536| Prach1536 | Prach1536 | Prach1536 | Prach1536
	memmove(prach2+(1536<<1)*6,prach2,(1536<<2)*6);
	// here we have |empty | Prach1536 | Prach1536| Prach1536 | Prach1536 | Prach1536 | Prach1536 | Prach1536 | Prach1536| Prach1536 | Prach1536 | Prach1536 | Prach1536|
	memmove(prach,prach+(1536<<1),(Ncp<<2));
	// here we have |Prefix | Prach1536 | Prach1536| Prach1536 | Prach1536 | Prach1536 | Prach1536 | Prach1536 | Prach1536| Prach1536 | Prach1536 | Prach1536 | Prach1536|
591
	prach_len = (1536*12)+Ncp; 
592
      }      
Agustin's avatar
Agustin committed
593
    }
594 595
  }
  else if (fp->N_RB_UL <= 273) {// 92.16 or 122.88 Ms/s
596 597 598
    if (fp->threequarter_fs==0) { //122.88 Ms/s
      Ncp<<=2;
      prach2 = prach+(Ncp<<1);
599
      if (prach_fmt == 0) { //24576 samples @ 30.72 Ms/s, 98304 samples @ 122.88 Ms/s
frtabu's avatar
frtabu committed
600
	idft(IDFT_98304,prachF,prach2,1);
601
	dftlen=98304;
602
	// here we have |empty | Prach98304|
603
	memmove(prach,prach+(98304<<1),(Ncp<<2));
604
	// here we have |Prefix | Prach98304|
605
	prach_len = (98304*1)+Ncp;
606 607
      }
      else if (prach_fmt == 1) {
frtabu's avatar
frtabu committed
608
	idft(IDFT_98304,prachF,prach2,1);
609
	dftlen=98304;
610 611
	memmove(prach2+(98304<<1),prach2,(98304<<2));
	// here we have |empty | Prach98304 | Prach98304|
612
	memmove(prach,prach+(98304<<2),(Ncp<<2));
613
	// here we have |Prefix | Prach98304 | Prach98304|
614
	prach_len = (98304*2)+Ncp;
615 616
      }
      else if (prach_fmt == 2) {
frtabu's avatar
frtabu committed
617
	idft(IDFT_98304,prachF,prach2,1);
618
	dftlen=98304;
619 620 621 622
	memmove(prach2+(98304<<1),prach2,(98304<<2));
	// here we have |empty | Prach98304 | Prach98304| empty98304 | empty98304
	memmove(prach2+(98304<<2),prach2,(98304<<3));
	// here we have |empty | Prach98304 | Prach98304| Prach98304 | Prach98304
623
	memmove(prach,prach+(98304<<3),(Ncp<<2));
624
	// here we have |Prefix | Prach98304 | Prach98304| Prach98304 | Prach98304
625
	prach_len = (98304*4)+Ncp;
626 627
      }
      else if (prach_fmt == 3) { // 4x6144, Ncp 3168
frtabu's avatar
frtabu committed
628
	idft(IDFT_24576,prachF,prach2,1);
629
	dftlen=24576;
630 631 632 633
	memmove(prach2+(24576<<1),prach2,(24576<<2));
	// here we have |empty | Prach24576 | Prach24576| empty24576 | empty24576
	memmove(prach2+(24576<<2),prach2,(24576<<3));
	// here we have |empty | Prach24576 | Prach24576| Prach24576 | Prach24576
634
	memmove(prach,prach+(24576<<3),(Ncp<<2));
635
	// here we have |Prefix | Prach24576 | Prach24576| Prach24576 | Prach24576
636
	prach_len = (24576*4)+(Ncp<<1);
637 638
      }
      else if (prach_fmt == 0xa1 || prach_fmt == 0xb1 || prach_fmt == 0xc0) {
frtabu's avatar
frtabu committed
639
	idft(IDFT_4096,prachF,prach2,1);
640
	dftlen=4096;
641
	// here we have |empty | Prach4096 |
642
	if (prach_fmt != 0xc0) {
643
	  memmove(prach2+(4096<<1),prach2,(4096<<2));
644 645 646
	  prach_len = (4096*2)+Ncp; 
	}
	else 	prach_len = (4096*1)+Ncp; 
647 648
	memmove(prach,prach+(4096<<1),(Ncp<<2));
	// here we have |Prefix | Prach4096 | Prach4096 (if ! 0xc0)  | 
Agustin's avatar
Agustin committed
649

650 651
      }
      else if (prach_fmt == 0xa2 || prach_fmt == 0xb2) { // 4x4096
frtabu's avatar
frtabu committed
652
	idft(IDFT_4096,prachF,prach2,1);
653 654 655 656 657 658 659 660 661
	dftlen=4096;
	// here we have |empty | Prach4096 |
	memmove(prach2+(4096<<1),prach2,(4096<<2));
	// here we have |empty | Prach4096 | Prach4096| empty4096 | empty4096 |
	memmove(prach2+(4096<<2),prach2,(4096<<3));
	// here we have |empty | Prach4096 | Prach4096| Prach4096 | Prach4096 |
	memmove(prach,prach+(4096<<1),(Ncp<<2));
	// here we have |Prefix | Prach4096 |
	prach_len = (4096*4)+Ncp;  
662 663
      }
      else if (prach_fmt == 0xa3 || prach_fmt == 0xb3) { // 6x4096
frtabu's avatar
frtabu committed
664
	idft(IDFT_4096,prachF,prach2,1);
665
	dftlen=4096;
666 667 668 669 670 671 672 673 674
	// here we have |empty | Prach4096 |
	memmove(prach2+(4096<<1),prach2,(4096<<2));
	// here we have |empty | Prach4096 | Prach4096| empty4096 | empty4096 | empty4096 | empty4096
	memmove(prach2+(4096<<2),prach2,(4096<<3));
	// here we have |empty | Prach4096 | Prach4096| Prach4096 | Prach4096 | empty4096 | empty4096
	memmove(prach2+((4096<<1)*3),prach2,(4096<<3));
	// here we have |empty | Prach4096 | Prach4096| Prach4096 | Prach4096 | Prach4096 | Prach4096
	memmove(prach,prach+(4096<<1),(Ncp<<2));
	// here we have |Prefix | Prach4096 | 
675
	prach_len = (4096*6)+Ncp; 
676 677
      }
      else if (prach_fmt == 0xb4) { // 12x4096
frtabu's avatar
frtabu committed
678
	idft(IDFT_4096,prachF,prach2,1);
679
	dftlen=4096;
680 681 682 683 684 685 686 687 688 689 690
	// here we have |empty | Prach4096 |
	memmove(prach2+(4096<<1),prach2,(4096<<2));
	// here we have |empty | Prach4096 | Prach4096| empty4096 | empty4096 | empty4096 | empty4096
	memmove(prach2+(4096<<2),prach2,(4096<<3));
	// here we have |empty | Prach4096 | Prach4096| Prach4096 | Prach4096 | empty4096 | empty4096
	memmove(prach2+(4096<<3),prach2,(4096<<3));
	// here we have |empty | Prach4096 | Prach4096| Prach4096 | Prach4096 | Prach4096 | Prach4096
	memmove(prach2+(4096<<1)*6,prach2,(4096<<2)*6);
	// here we have |empty | Prach4096 | Prach4096| Prach4096 | Prach4096 | Prach4096 | Prach4096 | Prach4096 | Prach4096| Prach4096 | Prach4096 | Prach4096 | Prach4096|
	memmove(prach,prach+(4096<<1),(Ncp<<2));
	// here we have |Prefix | Prach4096 | Prach4096| Prach4096 | Prach4096 | Prach4096 | Prach4096 | Prach4096 | Prach4096| Prach4096 | Prach4096 | Prach4096 | Prach4096|
691
	prach_len = (4096*12)+Ncp; 
Agustin's avatar
Agustin committed
692 693
      }
    }
694
    else {     // 92.16 Ms/s
695 696
      Ncp = (Ncp*3);
      prach2 = prach+(Ncp<<1);
697
      if (prach_fmt == 0) {
frtabu's avatar
frtabu committed
698
	idft(IDFT_73728,prachF,prach2,1);
699
	dftlen=73728;
700 701 702
	// here we have |empty | Prach73728|
	memmove(prach,prach+(73728<<1),(Ncp<<4));
	// here we have |Prefix | Prach73728|
703
	prach_len = (73728*1)+Ncp;
704 705
      }
      else if (prach_fmt == 1) {
frtabu's avatar
frtabu committed
706
	idft(IDFT_73728,prachF,prach2,1);
707
	dftlen=73728;
708 709 710 711
	memmove(prach2+(73728<<1),prach2,(73728<<2));
	// here we have |empty | Prach73728 | Prach73728|
	memmove(prach,prach+(73728<<2),(Ncp<<4));
	// here we have |Prefix | Prach73728 | Prach73728|
712
	prach_len = (73728*2)+Ncp;
713 714
      }
      if (prach_fmt == 2) {
frtabu's avatar
frtabu committed
715
	idft(IDFT_73728,prachF,prach2,1);
716
	dftlen=73728;
717 718 719 720 721 722
	memmove(prach2+(73728<<1),prach2,(73728<<2));
	// here we have |empty | Prach73728 | Prach73728| empty73728 | empty73728
	memmove(prach2+(73728<<2),prach2,(73728<<3));
	// here we have |empty | Prach73728 | Prach73728| Prach73728 | Prach73728
	memmove(prach,prach+(73728<<3),(Ncp<<4));
	// here we have |Prefix | Prach73728 | Prach73728| Prach73728 | Prach73728
723
	prach_len = (73728*4)+Ncp;
724 725
      }
      else if (prach_fmt == 3) {
frtabu's avatar
frtabu committed
726
	idft(IDFT_18432,prachF,prach2,1);
727
	dftlen=18432;
728 729 730 731 732 733
	memmove(prach2+(18432<<1),prach2,(18432<<2));
	// here we have |empty | Prach18432 | Prach18432| empty18432 | empty18432
	memmove(prach2+(18432<<2),prach2,(18432<<3));
	// here we have |empty | Prach18432 | Prach18432| Prach18432 | Prach18432
	memmove(prach,prach+(18432<<3),(Ncp<<4));
	// here we have |Prefix | Prach18432 | Prach18432| Prach18432 | Prach18432
734
	prach_len = (18432*4)+Ncp;
735 736
      }
      else if (prach_fmt == 0xa1 || prach_fmt == 0xb1 || prach_fmt == 0xc0) {
frtabu's avatar
frtabu committed
737
	idft(IDFT_3072,prachF,prach2,1);
738
	dftlen=3072;
739
	// here we have |empty | Prach3072 |
740
	if (prach_fmt != 0xc0) {
741
	  memmove(prach2+(3072<<1),prach2,(3072<<2));
742 743 744
	  prach_len = (3072*2)+Ncp;
	} 
	else 	  prach_len = (3072*1)+Ncp;
745 746 747 748
	memmove(prach,prach+(3072<<1),(Ncp<<2));
	// here we have |Prefix | Prach3072 | Prach3072 (if ! 0xc0)  | 
      }
      else if (prach_fmt == 0xa3 || prach_fmt == 0xb3) { // 6x3072
frtabu's avatar
frtabu committed
749
	idft(IDFT_3072,prachF,prach2,1);
750
	dftlen=3072;
751 752 753 754 755 756 757 758 759
	// here we have |empty | Prach3072 |
	memmove(prach2+(3072<<1),prach2,(3072<<2));
	// here we have |empty | Prach3072 | Prach3072| empty3072 | empty3072 | empty3072 | empty3072
	memmove(prach2+(3072<<2),prach2,(3072<<3));
	// here we have |empty | Prach3072 | Prach3072| Prach3072 | Prach3072 | empty3072 | empty3072
	memmove(prach2+((3072<<1)*3),prach2,(3072<<3));
	// here we have |empty | Prach3072 | Prach3072| Prach3072 | Prach3072 | Prach3072 | Prach3072
	memmove(prach,prach+(3072<<1),(Ncp<<2));
	// here we have |Prefix | Prach3072 | 
760 761 762
	prach_len = (3072*6)+Ncp;
      }
      else if (prach_fmt == 0xa2 || prach_fmt == 0xb2) { // 4x3072
frtabu's avatar
frtabu committed
763
	idft(IDFT_3072,prachF,prach2,1);
764 765 766 767 768 769 770 771 772
	dftlen=3072;
	// here we have |empty | Prach3072 |
	memmove(prach2+(3072<<1),prach2,(3072<<2));
	// here we have |empty | Prach3072 | Prach3072| empty3072 | empty3072 |
	memmove(prach2+(3072<<2),prach2,(3072<<3));
	// here we have |empty | Prach3072 | Prach3072| Prach3072 | Prach3072 |
	memmove(prach,prach+(3072<<1),(Ncp<<2));
	// here we have |Prefix | Prach3072 | 
	prach_len = (3072*4)+Ncp;
773 774
      }
      else if (prach_fmt == 0xb4) { // 12x3072
frtabu's avatar
frtabu committed
775
	idft(IDFT_3072,prachF,prach2,1);
776
	dftlen=3072;
777 778 779 780 781 782 783 784 785 786 787
	// here we have |empty | Prach3072 |
	memmove(prach2+(3072<<1),prach2,(3072<<2));
	// here we have |empty | Prach3072 | Prach3072| empty3072 | empty3072 | empty3072 | empty3072
	memmove(prach2+(3072<<2),prach2,(3072<<3));
	// here we have |empty | Prach3072 | Prach3072| Prach3072 | Prach3072 | empty3072 | empty3072
	memmove(prach2+(3072<<3),prach2,(3072<<3));
	// here we have |empty | Prach3072 | Prach3072| Prach3072 | Prach3072 | Prach3072 | Prach3072
	memmove(prach2+(3072<<1)*6,prach2,(3072<<2)*6);
	// here we have |empty | Prach3072 | Prach3072| Prach3072 | Prach3072 | Prach3072 | Prach3072 | Prach3072 | Prach3072| Prach3072 | Prach3072 | Prach3072 | Prach3072|
	memmove(prach,prach+(3072<<1),(Ncp<<2));
	// here we have |Prefix | Prach3072 | Prach3072| Prach3072 | Prach3072 | Prach3072 | Prach3072 | Prach3072 | Prach3072| Prach3072 | Prach3072 | Prach3072 | Prach3072|
788
	prach_len = (3072*12)+Ncp;
Agustin's avatar
Agustin committed
789 790
      }
    }
791
  }    
Agustin's avatar
Agustin committed
792 793 794 795




796
#if defined(OAI_USRP) || defined(OAI_BLADERF) || defined(OAI_LMSSDR)
Agustin's avatar
Agustin committed
797
  int j;
798
  int overflow = prach_start + prach_len - LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*fp->samples_per_subframe;
799
  LOG_D( PHY, "prach_start=%d, overflow=%d\n", prach_start, overflow );
Agustin's avatar
Agustin committed
800

801
  for (i=prach_start,j=0; i<min(fp->samples_per_subframe*LTE_NUMBER_OF_SUBFRAMES_PER_FRAME,prach_start+prach_len); i++,j++) {
Agustin's avatar
Agustin committed
802 803 804 805 806 807 808 809 810 811
    ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j];
    ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1];
  }

  for (i=0; i<overflow; i++,j++) {
    ((int16_t*)ue->common_vars.txdata[0])[2*i] = prach[2*j];
    ((int16_t*)ue->common_vars.txdata[0])[2*i+1] = prach[2*j+1];
  }
#else

812
  LOG_D( PHY, "prach_start=%d\n", prach_start);
Agustin's avatar
Agustin committed
813 814 815 816 817 818 819 820 821 822 823 824

  for (i=0; i<prach_len; i++) {
    ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i] = prach[2*i];
    ((int16_t*)(&ue->common_vars.txdata[0][prach_start]))[2*i+1] = prach[2*i+1];
  }
#endif



#if defined(PRACH_WRITE_OUTPUT_DEBUG)
  LOG_M("prach_txF0.m","prachtxF0",prachF,prach_len-Ncp,1,1);
  LOG_M("prach_tx0.m","prachtx0",prach+(Ncp<<1),prach_len-Ncp,1,1);
825
  LOG_M("txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][prach_start]),fp->samples_per_subframe,1,1);
Agustin's avatar
Agustin committed
826 827 828 829 830 831
  exit(-1);
#endif

  return signal_energy( (int*)prach, 256 );
}