nr_prach.c 54.5 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
/*
 * 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
 */

22 23 24 25 26 27 28
/*! \file PHY/NR_TRANSPORT/nr_prach.c
 * \brief Routines for UE PRACH physical channel
 * \author R. Knopp, G. Casati
 * \date 2019
 * \version 0.2
 * \company Eurecom, Fraunhofer IIS
 * \email: knopp@eurecom.fr, guido.casati@iis.fraunhofer.de
Agustin's avatar
Agustin committed
29 30 31 32 33 34 35 36
 * \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"
38
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
Agustin's avatar
Agustin committed
39 40 41 42 43 44

#include "common/utils/LOG/log.h"
#include "common/utils/LOG/vcd_signal_dumper.h"

#include "T.h"

45
//#define NR_PRACH_DEBUG 1
46

47 48 49 50
extern uint16_t prach_root_sequence_map_0_3[838];
extern uint16_t prach_root_sequence_map_abc[138];
extern uint16_t nr_du[838];
extern int16_t nr_ru[2*839];
51
extern const char *prachfmt[];
Agustin's avatar
Agustin committed
52

53 54 55 56 57 58 59 60
// Note:
// - prach_fmt_id is an ID used to map to the corresponding PRACH format value in prachfmt
// WIP todo:
// - take prach start symbol into account
// - idft for short sequence assumes we are transmitting starting in symbol 0 of a PRACH slot
// - Assumes that PRACH SCS is same as PUSCH SCS @ 30 kHz, take values for formats 0-2 and adjust for others below
// - Preamble index different from 0 is not detected by gNB
int32_t generate_nr_prach(PHY_VARS_NR_UE *ue, uint8_t gNB_id, uint8_t slot){
Agustin's avatar
Agustin committed
61

62
  NR_DL_FRAME_PARMS *fp=&ue->frame_parms;
63 64
  fapi_nr_config_request_t *nrUE_config = &ue->nrUE_config;
  NR_PRACH_RESOURCES_t *prach_resources = ue->prach_resources[gNB_id];
65
  fapi_nr_ul_config_prach_pdu *prach_pdu = &ue->prach_vars[gNB_id]->prach_pdu;
Agustin's avatar
Agustin committed
66

67
  uint8_t Mod_id, fd_occasion, preamble_index, restricted_set, not_found;
68 69
  uint16_t rootSequenceIndex, prach_fmt_id, NCS, *prach_root_sequence_map, preamble_offset = 0;
  uint16_t preamble_shift = 0, preamble_index0, n_shift_ra, n_shift_ra_bar, d_start, numshift, N_ZC, u, offset, offset2, first_nonzero_root_idx;
70
  int16_t prach_tmp[98304*2*4] __attribute__((aligned(32)));
Agustin's avatar
Agustin committed
71

72
  int16_t Ncp = 0, amp, *prach, *prach2, *prachF, *Xu;
73
  int32_t Xu_re, Xu_im;
74
  int prach_start, prach_sequence_length, i, prach_len, dftlen, mu, kbar, K, n_ra_prb, k, prachStartSymbol, sample_offset_slot;
75 76 77 78 79 80 81 82 83
  //int restricted_Type;

  prach                   = prach_tmp;
  prachF                  = ue->prach_vars[gNB_id]->prachF;
  amp                     = ue->prach_vars[gNB_id]->amp;
  Mod_id                  = ue->Mod_id;
  prach_sequence_length   = nrUE_config->prach_config.prach_sequence_length;
  N_ZC                    = (prach_sequence_length == 0) ? 839:139;
  mu                      = nrUE_config->prach_config.prach_sub_c_spacing;
84 85
  restricted_set          = prach_pdu->restricted_set;
  rootSequenceIndex       = prach_pdu->root_seq_id;
Laurent THOMAS's avatar
Laurent THOMAS committed
86
  fd_occasion             = 0;
87
  n_ra_prb                = nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1,//prach_pdu->freq_msg1;
88 89
  NCS                     = prach_pdu->num_cs;
  prach_fmt_id            = prach_pdu->prach_format;
90
  preamble_index          = prach_resources->ra_PreambleIndex;
91 92 93 94 95 96
  prach_len               = 0;
  dftlen                  = 0;
  first_nonzero_root_idx  = 0;
  kbar                    = 1;
  K                       = 24;
  k                       = 12*n_ra_prb - 6*fp->N_RB_UL;
97
  prachStartSymbol        = prach_pdu->prach_start_symbol;
98 99 100 101 102 103 104
  //restricted_Type         = 0;

  compute_nr_prach_seq(nrUE_config->prach_config.prach_sequence_length,
                       nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].num_root_sequences,
                       nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index,
                       ue->X_u);

105 106
  sample_offset_slot = (prachStartSymbol==0?0:fp->ofdm_symbol_size*prachStartSymbol+fp->nb_prefix_samples0+fp->nb_prefix_samples*(prachStartSymbol-1));
  prach_start = fp->get_samples_slot_timestamp(slot, fp, 0) + sample_offset_slot;
107

108 109
  //printf("prachstartsymbold %d, sample_offset_slot %d, prach_start %d\n",prachStartSymbol, sample_offset_slot, prach_start);

Agustin's avatar
Agustin committed
110 111 112 113 114 115 116 117
  // 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
  *************************************************************************/

118
  prach_root_sequence_map = (prach_sequence_length == 0) ? prach_root_sequence_map_0_3 : prach_root_sequence_map_abc;
Agustin's avatar
Agustin committed
119 120

  if (restricted_set == 0) {
121 122
    // 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)));
Agustin's avatar
Agustin committed
123 124 125 126 127
    // 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

128 129 130
    #ifdef NR_PRACH_DEBUG
      LOG_I(PHY, "PRACH [UE %d] High-speed mode, NCS %d\n", Mod_id, NCS);
    #endif
Agustin's avatar
Agustin committed
131 132

    not_found = 1;
133
    nr_fill_du(N_ZC,prach_root_sequence_map);
Agustin's avatar
Agustin committed
134 135 136 137 138 139 140 141
    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;
142
      uint16_t n_group_ra = 0;
Agustin's avatar
Agustin committed
143

144
      if (prach_fmt_id<4) {
Agustin's avatar
Agustin committed
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 175 176 177 178 179 180 181 182 183 184 185
        // 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];

      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;
      }
    }
  }

186
  // now generate PRACH signal
187
#ifdef NR_PRACH_DEBUG
188
    if (NCS>0)
cig's avatar
cig committed
189 190 191 192 193
      LOG_I(PHY, "PRACH [UE %d] generate PRACH in slot %d for RootSeqIndex %d, Preamble Index %d, PRACH Format %s, NCS %d (N_ZC %d): Preamble_offset %d, Preamble_shift %d msg1 frequency start %d\n",
        Mod_id,
        slot,
        rootSequenceIndex,
        preamble_index,
194
        prachfmt[prach_fmt_id],
195 196 197
        NCS,
        N_ZC,
        preamble_offset,
cig's avatar
cig committed
198 199
        preamble_shift,
        n_ra_prb);
200
  #endif
Agustin's avatar
Agustin committed
201 202

  //  nsymb = (frame_parms->Ncp==0) ? 14:12;
203 204 205 206 207 208 209 210
  //  subframe_offset = (unsigned int)frame_parms->ofdm_symbol_size*slot*nsymb;

  if (prach_sequence_length == 0 && prach_fmt_id == 3) {
    K = 4;
    kbar = 10;
  } else if (prach_sequence_length == 1) {
    K = 1;
    kbar = 2;
211
  }
Agustin's avatar
Agustin committed
212

213 214
  if (k<0)
    k += fp->ofdm_symbol_size;
Agustin's avatar
Agustin committed
215

216 217 218
  k *= K;
  k += kbar;
  k *= 2;
Agustin's avatar
Agustin committed
219

220 221 222 223 224 225 226
  LOG_I(PHY, "PRACH [UE %d] in slot %d, placing PRACH in position %d, msg1 frequency start %d (k1 %d), preamble_offset %d, first_nonzero_root_idx %d\n", Mod_id,
	slot,
	k,
	n_ra_prb,
	nrUE_config->prach_config.num_prach_fd_occasions_list[fd_occasion].k1,
	preamble_offset,
	first_nonzero_root_idx);
Agustin's avatar
Agustin committed
227 228 229

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

230 231 232 233
  #if defined (PRACH_WRITE_OUTPUT_DEBUG)
    LOG_M("X_u.m", "X_u", (int16_t*)ue->X_u[preamble_offset-first_nonzero_root_idx], N_ZC, 1, 1);
  #endif

234 235 236 237 238 239 240 241 242 243 244 245 246 247
  /********************************************************
   *
   * 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 ]
   *
   *********************************************************/

248
  if (mu==1) {
249
    switch(fp->samples_per_subframe) {
250 251
    case 15360:
      // 10, 15 MHz @ 15.36 Ms/s
252 253
      if (prach_sequence_length == 0) {
        if (prach_fmt_id == 0 || prach_fmt_id == 1 || prach_fmt_id == 2)
254
          dftlen = 12288;
255
        if (prach_fmt_id == 3)
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
          dftlen = 3072;
      } else { // 839 sequence
        dftlen = 512;
      }
      break;

    case 30720:
      // 20, 25, 30 MHz @ 30.72 Ms/s
      if (prach_sequence_length == 0) {
        if (prach_fmt_id == 0 || prach_fmt_id == 1 || prach_fmt_id == 2)
          dftlen = 24576;
        if (prach_fmt_id == 3)
          dftlen = 6144;
      } else { // 839 sequence
        dftlen = 1024;
271
      }
272 273
      break;

274 275
    case 46080:
      // 40 MHz @ 46.08 Ms/s
276 277 278 279 280
      if (prach_sequence_length == 0) {
        if (prach_fmt_id == 0 || prach_fmt_id == 1 || prach_fmt_id == 2)
          dftlen = 36864;
        if (prach_fmt_id == 3)
          dftlen = 9216;
281 282
      } else { // 839 sequence
        dftlen = 1536;
283
      }
284 285 286 287
      break;

    case 61440:
      // 40, 50, 60 MHz @ 61.44 Ms/s
288 289
      if (prach_sequence_length == 0) {
        if (prach_fmt_id == 0 || prach_fmt_id == 1 || prach_fmt_id == 2)
290
          dftlen = 49152;
291
        if (prach_fmt_id == 3)
292 293 294
          dftlen = 12288;
      } else { // 839 sequence
        dftlen = 2048;
295
      }
296 297 298 299 300 301 302 303 304 305 306
      break;

    case 92160:
      // 50, 60, 70, 80, 90 MHz @ 92.16 Ms/s
      if (prach_sequence_length == 0) {
        if (prach_fmt_id == 0 || prach_fmt_id == 1 || prach_fmt_id == 2)
          dftlen = 73728;
        if (prach_fmt_id == 3)
          dftlen = 18432;
      } else { // 839 sequence
        dftlen = 3072;
307
      }
308 309 310 311
      break;

    case 122880:
      // 70, 80, 90, 100 MHz @ 122.88 Ms/s
312 313 314 315 316
      if (prach_sequence_length == 0) {
        if (prach_fmt_id == 0 || prach_fmt_id == 1 || prach_fmt_id == 2)
          dftlen = 98304;
        if (prach_fmt_id == 3)
          dftlen = 24576;
317 318
      } else { // 839 sequence
        dftlen = 4096;
319
      }
320 321 322 323
      break;

    default:
      AssertFatal(1==0,"sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu);
324 325
    }
  }
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
  else if (mu==3) {
    if (fp->threequarter_fs) 
      AssertFatal(1==0,"3/4 sampling not supported for numerology %d\n",mu);
    
    if (prach_sequence_length == 0) 
	AssertFatal(1==0,"long prach not supported for numerology %d\n",mu);

    if (fp->N_RB_UL == 32) 
      dftlen=512;
    else if (fp->N_RB_UL == 66) 
      dftlen=1024;
    else 
      AssertFatal(1==0,"N_RB_UL %d not support for numerology %d\n",fp->N_RB_UL,mu);
  }

341 342 343 344 345 346 347 348 349 350

  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;
351

352 353
    if (k==dftlen) k=0;
  }
Agustin's avatar
Agustin committed
354

355 356 357 358 359 360 361 362 363
  #if defined (PRACH_WRITE_OUTPUT_DEBUG)
    LOG_M("prachF.m", "prachF", &prachF[1804], 1024, 1, 1);
    LOG_M("Xu.m", "Xu", Xu, N_ZC, 1, 1);
  #endif

  if (prach_sequence_length == 0) {

    AssertFatal(prach_fmt_id < 4, "Illegal PRACH format %d for sequence length 839\n", prach_fmt_id);

364
    // Ncp here is given in terms of T_s wich is 30.72MHz sampling
365 366 367 368 369 370 371 372 373 374 375 376 377 378
    switch (prach_fmt_id) {
    case 0:
      Ncp = 3168;
      break;
    case 1:
      Ncp = 21024;
      break;
    case 2:
      Ncp = 4688;
      break;
    case 3:
      Ncp = 3168;
      break;
    }
Agustin's avatar
Agustin committed
379

380 381 382
  } else {

    switch (prach_fmt_id) {
383
    case 4: //A1
384 385
      Ncp = 288/(1<<mu);
      break;
386
    case 5: //A2
387 388
      Ncp = 576/(1<<mu);
      break;
389
    case 6: //A3
390 391
      Ncp = 864/(1<<mu);
      break;
392
    case 7: //B1
393
      Ncp = 216/(1<<mu);
Agustin's avatar
Agustin committed
394
    break;
395
    /*
396 397 398 399 400 401
    case 4: //B2
      Ncp = 360/(1<<mu);
      break;
    case 5: //B3
      Ncp = 504/(1<<mu);
      break;
402 403
    */
    case 8: //B4
404 405
      Ncp = 936/(1<<mu);
      break;
406
    case 9: //C0
407 408
      Ncp = 1240/(1<<mu);
      break;
409
    case 10: //C2
410 411 412 413 414 415
      Ncp = 2048/(1<<mu);
      break;
    default:
      AssertFatal(1==0,"Unknown PRACH format ID %d\n", prach_fmt_id);
      break;
    }
Agustin's avatar
Agustin committed
416 417
  }

cig's avatar
cig committed
418 419 420
  #ifdef NR_PRACH_DEBUG
    LOG_D(PHY, "PRACH [UE %d] Ncp %d, dftlen %d \n", Mod_id, Ncp, dftlen);
  #endif
Agustin's avatar
Agustin committed
421

Florian Kaltenberger's avatar
Florian Kaltenberger committed
422 423 424 425
  //actually what we should be checking here is how often the current prach crosses a 0.5ms boundary. I am not quite sure for which paramter set this would be the case, so I will ignore it for now and just check if the prach starts on a 0.5ms boundary
  uint8_t  use_extended_prach_prefix = 0;
  if(fp->numerology_index == 0) {
    if (prachStartSymbol == 0 || prachStartSymbol == 7)
426
      use_extended_prach_prefix = 1;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
427 428 429
  }
  else {
    if (slot%(fp->slots_per_subframe/2)==0 && prachStartSymbol == 0)
430
      use_extended_prach_prefix = 1;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
431
  }
432

433 434 435
  if (mu == 3) {
    switch (fp->samples_per_subframe) {
    case 61440: // 32 PRB case, 61.44 Msps
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
      Ncp<<=1; //to account for 61.44Mbps
      // This is after cyclic prefix 
      prach2 = prach+(Ncp<<1); //times 2 for complex samples
      if (prach_sequence_length == 0)
	AssertFatal(1==0,"no long PRACH for this PRACH size %d\n",fp->N_RB_UL);
      else {
	if (use_extended_prach_prefix) 
          Ncp+=32;  // 16*kappa, kappa=2 for 61.44Msps
	prach2 = prach+(Ncp<<1); //times 2 for complex samples
        if (prach_fmt_id == 4 || prach_fmt_id == 7 || prach_fmt_id == 9) {
          idft(IDFT_512,prachF,prach2,1);
          // here we have |empty | Prach512 |
          if (prach_fmt_id != 9) {
            memmove(prach2+(512<<1),prach2,(512<<2));
            prach_len = (512*2)+Ncp;
          }
          else prach_len = (512*1)+Ncp;
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have |Prefix | Prach512 | Prach512 (if ! 0xc0)  |
        } else if (prach_fmt_id == 5) { // 6x512
          idft(IDFT_512,prachF,prach2,1);
          // here we have |empty | Prach512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have |empty | Prach512 | Prach512| empty512 | empty512 |
          memmove(prach2+(512<<2),prach2,(512<<3));
          // here we have |empty | Prach512 | Prach512| Prach512 | Prach512 |
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have |Prefix | Prach512 |
          prach_len = (512*4)+Ncp;
        } else if (prach_fmt_id == 6) { // 6x512
          idft(IDFT_512,prachF,prach2,1);
          // here we have |empty | Prach512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have |empty | Prach512 | Prach512| empty512 | empty512 | empty512 | empty512
          memmove(prach2+(512<<2),prach2,(512<<3));
          // here we have |empty | Prach512 | Prach512| Prach512 | Prach512 | empty512 | empty512
          memmove(prach2+(512<<3),prach2,(512<<3));
          // here we have |empty | Prach512 | Prach512| Prach512 | Prach512 | Prach512 | Prach512
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have |Prefix | Prach512 |
          prach_len = (512*6)+Ncp;
        } else if (prach_fmt_id == 8) { // 12x512
          idft(IDFT_512,prachF,prach2,1);
          // here we have |empty | Prach512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have |empty | Prach512 | Prach512| empty512 | empty512 | empty512 | empty512
          memmove(prach2+(512<<2),prach2,(512<<3));
          // here we have |empty | Prach512 | Prach512| Prach512 | Prach512 | empty512 | empty512
          memmove(prach2+(512<<3),prach2,(512<<3));
          // here we have |empty | Prach512 | Prach512| Prach512 | Prach512 | Prach512 | Prach512
          memmove(prach2+(512<<1)*6,prach2,(512<<2)*6);
          // here we have |empty | Prach512 | Prach512| Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512| Prach512 | Prach512 | Prach512 | Prach512|
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have |Prefix | Prach512 | Prach512| Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512| Prach512 | Prach512 | Prach512 | Prach512|
          prach_len = (512*12)+Ncp;
	}		
      }
493 494 495
      break;

    case 122880: // 66 PRB case, 122.88 Msps
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
      Ncp<<=2; //to account for 122.88Mbps
      // This is after cyclic prefix 
      prach2 = prach+(Ncp<<1); //times 2 for complex samples
      if (prach_sequence_length == 0)
	AssertFatal(1==0,"no long PRACH for this PRACH size %d\n",fp->N_RB_UL);
      else {
	if (use_extended_prach_prefix) 
          Ncp+=64;  // 16*kappa, kappa=4 for 122.88Msps
	prach2 = prach+(Ncp<<1); //times 2 for complex samples
        if (prach_fmt_id == 4 || prach_fmt_id == 7 || prach_fmt_id == 9) {
          idft(IDFT_1024,prachF,prach2,1);
          // here we have |empty | Prach1024 |
          if (prach_fmt_id != 9) {
            memmove(prach2+(1024<<1),prach2,(1024<<2));
            prach_len = (1024*2)+Ncp;
          }
          else prach_len = (1024*1)+Ncp;
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have |Prefix | Prach1024 | Prach1024 (if ! 0xc0)  |
        } else if (prach_fmt_id == 5) { // 6x1024
          idft(IDFT_1024,prachF,prach2,1);
          // here we have |empty | Prach1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have |empty | Prach1024 | Prach1024| empty1024 | empty1024 |
          memmove(prach2+(1024<<2),prach2,(1024<<3));
          // here we have |empty | Prach1024 | Prach1024| Prach1024 | Prach1024 |
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have |Prefix | Prach1024 |
          prach_len = (1024*4)+Ncp;
        } else if (prach_fmt_id == 6) { // 6x1024
          idft(IDFT_1024,prachF,prach2,1);
          // here we have |empty | Prach1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have |empty | Prach1024 | Prach1024| empty1024 | empty1024 | empty1024 | empty1024
          memmove(prach2+(1024<<2),prach2,(1024<<3));
          // here we have |empty | Prach1024 | Prach1024| Prach1024 | Prach1024 | empty1024 | empty1024
          memmove(prach2+(1024<<3),prach2,(1024<<3));
          // here we have |empty | Prach1024 | Prach1024| Prach1024 | Prach1024 | Prach1024 | Prach1024
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have |Prefix | Prach1024 |
          prach_len = (1024*6)+Ncp;
        } else if (prach_fmt_id == 8) { // 12x1024
          idft(IDFT_1024,prachF,prach2,1);
          // here we have |empty | Prach1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have |empty | Prach1024 | Prach1024| empty1024 | empty1024 | empty1024 | empty1024
          memmove(prach2+(1024<<2),prach2,(1024<<3));
          // here we have |empty | Prach1024 | Prach1024| Prach1024 | Prach1024 | empty1024 | empty1024
          memmove(prach2+(1024<<3),prach2,(1024<<3));
          // here we have |empty | Prach1024 | Prach1024| Prach1024 | Prach1024 | Prach1024 | Prach1024
          memmove(prach2+(1024<<1)*6,prach2,(1024<<2)*6);
          // here we have |empty | Prach1024 | Prach1024| Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024| Prach1024 | Prach1024 | Prach1024 | Prach1024|
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have |Prefix | Prach1024 | Prach1024| Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024| Prach1024 | Prach1024 | Prach1024 | Prach1024|
          prach_len = (1024*12)+Ncp;
	}	
      }
553 554 555 556
      break;

    default:
      AssertFatal(1==0,"sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu);
557
    }
558 559
  } else if (mu == 1) {
    switch (fp->samples_per_subframe) {
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
    case 15360: // full sampling @ 15.36 Ms/s
      Ncp = Ncp/2; // to account for 15.36 Ms/s
      // This is after cyclic prefix
      prach2 = prach+(2*Ncp); // times 2 for complex samples
      if (prach_sequence_length == 0){
        if (prach_fmt_id == 0) { // 24576 samples @ 30.72 Ms/s, 12288 samples @ 15.36 Ms/s
          idft(IDFT_12288,prachF,prach2,1);
          // here we have | empty  | Prach12288 |
          memmove(prach,prach+(12288<<1),(Ncp<<2));
          // here we have | Prefix | Prach12288 |
          prach_len = 12288+Ncp;
        } else if (prach_fmt_id == 1) { // 24576 samples @ 30.72 Ms/s, 12288 samples @ 15.36 Ms/s
          idft(IDFT_12288,prachF,prach2,1);
          // here we have | empty  | Prach12288 | empty12288 |
          memmove(prach2+(12288<<1),prach2,(12288<<2));
          // here we have | empty  | Prach12288 | Prach12288 |
          memmove(prach,prach+(12288<<2),(Ncp<<2));
          // here we have | Prefix | Prach12288 | Prach12288 |
          prach_len = (12288*2)+Ncp;
        } else if (prach_fmt_id == 2) { // 24576 samples @ 30.72 Ms/s, 12288 samples @ 15.36 Ms/s
          idft(IDFT_12288,prachF,prach2,1);
          // here we have | empty  | Prach12288 | empty12288 | empty12288 | empty12288 |
          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<<2));
          // here we have | Prefix | Prach12288 | Prach12288 | Prach12288 | Prach12288 |
          prach_len = (12288*4)+Ncp;
        } else if (prach_fmt_id == 3) { // 6144 samples @ 30.72 Ms/s, 3072 samples @ 15.36 Ms/s
          idft(IDFT_3072,prachF,prach2,1);
          // here we have | empty  | Prach3072 | empty3072 | empty3072 | empty3072 |
          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<<3),(Ncp<<2));
          // here we have | Prefix | Prach3072 | Prach3072 | Prach3072 | Prach3072 |
          prach_len = (3072*4)+Ncp;
        }
      } else { // short PRACH sequence
	if (use_extended_prach_prefix)
	  Ncp += 8; // 16*kappa, kappa=0.5 for 15.36 Ms/s
	prach2 = prach+(2*Ncp); // times 2 for complex samples
        if (prach_fmt_id == 9) {
          idft(IDFT_512,prachF,prach2,1);
          // here we have | empty  | Prach512 |
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have | Prefix | Prach512 |
          prach_len = (512*1)+Ncp;
        } else if (prach_fmt_id == 4 || prach_fmt_id == 7) {
          idft(IDFT_512,prachF,prach2,1);
          // here we have | empty  | Prach512 | empty512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have | empty  | Prach512 | Prach512 |
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have | Prefix | Prach512 | Prach512 |
          prach_len = (512*2)+Ncp;
        } else if (prach_fmt_id == 5) { // 4x512
          idft(IDFT_512,prachF,prach2,1);
          // here we have | empty  | Prach512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have | empty  | Prach512 | Prach512 | empty512 | empty512 |
          memmove(prach2+(512<<2),prach2,(512<<3));
          // here we have | empty  | Prach512 | Prach512 | Prach512 | Prach512 |
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have | Prefix | Prach512 | Prach512 | Prach512 | Prach512 |
          prach_len = (512*4)+Ncp;
        } else if (prach_fmt_id == 6) { // 6x512
          idft(IDFT_512,prachF,prach2,1);
          // here we have | empty  | Prach512 | empty512 | empty512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have | empty  | Prach512 | Prach512 | empty512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<2),prach2,(512<<3));
          // here we have | empty  | Prach512 | Prach512 | Prach512 | Prach512 | empty512 | empty512 |
          memmove(prach2+(512<<3),prach2,(512<<3));
          // here we have | empty  | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 |
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have | Prefix | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 |
          prach_len = (512*6)+Ncp;
        } else if (prach_fmt_id == 8) { // 12x512
          idft(IDFT_512,prachF,prach2,1);
          // here we have | empty  | Prach512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<1),prach2,(512<<2));
          // here we have | empty  | Prach512 | Prach512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<2),prach2,(512<<3));
          // here we have | empty  | Prach512 | Prach512 | Prach512 | Prach512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<3),prach2,(512<<3));
          // here we have | empty  | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | empty512 | empty512 | empty512 | empty512 | empty512 | empty512 |
          memmove(prach2+(512<<1)*6,prach2,(512<<2)*6);
          // here we have | empty  | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 |
          memmove(prach,prach+(512<<1),(Ncp<<2));
          // here we have | Prefix | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 | Prach512 |
          prach_len = (512*12)+Ncp;
        }
      }
      break;

    case 30720: // full sampling @ 30.72 Ms/s
      Ncp = Ncp*1; // to account for 30.72 Ms/s
      // This is after cyclic prefix
      prach2 = prach+(2*Ncp); // times 2 for complex samples
      if (prach_sequence_length == 0){
        if (prach_fmt_id == 0) { // 24576 samples @ 30.72 Ms/s
          idft(IDFT_24576,prachF,prach2,1);
          // here we have | empty  | Prach24576 |
          memmove(prach,prach+(24576<<1),(Ncp<<2));
          // here we have | Prefix | Prach24576 |
          prach_len = 24576+Ncp;
        } else if (prach_fmt_id == 1) { // 24576 samples @ 30.72 Ms/s
          idft(IDFT_24576,prachF,prach2,1);
          // here we have | empty  | Prach24576 | empty24576 |
          memmove(prach2+(24576<<1),prach2,(24576<<2));
          // here we have | empty  | Prach24576 | Prach24576 |
          memmove(prach,prach+(24576<<2),(Ncp<<2));
          // here we have | Prefix | Prach24576 | Prach24576 |
          prach_len = (24576*2)+Ncp;
        } else if (prach_fmt_id == 2) { // 24576 samples @ 30.72 Ms/s
          idft(IDFT_24576,prachF,prach2,1);
          // here we have | empty  | Prach24576 | empty24576 | empty24576 | empty24576 |
          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 |
          memmove(prach,prach+(24576<<3),(Ncp<<2));
          // here we have | Prefix | Prach24576 | Prach24576 | Prach24576 | Prach24576 |
          prach_len = (24576*4)+Ncp;
        } else if (prach_fmt_id == 3) { // 6144 samples @ 30.72 Ms/s
          idft(IDFT_6144,prachF,prach2,1);
          // here we have | empty  | Prach6144 | empty6144 | empty6144 | empty6144 |
          memmove(prach2+(6144<<1),prach2,(6144<<2));
          // here we have | empty  | Prach6144 | Prach6144 | empty6144 | empty6144 |
          memmove(prach2+(6144<<2),prach2,(6144<<3));
          // here we have | empty  | Prach6144 | Prach6144 | Prach6144 | Prach6144 |
          memmove(prach,prach+(6144<<3),(Ncp<<2));
          // here we have | Prefix | Prach6144 | Prach6144 | Prach6144 | Prach6144 |
          prach_len = (6144*4)+Ncp;
        }
      } else { // short PRACH sequence
	if (use_extended_prach_prefix)
	  Ncp += 16; // 16*kappa, kappa=1 for 30.72Msps
	prach2 = prach+(2*Ncp); // times 2 for complex samples
        if (prach_fmt_id == 9) {
          idft(IDFT_1024,prachF,prach2,1);
          // here we have | empty  | Prach1024 |
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have | Prefix | Prach1024 |
          prach_len = (1024*1)+Ncp;
        } else if (prach_fmt_id == 4 || prach_fmt_id == 7) {
          idft(IDFT_1024,prachF,prach2,1);
          // here we have | empty  | Prach1024 | empty1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have | empty  | Prach1024 | Prach1024 |
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have | Prefix | Prach1024 | Prach1024 |
          prach_len = (1024*2)+Ncp;
        } else if (prach_fmt_id == 5) { // 4x1024
          idft(IDFT_1024,prachF,prach2,1);
          // here we have | empty  | Prach1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have | empty  | Prach1024 | Prach1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<2),prach2,(1024<<3));
          // here we have | empty  | Prach1024 | Prach1024 | Prach1024 | Prach1024 |
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have | Prefix | Prach1024 | Prach1024 | Prach1024 | Prach1024 |
          prach_len = (1024*4)+Ncp;
        } else if (prach_fmt_id == 6) { // 6x1024
          idft(IDFT_1024,prachF,prach2,1);
          // here we have | empty  | Prach1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have | empty  | Prach1024 | Prach1024 | empty1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<2),prach2,(1024<<3));
          // here we have | empty  | Prach1024 | Prach1024 | Prach1024 | Prach1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<3),prach2,(1024<<3));
          // here we have | empty  | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 |
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have | Prefix | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 |
          prach_len = (1024*6)+Ncp;
        } else if (prach_fmt_id == 8) { // 12x1024
          idft(IDFT_1024,prachF,prach2,1);
          // here we have | empty  | Prach1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<1),prach2,(1024<<2));
          // here we have | empty  | Prach1024 | Prach1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<2),prach2,(1024<<3));
          // here we have | empty  | Prach1024 | Prach1024 | Prach1024 | Prach1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<3),prach2,(1024<<3));
          // here we have | empty  | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 | empty1024 |
          memmove(prach2+(1024<<1)*6,prach2,(1024<<2)*6);
          // here we have | empty  | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 |
          memmove(prach,prach+(1024<<1),(Ncp<<2));
          // here we have | Prefix | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 | Prach1024 |
          prach_len = (1024*12)+Ncp;
        }
      }
      break;

756 757
    case 61440: // full sampling @ 61.44 Ms/s
      Ncp = Ncp*2; // to account for 61.44 Ms/s
758 759
      // This is after cyclic prefix 
      prach2 = prach+(Ncp<<1); //times 2 for complex samples
760 761
      if (prach_sequence_length == 0){
        if (prach_fmt_id == 0) { //24576 samples @ 30.72 Ms/s, 49152 samples @ 61.44 Ms/s
762
          idft(IDFT_49152,prachF,prach2,1);
763 764 765 766 767
          // here we have |empty | Prach49152|
          memmove(prach,prach+(49152<<1),(Ncp<<2));
          // here we have |Prefix | Prach49152|
          prach_len = 49152+Ncp;
        } else if (prach_fmt_id == 1) { //24576 samples @ 30.72 Ms/s, 49152 samples @ 61.44 Ms/s
768
          idft(IDFT_49152,prachF,prach2,1);
769 770 771 772 773 774
          memmove(prach2+(49152<<1),prach2,(49152<<2));
          // here we have |empty | Prach49152 | Prach49152|
          memmove(prach,prach+(49152<<2),(Ncp<<2));
          // here we have |Prefix | Prach49152 | Prach49152|
          prach_len = (49152*2)+Ncp;
        } else if (prach_fmt_id == 2) { //24576 samples @ 30.72 Ms/s, 49152 samples @ 61.44 Ms/s
775
          idft(IDFT_49152,prachF,prach2,1);
776 777 778 779 780 781 782
          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<<2));
          // here we have |Prefix | Prach49152 | Prach49152| Prach49152 | Prach49152
          prach_len = (49152*4)+Ncp;
783
        } else if (prach_fmt_id == 3) { // 6144 samples @ 30.72 Ms/s, 12288 samples @ 61.44 Ms/s
784
          idft(IDFT_12288,prachF,prach2,1);
785 786 787 788 789 790 791 792 793
          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<<2));
          // here we have |Prefix | Prach12288 | Prach12288| Prach12288 | Prach12288
          prach_len = (12288*4)+Ncp;
        }
      } else { // short PRACH sequence
794 795 796
	if (use_extended_prach_prefix) 
	  Ncp+=32; // 16*kappa, kappa=2 for 61.44Msps 
	prach2 = prach+(Ncp<<1); //times 2 for complex samples
797
        if (prach_fmt_id == 4 || prach_fmt_id == 7 || prach_fmt_id == 9) {
798
          idft(IDFT_2048,prachF,prach2,1);
799
          // here we have |empty | Prach2048 |
800
          if (prach_fmt_id != 9) {
801 802 803 804 805 806
            memmove(prach2+(2048<<1),prach2,(2048<<2));
            prach_len = (2048*2)+Ncp;
          }
          else prach_len = (2048*1)+Ncp;
          memmove(prach,prach+(2048<<1),(Ncp<<2));
          // here we have |Prefix | Prach2048 | Prach2048 (if ! 0xc0)  |
807
        } else if (prach_fmt_id == 5) { // 6x2048
808
          idft(IDFT_2048,prachF,prach2,1);
809 810 811 812 813 814 815 816
          // 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;
817
        } else if (prach_fmt_id == 6) { // 6x2048
818
          idft(IDFT_2048,prachF,prach2,1);
819 820 821 822 823 824 825 826 827 828
          // 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(prach,prach+(2048<<1),(Ncp<<2));
          // here we have |Prefix | Prach2048 |
          prach_len = (2048*6)+Ncp;
829
        } else if (prach_fmt_id == 8) { // 12x2048
830
          idft(IDFT_2048,prachF,prach2,1);
831 832 833 834 835 836 837 838 839 840 841 842 843 844
          // 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|
          prach_len = (2048*12)+Ncp;
        }
      }
845 846 847
      break;

    case 46080: // threequarter sampling @ 46.08 Ms/s
848 849
      Ncp = (Ncp*3)/2;
      prach2 = prach+(Ncp<<1);
850 851
      if (prach_sequence_length == 0){
        if (prach_fmt_id == 0) {
852
          idft(IDFT_36864,prachF,prach2,1);
853 854 855 856 857
          // here we have |empty | Prach73728|
          memmove(prach,prach+(36864<<1),(Ncp<<2));
          // here we have |Prefix | Prach73728|
          prach_len = (36864*1)+Ncp;
        } else if (prach_fmt_id == 1) {
858
          idft(IDFT_36864,prachF,prach2,1);
859 860 861 862 863 864
          memmove(prach2+(36864<<1),prach2,(36864<<2));
          // here we have |empty | Prach73728 | Prach73728|
          memmove(prach,prach+(36864<<2),(Ncp<<2));
          // here we have |Prefix | Prach73728 | Prach73728|
          prach_len = (36864*2)+Ncp;
        } else if (prach_fmt_id == 2) {
865
          idft(IDFT_36864,prachF,prach2,1);
866 867 868 869 870 871 872 873
          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
          memmove(prach,prach+(36864<<3),(Ncp<<2));
          // here we have |Prefix | Prach73728 | Prach73728| Prach73728 | Prach73728
          prach_len = (36864*4)+Ncp;
        } else if (prach_fmt_id == 3) {
874
          idft(IDFT_9216,prachF,prach2,1);
875 876 877 878 879 880 881 882 883
          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
          memmove(prach,prach+(9216<<3),(Ncp<<2));
          // here we have |Prefix | Prach9216 | Prach9216| Prach9216 | Prach9216
          prach_len = (9216*4)+Ncp;
        }
      } else { // short sequence
884 885 886
	if (use_extended_prach_prefix) 
	  Ncp+=24; // 16*kappa, kappa=1.5 for 46.08Msps 
	prach2 = prach+(Ncp<<1); //times 2 for complex samples
887
        if (prach_fmt_id == 4 || prach_fmt_id == 7 || prach_fmt_id == 9) {
888
          idft(IDFT_1536,prachF,prach2,1);
889
          // here we have |empty | Prach1536 |
890
          if (prach_fmt_id != 9) {
891 892 893 894 895 896 897
            memmove(prach2+(1536<<1),prach2,(1536<<2));
            prach_len = (1536*2)+Ncp;
          }	else prach_len = (1536*1)+Ncp;

          memmove(prach,prach+(1536<<1),(Ncp<<2));
          // here we have |Prefix | Prach1536 | Prach1536 (if ! 0xc0) |

898
        } else if (prach_fmt_id == 5) { // 6x1536
899
          idft(IDFT_1536,prachF,prach2,1);
900 901 902 903 904 905 906 907
          // 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;
908
        } else if (prach_fmt_id == 6) { // 6x1536
909
          idft(IDFT_1536,prachF,prach2,1);
910 911 912 913 914 915 916 917 918 919
          // 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(prach,prach+(1536<<1),(Ncp<<2));
          // here we have |Prefix | Prach1536 |
          prach_len = (1536*6)+Ncp;
920
        } else if (prach_fmt_id == 8) { // 12x1536
921
          idft(IDFT_1536,prachF,prach2,1);
922 923 924 925 926 927 928 929 930 931 932 933 934
          // 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|
          prach_len = (1536*12)+Ncp;
        }
935
      }
936 937 938
      break;

    case 122880: // full sampling @ 122.88 Ms/s
939 940 941
      Ncp<<=2; //to account for 122.88Mbps
      // This is after cyclic prefix
      prach2 = prach+(Ncp<<1); //times 2 for complex samples
942 943
      if (prach_sequence_length == 0){
        if (prach_fmt_id == 0) { //24576 samples @ 30.72 Ms/s, 98304 samples @ 122.88 Ms/s
944
          idft(IDFT_98304,prachF,prach2,1);
945 946 947 948 949
          // here we have |empty | Prach98304|
          memmove(prach,prach+(98304<<1),(Ncp<<2));
          // here we have |Prefix | Prach98304|
          prach_len = (98304*1)+Ncp;
        } else if (prach_fmt_id == 1) {
950
          idft(IDFT_98304,prachF,prach2,1);
951 952 953 954 955 956
          memmove(prach2+(98304<<1),prach2,(98304<<2));
          // here we have |empty | Prach98304 | Prach98304|
          memmove(prach,prach+(98304<<2),(Ncp<<2));
          // here we have |Prefix | Prach98304 | Prach98304|
          prach_len = (98304*2)+Ncp;
        } else if (prach_fmt_id == 2) {
957
          idft(IDFT_98304,prachF,prach2,1);
958 959 960 961 962 963 964 965
          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
          memmove(prach,prach+(98304<<3),(Ncp<<2));
          // here we have |Prefix | Prach98304 | Prach98304| Prach98304 | Prach98304
          prach_len = (98304*4)+Ncp;
        } else if (prach_fmt_id == 3) { // 4x6144, Ncp 3168
966
          idft(IDFT_24576,prachF,prach2,1);
967 968 969 970 971 972 973 974 975
          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
          memmove(prach,prach+(24576<<3),(Ncp<<2));
          // here we have |Prefix | Prach24576 | Prach24576| Prach24576 | Prach24576
          prach_len = (24576*4)+Ncp;
        }
      } else { // short sequence
976 977 978
	if (use_extended_prach_prefix) 
          Ncp+=64; // 16*kappa, kappa=4 for 122.88Msps
	prach2 = prach+(Ncp<<1); //times 2 for complex samples
979
        if (prach_fmt_id == 4 || prach_fmt_id == 7 || prach_fmt_id == 9) {
980
          idft(IDFT_4096,prachF,prach2,1);
981
          // here we have |empty | Prach4096 |
982
          if (prach_fmt_id != 9) {
983 984 985 986 987
            memmove(prach2+(4096<<1),prach2,(4096<<2));
            prach_len = (4096*2)+Ncp; 
          }	else 	prach_len = (4096*1)+Ncp;
          memmove(prach,prach+(4096<<1),(Ncp<<2));
          // here we have |Prefix | Prach4096 | Prach4096 (if ! 0xc0) |
988
        } else if (prach_fmt_id == 5) { // 4x4096
989
          idft(IDFT_4096,prachF,prach2,1);
990 991 992 993 994 995 996 997
          // 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;
998
        } else if (prach_fmt_id == 6) { // 6x4096
999
          idft(IDFT_4096,prachF,prach2,1);
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
          // 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(prach,prach+(4096<<1),(Ncp<<2));
          // here we have |Prefix | Prach4096 |
          prach_len = (4096*6)+Ncp;
1010
        } else if (prach_fmt_id == 8) { // 12x4096
1011
          idft(IDFT_4096,prachF,prach2,1);
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
          // 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|
          prach_len = (4096*12)+Ncp;
        }
      }
1026 1027 1028
      break;

    case 92160: // three quarter sampling @ 92.16 Ms/s
1029 1030
      Ncp = (Ncp*3); //to account for 92.16 Msps
      prach2 = prach+(Ncp<<1); //times 2 for complex samples
1031 1032
      if (prach_sequence_length == 0){
        if (prach_fmt_id == 0) {
1033
          idft(IDFT_73728,prachF,prach2,1);
1034 1035 1036 1037 1038
          // here we have |empty | Prach73728|
          memmove(prach,prach+(73728<<1),(Ncp<<2));
          // here we have |Prefix | Prach73728|
          prach_len = (73728*1)+Ncp;
        } else if (prach_fmt_id == 1) {
1039
          idft(IDFT_73728,prachF,prach2,1);
1040 1041 1042 1043 1044 1045
          memmove(prach2+(73728<<1),prach2,(73728<<2));
          // here we have |empty | Prach73728 | Prach73728|
          memmove(prach,prach+(73728<<2),(Ncp<<2));
          // here we have |Prefix | Prach73728 | Prach73728|
          prach_len = (73728*2)+Ncp;
        } if (prach_fmt_id == 2) {
1046
          idft(IDFT_73728,prachF,prach2,1);
1047 1048 1049 1050 1051 1052 1053 1054
          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<<2));
          // here we have |Prefix | Prach73728 | Prach73728| Prach73728 | Prach73728
          prach_len = (73728*4)+Ncp;
        } else if (prach_fmt_id == 3) {
1055
          idft(IDFT_18432,prachF,prach2,1);
1056 1057 1058 1059 1060 1061 1062 1063 1064
          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<<2));
          // here we have |Prefix | Prach18432 | Prach18432| Prach18432 | Prach18432
          prach_len = (18432*4)+Ncp;
        }
      } else { // short sequence
1065 1066 1067 1068
	if (use_extended_prach_prefix) 
          Ncp+=48; // 16*kappa, kappa=3 for 92.16Msps 
	prach2 = prach+(Ncp<<1); //times 2 for complex samples
	if (prach_fmt_id == 4 || prach_fmt_id == 7 || prach_fmt_id == 9) {
1069
          idft(IDFT_3072,prachF,prach2,1);
1070
          // here we have |empty | Prach3072 |
1071
          if (prach_fmt_id != 9) {
1072 1073 1074
            memmove(prach2+(3072<<1),prach2,(3072<<2));
            prach_len = (3072*2)+Ncp;
          } else 	  prach_len = (3072*1)+Ncp;
1075 1076
	  memmove(prach,prach+(3072<<1),(Ncp<<2));
	  // here we have |Prefix | Prach3072 | Prach3072 (if ! 0xc0) |
1077
        } else if (prach_fmt_id == 6) { // 6x3072
1078
          idft(IDFT_3072,prachF,prach2,1);
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
          // 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(prach,prach+(3072<<1),(Ncp<<2));
          // here we have |Prefix | Prach3072 |
          prach_len = (3072*6)+Ncp;
1089
        } else if (prach_fmt_id == 5) { // 4x3072
1090
          idft(IDFT_3072,prachF,prach2,1);
1091 1092 1093 1094 1095 1096 1097 1098 1099
          // 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;
        } else if (prach_fmt_id == 6) { // 12x3072
1100
          idft(IDFT_3072,prachF,prach2,1);
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
          // 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|
          prach_len = (3072*12)+Ncp;
        }
1114
      }
1115 1116 1117 1118
      break;

    default:
      AssertFatal(1==0,"sample rate %f MHz not supported for numerology %d\n", fp->samples_per_subframe / 1000.0, mu);
Agustin's avatar
Agustin committed
1119 1120 1121
    }
  }

1122
  #ifdef NR_PRACH_DEBUG
1123
    LOG_I(PHY, "PRACH [UE %d] N_RB_UL %d prach_start %d, prach_len %d\n", Mod_id,
1124 1125
      fp->N_RB_UL,
      prach_start,
1126
      prach_len);
1127 1128
  #endif

1129 1130 1131 1132
  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];
  }
Agustin's avatar
Agustin committed
1133

1134 1135 1136 1137 1138
  //printf("----------------------\n");
  //for(int ii = prach_start; ii<2*(prach_start + prach_len); ii++){
  //  printf("PRACH rx data[%d] = %d\n", ii, ue->common_vars.txdata[0][ii]);
  //}
  //printf(" \n");
Agustin's avatar
Agustin committed
1139

cig's avatar
cig committed
1140
  #ifdef PRACH_WRITE_OUTPUT_DEBUG
1141 1142 1143
    LOG_M("prach_tx0.m", "prachtx0", prach+(Ncp<<1), prach_len-Ncp, 1, 1);
    LOG_M("Prach_txsig.m","txs",(int16_t*)(&ue->common_vars.txdata[0][prach_start]), 2*(prach_start+prach_len), 1, 1)
  #endif
Agustin's avatar
Agustin committed
1144

1145
  return signal_energy((int*)prach, 256);
Agustin's avatar
Agustin committed
1146 1147
}