prachsim.c 25.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * 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
 */

#include <string.h>
#include <math.h>
#include <unistd.h>
25
#include <pthread.h>
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

#include "common/config/config_userapi.h"
#include "common/utils/LOG/log.h"
#include "common/ran_context.h" 

#include "SIMULATION/TOOLS/sim.h"
#include "SIMULATION/RF/rf.h"
#include "PHY/types.h"
#include "PHY/defs_gNB.h"
#include "PHY/defs_nr_UE.h"
#include "SCHED_NR/sched_nr.h"
#include "SCHED_NR_UE/phy_frame_config_nr.h"
#include "PHY/phy_vars_nr_ue.h"
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
#include "PHY/MODULATION/modulation_eNB.h"
#include "PHY/MODULATION/modulation_UE.h"
#include "PHY/INIT/phy_init.h"
cig's avatar
cig committed
43
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
44
#include "PHY/NR_TRANSPORT/nr_transport_common_proto.h"
45
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
46
#include "nr_unitary_defs.h"
47 48
#include "OCG_vars.h"

49 50
#define NR_PRACH_DEBUG 1
#define PRACH_WRITE_OUTPUT_DEBUG 1
51

52 53 54 55
unsigned char NB_eNB_INST=0;
LCHAN_DESC DCCH_LCHAN_DESC,DTCH_DL_LCHAN_DESC,DTCH_UL_LCHAN_DESC;
rlc_info_t Rlc_info_um,Rlc_info_am_config;

56 57 58
PHY_VARS_gNB *gNB;
PHY_VARS_NR_UE *UE;
RAN_CONTEXT_t RC;
59
RU_t *ru;
60 61
double cpuf;
extern uint16_t prach_root_sequence_map0_3[838];
62
uint16_t NB_UE_INST=1;
63
openair0_config_t openair0_cfg[MAX_CARDS];
cig's avatar
cig committed
64
uint8_t nfapi_mode=0;
65
int sl_ahead = 0;
66

67
//void dump_nr_prach_config(NR_DL_FRAME_PARMS *frame_parms,uint8_t subframe);
68

69 70 71
/* temporary dummy implem of get_softmodem_optmask, till basic simulators implemented as device */
uint64_t get_softmodem_optmask(void) {return 0;}
softmodem_params_t *get_softmodem_params(void) {return 0;}
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
void
rrc_data_ind(
  const protocol_ctxt_t *const ctxt_pP,
  const rb_id_t                Srb_id,
  const sdu_size_t             sdu_sizeP,
  const uint8_t   *const       buffer_pP
)
{
}

int
gtpv1u_create_s1u_tunnel(
  const instance_t                              instanceP,
  const gtpv1u_enb_create_tunnel_req_t *const  create_tunnel_req_pP,
  gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP
) {
  return 0;
}
91

92 93 94 95 96 97 98 99
int
rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(
  const protocol_ctxt_t *const ctxt_pP,
  const gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP,
  uint8_t                         *inde_list
) {
  return 0;
}
100

101
int8_t nr_mac_rrc_data_ind_ue(const module_id_t module_id, const int CC_id, const uint8_t gNB_index, const int8_t channel, const uint8_t* pduP, const sdu_size_t pdu_len) {return 0;}
102

103
// Dummy function to avoid linking error at compilation of nr-prachsim
104 105 106 107 108
int is_x2ap_enabled(void)
{
  return 0;
}

109
int main(int argc, char **argv){
110 111 112

  char c;

113 114 115 116
  double sigma2, sigma2_dB = 0, SNR, snr0 = -2.0, snr1 = 0.0, ue_speed0 = 0.0, ue_speed1 = 0.0;
  double **s_re, **s_im, **r_re, **r_im, iqim = 0.0, delay_avg = 0, ue_speed = 0, fs, bw;
  int i, aa, aarx, **txdata, trial, n_frames = 1, prach_start, rx_prach_start; //, ntrials=1;
  int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0, loglvl = OAILOG_INFO, numRA = 0, prachStartSymbol = 0;
117
  uint8_t snr1set = 0, ue_speed1set = 0, transmission_mode = 1, n_tx = 1, n_rx = 1, awgn_flag = 0, msg1_frequencystart = 0, num_prach_fd_occasions = 1, prach_format=0;
118
  uint8_t frame = 1, subframe = 9, slot=19, slot_gNB=19, config_index = 98, prach_sequence_length = 1, num_root_sequences = 16, restrictedSetConfig = 0, N_dur, N_t_slot, start_symbol;
119 120 121
  uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format, format0, format1;
  uint32_t tx_lev = 10000, prach_errors = 0, samp_count; //,tx_lev_dB;
  uint64_t SSB_positions = 0x01, absoluteFrequencyPointA = 640000;
122 123 124 125
  uint16_t RA_sfn_index;
  uint8_t N_RA_slot;
  uint8_t config_period;
  int prachOccasion = 0;
126
  double DS_TDL = .03;
127 128 129 130

  //  int8_t interf1=-19,interf2=-19;
  //  uint8_t abstraction_flag=0,calibration_flag=0;
  //  double prach_sinr;
131 132
  //  uint32_t nsymb;
  //  uint16_t preamble_max, preamble_energy_max;
133 134 135
  FILE *input_fd=NULL;
  char* input_file=NULL;
  int n_bytes=0;
136

137
  NR_DL_FRAME_PARMS *frame_parms;
138
  NR_PRACH_RESOURCES_t prach_resources;
139 140 141 142
  nfapi_nr_prach_config_t *prach_config;
  nfapi_nr_prach_pdu_t *prach_pdu;
  fapi_nr_prach_config_t *ue_prach_config;
  fapi_nr_ul_config_prach_pdu *ue_prach_pdu;
143

144 145
  channel_desc_t *UE2gNB;
  SCM_t channel_model = Rayleigh1;
146 147
  cpuf = get_cpu_freq_GHz();

148
  if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) {
149 150 151 152 153
    exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
  }

  randominit(0);

154
  while ((c = getopt (argc, argv, "hHaA:Cc:r:p:g:m:n:s:S:t:x:y:v:V:z:N:F:d:Z:L:R:E")) != -1) {
155 156 157 158 159 160 161 162
    switch (c) {
    case 'a':
      printf("Running AWGN simulation\n");
      awgn_flag = 1;
      /* ntrials not used later, no need to set */
      //ntrials=1;
      break;

163 164 165 166
    case 'c':
      config_index = atoi(optarg);
      break;

167 168 169 170
    case 'r':
      msg1_frequencystart = atoi(optarg);
      break;

171 172 173 174 175 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
    case 'd':
      delay = atoi(optarg);
      break;

    case 'g':
      switch((char)*optarg) {
      case 'A':
        channel_model=SCM_A;
        break;

      case 'B':
        channel_model=SCM_B;
        break;

      case 'C':
        channel_model=SCM_C;
        break;

      case 'D':
        channel_model=SCM_D;
        break;

      case 'E':
        channel_model=EPA;
        break;

      case 'F':
        channel_model=EVA;
        break;

      case 'G':
        channel_model=ETU;
        break;

      case 'H':
        channel_model=Rayleigh8;
207
        break;
208 209 210

      case 'I':
        channel_model=Rayleigh1;
211
        break;
212 213 214

      case 'J':
        channel_model=Rayleigh1_corr;
215
        break;
216 217 218

      case 'K':
        channel_model=Rayleigh1_anticorr;
219
        break;
220 221 222

      case 'L':
        channel_model=Rice8;
223
        break;
224 225 226

      case 'M':
        channel_model=Rice1;
227
        break;
228 229 230 231 232 233

      case 'N':
        channel_model=Rayleigh1_800;
        break;

      default:
234
        printf("Unsupported channel model!\n");
235 236 237 238 239 240 241 242 243
        exit(-1);
      }

      break;

    case 'E':
      threequarter_fs=1;
      break;

244 245 246 247
    case 'm':
      mu = atoi(optarg);
      break;

248 249 250 251 252 253
    case 'n':
      n_frames = atoi(optarg);
      break;

    case 's':
      snr0 = atof(optarg);
254
      printf("Setting SNR0 to %f\n",snr0);
255 256 257 258 259
      break;

    case 'S':
      snr1 = atof(optarg);
      snr1set=1;
260
      printf("Setting SNR1 to %f\n",snr1);
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
      break;

    case 'p':
      preamble_tx=atoi(optarg);
      break;

    case 'v':
      ue_speed0 = atoi(optarg);
      break;

    case 'V':
      ue_speed1 = atoi(optarg);
      ue_speed1set = 1;
      break;

    case 'Z':
      NCS_config = atoi(optarg);

      if ((NCS_config > 15) || (NCS_config < 0))
        printf("Illegal NCS_config %d, (should be 0-15)\n",NCS_config);

      break;

    case 'H':
      printf("High-Speed Flag enabled\n");
286
      restrictedSetConfig = 1;
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
      break;

    case 'L':
      rootSequenceIndex = atoi(optarg);

      if ((rootSequenceIndex < 0) || (rootSequenceIndex > 837))
        printf("Illegal rootSequenceNumber %d, (should be 0-837)\n",rootSequenceIndex);

      break;

    case 'x':
      transmission_mode=atoi(optarg);

      if ((transmission_mode!=1) &&
          (transmission_mode!=2) &&
          (transmission_mode!=6)) {
303
        printf("Unsupported transmission mode %d\n",transmission_mode);
304 305 306 307 308 309 310 311 312
        exit(-1);
      }

      break;

    case 'y':
      n_tx=atoi(optarg);

      if ((n_tx==0) || (n_tx>2)) {
313
        printf("Unsupported number of tx antennas %d\n",n_tx);
314 315 316 317 318 319 320 321 322
        exit(-1);
      }

      break;

    case 'z':
      n_rx=atoi(optarg);

      if ((n_rx==0) || (n_rx>2)) {
323
        printf("Unsupported number of rx antennas %d\n",n_rx);
324 325 326 327 328 329 330 331 332 333 334 335 336 337
        exit(-1);
      }

      break;

    case 'N':
      Nid_cell = atoi(optarg);
      break;

    case 'R':
      N_RB_UL = atoi(optarg);
      break;

    case 'F':
338 339 340 341 342 343 344 345
      input_fd = fopen(optarg,"r");
      input_file = optarg;
      
      if (input_fd==NULL) {
	printf("Problem with filename %s\n",optarg);
	exit(-1);
      }
      
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
      break;

    default:
    case 'h':
      printf("%s -h(elp) -a(wgn on) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -s snr0 -S snr1 -x transmission_mode -y TXant -z RXant -i Intefrence0 -j Interference1 -A interpolation_file -C(alibration offset dB) -N CellId\n",
             argv[0]);
      printf("-h This message\n");
      printf("-a Use AWGN channel and not multipath\n");
      printf("-n Number of frames to simulate\n");
      printf("-s Starting SNR, runs from SNR0 to SNR0 + 5 dB.  If n_frames is 1 then just SNR is simulated\n");
      printf("-S Ending SNR, runs from SNR0 to SNR1\n");
      printf("-g [A,B,C,D,E,F,G,I,N] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) or Rayleigh1 (I) or Rayleigh1_800 (N) models (ignores delay spread and Ricean factor)\n");
      printf("-z Number of RX antennas used in gNB\n");
      printf("-N Nid_cell\n");
      printf("-O oversampling factor (1,2,4,8,16)\n");
      //    printf("-f PRACH format (0=1,1=2,2=3,3=4)\n");
      printf("-d Channel delay \n");
      printf("-v Starting UE velocity in km/h, runs from 'v' to 'v+50km/h'. If n_frames is 1 just 'v' is simulated \n");
      printf("-V Ending UE velocity in km/h, runs from 'v' to 'V'");
      printf("-L rootSequenceIndex (0-837)\n");
      printf("-Z NCS_config (ZeroCorrelationZone) (0-15)\n");
      printf("-H Run with High-Speed Flag enabled \n");
      printf("-R Number of PRB (6,15,25,50,75,100)\n");
      printf("-F Input filename (.txt format) for RX conformance testing\n");
      exit (-1);
      break;
    }
  }

375
  // Configure log
376 377 378 379 380
  logInit();
  set_glog(loglvl);
  T_stdout = 1;
  SET_LOG_DEBUG(PRACH); 

381
  // Configure gNB and RU
382 383 384
  RC.gNB = (PHY_VARS_gNB**) malloc(2*sizeof(PHY_VARS_gNB *));
  RC.gNB[0] = malloc(sizeof(PHY_VARS_gNB));
  memset(RC.gNB[0],0,sizeof(PHY_VARS_gNB));
385 386 387 388 389 390

  RC.ru = (RU_t**) malloc(2*sizeof(RU_t *));
  RC.ru[0] = (RU_t*) malloc(sizeof(RU_t ));
  memset(RC.ru[0],0,sizeof(RU_t));
  RC.nb_RU = 1;

391 392 393 394 395 396
  gNB          = RC.gNB[0];
  ru           = RC.ru[0];
  frame_parms  = &gNB->frame_parms;
  prach_config = &gNB->gNB_config.prach_config;
  prach_pdu    = &gNB->prach_vars.list[0].pdu;
  frame_parms  = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
397 398 399 400 401 402

  s_re = malloc(2*sizeof(double*));
  s_im = malloc(2*sizeof(double*));
  r_re = malloc(2*sizeof(double*));
  r_im = malloc(2*sizeof(double*));

403 404 405 406 407 408 409 410 411 412 413
  frame_parms->nb_antennas_tx   = n_tx;
  frame_parms->nb_antennas_rx   = n_rx;
  frame_parms->N_RB_DL          = N_RB_UL;
  frame_parms->N_RB_UL          = N_RB_UL;
  frame_parms->threequarter_fs  = threequarter_fs;
  frame_parms->frame_type       = TDD;
  frame_parms->freq_range       = nr_FR1;
  frame_parms->numerology_index = mu;

  nr_phy_config_request_sim(gNB, N_RB_UL, N_RB_UL, mu, Nid_cell, SSB_positions);

414 415 416 417 418
  absoluteFrequencyPointA = to_nrarfcn(frame_parms->nr_band,
				       frame_parms->dl_CarrierFreq,
				       frame_parms->numerology_index,
				       frame_parms->N_RB_UL*(180e3)*(1 << frame_parms->numerology_index));

419 420 421 422 423 424 425
  subframe = slot/frame_parms->slots_per_subframe;
  
  if (config_index<67 && mu==1)  { prach_sequence_length=0; slot = subframe*2; slot_gNB = 1+(subframe*2); }
  uint16_t N_ZC = prach_sequence_length == 0 ? 839 : 139;

  printf("Config_index %d, prach_sequence_length %d\n",config_index,prach_sequence_length);

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440

  printf("FFT Size %d, Extended Prefix %d, Samples per subframe %d, Frame type %s, Frequency Range %s\n",
         NUMBER_OF_OFDM_CARRIERS,
         frame_parms->Ncp,
         frame_parms->samples_per_subframe,
         frame_parms->frame_type == FDD ? "FDD" : "TDD",
         frame_parms->freq_range == nr_FR1 ? "FR1" : "FR2");

  ru->nr_frame_parms = frame_parms;
  ru->if_south       = LOCAL_RF;
  ru->nb_tx          = n_tx;
  ru->nb_rx          = n_rx;

  gNB->gNB_config.carrier_config.num_tx_ant.value = 1;
  gNB->gNB_config.carrier_config.num_rx_ant.value = 1;
441 442 443 444 445 446 447 448
  if (mu==1)
    gNB->gNB_config.tdd_table.tdd_period.value = 6;
  else if (mu==3)
    gNB->gNB_config.tdd_table.tdd_period.value = 3;
  else {
    printf("unsupported numerology %d\n",mu);
    exit(-1);
  }
449 450 451 452

  gNB->gNB_config.prach_config.num_prach_fd_occasions.value = num_prach_fd_occasions;
  gNB->gNB_config.prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *) malloc(num_prach_fd_occasions*sizeof(nfapi_nr_num_prach_fd_occasions_t));

453
  gNB->proc.slot_rx       = slot;
454

455
  int ret = get_nr_prach_info_from_index(config_index,
456 457 458 459 460 461 462 463 464 465 466 467
					 (int)frame,
					 (int)slot_gNB,
					 absoluteFrequencyPointA,
					 mu,
					 frame_parms->frame_type,
					 &format,
					 &start_symbol,
					 &N_t_slot,
					 &N_dur,
					 &RA_sfn_index,
					 &N_RA_slot,
					 &config_period);
468

469
  if (ret == 0) {printf("No prach in %d.%d, mu %d, config_index %d\n",frame,slot,mu,config_index); exit(-1);}
470 471 472 473 474
  format0 = format&0xff;      // first column of format from table
  format1 = (format>>8)&0xff; // second column of format from table

  if (format1 != 0xff) {
    switch(format0) {
475
    case 0xa1:
476
      prach_format = 11;
477 478
      break;
    case 0xa2:
479
      prach_format = 12;
480 481
      break;
    case 0xa3:
482
      prach_format = 13;
483
      break;
484 485 486 487
    default:
      AssertFatal(1==0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
    }
  } else {
488 489 490 491 492 493 494 495 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
    switch(format0) { // single PRACH format
    case 0:
      prach_format = 0;
      break;
    case 1:
      prach_format = 1;
      break;
    case 2:
      prach_format = 2;
      break;
    case 3:
      prach_format = 3;
      break;
    case 0xa1:
      prach_format = 4;
      break;
    case 0xa2:
      prach_format = 5;
      break;
    case 0xa3:
      prach_format = 6;
      break;
    case 0xb1:
      prach_format = 7;
      break;
    case 0xb4:
      prach_format = 8;
      break;
    case 0xc0:
      prach_format = 9;
      break;
    case 0xc2:
      prach_format = 10;
      break;
522
    default:
523
      AssertFatal(1 == 0, "Invalid PRACH format");
524 525
    }
  }
526

527 528
  printf("PRACH format %d\n",prach_format);
      
529 530 531 532 533
  prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index.value = rootSequenceIndex;
  prach_config->num_prach_fd_occasions_list[fd_occasion].k1.value                        = msg1_frequencystart;
  prach_config->restricted_set_config.value                                              = restrictedSetConfig;
  prach_config->prach_sequence_length.value                                              = prach_sequence_length;
  prach_pdu->num_cs                                                                      = get_NCS(NCS_config, format0, restrictedSetConfig);
534
  prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value        = 1+(64/(N_ZC/prach_pdu->num_cs));
535
  prach_pdu->prach_format                                                                = prach_format;
536 537

  memcpy((void*)&ru->config,(void*)&RC.gNB[0]->gNB_config,sizeof(ru->config));
538 539
  RC.nb_nr_L1_inst=1;
  phy_init_nr_gNB(gNB,0,0);
540
  nr_phy_init_RU(ru);
541 542
  gNB->common_vars.rxdata = ru->common.rxdata;
  set_tdd_config_nr(&gNB->gNB_config, mu, 7, 6, 2, 4);
543

544
  // Configure UE
545 546 547 548 549 550
  UE = malloc(sizeof(PHY_VARS_NR_UE));
  memset((void*)UE,0,sizeof(PHY_VARS_NR_UE));
  PHY_vars_UE_g = malloc(2*sizeof(PHY_VARS_NR_UE**));
  PHY_vars_UE_g[0] = malloc(2*sizeof(PHY_VARS_NR_UE*));
  PHY_vars_UE_g[0][0] = UE;
  memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
551 552 553
  UE->nrUE_config.prach_config.num_prach_fd_occasions_list = (fapi_nr_num_prach_fd_occasions_t *) malloc(num_prach_fd_occasions*sizeof(fapi_nr_num_prach_fd_occasions_t));

  if (init_nr_ue_signal(UE, 1, 0) != 0){
554 555 556 557
    printf("Error at UE NR initialisation\n");
    exit(-1);
  }

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
  ue_prach_pdu           = &UE->prach_vars[0]->prach_pdu;
  ue_prach_config        = &UE->nrUE_config.prach_config;
  UE->prach_resources[0] = &prach_resources;
  txdata                 = UE->common_vars.txdata;

  UE->prach_vars[0]->amp        = AMP;
  ue_prach_pdu->root_seq_id     = rootSequenceIndex;
  ue_prach_pdu->num_cs          = get_NCS(NCS_config, format0, restrictedSetConfig);
  ue_prach_pdu->restricted_set  = restrictedSetConfig;
  ue_prach_pdu->freq_msg1       = msg1_frequencystart;
  ue_prach_pdu->prach_format    = prach_format;

  ue_prach_config->prach_sub_c_spacing                                                = mu;
  ue_prach_config->prach_sequence_length                                              = prach_sequence_length;
  ue_prach_config->restricted_set_config                                              = restrictedSetConfig;
573
  ue_prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences        = prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value ;
574 575 576 577 578 579 580 581 582 583
  ue_prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index = rootSequenceIndex;
  ue_prach_config->num_prach_fd_occasions_list[fd_occasion].k1                        = msg1_frequencystart;

  if (preamble_tx == 99)
    preamble_tx = (uint16_t)(taus()&0x3f);

  if (n_frames == 1)
    printf("raPreamble %d\n",preamble_tx);

  UE->prach_resources[0]->ra_PreambleIndex = preamble_tx;
584
  UE->prach_resources[0]->init_msg1 = 1;
585

586 587 588
  // Configure channel
  bw = N_RB_UL*(180e3)*(1 << frame_parms->numerology_index);
  AssertFatal(bw<=122.88e6,"Illegal channel bandwidth %f (mu %d,N_RB_UL %d)\n", bw, frame_parms->numerology_index, N_RB_UL);
589

590 591 592 593 594 595
  if (bw <= 30.72e6)
    fs = 30.72e6;
  else if (bw <= 61.44e6)
    fs = 61.44e6;
  else if (bw <= 122.88e6)
    fs = 122.88e6;
596 597 598 599 600 601

  LOG_I(PHY,"Running with bandwidth %f Hz, fs %f samp/s, FRAME_LENGTH_COMPLEX_SAMPLES %d\n",bw,fs,FRAME_LENGTH_COMPLEX_SAMPLES);

  UE2gNB = new_channel_desc_scm(UE->frame_parms.nb_antennas_tx,
                                gNB->frame_parms.nb_antennas_rx,
                                channel_model,
602 603
                                fs,
                                bw,
604
                                DS_TDL,
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626
                                0.0,
                                delay,
                                0);

  if (UE2gNB==NULL) {
    printf("Problem generating channel model. Exiting.\n");
    exit(-1);
  }

  for (i=0; i<2; i++) {

    s_re[i] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
    bzero(s_re[i],FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
    s_im[i] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
    bzero(s_im[i],FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));

    r_re[i] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
    bzero(r_re[i],FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
    r_im[i] = malloc(FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
    bzero(r_im[i],FRAME_LENGTH_COMPLEX_SAMPLES*sizeof(double));
  }

627 628 629 630 631
  // compute PRACH sequence
  compute_nr_prach_seq(prach_config->prach_sequence_length.value,
                       prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value,
                       prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index.value,
                       gNB->X_u);
632

633 634 635 636
  compute_nr_prach_seq(ue_prach_config->prach_sequence_length,
                       ue_prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences,
                       ue_prach_config->num_prach_fd_occasions_list[fd_occasion].prach_root_sequence_index,
                       UE->X_u);
637

638
  /*tx_lev = generate_nr_prach(UE,
639
			     0, //gNB_id,
cig's avatar
cig committed
640
			     subframe); */ //commented for testing purpose
641

642
  UE_nr_rxtx_proc_t proc={0};
643
  proc.frame_tx  = frame;
644
  proc.nr_tti_tx = slot;
645
  nr_ue_prach_procedures(UE,&proc,0,0);
646 647 648 649

  /* tx_lev_dB not used later, no need to set */
  //tx_lev_dB = (unsigned int) dB_fixed(tx_lev);

650
  prach_start = subframe*frame_parms->samples_per_subframe;
651 652

  #ifdef NR_PRACH_DEBUG
653
  LOG_M("txsig0.m", "txs0", &txdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1);
654
    LOG_M("txsig0_frame.m","txs0", txdata[0],frame_parms->samples_per_frame,1,1);
655
  #endif
656 657

  // multipath channel
658
  // dump_nr_prach_config(&gNB->frame_parms,subframe);
659

660
  for (i = 0; i < frame_parms->samples_per_subframe<<1; i++) {
661 662
    for (aa=0; aa<1; aa++) {
      if (awgn_flag == 0) {
663 664
        s_re[aa][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)]);
        s_im[aa][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)+1]);
665 666 667
      } else {
        for (aarx=0; aarx<gNB->frame_parms.nb_antennas_rx; aarx++) {
          if (aa==0) {
668 669
            r_re[aarx][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)]);
            r_im[aarx][i] = ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)+1]);
670
          } else {
671 672
            r_re[aarx][i] += ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)]);
            r_im[aarx][i] += ((double)(((short *)&txdata[aa][prach_start]))[(i<<1)+1]);
673 674 675 676 677 678
          }
        }
      }
    }
  }

679 680 681 682 683 684 685 686
  if (snr1set == 0) {
    if (n_frames == 1)
      snr1 = snr0 + .1;
    else
      snr1 = snr0 + 5.0;
  }

  printf("SNR0 %f, SNR1 %f\n", snr0, snr1);
687

688 689 690 691 692 693 694
  if (ue_speed1set == 0) {
    if (n_frames == 1)
      ue_speed1 = ue_speed0 + 10;
    else
      ue_speed1 = ue_speed0 + 50;
  }

695
  rx_prach_start = subframe*frame_parms->samples_per_subframe;
696
  if (n_frames==1) printf("slot %d, rx_prach_start %d\n",slot,rx_prach_start);
697 698
  uint16_t preamble_rx, preamble_energy;

699

Thomas Schlichter's avatar
Thomas Schlichter committed
700
  for (SNR=snr0; SNR<snr1; SNR+=.1) {
701 702 703 704 705 706 707 708 709
    for (ue_speed=ue_speed0; ue_speed<ue_speed1; ue_speed+=10) {
      delay_avg = 0.0;
      // max Doppler shift
      UE2gNB->max_Doppler = 1.9076e9*(ue_speed/3.6)/3e8;
      printf("n_frames %d SNR %f\n",n_frames,SNR);
      prach_errors=0;

      for (trial=0; trial<n_frames; trial++) {

710
	if (input_fd==NULL) {
711
        sigma2_dB = 10*log10((double)tx_lev) - SNR - 10*log10(N_RB_UL*12/N_ZC);
712 713 714 715 716 717 718 719 720

        if (n_frames==1)
          printf("sigma2_dB %f (SNR %f dB) tx_lev_dB %f\n",sigma2_dB,SNR,10*log10((double)tx_lev));

        //AWGN
        sigma2 = pow(10,sigma2_dB/10);
        //  printf("Sigma2 %f (sigma2_dB %f)\n",sigma2,sigma2_dB);

        if (awgn_flag == 0) {
721
          multipath_tv_channel(UE2gNB, s_re, s_im, r_re, r_im, frame_parms->samples_per_tti<<1, 0);
722 723 724 725 726 727 728 729
        }

        if (n_frames==1) {
          printf("rx_level data symbol %f, tx_lev %f\n",
                 10*log10(signal_energy_fp(r_re,r_im,1,OFDM_SYMBOL_SIZE_COMPLEX_SAMPLES,0)),
                 10*log10(tx_lev));
        }

730
        for (i = 0; i< frame_parms->samples_per_subframe; i++) {
731
          for (aa = 0; aa < frame_parms->nb_antennas_rx; aa++) {
732 733
            ((short*) &ru->common.rxdata[aa][rx_prach_start])[2*i] = (short) (.167*(r_re[aa][i] +sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
            ((short*) &ru->common.rxdata[aa][rx_prach_start])[2*i+1] = (short) (.167*(r_im[aa][i] + (iqim*r_re[aa][i]) + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
734 735
          }
        }
736
	} else {
737
	  n_bytes = fread(&ru->common.rxdata[0][rx_prach_start],sizeof(int32_t),frame_parms->samples_per_subframe,input_fd);
738
	  printf("fread %d bytes from file %s\n",n_bytes,input_file);
739 740
	  if (n_bytes!=frame_parms->samples_per_subframe) {
	    printf("expected %d bytes\n",frame_parms->samples_per_subframe);
741 742 743 744
	    exit(-1);
	  }
	}

745

746
        rx_nr_prach_ru(ru, prach_format, numRA, prachStartSymbol, prachOccasion, frame, slot);
747

748
        gNB->prach_vars.rxsigF = ru->prach_rxsigF[prachOccasion];
749
	if (n_frames == 1) printf("ncs %d,num_seq %d\n",prach_pdu->num_cs,  prach_config->num_prach_fd_occasions_list[fd_occasion].num_root_sequences.value);
750
        rx_nr_prach(gNB, prach_pdu, prachOccasion, frame, subframe, &preamble_rx, &preamble_energy, &preamble_delay);
751

752
	//        printf(" preamble_energy %d preamble_rx %d preamble_tx %d \n", preamble_energy, preamble_rx, preamble_tx);
753 754

        if (preamble_rx != preamble_tx)
755
          prach_errors++;
756
        else
757
          delay_avg += (double)preamble_delay;
758 759

        N_ZC = (prach_sequence_length) ? 139 : 839;
760 761

        if (n_frames==1) {
762 763
          printf("preamble %d (tx %d) : energy %d, delay %d\n",preamble_rx,preamble_tx,preamble_energy,preamble_delay);
          #ifdef NR_PRACH_DEBUG
764
	  LOG_M("prach0.m","prach0", &txdata[0][prach_start], frame_parms->samples_per_subframe, 1, 1);
765
            LOG_M("prachF0.m","prachF0", &gNB->prach_vars.prachF[0], N_ZC, 1, 1);
766 767
            LOG_M("rxsig0.m","rxs0", &gNB->common_vars.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1);
            LOG_M("ru_rxsig0.m","rxs0", &ru->common.rxdata[0][subframe*frame_parms->samples_per_subframe], frame_parms->samples_per_subframe, 1, 1);
768
            LOG_M("ru_rxsigF0.m","rxsF0", ru->prach_rxsigF[0][0], N_ZC, 1, 1);
769 770 771
            LOG_M("prach_preamble.m","prachp", &gNB->X_u[0], N_ZC, 1, 1);
            LOG_M("ue_prach_preamble.m","prachp", &UE->X_u[0], N_ZC, 1, 1);
          #endif
772 773 774
        }
      }

775
      printf("SNR %f dB, UE Speed %f km/h: errors %d/%d (delay %f)\n", SNR, ue_speed, prach_errors, n_frames, delay_avg/(double)(n_frames-prach_errors));
776 777
      if (input_fd)
	break;
Thomas Schlichter's avatar
Thomas Schlichter committed
778 779
      if (prach_errors)
        break;
780 781

    } // UE Speed loop
Thomas Schlichter's avatar
Thomas Schlichter committed
782 783 784 785
    if (!prach_errors) {
      printf("PRACH test OK\n");
      break;
    }
786 787
    if (input_fd)
      break;
788 789 790 791 792 793 794 795 796 797 798 799 800 801
  } //SNR loop

  for (i=0; i<2; i++) {
    free(s_re[i]);
    free(s_im[i]);
    free(r_re[i]);
    free(r_im[i]);
  }

  free(s_re);
  free(s_im);
  free(r_re);
  free(r_im);

802 803
  if (input_fd) fclose(input_fd);

804 805
  return(0);
}