lte_sync_time.c 14.8 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * 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
 */
ghaddab's avatar
ghaddab committed
21

22 23 24
/* file: lte_sync_time.c
   purpose: coarse timing synchronization for LTE (using PSS)
   author: florian.kaltenberger@eurecom.fr, oscar.tonelli@yahoo.it
25
   date: 22.10.2009
26 27 28 29
*/

//#include <string.h>
#include <math.h>
yilmazt's avatar
yilmazt committed
30 31
#include "PHY/defs_UE.h"
#include "PHY/phy_extern_ue.h"
Raymond Knopp's avatar
Raymond Knopp committed
32
#include "PHY/LTE_REFSIG/lte_refsig.h"
33

34 35
// Note: this is for prototype of generate_drs_pusch (OTA synchronization of RRUs)
#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
36

Laurent THOMAS's avatar
Laurent THOMAS committed
37 38 39
static struct complex16 *primary_synch0_time __attribute__((aligned(32)));
static struct complex16 *primary_synch1_time __attribute__((aligned(32)));
static struct complex16 *primary_synch2_time __attribute__((aligned(32)));
40

Laurent THOMAS's avatar
Laurent THOMAS committed
41 42
static void doIdft(int size, short *in, short *out) {
  switch (size) {
43
  case 6:
Laurent THOMAS's avatar
Laurent THOMAS committed
44
      idft(IDFT_128,in,out,1);
45
    break;
Laurent THOMAS's avatar
Laurent THOMAS committed
46

47
  case 25:
Laurent THOMAS's avatar
Laurent THOMAS committed
48
      idft(IDFT_512,in,out,1);
49
    break;
Laurent THOMAS's avatar
Laurent THOMAS committed
50

51
  case 50:
Laurent THOMAS's avatar
Laurent THOMAS committed
52
      idft(IDFT_1024,in,out,1);
53 54 55
    break;
    
  case 75:
Laurent THOMAS's avatar
Laurent THOMAS committed
56
      idft(IDFT_1536,in,out,1);
57
    break;
Laurent THOMAS's avatar
Laurent THOMAS committed
58

59
  case 100:
Laurent THOMAS's avatar
Laurent THOMAS committed
60
      idft(IDFT_2048,in,out,1);
61
    break;
Laurent THOMAS's avatar
Laurent THOMAS committed
62

63
  default:
Laurent THOMAS's avatar
Laurent THOMAS committed
64 65
      LOG_E(PHY,"Unsupported N_RB_DL %d\n",size);
      abort();
66
    break;
67 68 69
    }
  }

Laurent THOMAS's avatar
Laurent THOMAS committed
70 71
static void copyPrimary( struct complex16 *out, struct complex16 *in, int ofdmSize) {
  int k=ofdmSize-36;
72
    
Laurent THOMAS's avatar
Laurent THOMAS committed
73
  for (int i=0; i<72; i++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
74 75
    out[k].r = in[i].r>>1;  //we need to shift input to avoid overflow in fft
    out[k].i = in[i].i>>1;
76
    k++;
77

Laurent THOMAS's avatar
Laurent THOMAS committed
78
    if (k >= ofdmSize) {
79
      k++;  // skip DC carrier
Laurent THOMAS's avatar
Laurent THOMAS committed
80
      k-=ofdmSize;
81 82
    }
  }
83
  }
84

Laurent THOMAS's avatar
Laurent THOMAS committed
85
int lte_sync_time_init(LTE_DL_FRAME_PARMS *frame_parms ) { // LTE_UE_COMMON *common_vars
Laurent THOMAS's avatar
Laurent THOMAS committed
86
  struct complex16 syncF_tmp[2048]__attribute__((aligned(32)))= {{0}};
Laurent THOMAS's avatar
Laurent THOMAS committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100
  int sz=frame_parms->ofdm_symbol_size*sizeof(*primary_synch0_time);
  AssertFatal( NULL != (primary_synch0_time = (struct complex16 *)malloc16(sz)),"");
  bzero(primary_synch0_time,sz);
  AssertFatal( NULL != (primary_synch1_time = (struct complex16 *)malloc16(sz)),"");
  bzero(primary_synch1_time,sz);
  AssertFatal( NULL != (primary_synch2_time = (struct complex16 *)malloc16(sz)),"");
  bzero(primary_synch2_time,sz);
  // generate oversampled sync_time sequences
  copyPrimary( syncF_tmp, (struct complex16 *) primary_synch0, frame_parms->ofdm_symbol_size);
  doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch0_time);
  copyPrimary( syncF_tmp, (struct complex16 *) primary_synch1, frame_parms->ofdm_symbol_size);
  doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch1_time);
  copyPrimary( syncF_tmp, (struct complex16 *) primary_synch2, frame_parms->ofdm_symbol_size);
  doIdft(frame_parms->N_RB_DL, (short *)syncF_tmp,(short *)primary_synch2_time);
101

102
  if ( LOG_DUMPFLAG(DEBUG_LTEESTIM)){
103 104 105 106
    LOG_M("primary_sync0.m","psync0",primary_synch0_time,frame_parms->ofdm_symbol_size,1,1);
    LOG_M("primary_sync1.m","psync1",primary_synch1_time,frame_parms->ofdm_symbol_size,1,1);
    LOG_M("primary_sync2.m","psync2",primary_synch2_time,frame_parms->ofdm_symbol_size,1,1);
  }
Laurent THOMAS's avatar
Laurent THOMAS committed
107

108 109 110 111
  return (1);
}


Laurent THOMAS's avatar
Laurent THOMAS committed
112
void lte_sync_time_free(void) {
113
  if (primary_synch0_time) {
114
    LOG_D(PHY,"Freeing primary_sync0_time ...\n");
115 116
    free(primary_synch0_time);
  }
117

118
  if (primary_synch1_time) {
119
    LOG_D(PHY,"Freeing primary_sync1_time ...\n");
120 121
    free(primary_synch1_time);
  }
122

123
  if (primary_synch2_time) {
124
    LOG_D(PHY,"Freeing primary_sync2_time ...\n");
125 126
    free(primary_synch2_time);
  }
127

128 129 130
  primary_synch0_time = NULL;
  primary_synch1_time = NULL;
  primary_synch2_time = NULL;
131 132
}

yilmazt's avatar
yilmazt committed
133

Laurent THOMAS's avatar
Laurent THOMAS committed
134
static inline int abs32(int x) {
135 136 137
  return (((int)((short*)&x)[0])*((int)((short*)&x)[0]) + ((int)((short*)&x)[1])*((int)((short*)&x)[1]));
}

Laurent THOMAS's avatar
Laurent THOMAS committed
138 139
static inline double absF(struct complexd x) {
  return x.r*x.r+x.i*x.i;
140 141
}

Laurent THOMAS's avatar
Laurent THOMAS committed
142
#define complexNull(c) bzero((void*) &(c), sizeof(c))
yilmazt's avatar
yilmazt committed
143

144 145
#define SHIFT 17

yilmazt's avatar
yilmazt committed
146

147
int lte_sync_time(int **rxdata, ///rx data in time domain
148
                  LTE_DL_FRAME_PARMS *frame_parms,
Laurent THOMAS's avatar
Laurent THOMAS committed
149
                  int *eNB_id) {
150 151 152
  // perform a time domain correlation using the oversampled sync sequence
  unsigned int n, ar, s, peak_pos, peak_val, sync_source;
  int result,result2;
Laurent THOMAS's avatar
Laurent THOMAS committed
153
  struct complexd sync_out[3]= {{0}}, sync_out2[3]= {{0}};
154 155 156 157 158 159
  int length =   LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti>>1;
  peak_val = 0;
  peak_pos = 0;
  sync_source = 0;

  for (n=0; n<length; n+=4) {
160
    for (s=0; s<3; s++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
161 162
      complexNull(sync_out[s]);
      complexNull(sync_out2[s]);
163
    }
164

165 166 167
    //    if (n<(length-frame_parms->ofdm_symbol_size-frame_parms->nb_prefix_samples)) {
    if (n<(length-frame_parms->ofdm_symbol_size)) {
      //calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
168
      for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
169 170 171 172 173 174
        result  = dot_product((short *)primary_synch0_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
        result2 = dot_product((short *)primary_synch0_time, (short *) &(rxdata[ar][n+length]), frame_parms->ofdm_symbol_size, SHIFT);
        sync_out[0].r += ((short *) &result)[0];
        sync_out[0].i += ((short *) &result)[1];
        sync_out2[0].r += ((short *) &result2)[0];
        sync_out2[0].i += ((short *) &result2)[1];
175
      }
176 177

      for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
178 179 180 181 182 183
        result = dot_product((short *)primary_synch1_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
        result2 = dot_product((short *)primary_synch1_time, (short *) &(rxdata[ar][n+length]), frame_parms->ofdm_symbol_size, SHIFT);
        sync_out[1].r += ((short *) &result)[0];
        sync_out[1].i += ((short *) &result)[1];
        sync_out2[1].r += ((short *) &result2)[0];
        sync_out2[1].i += ((short *) &result2)[1];
184 185
      }

186
      for (ar=0; ar<frame_parms->nb_antennas_rx; ar++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
187 188 189 190 191 192
        result = dot_product((short *)primary_synch2_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
        result2 = dot_product((short *)primary_synch2_time, (short *) &(rxdata[ar][n+length]), frame_parms->ofdm_symbol_size, SHIFT);
        sync_out[2].r += ((short *) &result)[0];
        sync_out[2].i += ((short *) &result)[1];
        sync_out2[2].r += ((short *) &result2)[0];
        sync_out2[2].i += ((short *) &result2)[1];
193 194
      }
    }
195

196 197
    // calculate the absolute value of sync_corr[n]

198
    for (s=0; s<3; s++) {
Laurent THOMAS's avatar
Laurent THOMAS committed
199
      double tmp = absF(sync_out[s]) + absF(sync_out2[s]);
200

Laurent THOMAS's avatar
Laurent THOMAS committed
201 202
      if (tmp>peak_val) {
        peak_val = tmp;
203 204 205 206 207 208 209
        peak_pos = n;
        sync_source = s;
        /*
        printf("s %d: n %d sync_out %d, sync_out2  %d (sync_corr %d,%d), (%d,%d) (%d,%d)\n",s,n,abs32(sync_out[s]),abs32(sync_out2[s]),sync_corr_ue0[n],
               sync_corr_ue0[n+length],((int16_t*)&sync_out[s])[0],((int16_t*)&sync_out[s])[1],((int16_t*)&sync_out2[s])[0],((int16_t*)&sync_out2[s])[1]);
        */
      }
210 211 212 213
    }
  }

  *eNB_id = sync_source;
Laurent THOMAS's avatar
Laurent THOMAS committed
214
  LOG_I(PHY,"[UE] lte_sync_time: Sync source = %d, Peak found at pos %d, val = %d (%d dB)\n",sync_source,peak_pos,peak_val/2,dB_fixed(peak_val/2)/2);
215 216 217
  return(peak_pos);
}

218

Laurent THOMAS's avatar
Laurent THOMAS committed
219
int ru_sync_time_init(RU_t *ru) { // LTE_UE_COMMON *common_vars
magounak's avatar
magounak committed
220
  /*
221 222
  int16_t dmrs[2048];
  int16_t *dmrsp[2] = {dmrs,NULL};
magounak's avatar
magounak committed
223
  */
yilmazt's avatar
yilmazt committed
224 225
  int32_t dmrs[ru->frame_parms->ofdm_symbol_size*14] __attribute__((aligned(32)));
  //int32_t *dmrsp[2] = {&dmrs[(3-ru->frame_parms->Ncp)*ru->frame_parms->ofdm_symbol_size],NULL};
226
  int32_t *dmrsp[2] = {&dmrs[0],NULL};
magounak's avatar
magounak committed
227
  generate_ul_ref_sigs();
Laurent THOMAS's avatar
Laurent THOMAS committed
228 229
  ru->dmrssync = (int16_t *)malloc16_clear(ru->frame_parms->ofdm_symbol_size*2*sizeof(int16_t));
  ru->dmrs_corr = (uint64_t *)malloc16_clear(ru->frame_parms->samples_per_tti*10*sizeof(uint64_t));
yilmazt's avatar
yilmazt committed
230 231 232 233 234 235 236 237 238 239 240 241
  generate_drs_pusch(NULL,
                     NULL,
                     ru->frame_parms,
                     dmrsp,
                     0,
                     AMP,
                     0,
                     0,
                     ru->frame_parms->N_RB_DL,
                     0);

  switch (ru->frame_parms->N_RB_DL) {
Laurent THOMAS's avatar
Laurent THOMAS committed
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
    case 6:
      idft(IDFT_128,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
           ru->dmrssync, /// complex output
           1);
      break;

    case 25:
      idft(IDFT_512,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
           ru->dmrssync, /// complex output
           1);
      break;

    case 50:
      idft(IDFT_1024,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
           ru->dmrssync, /// complex output
           1);
      break;

    case 75:
      idft(IDFT_1536,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
           ru->dmrssync,
           1); /// complex output
      break;

    case 100:
      idft(IDFT_2048,(int16_t *)(&dmrsp[0][3*ru->frame_parms->ofdm_symbol_size]),
           ru->dmrssync, /// complex output
           1);
      break;

    default:
      AssertFatal(1==0,"Unsupported N_RB_DL %d\n",ru->frame_parms->N_RB_DL);
      break;
275 276 277 278 279
  }

  return(0);
}

yilmazt's avatar
yilmazt committed
280

281 282 283
void ru_sync_time_free(RU_t *ru) {
  AssertFatal(ru->dmrssync!=NULL,"ru->dmrssync is NULL\n");
  free(ru->dmrssync);
Laurent THOMAS's avatar
Laurent THOMAS committed
284 285 286

  if (ru->dmrs_corr)
    free(ru->dmrs_corr);
287 288
}

289 290
//#define DEBUG_PHY

291
int lte_sync_time_eNB(int32_t **rxdata, ///rx data in time domain
292 293 294
                      LTE_DL_FRAME_PARMS *frame_parms,
                      uint32_t length,
                      uint32_t *peak_val_out,
Laurent THOMAS's avatar
Laurent THOMAS committed
295
                      uint32_t *sync_corr_eNB) {
296
  // perform a time domain correlation using the oversampled sync sequence
297 298
  unsigned int n, ar, peak_val, peak_pos;
  uint64_t mean_val;
299 300 301 302
  int result;
  short *primary_synch_time;
  int eNB_id = frame_parms->Nid_cell%3;

303
  // LOG_E(PHY,"[SYNC TIME] Calling sync_time_eNB(%p,%p,%d,%d)\n",rxdata,frame_parms,eNB_id,length);
304
  if (sync_corr_eNB == NULL) {
305
    LOG_E(PHY,"[SYNC TIME] sync_corr_eNB not yet allocated! Exiting.\n");
306 307 308 309
    return(-1);
  }

  switch (eNB_id) {
Laurent THOMAS's avatar
Laurent THOMAS committed
310 311 312
    case 0:
      primary_synch_time = (short *)primary_synch0_time;
      break;
313

Laurent THOMAS's avatar
Laurent THOMAS committed
314 315 316
    case 1:
      primary_synch_time = (short *)primary_synch1_time;
      break;
317

Laurent THOMAS's avatar
Laurent THOMAS committed
318 319 320
    case 2:
      primary_synch_time = (short *)primary_synch2_time;
      break;
321

Laurent THOMAS's avatar
Laurent THOMAS committed
322 323 324
    default:
      LOG_E(PHY,"[SYNC TIME] Illegal eNB_id!\n");
      return (-1);
325 326 327 328 329 330 331 332 333 334 335
  }

  peak_val = 0;
  peak_pos = 0;
  mean_val = 0;

  for (n=0; n<length; n+=4) {
    sync_corr_eNB[n] = 0;

    if (n<(length-frame_parms->ofdm_symbol_size-frame_parms->nb_prefix_samples)) {
      //calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
336
      for (ar=0; ar<frame_parms->nb_antennas_rx; ar++)  {
Laurent THOMAS's avatar
Laurent THOMAS committed
337
        result = dot_product((short *)primary_synch_time, (short *) &(rxdata[ar][n]), frame_parms->ofdm_symbol_size, SHIFT);
338 339 340
        //((short*)sync_corr)[2*n]   += ((short*) &result)[0];
        //((short*)sync_corr)[2*n+1] += ((short*) &result)[1];
        sync_corr_eNB[n] += abs32(result);
341 342
      }
    }
343

344 345 346
    /*
    if (eNB_id == 2) {
      printf("sync_time_eNB %d : %d,%d (%d)\n",n,sync_corr_eNB[n],mean_val,
347
       peak_val);
348 349
    }
    */
350
    mean_val += sync_corr_eNB[n];
351 352 353 354 355 356 357

    if (sync_corr_eNB[n]>peak_val) {
      peak_val = sync_corr_eNB[n];
      peak_pos = n;
    }
  }

358
  mean_val/=length;
359 360
  *peak_val_out = peak_val;

361
  if (peak_val <= (40*(uint32_t)mean_val)) {
Eurecom's avatar
Eurecom committed
362
    LOG_I(PHY,"[SYNC TIME] No peak found (%u,%u,%"PRIu64",%"PRIu64")\n",peak_pos,peak_val,mean_val,40*mean_val);
363
    return(-1);
364
  } else {
Eurecom's avatar
Eurecom committed
365
    LOG_I(PHY,"[SYNC TIME] Peak found at pos %u, val = %u, mean_val = %"PRIu64"\n",peak_pos,peak_val,mean_val);
366 367 368 369
    return(peak_pos);
  }
}

yilmazt's avatar
yilmazt committed
370

Laurent THOMAS's avatar
Laurent THOMAS committed
371 372 373
static inline int64_t abs64(int64_t x) {
  return (((int64_t)((int32_t *)&x)[0])*((int64_t)((int32_t *)&x)[0]) + ((int64_t)
          ((int32_t *)&x)[1])*((int64_t)((int32_t *)&x)[1]));
374
}
375

yilmazt's avatar
yilmazt committed
376

377
int ru_sync_time(RU_t *ru,
yilmazt's avatar
yilmazt committed
378
                 int64_t *lev,
Laurent THOMAS's avatar
Laurent THOMAS committed
379
                 int64_t *avg) {
yilmazt's avatar
yilmazt committed
380
  LTE_DL_FRAME_PARMS *frame_parms = ru->frame_parms;
381
  RU_CALIBRATION *calibration = &ru->calibration;
382 383 384 385
  // perform a time domain correlation using the oversampled sync sequence
  int length =   LTE_NUMBER_OF_SUBFRAMES_PER_FRAME*frame_parms->samples_per_tti;

  // circular copy of beginning to end of rxdata buffer. Note: buffer should be big enough upon calling this function
Laurent THOMAS's avatar
Laurent THOMAS committed
386 387 388 389 390
  for (int ar=0; ar<ru->nb_rx; ar++)
    memcpy((void *)&ru->common.rxdata[ar][2*length],
           (void *)&ru->common.rxdata[ar][0],
           frame_parms->ofdm_symbol_size);

Raymond Knopp's avatar
Raymond Knopp committed
391
  int32_t maxlev0=0;
392 393
  int     maxpos0=0;
  int64_t avg0=0;
394 395 396
  int64_t result;
  int64_t dmrs_corr;
  int maxval=0;
Laurent THOMAS's avatar
Laurent THOMAS committed
397 398

  for (int i=0; i<2*(frame_parms->ofdm_symbol_size); i++) {
399 400 401
    maxval = max(maxval,ru->dmrssync[i]);
    maxval = max(maxval,-ru->dmrssync[i]);
  }
402 403

  if (ru->state == RU_CHECK_SYNC) {
Laurent THOMAS's avatar
Laurent THOMAS committed
404 405 406 407
    for (int i=0; i<2*(frame_parms->ofdm_symbol_size); i++) {
      maxval = max(maxval,calibration->drs_ch_estimates_time[0][i]);
      maxval = max(maxval,-calibration->drs_ch_estimates_time[0][i]);
    }
408 409
  }

410
  int shift = log2_approx(maxval);
411

412
  for (int n=0; n<length; n+=4) {
413
    dmrs_corr = 0;
414

415 416
    //calculate dot product of primary_synch0_time and rxdata[ar][n] (ar=0..nb_ant_rx) and store the sum in temp[n];
    for (int ar=0; ar<ru->nb_rx; ar++) {
417
      result  = dot_product64(ru->dmrssync,
Laurent THOMAS's avatar
Laurent THOMAS committed
418
                              (int16_t *) &ru->common.rxdata[ar][n],
419 420
                              frame_parms->ofdm_symbol_size,
                              shift);
Laurent THOMAS's avatar
Laurent THOMAS committed
421 422 423 424 425 426

      if (ru->state == RU_CHECK_SYNC) {
        result  = dot_product64((int16_t *) &calibration->drs_ch_estimates_time[ar],
                                (int16_t *) &ru->common.rxdata[ar][n],
                                frame_parms->ofdm_symbol_size,
                                shift);
427
      }
Laurent THOMAS's avatar
Laurent THOMAS committed
428

429
      dmrs_corr += abs64(result);
430
    }
Laurent THOMAS's avatar
Laurent THOMAS committed
431 432 433

    if (ru->dmrs_corr != NULL)
      ru->dmrs_corr[n] = dmrs_corr;
434 435 436

    // tmpi holds <synchi,rx0>+<synci,rx1>+...+<synchi,rx_{nbrx-1}>

Laurent THOMAS's avatar
Laurent THOMAS committed
437 438 439 440
    if (dmrs_corr>maxlev0) {
      maxlev0 = dmrs_corr;
      maxpos0 = n;
    }
441

442
    avg0 += dmrs_corr;
443
  }
444

Laurent THOMAS's avatar
Laurent THOMAS committed
445
  avg0/=(length/4);
446
  int dmrsoffset = frame_parms->samples_per_tti + (3*frame_parms->ofdm_symbol_size)+(3*frame_parms->nb_prefix_samples) + frame_parms->nb_prefix_samples0;
Laurent THOMAS's avatar
Laurent THOMAS committed
447 448 449 450 451 452

  if ((int64_t)maxlev0 > (10*avg0)) {
    *lev = maxlev0;
    *avg=avg0;
    return((length+maxpos0-dmrsoffset)%length);
  }
453

454 455
  return(-1);
}