pbchsim.c 16.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>

29 30 31 32
#include "common/config/config_userapi.h"
#include "common/utils/LOG/log.h"
#include "common/ran_context.h" 

33 34 35 36 37 38
#include "SIMULATION/TOOLS/sim.h"
#include "SIMULATION/RF/rf.h"
#include "PHY/types.h"
#include "PHY/defs_nr_common.h"
#include "PHY/defs_nr_UE.h"
#include "PHY/defs_gNB.h"
39
#include "PHY/NR_REFSIG/refsig_defs_ue.h"
40
#include "PHY/NR_REFSIG/nr_mod_table.h"
41 42
#include "PHY/MODULATION/modulation_eNB.h"
#include "PHY/MODULATION/modulation_UE.h"
43
#include "PHY/INIT/phy_init.h"
44 45 46
#include "PHY/NR_TRANSPORT/nr_transport.h"
#include "PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h"

47 48
#include "SCHED_NR/sched_nr.h"

49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68

PHY_VARS_gNB *gNB;
PHY_VARS_NR_UE *UE;
RAN_CONTEXT_t RC;


double cpuf;

// dummy functions
int nfapi_mode=0;
int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) { return(0);}
int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req) { return(0); }

int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) { return(0); }

int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) { return(0); }

int oai_nfapi_nr_dl_config_req(nfapi_nr_dl_config_request_t *dl_config_req) {return(0);}

knopp's avatar
knopp committed
69 70
uint32_t from_nrarfcn(int nr_bandP,uint32_t dl_nrarfcn) {return(0);}
int32_t get_uldl_offset(int nr_bandP) {return(0);}
71 72 73

NR_IF_Module_t *NR_IF_Module_init(int Mod_id){return(NULL);}

74 75 76 77 78
void exit_function(const char* file, const char* function, const int line,const char *s) { 
   const char * msg= s==NULL ? "no comment": s;
   printf("Exiting at: %s:%d %s(), %s\n", file, line, function, msg); 
   exit(-1); 
}
79

80
// needed for some functions
81
PHY_VARS_NR_UE * PHY_vars_UE_g[1][1]={{NULL}};
82

83 84 85 86 87
int main(int argc, char **argv)
{

  char c;

88
  int i,aa;//,l;
89
  double sigma2, sigma2_dB=10,SNR,snr0=-2.0,snr1=2.0;
90
  uint8_t snr1set=0;
91 92
  int **txdata;
  double **s_re,**s_im,**r_re,**r_im;
93 94
  //double iqim = 0.0;
  //unsigned char pbch_pdu[6];
95 96 97 98 99
  //  int sync_pos, sync_pos_slot;
  //  FILE *rx_frame_file;
  FILE *output_fd = NULL;
  uint8_t write_output_file=0;
  //int result;
100
  //int freq_offset;
101 102
  //  int subframe_offset;
  //  char fname[40], vname[40];
103
  int trial,n_trials=1,n_errors=0,n_errors_payload=0;
104 105 106 107
  uint8_t transmission_mode = 1,n_tx=1,n_rx=1;
  uint16_t Nid_cell=0;

  channel_desc_t *gNB2UE;
108

109 110 111 112
  uint8_t extended_prefix_flag=0;
  int8_t interf1=-21,interf2=-21;

  FILE *input_fd=NULL,*pbch_file_fd=NULL;
113

114 115 116 117 118
  //uint32_t nsymb,tx_lev,tx_lev1 = 0,tx_lev2 = 0;
  //char input_val_str[50],input_val_str2[50];
  //uint8_t frame_mod4,num_pdcch_symbols = 0;
  //double pbch_sinr;
  //int pbch_tx_ant;
119 120 121

  SCM_t channel_model=AWGN;//Rayleigh1_anticorr;

122

knopp's avatar
knopp committed
123
  int N_RB_DL=273,mu=1;
124 125 126 127 128 129 130 131

  unsigned char frame_type = 0;
  unsigned char pbch_phase = 0;

  int frame=0,subframe=0;
  int frame_length_complex_samples;
  int frame_length_complex_samples_no_prefix;
  NR_DL_FRAME_PARMS *frame_parms;
132
  nfapi_nr_config_request_t *gNB_config;
Florian Kaltenberger's avatar
Florian Kaltenberger committed
133

Guy De Souza's avatar
Guy De Souza committed
134
  int ret, payload_ret=0;
135 136
  int run_initial_sync=0;

137 138
  int loglvl=OAILOG_WARNING;

139 140
  float target_error_rate = 0.01;

141 142 143 144 145 146
  cpuf = get_cpu_freq_GHz();

  if ( load_configmodule(argc,argv) == 0) {
    exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
  }

147
  randominit(0);
148

149
  while ((c = getopt (argc, argv, "f:hA:pf:g:i:j:n:s:S:t:x:y:z:N:F:GR:dP:IL:")) != -1) {
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 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
    switch (c) {
    case 'f':
      write_output_file=1;
      output_fd = fopen(optarg,"w");

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

      break;

    case 'd':
      frame_type = 1;
      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;

      default:
        msg("Unsupported channel model!\n");
        exit(-1);
      }

      break;

    case 'i':
      interf1=atoi(optarg);
      break;

    case 'j':
      interf2=atoi(optarg);
      break;

    case 'n':
212
      n_trials = atoi(optarg);
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 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 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
      break;

    case 's':
      snr0 = atof(optarg);
      msg("Setting SNR0 to %f\n",snr0);
      break;

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

      /*
      case 't':
      Td= atof(optarg);
      break;
      */
    case 'p':
      extended_prefix_flag=1;
      break;

      /*
      case 'r':
      ricean_factor = pow(10,-.1*atof(optarg));
      if (ricean_factor>1) {
        printf("Ricean factor must be between 0 and 1\n");
        exit(-1);
      }
      break;
      */
    case 'x':
      transmission_mode=atoi(optarg);

      if ((transmission_mode!=1) &&
          (transmission_mode!=2) &&
          (transmission_mode!=6)) {
        msg("Unsupported transmission mode %d\n",transmission_mode);
        exit(-1);
      }

      break;

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

      if ((n_tx==0) || (n_tx>2)) {
        msg("Unsupported number of tx antennas %d\n",n_tx);
        exit(-1);
      }

      break;

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

      if ((n_rx==0) || (n_rx>2)) {
        msg("Unsupported number of rx antennas %d\n",n_rx);
        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 'P':
      pbch_phase = atoi(optarg);

      if (pbch_phase>3)
        printf("Illegal PBCH phase (0-3) got %d\n",pbch_phase);

      break;
301 302 303
      
    case 'I':
      run_initial_sync=1;
304
      target_error_rate=0.1;
305
      break;
306 307 308 309 310

    case 'L':
      loglvl = atoi(optarg);
      break;

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    default:
    case 'h':
      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]);
      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("-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");
      //    printf("-C Generate Calibration information for Abstraction (effective SNR adjustment to remove Pe bias w.r.t. AWGN)\n");
      printf("-f Output filename (.txt format) for Pe/SNR results\n");
      printf("-F Input filename (.txt format) for RX conformance testing\n");
      exit (-1);
      break;
    }
  }

340 341 342 343
  logInit();
  set_glog(loglvl);
  T_stdout = 1;

Florian Kaltenberger's avatar
Florian Kaltenberger committed
344 345 346
  if (snr1set==0)
    snr1 = snr0+10;

knopp's avatar
knopp committed
347
  printf("Initializing gNodeB for mu %d, N_RB_DL %d\n",mu,N_RB_DL);
348 349 350 351 352

  RC.gNB = (PHY_VARS_gNB***) malloc(sizeof(PHY_VARS_gNB **));
  RC.gNB[0] = (PHY_VARS_gNB**) malloc(sizeof(PHY_VARS_gNB *));
  RC.gNB[0][0] = malloc(sizeof(PHY_VARS_gNB));
  gNB = RC.gNB[0][0];
353
  gNB_config = &gNB->gNB_config;
354
  frame_parms = &gNB->frame_parms; //to be initialized I suppose (maybe not necessary for PBCH)
355 356 357
  frame_parms->nb_antennas_tx = n_tx;
  frame_parms->nb_antennas_rx = n_rx;
  frame_parms->N_RB_DL = N_RB_DL;
knopp's avatar
knopp committed
358
  frame_parms->N_RB_UL = N_RB_DL;
359

knopp's avatar
knopp committed
360
  nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu);
361 362
  phy_init_nr_gNB(gNB,0,0);

knopp's avatar
knopp committed
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
  double fs,bw;

  if (mu == 1 && N_RB_DL == 217) { 
    fs = 122.88e6;
    bw = 80e6;
  }					       
  else if (mu == 1 && N_RB_DL == 245) {
    fs = 122.88e6;
    bw = 90e6;
  }
  else if (mu == 1 && N_RB_DL == 273) {
    fs = 122.88e6;
    bw = 100e6;
  }
  else if (mu == 1 && N_RB_DL == 106) { 
    fs = 61.44e6;
    bw = 40e6;
  }
  else AssertFatal(1==0,"Unsupported numerology for mu %d, N_RB %d\n",mu, N_RB_DL);

  gNB2UE = new_channel_desc_scm(n_tx,
                                n_rx,
                                channel_model,
 				fs, 
				bw, 
                                0,
                                0,
                                0);

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

397
  frame_length_complex_samples = frame_parms->samples_per_subframe*NR_NUMBER_OF_SUBFRAMES_PER_FRAME;
398 399
  frame_length_complex_samples_no_prefix = frame_parms->samples_per_subframe_wCP;

400 401 402 403 404 405
  s_re = malloc(2*sizeof(double*));
  s_im = malloc(2*sizeof(double*));
  r_re = malloc(2*sizeof(double*));
  r_im = malloc(2*sizeof(double*));
  txdata = malloc(2*sizeof(int*));

406 407 408 409 410 411 412 413 414 415 416 417
  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));

knopp's avatar
knopp committed
418
    printf("Allocating %d samples for txdata\n",frame_length_complex_samples);
419 420 421 422
    txdata[i] = malloc(frame_length_complex_samples*sizeof(int));
    bzero(r_re[i],frame_length_complex_samples*sizeof(int));
  
  }
423 424 425 426 427

  if (pbch_file_fd!=NULL) {
    load_pbch_desc(pbch_file_fd);
  }

428 429 430 431

  //configure UE
  UE = malloc(sizeof(PHY_VARS_NR_UE));
  memcpy(&UE->frame_parms,frame_parms,sizeof(NR_DL_FRAME_PARMS));
432
  //phy_init_nr_top(UE); //called from init_nr_ue_signal
433 434 435
  if (run_initial_sync==1)  UE->is_synchronized = 0;
  else                      UE->is_synchronized = 1;
                      
knopp's avatar
knopp committed
436 437
  UE->perfect_ce = 0;

438 439 440 441 442 443
  if (init_nr_ue_signal(UE, 1, 0) != 0)
  {
    printf("Error at UE NR initialisation\n");
    exit(-1);
  }

444
  nr_gold_pbch(UE);
445
  // generate signal
446
  if (input_fd==NULL) {
knopp's avatar
knopp committed
447
    gNB->pbch_configured = 1;
448
    for (int i=0;i<4;i++) gNB->pbch_pdu[i]=i+1;
449 450
    nr_common_signal_procedures (gNB,frame,subframe);

451 452 453
	LOG_M("txsigF0.m","txsF0", gNB->common_vars.txdataF[0],frame_length_complex_samples_no_prefix,1,1);
	if (gNB->frame_parms.nb_antennas_tx>1)
	LOG_M("txsigF1.m","txsF1", gNB->common_vars.txdataF[1],frame_length_complex_samples_no_prefix,1,1);
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
    //TODO: loop over slots
    for (aa=0; aa<gNB->frame_parms.nb_antennas_tx; aa++) {
      if (gNB_config->subframe_config.dl_cyclic_prefix_type.value == 1) {
	PHY_ofdm_mod(gNB->common_vars.txdataF[aa],
		     txdata[aa],
		     frame_parms->ofdm_symbol_size,
		     12,
		     frame_parms->nb_prefix_samples,
		     CYCLIC_PREFIX);
      } else {
	nr_normal_prefix_mod(gNB->common_vars.txdataF[aa],
			     txdata[aa],
			     14,
			     frame_parms);
      }
    }
  } else {
    printf("Reading %d samples from file to antenna buffer %d\n",frame_length_complex_samples,0);
    
    if (fread(txdata[0],
	      sizeof(int32_t),
	      frame_length_complex_samples,
	      input_fd) != frame_length_complex_samples) {
      printf("error reading from file\n");
      exit(-1);
480 481
    }
  }
482

483 484 485
  LOG_M("txsig0.m","txs0", txdata[0],frame_length_complex_samples,1,1);
  if (gNB->frame_parms.nb_antennas_tx>1)
    LOG_M("txsig1.m","txs1", txdata[1],frame_length_complex_samples,1,1);
486 487 488 489

  if (output_fd) 
    fwrite(txdata[0],sizeof(int32_t),frame_length_complex_samples,output_fd);

knopp's avatar
knopp committed
490 491 492
  int txlev = signal_energy(&txdata[0][5*frame_parms->ofdm_symbol_size + 4*frame_parms->nb_prefix_samples + frame_parms->nb_prefix_samples0],
			    frame_parms->ofdm_symbol_size + frame_parms->nb_prefix_samples);

493
  //  printf("txlev %d (%f)\n",txlev,10*log10(txlev));
494 495 496

  for (i=0; i<frame_length_complex_samples; i++) {
    for (aa=0; aa<frame_parms->nb_antennas_tx; aa++) {
497 498
      r_re[aa][i] = ((double)(((short *)txdata[aa]))[(i<<1)]);
      r_im[aa][i] = ((double)(((short *)txdata[aa]))[(i<<1)+1]);
499
    }
knopp's avatar
knopp committed
500
  }
501 502 503 504
  
  for (SNR=snr0; SNR<snr1; SNR+=.2) {

    n_errors = 0;
505
    n_errors_payload = 0;
506 507 508

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

509 510
      // multipath channel
      //multipath_channel(gNB2UE,s_re,s_im,r_re,r_im,frame_length_complex_samples,0);
511 512
      
      //AWGN
513
      sigma2_dB = 10*log10((double)txlev)-SNR;
514
      sigma2 = pow(10,sigma2_dB/10);
515
      //      printf("sigma2 %f (%f dB)\n",sigma2,sigma2_dB);
knopp's avatar
knopp committed
516

517
      for (i=0; i<frame_parms->samples_per_subframe; i++) {
518 519
	for (aa=0; aa<frame_parms->nb_antennas_rx; aa++) {
	  
520 521
	  ((short*) UE->common_vars.rxdata[aa])[2*i]   = (short) ((r_re[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
	  ((short*) UE->common_vars.rxdata[aa])[2*i+1] = (short) ((r_im[aa][i] + sqrt(sigma2/2)*gaussdouble(0.0,1.0)));
522 523
	}
      }
524 525

      if (n_trials==1) {
526
	LOG_M("rxsig0.m","rxs0", UE->common_vars.rxdata[0],frame_parms->samples_per_subframe,1,1);
527
	if (gNB->frame_parms.nb_antennas_tx>1)
528
	  LOG_M("rxsig1.m","rxs1", UE->common_vars.rxdata[1],frame_parms->samples_per_subframe,1,1);
529
      }
530

531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563
      if (UE->is_synchronized == 0) {
	ret = nr_initial_sync(UE, normal_txrx);
	printf("nr_initial_sync1 returns %d\n",ret);
	if (ret<0) n_errors++;
      }
      else {
	UE->rx_offset=0;
	//symbol 1
	nr_slot_fep(UE,
		    5,
		    0,
		    0,
		    0,
		    1,
		    NR_PBCH_EST);
	
	//symbol 2
	nr_slot_fep(UE,
		    6,
		    0,
		    0,
		    0,
		    1,
		    NR_PBCH_EST);
	
	//symbol 3
	nr_slot_fep(UE,
		    7,
		    0,
		    0,
		    0,
		    1,
		    NR_PBCH_EST);
564
	 
565 566 567 568 569 570 571
	ret = nr_rx_pbch(UE,
			 &UE->proc.proc_rxtx[0],
			 UE->pbch_vars[0],
			 frame_parms,
			 0,
			 SISO,
			 UE->high_speed_flag);
Florian Kaltenberger's avatar
Florian Kaltenberger committed
572

573 574 575
	if (ret==0) {
	  //UE->rx_ind.rx_indication_body->mib_pdu.ssb_index;  //not yet detected automatically
	  //UE->rx_ind.rx_indication_body->mib_pdu.ssb_length; //Lmax, not yet detected automatically
576 577 578 579 580
	  uint8_t gNB_xtra_byte=0;
	  for (int i=0; i<8; i++)
	    gNB_xtra_byte |= ((gNB->pbch.pbch_a>>(31-i))&1)<<(7-i);
	  
	  payload_ret = (UE->rx_ind.rx_indication_body->mib_pdu.additional_bits == gNB_xtra_byte);
Guy De Souza's avatar
Guy De Souza committed
581
	  for (i=0;i<3;i++){
582 583 584
	    payload_ret += (UE->rx_ind.rx_indication_body->mib_pdu.pdu[i] == gNB->pbch_pdu[2-i]);
	    //printf("pdu byte %d gNB: 0x%02x UE: 0x%02x\n",i,gNB->pbch_pdu[i], UE->rx_ind.rx_indication_body->mib_pdu.pdu[i]); 
	  } 
Guy De Souza's avatar
Guy De Souza committed
585
	  //printf("xtra byte gNB: 0x%02x UE: 0x%02x\n",gNB_xtra_byte, UE->rx_ind.rx_indication_body->mib_pdu.additional_bits);
586
	  //printf("ret %d\n", payload_ret);
587 588
	  if (payload_ret!=4) 
	    n_errors_payload++;
589 590
	}

knopp's avatar
knopp committed
591
	if (ret!=0) n_errors++;
592
      }
593 594
    } //noise trials

595
    printf("SNR %f: trials %d, n_errors_crc = %d, n_errors_payload %d\n", SNR,n_trials,n_errors,n_errors_payload);
596

597
    if (((float)n_errors/(float)n_trials <= target_error_rate) && (n_errors_payload==0)) {
598 599 600 601
      printf("PBCH test OK\n");
      break;
    }
      
602 603 604
    if (n_trials==1)
      break;

605 606 607 608 609 610 611
  } // NSR

  for (i=0; i<2; i++) {
    free(s_re[i]);
    free(s_im[i]);
    free(r_re[i]);
    free(r_im[i]);
612
    free(txdata[i]);
613 614 615 616 617 618
  }

  free(s_re);
  free(s_im);
  free(r_re);
  free(r_im);
619
  free(txdata);
620

621
  if (output_fd)
622 623
    fclose(output_fd);

624 625 626
  if (input_fd)
    fclose(input_fd);

627 628 629 630 631 632
  return(n_errors);

}