sss.c 12.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * 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.0  (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
 */
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

/*! \file PHY/LTE_TRANSPORT/sss.c
* \brief Top-level routines for generating and decoding the secondary synchronization signal (SSS) V8.6 2009-03
* \author R. Knopp
* \date 2011
* \version 0.1
* \company Eurecom
* \email: knopp@eurecom.fr
* \note
* \warning
*/
#include "PHY/defs.h"
#include "defs.h"
#include "PHY/extern.h"

//#define DEBUG_SSS


39
int generate_sss(int32_t **txdataF,
40
41
42
43
44
                 int16_t amp,
                 LTE_DL_FRAME_PARMS *frame_parms,
                 uint16_t symbol,
                 uint16_t slot_offset)
{
45

gauthier's avatar
gauthier committed
46
  uint8_t i,aa,Nsymb;
knopp's avatar
   
knopp committed
47
  int16_t *d,k;
gauthier's avatar
gauthier committed
48
49
  uint8_t Nid2;
  uint16_t Nid1;
knopp's avatar
   
knopp committed
50
  int16_t a;
51
52
53
54

  Nid2 = frame_parms->Nid_cell % 3;
  Nid1 = frame_parms->Nid_cell/3;

55
  if (slot_offset < 3)
56
57
58
59
    d = &d0_sss[62*(Nid2 + (Nid1*3))];
  else
    d = &d5_sss[62*(Nid2 + (Nid1*3))];

knopp's avatar
   
knopp committed
60
  Nsymb = (frame_parms->Ncp==NORMAL)?14:12;
61
  k = frame_parms->ofdm_symbol_size-3*12+5;
62
  a = (frame_parms->nb_antenna_ports_eNB == 1) ? amp : (amp*ONE_OVER_SQRT2_Q15)>>15;
63
64

  for (i=0; i<62; i++) {
65
    for (aa=0; aa<frame_parms->nb_antenna_ports_eNB; aa++) {
66

knopp's avatar
   
knopp committed
67
      ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb/2*frame_parms->ofdm_symbol_size +
68
69
                                 symbol*frame_parms->ofdm_symbol_size + k)] =
                                   (a * d[i]);
knopp's avatar
   
knopp committed
70
      ((int16_t*)txdataF[aa])[2*(slot_offset*Nsymb/2*frame_parms->ofdm_symbol_size +
71
                                 symbol*frame_parms->ofdm_symbol_size + k)+1] = 0;
knopp's avatar
   
knopp committed
72
    }
73

74
    k+=1;
75

76
77
78
79
80
    if (k >= frame_parms->ofdm_symbol_size) {
      k++;
      k-=frame_parms->ofdm_symbol_size;
    }
  }
81

82
83
84
  return(0);
}

85
int pss_ch_est(PHY_VARS_UE *ue,
86
87
88
               int32_t pss_ext[4][72],
               int32_t sss_ext[4][72])
{
89

knopp's avatar
   
knopp committed
90
91
  int16_t *pss;
  int16_t *pss_ext2,*sss_ext2,*sss_ext3,tmp_re,tmp_im,tmp_re2,tmp_im2;
gauthier's avatar
gauthier committed
92
  uint8_t aarx,i;
93
  LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
94

95
  switch (ue->common_vars.eNb_id) {
96

97
98
99
  case 0:
    pss = &primary_synch0[10];
    break;
100

101
102
103
  case 1:
    pss = &primary_synch1[10];
    break;
104

105
106
107
  case 2:
    pss = &primary_synch2[10];
    break;
108

109
110
111
112
113
  default:
    pss = &primary_synch0[10];
    break;
  }

knopp's avatar
   
knopp committed
114
  sss_ext3 = (int16_t*)&sss_ext[0][5];
115
116

  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
117

knopp's avatar
   
knopp committed
118
119
    sss_ext2 = (int16_t*)&sss_ext[aarx][5];
    pss_ext2 = (int16_t*)&pss_ext[aarx][5];
120
121

    for (i=0; i<62; i++) {
122
123

      // This is H*(PSS) = R* \cdot PSS
gauthier's avatar
gauthier committed
124
125
      tmp_re = (int16_t)(((pss_ext2[i<<1] * (int32_t)pss[i<<1])>>15)     + ((pss_ext2[1+(i<<1)] * (int32_t)pss[1+(i<<1)])>>15));
      tmp_im = (int16_t)(((pss_ext2[i<<1] * (int32_t)pss[1+(i<<1)])>>15) - ((pss_ext2[1+(i<<1)] * (int32_t)pss[(i<<1)])>>15));
126
127
      //      printf("H*(%d,%d) : (%d,%d)\n",aarx,i,tmp_re,tmp_im);
      // This is R(SSS) \cdot H*(PSS)
128
      tmp_re2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[i<<1])>>15)     - ((tmp_im * (int32_t)sss_ext2[1+(i<<1)]>>15)));
gauthier's avatar
gauthier committed
129
      tmp_im2 = (int16_t)(((tmp_re * (int32_t)sss_ext2[1+(i<<1)])>>15) + ((tmp_im * (int32_t)sss_ext2[(i<<1)]>>15)));
130
131

      //      printf("SSSi(%d,%d) : (%d,%d)\n",aarx,i,sss_ext2[i<<1],sss_ext2[1+(i<<1)]);
132
133
134
      //      printf("SSSo(%d,%d) : (%d,%d)\n",aarx,i,tmp_re2,tmp_im2);
      // MRC on RX antennas
      if (aarx==0) {
135
136
137
138
139
        sss_ext3[i<<1]      = tmp_re2;
        sss_ext3[1+(i<<1)]  = tmp_im2;
      } else {
        sss_ext3[i<<1]      += tmp_re2;
        sss_ext3[1+(i<<1)]  += tmp_im2;
140
141
142
      }
    }
  }
143

144
145
146
147
148
  // sss_ext now contains the compensated SSS
  return(0);
}


149
int _do_pss_sss_extract(PHY_VARS_UE *ue,
150
                    int32_t pss_ext[4][72],
151
                    int32_t sss_ext[4][72],
152
153
                    uint8_t doPss, uint8_t doSss,
					uint8_t subframe) // add flag to indicate extracting only PSS, only SSS, or both
154
155
156
{


157

gauthier's avatar
gauthier committed
158
159
160
161
  uint16_t rb,nb_rb=6;
  uint8_t i,aarx;
  int32_t *pss_rxF,*pss_rxF_ext;
  int32_t *sss_rxF,*sss_rxF_ext;
162
  LTE_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
163
164

  int rx_offset = frame_parms->ofdm_symbol_size-3*12;
gauthier's avatar
gauthier committed
165
  uint8_t pss_symb,sss_symb;
166

167
  int32_t **rxdataF;
168

169
170
  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {

171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
	  if (frame_parms->frame_type == FDD) {
	    pss_symb = 6-frame_parms->Ncp;
	    sss_symb = pss_symb-1;

	    rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[(subframe&0x1)].rxdataF;
	    pss_rxF  =  &rxdataF[aarx][(rx_offset + (pss_symb*(frame_parms->ofdm_symbol_size)))];
	    sss_rxF  =  &rxdataF[aarx][(rx_offset + (sss_symb*(frame_parms->ofdm_symbol_size)))];

	  } else {
	    pss_symb = 2;
	    sss_symb = frame_parms->symbols_per_tti-1;

	    rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[(subframe&0x1)].rxdataF;
	    sss_rxF  =  &rxdataF[aarx][(rx_offset + (sss_symb*(frame_parms->ofdm_symbol_size)))];

	    rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[((subframe+1)&0x1)].rxdataF;
	    pss_rxF  =  &rxdataF[aarx][(rx_offset + (pss_symb*(frame_parms->ofdm_symbol_size)))];

	  }
190
191
192
193
194
195
196
197
198
199
    //printf("extract_rbs: symbol_mod=%d, rx_offset=%d, ch_offset=%d\n",symbol_mod,
    //   (rx_offset + (symbol*(frame_parms->ofdm_symbol_size)))*2,
    //   LTE_CE_OFFSET+ch_offset+(symbol_mod*(frame_parms->ofdm_symbol_size)));

    pss_rxF_ext    = &pss_ext[aarx][0];
    sss_rxF_ext    = &sss_ext[aarx][0];

    for (rb=0; rb<nb_rb; rb++) {
      // skip DC carrier
      if (rb==3) {
200
201
202
203
204
205
206
207
208
209
210
211
212
        if(frame_parms->frame_type == FDD)
        {
          sss_rxF       = &rxdataF[aarx][(1 + (sss_symb*(frame_parms->ofdm_symbol_size)))];
          pss_rxF       = &rxdataF[aarx][(1 + (pss_symb*(frame_parms->ofdm_symbol_size)))];
        }
        else
        {
    	    rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[(subframe&0x1)].rxdataF;
    	    sss_rxF  =  &rxdataF[aarx][(1 + (sss_symb*(frame_parms->ofdm_symbol_size)))];

    	    rxdataF  =  ue->common_vars.common_vars_rx_data_per_thread[((subframe+1)&0x1)].rxdataF;
    	    pss_rxF  =  &rxdataF[aarx][(1 + (pss_symb*(frame_parms->ofdm_symbol_size)))];
        }
213
      }
214
215

      for (i=0; i<12; i++) {
216
217
        if (doPss) {pss_rxF_ext[i]=pss_rxF[i];}
        if (doSss) {sss_rxF_ext[i]=sss_rxF[i];}
218
      }
219

220
221
222
223
224
225
226
      pss_rxF+=12;
      sss_rxF+=12;
      pss_rxF_ext+=12;
      sss_rxF_ext+=12;
    }

  }
227

228
229
230
  return(0);
}

231
232
int pss_sss_extract(PHY_VARS_UE *phy_vars_ue,
                    int32_t pss_ext[4][72],
233
234
                    int32_t sss_ext[4][72],
					uint8_t subframe)
235
{
236
  return _do_pss_sss_extract(phy_vars_ue, pss_ext, sss_ext, 1 /* doPss */, 1 /* doSss */, subframe);
237
238
239
240
241
242
}

int pss_only_extract(PHY_VARS_UE *phy_vars_ue,
                    int32_t pss_ext[4][72])
{
  static int32_t dummy[4][72];
243
  return _do_pss_sss_extract(phy_vars_ue, pss_ext, dummy, 1 /* doPss */, 0 /* doSss */, 0);
244
245
246
247
248
249
250
}


int sss_only_extract(PHY_VARS_UE *phy_vars_ue,
                    int32_t sss_ext[4][72])
{
  static int32_t dummy[4][72];
251
  return _do_pss_sss_extract(phy_vars_ue, dummy, sss_ext, 0 /* doPss */, 1 /* doSss */, 0);
252
253
}

254

knopp's avatar
   
knopp committed
255
256
int16_t phase_re[7] = {16383, 25101, 30791, 32767, 30791, 25101, 16383};
int16_t phase_im[7] = {-28378, -21063, -11208, 0, 11207, 21062, 28377};
257
258


259
int rx_sss(PHY_VARS_UE *ue,int32_t *tot_metric,uint8_t *flip_max,uint8_t *phase_max)
260
261
{

gauthier's avatar
gauthier committed
262
263
264
  uint8_t i;
  int32_t pss_ext[4][72];
  int32_t sss0_ext[4][72],sss5_ext[4][72];
265
  uint8_t Nid2 = ue->common_vars.eNb_id;
gauthier's avatar
gauthier committed
266
267
268
  uint8_t flip,phase;
  uint16_t Nid1;
  int16_t *sss0,*sss5;
269
  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
gauthier's avatar
gauthier committed
270
271
  int32_t metric;
  int16_t *d0,*d5;
272

273
  if (frame_parms->frame_type == FDD) {
274
#ifdef DEBUG_SSS
275

276
277
    if (frame_parms->Ncp == NORMAL)
      msg("[PHY][UE%d] Doing SSS for FDD Normal Prefix\n",ue->Mod_id);
278
    else
279
      msg("[PHY][UE%d] Doing SSS for FDD Extended Prefix\n",ue->Mod_id);
280

281
282
283
#endif
    // Do FFTs for SSS/PSS
    // SSS
284
    slot_fep(ue,
285
286
             (frame_parms->symbols_per_tti/2)-2, // second to last symbol of
             0,                                  // slot 0
287
             ue->rx_offset,
288
289
             0,
	     1);
290
    // PSS
291
    slot_fep(ue,
292
293
             (frame_parms->symbols_per_tti/2)-1, // last symbol of
             0,                                  // slot 0
294
             ue->rx_offset,
295
296
             0,
	     1);
297
  } else { // TDD
298
#ifdef DEBUG_SSS
299
300
    if (ue->frame_parms->Ncp == NORMAL)
      msg("[PHY][UE%d] Doing SSS for TDD Normal Prefix\n",ue->Mod_id);
301
    else
302
      msg("[PHY][UE%d] Doing SSS for TDD Extended Prefix\n",ue->Mod_id);
303

304
305
#endif
    // SSS
306
    slot_fep(ue,
307
308
             (frame_parms->symbols_per_tti>>1)-1,  // last symbol of
             1,                                    // slot 1
309
             ue->rx_offset,
310
311
             0,
	     1);
312
    // PSS
313
    slot_fep(ue,
314
315
             2,                                   // symbol 2 of
             2,                                   // slot 2
316
             ue->rx_offset,
317
318
             0,
	     1);
319
  }
320
  // pss sss extract for subframe 0
321
  pss_sss_extract(ue,
322
                  pss_ext,
323
                  sss0_ext,0);
324
  /*
325
326
  write_output("rxsig0.m","rxs0",&ue->common_vars.rxdata[0][0],ue->frame_parms.samples_per_tti,1,1);
  write_output("rxdataF0.m","rxF0",&ue->common_vars.rxdataF[0][0],2*14*ue->frame_parms.ofdm_symbol_size,2,1);
327
328
329
330
  write_output("pss_ext0.m","pssext0",pss_ext,72,1,1);
  write_output("sss0_ext0.m","sss0ext0",sss0_ext,72,1,1);
  */

331
332
  // get conjugated channel estimate from PSS (symbol 6), H* = R* \cdot PSS
  // and do channel estimation and compensation based on PSS
333

334
  pss_ch_est(ue,
335
336
337
             pss_ext,
             sss0_ext);

338
339
  //  write_output("sss0_comp0.m","sss0comp0",sss0_ext,72,1,1);

340
  if (ue->frame_parms.frame_type == FDD) { // FDD
341
342

    // SSS
343
    slot_fep(ue,
344
345
             (frame_parms->symbols_per_tti/2)-2,
             10,
346
             ue->rx_offset,
347
             0,1);
348
    // PSS
349
    slot_fep(ue,
350
351
             (frame_parms->symbols_per_tti/2)-1,
             10,
352
             ue->rx_offset,
353
             0,1);
354
  } else { // TDD
355
    // SSS
356
    slot_fep(ue,
357
358
             (frame_parms->symbols_per_tti>>1)-1,
             11,
359
             ue->rx_offset,
360
361
             0,
	     1);
362
    // PSS
363
    slot_fep(ue,
364
365
             2,
             12,
366
             ue->rx_offset,
367
368
             0,
	     1);
369
  }
370

371
  // pss sss extract for subframe 5
372
  pss_sss_extract(ue,
373
                  pss_ext,
374
                  sss5_ext,5);
375
376
377
378

  //  write_output("sss5_ext0.m","sss5ext0",sss5_ext,72,1,1);
  // get conjugated channel estimate from PSS (symbol 6), H* = R* \cdot PSS
  // and do channel estimation and compensation based on PSS
379

380
  pss_ch_est(ue,
381
382
383
384
385
             pss_ext,
             sss5_ext);



386
  // now do the SSS detection based on the precomputed sequences in PHY/LTE_TRANSPORT/sss.h
387

388
  *tot_metric = -99999999;
389
390


knopp's avatar
   
knopp committed
391
392
  sss0 = (int16_t*)&sss0_ext[0][5];
  sss5 = (int16_t*)&sss5_ext[0][5];
393
394
395

  for (flip=0; flip<2; flip++) {      //  d0/d5 flip in RX frame
    for (phase=0; phase<7; phase++) { // phase offset between PSS and SSS
396
      for (Nid1 = 0 ; Nid1 <= 167; Nid1++) {  // 168 possible Nid1 values
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
        metric = 0;

        if (flip==0) {
          d0 = &d0_sss[62*(Nid2 + (Nid1*3))];
          d5 = &d5_sss[62*(Nid2 + (Nid1*3))];
        } else {
          d5 = &d0_sss[62*(Nid2 + (Nid1*3))];
          d0 = &d5_sss[62*(Nid2 + (Nid1*3))];
        }

        // This is the inner product using one particular value of each unknown parameter
        for (i=0; i<62; i++) {
          metric += (int16_t)(((d0[i]*((((phase_re[phase]*(int32_t)sss0[i<<1])>>19)-((phase_im[phase]*(int32_t)sss0[1+(i<<1)])>>19)))) +
                               (d5[i]*((((phase_re[phase]*(int32_t)sss5[i<<1])>>19)-((phase_im[phase]*(int32_t)sss5[1+(i<<1)])>>19))))));
        }

        // if the current metric is better than the last save it
        if (metric > *tot_metric) {
          *tot_metric = metric;
416
          ue->frame_parms.Nid_cell = Nid2+(3*Nid1);
417
418
          *phase_max = phase;
          *flip_max=flip;
419
#ifdef DEBUG_SSS
420
          msg("(flip,phase,Nid1) (%d,%d,%d), metric_phase %d tot_metric %d, phase_max %d, flip_max %d\n",flip,phase,Nid1,metric,*tot_metric,*phase_max,*flip_max);
421
#endif
422
423

        }
424
      }
425
    }
426
427
428
429
430
  }

  return(0);
}