pucchsim.c 26.9 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 25 26 27 28
/*
 * 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>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include "common/config/config_userapi.h"
29
#include "common/utils/load_module_shlib.h"
30
#include "common/utils/nr/nr_common.h"
31 32 33 34 35 36 37 38 39
#include "common/utils/LOG/log.h"
#include "common/ran_context.h" 
#include "PHY/types.h"
#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/defs_gNB.h"
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
#include "PHY/MODULATION/modulation_eNB.h"
#include "PHY/MODULATION/modulation_UE.h"
40
#include "PHY/NR_ESTIMATION/nr_ul_estimation.h"
41
#include "PHY/INIT/nr_phy_init.h"
cig's avatar
cig committed
42
#include "PHY/NR_TRANSPORT/nr_transport_proto.h"
43 44
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"
#include "PHY/NR_UE_TRANSPORT/pucch_nr.h"
45 46 47 48
#include "SCHED_NR/sched_nr.h"
#include "openair1/SIMULATION/TOOLS/sim.h"
#include "openair1/SIMULATION/RF/rf.h"
#include "openair1/SIMULATION/NR_PHY/nr_unitary_defs.h"
49
#include "executables/nr-uesoftmodem.h"
50
#include "nfapi/oai_integration/vendor_ext.h"
51
#include "executables/softmodem-common.h"
52

francescomani's avatar
francescomani committed
53
THREAD_STRUCT thread_struct;
54 55 56
PHY_VARS_gNB *gNB;
PHY_VARS_NR_UE *UE;
RAN_CONTEXT_t RC;
prasanth's avatar
prasanth committed
57
openair0_config_t openair0_cfg[MAX_CARDS];
58
int32_t uplink_frequency_offset[MAX_NUM_CCs][4];
francescomani's avatar
francescomani committed
59
uint64_t downlink_frequency[MAX_NUM_CCs][4];
60

61
double cpuf;
62
//uint8_t nfapi_mode = 0;
laurent's avatar
laurent committed
63
const int NB_UE_INST = 1;
64
uint8_t const nr_rv_round_map[4] = {0, 2, 3, 1};
Hongzhi Wang's avatar
Hongzhi Wang committed
65 66
const short conjugate[8]__attribute__((aligned(16))) = {-1,1,-1,1,-1,1,-1,1};
const short conjugate2[8]__attribute__((aligned(16))) = {1,-1,1,-1,1,-1,1,-1};
67 68 69
// needed for some functions
PHY_VARS_NR_UE * PHY_vars_UE_g[1][1]={{NULL}};

70
uint64_t get_softmodem_optmask(void) {return 0;}
71 72 73 74
static softmodem_params_t softmodem_params;
softmodem_params_t *get_softmodem_params(void) {
  return &softmodem_params;
}
75

76
void init_downlink_harq_status(NR_DL_UE_HARQ_t *dl_harq) {}
77 78
NR_IF_Module_t *NR_IF_Module_init(int Mod_id) { return (NULL); }
nfapi_mode_t nfapi_getmode(void) { return NFAPI_MODE_UNKNOWN; }
79

80 81 82 83 84 85 86 87 88 89 90
void inc_ref_sched_response(int _)
{
  LOG_E(PHY, "fatal\n");
  exit(1);
}
void deref_sched_response(int _)
{
  LOG_E(PHY, "fatal\n");
  exit(1);
}

91 92 93 94 95 96 97
nrUE_params_t nrUE_params={0};

nrUE_params_t *get_nrUE_params(void) {
  return &nrUE_params;
}


98 99 100
int main(int argc, char **argv)
{
  char c;
Raymond Knopp's avatar
Raymond Knopp committed
101
  int i;//,l;
102 103 104 105
  double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0;
  double cfo=0;
  uint8_t snr1set=0;
  double **s_re,**s_im,**r_re,**r_im;
yilmazt's avatar
yilmazt committed
106 107
  //int sync_pos, sync_pos_slot;
  //FILE *rx_frame_file;
108
  FILE *output_fd = NULL;
109
  //uint8_t write_output_file=0;
110 111
  //int result;
  //int freq_offset;
112 113
  //int subframe_offset;
  //char fname[40], vname[40];
114
  int trial,n_trials=100,n_errors=0,ack_nack_errors=0,sr_errors=0;
115 116
  uint8_t transmission_mode = 1,n_tx=1,n_rx=1;
  uint16_t Nid_cell=0;
prasanth's avatar
prasanth committed
117
  uint64_t SSB_positions=0x01;
118
  channel_desc_t *UE2gNB;
119
  int format=0;
yilmazt's avatar
yilmazt committed
120
  //uint8_t extended_prefix_flag=0;
121
  FILE *input_fd=NULL;
122
  //uint8_t nacktoack_flag=0;
123
  int16_t amp=0x7FFF;
124
  int nr_slot_tx=0;
rmagueta's avatar
rmagueta committed
125
  int nr_frame_tx=0;
126
  uint64_t actual_payload = 0, payload_received = 0;
127
  bool random_payload = true;
128 129 130 131 132
  int nr_bit=1; // maximum value possible is 2
  uint8_t m0=0;// higher layer paramater initial cyclic shift
  uint8_t nrofSymbols=1; //number of OFDM symbols can be 1-2 for format 1
  uint8_t startingSymbolIndex=0; // resource allocated see 9.2.1, 38.213 for more info.should be actually present in the resource set provided
  uint16_t startingPRB=0,startingPRB_intraSlotHopping=0; //PRB number not sure see 9.2.1, 38.213 for more info. Should be actually present in the resource set provided
133
  uint16_t nrofPRB=2;
134
  uint8_t timeDomainOCC=0;
135 136 137
  SCM_t channel_model=AWGN;//Rayleigh1_anticorr;

  double DS_TDL = .03;
138 139
 
  double delay_us = 0;
140
  int N_RB_DL=273,mu=1;
141
  float target_error_rate=0.001;
142
  int frame_length_complex_samples;
yilmazt's avatar
yilmazt committed
143
  //int frame_length_complex_samples_no_prefix;
144
  NR_DL_FRAME_PARMS *frame_parms;
yilmazt's avatar
yilmazt committed
145
  //unsigned char frame_type = 0;
146
  int loglvl=OAILOG_WARNING;
147
  int sr_flag = 0;
148
  int pucch_DTX_thres = 50;
149 150
  cpuf = get_cpu_freq_GHz();

yilmazt's avatar
yilmazt committed
151 152
  if ( load_configmodule(argc,argv,CONFIG_ENABLECMDLINEONLY) == 0) {
    exit_fun("[NR_PUCCHSIM] Error, configuration module init failed\n");
153 154 155
  }

  randominit(0);
yilmazt's avatar
yilmazt committed
156
  logInit();
157

158
  while ((c = getopt (argc, argv, "f:hA:f:g:i:I:P:B:b:t:T:m:n:r:o:s:S:x:y:z:N:F:GR:IL:q:cd:")) != -1) {
159 160
    switch (c) {
    case 'f':
161
      //write_output_file=1;
162 163 164 165 166 167 168 169
      output_fd = fopen(optarg,"w");

      if (output_fd==NULL) {
        printf("Error opening %s\n",optarg);
        exit(-1);
      }
      break;

yilmazt's avatar
yilmazt committed
170

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

    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;
201 202 203 204 205 206 207 208 209 210 211 212 213 214
      case 'H':
        channel_model = TDL_C;
	DS_TDL = .030; // 30 ns
	break;
  
      case 'I':
	channel_model = TDL_C;
	DS_TDL = .3;  // 300ns
        break;
     
      case 'J':
	channel_model=TDL_D;
	DS_TDL = .03;
	break;
215 216

      default:
217
        printf("Unsupported channel model!\n");
218 219 220 221 222 223 224 225 226 227
        exit(-1);
      }
      break;

    case 'n':
      n_trials = atoi(optarg);
      break;

    case 'o':
      cfo = atof(optarg);
228
      printf("Setting CFO to %f Hz\n",cfo);
229 230 231 232
      break;

    case 's':
      snr0 = atof(optarg);
233
      printf("Setting SNR0 to %f\n",snr0);
234 235 236 237 238
      break;

    case 'S':
      snr1 = atof(optarg);
      snr1set=1;
239
      printf("Setting SNR1 to %f\n",snr1);
240 241
      break;

Raymond Knopp's avatar
Raymond Knopp committed
242
      
yilmazt's avatar
yilmazt committed
243
    case 't':
Raymond Knopp's avatar
Raymond Knopp committed
244
      pucch_DTX_thres= atoi(optarg);
245
      break;
Raymond Knopp's avatar
Raymond Knopp committed
246
      /*
247 248 249 250
    case 'p':
      extended_prefix_flag=1;
      break;

yilmazt's avatar
yilmazt committed
251 252 253 254 255
    case 'd':
      frame_type = 1;
      break;

    case 'r':
256 257 258 259 260 261 262
      ricean_factor = pow(10,-.1*atof(optarg));
      if (ricean_factor>1) {
        printf("Ricean factor must be between 0 and 1\n");
        exit(-1);
      }
      break;
      */
263 264 265
    case 'd':
       delay_us=atof(optarg);
       break;
266 267 268 269 270 271
    case 'x':
      transmission_mode=atoi(optarg);

      if ((transmission_mode!=1) &&
          (transmission_mode!=2) &&
          (transmission_mode!=6)) {
272
        printf("Unsupported transmission mode %d\n",transmission_mode);
273 274 275 276 277 278 279 280
        exit(-1);
      }
      break;

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

      if ((n_tx==0) || (n_tx>2)) {
281
        printf("Unsupported number of tx antennas %d\n",n_tx);
282 283 284 285 286 287 288
        exit(-1);
      }
      break;

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

Raymond Knopp's avatar
Raymond Knopp committed
289
      if ((n_rx==0) || (n_rx>8)) {
290
        printf("Unsupported number of rx antennas %d\n",n_rx);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
        exit(-1);
      }
      break;

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

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

    case 'F':
      input_fd = fopen(optarg,"r");

      if (input_fd==NULL) {
        printf("Problem with filename %s\n",optarg);
        exit(-1);
      }
      break;

    case 'L':
      loglvl = atoi(optarg);
      break;
315 316 317
    case 'i':
      nrofSymbols=(uint8_t)atoi(optarg);
      break;
Francesco Mani's avatar
Francesco Mani committed
318 319 320 321 322 323
    case 'I':
      startingSymbolIndex=(uint8_t)atoi(optarg);
      break;
    case 'r':
      startingPRB=atoi(optarg);
      break;
324 325 326
    case 'q':
      nrofPRB=atoi(optarg);
      break;
327 328 329
    case 'P':
      format=atoi(optarg);
      break;
Francesco Mani's avatar
Francesco Mani committed
330 331 332
    case 'm':
      m0=atoi(optarg);
      break;
333 334 335
    case 'b':
      nr_bit=atoi(optarg);
      break;
336 337 338
    case 'c':
      sr_flag=1;
      break;
Francesco Mani's avatar
Francesco Mani committed
339 340
    case 'B':
      actual_payload=atoi(optarg);
341
      random_payload = false;
Francesco Mani's avatar
Francesco Mani committed
342
      break;
343
    case 'T':
344
      //nacktoack_flag=(uint8_t)atoi(optarg);
345 346
      target_error_rate=0.001;
      break;
347 348
    default:
    case 'h':
yilmazt's avatar
yilmazt committed
349
      printf("%s -h(elp) -p(extended_prefix) -N cell_id -f output_filename -F input_filename -g channel_model -n n_frames -t Delayspread -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]);
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
      printf("-h This message\n");
      printf("-p Use extended prefix mode\n");
      printf("-d Use TDD\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("-t Delay spread for multipath channel\n");
      printf("-g [A,B,C,D,E,F,G] Use 3GPP SCM (A,B,C,D) or 36-101 (E-EPA,F-EVA,G-ETU) models (ignores delay spread and Ricean factor)\n");
      printf("-x Transmission mode (1,2,6 for the moment)\n");
      printf("-y Number of TX antennas used in eNB\n");
      printf("-z Number of RX antennas used in UE\n");
      printf("-i Relative strength of first intefering eNB (in dB) - cell_id mod 3 = 1\n");
      printf("-j Relative strength of second intefering eNB (in dB) - cell_id mod 3 = 2\n");
      printf("-o Carrier frequency offset in Hz\n");
      printf("-N Nid_cell\n");
      printf("-R N_RB_DL\n");
      printf("-O oversampling factor (1,2,4,8,16)\n");
      printf("-A Interpolation_filname Run with Abstraction to generate Scatter plot using interpolation polynomial in file\n");
yilmazt's avatar
yilmazt committed
368
      //printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n");
369 370
      printf("-f Output filename (.txt format) for Pe/SNR results\n");
      printf("-F Input filename (.txt format) for RX conformance testing\n");
371
      printf("-i Enter number of ofdm symbols for pucch\n");
Francesco Mani's avatar
Francesco Mani committed
372
      printf("-I Starting symbol index for pucch\n");
373 374
      printf("-r PUCCH starting PRB\n");
      printf("-q PUCCH number of PRB\n");
375 376
      printf("-P Enter the format of PUCCH\n");
      printf("-b number of HARQ bits (1-2)\n");
Francesco Mani's avatar
Francesco Mani committed
377 378
      printf("-B payload to be transmitted on PUCCH\n");
      printf("-m initial cyclic shift m0\n");
Roberto Louro Magueta's avatar
Roberto Louro Magueta committed
379
      printf("-T to check nacktoack miss for format 1\n");
380 381 382
      exit (-1);
      break;
    }
yilmazt's avatar
yilmazt committed
383
  }
384

385 386
  double phase = (1<<mu)*30e-3*delay_us;

387 388
  set_glog(loglvl);

yilmazt's avatar
yilmazt committed
389
  if (snr1set==0) snr1 = snr0+10;
390

Raymond Knopp's avatar
Raymond Knopp committed
391
  printf("Initializing gNodeB for mu %d, N_RB_DL %d, n_rx %d\n",mu,N_RB_DL,n_rx);
392

393
  if((format!=0) && (format!=1) && (format!=2)){
Francesco Mani's avatar
Francesco Mani committed
394 395 396 397
    printf("PUCCH format %d not supported\n",format);
    exit(0); 
  }

Raymond Knopp's avatar
Raymond Knopp committed
398
  AssertFatal(((format < 2)&&(nr_bit<3)&&(actual_payload<5)) ||
399
	      ((format == 2)&&(nr_bit>2)&&(nr_bit<65)),"illegal combination format %d, nr_bit %d\n",
400
	      format,nr_bit);
Raymond Knopp's avatar
Raymond Knopp committed
401 402
  int do_DTX=0;
  if ((format < 2) && (actual_payload == 4)) do_DTX=1;
Francesco Mani's avatar
Francesco Mani committed
403

404 405 406 407
  if (random_payload) {
    srand(time(NULL));   // Initialization, should only be called once.
    actual_payload = rand();      // Returns a pseudo-random integer between 0 and RAND_MAX.
  }
408
  actual_payload &= nr_bit < 64 ? (1UL << nr_bit) - 1: 0xffffffffffffffff;
Francesco Mani's avatar
Francesco Mani committed
409

410
  printf("Transmitted payload is %lu, do_DTX = %d\n",actual_payload,do_DTX);
411

412
  RC.gNB = calloc(1, sizeof(PHY_VARS_gNB *));
Raymond Knopp's avatar
Raymond Knopp committed
413
  RC.gNB[0] = calloc(1,sizeof(PHY_VARS_gNB));
414
  gNB = RC.gNB[0];
Raymond Knopp's avatar
Raymond Knopp committed
415
  gNB->pucch0_thres = pucch_DTX_thres;
416 417 418 419 420 421 422
  frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
  frame_parms->nb_antennas_tx = n_tx;
  frame_parms->nb_antennas_rx = n_rx;
  frame_parms->N_RB_DL = N_RB_DL;
  frame_parms->N_RB_UL = N_RB_DL;
  frame_parms->Nid_cell = Nid_cell;

423 424 425
  nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
  cfg->carrier_config.num_tx_ant.value = n_tx;
  cfg->carrier_config.num_rx_ant.value = n_rx;
prasanth's avatar
prasanth committed
426
  nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions);
francescomani's avatar
francescomani committed
427 428
  gNB->gNB_config.tdd_table.tdd_period.value = 6;
  set_tdd_config_nr(&gNB->gNB_config, mu, 7, 6, 2, 4);
429
  phy_init_nr_gNB(gNB);
430 431 432
  /* RU handles rxdataF, and gNB just has a pointer. Here, we don't have an RU,
   * so we need to allocate that memory as well. */
  for (i = 0; i < n_rx; i++)
433
    gNB->common_vars.rxdataF[i] = malloc16_clear(gNB->frame_parms.samples_per_frame_wCP*sizeof(c16_t));
434

435 436 437 438 439 440 441 442 443 444
  double fs,txbw,rxbw;
  uint32_t samples;

  get_samplerate_and_bw(mu,
                        N_RB_DL,
                        frame_parms->threequarter_fs,
                        &fs,
                        &samples,
                        &txbw,
                        &rxbw);
445

446
  UE2gNB = new_channel_desc_scm(n_tx, n_rx, channel_model, fs, 0, txbw, DS_TDL, 0.0, CORR_LEVEL_LOW, 0, 0, 0, 0);
447

448
  if (UE2gNB==NULL) {
449
    printf("Problem generating channel model. Exiting.\n");
450 451 452 453
    exit(-1);
  }

  frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
yilmazt's avatar
yilmazt committed
454
  //frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP;
455

Raymond Knopp's avatar
Raymond Knopp committed
456 457 458 459
  s_re = malloc(n_tx*sizeof(double*));
  s_im = malloc(n_tx*sizeof(double*));
  r_re = malloc(n_rx*sizeof(double*));
  r_im = malloc(n_rx*sizeof(double*));
460
  memcpy((void*)&gNB->frame_parms,(void*)frame_parms,sizeof(frame_parms));
Raymond Knopp's avatar
Raymond Knopp committed
461 462 463
  for (int aatx=0; aatx<n_tx; aatx++) {
    s_re[aatx] = calloc(1,frame_length_complex_samples*sizeof(double));
    s_im[aatx] = calloc(1,frame_length_complex_samples*sizeof(double));
464 465
  }

Raymond Knopp's avatar
Raymond Knopp committed
466 467 468 469
  for (int aarx=0; aarx<n_rx; aarx++) {
    r_re[aarx] = calloc(1,frame_length_complex_samples*sizeof(double));
    r_im[aarx] = calloc(1,frame_length_complex_samples*sizeof(double));
  }
470

471
  uint8_t mcs=0;
Francesco Mani's avatar
Francesco Mani committed
472
  int shift = 0;
Francesco Mani's avatar
Francesco Mani committed
473
  if(format==0){
Francesco Mani's avatar
Francesco Mani committed
474 475
    if (sr_flag)
      shift = 1<<nr_bit;
476 477 478
    if (nr_bit ==0) 
      mcs=table1_mcs[0];
    else if(nr_bit==1)
Francesco Mani's avatar
Francesco Mani committed
479
      mcs=table1_mcs[actual_payload+shift];
Francesco Mani's avatar
Francesco Mani committed
480
    else if(nr_bit==2)
Francesco Mani's avatar
Francesco Mani committed
481
      mcs=table2_mcs[actual_payload+shift];
laurent's avatar
laurent committed
482
    else AssertFatal(1==0,"Either nr_bit %d or sr_flag %d must be non-zero\n", nr_bit, sr_flag);
483
  }
rmagueta's avatar
rmagueta committed
484 485 486 487 488 489 490 491 492

  startingPRB_intraSlotHopping = N_RB_DL-1;
  uint32_t hopping_id = Nid_cell;
  uint32_t dmrs_scrambling_id = 0;
  uint32_t data_scrambling_id = 0;

  //configure UE
  UE = calloc(1,sizeof(PHY_VARS_NR_UE));
  memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
493
  UE->frame_parms.nb_antennas_rx=1;
rmagueta's avatar
rmagueta committed
494

495
  if (init_nr_ue_signal(UE, 1) != 0)
rmagueta's avatar
rmagueta committed
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
  {
    printf("Error at UE NR initialisation\n");
    exit(-1);
  }

  fapi_nr_ul_config_pucch_pdu pucch_tx_pdu;
  if (format==0) {
    pucch_tx_pdu.format_type = 0;
    pucch_tx_pdu.nr_of_symbols = nrofSymbols;
    pucch_tx_pdu.start_symbol_index = startingSymbolIndex;
    pucch_tx_pdu.bwp_start = 0;
    pucch_tx_pdu.prb_start = startingPRB;
    pucch_tx_pdu.hopping_id = hopping_id;
    pucch_tx_pdu.group_hop_flag = 0;
    pucch_tx_pdu.sequence_hop_flag = 0;
    pucch_tx_pdu.freq_hop_flag = 0;
    pucch_tx_pdu.mcs = mcs;
    pucch_tx_pdu.initial_cyclic_shift = 0;
    pucch_tx_pdu.second_hop_prb = startingPRB_intraSlotHopping;
  }
  if (format==2) {
    pucch_tx_pdu.format_type = 2;
    pucch_tx_pdu.rnti = 0x1234;
    pucch_tx_pdu.n_bit = nr_bit;
    pucch_tx_pdu.payload = actual_payload;
    pucch_tx_pdu.nr_of_symbols = nrofSymbols;
    pucch_tx_pdu.start_symbol_index = startingSymbolIndex;
    pucch_tx_pdu.bwp_start = 0;
    pucch_tx_pdu.prb_start = startingPRB;
    pucch_tx_pdu.prb_size = nrofPRB;
    pucch_tx_pdu.hopping_id = hopping_id;
    pucch_tx_pdu.group_hop_flag = 0;
    pucch_tx_pdu.sequence_hop_flag = 0;
    pucch_tx_pdu.freq_hop_flag = 0;
    pucch_tx_pdu.dmrs_scrambling_id = dmrs_scrambling_id;
    pucch_tx_pdu.data_scrambling_id = data_scrambling_id;
    pucch_tx_pdu.second_hop_prb = startingPRB_intraSlotHopping;
  }

  pucch_GroupHopping_t PUCCH_GroupHopping = pucch_tx_pdu.group_hop_flag + (pucch_tx_pdu.sequence_hop_flag<<1);

537
  for(SNR=snr0;SNR<=snr1;SNR+=1){
538
    ack_nack_errors=0;
539
    sr_errors=0;
540
    n_errors = 0;
541
    c16_t **txdataF = gNB->common_vars.txdataF;
542
    for (trial=0; trial<n_trials; trial++) {
Raymond Knopp's avatar
Raymond Knopp committed
543 544 545
      for (int aatx=0;aatx<1;aatx++)
        bzero(txdataF[aatx],frame_parms->ofdm_symbol_size*sizeof(int));
      if(format==0 && do_DTX==0){
rmagueta's avatar
rmagueta committed
546 547 548 549 550
        nr_generate_pucch0(UE, txdataF, frame_parms, amp, nr_slot_tx, &pucch_tx_pdu);
      } else if (format == 1 && do_DTX==0){
        nr_generate_pucch1(UE, txdataF, frame_parms, amp, nr_slot_tx, &pucch_tx_pdu);
      } else if (do_DTX == 0){
        nr_generate_pucch2(UE, txdataF, frame_parms, amp, nr_slot_tx, &pucch_tx_pdu);
551
      }
552

Raymond Knopp's avatar
Raymond Knopp committed
553 554
      // SNR Computation
      // standard says: SNR = S / N, where S is the total signal energy, N is the noise energy in the transmission bandwidth (i.e. N_RB_DL resource blocks)
rmagueta's avatar
rmagueta committed
555
      // txlev = S.
556
      int txlev = signal_energy((int32_t *)&txdataF[0][startingSymbolIndex*frame_parms->ofdm_symbol_size], frame_parms->ofdm_symbol_size);
rmagueta's avatar
rmagueta committed
557

Raymond Knopp's avatar
Raymond Knopp committed
558 559
      // sigma2 is variance per dimension, so N/(N_RB*12)
      // so, sigma2 = N/(N_RB_DL*12) => (S/SNR)/(N_RB*12)
rmagueta's avatar
rmagueta committed
560
      int N_RB = (format == 0 || format == 1) ? 1 : nrofPRB;
561
      sigma2_dB = 10*log10(txlev*(N_RB_DL/N_RB))-SNR;
Raymond Knopp's avatar
Raymond Knopp committed
562
      sigma2 = pow(10.0,sigma2_dB/10.0);
rmagueta's avatar
rmagueta committed
563 564 565

      if (n_trials==1) printf("txlev %d (%f dB), offset %d, sigma2 %f ( %f dB)\n",txlev,10*log10(txlev),startingSymbolIndex*frame_parms->ofdm_symbol_size,sigma2,sigma2_dB);

566
      c16_t **rxdataF =  gNB->common_vars.rxdataF;
Raymond Knopp's avatar
Raymond Knopp committed
567 568
      for (int symb=0; symb<gNB->frame_parms.symbols_per_slot;symb++) {
        if (symb<startingSymbolIndex || symb >= startingSymbolIndex+nrofSymbols) {
569
          int i0 = symb*gNB->frame_parms.ofdm_symbol_size;
Raymond Knopp's avatar
Raymond Knopp committed
570 571 572
          for (int re=0;re<N_RB_DL*12;re++) {
            i=i0+((gNB->frame_parms.first_carrier_offset + re)%gNB->frame_parms.ofdm_symbol_size);
            for (int aarx=0;aarx<n_rx;aarx++) {
573 574 575 576
              double nr = sqrt(sigma2/2)*gaussdouble(0.0,1.0);
              double ni = sqrt(sigma2/2)*gaussdouble(0.0,1.0);
              rxdataF[aarx][i].r = (int16_t)(100.0*(nr)/sqrt((double)txlev));
              rxdataF[aarx][i].i = (int16_t)(100.0*(ni)/sqrt((double)txlev));
Raymond Knopp's avatar
Raymond Knopp committed
577 578 579
            }
          }
        }
580
      }
rmagueta's avatar
rmagueta committed
581 582

      random_channel(UE2gNB,0);
583
      freq_channel(UE2gNB,N_RB_DL,2*N_RB_DL+1,15<<mu);
Raymond Knopp's avatar
Raymond Knopp committed
584
      for (int symb=0; symb<nrofSymbols; symb++) {
585
        int i0 = (startingSymbolIndex + symb)*gNB->frame_parms.ofdm_symbol_size;
Raymond Knopp's avatar
Raymond Knopp committed
586 587
        for (int re=0;re<N_RB_DL*12;re++) {
          i=i0+((gNB->frame_parms.first_carrier_offset + re)%gNB->frame_parms.ofdm_symbol_size);
588 589
          struct complexd phasor;
	  phasor.r = cos(2*M_PI*phase*re);
590
          phasor.i = sin(2*M_PI*phase*re);
Raymond Knopp's avatar
Raymond Knopp committed
591
          for (int aarx=0;aarx<n_rx;aarx++) {
592 593 594 595 596 597 598 599
            double txr = (double)(((int16_t *)txdataF[0])[(i<<1)]);
            double txi = (double)(((int16_t *)txdataF[0])[1+(i<<1)]);
	    double rxr={0},rxi={0};
	    for (int l = 0; l<UE2gNB->channel_length; l++) {
	      rxr = txr*UE2gNB->chF[aarx][l].r - txi*UE2gNB->chF[aarx][l].i;
	      rxi = txr*UE2gNB->chF[aarx][l].i + txi*UE2gNB->chF[aarx][l].r;
	    }
	    double rxr_tmp = rxr*phasor.r - rxi*phasor.i;
600 601
            rxi     = rxr*phasor.i + rxi*phasor.r;
            rxr = rxr_tmp;
602 603 604 605
            double nr = sqrt(sigma2/2)*gaussdouble(0.0,1.0);
            double ni = sqrt(sigma2/2)*gaussdouble(0.0,1.0);
            rxdataF[aarx][i].r = (int16_t)(100.0*(rxr + nr)/sqrt((double)txlev));
            rxdataF[aarx][i].i=(int16_t)(100.0*(rxi + ni)/sqrt((double)txlev));
rmagueta's avatar
rmagueta committed
606

607
            if (n_trials==1 && fabs(txr) > 0) printf("symb %d, re %d , aarx %d : txr %f, txi %f, chr %f, chi %f, nr %f, ni %f, rxr %f, rxi %f => %d,%d\n",
Raymond Knopp's avatar
Raymond Knopp committed
608
                                                    symb, re, aarx, txr,txi,
rmagueta's avatar
rmagueta committed
609
                                                    UE2gNB->chF[aarx][re].r,UE2gNB->chF[aarx][re].i,
Raymond Knopp's avatar
Raymond Knopp committed
610
                                                    nr,ni, rxr,rxi,
611
                                                    rxdataF[aarx][i].r,rxdataF[aarx][i].i);
Raymond Knopp's avatar
Raymond Knopp committed
612 613 614
          }
        }
      }
rmagueta's avatar
rmagueta committed
615

Raymond Knopp's avatar
Raymond Knopp committed
616
      int rxlev=0;
617
      for (int aarx=0;aarx<n_rx;aarx++) rxlev += signal_energy((int32_t*)&rxdataF[aarx][startingSymbolIndex*frame_parms->ofdm_symbol_size],
Raymond Knopp's avatar
Raymond Knopp committed
618
                                                           frame_parms->ofdm_symbol_size);
619

620 621
      int rxlev_pucch=0;

622
      for (int aarx=0;aarx<n_rx;aarx++) rxlev_pucch += signal_energy((int32_t*)&rxdataF[aarx][startingSymbolIndex*frame_parms->ofdm_symbol_size],
623 624 625
                                                           12);

      // set UL mask for pucch allocation
Raymond Knopp's avatar
Raymond Knopp committed
626 627 628 629 630 631
      for (int s=0;s<frame_parms->symbols_per_slot;s++){
        if (s>=startingSymbolIndex && s<(startingSymbolIndex+nrofSymbols))
          for (int rb=0; rb<N_RB; rb++) {
            int rb2 = rb+startingPRB;
            gNB->rb_mask_ul[s][rb2>>5] |= (1<<(rb2&31));
          }
632
      }
633 634

      // noise measurement (all PRBs)
Raymond Knopp's avatar
Raymond Knopp committed
635
      gNB_I0_measurements(gNB, nr_slot_tx, 0, gNB->frame_parms.symbols_per_slot);
636

637
      if (n_trials==1) printf("noise rxlev %d (%d dB), rxlev pucch %d dB sigma2 %f dB, SNR %f, TX %f, I0 (pucch) %d, I0 (avg) %d\n",rxlev,dB_fixed(rxlev),dB_fixed(rxlev_pucch),sigma2_dB,SNR,10*log10((double)txlev*UE->frame_parms.ofdm_symbol_size/12),gNB->measurements.n0_subband_power_tot_dB[startingPRB],gNB->measurements.n0_subband_power_avg_dB);
638
      if(format==0){
639 640
        nfapi_nr_uci_pucch_pdu_format_0_1_t uci_pdu;
        nfapi_nr_pucch_pdu_t pucch_pdu;
francescomani's avatar
francescomani committed
641
        gNB->phy_stats[0].rnti = 0x1234;
rmagueta's avatar
rmagueta committed
642
        pucch_pdu.rnti                  = 0x1234;
643 644 645 646 647 648 649 650 651 652 653 654
        pucch_pdu.subcarrier_spacing    = 1;
        pucch_pdu.group_hop_flag        = PUCCH_GroupHopping&1;
        pucch_pdu.sequence_hop_flag     = (PUCCH_GroupHopping>>1)&1;
        pucch_pdu.bit_len_harq          = nr_bit;
        pucch_pdu.bit_len_csi_part1     = 0;
        pucch_pdu.bit_len_csi_part2     = 0;
        pucch_pdu.sr_flag               = sr_flag;
        pucch_pdu.nr_of_symbols         = nrofSymbols;
        pucch_pdu.hopping_id            = hopping_id;
        pucch_pdu.initial_cyclic_shift  = 0;
        pucch_pdu.start_symbol_index    = startingSymbolIndex;
        pucch_pdu.prb_start             = startingPRB;
655
        pucch_pdu.prb_size              = 1;
rmagueta's avatar
rmagueta committed
656
        pucch_pdu.bwp_start             = 0;
Raymond Knopp's avatar
Raymond Knopp committed
657
        pucch_pdu.bwp_size              = N_RB_DL;
658
        if (nrofSymbols>1) {
Raymond Knopp's avatar
Raymond Knopp committed
659 660 661 662 663
          pucch_pdu.freq_hop_flag       = 1;
          pucch_pdu.second_hop_prb      = N_RB_DL-1;
        }
        else pucch_pdu.freq_hop_flag = 0;

rmagueta's avatar
rmagueta committed
664
        nr_decode_pucch0(gNB, nr_frame_tx, nr_slot_tx,&uci_pdu,&pucch_pdu);
665
        if(sr_flag==1){
666
          if (uci_pdu.sr.sr_indication == 0 || uci_pdu.sr.sr_confidence_level == 1)
667 668
            sr_errors+=1;
        }
669
        // harq value 0 -> pass
670
        nfapi_nr_harq_t *harq_list = uci_pdu.harq.harq_list;
671
        // confidence value 0 -> good confidence
672
        const int confidence_lvl = uci_pdu.harq.harq_confidence_level;
673
        if(nr_bit>0){
674
          if (nr_bit==1 && do_DTX == 0)
675
            ack_nack_errors+=(actual_payload^(!harq_list[0].harq_value));
Raymond Knopp's avatar
Raymond Knopp committed
676
          else if (do_DTX == 0)
677
            ack_nack_errors+=(((actual_payload&1)^(!harq_list[1].harq_value))+((actual_payload>>1)^(!harq_list[0].harq_value)));
678 679
          else if ((!confidence_lvl && !harq_list[0].harq_value) ||
                   (!confidence_lvl && nr_bit == 2 && !harq_list[1].harq_value))
680
            ack_nack_errors++;
681
        }
682
      }
683
      else if (format==1) {
684
        nr_decode_pucch1((c16_t **)rxdataF,PUCCH_GroupHopping,hopping_id,
685
                         &(payload_received),frame_parms,amp,nr_slot_tx,
686 687
                         m0,nrofSymbols,startingSymbolIndex,startingPRB,
                         startingPRB_intraSlotHopping,timeDomainOCC,nr_bit);
yilmazt's avatar
yilmazt committed
688 689 690 691
        if(nr_bit==1)
          ack_nack_errors+=((actual_payload^payload_received)&1);
        else
          ack_nack_errors+=((actual_payload^payload_received)&1) + (((actual_payload^payload_received)&2)>>1);
692
      }
693
      else if (format==2) {
694 695
        nfapi_nr_uci_pucch_pdu_format_2_3_4_t uci_pdu={0};
        nfapi_nr_pucch_pdu_t pucch_pdu={0};
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711
        pucch_pdu.rnti = 0x1234;
        pucch_pdu.subcarrier_spacing    = 1;
        pucch_pdu.group_hop_flag        = PUCCH_GroupHopping&1;
        pucch_pdu.sequence_hop_flag     = (PUCCH_GroupHopping>>1)&1;
        pucch_pdu.bit_len_csi_part1     = nr_bit;
        pucch_pdu.bit_len_harq          = 0;
        pucch_pdu.bit_len_csi_part2     = 0;
        pucch_pdu.sr_flag               = 0;
        pucch_pdu.nr_of_symbols         = nrofSymbols;
        pucch_pdu.hopping_id            = hopping_id;
        pucch_pdu.initial_cyclic_shift  = 0;
        pucch_pdu.start_symbol_index    = startingSymbolIndex;
        pucch_pdu.prb_size              = nrofPRB;
        pucch_pdu.prb_start             = startingPRB;
        pucch_pdu.dmrs_scrambling_id    = dmrs_scrambling_id;
        pucch_pdu.data_scrambling_id    = data_scrambling_id;
712
        if (nrofSymbols>1) {
Raymond Knopp's avatar
Raymond Knopp committed
713 714 715 716
          pucch_pdu.freq_hop_flag       = 1;
          pucch_pdu.second_hop_prb      = N_RB_DL-1;
        }
        else pucch_pdu.freq_hop_flag = 0;
717
        nr_decode_pucch2(gNB,nr_frame_tx,nr_slot_tx,&uci_pdu,&pucch_pdu);
718 719 720 721 722 723 724 725 726
        int csi_part1_bytes=pucch_pdu.bit_len_csi_part1>>3;
        if ((pucch_pdu.bit_len_csi_part1&7) > 0) csi_part1_bytes++;
        for (int i=0;i<csi_part1_bytes;i++) {
          if (uci_pdu.csi_part1.csi_part1_payload[i] != ((uint8_t*)&actual_payload)[i]) {
            ack_nack_errors++;
            break;
          }
        }
        free(uci_pdu.csi_part1.csi_part1_payload);
727 728

      }
729 730
      n_errors=((actual_payload^payload_received)&1)+(((actual_payload^payload_received)&2)>>1)+(((actual_payload^payload_received)&4)>>2)+n_errors;
    }
731 732 733 734 735
    if (sr_flag == 1)
      printf("SR: SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,sr_errors);
    if(nr_bit > 0)
      printf("ACK/NACK: SNR=%f, n_trials=%d, n_bit_errors=%d\n",SNR,n_trials,ack_nack_errors);
    if((float)(ack_nack_errors+sr_errors)/(float)(n_trials)<=target_error_rate){
736 737 738
      printf("PUCCH test OK\n");
      break;
    }
739
  }
740 741 742
  free_channel_desc_scm(UE2gNB);
  term_freq_channel();

francescomani's avatar
francescomani committed
743 744 745 746 747
  int nb_slots_to_set = TDD_CONFIG_NB_FRAMES * (1 << mu) * NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
  for (int i = 0; i < nb_slots_to_set; ++i)
    free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list[i].max_num_of_symbol_per_slot_list);
  free(gNB->gNB_config.tdd_table.max_tdd_periodicity_list);

748 749
  for (i = 0; i < n_rx; i++)
    free(gNB->common_vars.rxdataF[i]);
750 751 752 753 754 755 756
  phy_free_nr_gNB(gNB);
  free(RC.gNB[0]);
  free(RC.gNB);

  term_nr_ue_signal(UE, 1);
  free(UE);

Raymond Knopp's avatar
Raymond Knopp committed
757 758 759 760 761 762 763
  for (int aatx=0; aatx<n_tx; aatx++) {
    free(s_re[aatx]);
    free(s_im[aatx]);
  }
  for (int aarx=0; aarx<n_rx; aarx++) {
    free(r_re[aarx]);
    free(r_im[aarx]);
764 765 766 767 768 769
  }
  free(s_re);
  free(s_im);
  free(r_re);
  free(r_im);

yilmazt's avatar
yilmazt committed
770 771
  if (output_fd) fclose(output_fd);
  if (input_fd)  fclose(input_fd);
772

773 774 775
  loader_reset();
  logTerm();

776 777
  return(n_errors);
}