lte_sync_timefreq.c 11.2 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*******************************************************************************
    OpenAirInterface 
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with OpenAirInterface.The full GNU General Public License is 
   included in this distribution in the file called "COPYING". If not, 
   see <http://www.gnu.org/licenses/>.

  Contact Information
  OpenAirInterface Admin: openair_admin@eurecom.fr
  OpenAirInterface Tech : openair_tech@eurecom.fr
  OpenAirInterface Dev  : openair4g-devel@eurecom.fr
  
  Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE

 *******************************************************************************/

/*! \file PHY/LTE_ESTIMATION/lte_sync_timefreq.c
* \brief Initial time frequency scan of entire LTE band
* \author R. Knopp
* \date 2014
* \version 0.1
* \company Eurecom
* \email: raymond.knopp@eurecom.fr
* \note
* \warning
*/
/* file: lte_sync_timefreq.c
   purpose: scan for likely cells over entire LTE band using PSS. Provides coarse frequency offset in addtition to 10 top likelihoods per PSS sequence
   author: raymond.knopp@eurecom.fr
   date: 23.01.2015
*/

//#include "defs.h"
#include "PHY/defs.h"
#include "PHY/extern.h"
49
#include "pss6144.h"
50

51
#define DEBUG_TF 1
52
extern void print_shorts(char*,__m128i*);
53

54
void lte_sync_timefreq(PHY_VARS_UE *ue,int band,unsigned int DL_freq) {
55
56
57
58

  UE_SCAN_INFO_t *scan_info = &ue->scan_info[band];
  int16_t spectrum[12288] __attribute__((aligned(16)));
  int16_t spectrum_p5ms[12288] __attribute__((aligned(16)));
59
  int i,f,f2,band_idx;
60
61
62
63
64
65
66
  __m128i autocorr0[256/4],autocorr1[256/4],autocorr2[256/4];
  __m128i autocorr0_t[256/4],autocorr1_t[256/4],autocorr2_t[256/4];
  __m128i tmp_t[256/4];
  int32_t *rxp;
  int16_t *sp;
  __m128i *sp2;
  __m128i s;
67
  int re,re256;
68
69
  __m128i mmtmp00,mmtmp01,mmtmp02,mmtmp10,mmtmp11,mmtmp12;
  int maxcorr[3],minamp,pos,pssind;
70
71
72
73
74
  int16_t *pss6144_0,*pss6144_1,*pss6144_2;
  
  
  
  //    for (i=0;i<38400*4;i+=3072)   // steps of 200 us with 100 us overlap, 0 to 5s
75
  write_output("rxsig0.m","rxs0",ue->lte_ue_common_vars.rxdata[0],30720,1,1);
76
  for (i = 15360-3072*2;i<15360+3072+1;i+=3072)  {
77

78
 
79
80
      //compute frequency-domain representation of 6144-sample chunk
      
81
82
83
84
      rxp = &ue->lte_ue_common_vars.rxdata[0][i];
      sp=spectrum;
      while (1) {

85
86
87
	//compute frequency-domain representation of 6144-sample chunk
	fft6144((int16_t *)rxp,
		sp);
88
89
90
	printf("i %d: sp %p\n",i,sp);

	if (i==12288){
91
	  write_output("scan6144F.m","s6144F",sp,6144,1,1);
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
	  write_output("scan6144.m","s6144",rxp,6144,1,1);
	}
	for (f = -130;f<-125;f++) {  // this is -10MHz to 10 MHz in 5 kHz steps
	  
	  if ((f<-256)||(f>=0)) { // no split around DC
	    printf("No split, f %d (%d)\n",f,f&3);
	    // align filters and input buffer pointer to 128-bit
	    switch (f&3) {
	    case 0: 
	      pss6144_0 = &pss6144_0_0[0];
	      pss6144_1 = &pss6144_1_0[0];
	      pss6144_2 = &pss6144_2_0[0];
	      sp2 = (f<0) ? (__m128i*)&sp[12288+(f<<1)] : (__m128i*)&sp;
	      break;
	    case 1: 
	      pss6144_0 = &pss6144_0_1[0];
	      pss6144_1 = &pss6144_1_1[0];
	      pss6144_2 = &pss6144_2_1[0];
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
		sp2 = (f<0) ? (__m128i*)&sp[12286+(f<<1)] : (__m128i*)sp;
		break;
	      case 2: 
		pss6144_0 = &pss6144_0_2[0];
		pss6144_1 = &pss6144_1_2[0];
		pss6144_2 = &pss6144_2_2[0];
		sp2 = (f<0) ? (__m128i*)&sp[12284+(f<<1)] : (__m128i*)sp;
		break;
	      case 3: 
		pss6144_0 = &pss6144_0_3[0];
		pss6144_1 = &pss6144_1_3[0];
		pss6144_2 = &pss6144_2_3[0];
		sp2 = (f<0) ? (__m128i*)&sp[12282+(f<<1)] : (__m128i*)sp;
		break;
	      } 
125
	      re256=32;
126
127
128
129
130
131
132
133
134
135
136
137
138
	      for (re = 0; re<256/4; re++) {  // loop over 256 points of upsampled PSS
		s = sp2[re];
		mmtmp00 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_0)[re],s),15);
		mmtmp01 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_1)[re],s),15);
		mmtmp02 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_2)[re],s),15);
		
		s = _mm_shufflelo_epi16(s,_MM_SHUFFLE(2,3,0,1));
		s = _mm_shufflehi_epi16(s,_MM_SHUFFLE(2,3,0,1));
		s = _mm_sign_epi16(s,*(__m128i*)&conjugate[0]);
		mmtmp10 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_0)[re],s),15);
		mmtmp11 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_1)[re],s),15);
		mmtmp12 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_2)[re],s),15);
		
139
140
141
142
143
		autocorr0[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp00,mmtmp10),_mm_unpackhi_epi32(mmtmp00,mmtmp10));
		autocorr1[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp01,mmtmp11),_mm_unpackhi_epi32(mmtmp01,mmtmp11));
		autocorr2[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp02,mmtmp12),_mm_unpackhi_epi32(mmtmp02,mmtmp12));

		re256 = (re256+1)&0x3f;
144
145
146
	      }
	    }
	    else { // Split around DC, this is the negative frequencies
147
	      printf("split around DC, f %d (f/4 %d, f&3 %d)\n",f,f>>2,f&3);
148
149
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
	      // align filters and input buffer pointer to 128-bit	      
	      switch (f&3) {
	      case 0: 
		pss6144_0 = &pss6144_0_0[0];
		pss6144_1 = &pss6144_1_0[0];
		pss6144_2 = &pss6144_2_0[0];
		sp2 = (__m128i*)&sp[12288+(f<<1)];
		break;
	      case 1: 
		pss6144_0 = &pss6144_0_1[0];
		pss6144_1 = &pss6144_1_1[0];
		pss6144_2 = &pss6144_2_1[0];
		sp2 = (__m128i*)&sp[12286+(f<<1)];
		break;
	      case 2: 
		pss6144_0 = &pss6144_0_2[0];
		pss6144_1 = &pss6144_1_2[0];
		pss6144_2 = &pss6144_2_2[0];
		sp2 = (__m128i*)&sp[12284+(f<<1)];
		break;
	      case 3: 
		pss6144_0 = &pss6144_0_3[0];
		pss6144_1 = &pss6144_1_3[0];
		pss6144_2 = &pss6144_2_3[0];
		sp2 = (__m128i*)&sp[12282+(f<<1)];
		break;
	      } 
175
176
	      re256 = 32;
	      for (re = 0; re<(-f+3)/4; re++) {  // loop over 256 points of upsampled PSS
177
178
179
		s = sp2[re];
		printf("re %d, %p\n",re,&sp2[re]);
		print_shorts("s",&s);
180
		print_shorts("pss",&((__m128i*)pss6144_0)[re]);
181
182
183
184
185
186
187
188
189
190
191
192

		mmtmp00 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_0)[re],s),15);
		mmtmp01 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_1)[re],s),15);
		mmtmp02 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_2)[re],s),15);
		
		s = _mm_shufflelo_epi16(s,_MM_SHUFFLE(2,3,0,1));
		s = _mm_shufflehi_epi16(s,_MM_SHUFFLE(2,3,0,1));
		s = _mm_sign_epi16(s,*(__m128i*)&conjugate[0]);
		mmtmp10 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_0)[re],s),15);
		mmtmp11 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_1)[re],s),15);
		mmtmp12 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_2)[re],s),15);
		
193
194
195
		autocorr0[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp00,mmtmp10),_mm_unpackhi_epi32(mmtmp00,mmtmp10));
		autocorr1[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp01,mmtmp11),_mm_unpackhi_epi32(mmtmp01,mmtmp11));
		autocorr2[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp02,mmtmp12),_mm_unpackhi_epi32(mmtmp02,mmtmp12));
196
		
197
		re256 = (re256+1)&0x3f;
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
	      }
	      // This is the +ve frequencies

	      // align filters to 128-bit
	      sp2 = (__m128i*)&sp[0];
	      switch (f&3) {
	      case 0: 
		pss6144_0 = &pss6144_0_0[256];
		pss6144_1 = &pss6144_1_0[256];
		pss6144_2 = &pss6144_2_0[256];
		break;
	      case 1: 
		pss6144_0 = &pss6144_0_1[256];
		pss6144_1 = &pss6144_1_1[256];
		pss6144_2 = &pss6144_2_1[256];
		break;
	      case 2: 
		pss6144_0 = &pss6144_0_2[256];
		pss6144_1 = &pss6144_1_2[256];
		pss6144_2 = &pss6144_2_2[256];
		break;
	      case 3: 
		pss6144_0 = &pss6144_0_3[256];
		pss6144_1 = &pss6144_1_3[256];
		pss6144_2 = &pss6144_2_3[256];
		break;
	      } 
225
	      for (re = 0; re<(256+f)/4; re++) {  // loop over 256 points of upsampled PSS
226
227
228
		s = sp2[re];
		printf("re %d %p\n",re,&sp2[re]);
		print_shorts("s",&s);
229
		print_shorts("pss",&((__m128i*)pss6144_0)[re]);
230
231
232
233
234
235
236
237
238
239
240
		mmtmp00 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_0)[re],s),15);
		mmtmp01 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_1)[re],s),15);
		mmtmp02 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_2)[re],s),15);
		
		s = _mm_shufflelo_epi16(s,_MM_SHUFFLE(2,3,0,1));
		s = _mm_shufflehi_epi16(s,_MM_SHUFFLE(2,3,0,1));
		s = _mm_sign_epi16(s,*(__m128i*)&conjugate[0]);
		mmtmp10 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_0)[re],s),15);
		mmtmp11 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_1)[re],s),15);
		mmtmp12 = _mm_srai_epi32(_mm_madd_epi16(((__m128i*)pss6144_2)[re],s),15);
		
241
242
243
244
245
		autocorr0[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp00,mmtmp10),_mm_unpackhi_epi32(mmtmp00,mmtmp10));
		autocorr1[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp01,mmtmp11),_mm_unpackhi_epi32(mmtmp01,mmtmp11));
		autocorr2[re256] = _mm_packs_epi32(_mm_unpacklo_epi32(mmtmp02,mmtmp12),_mm_unpackhi_epi32(mmtmp02,mmtmp12));

		re256 = (re256+1)&0x3f;		
246
247
248
249
250
	      }
	      
	    }
	    // ifft, accumulate energy over two half-frames
	    idft256((int16_t*)autocorr0,(int16_t*)tmp_t,1);
251
252
253
254
	    if (i==12288) {
	      write_output("corr256F.m","c256F",autocorr0,256,1,1);
	      write_output("corr256.m","c256",tmp_t,256,1,1);
	    }
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
	    memset((void*)autocorr0_t,0,256*4);
	    memset((void*)autocorr1_t,0,256*4);
	    memset((void*)autocorr2_t,0,256*4);
	    for (re=0;re<(256/4);re++)
	      autocorr0_t[re] = _mm_add_epi32(autocorr0_t[re],_mm_madd_epi16(tmp_t[re],tmp_t[re]));
	    idft256((int16_t*)autocorr1,(int16_t*)autocorr1_t,1);
	    for (re=0;re<(256/4);re++)
	      autocorr1_t[re] = _mm_add_epi32(autocorr1_t[re],_mm_madd_epi16(tmp_t[re],tmp_t[re]));
	    idft256((int16_t*)autocorr2,(int16_t*)autocorr2_t,1);
	    for (re=0;re<(256/4);re++)
	      autocorr2_t[re] = _mm_add_epi32(autocorr2_t[re],_mm_madd_epi16(tmp_t[re],tmp_t[re]));

	  
	    //compute max correlation over time window
	    maxcorr[0] = 0;
	    maxcorr[1] = 0;
	    maxcorr[2] = 0;
	    for (re=0;re<256;re++) {
#ifdef DEBUG_TF
	      printf("%d,",((int32_t*)autocorr0_t)[re]);
#endif
	      if (((int32_t*)autocorr0_t)[re] > maxcorr[0]) {
		maxcorr[0]=((int32_t*)autocorr0_t)[re];
		printf("*");
	      }
	      if (((int32_t*)autocorr1_t)[re] > maxcorr[1])
		maxcorr[1]=((int32_t*)autocorr1_t)[re];
	      if (((int32_t*)autocorr2_t)[re] > maxcorr[2])
		maxcorr[2]=((int32_t*)autocorr2_t)[re];
	    }
#ifdef DEBUG_TF
	    printf("\n");
#endif
288
289
	    
	    
290
291
292
293
294
295
296
297
298
299
300
301
302
	    for (pssind=0;pssind<3;pssind++) {
	      printf("pss %d, amp %d freq %u, i %d\n",pssind,maxcorr[pssind],((f+128)*5000)+DL_freq,i);
	      minamp=(int)((1<<30)-1);
	      for (band_idx=0;band_idx<10;band_idx++)
		if (minamp > scan_info->amp[pssind][band_idx]) {
		  minamp = scan_info->amp[pssind][band_idx];
		  pos    = band_idx;
		}
	      if (maxcorr[pssind]>minamp) {
		scan_info->amp[pssind][pos]=maxcorr[pssind];
		scan_info->freq_offset_Hz[pssind][pos]=(f*5000)+DL_freq;
	      }
	    } // loop on pss index
303
	  }
304
305
306
	  if (rxp == &ue->lte_ue_common_vars.rxdata[0][i+38400*4]) {
	    rxp = &ue->lte_ue_common_vars.rxdata[0][i+38400*4];
	    sp=spectrum_p5ms; 
307
	  }
308
309
	  else {
	    break;
310
	  }
311
312
313
314
315
      }   
      }// loop on time index i
#ifdef DEBUG_TF
      exit(-1);
#endif
316
317
}