pmch_ue.c 51.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * 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
 */

22
23
24
25
26
27
28
29
30
31
32
33
/*! \file PHY/LTE_UE_TRANSPORT/pmch_ue.c
* \brief This includes routines for decoding the UE FeMBMS/PMCH physical/multicast/transport channel 3GPP TS 36.211 version 14.2.0 Release 14 Sections 6.5/6.10.2
* \author J. Morgade
* \date 2019
* \version 0.1
* \company Vicomtech
* \email: javier.morgade@ieee.org
* \note
* \warning
*/


34
35
#include "PHY/defs_UE.h"
#include "PHY/phy_extern_ue.h"
36
#include "PHY/sse_intrin.h"
37
#include "PHY/LTE_UE_TRANSPORT/transport_proto_ue.h"
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

// Mask for identifying subframe for MBMS
#define MBSFN_TDD_SF3 0x80// for TDD
#define MBSFN_TDD_SF4 0x40
#define MBSFN_TDD_SF7 0x20
#define MBSFN_TDD_SF8 0x10
#define MBSFN_TDD_SF9 0x08

#define MBSFN_FDD_SF1 0x80// for FDD
#define MBSFN_FDD_SF2 0x40
#define MBSFN_FDD_SF3 0x20
#define MBSFN_FDD_SF6 0x10
#define MBSFN_FDD_SF7 0x08
#define MBSFN_FDD_SF8 0x04



55
void dump_mch(PHY_VARS_UE *ue,uint8_t eNB_id,uint16_t coded_bits_per_codeword,int subframe) {
56
  char fname[32],vname[32];
57
#define NSYMB_PMCH 12
58
59
  sprintf(fname,"mch_rxF_ext0.m");
  sprintf(vname,"pmch_rxF_ext0");
60
  LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->rxdataF_ext[0],12*(ue->frame_parms.N_RB_DL)*12,1,1);
61
62
  sprintf(fname,"mch_ch_ext00.m");
  sprintf(vname,"pmch_ch_ext00");
63
  LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->dl_ch_estimates_ext[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1);
64
  /*
65
66
67
68
    LOG_M("dlsch%d_ch_ext01.m","dl01_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*NSYMB_PMCH,1,1);
    LOG_M("dlsch%d_ch_ext10.m","dl10_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[2],12*N_RB_DL*NSYMB_PMCH,1,1);
    LOG_M("dlsch%d_ch_ext11.m","dl11_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[3],12*N_RB_DL*NSYMB_PMCH,1,1);
    LOG_M("dlsch%d_rho.m","dl_rho",pdsch_vars[eNB_id]->rho[0],12*N_RB_DL*NSYMB_PMCH,1,1);
69
70
71
  */
  sprintf(fname,"mch_rxF_comp0.m");
  sprintf(vname,"pmch_rxF_comp0");
72
  LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->rxdataF_comp0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1);
73
74
  sprintf(fname,"mch_rxF_llr.m");
  sprintf(vname,"pmch_llr");
75
  LOG_M(fname,vname, ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->llr[0],coded_bits_per_codeword,1,0);
76
77
  sprintf(fname,"mch_mag1.m");
  sprintf(vname,"pmch_mag1");
78
  LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->dl_ch_mag0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1);
79
80
  sprintf(fname,"mch_mag2.m");
  sprintf(vname,"pmch_mag2");
81
  LOG_M(fname,vname,ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id]->dl_ch_magb0[0],12*(ue->frame_parms.N_RB_DL)*NSYMB_PMCH,1,1);
Mongazon's avatar
Mongazon committed
82
  LOG_M("mch00_ch0.m","pmch00_ch0",
83
84
        &(ue->common_vars.common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id][0][0]),
        ue->frame_parms.ofdm_symbol_size*12,1,1);
Mongazon's avatar
Mongazon committed
85
  LOG_M("rxsig_mch.m","rxs_mch",
86
87
        &ue->common_vars.rxdata[0][subframe*ue->frame_parms.samples_per_tti],
        ue->frame_parms.samples_per_tti,1,1);
88
89
  /*
  if (PHY_vars_eNB_g)
Mongazon's avatar
Mongazon committed
90
    LOG_M("txsig_mch.m","txs_mch",
91
92
93
94
95
                 &PHY_vars_eNB_g[0][0]->common_vars.txdata[0][0][subframe*ue->frame_parms.samples_per_tti],
                 ue->frame_parms.samples_per_tti,1,1);*/
}


96
void fill_UE_dlsch_MCH(PHY_VARS_UE *ue,int mcs,int ndi,int rvidx,int eNB_id) {
97
98
  LTE_UE_DLSCH_t *dlsch = ue->dlsch_MCH[eNB_id];
  LTE_DL_FRAME_PARMS *frame_parms=&ue->frame_parms;
99
  dlsch->Mdlharq = 1;
100
101
102
103
104
105
106
107
108
109
  //  dlsch->rnti   = M_RNTI;
  dlsch->harq_processes[0]->mcs   = mcs;
  dlsch->harq_processes[0]->rvidx = rvidx;
  //  dlsch->harq_processes[0]->Ndi   = ndi;
  dlsch->harq_processes[0]->Nl    = 1;
  dlsch->harq_processes[0]->TBS = TBStable[get_I_TBS(dlsch->harq_processes[0]->mcs)][frame_parms->N_RB_DL-1];
  dlsch->current_harq_pid = 0;
  dlsch->harq_processes[0]->nb_rb = frame_parms->N_RB_DL;

  switch(frame_parms->N_RB_DL) {
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
    case 6:
      dlsch->harq_processes[0]->rb_alloc_even[0] = 0x3f;
      dlsch->harq_processes[0]->rb_alloc_odd[0] = 0x3f;
      break;

    case 25:
      dlsch->harq_processes[0]->rb_alloc_even[0] = 0x1ffffff;
      dlsch->harq_processes[0]->rb_alloc_odd[0] = 0x1ffffff;
      break;

    case 50:
      dlsch->harq_processes[0]->rb_alloc_even[0] = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_odd[0]  = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_even[1] = 0x3ffff;
      dlsch->harq_processes[0]->rb_alloc_odd[1]  = 0x3ffff;
      break;

    case 100:
      dlsch->harq_processes[0]->rb_alloc_even[0] = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_odd[0]  = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_even[1] = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_odd[1]  = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_even[2] = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_odd[2]  = 0xffffffff;
      dlsch->harq_processes[0]->rb_alloc_even[3] = 0xf;
      dlsch->harq_processes[0]->rb_alloc_odd[3]  = 0xf;
      break;
137
138
139
  }
}

140

141
142
143
144
145
146
147
void mch_extract_rbs_khz_1dot25(int **rxdataF,
                                int **dl_ch_estimates,
                                int **rxdataF_ext,
                                int **dl_ch_estimates_ext,
                                /*unsigned char symbol,*/
                                unsigned char subframe,
                                LTE_DL_FRAME_PARMS *frame_parms) {
148
149
  int i,j,offset,aarx,numext;

150
151
152
153
  if( (subframe&0x1) == 0) {
    offset=0;
  } else {
    offset=3;
154
  }
155

156
  numext=0;
157

158
  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
159
160
161
162
163
164
165
166
167
    for (i=0,j=0; i<frame_parms->N_RB_DL*72; i++) {
      if( ((i-offset)%6) != 0 ) {
        //rxdataF_ext[aarx][j+0] = rxdataF[aarx][i+4344 +0];
        rxdataF_ext[aarx][j+0] = rxdataF[aarx][i+frame_parms->first_carrier_offset_khz_1dot25 +0];
        rxdataF_ext[aarx][(frame_parms->N_RB_DL*60)+j+0] = rxdataF[aarx][i+1+0]; //DC
        dl_ch_estimates_ext[aarx][j+0] = dl_ch_estimates[aarx][i+0];
        dl_ch_estimates_ext[aarx][(frame_parms->N_RB_DL*60)+j+0] = dl_ch_estimates[aarx][i+(frame_parms->N_RB_DL*72)+0];
        numext+=2;
        j++;
168
      }
169
    }
170
171
  }
}
172
173
174
175
176
177
178
179


void mch_extract_rbs(int **rxdataF,
                     int **dl_ch_estimates,
                     int **rxdataF_ext,
                     int **dl_ch_estimates_ext,
                     unsigned char symbol,
                     unsigned char subframe,
180
                     LTE_DL_FRAME_PARMS *frame_parms) {
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  int pilots=0,i,j,offset,aarx;

  if ((symbol==2)||
      (symbol==10)) {
    pilots = 1;
    offset = 1;
  } else if (symbol==6) {
    pilots = 1;
    offset = 0;
  }

  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
    if (pilots==1) {
      for (i=offset,j=0; i<frame_parms->N_RB_DL*6; i+=2,j++) {
        /*  printf("MCH with pilots: i %d, j %d => %d,%d\n",i,j,
               *(int16_t*)&rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)],
               *(int16_t*)(1+&rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)]));
               */
        rxdataF_ext[aarx][j+symbol*(frame_parms->N_RB_DL*12)]                                  = rxdataF[aarx][i+frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)];
        rxdataF_ext[aarx][(frame_parms->N_RB_DL*3)+j+symbol*(frame_parms->N_RB_DL*12)]         = rxdataF[aarx][i+1+ (symbol*frame_parms->ofdm_symbol_size)];
        dl_ch_estimates_ext[aarx][j+symbol*(frame_parms->N_RB_DL*12)]                          = dl_ch_estimates[aarx][i+(symbol*frame_parms->ofdm_symbol_size)];
        dl_ch_estimates_ext[aarx][(frame_parms->N_RB_DL*3)+j+symbol*(frame_parms->N_RB_DL*12)] = dl_ch_estimates[aarx][i+(frame_parms->N_RB_DL*6)+(symbol*frame_parms->ofdm_symbol_size)];
      }
    } else {
205
206
      memcpy((void *)&rxdataF_ext[aarx][symbol*(frame_parms->N_RB_DL*12)],
             (void *)&rxdataF[aarx][frame_parms->first_carrier_offset + (symbol*frame_parms->ofdm_symbol_size)],
207
             frame_parms->N_RB_DL*24);
208
209
      memcpy((void *)&rxdataF_ext[aarx][(frame_parms->N_RB_DL*6) + symbol*(frame_parms->N_RB_DL*12)],
             (void *)&rxdataF[aarx][1 + (symbol*frame_parms->ofdm_symbol_size)],
210
             frame_parms->N_RB_DL*24);
211
212
      memcpy((void *)&dl_ch_estimates_ext[aarx][symbol*(frame_parms->N_RB_DL*12)],
             (void *)&dl_ch_estimates[aarx][(symbol*frame_parms->ofdm_symbol_size)],
213
214
215
216
217
218
219
220
221
             frame_parms->N_RB_DL*48);
    }
  }
}

void mch_channel_level(int **dl_ch_estimates_ext,
                       LTE_DL_FRAME_PARMS *frame_parms,
                       int *avg,
                       uint8_t symbol,
222
                       unsigned short nb_rb) {
223
224
225
226
  int i,aarx,nre;
#if defined(__x86_64__) || defined(__i386__)
  __m128i *dl_ch128,avg128;
#elif defined(__arm__)
227
  int32x4_t avg128;
228
#endif
229

230
231
  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
#if defined(__x86_64__) || defined(__i386__)
232
    //clear average level
233
234
235
236
237
    avg128 = _mm_setzero_si128();
    // 5 is always a symbol with no pilots for both normal and extended prefix
    dl_ch128=(__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
#endif
238

239
240
241
242
243
244
245
    if ((symbol == 2) || (symbol == 6) || (symbol == 10))
      nre = (frame_parms->N_RB_DL*6);
    else
      nre = (frame_parms->N_RB_DL*12);

    for (i=0; i<(nre>>2); i++) {
#if defined(__x86_64__) || defined(__i386__)
246
      avg128 = _mm_add_epi32(avg128,_mm_srai_epi32(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),log2_approx(nre>>2)-1));
247
248
249
250
#elif defined(__arm__)
#endif
    }

251
    avg[aarx] = (((((int*)&avg128)[0] +
252
253
                 ((int*)&avg128)[1] +
                 ((int*)&avg128)[2] +
254
                 ((int*)&avg128)[3])/(nre>>factor2(nre)))*(1<<(log2_approx(nre>>2)-1-factor2(nre))));
255
256
257
258
259
260
261
262
263
264

    //            printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
  }

#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}

265
void mch_channel_level_khz_1dot25(int **dl_ch_estimates_ext,
266
267
268
269
                                  LTE_DL_FRAME_PARMS *frame_parms,
                                  int *avg,
                                  /*uint8_t symbol,*/
                                  unsigned short nb_rb) {
270
271
272
273
274
275
  int i,aarx,nre;
#if defined(__x86_64__) || defined(__i386__)
  __m128i *dl_ch128,avg128;
#elif defined(__arm__)
  int32x4_t avg128;
#endif
276

277
278
  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
#if defined(__x86_64__) || defined(__i386__)
279
    //clear average level
280
281
282
283
284
285
286
287
288
289
290
291
292
293
    avg128 = _mm_setzero_si128();
    // 5 is always a symbol with no pilots for both normal and extended prefix
    dl_ch128=(__m128i *)&dl_ch_estimates_ext[aarx][0/*symbol*frame_parms->N_RB_DL*12*/];
#elif defined(__arm__)
#endif
    /*if ((symbol == 2) || (symbol == 6) || (symbol == 10))
      nre = (frame_parms->N_RB_DL*6);
    else
      nre = (frame_parms->N_RB_DL*12);*/
    nre = frame_parms->N_RB_DL*12*10;
    //nre = frame_parms->N_RB_DL*12;

    for (i=0; i<(nre>>2); i++) {
#if defined(__x86_64__) || defined(__i386__)
294
295
      //avg128 = _mm_add_epi32(avg128,_mm_madd_epi16(dl_ch128[0],dl_ch128[0]));
      avg128 = _mm_add_epi32(avg128,_mm_srai_epi32(_mm_madd_epi16(dl_ch128[0],dl_ch128[0]),log2_approx(nre>>2)-1));
296
297
298
299
#elif defined(__arm__)
#endif
    }

300
301
302
303
304
   // avg[aarx] = (((int*)&avg128)[0] +
   //              ((int*)&avg128)[1] +
   //              ((int*)&avg128)[2] +
   //              ((int*)&avg128)[3])/nre;
   avg[aarx] = (((((int*)&avg128)[0] +
305
306
                 ((int*)&avg128)[1] +
                 ((int*)&avg128)[2] +
307
                 ((int*)&avg128)[3])/(nre>>factor2(nre)))*(1<<(log2_approx(nre>>2)-1-factor2(nre))));
308
309
310
311
312
313
314
315
                //printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
  }

#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}
316

317
318


319
320
321
322
323
324
325
326
void mch_channel_compensation(int **rxdataF_ext,
                              int **dl_ch_estimates_ext,
                              int **dl_ch_mag,
                              int **dl_ch_magb,
                              int **rxdataF_comp,
                              LTE_DL_FRAME_PARMS *frame_parms,
                              unsigned char symbol,
                              unsigned char mod_order,
327
                              unsigned char output_shift) {
328
329
330
  int aarx,nre,i;
#if defined(__x86_64__) || defined(__i386__)
  __m128i *dl_ch128,*dl_ch_mag128,*dl_ch_mag128b,*rxdataF128,*rxdataF_comp128;
331
  __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128={0},QAM_amp128b={0};
332
333
#elif defined(__arm__)
#endif
334

335
336
337
338
339
340
  if ((symbol == 2) || (symbol == 6) || (symbol == 10))
    nre = frame_parms->N_RB_DL*6;
  else
    nre = frame_parms->N_RB_DL*12;

#if defined(__x86_64__) || defined(__i386__)
341

342
343
344
345
346
347
348
349
  if (mod_order == 4) {
    QAM_amp128 = _mm_set1_epi16(QAM16_n1);  // 2/sqrt(10)
    QAM_amp128b = _mm_setzero_si128();
  } else if (mod_order == 6) {
    QAM_amp128  = _mm_set1_epi16(QAM64_n1); //
    QAM_amp128b = _mm_set1_epi16(QAM64_n2);
  }

350
#elif defined(__arm__)
351
352
353
354
355
356
357
358
359
360
361
362
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
#endif

  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
#if defined(__x86_64__) || defined(__i386__)
    dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128      = (__m128i *)&dl_ch_mag[aarx][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128b     = (__m128i *)&dl_ch_magb[aarx][symbol*frame_parms->N_RB_DL*12];
    rxdataF128        = (__m128i *)&rxdataF_ext[aarx][symbol*frame_parms->N_RB_DL*12];
    rxdataF_comp128   = (__m128i *)&rxdataF_comp[aarx][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
#endif

    for (i=0; i<(nre>>2); i+=2) {
      if (mod_order>2) {
        // get channel amplitude if not QPSK
#if defined(__x86_64__) || defined(__i386__)
        mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128[0]);
        mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
        mmtmpD1 = _mm_madd_epi16(dl_ch128[1],dl_ch128[1]);
        mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
        mmtmpD0 = _mm_packs_epi32(mmtmpD0,mmtmpD1);
        // store channel magnitude here in a new field of dlsch
        dl_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpD0,mmtmpD0);
        dl_ch_mag128b[0] = dl_ch_mag128[0];
        dl_ch_mag128[0] = _mm_mulhi_epi16(dl_ch_mag128[0],QAM_amp128);
        dl_ch_mag128[0] = _mm_slli_epi16(dl_ch_mag128[0],1);
        dl_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpD0,mmtmpD0);
        dl_ch_mag128b[1] = dl_ch_mag128[1];
        dl_ch_mag128[1] = _mm_mulhi_epi16(dl_ch_mag128[1],QAM_amp128);
        dl_ch_mag128[1] = _mm_slli_epi16(dl_ch_mag128[1],1);
        dl_ch_mag128b[0] = _mm_mulhi_epi16(dl_ch_mag128b[0],QAM_amp128b);
        dl_ch_mag128b[0] = _mm_slli_epi16(dl_ch_mag128b[0],1);
        dl_ch_mag128b[1] = _mm_mulhi_epi16(dl_ch_mag128b[1],QAM_amp128b);
        dl_ch_mag128b[1] = _mm_slli_epi16(dl_ch_mag128b[1],1);
#elif defined(__arm__)
#endif
      }

#if defined(__x86_64__) || defined(__i386__)
      // multiply by conjugated channel
      mmtmpD0 = _mm_madd_epi16(dl_ch128[0],rxdataF128[0]);
      //  print_ints("re",&mmtmpD0);
      // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
      mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
      mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
396
      mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i *)&conjugate[0]);
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
      //  print_ints("im",&mmtmpD1);
      mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[0]);
      // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
      mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
      //  print_ints("re(shift)",&mmtmpD0);
      mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
      //  print_ints("im(shift)",&mmtmpD1);
      mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
      mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
      //        print_ints("c0",&mmtmpD2);
      //  print_ints("c1",&mmtmpD3);
      rxdataF_comp128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
      //  print_shorts("rx:",rxdataF128);
      //  print_shorts("ch:",dl_ch128);
      //  print_shorts("pack:",rxdataF_comp128);
      // multiply by conjugated channel
      mmtmpD0 = _mm_madd_epi16(dl_ch128[1],rxdataF128[1]);
      // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
      mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
      mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
417
      mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i *)conjugate);
418
419
      mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[1]);
      // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
420
      mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
      mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
      mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
      mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
      rxdataF_comp128[1] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
      //  print_shorts("rx:",rxdataF128+1);
      //  print_shorts("ch:",dl_ch128+1);
      //  print_shorts("pack:",rxdataF_comp128+1);
      dl_ch128+=2;
      dl_ch_mag128+=2;
      dl_ch_mag128b+=2;
      rxdataF128+=2;
      rxdataF_comp128+=2;
#elif defined(__arm__)
#endif
    }
  }

#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}

444
445


446
447
448
449
450
451
452
453
454
void mch_channel_compensation_khz_1dot25(int **rxdataF_ext,
    int **dl_ch_estimates_ext,
    int **dl_ch_mag,
    int **dl_ch_magb,
    int **rxdataF_comp,
    LTE_DL_FRAME_PARMS *frame_parms,
    /*unsigned char symbol,*/
    unsigned char mod_order,
    unsigned char output_shift) {
455
456
457
  int aarx,nre,i;
#if defined(__x86_64__) || defined(__i386__)
  __m128i *dl_ch128,*dl_ch_mag128,*dl_ch_mag128b,*rxdataF128,*rxdataF_comp128;
458
  __m128i mmtmpD0,mmtmpD1,mmtmpD2,mmtmpD3,QAM_amp128={0},QAM_amp128b={0};
459
460
461
462
463
464
465
466
#elif defined(__arm__)
#endif
  /*if ((symbol == 2) || (symbol == 6) || (symbol == 10))
    nre = frame_parms->N_RB_DL*6;
  else
    nre = frame_parms->N_RB_DL*12;*/
  nre = frame_parms->N_RB_DL*12*10;
#if defined(__x86_64__) || defined(__i386__)
467

468
469
470
471
472
473
474
475
  if (mod_order == 4) {
    QAM_amp128 = _mm_set1_epi16(QAM16_n1);  // 2/sqrt(10)
    QAM_amp128b = _mm_setzero_si128();
  } else if (mod_order == 6) {
    QAM_amp128  = _mm_set1_epi16(QAM64_n1); //
    QAM_amp128b = _mm_set1_epi16(QAM64_n2);
  }

476
#elif defined(__arm__)
477
478
479
480
481
482
483
484
485
#endif

  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
#if defined(__x86_64__) || defined(__i386__)
    dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aarx][0];
    dl_ch_mag128      = (__m128i *)&dl_ch_mag[aarx][0];
    dl_ch_mag128b     = (__m128i *)&dl_ch_magb[aarx][0];
    rxdataF128        = (__m128i *)&rxdataF_ext[aarx][0];
    rxdataF_comp128   = (__m128i *)&rxdataF_comp[aarx][0];
486
#elif defined(__arm__)
487
488
489
490
491
492
493
494
495
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
#endif

    for (i=0; i<(nre>>2); i+=2) {
      if (mod_order>2) {
        // get channel amplitude if not QPSK
#if defined(__x86_64__) || defined(__i386__)
        mmtmpD0 = _mm_madd_epi16(dl_ch128[0],dl_ch128[0]);
        mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
        mmtmpD1 = _mm_madd_epi16(dl_ch128[1],dl_ch128[1]);
        mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
        mmtmpD0 = _mm_packs_epi32(mmtmpD0,mmtmpD1);
        // store channel magnitude here in a new field of dlsch
        dl_ch_mag128[0] = _mm_unpacklo_epi16(mmtmpD0,mmtmpD0);
        dl_ch_mag128b[0] = dl_ch_mag128[0];
        dl_ch_mag128[0] = _mm_mulhi_epi16(dl_ch_mag128[0],QAM_amp128);
        dl_ch_mag128[0] = _mm_slli_epi16(dl_ch_mag128[0],1);
        dl_ch_mag128[1] = _mm_unpackhi_epi16(mmtmpD0,mmtmpD0);
        dl_ch_mag128b[1] = dl_ch_mag128[1];
        dl_ch_mag128[1] = _mm_mulhi_epi16(dl_ch_mag128[1],QAM_amp128);
        dl_ch_mag128[1] = _mm_slli_epi16(dl_ch_mag128[1],1);
        dl_ch_mag128b[0] = _mm_mulhi_epi16(dl_ch_mag128b[0],QAM_amp128b);
        dl_ch_mag128b[0] = _mm_slli_epi16(dl_ch_mag128b[0],1);
        dl_ch_mag128b[1] = _mm_mulhi_epi16(dl_ch_mag128b[1],QAM_amp128b);
        dl_ch_mag128b[1] = _mm_slli_epi16(dl_ch_mag128b[1],1);
#elif defined(__arm__)
#endif
      }

#if defined(__x86_64__) || defined(__i386__)
      // multiply by conjugated channel
      mmtmpD0 = _mm_madd_epi16(dl_ch128[0],rxdataF128[0]);
      //  print_ints("re",&mmtmpD0);
      // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
      mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[0],_MM_SHUFFLE(2,3,0,1));
      mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
522
      mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i *)&conjugate[0]);
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
      //  print_ints("im",&mmtmpD1);
      mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[0]);
      // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
      mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
      //  print_ints("re(shift)",&mmtmpD0);
      mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
      //  print_ints("im(shift)",&mmtmpD1);
      mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
      mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
      //        print_ints("c0",&mmtmpD2);
      //  print_ints("c1",&mmtmpD3);
      rxdataF_comp128[0] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
      //  print_shorts("rx:",rxdataF128);
      //  print_shorts("ch:",dl_ch128);
      //  print_shorts("pack:",rxdataF_comp128);
      // multiply by conjugated channel
      mmtmpD0 = _mm_madd_epi16(dl_ch128[1],rxdataF128[1]);
      // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
      mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[1],_MM_SHUFFLE(2,3,0,1));
      mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1,_MM_SHUFFLE(2,3,0,1));
543
      mmtmpD1 = _mm_sign_epi16(mmtmpD1,*(__m128i *)conjugate);
544
545
546
547
548
549
550
      mmtmpD1 = _mm_madd_epi16(mmtmpD1,rxdataF128[1]);
      // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
      mmtmpD0 = _mm_srai_epi32(mmtmpD0,output_shift);
      mmtmpD1 = _mm_srai_epi32(mmtmpD1,output_shift);
      mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0,mmtmpD1);
      mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0,mmtmpD1);
      rxdataF_comp128[1] = _mm_packs_epi32(mmtmpD2,mmtmpD3);
551
552
553
554
      //      print_shorts("rx:",rxdataF128+1);
      //     print_shorts("ch:",dl_ch128+1);
      //      print_shorts("pack:",rxdataF_comp128+1);
      dl_ch128+=2;
555
556
557
558
559
560
561
562
563
564
565
566
567
568
      dl_ch_mag128+=2;
      dl_ch_mag128b+=2;
      rxdataF128+=2;
      rxdataF_comp128+=2;
#elif defined(__arm__)
#endif
    }
  }

#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}
569

570
571


572
573
574
575
void mch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms,
                       int **rxdataF_comp,
                       int **dl_ch_mag,
                       int **dl_ch_magb,
576
                       unsigned char symbol) {
577
578
579
580
581
582
583
  int i;
#if defined(__x86_64__) || defined(__i386__)
  __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b;
#elif defined(__arm__)
  int16x8_t *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b;
#endif

584
  if (frame_parms->nb_antennas_rx>1) {
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
#if defined(__x86_64__) || defined(__i386__)
    rxdataF_comp128_0   = (__m128i *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
    rxdataF_comp128_1   = (__m128i *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_0      = (__m128i *)&dl_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_1      = (__m128i *)&dl_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
#elif defined(__arm__)
    rxdataF_comp128_0   = (int16x8_t *)&rxdataF_comp[0][symbol*frame_parms->N_RB_DL*12];
    rxdataF_comp128_1   = (int16x8_t *)&rxdataF_comp[1][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_0      = (int16x8_t *)&dl_ch_mag[0][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_1      = (int16x8_t *)&dl_ch_mag[1][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_0b     = (int16x8_t *)&dl_ch_magb[0][symbol*frame_parms->N_RB_DL*12];
    dl_ch_mag128_1b     = (int16x8_t *)&dl_ch_magb[1][symbol*frame_parms->N_RB_DL*12];
#endif
600

601
602
603
604
605
606
607
608
609
610
611
612
613
    // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
    for (i=0; i<frame_parms->N_RB_DL*3; i++) {
#if defined(__x86_64__) || defined(__i386__)
      rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_1[i],1));
      dl_ch_mag128_0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0[i],1),_mm_srai_epi16(dl_ch_mag128_1[i],1));
      dl_ch_mag128_0b[i]   = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0b[i],1),_mm_srai_epi16(dl_ch_mag128_1b[i],1));
#elif defined(__arm__)
      rxdataF_comp128_0[i] = vhaddq_s16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
      dl_ch_mag128_0[i]    = vhaddq_s16(dl_ch_mag128_0[i],dl_ch_mag128_1[i]);
      dl_ch_mag128_0b[i]   = vhaddq_s16(dl_ch_mag128_0b[i],dl_ch_mag128_1b[i]);
#endif
    }
  }
614

615
616
617
618
619
620
#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}

621

622
623
624
625
626
void mch_detection_mrc_khz_1dot25(LTE_DL_FRAME_PARMS *frame_parms,
                                  int **rxdataF_comp,
                                  int **dl_ch_mag,
                                  int **dl_ch_magb/*,
                       unsigned char symbol*/) {
627
628
629
630
631
632
633
  int i;
#if defined(__x86_64__) || defined(__i386__)
  __m128i *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b;
#elif defined(__arm__)
  int16x8_t *rxdataF_comp128_0,*rxdataF_comp128_1,*dl_ch_mag128_0,*dl_ch_mag128_1,*dl_ch_mag128_0b,*dl_ch_mag128_1b;
#endif

634
  if (frame_parms->nb_antennas_rx>1) {
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
#if defined(__x86_64__) || defined(__i386__)
    rxdataF_comp128_0   = (__m128i *)&rxdataF_comp[0][0];
    rxdataF_comp128_1   = (__m128i *)&rxdataF_comp[1][0];
    dl_ch_mag128_0      = (__m128i *)&dl_ch_mag[0][0];
    dl_ch_mag128_1      = (__m128i *)&dl_ch_mag[1][0];
    dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb[0][0];
    dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb[1][0];
#elif defined(__arm__)
    rxdataF_comp128_0   = (int16x8_t *)&rxdataF_comp[0][0];
    rxdataF_comp128_1   = (int16x8_t *)&rxdataF_comp[1][0];
    dl_ch_mag128_0      = (int16x8_t *)&dl_ch_mag[0][0];
    dl_ch_mag128_1      = (int16x8_t *)&dl_ch_mag[1][0];
    dl_ch_mag128_0b     = (int16x8_t *)&dl_ch_magb[0][0];
    dl_ch_mag128_1b     = (int16x8_t *)&dl_ch_magb[1][0];
#endif
650

651
652
653
654
655
656
657
658
659
660
661
662
663
    // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
    for (i=0; i<frame_parms->N_RB_DL*30; i++) {
#if defined(__x86_64__) || defined(__i386__)
      rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i],1),_mm_srai_epi16(rxdataF_comp128_1[i],1));
      dl_ch_mag128_0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0[i],1),_mm_srai_epi16(dl_ch_mag128_1[i],1));
      dl_ch_mag128_0b[i]   = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_0b[i],1),_mm_srai_epi16(dl_ch_mag128_1b[i],1));
#elif defined(__arm__)
      rxdataF_comp128_0[i] = vhaddq_s16(rxdataF_comp128_0[i],rxdataF_comp128_1[i]);
      dl_ch_mag128_0[i]    = vhaddq_s16(dl_ch_mag128_0[i],dl_ch_mag128_1[i]);
      dl_ch_mag128_0b[i]   = vhaddq_s16(dl_ch_mag128_0b[i],dl_ch_mag128_1b[i]);
#endif
    }
  }
664

665
666
667
668
669
#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}
670

671
672
673
674
675





676
677
678
679
int mch_qpsk_llr(LTE_DL_FRAME_PARMS *frame_parms,
                 int **rxdataF_comp,
                 short *dlsch_llr,
                 unsigned char symbol,
680
681
                 short **llr32p) {
  uint32_t *rxF = (uint32_t *)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
682
683
684
685
  uint32_t *llr32;
  int i,len;

  if (symbol==2) {
686
    llr32 = (uint32_t *)dlsch_llr;
687
  } else {
688
    llr32 = (uint32_t *)(*llr32p);
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  }

  AssertFatal(llr32!=NULL,"dlsch_qpsk_llr: llr is null, symbol %d, llr32=%p\n",symbol, llr32);

  if ((symbol==2) || (symbol==6) || (symbol==10)) {
    len = frame_parms->N_RB_DL*6;
  } else {
    len = frame_parms->N_RB_DL*12;
  }

  for (i=0; i<len; i++) {
    *llr32 = *rxF;
    rxF++;
    llr32++;
  }

  *llr32p = (short *)llr32;
#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
  return(0);
}

713

714
715
716
717
718
719
int mch_qpsk_llr_khz_1dot25(LTE_DL_FRAME_PARMS *frame_parms,
                            int **rxdataF_comp,
                            short *dlsch_llr,
                            /*unsigned char symbol,*/
                            short **llr32p) {
  uint32_t *rxF = (uint32_t *)&rxdataF_comp[0][0/*(symbol*frame_parms->N_RB_DL*12)*/];
720
721
722
723
  //uint32_t *rxF = (uint32_t*)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
  uint32_t *llr32;
  int i,len;
  //if (symbol==0) {
724
  llr32 = (uint32_t *)dlsch_llr;
725
  //} else {
726
  //llr32 = (uint32_t*)(*llr32p);
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
  //}
  //AssertFatal(llr32!=NULL,"dlsch_qpsk_llr: llr is null, symbol %d, llr32=%p\n",symbol, llr32);
  AssertFatal(llr32!=NULL,"dlsch_qpsk_llr: llr is null, llr32=%p\n",llr32);
  len = frame_parms->N_RB_DL*12*10;

  for (i=0; i<len; i++) {
    *llr32 = *rxF;
    rxF++;
    llr32++;
  }

  *llr32p = (short *)llr32;
#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
  return(0);
}
745

746
747


748
749
750
751
752
753
754
755
756
//----------------------------------------------------------------------------------------------
// 16-QAM
//----------------------------------------------------------------------------------------------

void mch_16qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
                   int **rxdataF_comp,
                   short *dlsch_llr,
                   int **dl_ch_mag,
                   unsigned char symbol,
757
                   int16_t **llr32p) {
758
#if defined(__x86_64__) || defined(__i386__)
759
  __m128i *rxF = (__m128i *)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
760
761
762
763
  __m128i *ch_mag;
  __m128i llr128[2],xmm0;
  uint32_t *llr32;
#elif defined(__arm__)
764
  int16x8_t *rxF = (int16x8_t *)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
765
766
767
768
769
770
771
  int16x8_t *ch_mag;
  int16x8_t llr128[2],xmm0;
  int16_t *llr16;
#endif
  int i,len;
  unsigned char len_mod4=0;
#if defined(__x86_64__) || defined(__i386__)
772

773
  if (symbol==2) {
774
    llr32 = (uint32_t *)dlsch_llr;
775
  } else {
776
    llr32 = (uint32_t *)*llr32p;
777
  }
778

779
#elif defined(__arm__)
780

781
  if (symbol==2) {
782
    llr16 = (int16_t *)dlsch_llr;
783
  } else {
784
    llr16 = (int16_t *)*llr32p;
785
  }
786

787
788
#endif
#if defined(__x86_64__) || defined(__i386__)
789
  ch_mag = (__m128i *)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
790
#elif defined(__arm__)
791
  ch_mag = (int16x8_t *)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
792
#endif
793

794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
  if ((symbol==2) || (symbol==6) || (symbol==10)) {
    len = frame_parms->N_RB_DL*6;
  } else {
    len = frame_parms->N_RB_DL*12;
  }

  // update output pointer according to number of REs in this symbol (<<2 because 4 bits per RE)
  if (symbol==2)
    *llr32p = dlsch_llr + (len<<2);
  else
    *llr32p += (len<<2);

  len_mod4 = len&3;
  len>>=2;  // length in quad words (4 REs)
  len+=(len_mod4==0 ? 0 : 1);

  for (i=0; i<len; i++) {
#if defined(__x86_64__) || defined(__i386__)
    xmm0 = _mm_abs_epi16(rxF[i]);
    xmm0 = _mm_subs_epi16(ch_mag[i],xmm0);
    // lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
    llr128[0] = _mm_unpacklo_epi32(rxF[i],xmm0);
    llr128[1] = _mm_unpackhi_epi32(rxF[i],xmm0);
    llr32[0] = ((uint32_t *)&llr128[0])[0];
    llr32[1] = ((uint32_t *)&llr128[0])[1];
    llr32[2] = ((uint32_t *)&llr128[0])[2];
    llr32[3] = ((uint32_t *)&llr128[0])[3];
    llr32[4] = ((uint32_t *)&llr128[1])[0];
    llr32[5] = ((uint32_t *)&llr128[1])[1];
    llr32[6] = ((uint32_t *)&llr128[1])[2];
    llr32[7] = ((uint32_t *)&llr128[1])[3];
    llr32+=8;
#elif defined(__arm__)
    xmm0 = vabsq_s16(rxF[i]);
    xmm0 = vsubq_s16(ch_mag[i],xmm0);
    // lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
    llr16[0] = vgetq_lane_s16(rxF[i],0);
    llr16[1] = vgetq_lane_s16(xmm0,0);
    llr16[2] = vgetq_lane_s16(rxF[i],1);
    llr16[3] = vgetq_lane_s16(xmm0,1);
    llr16[4] = vgetq_lane_s16(rxF[i],2);
    llr16[5] = vgetq_lane_s16(xmm0,2);
    llr16[6] = vgetq_lane_s16(rxF[i],2);
    llr16[7] = vgetq_lane_s16(xmm0,3);
    llr16[8] = vgetq_lane_s16(rxF[i],4);
    llr16[9] = vgetq_lane_s16(xmm0,4);
    llr16[10] = vgetq_lane_s16(rxF[i],5);
    llr16[11] = vgetq_lane_s16(xmm0,5);
    llr16[12] = vgetq_lane_s16(rxF[i],6);
    llr16[13] = vgetq_lane_s16(xmm0,6);
    llr16[14] = vgetq_lane_s16(rxF[i],7);
    llr16[15] = vgetq_lane_s16(xmm0,7);
    llr16+=16;
#endif
  }

#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}

856

857
858
859
860
861
862
void mch_16qam_llr_khz_1dot25(LTE_DL_FRAME_PARMS *frame_parms,
                              int **rxdataF_comp,
                              short *dlsch_llr,
                              int **dl_ch_mag,
                              /*unsigned char symbol,*/
                              int16_t **llr32p) {
863
#if defined(__x86_64__) || defined(__i386__)
864
  __m128i *rxF = (__m128i *)&rxdataF_comp[0][0];
865
866
867
868
  __m128i *ch_mag;
  __m128i llr128[2],xmm0;
  uint32_t *llr32;
#elif defined(__arm__)
869
  int16x8_t *rxF = (int16x8_t *)&rxdataF_comp[0][0];
870
871
872
873
874
875
876
877
  int16x8_t *ch_mag;
  int16x8_t llr128[2],xmm0;
  int16_t *llr16;
#endif
  int i,len;
  unsigned char len_mod4=0;
#if defined(__x86_64__) || defined(__i386__)
  //if (symbol==2) {
878
  llr32 = (uint32_t *)dlsch_llr;
879
  //} else {
880
  //llr32 = (uint32_t*)*llr32p;
881
882
883
  //}
#elif defined(__arm__)
  //if (symbol==2) {
884
  llr16 = (int16_t *)dlsch_llr;
885
886
887
888
889
  //} else {
  //  llr16 = (int16_t*)*llr32p;
  //}
#endif
#if defined(__x86_64__) || defined(__i386__)
890
  ch_mag = (__m128i *)&dl_ch_mag[0][0];
891
#elif defined(__arm__)
892
  ch_mag = (int16x8_t *)&dl_ch_mag[0][0];
893
894
895
896
#endif
  len = frame_parms->N_RB_DL*12*10;
  // update output pointer according to number of REs in this symbol (<<2 because 4 bits per RE)
  //if (symbol==2)
897
  *llr32p = dlsch_llr + (len<<2);
898
  //else
899
  //*llr32p += (len<<2);
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  len_mod4 = len&3;
  len>>=2;  // length in quad words (4 REs)
  len+=(len_mod4==0 ? 0 : 1);

  for (i=0; i<len; i++) {
#if defined(__x86_64__) || defined(__i386__)
    xmm0 = _mm_abs_epi16(rxF[i]);
    xmm0 = _mm_subs_epi16(ch_mag[i],xmm0);
    // lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
    llr128[0] = _mm_unpacklo_epi32(rxF[i],xmm0);
    llr128[1] = _mm_unpackhi_epi32(rxF[i],xmm0);
    llr32[0] = ((uint32_t *)&llr128[0])[0];
    llr32[1] = ((uint32_t *)&llr128[0])[1];
    llr32[2] = ((uint32_t *)&llr128[0])[2];
    llr32[3] = ((uint32_t *)&llr128[0])[3];
    llr32[4] = ((uint32_t *)&llr128[1])[0];
    llr32[5] = ((uint32_t *)&llr128[1])[1];
    llr32[6] = ((uint32_t *)&llr128[1])[2];
    llr32[7] = ((uint32_t *)&llr128[1])[3];
    llr32+=8;
#elif defined(__arm__)
    xmm0 = vabsq_s16(rxF[i]);
    xmm0 = vsubq_s16(ch_mag[i],xmm0);
    // lambda_1=y_R, lambda_2=|y_R|-|h|^2, lamda_3=y_I, lambda_4=|y_I|-|h|^2
    llr16[0] = vgetq_lane_s16(rxF[i],0);
    llr16[1] = vgetq_lane_s16(xmm0,0);
    llr16[2] = vgetq_lane_s16(rxF[i],1);
    llr16[3] = vgetq_lane_s16(xmm0,1);
    llr16[4] = vgetq_lane_s16(rxF[i],2);
    llr16[5] = vgetq_lane_s16(xmm0,2);
    llr16[6] = vgetq_lane_s16(rxF[i],2);
    llr16[7] = vgetq_lane_s16(xmm0,3);
    llr16[8] = vgetq_lane_s16(rxF[i],4);
    llr16[9] = vgetq_lane_s16(xmm0,4);
    llr16[10] = vgetq_lane_s16(rxF[i],5);
    llr16[11] = vgetq_lane_s16(xmm0,5);
    llr16[12] = vgetq_lane_s16(rxF[i],6);
    llr16[13] = vgetq_lane_s16(xmm0,6);
    llr16[14] = vgetq_lane_s16(rxF[i],7);
    llr16[15] = vgetq_lane_s16(xmm0,7);
    llr16+=16;
#endif
  }

#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}
949

950

951
952
953
954
955
956
957
958
959
960
//----------------------------------------------------------------------------------------------
// 64-QAM
//----------------------------------------------------------------------------------------------

void mch_64qam_llr(LTE_DL_FRAME_PARMS *frame_parms,
                   int **rxdataF_comp,
                   short *dlsch_llr,
                   int **dl_ch_mag,
                   int **dl_ch_magb,
                   unsigned char symbol,
961
                   short **llr_save) {
962
963
#if defined(__x86_64__) || defined(__i386__)
  __m128i xmm1,xmm2,*ch_mag,*ch_magb;
964
  __m128i *rxF = (__m128i *)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
965
966
#elif defined(__arm__)
  int16x8_t xmm1,xmm2,*ch_mag,*ch_magb;
967
  int16x8_t *rxF = (int16x8_t *)&rxdataF_comp[0][(symbol*frame_parms->N_RB_DL*12)];
968
969
970
971
972
973
974
975
976
977
978
979
980
#endif
  int i,len,len2;
  //   int j=0;
  unsigned char len_mod4;
  short *llr;
  int16_t *llr2;

  if (symbol==2)
    llr = dlsch_llr;
  else
    llr = *llr_save;

#if defined(__x86_64__) || defined(__i386__)
981
982
  ch_mag = (__m128i *)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
  ch_magb = (__m128i *)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
983
#elif defined(__arm__)
984
985
  ch_mag = (int16x8_t *)&dl_ch_mag[0][(symbol*frame_parms->N_RB_DL*12)];
  ch_magb = (int16x8_t *)&dl_ch_magb[0][(symbol*frame_parms->N_RB_DL*12)];
986
#endif
987

988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
  if ((symbol==2) || (symbol==6) || (symbol==10)) {
    len = frame_parms->N_RB_DL*6;
  } else {
    len = frame_parms->N_RB_DL*12;
  }

  llr2 = llr;
  llr += (len*6);
  len_mod4 =len&3;
  len2=len>>2;  // length in quad words (4 REs)
  len2+=(len_mod4?0:1);

  for (i=0; i<len2; i++) {
#if defined(__x86_64__) || defined(__i386__)
    xmm1 = _mm_abs_epi16(rxF[i]);
    xmm1  = _mm_subs_epi16(ch_mag[i],xmm1);
    xmm2 = _mm_abs_epi16(xmm1);
    xmm2 = _mm_subs_epi16(ch_magb[i],xmm2);
#elif defined(__arm__)
    xmm1 = vabsq_s16(rxF[i]);
    xmm1 = vsubq_s16(ch_mag[i],xmm1);
    xmm2 = vabsq_s16(xmm1);
    xmm2 = vsubq_s16(ch_magb[i],xmm2);
#endif
1012
    // loop over all LLRs in quad word (24 coded bits)
1013
    /*
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
    for (j=0;j<8;j+=2) {
      llr2[0] = ((short *)&rxF[i])[j];
      llr2[1] = ((short *)&rxF[i])[j+1];
      llr2[2] = _mm_extract_epi16(xmm1,j);
      llr2[3] = _mm_extract_epi16(xmm1,j+1);//((short *)&xmm1)[j+1];
      llr2[4] = _mm_extract_epi16(xmm2,j);//((short *)&xmm2)[j];
      llr2[5] = _mm_extract_epi16(xmm2,j+1);//((short *)&xmm2)[j+1];

      llr2+=6;
    }
1024
    */
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
    llr2[0] = ((short *)&rxF[i])[0];
    llr2[1] = ((short *)&rxF[i])[1];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,0);
    llr2[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,0);
    llr2[3] = vgetq_lane_s16(xmm1,1);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,0);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,1);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
    llr2[0] = ((short *)&rxF[i])[2];
    llr2[1] = ((short *)&rxF[i])[3];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,2);
    llr2[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,2);
    llr2[3] = vgetq_lane_s16(xmm1,3);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,2);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,3);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
    llr2[0] = ((short *)&rxF[i])[4];
    llr2[1] = ((short *)&rxF[i])[5];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,4);
    llr2[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,4);
    llr2[3] = vgetq_lane_s16(xmm1,5);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,4);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,5);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
    llr2[0] = ((short *)&rxF[i])[6];
    llr2[1] = ((short *)&rxF[i])[7];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,6);
    llr2[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,6);
    llr2[3] = vgetq_lane_s16(xmm1,7);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,6);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,7);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
  }

  *llr_save = llr;
#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}

void mch_64qam_llr_khz_1dot25(LTE_DL_FRAME_PARMS *frame_parms,
1091
1092
1093
1094
1095
1096
                              int **rxdataF_comp,
                              short *dlsch_llr,
                              int **dl_ch_mag,
                              int **dl_ch_magb,
                              /*unsigned char symbol,*/
                              short **llr_save) {
1097
1098
#if defined(__x86_64__) || defined(__i386__)
  __m128i xmm1,xmm2,*ch_mag,*ch_magb;
1099
  __m128i *rxF = (__m128i *)&rxdataF_comp[0][0];
1100
1101
#elif defined(__arm__)
  int16x8_t xmm1,xmm2,*ch_mag,*ch_magb;
1102
  int16x8_t *rxF = (int16x8_t *)&rxdataF_comp[0][0];
1103
1104
1105
1106
1107
1108
1109
#endif
  int i,len,len2;
  //   int j=0;
  unsigned char len_mod4;
  short *llr;
  int16_t *llr2;
  //if (symbol==2)
1110
  llr = dlsch_llr;
1111
  //else
1112
  //llr = *llr_save;
1113
#if defined(__x86_64__) || defined(__i386__)
1114
1115
  ch_mag = (__m128i *)&dl_ch_mag[0][0];
  ch_magb = (__m128i *)&dl_ch_magb[0][0];
1116
#elif defined(__arm__)
1117
1118
  ch_mag = (int16x8_t *)&dl_ch_mag[0][0];
  ch_magb = (int16x8_t *)&dl_ch_magb[0][0];
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
#endif
  len = frame_parms->N_RB_DL*12*10;
  llr2 = llr;
  llr += (len*6);
  len_mod4 =len&3;
  len2=len>>2;  // length in quad words (4 REs)
  len2+=(len_mod4?0:1);

  for (i=0; i<len2; i++) {
#if defined(__x86_64__) || defined(__i386__)
    xmm1 = _mm_abs_epi16(rxF[i]);
    xmm1  = _mm_subs_epi16(ch_mag[i],xmm1);
    xmm2 = _mm_abs_epi16(xmm1);
    xmm2 = _mm_subs_epi16(ch_magb[i],xmm2);
#elif defined(__arm__)
    xmm1 = vabsq_s16(rxF[i]);
    xmm1 = vsubq_s16(ch_mag[i],xmm1);
    xmm2 = vabsq_s16(xmm1);
    xmm2 = vsubq_s16(ch_magb[i],xmm2);
#endif
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
    // loop over all LLRs in quad word (24 coded bits)
    /*
    for (j=0;j<8;j+=2) {
      llr2[0] = ((short *)&rxF[i])[j];
      llr2[1] = ((short *)&rxF[i])[j+1];
      llr2[2] = _mm_extract_epi16(xmm1,j);
      llr2[3] = _mm_extract_epi16(xmm1,j+1);//((short *)&xmm1)[j+1];
      llr2[4] = _mm_extract_epi16(xmm2,j);//((short *)&xmm2)[j];
      llr2[5] = _mm_extract_epi16(xmm2,j+1);//((short *)&xmm2)[j+1];

      llr2+=6;
    }
    */
    llr2[0] = ((short *)&rxF[i])[0];
    llr2[1] = ((short *)&rxF[i])[1];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,0);
    llr2[3] = _mm_extract_epi16(xmm1,1);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,0);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,1);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,0);
    llr2[3] = vgetq_lane_s16(xmm1,1);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,0);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,1);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
    llr2[0] = ((short *)&rxF[i])[2];
    llr2[1] = ((short *)&rxF[i])[3];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,2);
    llr2[3] = _mm_extract_epi16(xmm1,3);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,2);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,3);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,2);
    llr2[3] = vgetq_lane_s16(xmm1,3);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,2);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,3);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
    llr2[0] = ((short *)&rxF[i])[4];
    llr2[1] = ((short *)&rxF[i])[5];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,4);
    llr2[3] = _mm_extract_epi16(xmm1,5);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,4);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,5);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,4);
    llr2[3] = vgetq_lane_s16(xmm1,5);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,4);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,5);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
    llr2[0] = ((short *)&rxF[i])[6];
    llr2[1] = ((short *)&rxF[i])[7];
#if defined(__x86_64__) || defined(__i386__)
    llr2[2] = _mm_extract_epi16(xmm1,6);
    llr2[3] = _mm_extract_epi16(xmm1,7);//((short *)&xmm1)[j+1];
    llr2[4] = _mm_extract_epi16(xmm2,6);//((short *)&xmm2)[j];
    llr2[5] = _mm_extract_epi16(xmm2,7);//((short *)&xmm2)[j+1];
#elif defined(__arm__)
    llr2[2] = vgetq_lane_s16(xmm1,6);
    llr2[3] = vgetq_lane_s16(xmm1,7);//((short *)&xmm1)[j+1];
    llr2[4] = vgetq_lane_s16(xmm2,6);//((short *)&xmm2)[j];
    llr2[5] = vgetq_lane_s16(xmm2,7);//((short *)&xmm2)[j+1];
#endif
    llr2+=6;
  }

  *llr_save = llr;
#if defined(__x86_64__) || defined(__i386__)
  _mm_empty();
  _m_empty();
#endif
}
1216

1217

1218
1219
1220
1221
1222

int avg_pmch[4];
int rx_pmch(PHY_VARS_UE *ue,
            unsigned char eNB_id,
            uint8_t subframe,
1223
            unsigned char symbol) {
1224
  LTE_UE_COMMON *common_vars  = &ue->common_vars;
1225
  LTE_UE_PDSCH **pdsch_vars   = &ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id];
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
  LTE_DL_FRAME_PARMS *frame_parms    = &ue->frame_parms;
  LTE_UE_DLSCH_t   **dlsch        = &ue->dlsch_MCH[eNB_id];
  int avgs,aarx;
  mch_extract_rbs(common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF,
                  common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id],
                  pdsch_vars[eNB_id]->rxdataF_ext,
                  pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                  symbol,
                  subframe,
                  frame_parms);

  if (symbol == 2) {
    mch_channel_level(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                      frame_parms,
                      avg_pmch,
                      symbol,
                      frame_parms->N_RB_DL);
  }

  avgs = 0;

  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
    avgs = cmax(avgs,avg_pmch[aarx]);

  if (get_Qm(dlsch[0]->harq_processes[0]->mcs)==2)
    pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2) ;// + 2
  else
    pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2); // + 5;// + 2

  mch_channel_compensation(pdsch_vars[eNB_id]->rxdataF_ext,
                           pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                           pdsch_vars[eNB_id]->dl_ch_mag0,
                           pdsch_vars[eNB_id]->dl_ch_magb0,
                           pdsch_vars[eNB_id]->rxdataF_comp0,
                           frame_parms,
                           symbol,
                           get_Qm(dlsch[0]->harq_processes[0]->mcs),
                           pdsch_vars[eNB_id]->log2_maxh);

  if (frame_parms->nb_antennas_rx > 1)
    mch_detection_mrc(frame_parms,
                      pdsch_vars[eNB_id]->rxdataF_comp0,
                      pdsch_vars[eNB_id]->dl_ch_mag0,
                      pdsch_vars[eNB_id]->dl_ch_magb0,
                      symbol);

  switch (get_Qm(dlsch[0]->harq_processes[0]->mcs)) {
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
    case 2 :
      mch_qpsk_llr(frame_parms,
                   pdsch_vars[eNB_id]->rxdataF_comp0,
                   pdsch_vars[eNB_id]->llr[0],
                   symbol,
                   pdsch_vars[eNB_id]->llr128);
      break;

    case 4:
      mch_16qam_llr(frame_parms,
                    pdsch_vars[eNB_id]->rxdataF_comp0,
                    pdsch_vars[eNB_id]->llr[0],
                    pdsch_vars[eNB_id]->dl_ch_mag0,
                    symbol,
                    pdsch_vars[eNB_id]->llr128);
      break;

    case 6:
      mch_64qam_llr(frame_parms,
                    pdsch_vars[eNB_id]->rxdataF_comp0,
                    pdsch_vars[eNB_id]->llr[0],
                    pdsch_vars[eNB_id]->dl_ch_mag0,
                    pdsch_vars[eNB_id]->dl_ch_magb0,
                    symbol,
                    pdsch_vars[eNB_id]->llr128);
      break;
1299
1300
1301
1302
  }

  return(0);
}
1303

1304
1305
1306
1307
1308
1309
1310
int rx_pmch_khz_1dot25(PHY_VARS_UE *ue,
                       unsigned char eNB_id,
                       uint8_t subframe/*,
            unsigned char symbol*/
                       ,int mcs) { // currently work around TOFIX
  //unsigned int symbol;
  LTE_UE_COMMON *common_vars  = &ue->common_vars;
1311
  LTE_UE_PDSCH **pdsch_vars   = &ue->pdsch_vars_MCH[ue->current_thread_id[subframe]][eNB_id];
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
  LTE_DL_FRAME_PARMS *frame_parms    = &ue->frame_parms;
  //LTE_UE_DLSCH_t   **dlsch        = &ue->dlsch_MCH[eNB_id];
  int avgs,aarx;
  mch_extract_rbs_khz_1dot25(common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF,
                             common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].dl_ch_estimates[eNB_id],
                             pdsch_vars[eNB_id]->rxdataF_ext,
                             pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                             /*symbol,*/
                             subframe,
                             frame_parms);
  mch_channel_level_khz_1dot25(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                               frame_parms,
                               avg_pmch,
                               /*symbol,*/
                               frame_parms->N_RB_DL);
  avgs = 0;
1328

1329
1330
1331
  for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
    avgs = cmax(avgs,avg_pmch[aarx]);
  }
1332

1333
1334
1335
1336
  if (get_Qm(mcs/*dlsch[0]->harq_processes[0]->mcs)==2*/)==2)
    pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2) ;// + 2
  else
    pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs)/2); // + 5;// + 2*/
1337

1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
  mch_channel_compensation_khz_1dot25(pdsch_vars[eNB_id]->rxdataF_ext,
                                      pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                      pdsch_vars[eNB_id]->dl_ch_mag0,
                                      pdsch_vars[eNB_id]->dl_ch_magb0,
                                      pdsch_vars[eNB_id]->rxdataF_comp0,
                                      frame_parms,
                                      /*symbol,*/
                                      get_Qm(mcs/*dlsch[0]->harq_processes[0]->mcs*/),
                                      pdsch_vars[eNB_id]->log2_maxh);

  if (frame_parms->nb_antennas_rx > 1) {
1349
    mch_detection_mrc_khz_1dot25(frame_parms,
1350
1351
1352
                                 pdsch_vars[eNB_id]->rxdataF_comp0,
                                 pdsch_vars[eNB_id]->dl_ch_mag0,
                                 pdsch_vars[eNB_id]->dl_ch_magb0/*,
1353
1354
1355
1356
                      symbol*/);
  }

  switch (get_Qm(mcs/*dlsch[0]->harq_processes[0]->mcs*/)) {
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
    case 2 :
      mch_qpsk_llr_khz_1dot25(frame_parms,
                              pdsch_vars[eNB_id]->rxdataF_comp0,
                              pdsch_vars[eNB_id]->llr[0],
                              /*symbol,*/
                              pdsch_vars[eNB_id]->llr128);
      break;

    case 4:
      mch_16qam_llr_khz_1dot25(frame_parms,
                               pdsch_vars[eNB_id]->rxdataF_comp0,
                               pdsch_vars[eNB_id]->llr[0],
                               pdsch_vars[eNB_id]->dl_ch_mag0,
                               /*symbol,*/
                               pdsch_vars[eNB_id]->llr128);
      break;

    case 6:
      mch_64qam_llr_khz_1dot25(frame_parms,
                               pdsch_vars[eNB_id]->rxdataF_comp0,
                               pdsch_vars[eNB_id]->llr[0],
                               pdsch_vars[eNB_id]->dl_ch_mag0,
                               pdsch_vars[eNB_id]->dl_ch_magb0,
                               /*symbol,*/
                               pdsch_vars[eNB_id]->llr128);
      break;
1383
1384
1385
1386
  }

  return(0);
}
1387

1388