/*
    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
*/

/*! \file PHY/LTE_TRANSPORT/dlsch_demodulation.c
    \brief Top-level routines for demodulating the PDSCH physical channel from 36-211, V8.6 2009-03
    \author R. Knopp, F. Kaltenberger,A. Bhamri, S. Aubert, X. Xiang
    \date 2011
    \version 0.1
    \company Eurecom
    \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,ankit.bhamri@eurecom.fr,sebastien.aubert@eurecom.fr
    \note
    \warning
*/
#include "PHY/defs_UE.h"
#include "PHY/phy_extern_ue.h"
#include "SCHED_UE/sched_UE.h"
#include "transport_ue.h"
#include "transport_proto_ue.h"
#include "PHY/sse_intrin.h"
#include "T.h"
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
#include <string.h>
#include <linux/version.h>
#if RHEL_RELEASE_CODE >= 1796
    #include <lapacke/lapacke_utils.h>
    #include <lapacke/lapacke.h>
#else
    #include <lapacke_utils.h>
    #include <lapacke.h>
#endif
#include <cblas.h>
#include "linear_preprocessing_rec.h"

#define NOCYGWIN_STATIC
//#define DEBUG_MMSE

/*  dynamic shift for LLR computation for TM3/4
    set as command line argument, see lte-softmodem.c
    default value: 0
*/
int16_t dlsch_demod_shift = 0;
int16_t interf_unaw_shift = 13;

unsigned char offset_mumimo_llr_drange_fix = 0;
//inferference-free case
unsigned char interf_unaw_shift_tm4_mcs[29] = {5, 3, 4, 3, 3, 2, 1, 1, 2, 0, 1, 1, 1, 1, 0, 0,
                                               1, 1, 1, 1, 0, 2, 1, 0, 1, 0, 1, 0, 0
                                              } ;
unsigned char interf_unaw_shift_tm1_mcs[29] = {5, 5, 4, 3, 3, 3, 2, 2, 4, 4, 2, 3, 3, 3, 1, 1,
                                               0, 1, 1, 2, 5, 4, 4, 6, 5, 1, 0, 5, 6
                                              } ; // mcs 21, 26, 28 seem to be errorneous

/*
    //original values from sebastion + same hand tuning
    unsigned char offset_mumimo_llr_drange[29][3]={{8,8,8},{7,7,7},{7,7,7},{7,7,7},{6,6,6},{6,6,6},{6,6,6},{5,5,5},{4,4,4},{1,2,4}, // QPSK
    {5,5,4},{5,5,5},{5,5,5},{3,3,3},{2,2,2},{2,2,2},{2,2,2}, // 16-QAM
    {2,2,1},{3,3,3},{3,3,3},{3,3,1},{2,2,2},{2,2,2},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}}; //64-QAM
*/
/*
    //first optimization try
    unsigned char offset_mumimo_llr_drange[29][3]={{7, 8, 7},{6, 6, 7},{6, 6, 7},{6, 6, 6},{5, 6, 6},{5, 5, 6},{5, 5, 6},{4, 5, 4},{4, 3, 4},{3, 2, 2},{6, 5, 5},{5, 4, 4},{5, 5, 4},{3, 3, 2},{2, 2, 1},{2, 1, 1},{2, 2, 2},{3, 3, 3},{3, 3, 2},{3, 3, 2},{3, 2, 1},{2, 2, 2},{2, 2, 2},{0, 0, 0},{0, 0, 0},{0, 0, 0},{0, 0, 0},{0, 0, 0}};
*/
//second optimization try
/*
    unsigned char offset_mumimo_llr_drange[29][3]={{5, 8, 7},{4, 6, 8},{3, 6, 7},{7, 7, 6},{4, 7, 8},{4, 7, 4},{6, 6, 6},{3, 6, 6},{3, 6, 6},{1, 3, 4},{1, 1, 0},{3, 3, 2},{3, 4, 1},{4, 0, 1},{4, 2, 2},{3, 1, 2},{2, 1, 0},{2, 1, 1},{1, 0, 1},{1, 0, 1},{0, 0, 0},{1, 0, 0},{0, 0, 0},{0, 1, 0},{1, 0, 0},{0, 0, 0},{0, 0, 0},{0, 0, 0},{0, 0, 0}};  w
*/
unsigned char offset_mumimo_llr_drange[29][3] = {{0, 6, 5}, {0, 4, 5}, {0, 4, 5}, {0, 5, 4}, {0, 5, 6}, {0, 5, 3}, {0, 4, 4}, {0, 4, 4}, {0, 3, 3}, {0, 1, 2}, {1, 1, 0}, {1, 3, 2}, {3, 4, 1}, {2, 0, 0}, {2, 2, 2}, {1, 1, 1}, {2, 1, 0}, {2, 1, 1}, {1, 0, 1}, {1, 0, 1}, {0, 0, 0}, {1, 0, 0}, {0, 0, 0}, {0, 1, 0}, {1, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}};

extern void print_shorts(char *s, int16_t *x);

int rx_pdsch(PHY_VARS_UE *ue,
             PDSCH_t type,
             unsigned char eNB_id,
             unsigned char eNB_id_i, //if this == ue->n_connected_eNB, we assume MU interference
             uint32_t frame,
             uint8_t subframe,
             unsigned char symbol,
             unsigned char first_symbol_flag,
             RX_type_t rx_type,
             unsigned char i_mod,
             unsigned char harq_pid)
{
    LTE_UE_COMMON *common_vars  = &ue->common_vars;
    LTE_UE_PDSCH **pdsch_vars;
    LTE_DL_FRAME_PARMS *frame_parms    = &ue->frame_parms;
    PHY_MEASUREMENTS *measurements = &ue->measurements;
    LTE_UE_DLSCH_t   **dlsch;
    int avg[4];
    int avg_0[2];
    int avg_1[2];
    unsigned short mmse_flag = 0;
#if UE_TIMING_TRACE
    uint8_t slot = 0;
#endif
    unsigned char aatx, aarx;
    unsigned short nb_rb = 0, round;
    int avgs = 0, rb;
    LTE_DL_UE_HARQ_t *dlsch0_harq, *dlsch1_harq = 0;
    uint8_t beamforming_mode;
    uint32_t *rballoc;
    int32_t **rxdataF_comp_ptr;
    int32_t **dl_ch_mag_ptr;
    int32_t codeword_TB0 = -1;
    int32_t codeword_TB1 = -1;

    switch(type)
    {
        case SI_PDSCH:
            pdsch_vars = &ue->pdsch_vars_SI[eNB_id];
            dlsch = &ue->dlsch_SI[eNB_id];
            dlsch0_harq = dlsch[0]->harq_processes[harq_pid];
            beamforming_mode  = 0;
            break;

        case RA_PDSCH:
            pdsch_vars = &ue->pdsch_vars_ra[eNB_id];
            dlsch = &ue->dlsch_ra[eNB_id];
            dlsch0_harq = dlsch[0]->harq_processes[harq_pid];
            beamforming_mode  = 0;
            break;

        case PDSCH:
            pdsch_vars = ue->pdsch_vars[ue->current_thread_id[subframe]];
            dlsch = ue->dlsch[ue->current_thread_id[subframe]][eNB_id];
            //printf("status TB0 = %d, status TB1 = %d \n", dlsch[0]->harq_processes[harq_pid]->status, dlsch[1]->harq_processes[harq_pid]->status);
            LOG_D(PHY, "AbsSubframe %d.%d / Sym %d harq_pid %d,  harq status %d.%d \n",
                  frame, subframe, symbol, harq_pid,
                  dlsch[0]->harq_processes[harq_pid]->status,
                  dlsch[1]->harq_processes[harq_pid]->status);

            if((dlsch[0]->harq_processes[harq_pid]->status == ACTIVE) &&
                    (dlsch[1]->harq_processes[harq_pid]->status == ACTIVE))
            {
                codeword_TB0 = dlsch[0]->harq_processes[harq_pid]->codeword;
                codeword_TB1 = dlsch[1]->harq_processes[harq_pid]->codeword;
                dlsch0_harq = dlsch[codeword_TB0]->harq_processes[harq_pid];
                dlsch1_harq = dlsch[codeword_TB1]->harq_processes[harq_pid];
#ifdef DEBUG_HARQ
                printf("[DEMOD] I am assuming both TBs are active\n");
#endif
            }
            else if((dlsch[0]->harq_processes[harq_pid]->status == ACTIVE) &&
                    (dlsch[1]->harq_processes[harq_pid]->status != ACTIVE))
            {
                codeword_TB0 = dlsch[0]->harq_processes[harq_pid]->codeword;
                dlsch0_harq = dlsch[0]->harq_processes[harq_pid];
                dlsch1_harq = NULL;
                codeword_TB1 = -1;
#ifdef DEBUG_HARQ
                printf("[DEMOD] I am assuming only TB0 is active\n");
#endif
            }
            else if((dlsch[0]->harq_processes[harq_pid]->status != ACTIVE) &&
                    (dlsch[1]->harq_processes[harq_pid]->status == ACTIVE))
            {
                codeword_TB1 = dlsch[1]->harq_processes[harq_pid]->codeword;
                dlsch0_harq  = dlsch[1]->harq_processes[harq_pid];
                dlsch1_harq  = NULL;
                codeword_TB0 = -1;
#ifdef DEBUG_HARQ
                printf("[DEMOD] I am assuming only TB1 is active, it is in cw %d\n", dlsch0_harq->codeword);
#endif
            }
            else
            {
                LOG_E(PHY, "[UE][FATAL] Frame %d subframe %d: no active DLSCH\n", ue->proc.proc_rxtx[0].frame_rx, subframe);
                return(-1);
            }

            beamforming_mode  = ue->transmission_mode[eNB_id] < 7 ? 0 : ue->transmission_mode[eNB_id];
            break;

        default:
            LOG_E(PHY, "[UE][FATAL] Frame %d subframe %d: Unknown PDSCH format %d\n", ue->proc.proc_rxtx[0].frame_rx, subframe, type);
            return(-1);
            break;
    }

#ifdef DEBUG_HARQ
    printf("[DEMOD] MIMO mode = %d\n", dlsch0_harq->mimo_mode);
    printf("[DEMOD] cw for TB0 = %d, cw for TB1 = %d\n", codeword_TB0, codeword_TB1);
#endif
    DevAssert(dlsch0_harq);
    round = dlsch0_harq->round;
    //printf("round = %d\n", round);

    if(eNB_id > 2)
    {
        LOG_W(PHY, "dlsch_demodulation.c: Illegal eNB_id %d\n", eNB_id);
        return(-1);
    }

    if(!common_vars)
    {
        LOG_W(PHY, "dlsch_demodulation.c: Null common_vars\n");
        return(-1);
    }

    if(!dlsch[0])
    {
        LOG_W(PHY, "dlsch_demodulation.c: Null dlsch_ue pointer\n");
        return(-1);
    }

    if(!pdsch_vars)
    {
        LOG_W(PHY, "dlsch_demodulation.c: Null pdsch_vars pointer\n");
        return(-1);
    }

    if(!frame_parms)
    {
        LOG_W(PHY, "dlsch_demodulation.c: Null frame_parms\n");
        return(-1);
    }

    if(((frame_parms->Ncp == NORMAL) && (symbol >= 7)) ||
            ((frame_parms->Ncp == EXTENDED) && (symbol >= 6)))
    {
        rballoc = dlsch0_harq->rb_alloc_odd;
    }
    else
    {
        rballoc = dlsch0_harq->rb_alloc_even;
    }

    if(dlsch0_harq->mimo_mode > DUALSTREAM_PUSCH_PRECODING)
    {
        LOG_E(PHY, "This transmission mode is not yet supported!\n");
        return(-1);
    }

    if((dlsch0_harq->mimo_mode == LARGE_CDD) || ((dlsch0_harq->mimo_mode >= DUALSTREAM_UNIFORM_PRECODING1) && (dlsch0_harq->mimo_mode <= DUALSTREAM_PUSCH_PRECODING)))
    {
        DevAssert(dlsch1_harq);

        if(eNB_id != eNB_id_i)
        {
            LOG_E(PHY, "TM3/TM4 requires to set eNB_id==eNB_id_i!\n");
            return(-1);
        }
    }

#if UE_TIMING_TRACE

    if(symbol > ue->frame_parms.symbols_per_tti >> 1)
    {
        slot = 1;
    }

#endif
#ifdef DEBUG_HARQ
    printf("Demod  dlsch0_harq->pmi_alloc %d\n",  dlsch0_harq->pmi_alloc);
#endif

    if(frame_parms->nb_antenna_ports_eNB > 1 && beamforming_mode == 0)
    {
#ifdef DEBUG_DLSCH_MOD
        LOG_D(PHY, "dlsch: using pmi %x (%p), rb_alloc %x\n", pmi2hex_2Ar1(dlsch0_harq->pmi_alloc), dlsch[0], dlsch0_harq->rb_alloc_even[0]);
#endif
#if UE_TIMING_TRACE
        start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
#endif
        nb_rb = dlsch_extract_rbs_dual(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,
                                       dlsch0_harq->pmi_alloc,
                                       pdsch_vars[eNB_id]->pmi_ext,
                                       rballoc,
                                       symbol,
                                       subframe,
                                       ue->high_speed_flag,
                                       frame_parms,
                                       dlsch0_harq->mimo_mode);
#ifdef DEBUG_DLSCH_MOD
        printf("dlsch: using pmi %lx, rb_alloc %x, pmi_ext ", pmi2hex_2Ar1(dlsch0_harq->pmi_alloc), *rballoc);

        for(rb = 0; rb < nb_rb; rb++)
        {
            printf("%d", pdsch_vars[eNB_id]->pmi_ext[rb]);
        }

        printf("\n");
#endif

        if(rx_type >= rx_IC_single_stream)
        {
            if(eNB_id_i < ue->n_connected_eNB) // we are in TM5
                nb_rb = dlsch_extract_rbs_dual(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_i],
                                               pdsch_vars[eNB_id_i]->rxdataF_ext,
                                               pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                               dlsch0_harq->pmi_alloc,
                                               pdsch_vars[eNB_id_i]->pmi_ext,
                                               rballoc,
                                               symbol,
                                               subframe,
                                               ue->high_speed_flag,
                                               frame_parms,
                                               dlsch0_harq->mimo_mode);
            else
                nb_rb = dlsch_extract_rbs_dual(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_i]->rxdataF_ext,
                                               pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                               dlsch0_harq->pmi_alloc,
                                               pdsch_vars[eNB_id_i]->pmi_ext,
                                               rballoc,
                                               symbol,
                                               subframe,
                                               ue->high_speed_flag,
                                               frame_parms,
                                               dlsch0_harq->mimo_mode);
        }
    }
    else if(beamforming_mode == 0)    //else if nb_antennas_ports_eNB==1 && beamforming_mode == 0
    {
        nb_rb = dlsch_extract_rbs_single(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,
                                         dlsch0_harq->pmi_alloc,
                                         pdsch_vars[eNB_id]->pmi_ext,
                                         rballoc,
                                         symbol,
                                         subframe,
                                         ue->high_speed_flag,
                                         frame_parms);

        if(rx_type == rx_IC_single_stream)
        {
            if(eNB_id_i < ue->n_connected_eNB)
                nb_rb = dlsch_extract_rbs_single(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_i],
                                                 pdsch_vars[eNB_id_i]->rxdataF_ext,
                                                 pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                                 dlsch0_harq->pmi_alloc,
                                                 pdsch_vars[eNB_id_i]->pmi_ext,
                                                 rballoc,
                                                 symbol,
                                                 subframe,
                                                 ue->high_speed_flag,
                                                 frame_parms);
            else
                nb_rb = dlsch_extract_rbs_single(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_i]->rxdataF_ext,
                                                 pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                                 dlsch0_harq->pmi_alloc,
                                                 pdsch_vars[eNB_id_i]->pmi_ext,
                                                 rballoc,
                                                 symbol,
                                                 subframe,
                                                 ue->high_speed_flag,
                                                 frame_parms);
        }
    }
    else if(beamforming_mode == 7)    //else if beamforming_mode == 7
    {
        nb_rb = dlsch_extract_rbs_TM7(common_vars->common_vars_rx_data_per_thread[ue->current_thread_id[subframe]].rxdataF,
                                      pdsch_vars[eNB_id]->dl_bf_ch_estimates,
                                      pdsch_vars[eNB_id]->rxdataF_ext,
                                      pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext,
                                      rballoc,
                                      symbol,
                                      subframe,
                                      ue->high_speed_flag,
                                      frame_parms);
    }
    else if(beamforming_mode > 7)
    {
        LOG_W(PHY, "dlsch_demodulation: beamforming mode not supported yet.\n");
    }

    //printf("nb_rb = %d, eNB_id %d\n",nb_rb,eNB_id);
    if(nb_rb == 0)
    {
        //    LOG_D(PHY,"dlsch_demodulation.c: nb_rb=0\n");
        return(-1);
    }

#if UE_TIMING_TRACE
    stop_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
    LOG_I(PHY, "[AbsSFN %d.%d] Slot%d Symbol %d Flag %d type %d: Pilot/Data extraction  %5.2f \n", frame, subframe, slot, symbol,
          ue->high_speed_flag, type, ue->generic_stat_bis[ue->current_thread_id[subframe]][slot].p_time / (cpuf * 1000.0));
#endif
#if UE_TIMING_TRACE
    start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
#endif
    aatx = frame_parms->nb_antenna_ports_eNB;
    aarx = frame_parms->nb_antennas_rx;
    dlsch_scale_channel(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                        frame_parms,
                        dlsch,
                        symbol,
                        nb_rb);

    if((dlsch0_harq->mimo_mode < DUALSTREAM_UNIFORM_PRECODING1) &&
            (rx_type == rx_IC_single_stream) &&
            (eNB_id_i == ue->n_connected_eNB) &&
            (dlsch0_harq->dl_power_off == 0)
      )   // TM5 two-user
    {
        dlsch_scale_channel(pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                            frame_parms,
                            dlsch,
                            symbol,
                            nb_rb);
    }

#if UE_TIMING_TRACE
    stop_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
    LOG_I(PHY, "[AbsSFN %d.%d] Slot%d Symbol %d: Channel Scale  %5.2f \n", frame, subframe, slot, symbol, ue->generic_stat_bis[ue->current_thread_id[subframe]][slot].p_time / (cpuf * 1000.0));
    start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
#endif

    if(first_symbol_flag == 1)
    {
        if(beamforming_mode == 0)
        {
            if(dlsch0_harq->mimo_mode < LARGE_CDD)
            {
                dlsch_channel_level(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                    frame_parms,
                                    avg,
                                    symbol,
                                    nb_rb);
                avgs = 0;

                for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
                    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
                    {
                        avgs = cmax(avgs, avg[(aatx << 1) + aarx]);
                    }

                pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs) / 2) + 1;
            }
            else if((dlsch0_harq->mimo_mode == LARGE_CDD) ||
                    ((dlsch0_harq->mimo_mode >= DUALSTREAM_UNIFORM_PRECODING1) &&
                     (dlsch0_harq->mimo_mode <= DUALSTREAM_PUSCH_PRECODING)))
            {
                dlsch_channel_level_TM34(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                         frame_parms,
                                         pdsch_vars[eNB_id]->pmi_ext,
                                         avg_0,
                                         avg_1,
                                         symbol,
                                         nb_rb,
                                         mmse_flag,
                                         dlsch0_harq->mimo_mode);
                LOG_D(PHY, "Channel Level TM34  avg_0 %d, avg_1 %d, rx_type %d, rx_standard %d, dlsch_demod_shift %d \n", avg_0[0],
                      avg_1[0], rx_type, rx_standard, dlsch_demod_shift);

                if(rx_type > rx_standard)
                {
                    avg_0[0] = (log2_approx(avg_0[0]) / 2) + dlsch_demod_shift; // + 2 ;//+ 4;
                    avg_1[0] = (log2_approx(avg_1[0]) / 2) + dlsch_demod_shift; // + 2 ;//+ 4;
                    pdsch_vars[eNB_id]->log2_maxh0 = cmax(avg_0[0], 0);
                    pdsch_vars[eNB_id]->log2_maxh1 = cmax(avg_1[0], 0);
                    // printf("dlsch_demod_shift  %d\n", dlsch_demod_shift);
                }
                else
                {
                    avg_0[0] = (log2_approx(avg_0[0]) / 2) - 13 + interf_unaw_shift;
                    avg_1[0] = (log2_approx(avg_1[0]) / 2) - 13 + interf_unaw_shift;
                    pdsch_vars[eNB_id]->log2_maxh0 = cmax(avg_0[0], 0);
                    pdsch_vars[eNB_id]->log2_maxh1 = cmax(avg_1[0], 0);
                }
            }
            else if(dlsch0_harq->mimo_mode < DUALSTREAM_UNIFORM_PRECODING1)    // single-layer precoding (TM5, TM6)
            {
                if((rx_type == rx_IC_single_stream) && (eNB_id_i == ue->n_connected_eNB) && (dlsch0_harq->dl_power_off == 0))
                {
                    dlsch_channel_level_TM56(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                             frame_parms,
                                             pdsch_vars[eNB_id]->pmi_ext,
                                             avg,
                                             symbol,
                                             nb_rb);
                    avg[0] = log2_approx(avg[0]) - 13 + offset_mumimo_llr_drange[dlsch0_harq->mcs][(i_mod >> 1) - 1];
                    pdsch_vars[eNB_id]->log2_maxh = cmax(avg[0], 0);
                }
                else if(dlsch0_harq->dl_power_off == 1)    //TM6
                {
                    dlsch_channel_level(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                        frame_parms,
                                        avg,
                                        symbol,
                                        nb_rb);
                    avgs = 0;

                    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
                        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
                        {
                            avgs = cmax(avgs, avg[(aatx << 1) + aarx]);
                        }

                    pdsch_vars[eNB_id]->log2_maxh = (log2_approx(avgs) / 2) + 1;
                    pdsch_vars[eNB_id]->log2_maxh++;
                }
            }
        }
        else if(beamforming_mode == 7)
            dlsch_channel_level_TM7(pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext,
                                    frame_parms,
                                    avg,
                                    symbol,
                                    nb_rb);

#ifdef UE_DEBUG_TRACE
        LOG_D(PHY, "[DLSCH] AbsSubframe %d.%d log2_maxh = %d [log2_maxh0 %d log2_maxh1 %d] (%d,%d)\n",
              frame % 1024, subframe, pdsch_vars[eNB_id]->log2_maxh,
              pdsch_vars[eNB_id]->log2_maxh0,
              pdsch_vars[eNB_id]->log2_maxh1,
              avg[0], avgs);
        //LOG_D(PHY,"[DLSCH] mimo_mode = %d\n", dlsch0_harq->mimo_mode);
#endif
        //wait until pdcch is decoded
        //proc->channel_level = 1;
    }

    /*
        uint32_t wait = 0;
        while(proc->channel_level == 0)
        {
        usleep(1);
        wait++;
        }
    */
#if T_TRACER

    if(type == PDSCH)
    {
        T(T_UE_PHY_PDSCH_ENERGY, T_INT(eNB_id), T_INT(frame % 1024), T_INT(subframe),
          T_INT(avg[0]), T_INT(avg[1]),     T_INT(avg[2]),   T_INT(avg[3]));
    }

#endif
#if UE_TIMING_TRACE
    stop_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
    LOG_I(PHY, "[AbsSFN %d.%d] Slot%d Symbol %d first_symbol_flag %d: Channel Level  %5.2f \n", frame, subframe, slot, symbol, first_symbol_flag,
          ue->generic_stat_bis[ue->current_thread_id[subframe]][slot].p_time / (cpuf * 1000.0));
    start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
#endif

    if(rx_type == rx_IC_dual_stream && mmse_flag == 1)
    {
        precode_channel_est(pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                            frame_parms,
                            pdsch_vars[eNB_id],
                            symbol,
                            nb_rb,
                            dlsch0_harq->mimo_mode);
        mmse_processing_oai(pdsch_vars[eNB_id],
                            frame_parms,
                            measurements,
                            first_symbol_flag,
                            dlsch0_harq->mimo_mode,
                            mmse_flag,
                            0.0,
                            symbol,
                            nb_rb);
    }

    // Now channel compensation
    if(dlsch0_harq->mimo_mode < LARGE_CDD)
    {
        dlsch_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,
                                   (aatx > 1) ? pdsch_vars[eNB_id]->rho : NULL,
                                   frame_parms,
                                   symbol,
                                   first_symbol_flag,
                                   dlsch0_harq->Qm,
                                   nb_rb,
                                   pdsch_vars[eNB_id]->log2_maxh,
                                   measurements); // log2_maxh+I0_shift

        if(symbol == 5)
        {
            LOG_M("rxF_comp_d.m", "rxF_c_d", &pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1);
        }

        if((rx_type == rx_IC_single_stream) &&
                (eNB_id_i < ue->n_connected_eNB))
        {
            dlsch_channel_compensation(pdsch_vars[eNB_id_i]->rxdataF_ext,
                                       pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                       pdsch_vars[eNB_id_i]->dl_ch_mag0,
                                       pdsch_vars[eNB_id_i]->dl_ch_magb0,
                                       pdsch_vars[eNB_id_i]->rxdataF_comp0,
                                       (aatx > 1) ? pdsch_vars[eNB_id_i]->rho : NULL,
                                       frame_parms,
                                       symbol,
                                       first_symbol_flag,
                                       i_mod,
                                       nb_rb,
                                       pdsch_vars[eNB_id]->log2_maxh,
                                       measurements); // log2_maxh+I0_shift

            if(symbol == 5)
            {
                LOG_M("rxF_comp_d.m", "rxF_c_d", &pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1);
                LOG_M("rxF_comp_i.m", "rxF_c_i", &pdsch_vars[eNB_id_i]->rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1);
            }

            dlsch_dual_stream_correlation(frame_parms,
                                          symbol,
                                          nb_rb,
                                          pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                          pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                          pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                          pdsch_vars[eNB_id]->log2_maxh);
        }
    }
    else if((dlsch0_harq->mimo_mode == LARGE_CDD) || ((dlsch0_harq->mimo_mode >= DUALSTREAM_UNIFORM_PRECODING1) &&
            (dlsch0_harq->mimo_mode <= DUALSTREAM_PUSCH_PRECODING)))
    {
        dlsch_channel_compensation_TM34(frame_parms,
                                        pdsch_vars[eNB_id],
                                        measurements,
                                        eNB_id,
                                        symbol,
                                        dlsch0_harq->Qm,
                                        dlsch1_harq->Qm,
                                        harq_pid,
                                        dlsch0_harq->round,
                                        dlsch0_harq->mimo_mode,
                                        nb_rb,
                                        mmse_flag,
                                        pdsch_vars[eNB_id]->log2_maxh0,
                                        pdsch_vars[eNB_id]->log2_maxh1);

        if(symbol == 5)
        {
            LOG_M("rxF_comp_d00.m", "rxF_c_d00", &pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); // should be QAM
            LOG_M("rxF_comp_d01.m", "rxF_c_d01", &pdsch_vars[eNB_id]->rxdataF_comp0[1][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be almost 0
            LOG_M("rxF_comp_d10.m", "rxF_c_d10", &pdsch_vars[eNB_id]->rxdataF_comp1[harq_pid][round][0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be almost 0
            LOG_M("rxF_comp_d11.m", "rxF_c_d11", &pdsch_vars[eNB_id]->rxdataF_comp1[harq_pid][round][1][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be QAM
        }

        // compute correlation between signal and interference channels (rho12 and rho21)
        dlsch_dual_stream_correlation(frame_parms, // this is doing h11'*h12 and h21'*h22
                                      symbol,
                                      nb_rb,
                                      pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                      &(pdsch_vars[eNB_id]->dl_ch_estimates_ext[2]),
                                      pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                      pdsch_vars[eNB_id]->log2_maxh0);
        //printf("rho stream1 =%d\n", &pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round] );
        //to be optimized (just take complex conjugate)
        dlsch_dual_stream_correlation(frame_parms, // this is doing h12'*h11 and h22'*h21
                                      symbol,
                                      nb_rb,
                                      &(pdsch_vars[eNB_id]->dl_ch_estimates_ext[2]),
                                      pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                      pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                      pdsch_vars[eNB_id]->log2_maxh1);

        //  printf("rho stream2 =%d\n",&pdsch_vars[eNB_id]->dl_ch_rho2_ext );
        //printf("TM3 log2_maxh : %d\n",pdsch_vars[eNB_id]->log2_maxh);
        if(symbol == 5)
        {
            LOG_M("rho0_0.m", "rho0_0", &pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round][0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); // should be QAM
            LOG_M("rho2_0.m", "rho2_0", &pdsch_vars[eNB_id]->dl_ch_rho2_ext[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be almost 0
            LOG_M("rho0_1.m.m", "rho0_1", &pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round][1][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be almost 0
            LOG_M("rho2_1.m", "rho2_1", &pdsch_vars[eNB_id]->dl_ch_rho2_ext[1][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be QAM
        }
    }
    else if(dlsch0_harq->mimo_mode < DUALSTREAM_UNIFORM_PRECODING1)   // single-layer precoding (TM5, TM6)
    {
        if((rx_type == rx_IC_single_stream) && (eNB_id_i == ue->n_connected_eNB) && (dlsch0_harq->dl_power_off == 0))
        {
            dlsch_channel_compensation_TM56(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,
                                            pdsch_vars[eNB_id]->pmi_ext,
                                            frame_parms,
                                            measurements,
                                            eNB_id,
                                            symbol,
                                            dlsch0_harq->Qm,
                                            nb_rb,
                                            pdsch_vars[eNB_id]->log2_maxh,
                                            dlsch0_harq->dl_power_off);

            for(rb = 0; rb < nb_rb; rb++)
            {
                switch(pdsch_vars[eNB_id]->pmi_ext[rb])
                {
                    case 0:
                        pdsch_vars[eNB_id_i]->pmi_ext[rb] = 1;
                        break;

                    case 1:
                        pdsch_vars[eNB_id_i]->pmi_ext[rb] = 0;
                        break;

                    case 2:
                        pdsch_vars[eNB_id_i]->pmi_ext[rb] = 3;
                        break;

                    case 3:
                        pdsch_vars[eNB_id_i]->pmi_ext[rb] = 2;
                        break;
                }

                //  if (rb==0)
                //    printf("pmi %d, pmi_i %d\n",pdsch_vars[eNB_id]->pmi_ext[rb],pdsch_vars[eNB_id_i]->pmi_ext[rb]);
            }

            dlsch_channel_compensation_TM56(pdsch_vars[eNB_id_i]->rxdataF_ext,
                                            pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                            pdsch_vars[eNB_id_i]->dl_ch_mag0,
                                            pdsch_vars[eNB_id_i]->dl_ch_magb0,
                                            pdsch_vars[eNB_id_i]->rxdataF_comp0,
                                            pdsch_vars[eNB_id_i]->pmi_ext,
                                            frame_parms,
                                            measurements,
                                            eNB_id_i,
                                            symbol,
                                            i_mod,
                                            nb_rb,
                                            pdsch_vars[eNB_id]->log2_maxh,
                                            dlsch0_harq->dl_power_off);

            if(symbol == 5)
            {
                LOG_M("rxF_comp_d.m", "rxF_c_d", &pdsch_vars[eNB_id]->rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1);
                LOG_M("rxF_comp_i.m", "rxF_c_i", &pdsch_vars[eNB_id_i]->rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1);
            }

            dlsch_dual_stream_correlation(frame_parms,
                                          symbol,
                                          nb_rb,
                                          pdsch_vars[eNB_id]->dl_ch_estimates_ext,
                                          pdsch_vars[eNB_id_i]->dl_ch_estimates_ext,
                                          pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                          pdsch_vars[eNB_id]->log2_maxh);
        }
        else if(dlsch0_harq->dl_power_off == 1)
        {
            dlsch_channel_compensation_TM56(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,
                                            pdsch_vars[eNB_id]->pmi_ext,
                                            frame_parms,
                                            measurements,
                                            eNB_id,
                                            symbol,
                                            dlsch0_harq->Qm,
                                            nb_rb,
                                            pdsch_vars[eNB_id]->log2_maxh,
                                            1);
        }
    }
    else if(dlsch0_harq->mimo_mode == TM7)    //TM7
    {
        dlsch_channel_compensation(pdsch_vars[eNB_id]->rxdataF_ext,
                                   pdsch_vars[eNB_id]->dl_bf_ch_estimates_ext,
                                   pdsch_vars[eNB_id]->dl_ch_mag0,
                                   pdsch_vars[eNB_id]->dl_ch_magb0,
                                   pdsch_vars[eNB_id]->rxdataF_comp0,
                                   (aatx > 1) ? pdsch_vars[eNB_id]->rho : NULL,
                                   frame_parms,
                                   symbol,
                                   first_symbol_flag,
                                   get_Qm(dlsch0_harq->mcs),
                                   nb_rb,
                                   //9,
                                   pdsch_vars[eNB_id]->log2_maxh,
                                   measurements); // log2_maxh+I0_shift
    }

#if UE_TIMING_TRACE
    stop_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
    LOG_I(PHY, "[AbsSFN %d.%d] Slot%d Symbol %d log2_maxh %d Channel Comp  %5.2f \n", frame, subframe, slot, symbol, pdsch_vars[eNB_id]->log2_maxh,
          ue->generic_stat_bis[ue->current_thread_id[subframe]][slot].p_time / (cpuf * 1000.0));
    start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
#endif

    if(frame_parms->nb_antennas_rx > 1)
    {
        if((dlsch0_harq->mimo_mode == LARGE_CDD) ||
                ((dlsch0_harq->mimo_mode >= DUALSTREAM_UNIFORM_PRECODING1) &&
                 (dlsch0_harq->mimo_mode <= DUALSTREAM_PUSCH_PRECODING)))  // TM3 or TM4
        {
            if(frame_parms->nb_antenna_ports_eNB == 2)
            {
                dlsch_detection_mrc_TM34(frame_parms,
                                         pdsch_vars[eNB_id],
                                         harq_pid,
                                         dlsch0_harq->round,
                                         symbol,
                                         nb_rb,
                                         1);

                if(symbol == 5)
                {
                    LOG_M("rho0_mrc.m", "rho0_0", &pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round][0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); // should be QAM
                    LOG_M("rho2_mrc.m", "rho2_0", &pdsch_vars[eNB_id]->dl_ch_rho2_ext[0][symbol * frame_parms->N_RB_DL * 12], frame_parms->N_RB_DL * 12, 1, 1); //should be almost 0
                }
            }
        }
        else
        {
            dlsch_detection_mrc(frame_parms,
                                pdsch_vars[eNB_id]->rxdataF_comp0,
                                pdsch_vars[eNB_id_i]->rxdataF_comp0,
                                pdsch_vars[eNB_id]->rho,
                                pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                pdsch_vars[eNB_id]->dl_ch_mag0,
                                pdsch_vars[eNB_id]->dl_ch_magb0,
                                pdsch_vars[eNB_id_i]->dl_ch_mag0,
                                pdsch_vars[eNB_id_i]->dl_ch_magb0,
                                symbol,
                                nb_rb,
                                rx_type == rx_IC_single_stream);
        }
    }

    //  printf("Combining");
    if((dlsch0_harq->mimo_mode == SISO) ||
            ((dlsch0_harq->mimo_mode >= UNIFORM_PRECODING11) &&
             (dlsch0_harq->mimo_mode <= PUSCH_PRECODING0)) ||
            (dlsch0_harq->mimo_mode == TM7))
    {
        /*
            dlsch_siso(frame_parms,
            pdsch_vars[eNB_id]->rxdataF_comp,
            pdsch_vars[eNB_id_i]->rxdataF_comp,
            symbol,
            nb_rb);
        */
    }
    else if(dlsch0_harq->mimo_mode == ALAMOUTI)
    {
        dlsch_alamouti(frame_parms,
                       pdsch_vars[eNB_id]->rxdataF_comp0,
                       pdsch_vars[eNB_id]->dl_ch_mag0,
                       pdsch_vars[eNB_id]->dl_ch_magb0,
                       symbol,
                       nb_rb);
    }

    //    printf("LLR");
    if((dlsch0_harq->mimo_mode == LARGE_CDD) ||
            ((dlsch0_harq->mimo_mode >= DUALSTREAM_UNIFORM_PRECODING1) &&
             (dlsch0_harq->mimo_mode <= DUALSTREAM_PUSCH_PRECODING)))
    {
        rxdataF_comp_ptr = pdsch_vars[eNB_id]->rxdataF_comp1[harq_pid][round];
        dl_ch_mag_ptr = pdsch_vars[eNB_id]->dl_ch_mag1[harq_pid][round];
    }
    else
    {
        rxdataF_comp_ptr = pdsch_vars[eNB_id_i]->rxdataF_comp0;
        dl_ch_mag_ptr = pdsch_vars[eNB_id_i]->dl_ch_mag0;
        //i_mod should have been passed as a parameter
    }

#if UE_TIMING_TRACE
    stop_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
    LOG_I(PHY, "[AbsSFN %d.%d] Slot%d Symbol %d: Channel Combine  %5.2f \n", frame, subframe, slot, symbol, ue->generic_stat_bis[ue->current_thread_id[subframe]][slot].p_time / (cpuf * 1000.0));
    start_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
#endif
    //printf("LLR dlsch0_harq->Qm %d rx_type %d cw0 %d cw1 %d symbol %d \n",dlsch0_harq->Qm,rx_type,codeword_TB0,codeword_TB1,symbol);
    // compute LLRs
    // -> // compute @pointer where llrs should filled for this ofdm-symbol
    int8_t  *pllr_symbol_cw0;
    int8_t  *pllr_symbol_cw1;
    uint32_t llr_offset_symbol;
    llr_offset_symbol = pdsch_vars[eNB_id]->llr_offset[symbol];
    pllr_symbol_cw0  = (int8_t *)pdsch_vars[eNB_id]->llr[0];
    pllr_symbol_cw1  = (int8_t *)pdsch_vars[eNB_id]->llr[1];
    pllr_symbol_cw0 += llr_offset_symbol;
    pllr_symbol_cw1 += llr_offset_symbol;

    /*
        LOG_I(PHY,"compute LLRs [AbsSubframe %d.%d-%d] NbRB %d Qm %d LLRs-Length %d LLR-Offset %d @LLR Buff %p @LLR Buff(symb) %p\n",
               frame, subframe,symbol,
               nb_rb,dlsch0_harq->Qm,
               pdsch_vars[eNB_id]->llr_length[symbol],
               pdsch_vars[eNB_id]->llr_offset[symbol],
               (int16_t*)pdsch_vars[eNB_id]->llr[0],
               pllr_symbol_cw0);
    */
    switch(dlsch0_harq->Qm)
    {
        case 2 :
            if((rx_type == rx_standard) || (codeword_TB1 == -1))
            {
                dlsch_qpsk_llr(frame_parms,
                               pdsch_vars[eNB_id]->rxdataF_comp0,
                               (int16_t *)pllr_symbol_cw0,
                               symbol,
                               first_symbol_flag,
                               nb_rb,
                               adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 2, subframe, symbol),
                               beamforming_mode);
            }
            else if(codeword_TB0 == -1)
            {
                dlsch_qpsk_llr(frame_parms,
                               pdsch_vars[eNB_id]->rxdataF_comp0,
                               (int16_t *)pllr_symbol_cw1,
                               symbol,
                               first_symbol_flag,
                               nb_rb,
                               adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 2, subframe, symbol),
                               beamforming_mode);
            }
            else if(rx_type >= rx_IC_single_stream)
            {
                if(dlsch1_harq->Qm == 2)
                {
                    dlsch_qpsk_qpsk_llr(frame_parms,
                                        pdsch_vars[eNB_id]->rxdataF_comp0,
                                        rxdataF_comp_ptr,
                                        pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                        pdsch_vars[eNB_id]->llr[0],
                                        symbol, first_symbol_flag, nb_rb,
                                        adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 2, subframe, symbol),
                                        pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_qpsk_qpsk_llr(frame_parms,
                                            rxdataF_comp_ptr,
                                            pdsch_vars[eNB_id]->rxdataF_comp0,
                                            pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                            pdsch_vars[eNB_id]->llr[1],
                                            symbol, first_symbol_flag, nb_rb,
                                            adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 2, subframe, symbol),
                                            pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
                else if(dlsch1_harq->Qm == 4)
                {
                    dlsch_qpsk_16qam_llr(frame_parms,
                                         pdsch_vars[eNB_id]->rxdataF_comp0,
                                         rxdataF_comp_ptr,//i
                                         dl_ch_mag_ptr,//i
                                         pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                         pdsch_vars[eNB_id]->llr[0],
                                         symbol, first_symbol_flag, nb_rb,
                                         adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 2, subframe, symbol),
                                         pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_16qam_qpsk_llr(frame_parms,
                                             rxdataF_comp_ptr,
                                             pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                             dl_ch_mag_ptr,
                                             pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                             pdsch_vars[eNB_id]->llr[1],
                                             symbol, first_symbol_flag, nb_rb,
                                             adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 4, subframe, symbol),
                                             pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
                else
                {
                    dlsch_qpsk_64qam_llr(frame_parms,
                                         pdsch_vars[eNB_id]->rxdataF_comp0,
                                         rxdataF_comp_ptr,//i
                                         dl_ch_mag_ptr,//i
                                         pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                         pdsch_vars[eNB_id]->llr[0],
                                         symbol, first_symbol_flag, nb_rb,
                                         adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 2, subframe, symbol),
                                         pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_64qam_qpsk_llr(frame_parms,
                                             rxdataF_comp_ptr,
                                             pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                             dl_ch_mag_ptr,
                                             pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                             pdsch_vars[eNB_id]->llr[1],
                                             symbol, first_symbol_flag, nb_rb,
                                             adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 6, subframe, symbol),
                                             pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
            }

            break;

        case 4 :
            if((rx_type == rx_standard) || (codeword_TB1 == -1))
            {
                dlsch_16qam_llr(frame_parms,
                                pdsch_vars[eNB_id]->rxdataF_comp0,
                                pdsch_vars[eNB_id]->llr[0],
                                pdsch_vars[eNB_id]->dl_ch_mag0,
                                symbol, first_symbol_flag, nb_rb,
                                adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 4, subframe, symbol),
                                pdsch_vars[eNB_id]->llr128,
                                beamforming_mode);
            }
            else if(codeword_TB0 == -1)
            {
                dlsch_16qam_llr(frame_parms,
                                pdsch_vars[eNB_id]->rxdataF_comp0,
                                pdsch_vars[eNB_id]->llr[1],
                                pdsch_vars[eNB_id]->dl_ch_mag0,
                                symbol, first_symbol_flag, nb_rb,
                                adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 4, subframe, symbol),
                                pdsch_vars[eNB_id]->llr128_2ndstream,
                                beamforming_mode);
            }
            else if(rx_type >= rx_IC_single_stream)
            {
                if(dlsch1_harq->Qm == 2)
                {
                    dlsch_16qam_qpsk_llr(frame_parms,
                                         pdsch_vars[eNB_id]->rxdataF_comp0,
                                         rxdataF_comp_ptr,//i
                                         pdsch_vars[eNB_id]->dl_ch_mag0,
                                         pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                         pdsch_vars[eNB_id]->llr[0],
                                         symbol, first_symbol_flag, nb_rb,
                                         adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 4, subframe, symbol),
                                         pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_qpsk_16qam_llr(frame_parms,
                                             rxdataF_comp_ptr,
                                             pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                             pdsch_vars[eNB_id]->dl_ch_mag0,//i
                                             pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                             pdsch_vars[eNB_id]->llr[1],
                                             symbol, first_symbol_flag, nb_rb,
                                             adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 2, subframe, symbol),
                                             pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
                else if(dlsch1_harq->Qm == 4)
                {
                    dlsch_16qam_16qam_llr(frame_parms,
                                          pdsch_vars[eNB_id]->rxdataF_comp0,
                                          rxdataF_comp_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_mag0,
                                          dl_ch_mag_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                          pdsch_vars[eNB_id]->llr[0],
                                          symbol, first_symbol_flag, nb_rb,
                                          adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 4, subframe, symbol),
                                          pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_16qam_16qam_llr(frame_parms,
                                              rxdataF_comp_ptr,
                                              pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                              dl_ch_mag_ptr,
                                              pdsch_vars[eNB_id]->dl_ch_mag0,//i
                                              pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                              pdsch_vars[eNB_id]->llr[1],
                                              symbol, first_symbol_flag, nb_rb,
                                              adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 4, subframe, symbol),
                                              pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
                else
                {
                    dlsch_16qam_64qam_llr(frame_parms,
                                          pdsch_vars[eNB_id]->rxdataF_comp0,
                                          rxdataF_comp_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_mag0,
                                          dl_ch_mag_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                          pdsch_vars[eNB_id]->llr[0],
                                          symbol, first_symbol_flag, nb_rb,
                                          adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 4, subframe, symbol),
                                          pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_64qam_16qam_llr(frame_parms,
                                              rxdataF_comp_ptr,
                                              pdsch_vars[eNB_id]->rxdataF_comp0,
                                              dl_ch_mag_ptr,
                                              pdsch_vars[eNB_id]->dl_ch_mag0,
                                              pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                              pdsch_vars[eNB_id]->llr[1],
                                              symbol, first_symbol_flag, nb_rb,
                                              adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 6, subframe, symbol),
                                              pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
            }

            break;

        case 6 :
            if((rx_type == rx_standard) || (codeword_TB1 == -1))
            {
                dlsch_64qam_llr(frame_parms,
                                pdsch_vars[eNB_id]->rxdataF_comp0,
                                (int16_t *)pllr_symbol_cw0,
                                pdsch_vars[eNB_id]->dl_ch_mag0,
                                pdsch_vars[eNB_id]->dl_ch_magb0,
                                symbol, first_symbol_flag, nb_rb,
                                adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 6, subframe, symbol),
                                pdsch_vars[eNB_id]->llr_offset[symbol],
                                beamforming_mode);
            }
            else if(codeword_TB0 == -1)
            {
                dlsch_64qam_llr(frame_parms,
                                pdsch_vars[eNB_id]->rxdataF_comp0,
                                (int16_t *)pllr_symbol_cw1,
                                pdsch_vars[eNB_id]->dl_ch_mag0,
                                pdsch_vars[eNB_id]->dl_ch_magb0,
                                symbol, first_symbol_flag, nb_rb,
                                adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 6, subframe, symbol),
                                pdsch_vars[eNB_id]->llr_offset[symbol],
                                beamforming_mode);
            }
            else if(rx_type >= rx_IC_single_stream)
            {
                if(dlsch1_harq->Qm == 2)
                {
                    dlsch_64qam_qpsk_llr(frame_parms,
                                         pdsch_vars[eNB_id]->rxdataF_comp0,
                                         rxdataF_comp_ptr,//i
                                         pdsch_vars[eNB_id]->dl_ch_mag0,
                                         pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                         pdsch_vars[eNB_id]->llr[0],
                                         symbol, first_symbol_flag, nb_rb,
                                         adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 6, subframe, symbol),
                                         pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_qpsk_64qam_llr(frame_parms,
                                             rxdataF_comp_ptr,
                                             pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                             pdsch_vars[eNB_id]->dl_ch_mag0,
                                             pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                             pdsch_vars[eNB_id]->llr[1],
                                             symbol, first_symbol_flag, nb_rb,
                                             adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 2, subframe, symbol),
                                             pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
                else if(dlsch1_harq->Qm == 4)
                {
                    dlsch_64qam_16qam_llr(frame_parms,
                                          pdsch_vars[eNB_id]->rxdataF_comp0,
                                          rxdataF_comp_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_mag0,
                                          dl_ch_mag_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                          pdsch_vars[eNB_id]->llr[0],
                                          symbol, first_symbol_flag, nb_rb,
                                          adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 6, subframe, symbol),
                                          pdsch_vars[eNB_id]->llr128);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_16qam_64qam_llr(frame_parms,
                                              rxdataF_comp_ptr,
                                              pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                              dl_ch_mag_ptr,
                                              pdsch_vars[eNB_id]->dl_ch_mag0,//i
                                              pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                              pdsch_vars[eNB_id]->llr[1],
                                              symbol, first_symbol_flag, nb_rb,
                                              adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 4, subframe, symbol),
                                              pdsch_vars[eNB_id]->llr128_2ndstream);
                    }
                }
                else
                {
                    dlsch_64qam_64qam_llr(frame_parms,
                                          pdsch_vars[eNB_id]->rxdataF_comp0,
                                          rxdataF_comp_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_mag0,
                                          dl_ch_mag_ptr,//i
                                          pdsch_vars[eNB_id]->dl_ch_rho2_ext,
                                          (int16_t *)pllr_symbol_cw0,
                                          symbol, first_symbol_flag, nb_rb,
                                          adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 6, subframe, symbol),
                                          pdsch_vars[eNB_id]->llr_offset[symbol]);

                    if(rx_type == rx_IC_dual_stream)
                    {
                        dlsch_64qam_64qam_llr(frame_parms,
                                              rxdataF_comp_ptr,
                                              pdsch_vars[eNB_id]->rxdataF_comp0,//i
                                              dl_ch_mag_ptr,
                                              pdsch_vars[eNB_id]->dl_ch_mag0,//i
                                              pdsch_vars[eNB_id]->dl_ch_rho_ext[harq_pid][round],
                                              (int16_t *)pllr_symbol_cw1,
                                              symbol, first_symbol_flag, nb_rb,
                                              adjust_G2(frame_parms, dlsch1_harq->rb_alloc_even, 6, subframe, symbol),
                                              pdsch_vars[eNB_id]->llr_offset[symbol]);
                    }
                }
            }

            break;

        default:
            LOG_W(PHY, "rx_dlsch.c : Unknown mod_order!!!!\n");
            return(-1);
            break;
    }

    if(dlsch1_harq)
    {
        switch(get_Qm(dlsch1_harq->mcs))
        {
            case 2 :
                if(rx_type == rx_standard)
                {
                    dlsch_qpsk_llr(frame_parms,
                                   pdsch_vars[eNB_id]->rxdataF_comp0,
                                   (int16_t *)pllr_symbol_cw0,
                                   symbol, first_symbol_flag, nb_rb,
                                   adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 2, subframe, symbol),
                                   beamforming_mode);
                }

                break;

            case 4:
                if(rx_type == rx_standard)
                {
                    dlsch_16qam_llr(frame_parms,
                                    pdsch_vars[eNB_id]->rxdataF_comp0,
                                    pdsch_vars[eNB_id]->llr[0],
                                    pdsch_vars[eNB_id]->dl_ch_mag0,
                                    symbol, first_symbol_flag, nb_rb,
                                    adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 4, subframe, symbol),
                                    pdsch_vars[eNB_id]->llr128,
                                    beamforming_mode);
                }

                break;

            case 6 :
                if(rx_type == rx_standard)
                {
                    dlsch_64qam_llr(frame_parms,
                                    pdsch_vars[eNB_id]->rxdataF_comp0,
                                    (int16_t *)pllr_symbol_cw0,
                                    pdsch_vars[eNB_id]->dl_ch_mag0,
                                    pdsch_vars[eNB_id]->dl_ch_magb0,
                                    symbol, first_symbol_flag, nb_rb,
                                    adjust_G2(frame_parms, dlsch0_harq->rb_alloc_even, 6, subframe, symbol),
                                    pdsch_vars[eNB_id]->llr_offset[symbol],
                                    beamforming_mode);
                }

                break;

            default:
                LOG_W(PHY, "rx_dlsch.c : Unknown mod_order!!!!\n");
                return(-1);
                break;
        }
    }

#if UE_TIMING_TRACE
    stop_meas(&ue->generic_stat_bis[ue->current_thread_id[subframe]][slot]);
    LOG_D(PHY, "[AbsSFN %d.%d] Slot%d Symbol %d: LLR Computation  %5.2f \n", frame, subframe, slot, symbol, ue->generic_stat_bis[ue->current_thread_id[subframe]][slot].p_time / (cpuf * 1000.0));
#endif
    // Please keep it: useful for debugging
    T(T_UE_PHY_PDSCH_IQ, T_INT(eNB_id), T_INT(frame % 1024),
      T_INT(subframe), T_INT(nb_rb),
      T_INT(frame_parms->N_RB_UL), T_INT(frame_parms->symbols_per_tti),
      T_BUFFER(&pdsch_vars[eNB_id]->rxdataF_comp0[eNB_id][0],
               2 * /* ulsch[UE_id]->harq_processes[harq_pid]->nb_rb */ frame_parms->N_RB_UL * 12 * frame_parms->symbols_per_tti * 2));
    return 0;
}

//==============================================================================================
// Pre-processing for LLR computation
//==============================================================================================

void dlsch_channel_compensation(int **rxdataF_ext,
                                int **dl_ch_estimates_ext,
                                int **dl_ch_mag,
                                int **dl_ch_magb,
                                int **rxdataF_comp,
                                int **rho,
                                LTE_DL_FRAME_PARMS *frame_parms,
                                unsigned char symbol,
                                uint8_t first_symbol_flag,
                                unsigned char mod_order,
                                unsigned short nb_rb,
                                unsigned char output_shift,
                                PHY_MEASUREMENTS *measurements)
{
#if defined(__i386) || defined(__x86_64)
    unsigned short rb;
    unsigned char aatx, aarx, symbol_mod, pilots = 0;
    __m128i *dl_ch128, *dl_ch128_2, *dl_ch_mag128, *dl_ch_mag128b, *rxdataF128, *rxdataF_comp128, *rho128;
    __m128i mmtmpD0, mmtmpD1, mmtmpD2, mmtmpD3, QAM_amp128;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        if(frame_parms->nb_antenna_ports_eNB == 1) // 10 out of 12 so don't reduce size
        {
            nb_rb = 1 + (5 * nb_rb / 6);
        }
        else
        {
            pilots = 1;
        }
    }

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
    {
        __m128i QAM_amp128b = _mm_setzero_si128();

        if(mod_order == 4)
        {
            QAM_amp128 = _mm_set1_epi16(QAM16_n1);  // 2/sqrt(10)
        }
        else if(mod_order == 6)
        {
            QAM_amp128  = _mm_set1_epi16(QAM64_n1); //
            QAM_amp128b = _mm_set1_epi16(QAM64_n2);
        }

        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            /*  TODO: hack to be removed. There is crash for 1 antenna case, so
                for 1 antenna case, I put back the value 2 as it was before
                Elena's commit.
            */
            int x = frame_parms->nb_antennas_rx > 1 ? frame_parms->nb_antennas_rx : 2;
            dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aatx * x + aarx][symbol * frame_parms->N_RB_DL * 12];
            //print_shorts("dl_ch128[0]=",&dl_ch128[0]);*/
            dl_ch_mag128      = (__m128i *)&dl_ch_mag[aatx * x + aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128b     = (__m128i *)&dl_ch_magb[aatx * x + 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[aatx * x + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                if(mod_order > 2)
                {
                    // get channel amplitude if not QPSK
                    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);
                    //print_ints("Re(ch):",(int16_t*)&mmtmpD0);
                    //print_shorts("QAM_amp:",(int16_t*)&QAM_amp128);
                    //print_shorts("mag:",(int16_t*)&dl_ch_mag128[0]);
                    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);

                    if(pilots == 0)
                    {
                        mmtmpD0 = _mm_madd_epi16(dl_ch128[2], dl_ch128[2]);
                        mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift);
                        mmtmpD1 = _mm_packs_epi32(mmtmpD0, mmtmpD0);
                        dl_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1, mmtmpD1);
                        dl_ch_mag128b[2] = dl_ch_mag128[2];
                        dl_ch_mag128[2] = _mm_mulhi_epi16(dl_ch_mag128[2], QAM_amp128);
                        dl_ch_mag128[2] = _mm_slli_epi16(dl_ch_mag128[2], 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);

                    if(pilots == 0)
                    {
                        dl_ch_mag128b[2] = _mm_mulhi_epi16(dl_ch_mag128b[2], QAM_amp128b);
                        dl_ch_mag128b[2] = _mm_slli_epi16(dl_ch_mag128b[2], 1);
                    }
                }

                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch128[0], rxdataF128[0]);
                // 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));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
                //  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));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                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);
                //  print_shorts("rx:",rxdataF128+1);
                //  print_shorts("ch:",dl_ch128+1);
                //  print_shorts("pack:",rxdataF_comp128+1);

                if(pilots == 0)
                {
                    // multiply by conjugated channel
                    mmtmpD0 = _mm_madd_epi16(dl_ch128[2], rxdataF128[2]);
                    // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
                    mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[2], _MM_SHUFFLE(2, 3, 0, 1));
                    mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
                    mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                    mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[2]);
                    // 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[2] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                    //  print_shorts("rx:",rxdataF128+2);
                    //  print_shorts("ch:",dl_ch128+2);
                    // print_shorts("pack:",rxdataF_comp128+2);
                    dl_ch128 += 3;
                    dl_ch_mag128 += 3;
                    dl_ch_mag128b += 3;
                    rxdataF128 += 3;
                    rxdataF_comp128 += 3;
                }
                else     // we have a smaller PDSCH in symbols with pilots so skip last group of 4 REs and increment less
                {
                    dl_ch128 += 2;
                    dl_ch_mag128 += 2;
                    dl_ch_mag128b += 2;
                    rxdataF128 += 2;
                    rxdataF_comp128 += 2;
                }
            }
        }
    }

    if(rho)
    {
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            rho128        = (__m128i *)&rho[aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch128      = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch128_2    = (__m128i *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch128[0], dl_ch128_2[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));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
                //  print_ints("im",&mmtmpD1);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128_2[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);
                rho128[0] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                //print_shorts("rx:",dl_ch128_2);
                //print_shorts("ch:",dl_ch128);
                //print_shorts("pack:",rho128);
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch128[1], dl_ch128_2[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));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128_2[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);
                rho128[1] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                //print_shorts("rx:",dl_ch128_2+1);
                //print_shorts("ch:",dl_ch128+1);
                //print_shorts("pack:",rho128+1);
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch128[2], dl_ch128_2[2]);
                // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
                mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[2], _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128_2[2]);
                // 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);
                rho128[2] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                //print_shorts("rx:",dl_ch128_2+2);
                //print_shorts("ch:",dl_ch128+2);
                //print_shorts("pack:",rho128+2);
                dl_ch128 += 3;
                dl_ch128_2 += 3;
                rho128 += 3;
            }

            if(first_symbol_flag == 1)
            {
                measurements->rx_correlation[0][aarx] = signal_energy(&rho[aarx][symbol * frame_parms->N_RB_DL * 12], rb * 12);
            }
        }
    }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
    unsigned short rb;
    unsigned char aatx, aarx, symbol_mod, pilots = 0;
    int16x4_t *dl_ch128, *dl_ch128_2, *rxdataF128;
    int32x4_t mmtmpD0, mmtmpD1, mmtmpD0b, mmtmpD1b;
    int16x8_t *dl_ch_mag128, *dl_ch_mag128b, mmtmpD2, mmtmpD3, mmtmpD4;
    int16x8_t QAM_amp128, QAM_amp128b;
    int16x4x2_t *rxdataF_comp128, *rho128;
    int16_t conj[4]__attribute__((aligned(16))) = {1, -1, 1, -1};
    int32x4_t output_shift128 = vmovq_n_s32(-(int32_t)output_shift);
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        if(frame_parms->nb_antenna_ports_eNB == 1)  // 10 out of 12 so don't reduce size
        {
            nb_rb = 1 + (5 * nb_rb / 6);
        }
        else
        {
            pilots = 1;
        }
    }

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
    {
        if(mod_order == 4)
        {
            QAM_amp128  = vmovq_n_s16(QAM16_n1);  // 2/sqrt(10)
            QAM_amp128b = vmovq_n_s16(0);
        }
        else if(mod_order == 6)
        {
            QAM_amp128  = vmovq_n_s16(QAM64_n1); //
            QAM_amp128b = vmovq_n_s16(QAM64_n2);
        }

        //    printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol);

        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            dl_ch128          = (int16x4_t *)&dl_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128      = (int16x8_t *)&dl_ch_mag[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128b     = (int16x8_t *)&dl_ch_magb[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];
            rxdataF128        = (int16x4_t *)&rxdataF_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128   = (int16x4x2_t *)&rxdataF_comp[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                if(mod_order > 2)
                {
                    // get channel amplitude if not QPSK
                    mmtmpD0 = vmull_s16(dl_ch128[0], dl_ch128[0]);
                    // mmtmpD0 = [ch0*ch0,ch1*ch1,ch2*ch2,ch3*ch3];
                    mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                    // mmtmpD0 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3]>>output_shift128 on 32-bits
                    mmtmpD1 = vmull_s16(dl_ch128[1], dl_ch128[1]);
                    mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                    mmtmpD2 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                    // mmtmpD2 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3,ch4*ch4 + ch5*ch5,ch4*ch4 + ch5*ch5,ch6*ch6 + ch7*ch7,ch6*ch6 + ch7*ch7]>>output_shift128 on 16-bits
                    mmtmpD0 = vmull_s16(dl_ch128[2], dl_ch128[2]);
                    mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                    mmtmpD1 = vmull_s16(dl_ch128[3], dl_ch128[3]);
                    mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                    mmtmpD3 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

                    if(pilots == 0)
                    {
                        mmtmpD0 = vmull_s16(dl_ch128[4], dl_ch128[4]);
                        mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                        mmtmpD1 = vmull_s16(dl_ch128[5], dl_ch128[5]);
                        mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                        mmtmpD4 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                    }

                    dl_ch_mag128b[0] = vqdmulhq_s16(mmtmpD2, QAM_amp128b);
                    dl_ch_mag128b[1] = vqdmulhq_s16(mmtmpD3, QAM_amp128b);
                    dl_ch_mag128[0] = vqdmulhq_s16(mmtmpD2, QAM_amp128);
                    dl_ch_mag128[1] = vqdmulhq_s16(mmtmpD3, QAM_amp128);

                    if(pilots == 0)
                    {
                        dl_ch_mag128b[2] = vqdmulhq_s16(mmtmpD4, QAM_amp128b);
                        dl_ch_mag128[2]  = vqdmulhq_s16(mmtmpD4, QAM_amp128);
                    }
                }

                mmtmpD0 = vmull_s16(dl_ch128[0], rxdataF128[0]);
                //mmtmpD0 = [Re(ch[0])Re(rx[0]) Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1]) Im(ch[1])Im(ch[1])]
                mmtmpD1 = vmull_s16(dl_ch128[1], rxdataF128[1]);
                //mmtmpD1 = [Re(ch[2])Re(rx[2]) Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3]) Im(ch[3])Im(ch[3])]
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                //mmtmpD0 = [Re(ch[0])Re(rx[0])+Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1])+Im(ch[1])Im(ch[1]) Re(ch[2])Re(rx[2])+Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3])+Im(ch[3])Im(ch[3])]
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[0], *(int16x4_t *)conj)), rxdataF128[0]);
                //mmtmpD0 = [-Im(ch[0])Re(rx[0]) Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1]) Re(ch[1])Im(rx[1])]
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[1], *(int16x4_t *)conj)), rxdataF128[1]);
                //mmtmpD0 = [-Im(ch[2])Re(rx[2]) Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3]) Re(ch[3])Im(rx[3])]
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                //mmtmpD1 = [-Im(ch[0])Re(rx[0])+Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1])+Re(ch[1])Im(rx[1]) -Im(ch[2])Re(rx[2])+Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3])+Re(ch[3])Im(rx[3])]
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rxdataF_comp128[0] = vzip_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                mmtmpD0 = vmull_s16(dl_ch128[2], rxdataF128[2]);
                mmtmpD1 = vmull_s16(dl_ch128[3], rxdataF128[3]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[2], *(int16x4_t *)conj)), rxdataF128[2]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[3], *(int16x4_t *)conj)), rxdataF128[3]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rxdataF_comp128[1] = vzip_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

                if(pilots == 0)
                {
                    mmtmpD0 = vmull_s16(dl_ch128[4], rxdataF128[4]);
                    mmtmpD1 = vmull_s16(dl_ch128[5], rxdataF128[5]);
                    mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                           vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                    mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[4], *(int16x4_t *)conj)), rxdataF128[4]);
                    mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[5], *(int16x4_t *)conj)), rxdataF128[5]);
                    mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                           vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                    mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                    mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                    rxdataF_comp128[2] = vzip_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                    dl_ch128 += 6;
                    dl_ch_mag128 += 3;
                    dl_ch_mag128b += 3;
                    rxdataF128 += 6;
                    rxdataF_comp128 += 3;
                }
                else     // we have a smaller PDSCH in symbols with pilots so skip last group of 4 REs and increment less
                {
                    dl_ch128 += 4;
                    dl_ch_mag128 += 2;
                    dl_ch_mag128b += 2;
                    rxdataF128 += 4;
                    rxdataF_comp128 += 2;
                }
            }
        }
    }

    if(rho)
    {
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            rho128        = (int16x4x2_t *)&rho[aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch128      = (int16x4_t *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
            dl_ch128_2    = (int16x4_t *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                mmtmpD0 = vmull_s16(dl_ch128[0], dl_ch128_2[0]);
                mmtmpD1 = vmull_s16(dl_ch128[1], dl_ch128_2[1]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[0], *(int16x4_t *)conj)), dl_ch128_2[0]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[1], *(int16x4_t *)conj)), dl_ch128_2[1]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rho128[0] = vzip_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                mmtmpD0 = vmull_s16(dl_ch128[2], dl_ch128_2[2]);
                mmtmpD1 = vmull_s16(dl_ch128[3], dl_ch128_2[3]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[2], *(int16x4_t *)conj)), dl_ch128_2[2]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[3], *(int16x4_t *)conj)), dl_ch128_2[3]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rho128[1] = vzip_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                mmtmpD0 = vmull_s16(dl_ch128[0], dl_ch128_2[0]);
                mmtmpD1 = vmull_s16(dl_ch128[1], dl_ch128_2[1]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[4], *(int16x4_t *)conj)), dl_ch128_2[4]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch128[5], *(int16x4_t *)conj)), dl_ch128_2[5]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rho128[2] = vzip_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                dl_ch128 += 6;
                dl_ch128_2 += 6;
                rho128 += 3;
            }

            if(first_symbol_flag == 1)
            {
                measurements->rx_correlation[0][aarx] = signal_energy(&rho[aarx][symbol * frame_parms->N_RB_DL * 12], rb * 12);
            }
        }
    }

#endif
}

void dlsch_channel_compensation_core(int **rxdataF_ext,
                                     int **dl_ch_estimates_ext,
                                     int **dl_ch_mag,
                                     int **dl_ch_magb,
                                     int **rxdataF_comp,
                                     int **rho,
                                     unsigned char n_tx,
                                     unsigned char n_rx,
                                     unsigned char mod_order,
                                     unsigned char output_shift,
                                     int length,
                                     int start_point)

{
    unsigned short ii;
    int length_mod8 = 0;
    int length2;
    __m128i *dl_ch128, *dl_ch_mag128, *dl_ch_mag128b, *dl_ch128_2, *rxdataF128, *rxdataF_comp128, *rho128;
    __m128i mmtmpD0, mmtmpD1, mmtmpD2, mmtmpD3, QAM_amp128;
    int aatx = 0, aarx = 0;

    for(aatx = 0; aatx < n_tx; aatx++)
    {
        __m128i QAM_amp128b;

        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);
        }

        for(aarx = 0; aarx < n_rx; aarx++)
        {
            /*  TODO: hack to be removed. There is crash for 1 antenna case, so
                for 1 antenna case, I put back the value 2 as it was before
                Elena's commit.
            */
            int x = n_rx > 1 ? n_rx : 2;
            dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aatx * x + aarx][start_point];
            dl_ch_mag128      = (__m128i *)&dl_ch_mag[aatx * x + aarx][start_point];
            dl_ch_mag128b     = (__m128i *)&dl_ch_magb[aatx * x + aarx][start_point];
            rxdataF128        = (__m128i *)&rxdataF_ext[aarx][start_point];
            rxdataF_comp128   = (__m128i *)&rxdataF_comp[aatx * x + aarx][start_point];
            length_mod8 = length & 7;

            if(length_mod8 == 0)
            {
                length2 = length >> 3;

                for(ii = 0; ii < length2; ++ii)
                {
                    if(mod_order > 2)
                    {
                        // get channel amplitude if not QPSK
                        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);
                        //print_ints("Re(ch):",(int16_t*)&mmtmpD0);
                        //print_shorts("QAM_amp:",(int16_t*)&QAM_amp128);
                        //print_shorts("mag:",(int16_t*)&dl_ch_mag128[0]);
                        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);
                    }

                    // multiply by conjugated channel
                    mmtmpD0 = _mm_madd_epi16(dl_ch128[0], rxdataF128[0]);
                    // 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));
                    mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
                    //  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));
                    mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                    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);
                    //  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;
                }
            }
            else
            {
                printf("Channel Compensation: Received number of subcarriers is not multiple of 8, \n"
                       "need to adapt the code!\n");
            }
        }
    }

    /*This part of code makes sense only for processing in 2x2 blocks*/
    if(rho)
    {
        for(aarx = 0; aarx < n_rx; aarx++)
        {
            rho128        = (__m128i *)&rho[aarx][start_point];
            dl_ch128      = (__m128i *)&dl_ch_estimates_ext[aarx][start_point];
            dl_ch128_2    = (__m128i *)&dl_ch_estimates_ext[2 + aarx][start_point];

            if(length_mod8 == 0)
            {
                length2 = length >> 3;

                for(ii = 0; ii < length2; ++ii)
                {
                    // multiply by conjugated channel
                    mmtmpD0 = _mm_madd_epi16(dl_ch128[0], dl_ch128_2[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));
                    mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
                    //  print_ints("im",&mmtmpD1);
                    mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128_2[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);
                    rho128[0] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                    //print_shorts("rx:",dl_ch128_2);
                    //print_shorts("ch:",dl_ch128);
                    //print_shorts("pack:",rho128);
                    // multiply by conjugated channel
                    mmtmpD0 = _mm_madd_epi16(dl_ch128[1], dl_ch128_2[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));
                    mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                    mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128_2[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);
                    rho128[1] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                    dl_ch128 += 2;
                    dl_ch128_2 += 2;
                    rho128 += 2;
                }
            }
            else
            {
                printf("Channel Compensation: Received number of subcarriers is not multiple of 8, \n"
                       "need to adapt the code!\n");
            }
        }
    }

    _mm_empty();
    _m_empty();
}

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

void prec2A_TM56_128(unsigned char pmi, __m128i *ch0, __m128i *ch1)
{
    __m128i amp;
    amp = _mm_set1_epi16(ONE_OVER_SQRT2_Q15);

    switch(pmi)
    {
        case 0 :   // +1 +1
            //    print_shorts("phase 0 :ch0",ch0);
            //    print_shorts("phase 0 :ch1",ch1);
            ch0[0] = _mm_adds_epi16(ch0[0], ch1[0]);
            break;

        case 1 :   // +1 -1
            //    print_shorts("phase 1 :ch0",ch0);
            //    print_shorts("phase 1 :ch1",ch1);
            ch0[0] = _mm_subs_epi16(ch0[0], ch1[0]);
            //    print_shorts("phase 1 :ch0-ch1",ch0);
            break;

        case 2 :   // +1 +j
            ch1[0] = _mm_sign_epi16(ch1[0], *(__m128i *)&conjugate[0]);
            ch1[0] = _mm_shufflelo_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch1[0] = _mm_shufflehi_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch0[0] = _mm_subs_epi16(ch0[0], ch1[0]);
            break;   // +1 -j

        case 3 :
            ch1[0] = _mm_sign_epi16(ch1[0], *(__m128i *)&conjugate[0]);
            ch1[0] = _mm_shufflelo_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch1[0] = _mm_shufflehi_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch0[0] = _mm_adds_epi16(ch0[0], ch1[0]);
            break;
    }

    ch0[0] = _mm_mulhi_epi16(ch0[0], amp);
    ch0[0] = _mm_slli_epi16(ch0[0], 1);
    _mm_empty();
    _m_empty();
}
#elif defined(__arm__)
void prec2A_TM56_128(unsigned char pmi, __m128i *ch0, __m128i *ch1)
{
    // sqrt(2) is already taken into account in computation sqrt_rho_a, sqrt_rho_b,
    //so removed it

    //__m128i amp;
    //amp = _mm_set1_epi16(ONE_OVER_SQRT2_Q15);
    switch(pmi)
    {
        case 0 :   // +1 +1
            //    print_shorts("phase 0 :ch0",ch0);
            //    print_shorts("phase 0 :ch1",ch1);
            ch0[0] = _mm_adds_epi16(ch0[0], ch1[0]);
            break;

        case 1 :   // +1 -1
            //    print_shorts("phase 1 :ch0",ch0);
            //    print_shorts("phase 1 :ch1",ch1);
            ch0[0] = _mm_subs_epi16(ch0[0], ch1[0]);
            //    print_shorts("phase 1 :ch0-ch1",ch0);
            break;

        case 2 :   // +1 +j
            ch1[0] = _mm_sign_epi16(ch1[0], *(__m128i *)&conjugate[0]);
            ch1[0] = _mm_shufflelo_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch1[0] = _mm_shufflehi_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch0[0] = _mm_subs_epi16(ch0[0], ch1[0]);
            break;   // +1 -j

        case 3 :
            ch1[0] = _mm_sign_epi16(ch1[0], *(__m128i *)&conjugate[0]);
            ch1[0] = _mm_shufflelo_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch1[0] = _mm_shufflehi_epi16(ch1[0], _MM_SHUFFLE(2, 3, 0, 1));
            ch0[0] = _mm_adds_epi16(ch0[0], ch1[0]);
            break;
    }

    //ch0[0] = _mm_mulhi_epi16(ch0[0],amp);
    //ch0[0] = _mm_slli_epi16(ch0[0],1);
    _mm_empty();
    _m_empty();
}
#endif
// precoding is stream 0 .5(1,1)  .5(1,-1) .5(1,1)  .5(1,-1)
//              stream 1 .5(1,-1) .5(1,1)  .5(1,-1) .5(1,1)
// store "precoded" channel for stream 0 in ch0, stream 1 in ch1

short TM3_prec[8]__attribute__((aligned(16))) = {1, 1, -1, -1, 1, 1, -1, -1} ;

void prec2A_TM3_128(__m128i *ch0, __m128i *ch1)
{
    __m128i amp = _mm_set1_epi16(ONE_OVER_SQRT2_Q15);
    __m128i tmp0, tmp1;
    //_mm_mulhi_epi16
    //  print_shorts("prec2A_TM3 ch0 (before):",ch0);
    //  print_shorts("prec2A_TM3 ch1 (before):",ch1);
    tmp0 = ch0[0];
    tmp1  = _mm_sign_epi16(ch1[0], ((__m128i *)&TM3_prec)[0]);
    //  print_shorts("prec2A_TM3 ch1*s (mid):",(__m128i*)TM3_prec);
    ch0[0] = _mm_adds_epi16(ch0[0], tmp1);
    ch1[0] = _mm_subs_epi16(tmp0, tmp1);
    ch0[0] = _mm_mulhi_epi16(ch0[0], amp);
    ch0[0] = _mm_slli_epi16(ch0[0], 1);
    ch1[0] = _mm_mulhi_epi16(ch1[0], amp);
    ch1[0] = _mm_slli_epi16(ch1[0], 1);
    //  print_shorts("prec2A_TM3 ch0 (mid):",&tmp0);
    //  print_shorts("prec2A_TM3 ch1 (mid):",ch1);
    //ch0[0] = _mm_mulhi_epi16(ch0[0],amp);
    //ch0[0] = _mm_slli_epi16(ch0[0],1);
    //ch1[0] = _mm_mulhi_epi16(ch1[0],amp);
    //ch1[0] = _mm_slli_epi16(ch1[0],1);
    //ch0[0] = _mm_srai_epi16(ch0[0],1);
    //ch1[0] = _mm_srai_epi16(ch1[0],1);
    //  print_shorts("prec2A_TM3 ch0 (after):",ch0);
    //  print_shorts("prec2A_TM3 ch1 (after):",ch1);
    _mm_empty();
    _m_empty();
}

// pmi = 0 => stream 0 (1,1), stream 1 (1,-1)
// pmi = 1 => stream 0 (1,j), stream 2 (1,-j)

void prec2A_TM4_128(int pmi, __m128i *ch0, __m128i *ch1)
{
    // sqrt(2) is already taken into account in computation sqrt_rho_a, sqrt_rho_b,
    //so divide by 2 is replaced by divide by sqrt(2).
    // printf ("demod pmi=%d\n", pmi);
    __m128i amp;
    amp = _mm_set1_epi16(ONE_OVER_SQRT2_Q15);
    __m128i tmp0, tmp1;

    // print_shorts("prec2A_TM4 ch0 (before):",ch0);
    // print_shorts("prec2A_TM4 ch1 (before):",ch1);

    if(pmi == 0)    //[1 1;1 -1]
    {
        tmp0 = ch0[0];
        tmp1 = ch1[0];
        ch0[0] = _mm_adds_epi16(tmp0, tmp1);
        ch1[0] = _mm_subs_epi16(tmp0, tmp1);
    }
    else     //ch0+j*ch1 ch0-j*ch1
    {
        tmp0 = ch0[0];
        tmp1   = _mm_sign_epi16(ch1[0], *(__m128i *)&conjugate[0]);
        tmp1   = _mm_shufflelo_epi16(tmp1, _MM_SHUFFLE(2, 3, 0, 1));
        tmp1   = _mm_shufflehi_epi16(tmp1, _MM_SHUFFLE(2, 3, 0, 1));
        ch0[0] = _mm_subs_epi16(tmp0, tmp1);
        ch1[0] = _mm_add_epi16(tmp0, tmp1);
    }

    //print_shorts("prec2A_TM4 ch0 (middle):",ch0);
    //print_shorts("prec2A_TM4 ch1 (middle):",ch1);
    ch0[0] = _mm_mulhi_epi16(ch0[0], amp);
    ch0[0] = _mm_slli_epi16(ch0[0], 1);
    ch1[0] = _mm_mulhi_epi16(ch1[0], amp);
    ch1[0] = _mm_slli_epi16(ch1[0], 1);
    // ch0[0] = _mm_srai_epi16(ch0[0],1); //divide by 2
    // ch1[0] = _mm_srai_epi16(ch1[0],1); //divide by 2
    //print_shorts("prec2A_TM4 ch0 (end):",ch0);
    //print_shorts("prec2A_TM4 ch1 (end):",ch1);
    _mm_empty();
    _m_empty();
    // print_shorts("prec2A_TM4 ch0 (end):",ch0);
    //print_shorts("prec2A_TM4 ch1 (end):",ch1);
}

void dlsch_channel_compensation_TM56(int **rxdataF_ext,
                                     int **dl_ch_estimates_ext,
                                     int **dl_ch_mag,
                                     int **dl_ch_magb,
                                     int **rxdataF_comp,
                                     unsigned char *pmi_ext,
                                     LTE_DL_FRAME_PARMS *frame_parms,
                                     PHY_MEASUREMENTS *measurements,
                                     int eNB_id,
                                     unsigned char symbol,
                                     unsigned char mod_order,
                                     unsigned short nb_rb,
                                     unsigned char output_shift,
                                     unsigned char dl_power_off)
{
#if defined(__x86_64__) || defined(__i386__)
    unsigned short rb, Nre;
    __m128i *dl_ch0_128, *dl_ch1_128, *dl_ch_mag128, *dl_ch_mag128b, *rxdataF128, *rxdataF_comp128;
    unsigned char aarx = 0, symbol_mod, pilots = 0;
    int precoded_signal_strength = 0;
    __m128i mmtmpD0, mmtmpD1, mmtmpD2, mmtmpD3, QAM_amp128;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        pilots = 1;
    }

    //printf("comp prec: symbol %d, pilots %d\n",symbol, pilots);
    __m128i QAM_amp128b = _mm_setzero_si128();

    if(mod_order == 4)
    {
        QAM_amp128 = _mm_set1_epi16(QAM16_n1);
    }
    else if(mod_order == 6)
    {
        QAM_amp128  = _mm_set1_epi16(QAM64_n1);
        QAM_amp128b = _mm_set1_epi16(QAM64_n2);
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128          = (__m128i *)&dl_ch_estimates_ext[2 + 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];

        for(rb = 0; rb < nb_rb; rb++)
        {
            // combine TX channels using precoder from pmi
#ifdef DEBUG_DLSCH_DEMOD
            printf("mode 6 prec: rb %d, pmi->%d\n", rb, pmi_ext[rb]);
#endif
            prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128[0], &dl_ch1_128[0]);
            prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128[1], &dl_ch1_128[1]);

            if(pilots == 0)
            {
                prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128[2], &dl_ch1_128[2]);
            }

            if(mod_order > 2)
            {
                // get channel amplitude if not QPSK
                mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0], dl_ch0_128[0]);
                mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift);
                mmtmpD1 = _mm_madd_epi16(dl_ch0_128[1], dl_ch0_128[1]);
                mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift);
                mmtmpD0 = _mm_packs_epi32(mmtmpD0, mmtmpD1);
                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);
                //print_shorts("dl_ch_mag128[0]=",&dl_ch_mag128[0]);
                //print_shorts("dl_ch_mag128[0]=",&dl_ch_mag128[0]);
                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);

                if(pilots == 0)
                {
                    mmtmpD0 = _mm_madd_epi16(dl_ch0_128[2], dl_ch0_128[2]);
                    mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift);
                    mmtmpD1 = _mm_packs_epi32(mmtmpD0, mmtmpD0);
                    dl_ch_mag128[2] = _mm_unpacklo_epi16(mmtmpD1, mmtmpD1);
                    dl_ch_mag128b[2] = dl_ch_mag128[2];
                    dl_ch_mag128[2] = _mm_mulhi_epi16(dl_ch_mag128[2], QAM_amp128);
                    dl_ch_mag128[2] = _mm_slli_epi16(dl_ch_mag128[2], 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);
                //print_shorts("dl_ch_mag128b[0]=",&dl_ch_mag128b[0]);
                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);

                if(pilots == 0)
                {
                    dl_ch_mag128b[2] = _mm_mulhi_epi16(dl_ch_mag128b[2], QAM_amp128b);
                    dl_ch_mag128b[2] = _mm_slli_epi16(dl_ch_mag128b[2], 1);
                }
            }

            // MF multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0], rxdataF128[0]);
            //        print_ints("re",&mmtmpD0);
            // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
            mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[0], _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
            //        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_ch0_128[1], rxdataF128[1]);
            // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
            mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[1], _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
            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);
            //  print_shorts("rx:",rxdataF128+1);
            //  print_shorts("ch:",dl_ch128+1);
            //  print_shorts("pack:",rxdataF_comp128+1);

            if(pilots == 0)
            {
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch0_128[2], rxdataF128[2]);
                // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
                mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[2], _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[2]);
                // 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[2] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                //  print_shorts("rx:",rxdataF128+2);
                //  print_shorts("ch:",dl_ch128+2);
                //        print_shorts("pack:",rxdataF_comp128+2);
                dl_ch0_128 += 3;
                dl_ch1_128 += 3;
                dl_ch_mag128 += 3;
                dl_ch_mag128b += 3;
                rxdataF128 += 3;
                rxdataF_comp128 += 3;
            }
            else
            {
                dl_ch0_128 += 2;
                dl_ch1_128 += 2;
                dl_ch_mag128 += 2;
                dl_ch_mag128b += 2;
                rxdataF128 += 2;
                rxdataF_comp128 += 2;
            }
        }

        Nre = (pilots == 0) ? 12 : 8;
        precoded_signal_strength += ((signal_energy_nodc(&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * Nre],
                                      (nb_rb * Nre))) - (measurements->n0_power[aarx]));
    } // rx_antennas

    measurements->precoded_cqi_dB[eNB_id][0] = dB_fixed2(precoded_signal_strength, measurements->n0_power_tot);
    //printf("eNB_id %d, symbol %d: precoded CQI %d dB\n",eNB_id,symbol,
    //   measurements->precoded_cqi_dB[eNB_id][0]);
#elif defined(__arm__)
    uint32_t rb, Nre;
    uint32_t aarx, symbol_mod, pilots = 0;
    int16x4_t *dl_ch0_128, *dl_ch1_128, *rxdataF128;
    int16x8_t *dl_ch0_128b, *dl_ch1_128b;
    int32x4_t mmtmpD0, mmtmpD1, mmtmpD0b, mmtmpD1b;
    int16x8_t *dl_ch_mag128, *dl_ch_mag128b, mmtmpD2, mmtmpD3, mmtmpD4, *rxdataF_comp128;
    int16x8_t QAM_amp128, QAM_amp128b;
    int16_t conj[4]__attribute__((aligned(16))) = {1, -1, 1, -1};
    int32x4_t output_shift128 = vmovq_n_s32(-(int32_t)output_shift);
    int32_t precoded_signal_strength = 0;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        if(frame_parms->nb_antenna_ports_eNB == 1)  // 10 out of 12 so don't reduce size
        {
            nb_rb = 1 + (5 * nb_rb / 6);
        }
        else
        {
            pilots = 1;
        }
    }

    if(mod_order == 4)
    {
        QAM_amp128  = vmovq_n_s16(QAM16_n1);  // 2/sqrt(10)
        QAM_amp128b = vmovq_n_s16(0);
    }
    else if(mod_order == 6)
    {
        QAM_amp128  = vmovq_n_s16(QAM64_n1); //
        QAM_amp128b = vmovq_n_s16(QAM64_n2);
    }

    //    printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol);

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128          = (int16x4_t *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128          = (int16x4_t *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch0_128b         = (int16x8_t *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128b         = (int16x8_t *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag128        = (int16x8_t *)&dl_ch_mag[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag128b       = (int16x8_t *)&dl_ch_magb[aarx][symbol * frame_parms->N_RB_DL * 12];
        rxdataF128          = (int16x4_t *)&rxdataF_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        rxdataF_comp128     = (int16x8_t *)&rxdataF_comp[aarx][symbol * frame_parms->N_RB_DL * 12];

        for(rb = 0; rb < nb_rb; rb++)
        {
#ifdef DEBUG_DLSCH_DEMOD
            printf("mode 6 prec: rb %d, pmi->%u\n", rb, pmi_ext[rb]);
#endif
            prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128b[0], &dl_ch1_128b[0]);
            prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128b[1], &dl_ch1_128b[1]);

            if(pilots == 0)
            {
                prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128b[2], &dl_ch1_128b[2]);
            }

            if(mod_order > 2)
            {
                // get channel amplitude if not QPSK
                mmtmpD0 = vmull_s16(dl_ch0_128[0], dl_ch0_128[0]);
                // mmtmpD0 = [ch0*ch0,ch1*ch1,ch2*ch2,ch3*ch3];
                mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                // mmtmpD0 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3]>>output_shift128 on 32-bits
                mmtmpD1 = vmull_s16(dl_ch0_128[1], dl_ch0_128[1]);
                mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                mmtmpD2 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                // mmtmpD2 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3,ch4*ch4 + ch5*ch5,ch4*ch4 + ch5*ch5,ch6*ch6 + ch7*ch7,ch6*ch6 + ch7*ch7]>>output_shift128 on 16-bits
                mmtmpD0 = vmull_s16(dl_ch0_128[2], dl_ch0_128[2]);
                mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                mmtmpD1 = vmull_s16(dl_ch0_128[3], dl_ch0_128[3]);
                mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                mmtmpD3 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

                if(pilots == 0)
                {
                    mmtmpD0 = vmull_s16(dl_ch0_128[4], dl_ch0_128[4]);
                    mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                    mmtmpD1 = vmull_s16(dl_ch0_128[5], dl_ch0_128[5]);
                    mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                    mmtmpD4 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                }

                dl_ch_mag128b[0] = vqdmulhq_s16(mmtmpD2, QAM_amp128b);
                dl_ch_mag128b[1] = vqdmulhq_s16(mmtmpD3, QAM_amp128b);
                dl_ch_mag128[0] = vqdmulhq_s16(mmtmpD2, QAM_amp128);
                dl_ch_mag128[1] = vqdmulhq_s16(mmtmpD3, QAM_amp128);

                if(pilots == 0)
                {
                    dl_ch_mag128b[2] = vqdmulhq_s16(mmtmpD4, QAM_amp128b);
                    dl_ch_mag128[2]  = vqdmulhq_s16(mmtmpD4, QAM_amp128);
                }
            }

            mmtmpD0 = vmull_s16(dl_ch0_128[0], rxdataF128[0]);
            //mmtmpD0 = [Re(ch[0])Re(rx[0]) Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1]) Im(ch[1])Im(ch[1])]
            mmtmpD1 = vmull_s16(dl_ch0_128[1], rxdataF128[1]);
            //mmtmpD1 = [Re(ch[2])Re(rx[2]) Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3]) Im(ch[3])Im(ch[3])]
            mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                   vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
            //mmtmpD0 = [Re(ch[0])Re(rx[0])+Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1])+Im(ch[1])Im(ch[1]) Re(ch[2])Re(rx[2])+Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3])+Im(ch[3])Im(ch[3])]
            mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[0], *(int16x4_t *)conj)), rxdataF128[0]);
            //mmtmpD0 = [-Im(ch[0])Re(rx[0]) Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1]) Re(ch[1])Im(rx[1])]
            mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[1], *(int16x4_t *)conj)), rxdataF128[1]);
            //mmtmpD0 = [-Im(ch[2])Re(rx[2]) Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3]) Re(ch[3])Im(rx[3])]
            mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                   vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
            //mmtmpD1 = [-Im(ch[0])Re(rx[0])+Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1])+Re(ch[1])Im(rx[1]) -Im(ch[2])Re(rx[2])+Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3])+Re(ch[3])Im(rx[3])]
            mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
            mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
            rxdataF_comp128[0] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
            mmtmpD0 = vmull_s16(dl_ch0_128[2], rxdataF128[2]);
            mmtmpD1 = vmull_s16(dl_ch0_128[3], rxdataF128[3]);
            mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                   vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
            mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[2], *(int16x4_t *)conj)), rxdataF128[2]);
            mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[3], *(int16x4_t *)conj)), rxdataF128[3]);
            mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                   vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
            mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
            mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
            rxdataF_comp128[1] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

            if(pilots == 0)
            {
                mmtmpD0 = vmull_s16(dl_ch0_128[4], rxdataF128[4]);
                mmtmpD1 = vmull_s16(dl_ch0_128[5], rxdataF128[5]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[4], *(int16x4_t *)conj)), rxdataF128[4]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[5], *(int16x4_t *)conj)), rxdataF128[5]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rxdataF_comp128[2] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                dl_ch0_128 += 6;
                dl_ch1_128 += 6;
                dl_ch_mag128 += 3;
                dl_ch_mag128b += 3;
                rxdataF128 += 6;
                rxdataF_comp128 += 3;
            }
            else     // we have a smaller PDSCH in symbols with pilots so skip last group of 4 REs and increment less
            {
                dl_ch0_128 += 4;
                dl_ch1_128 += 4;
                dl_ch_mag128 += 2;
                dl_ch_mag128b += 2;
                rxdataF128 += 4;
                rxdataF_comp128 += 2;
            }
        }

        Nre = (pilots == 0) ? 12 : 8;
        precoded_signal_strength += ((signal_energy_nodc(&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * Nre],
                                      (nb_rb * Nre))) - (measurements->n0_power[aarx]));
        // rx_antennas
    }

    measurements->precoded_cqi_dB[eNB_id][0] = dB_fixed2(precoded_signal_strength, measurements->n0_power_tot);
    //printf("eNB_id %d, symbol %d: precoded CQI %d dB\n",eNB_id,symbol,
    //     measurements->precoded_cqi_dB[eNB_id][0]);
#endif
    _mm_empty();
    _m_empty();
}

void precode_channel_est(int32_t **dl_ch_estimates_ext,
                         LTE_DL_FRAME_PARMS *frame_parms,
                         LTE_UE_PDSCH *pdsch_vars,
                         unsigned char symbol,
                         unsigned short nb_rb,
                         MIMO_mode_t mimo_mode)
{
    unsigned short rb;
    __m128i *dl_ch0_128, *dl_ch1_128;
    unsigned char aarx = 0, symbol_mod, pilots = 0;
    unsigned char *pmi_ext = pdsch_vars->pmi_ext;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        pilots = 1;
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12]; // this is h11
        dl_ch1_128          = (__m128i *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12]; // this is h12

        for(rb = 0; rb < nb_rb; rb++)
        {
            if(mimo_mode == LARGE_CDD)
            {
                prec2A_TM3_128(&dl_ch0_128[0], &dl_ch1_128[0]);
                prec2A_TM3_128(&dl_ch0_128[1], &dl_ch1_128[1]);

                if(pilots == 0)
                {
                    prec2A_TM3_128(&dl_ch0_128[2], &dl_ch1_128[2]);
                }
            }
            else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODING1)
            {
                prec2A_TM4_128(0, &dl_ch0_128[0], &dl_ch1_128[0]);
                prec2A_TM4_128(0, &dl_ch0_128[1], &dl_ch1_128[1]);

                if(pilots == 0)
                {
                    prec2A_TM4_128(0, &dl_ch0_128[2], &dl_ch1_128[2]);
                }
            }
            else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODINGj)
            {
                prec2A_TM4_128(1, &dl_ch0_128[0], &dl_ch1_128[0]);
                prec2A_TM4_128(1, &dl_ch0_128[1], &dl_ch1_128[1]);

                if(pilots == 0)
                {
                    prec2A_TM4_128(1, &dl_ch0_128[2], &dl_ch1_128[2]);
                }
            }
            else if(mimo_mode == DUALSTREAM_PUSCH_PRECODING)
            {
                prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128[0], &dl_ch1_128[0]);
                prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128[1], &dl_ch1_128[1]);

                if(pilots == 0)
                {
                    prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128[2], &dl_ch1_128[2]);
                }
            }
            else
            {
                LOG_E(PHY, "Unknown MIMO mode\n");
                return;
            }

            if(pilots == 0)
            {
                dl_ch0_128 += 3;
                dl_ch1_128 += 3;
            }
            else
            {
                dl_ch0_128 += 2;
                dl_ch1_128 += 2;
            }
        }
    }
}

void dlsch_channel_compensation_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                                     LTE_UE_PDSCH *pdsch_vars,
                                     PHY_MEASUREMENTS *measurements,
                                     int eNB_id,
                                     unsigned char symbol,
                                     unsigned char mod_order0,
                                     unsigned char mod_order1,
                                     int harq_pid,
                                     int round,
                                     MIMO_mode_t mimo_mode,
                                     unsigned short nb_rb,
                                     unsigned short mmse_flag,
                                     unsigned char output_shift0,
                                     unsigned char output_shift1)
{
#if defined(__x86_64__) || defined(__i386__)
    unsigned short rb, Nre;
    __m128i *dl_ch0_128, *dl_ch1_128, *dl_ch_mag0_128, *dl_ch_mag1_128, *dl_ch_mag0_128b, *dl_ch_mag1_128b, *rxdataF128, *rxdataF_comp0_128, *rxdataF_comp1_128;
    unsigned char aarx = 0, symbol_mod, pilots = 0;
    int precoded_signal_strength0 = 0, precoded_signal_strength1 = 0;
    int rx_power_correction;
    int **rxdataF_ext           = pdsch_vars->rxdataF_ext;
    int **dl_ch_estimates_ext   = pdsch_vars->dl_ch_estimates_ext;
    int **dl_ch_mag0            = pdsch_vars->dl_ch_mag0;
    int **dl_ch_mag1            = pdsch_vars->dl_ch_mag1[harq_pid][round];
    int **dl_ch_magb0           = pdsch_vars->dl_ch_magb0;
    int **dl_ch_magb1           = pdsch_vars->dl_ch_magb1[harq_pid][round];
    int **rxdataF_comp0         = pdsch_vars->rxdataF_comp0;
    int **rxdataF_comp1         = pdsch_vars->rxdataF_comp1[harq_pid][round];
    unsigned char *pmi_ext      = pdsch_vars->pmi_ext;
    __m128i mmtmpD0, mmtmpD1, mmtmpD2, mmtmpD3, QAM_amp0_128, QAM_amp1_128;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        pilots = 1;
    }

    rx_power_correction = 1;
    // printf("comp prec: symbol %d, pilots %d\n",symbol, pilots);
    __m128i  QAM_amp0_128b = _mm_setzero_si128();

    if(mod_order0 == 4)
    {
        QAM_amp0_128  = _mm_set1_epi16(QAM16_n1);
    }
    else if(mod_order0 == 6)
    {
        QAM_amp0_128  = _mm_set1_epi16(QAM64_n1);
        QAM_amp0_128b = _mm_set1_epi16(QAM64_n2);
    }

    __m128i  QAM_amp1_128b = _mm_setzero_si128();

    if(mod_order1 == 4)
    {
        QAM_amp1_128  = _mm_set1_epi16(QAM16_n1);
    }
    else if(mod_order1 == 6)
    {
        QAM_amp1_128  = _mm_set1_epi16(QAM64_n1);
        QAM_amp1_128b = _mm_set1_epi16(QAM64_n2);
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12]; // this is h11
        dl_ch1_128          = (__m128i *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12]; // this is h12
        dl_ch_mag0_128      = (__m128i *)&dl_ch_mag0[aarx][symbol * frame_parms->N_RB_DL * 12]; //responsible for x1
        dl_ch_mag0_128b     = (__m128i *)&dl_ch_magb0[aarx][symbol * frame_parms->N_RB_DL * 12]; //responsible for x1
        dl_ch_mag1_128      = (__m128i *)&dl_ch_mag1[aarx][symbol * frame_parms->N_RB_DL * 12]; //responsible for x2. always coming from tx2
        dl_ch_mag1_128b     = (__m128i *)&dl_ch_magb1[aarx][symbol * frame_parms->N_RB_DL * 12]; //responsible for x2. always coming from tx2
        rxdataF128          = (__m128i *)&rxdataF_ext[aarx][symbol * frame_parms->N_RB_DL * 12]; //received signal on antenna of interest h11*x1+h12*x2
        rxdataF_comp0_128   = (__m128i *)&rxdataF_comp0[aarx][symbol * frame_parms->N_RB_DL * 12]; //result of multipl with MF x1 on antenna of interest
        rxdataF_comp1_128   = (__m128i *)&rxdataF_comp1[aarx][symbol * frame_parms->N_RB_DL * 12]; //result of multipl with MF x2 on antenna of interest

        for(rb = 0; rb < nb_rb; rb++)
        {
            if(mmse_flag == 0)
            {
                // combine TX channels using precoder from pmi
                if(mimo_mode == LARGE_CDD)
                {
                    prec2A_TM3_128(&dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM3_128(&dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM3_128(&dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODING1)
                {
                    prec2A_TM4_128(0, &dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM4_128(0, &dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM4_128(0, &dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODINGj)
                {
                    prec2A_TM4_128(1, &dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM4_128(1, &dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM4_128(1, &dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else if(mimo_mode == DUALSTREAM_PUSCH_PRECODING)
                {
                    prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else
                {
                    LOG_E(PHY, "Unknown MIMO mode\n");
                    return;
                }
            }

            if(mod_order0 > 2)
            {
                // get channel amplitude if not QPSK
                mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0], dl_ch0_128[0]);
                mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift0);
                mmtmpD1 = _mm_madd_epi16(dl_ch0_128[1], dl_ch0_128[1]);
                mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift0);
                mmtmpD0 = _mm_packs_epi32(mmtmpD0, mmtmpD1);
                dl_ch_mag0_128[0] = _mm_unpacklo_epi16(mmtmpD0, mmtmpD0);
                dl_ch_mag0_128b[0] = dl_ch_mag0_128[0];
                dl_ch_mag0_128[0] = _mm_mulhi_epi16(dl_ch_mag0_128[0], QAM_amp0_128);
                dl_ch_mag0_128[0] = _mm_slli_epi16(dl_ch_mag0_128[0], 1);
                //  print_shorts("dl_ch_mag0_128[0]=",&dl_ch_mag0_128[0]);
                dl_ch_mag0_128[1] = _mm_unpackhi_epi16(mmtmpD0, mmtmpD0);
                dl_ch_mag0_128b[1] = dl_ch_mag0_128[1];
                dl_ch_mag0_128[1] = _mm_mulhi_epi16(dl_ch_mag0_128[1], QAM_amp0_128);
                dl_ch_mag0_128[1] = _mm_slli_epi16(dl_ch_mag0_128[1], 1);

                if(pilots == 0)
                {
                    mmtmpD0 = _mm_madd_epi16(dl_ch0_128[2], dl_ch0_128[2]);
                    mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift0);
                    mmtmpD1 = _mm_packs_epi32(mmtmpD0, mmtmpD0);
                    dl_ch_mag0_128[2] = _mm_unpacklo_epi16(mmtmpD1, mmtmpD1);
                    dl_ch_mag0_128b[2] = dl_ch_mag0_128[2];
                    dl_ch_mag0_128[2] = _mm_mulhi_epi16(dl_ch_mag0_128[2], QAM_amp0_128);
                    dl_ch_mag0_128[2] = _mm_slli_epi16(dl_ch_mag0_128[2], 1);
                }

                dl_ch_mag0_128b[0] = _mm_mulhi_epi16(dl_ch_mag0_128b[0], QAM_amp0_128b);
                dl_ch_mag0_128b[0] = _mm_slli_epi16(dl_ch_mag0_128b[0], 1);
                // print_shorts("dl_ch_mag0_128b[0]=",&dl_ch_mag0_128b[0]);
                dl_ch_mag0_128b[1] = _mm_mulhi_epi16(dl_ch_mag0_128b[1], QAM_amp0_128b);
                dl_ch_mag0_128b[1] = _mm_slli_epi16(dl_ch_mag0_128b[1], 1);

                if(pilots == 0)
                {
                    dl_ch_mag0_128b[2] = _mm_mulhi_epi16(dl_ch_mag0_128b[2], QAM_amp0_128b);
                    dl_ch_mag0_128b[2] = _mm_slli_epi16(dl_ch_mag0_128b[2], 1);
                }
            }

            if(mod_order1 > 2)
            {
                // get channel amplitude if not QPSK
                mmtmpD0 = _mm_madd_epi16(dl_ch1_128[0], dl_ch1_128[0]);
                mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift1);
                mmtmpD1 = _mm_madd_epi16(dl_ch1_128[1], dl_ch1_128[1]);
                mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift1);
                mmtmpD0 = _mm_packs_epi32(mmtmpD0, mmtmpD1);
                dl_ch_mag1_128[0] = _mm_unpacklo_epi16(mmtmpD0, mmtmpD0);
                dl_ch_mag1_128b[0] = dl_ch_mag1_128[0];
                dl_ch_mag1_128[0] = _mm_mulhi_epi16(dl_ch_mag1_128[0], QAM_amp1_128);
                dl_ch_mag1_128[0] = _mm_slli_epi16(dl_ch_mag1_128[0], 1);
                // print_shorts("dl_ch_mag1_128[0]=",&dl_ch_mag1_128[0]);
                dl_ch_mag1_128[1] = _mm_unpackhi_epi16(mmtmpD0, mmtmpD0);
                dl_ch_mag1_128b[1] = dl_ch_mag1_128[1];
                dl_ch_mag1_128[1] = _mm_mulhi_epi16(dl_ch_mag1_128[1], QAM_amp1_128);
                dl_ch_mag1_128[1] = _mm_slli_epi16(dl_ch_mag1_128[1], 1);

                if(pilots == 0)
                {
                    mmtmpD0 = _mm_madd_epi16(dl_ch1_128[2], dl_ch1_128[2]);
                    mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift1);
                    mmtmpD1 = _mm_packs_epi32(mmtmpD0, mmtmpD0);
                    dl_ch_mag1_128[2] = _mm_unpacklo_epi16(mmtmpD1, mmtmpD1);
                    dl_ch_mag1_128b[2] = dl_ch_mag1_128[2];
                    dl_ch_mag1_128[2] = _mm_mulhi_epi16(dl_ch_mag1_128[2], QAM_amp1_128);
                    dl_ch_mag1_128[2] = _mm_slli_epi16(dl_ch_mag1_128[2], 1);
                }

                dl_ch_mag1_128b[0] = _mm_mulhi_epi16(dl_ch_mag1_128b[0], QAM_amp1_128b);
                dl_ch_mag1_128b[0] = _mm_slli_epi16(dl_ch_mag1_128b[0], 1);
                // print_shorts("dl_ch_mag1_128b[0]=",&dl_ch_mag1_128b[0]);
                dl_ch_mag1_128b[1] = _mm_mulhi_epi16(dl_ch_mag1_128b[1], QAM_amp1_128b);
                dl_ch_mag1_128b[1] = _mm_slli_epi16(dl_ch_mag1_128b[1], 1);

                if(pilots == 0)
                {
                    dl_ch_mag1_128b[2] = _mm_mulhi_epi16(dl_ch_mag1_128b[2], QAM_amp1_128b);
                    dl_ch_mag1_128b[2] = _mm_slli_epi16(dl_ch_mag1_128b[2], 1);
                }
            }

            // layer 0
            // MF multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch0_128[0], rxdataF128[0]);
            //  print_ints("re",&mmtmpD0);
            // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
            mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[0], _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
            mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[0]);
            // print_ints("im",&mmtmpD1);
            // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
            mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift0);
            // printf("Shift: %d\n",output_shift);
            // print_ints("re(shift)",&mmtmpD0);
            mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift0);
            // 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_comp0_128[0] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
            // print_shorts("rx:",rxdataF128);
            // print_shorts("ch:",dl_ch0_128);
            //print_shorts("pack:",rxdataF_comp0_128);
            // multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch0_128[1], rxdataF128[1]);
            // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
            mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[1], _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
            mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[1]);
            // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
            mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift0);
            mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift0);
            mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0, mmtmpD1);
            mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0, mmtmpD1);
            rxdataF_comp0_128[1] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
            //  print_shorts("rx:",rxdataF128+1);
            //  print_shorts("ch:",dl_ch0_128+1);
            // print_shorts("pack:",rxdataF_comp0_128+1);

            if(pilots == 0)
            {
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch0_128[2], rxdataF128[2]);
                // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
                mmtmpD1 = _mm_shufflelo_epi16(dl_ch0_128[2], _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[2]);
                // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
                mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift0);
                mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift0);
                mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0, mmtmpD1);
                mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0, mmtmpD1);
                rxdataF_comp0_128[2] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                //   print_shorts("rx:",rxdataF128+2);
                //   print_shorts("ch:",dl_ch0_128+2);
                //  print_shorts("pack:",rxdataF_comp0_128+2);
            }

            // layer 1
            // MF multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch1_128[0], rxdataF128[0]);
            //  print_ints("re",&mmtmpD0);
            // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
            mmtmpD1 = _mm_shufflelo_epi16(dl_ch1_128[0], _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
            //  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_shift1);
            // print_ints("re(shift)",&mmtmpD0);
            mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift1);
            // 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_comp1_128[0] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
            // print_shorts("rx:",rxdataF128);
            //  print_shorts("ch:",dl_ch1_128);
            // print_shorts("pack:",rxdataF_comp1_128);
            // multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch1_128[1], rxdataF128[1]);
            // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
            mmtmpD1 = _mm_shufflelo_epi16(dl_ch1_128[1], _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
            mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[1]);
            // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
            mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift1);
            mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift1);
            mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0, mmtmpD1);
            mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0, mmtmpD1);
            rxdataF_comp1_128[1] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
            //  print_shorts("rx:",rxdataF128+1);
            // print_shorts("ch:",dl_ch1_128+1);
            // print_shorts("pack:",rxdataF_comp1_128+1);

            if(pilots == 0)
            {
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch1_128[2], rxdataF128[2]);
                // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
                mmtmpD1 = _mm_shufflelo_epi16(dl_ch1_128[2], _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, rxdataF128[2]);
                // mmtmpD1 contains imag part of 4 consecutive outputs (32-bit)
                mmtmpD0 = _mm_srai_epi32(mmtmpD0, output_shift1);
                mmtmpD1 = _mm_srai_epi32(mmtmpD1, output_shift1);
                mmtmpD2 = _mm_unpacklo_epi32(mmtmpD0, mmtmpD1);
                mmtmpD3 = _mm_unpackhi_epi32(mmtmpD0, mmtmpD1);
                rxdataF_comp1_128[2] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                //   print_shorts("rx:",rxdataF128+2);
                //  print_shorts("ch:",dl_ch1_128+2);
                //         print_shorts("pack:",rxdataF_comp1_128+2);
                dl_ch0_128 += 3;
                dl_ch1_128 += 3;
                dl_ch_mag0_128 += 3;
                dl_ch_mag1_128 += 3;
                dl_ch_mag0_128b += 3;
                dl_ch_mag1_128b += 3;
                rxdataF128 += 3;
                rxdataF_comp0_128 += 3;
                rxdataF_comp1_128 += 3;
            }
            else
            {
                dl_ch0_128 += 2;
                dl_ch1_128 += 2;
                dl_ch_mag0_128 += 2;
                dl_ch_mag1_128 += 2;
                dl_ch_mag0_128b += 2;
                dl_ch_mag1_128b += 2;
                rxdataF128 += 2;
                rxdataF_comp0_128 += 2;
                rxdataF_comp1_128 += 2;
            }
        } // rb loop

        Nre = (pilots == 0) ? 12 : 8;
        precoded_signal_strength0 += ((signal_energy_nodc(&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * Nre],
                                       (nb_rb * Nre)) * rx_power_correction) - (measurements->n0_power[aarx]));
        precoded_signal_strength1 += ((signal_energy_nodc(&dl_ch_estimates_ext[aarx + 2][symbol * frame_parms->N_RB_DL * Nre],
                                       (nb_rb * Nre)) * rx_power_correction) - (measurements->n0_power[aarx]));
    } // rx_antennas

    measurements->precoded_cqi_dB[eNB_id][0] = dB_fixed2(precoded_signal_strength0, measurements->n0_power_tot);
    measurements->precoded_cqi_dB[eNB_id][1] = dB_fixed2(precoded_signal_strength1, measurements->n0_power_tot);
    // printf("eNB_id %d, symbol %d: precoded CQI %d dB\n",eNB_id,symbol,
    //  measurements->precoded_cqi_dB[eNB_id][0]);
    _mm_empty();
    _m_empty();
#elif defined(__arm__)
    unsigned short rb, Nre;
    unsigned char aarx, symbol_mod, pilots = 0;
    int precoded_signal_strength0 = 0, precoded_signal_strength1 = 0, rx_power_correction;
    int16x4_t *dl_ch0_128, *rxdataF128;
    int16x4_t *dl_ch1_128;
    int16x8_t *dl_ch0_128b, *dl_ch1_128b;
    int32x4_t mmtmpD0, mmtmpD1, mmtmpD0b, mmtmpD1b;
    int16x8_t *dl_ch_mag0_128, *dl_ch_mag0_128b, *dl_ch_mag1_128, *dl_ch_mag1_128b, mmtmpD2, mmtmpD3, mmtmpD4, *rxdataF_comp0_128, *rxdataF_comp1_128;
    int16x8_t QAM_amp0_128, QAM_amp0_128b, QAM_amp1_128, QAM_amp1_128b;
    int32x4_t output_shift128 = vmovq_n_s32(-(int32_t)output_shift);
    int **rxdataF_ext           = pdsch_vars->rxdataF_ext;
    int **dl_ch_estimates_ext   = pdsch_vars->dl_ch_estimates_ext;
    int **dl_ch_mag0            = pdsch_vars->dl_ch_mag0;
    int **dl_ch_mag1            = pdsch_vars->dl_ch_mag1[harq_pid][round];
    int **dl_ch_magb0           = pdsch_vars->dl_ch_magb0;
    int **dl_ch_magb1           = pdsch_vars->dl_ch_magb1[harq_pid][round];
    int **rxdataF_comp0         = pdsch_vars->rxdataF_comp0;
    int **rxdataF_comp1         = pdsch_vars->rxdataF_comp1[harq_pid][round];
    int16_t conj[4]__attribute__((aligned(16))) = {1, -1, 1, -1};
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        if(frame_parms->nb_antenna_ports_eNB == 1)  // 10 out of 12 so don't reduce size
        {
            nb_rb = 1 + (5 * nb_rb / 6);
        }
        else
        {
            pilots = 1;
        }
    }

    rx_power_correction = 1;

    if(mod_order0 == 4)
    {
        QAM_amp0_128  = vmovq_n_s16(QAM16_n1);  // 2/sqrt(10)
        QAM_amp0_128b = vmovq_n_s16(0);
    }
    else if(mod_order0 == 6)
    {
        QAM_amp0_128  = vmovq_n_s16(QAM64_n1); //
        QAM_amp0_128b = vmovq_n_s16(QAM64_n2);
    }

    if(mod_order1 == 4)
    {
        QAM_amp1_128  = vmovq_n_s16(QAM16_n1);  // 2/sqrt(10)
        QAM_amp1_128b = vmovq_n_s16(0);
    }
    else if(mod_order1 == 6)
    {
        QAM_amp1_128  = vmovq_n_s16(QAM64_n1); //
        QAM_amp1_128b = vmovq_n_s16(QAM64_n2);
    }

    //    printf("comp: rxdataF_comp %p, symbol %d\n",rxdataF_comp[0],symbol);

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128          = (int16x4_t *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128          = (int16x4_t *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch0_128b          = (int16x8_t *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128b          = (int16x8_t *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag0_128      = (int16x8_t *)&dl_ch_mag0[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag0_128b     = (int16x8_t *)&dl_ch_magb0[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag1_128      = (int16x8_t *)&dl_ch_mag1[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag1_128b     = (int16x8_t *)&dl_ch_magb1[aarx][symbol * frame_parms->N_RB_DL * 12];
        rxdataF128          = (int16x4_t *)&rxdataF_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        rxdataF_comp0_128   = (int16x8_t *)&rxdataF_comp0[aarx][symbol * frame_parms->N_RB_DL * 12];
        rxdataF_comp1_128   = (int16x8_t *)&rxdataF_comp1[aarx][symbol * frame_parms->N_RB_DL * 12];

        for(rb = 0; rb < nb_rb; rb++)
        {
            if(mmse_flag == 0)
            {
                // combine TX channels using precoder from pmi
                if(mimo_mode == LARGE_CDD)
                {
                    prec2A_TM3_128(&dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM3_128(&dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM3_128(&dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODING1)
                {
                    prec2A_TM4_128(0, &dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM4_128(0, &dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM4_128(0, &dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODINGj)
                {
                    prec2A_TM4_128(1, &dl_ch0_128[0], &dl_ch1_128[0]);
                    prec2A_TM4_128(1, &dl_ch0_128[1], &dl_ch1_128[1]);

                    if(pilots == 0)
                    {
                        prec2A_TM4_128(1, &dl_ch0_128[2], &dl_ch1_128[2]);
                    }
                }
                else
                {
                    LOG_E(PHY, "Unknown MIMO mode\n");
                    return;
                }
            }

            if(mod_order0 > 2)
            {
                // get channel amplitude if not QPSK
                mmtmpD0 = vmull_s16(dl_ch0_128[0], dl_ch0_128[0]);
                // mmtmpD0 = [ch0*ch0,ch1*ch1,ch2*ch2,ch3*ch3];
                mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                // mmtmpD0 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3]>>output_shift128 on 32-bits
                mmtmpD1 = vmull_s16(dl_ch0_128[1], dl_ch0_128[1]);
                mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                mmtmpD2 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                // mmtmpD2 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3,ch4*ch4 + ch5*ch5,ch4*ch4 + ch5*ch5,ch6*ch6 + ch7*ch7,ch6*ch6 + ch7*ch7]>>output_shift128 on 16-bits
                mmtmpD0 = vmull_s16(dl_ch0_128[2], dl_ch0_128[2]);
                mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                mmtmpD1 = vmull_s16(dl_ch0_128[3], dl_ch0_128[3]);
                mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                mmtmpD3 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

                if(pilots == 0)
                {
                    mmtmpD0 = vmull_s16(dl_ch0_128[4], dl_ch0_128[4]);
                    mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                    mmtmpD1 = vmull_s16(dl_ch0_128[5], dl_ch0_128[5]);
                    mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                    mmtmpD4 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                }

                dl_ch_mag0_128b[0] = vqdmulhq_s16(mmtmpD2, QAM_amp0_128b);
                dl_ch_mag0_128b[1] = vqdmulhq_s16(mmtmpD3, QAM_amp0_128b);
                dl_ch_mag0_128[0] = vqdmulhq_s16(mmtmpD2, QAM_amp0_128);
                dl_ch_mag0_128[1] = vqdmulhq_s16(mmtmpD3, QAM_amp0_128);

                if(pilots == 0)
                {
                    dl_ch_mag0_128b[2] = vqdmulhq_s16(mmtmpD4, QAM_amp0_128b);
                    dl_ch_mag0_128[2]  = vqdmulhq_s16(mmtmpD4, QAM_amp0_128);
                }
            }

            if(mod_order1 > 2)
            {
                // get channel amplitude if not QPSK
                mmtmpD0 = vmull_s16(dl_ch1_128[0], dl_ch1_128[0]);
                // mmtmpD0 = [ch0*ch0,ch1*ch1,ch2*ch2,ch3*ch3];
                mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                // mmtmpD0 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3]>>output_shift128 on 32-bits
                mmtmpD1 = vmull_s16(dl_ch1_128[1], dl_ch1_128[1]);
                mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                mmtmpD2 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                // mmtmpD2 = [ch0*ch0 + ch1*ch1,ch0*ch0 + ch1*ch1,ch2*ch2 + ch3*ch3,ch2*ch2 + ch3*ch3,ch4*ch4 + ch5*ch5,ch4*ch4 + ch5*ch5,ch6*ch6 + ch7*ch7,ch6*ch6 + ch7*ch7]>>output_shift128 on 16-bits
                mmtmpD0 = vmull_s16(dl_ch1_128[2], dl_ch1_128[2]);
                mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                mmtmpD1 = vmull_s16(dl_ch1_128[3], dl_ch1_128[3]);
                mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                mmtmpD3 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

                if(pilots == 0)
                {
                    mmtmpD0 = vmull_s16(dl_ch1_128[4], dl_ch1_128[4]);
                    mmtmpD0 = vqshlq_s32(vqaddq_s32(mmtmpD0, vrev64q_s32(mmtmpD0)), output_shift128);
                    mmtmpD1 = vmull_s16(dl_ch1_128[5], dl_ch1_128[5]);
                    mmtmpD1 = vqshlq_s32(vqaddq_s32(mmtmpD1, vrev64q_s32(mmtmpD1)), output_shift128);
                    mmtmpD4 = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                }

                dl_ch_mag1_128b[0] = vqdmulhq_s16(mmtmpD2, QAM_amp1_128b);
                dl_ch_mag1_128b[1] = vqdmulhq_s16(mmtmpD3, QAM_amp1_128b);
                dl_ch_mag1_128[0] = vqdmulhq_s16(mmtmpD2, QAM_amp1_128);
                dl_ch_mag1_128[1] = vqdmulhq_s16(mmtmpD3, QAM_amp1_128);

                if(pilots == 0)
                {
                    dl_ch_mag1_128b[2] = vqdmulhq_s16(mmtmpD4, QAM_amp1_128b);
                    dl_ch_mag1_128[2]  = vqdmulhq_s16(mmtmpD4, QAM_amp1_128);
                }
            }

            mmtmpD0 = vmull_s16(dl_ch0_128[0], rxdataF128[0]);
            //mmtmpD0 = [Re(ch[0])Re(rx[0]) Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1]) Im(ch[1])Im(ch[1])]
            mmtmpD1 = vmull_s16(dl_ch0_128[1], rxdataF128[1]);
            //mmtmpD1 = [Re(ch[2])Re(rx[2]) Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3]) Im(ch[3])Im(ch[3])]
            mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                   vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
            //mmtmpD0 = [Re(ch[0])Re(rx[0])+Im(ch[0])Im(ch[0]) Re(ch[1])Re(rx[1])+Im(ch[1])Im(ch[1]) Re(ch[2])Re(rx[2])+Im(ch[2])Im(ch[2]) Re(ch[3])Re(rx[3])+Im(ch[3])Im(ch[3])]
            mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[0], *(int16x4_t *)conj)), rxdataF128[0]);
            //mmtmpD0 = [-Im(ch[0])Re(rx[0]) Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1]) Re(ch[1])Im(rx[1])]
            mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[1], *(int16x4_t *)conj)), rxdataF128[1]);
            //mmtmpD0 = [-Im(ch[2])Re(rx[2]) Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3]) Re(ch[3])Im(rx[3])]
            mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                   vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
            //mmtmpD1 = [-Im(ch[0])Re(rx[0])+Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1])+Re(ch[1])Im(rx[1]) -Im(ch[2])Re(rx[2])+Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3])+Re(ch[3])Im(rx[3])]
            mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
            mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
            rxdataF_comp0_128[0] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
            mmtmpD0 = vmull_s16(dl_ch0_128[2], rxdataF128[2]);
            mmtmpD1 = vmull_s16(dl_ch0_128[3], rxdataF128[3]);
            mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                   vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
            mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[2], *(int16x4_t *)conj)), rxdataF128[2]);
            mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[3], *(int16x4_t *)conj)), rxdataF128[3]);
            mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                   vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
            mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
            mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
            rxdataF_comp0_128[1] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
            // second stream
            mmtmpD0 = vmull_s16(dl_ch1_128[0], rxdataF128[0]);
            mmtmpD1 = vmull_s16(dl_ch1_128[1], rxdataF128[1]);
            mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                   vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
            mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[0], *(int16x4_t *)conj)), rxdataF128[0]);
            mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[1], *(int16x4_t *)conj)), rxdataF128[1]);
            //mmtmpD0 = [-Im(ch[2])Re(rx[2]) Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3]) Re(ch[3])Im(rx[3])]
            mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                   vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
            //mmtmpD1 = [-Im(ch[0])Re(rx[0])+Re(ch[0])Im(rx[0]) -Im(ch[1])Re(rx[1])+Re(ch[1])Im(rx[1]) -Im(ch[2])Re(rx[2])+Re(ch[2])Im(rx[2]) -Im(ch[3])Re(rx[3])+Re(ch[3])Im(rx[3])]
            mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
            mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
            rxdataF_comp1_128[0] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
            mmtmpD0 = vmull_s16(dl_ch1_128[2], rxdataF128[2]);
            mmtmpD1 = vmull_s16(dl_ch1_128[3], rxdataF128[3]);
            mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                   vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
            mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[2], *(int16x4_t *)conj)), rxdataF128[2]);
            mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[3], *(int16x4_t *)conj)), rxdataF128[3]);
            mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                   vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
            mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
            mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
            rxdataF_comp1_128[1] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));

            if(pilots == 0)
            {
                mmtmpD0 = vmull_s16(dl_ch0_128[4], rxdataF128[4]);
                mmtmpD1 = vmull_s16(dl_ch0_128[5], rxdataF128[5]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[4], *(int16x4_t *)conj)), rxdataF128[4]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch0_128[5], *(int16x4_t *)conj)), rxdataF128[5]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rxdataF_comp0_128[2] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
                mmtmpD0 = vmull_s16(dl_ch1_128[4], rxdataF128[4]);
                mmtmpD1 = vmull_s16(dl_ch1_128[5], rxdataF128[5]);
                mmtmpD0 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0), vget_high_s32(mmtmpD0)),
                                       vpadd_s32(vget_low_s32(mmtmpD1), vget_high_s32(mmtmpD1)));
                mmtmpD0b = vmull_s16(vrev32_s16(vmul_s16(dl_ch1_128[4], *(int16x4_t *)conj)), rxdataF128[4]);
                mmtmpD1b = vmull_s16(vrev32_s16(vmul_s16(dl_ch1_128[5], *(int16x4_t *)conj)), rxdataF128[5]);
                mmtmpD1 = vcombine_s32(vpadd_s32(vget_low_s32(mmtmpD0b), vget_high_s32(mmtmpD0b)),
                                       vpadd_s32(vget_low_s32(mmtmpD1b), vget_high_s32(mmtmpD1b)));
                mmtmpD0 = vqshlq_s32(mmtmpD0, output_shift128);
                mmtmpD1 = vqshlq_s32(mmtmpD1, output_shift128);
                rxdataF_comp1_128[2] = vcombine_s16(vmovn_s32(mmtmpD0), vmovn_s32(mmtmpD1));
            }
        }

        Nre = (pilots == 0) ? 12 : 8;
        // rx_antennas
    }

    Nre = (pilots == 0) ? 12 : 8;
    precoded_signal_strength0 += ((signal_energy_nodc(&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * Nre],
                                   (nb_rb * Nre)) * rx_power_correction) - (measurements->n0_power[aarx]));
    precoded_signal_strength1 += ((signal_energy_nodc(&dl_ch_estimates_ext[aarx + 2][symbol * frame_parms->N_RB_DL * Nre],
                                   (nb_rb * Nre)) * rx_power_correction) - (measurements->n0_power[aarx]));
    measurements->precoded_cqi_dB[eNB_id][0] = dB_fixed2(precoded_signal_strength0, measurements->n0_power_tot);
    measurements->precoded_cqi_dB[eNB_id][1] = dB_fixed2(precoded_signal_strength1, measurements->n0_power_tot);
#endif
}

void dlsch_dual_stream_correlation(LTE_DL_FRAME_PARMS *frame_parms,
                                   unsigned char symbol,
                                   unsigned short nb_rb,
                                   int **dl_ch_estimates_ext,
                                   int **dl_ch_estimates_ext_i,
                                   int **dl_ch_rho_ext,
                                   unsigned char output_shift)
{
#if defined(__x86_64__)||defined(__i386__)
    unsigned short rb;
    __m128i *dl_ch128, *dl_ch128i, *dl_ch_rho128, mmtmpD0, mmtmpD1, mmtmpD2, mmtmpD3;
    unsigned char aarx, symbol_mod, pilots = 0;
    //    printf("dlsch_dual_stream_correlation: symbol %d\n",symbol);
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        pilots = 1;
    }

    //  printf("Dual stream correlation (%p)\n",dl_ch_estimates_ext_i);

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch128          = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];

        if(dl_ch_estimates_ext_i == NULL)  // TM3/4
        {
            dl_ch128i         = (__m128i *)&dl_ch_estimates_ext[aarx + frame_parms->nb_antennas_rx][symbol * frame_parms->N_RB_DL * 12];
        }
        else
        {
            dl_ch128i         = (__m128i *)&dl_ch_estimates_ext_i[aarx][symbol * frame_parms->N_RB_DL * 12];
        }

        dl_ch_rho128      = (__m128i *)&dl_ch_rho_ext[aarx][symbol * frame_parms->N_RB_DL * 12];

        for(rb = 0; rb < nb_rb; rb++)
        {
            // multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch128[0], dl_ch128i[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));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)&conjugate[0]);
            mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128i[0]);
            //      print_ints("im",&mmtmpD1);
            // 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);
            dl_ch_rho128[0] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
            // print_shorts("rho 0:",dl_ch_rho128);
            // multiply by conjugated channel
            mmtmpD0 = _mm_madd_epi16(dl_ch128[1], dl_ch128i[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));
            mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
            mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128i[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);
            dl_ch_rho128[1] = _mm_packs_epi32(mmtmpD2, mmtmpD3);

            if(pilots == 0)
            {
                // multiply by conjugated channel
                mmtmpD0 = _mm_madd_epi16(dl_ch128[2], dl_ch128i[2]);
                // mmtmpD0 contains real part of 4 consecutive outputs (32-bit)
                mmtmpD1 = _mm_shufflelo_epi16(dl_ch128[2], _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_shufflehi_epi16(mmtmpD1, _MM_SHUFFLE(2, 3, 0, 1));
                mmtmpD1 = _mm_sign_epi16(mmtmpD1, *(__m128i *)conjugate);
                mmtmpD1 = _mm_madd_epi16(mmtmpD1, dl_ch128i[2]);
                // 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);
                dl_ch_rho128[2] = _mm_packs_epi32(mmtmpD2, mmtmpD3);
                dl_ch128 += 3;
                dl_ch128i += 3;
                dl_ch_rho128 += 3;
            }
            else
            {
                dl_ch128 += 2;
                dl_ch128i += 2;
                dl_ch_rho128 += 2;
            }
        }
    }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
#endif
}

void dlsch_detection_mrc(LTE_DL_FRAME_PARMS *frame_parms,
                         int **rxdataF_comp,
                         int **rxdataF_comp_i,
                         int **rho,
                         int **rho_i,
                         int **dl_ch_mag,
                         int **dl_ch_magb,
                         int **dl_ch_mag_i,
                         int **dl_ch_magb_i,
                         unsigned char symbol,
                         unsigned short nb_rb,
                         unsigned char dual_stream_UE)
{
#if defined(__x86_64__)||defined(__i386__)
    unsigned char aatx;
    int i;
    __m128i *rxdataF_comp128_0, *rxdataF_comp128_1, *rxdataF_comp128_i0, *rxdataF_comp128_i1, *dl_ch_mag128_0, *dl_ch_mag128_1, *dl_ch_mag128_0b, *dl_ch_mag128_1b, *rho128_0, *rho128_1, *rho128_i0, *rho128_i1,
            *dl_ch_mag128_i0, *dl_ch_mag128_i1, *dl_ch_mag128_i0b, *dl_ch_mag128_i1b;

    if(frame_parms->nb_antennas_rx > 1)
    {
        for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
        {
            rxdataF_comp128_0   = (__m128i *)&rxdataF_comp[(aatx << 1)][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_1   = (__m128i *)&rxdataF_comp[(aatx << 1) + 1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_0      = (__m128i *)&dl_ch_mag[(aatx << 1)][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_1      = (__m128i *)&dl_ch_mag[(aatx << 1) + 1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb[(aatx << 1)][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb[(aatx << 1) + 1][symbol * frame_parms->N_RB_DL * 12];

            // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
            for(i = 0; i < nb_rb * 3; i++)
            {
                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));
                //       print_shorts("mrc comp0:",&rxdataF_comp128_0[i]);
                //       print_shorts("mrc mag0:",&dl_ch_mag128_0[i]);
                //       print_shorts("mrc mag0b:",&dl_ch_mag128_0b[i]);
                //      print_shorts("mrc rho1:",&rho128_1[i]);
            }
        }

        if(rho)
        {
            rho128_0 = (__m128i *) &rho[0][symbol * frame_parms->N_RB_DL * 12];
            rho128_1 = (__m128i *) &rho[1][symbol * frame_parms->N_RB_DL * 12];

            for(i = 0; i < nb_rb * 3; i++)
            {
                //      print_shorts("mrc rho0:",&rho128_0[i]);
                //      print_shorts("mrc rho1:",&rho128_1[i]);
                rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i], 1), _mm_srai_epi16(rho128_1[i], 1));
            }
        }

        if(dual_stream_UE == 1)
        {
            rho128_i0 = (__m128i *) &rho_i[0][symbol * frame_parms->N_RB_DL * 12];
            rho128_i1 = (__m128i *) &rho_i[1][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_i0   = (__m128i *)&rxdataF_comp_i[0][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_i1   = (__m128i *)&rxdataF_comp_i[1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i0      = (__m128i *)&dl_ch_mag_i[0][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i1      = (__m128i *)&dl_ch_mag_i[1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i0b     = (__m128i *)&dl_ch_magb_i[0][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i1b     = (__m128i *)&dl_ch_magb_i[1][symbol * frame_parms->N_RB_DL * 12];

            for(i = 0; i < nb_rb * 3; i++)
            {
                rxdataF_comp128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i0[i], 1), _mm_srai_epi16(rxdataF_comp128_i1[i], 1));
                rho128_i0[i]           = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i], 1), _mm_srai_epi16(rho128_i1[i], 1));
                dl_ch_mag128_i0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0[i], 1), _mm_srai_epi16(dl_ch_mag128_i1[i], 1));
                dl_ch_mag128_i0b[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0b[i], 1), _mm_srai_epi16(dl_ch_mag128_i1b[i], 1));
            }
        }
    }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
    unsigned char aatx;
    int i;
    int16x8_t *rxdataF_comp128_0, *rxdataF_comp128_1, *rxdataF_comp128_i0, *rxdataF_comp128_i1, *dl_ch_mag128_0, *dl_ch_mag128_1, *dl_ch_mag128_0b, *dl_ch_mag128_1b, *rho128_0, *rho128_1, *rho128_i0, *rho128_i1,
              *dl_ch_mag128_i0, *dl_ch_mag128_i1, *dl_ch_mag128_i0b, *dl_ch_mag128_i1b;

    if(frame_parms->nb_antennas_rx > 1)
    {
        for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
        {
            rxdataF_comp128_0   = (int16x8_t *)&rxdataF_comp[(aatx << 1)][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_1   = (int16x8_t *)&rxdataF_comp[(aatx << 1) + 1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_0      = (int16x8_t *)&dl_ch_mag[(aatx << 1)][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_1      = (int16x8_t *)&dl_ch_mag[(aatx << 1) + 1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_0b     = (int16x8_t *)&dl_ch_magb[(aatx << 1)][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_1b     = (int16x8_t *)&dl_ch_magb[(aatx << 1) + 1][symbol * frame_parms->N_RB_DL * 12];

            // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
            for(i = 0; i < nb_rb * 3; i++)
            {
                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]);
            }
        }

        if(rho)
        {
            rho128_0 = (int16x8_t *) &rho[0][symbol * frame_parms->N_RB_DL * 12];
            rho128_1 = (int16x8_t *) &rho[1][symbol * frame_parms->N_RB_DL * 12];

            for(i = 0; i < nb_rb * 3; i++)
            {
                //  print_shorts("mrc rho0:",&rho128_0[i]);
                //  print_shorts("mrc rho1:",&rho128_1[i]);
                rho128_0[i] = vhaddq_s16(rho128_0[i], rho128_1[i]);
            }
        }

        if(dual_stream_UE == 1)
        {
            rho128_i0 = (int16x8_t *) &rho_i[0][symbol * frame_parms->N_RB_DL * 12];
            rho128_i1 = (int16x8_t *) &rho_i[1][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_i0   = (int16x8_t *)&rxdataF_comp_i[0][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_i1   = (int16x8_t *)&rxdataF_comp_i[1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i0      = (int16x8_t *)&dl_ch_mag_i[0][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i1      = (int16x8_t *)&dl_ch_mag_i[1][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i0b     = (int16x8_t *)&dl_ch_magb_i[0][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_i1b     = (int16x8_t *)&dl_ch_magb_i[1][symbol * frame_parms->N_RB_DL * 12];

            for(i = 0; i < nb_rb * 3; i++)
            {
                rxdataF_comp128_i0[i] = vhaddq_s16(rxdataF_comp128_i0[i], rxdataF_comp128_i1[i]);
                rho128_i0[i]          = vhaddq_s16(rho128_i0[i], rho128_i1[i]);
                dl_ch_mag128_i0[i]    = vhaddq_s16(dl_ch_mag128_i0[i], dl_ch_mag128_i1[i]);
                dl_ch_mag128_i0b[i]   = vhaddq_s16(dl_ch_mag128_i0b[i], dl_ch_mag128_i1b[i]);
            }
        }
    }

#endif
}

void dlsch_detection_mrc_TM34(LTE_DL_FRAME_PARMS *frame_parms,
                              LTE_UE_PDSCH *pdsch_vars,
                              int harq_pid,
                              int round,
                              unsigned char symbol,
                              unsigned short nb_rb,
                              unsigned char dual_stream_UE)
{
    int i;
    __m128i *rxdataF_comp128_0, *rxdataF_comp128_1;
    __m128i *dl_ch_mag128_0, *dl_ch_mag128_1;
    __m128i *dl_ch_mag128_0b, *dl_ch_mag128_1b;
    __m128i *rho128_0, *rho128_1;
    int **rxdataF_comp0           = pdsch_vars->rxdataF_comp0;
    int **rxdataF_comp1           = pdsch_vars->rxdataF_comp1[harq_pid][round];
    int **dl_ch_rho_ext           = pdsch_vars->dl_ch_rho_ext[harq_pid][round]; //for second stream
    int **dl_ch_rho2_ext          = pdsch_vars->dl_ch_rho2_ext;
    int **dl_ch_mag0              = pdsch_vars->dl_ch_mag0;
    int **dl_ch_mag1              = pdsch_vars->dl_ch_mag1[harq_pid][round];
    int **dl_ch_magb0             = pdsch_vars->dl_ch_magb0;
    int **dl_ch_magb1             = pdsch_vars->dl_ch_magb1[harq_pid][round];
    rxdataF_comp128_0   = (__m128i *)&rxdataF_comp0[0][symbol * frame_parms->N_RB_DL * 12];
    rxdataF_comp128_1   = (__m128i *)&rxdataF_comp0[1][symbol * frame_parms->N_RB_DL * 12];
    dl_ch_mag128_0      = (__m128i *)&dl_ch_mag0[0][symbol * frame_parms->N_RB_DL * 12];
    dl_ch_mag128_1      = (__m128i *)&dl_ch_mag0[1][symbol * frame_parms->N_RB_DL * 12];
    dl_ch_mag128_0b     = (__m128i *)&dl_ch_magb0[0][symbol * frame_parms->N_RB_DL * 12];
    dl_ch_mag128_1b     = (__m128i *)&dl_ch_magb0[1][symbol * frame_parms->N_RB_DL * 12];
    rho128_0 = (__m128i *) &dl_ch_rho2_ext[0][symbol * frame_parms->N_RB_DL * 12];
    rho128_1 = (__m128i *) &dl_ch_rho2_ext[1][symbol * frame_parms->N_RB_DL * 12];

    // MRC on each re of rb, both on MF output and magnitude (for 16QAM/64QAM llr computation)
    for(i = 0; i < nb_rb * 3; i++)
    {
        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));
        rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i], 1), _mm_srai_epi16(rho128_1[i], 1));

        if(frame_parms->nb_antennas_rx > 2)
        {
            __m128i *rxdataF_comp128_2 = NULL;
            __m128i *rxdataF_comp128_3 = NULL;
            __m128i *dl_ch_mag128_2 = NULL;
            __m128i *dl_ch_mag128_3 = NULL;
            __m128i *dl_ch_mag128_2b = NULL;
            __m128i *dl_ch_mag128_3b = NULL;
            __m128i *rho128_2 = NULL;
            __m128i *rho128_3 = NULL;
            rxdataF_comp128_2   = (__m128i *)&rxdataF_comp0[2][symbol * frame_parms->N_RB_DL * 12];
            rxdataF_comp128_3   = (__m128i *)&rxdataF_comp0[3][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_2      = (__m128i *)&dl_ch_mag0[2][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_3      = (__m128i *)&dl_ch_mag0[3][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_2b     = (__m128i *)&dl_ch_magb0[2][symbol * frame_parms->N_RB_DL * 12];
            dl_ch_mag128_3b     = (__m128i *)&dl_ch_magb0[3][symbol * frame_parms->N_RB_DL * 12];
            rho128_2 = (__m128i *) &dl_ch_rho2_ext[2][symbol * frame_parms->N_RB_DL * 12];
            rho128_3 = (__m128i *) &dl_ch_rho2_ext[3][symbol * frame_parms->N_RB_DL * 12];
            /*rxdataF_comp*/
            rxdataF_comp128_2[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_2[i], 1), _mm_srai_epi16(rxdataF_comp128_3[i], 1));
            rxdataF_comp128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_0[i], 1), _mm_srai_epi16(rxdataF_comp128_2[i], 1));
            /*dl_ch_mag*/
            dl_ch_mag128_2[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_2[i], 1), _mm_srai_epi16(dl_ch_mag128_3[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_2[i], 1));
            /*dl_ch_mag*/
            dl_ch_mag128_2b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_2b[i], 1), _mm_srai_epi16(dl_ch_mag128_3b[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_2b[i], 1));
            /*rho*/
            rho128_2[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_2[i], 1), _mm_srai_epi16(rho128_3[i], 1));
            rho128_0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_0[i], 1), _mm_srai_epi16(rho128_2[i], 1));
        }
    }

    if(dual_stream_UE == 1)
    {
        __m128i *dl_ch_mag128_i0, *dl_ch_mag128_i1;
        __m128i *dl_ch_mag128_i0b, *dl_ch_mag128_i1b;
        __m128i *rho128_i0, *rho128_i1;
        __m128i *rxdataF_comp128_i0, *rxdataF_comp128_i1;
        rxdataF_comp128_i0   = (__m128i *)&rxdataF_comp1[0][symbol * frame_parms->N_RB_DL * 12];
        rxdataF_comp128_i1   = (__m128i *)&rxdataF_comp1[1][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag128_i0      = (__m128i *)&dl_ch_mag1[0][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag128_i1      = (__m128i *)&dl_ch_mag1[1][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag128_i0b     = (__m128i *)&dl_ch_magb1[0][symbol * frame_parms->N_RB_DL * 12];
        dl_ch_mag128_i1b     = (__m128i *)&dl_ch_magb1[1][symbol * frame_parms->N_RB_DL * 12];
        rho128_i0 = (__m128i *) &dl_ch_rho_ext[0][symbol * frame_parms->N_RB_DL * 12];
        rho128_i1 = (__m128i *) &dl_ch_rho_ext[1][symbol * frame_parms->N_RB_DL * 12];

        for(i = 0; i < nb_rb * 3; i++)
        {
            rxdataF_comp128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i0[i], 1), _mm_srai_epi16(rxdataF_comp128_i1[i], 1));
            dl_ch_mag128_i0[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0[i], 1), _mm_srai_epi16(dl_ch_mag128_i1[i], 1));
            dl_ch_mag128_i0b[i]    = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0b[i], 1), _mm_srai_epi16(dl_ch_mag128_i1b[i], 1));
            rho128_i0[i]           = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i], 1), _mm_srai_epi16(rho128_i1[i], 1));

            if(frame_parms->nb_antennas_rx > 2)
            {
                __m128i *rxdataF_comp128_i2 = NULL;
                __m128i *rxdataF_comp128_i3 = NULL;
                __m128i *dl_ch_mag128_i2 = NULL;
                __m128i *dl_ch_mag128_i3 = NULL;
                __m128i *dl_ch_mag128_i2b = NULL;
                __m128i *dl_ch_mag128_i3b = NULL;
                __m128i *rho128_i2 = NULL;
                __m128i *rho128_i3 = NULL;
                rxdataF_comp128_i2   = (__m128i *)&rxdataF_comp1[2][symbol * frame_parms->N_RB_DL * 12];
                rxdataF_comp128_i3   = (__m128i *)&rxdataF_comp1[3][symbol * frame_parms->N_RB_DL * 12];
                dl_ch_mag128_i2      = (__m128i *)&dl_ch_mag1[2][symbol * frame_parms->N_RB_DL * 12];
                dl_ch_mag128_i3      = (__m128i *)&dl_ch_mag1[3][symbol * frame_parms->N_RB_DL * 12];
                dl_ch_mag128_i2b     = (__m128i *)&dl_ch_magb1[2][symbol * frame_parms->N_RB_DL * 12];
                dl_ch_mag128_i3b     = (__m128i *)&dl_ch_magb1[3][symbol * frame_parms->N_RB_DL * 12];
                rho128_i2 = (__m128i *) &dl_ch_rho_ext[2][symbol * frame_parms->N_RB_DL * 12];
                rho128_i3 = (__m128i *) &dl_ch_rho_ext[3][symbol * frame_parms->N_RB_DL * 12];
                /*rxdataF_comp*/
                rxdataF_comp128_i2[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i2[i], 1), _mm_srai_epi16(rxdataF_comp128_i3[i], 1));
                rxdataF_comp128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rxdataF_comp128_i0[i], 1), _mm_srai_epi16(rxdataF_comp128_i2[i], 1));
                /*dl_ch_mag*/
                dl_ch_mag128_i2[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i2[i], 1), _mm_srai_epi16(dl_ch_mag128_i3[i], 1));
                dl_ch_mag128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0[i], 1), _mm_srai_epi16(dl_ch_mag128_i2[i], 1));
                /*dl_ch_mag*/
                dl_ch_mag128_i2b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i2b[i], 1), _mm_srai_epi16(dl_ch_mag128_i3b[i], 1));
                dl_ch_mag128_i0b[i] = _mm_adds_epi16(_mm_srai_epi16(dl_ch_mag128_i0b[i], 1), _mm_srai_epi16(dl_ch_mag128_i2b[i], 1));
                /*rho*/
                rho128_i2[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_i2[i], 1), _mm_srai_epi16(rho128_i3[i], 1));
                rho128_i0[i] = _mm_adds_epi16(_mm_srai_epi16(rho128_i0[i], 1), _mm_srai_epi16(rho128_i2[i], 1));
            }
        }
    }

    _mm_empty();
    _m_empty();
}

void dlsch_scale_channel(int **dl_ch_estimates_ext,
                         LTE_DL_FRAME_PARMS *frame_parms,
                         LTE_UE_DLSCH_t **dlsch_ue,
                         uint8_t symbol,
                         unsigned short nb_rb)
{
#if defined(__x86_64__)||defined(__i386__)
    short rb, ch_amp;
    unsigned char aatx, aarx, pilots = 0, symbol_mod;
    __m128i *dl_ch128, ch_amp128;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        if(frame_parms->nb_antenna_ports_eNB == 1) // 10 out of 12 so don't reduce size
        {
            nb_rb = 1 + (5 * nb_rb / 6);
        }
        else
        {
            pilots = 1;
        }
    }

    // Determine scaling amplitude based the symbol
    ch_amp = ((pilots) ? (dlsch_ue[0]->sqrt_rho_b) : (dlsch_ue[0]->sqrt_rho_a));
    LOG_D(PHY, "Scaling PDSCH Chest in OFDM symbol %d by %d, pilots %d nb_rb %d NCP %d symbol %d\n", symbol_mod, ch_amp, pilots, nb_rb, frame_parms->Ncp, symbol);
    // printf("Scaling PDSCH Chest in OFDM symbol %d by %d\n",symbol_mod,ch_amp);
    ch_amp128 = _mm_set1_epi16(ch_amp); // Q3.13

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
    {
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            dl_ch128 = (__m128i *)&dl_ch_estimates_ext[(aatx << 1) + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                dl_ch128[0] = _mm_mulhi_epi16(dl_ch128[0], ch_amp128);
                dl_ch128[0] = _mm_slli_epi16(dl_ch128[0], 3);
                dl_ch128[1] = _mm_mulhi_epi16(dl_ch128[1], ch_amp128);
                dl_ch128[1] = _mm_slli_epi16(dl_ch128[1], 3);

                if(pilots)
                {
                    dl_ch128 += 2;
                }
                else
                {
                    dl_ch128[2] = _mm_mulhi_epi16(dl_ch128[2], ch_amp128);
                    dl_ch128[2] = _mm_slli_epi16(dl_ch128[2], 3);
                    dl_ch128 += 3;
                }
            }
        }
    }

#elif defined(__arm__)
#endif
}

//compute average channel_level on each (TX,RX) antenna pair
void dlsch_channel_level(int **dl_ch_estimates_ext,
                         LTE_DL_FRAME_PARMS *frame_parms,
                         int32_t *avg,
                         uint8_t symbol,
                         unsigned short nb_rb)
{
#if defined(__x86_64__)||defined(__i386__)
    //printf("symbol = %d\n", symbol);
    short rb;
    unsigned char aatx, aarx, nre = 12, symbol_mod;
    __m128i *dl_ch128, avg128D;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
    {
        nre = 8;
    }
    else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB == 1))
    {
        nre = 10;
    }
    else
    {
        nre = 12;
    }

    //nb_rb*nre = y * 2^x
    int16_t x = factor2(nb_rb * nre);
    int16_t y = (nb_rb * nre) >> x;

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            //clear average level
            //printf("aatx = %d, aarx = %d, aatx*frame_parms->nb_antennas_rx + aarx] = %d \n", aatx, aarx, aatx*frame_parms->nb_antennas_rx + aarx);
            avg128D = _mm_setzero_si128();
            // 5 is always a symbol with no pilots for both normal and extended prefix
            dl_ch128 = (__m128i *)&dl_ch_estimates_ext[aatx * 2 + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                //printf("rb %d : ",rb);
                avg128D = _mm_add_epi32(avg128D, _mm_srai_epi32(_mm_madd_epi16(dl_ch128[0], dl_ch128[0]), x));
                avg128D = _mm_add_epi32(avg128D, _mm_srai_epi32(_mm_madd_epi16(dl_ch128[1], dl_ch128[1]), x));

                //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[0],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[0], coeff128),15)));
                //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[1],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[1], coeff128),15)));

                if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
                {
                    dl_ch128 += 2;
                }
                else
                {
                    avg128D = _mm_add_epi32(avg128D, _mm_srai_epi32(_mm_madd_epi16(dl_ch128[2], dl_ch128[2]), x));
                    //avg128D = _mm_add_epi32(avg128D,_mm_madd_epi16(dl_ch128[2],_mm_srai_epi16(_mm_mulhi_epi16(dl_ch128[2], coeff128),15)));
                    dl_ch128 += 3;
                }

                /*  if(rb==0){
                    print_shorts("dl_ch128",&dl_ch128[0]);
                    print_shorts("dl_ch128",&dl_ch128[1]);
                    print_shorts("dl_ch128",&dl_ch128[2]);
                    }*/
            }

            avg[aatx * frame_parms->nb_antennas_rx + aarx] = (((int32_t *)&avg128D)[0] +
                    ((int32_t *)&avg128D)[1] +
                    ((int32_t *)&avg128D)[2] +
                    ((int32_t *)&avg128D)[3]) / y;
        }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
    short rb;
    unsigned char aatx, aarx, nre = 12, symbol_mod;
    int32x4_t avg128D;
    int16x4_t *dl_ch128;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            //clear average level
            avg128D = vdupq_n_s32(0);
            // 5 is always a symbol with no pilots for both normal and extended prefix
            dl_ch128 = (int16x4_t *)&dl_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                //  printf("rb %d : ",rb);
                //  print_shorts("ch",&dl_ch128[0]);
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[0], dl_ch128[0]));
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[1], dl_ch128[1]));
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[2], dl_ch128[2]));
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[3], dl_ch128[3]));

                if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->mode1_flag == 0))
                {
                    dl_ch128 += 4;
                }
                else
                {
                    avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[4], dl_ch128[4]));
                    avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[5], dl_ch128[5]));
                    dl_ch128 += 6;
                }

                /*
                    if (rb==0) {
                    print_shorts("dl_ch128",&dl_ch128[0]);
                    print_shorts("dl_ch128",&dl_ch128[1]);
                    print_shorts("dl_ch128",&dl_ch128[2]);
                    }
                */
            }

            if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->mode1_flag == 0))
            {
                nre = 8;
            }
            else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->mode1_flag == 1))
            {
                nre = 10;
            }
            else
            {
                nre = 12;
            }

            avg[aatx * frame_parms->nb_antennas_rx + aarx] = (((int32_t *)&avg128D)[0] +
                    ((int32_t *)&avg128D)[1] +
                    ((int32_t *)&avg128D)[2] +
                    ((int32_t *)&avg128D)[3]) / (nb_rb * nre);
            //printf("Channel level : %d\n",avg[aatx*(frame_parms->nb_antennas_rx-1) + aarx]);
        }

#endif
}

void dlsch_channel_level_core(int **dl_ch_estimates_ext,
                              int32_t *avg,
                              int n_tx,
                              int n_rx,
                              int length,
                              int start_point)
{
#if defined(__x86_64__)||defined(__i386__)
    short ii;
    int aatx, aarx;
    int length_mod8;
    int length2;
    __m128i *dl_ch128, avg128D;
    int16_t x = factor2(length);
    int16_t y = (length) >> x;

    for(aatx = 0; aatx < n_tx; aatx++)
        for(aarx = 0; aarx < n_rx; aarx++)
        {
            avg128D = _mm_setzero_si128();
            dl_ch128 = (__m128i *)&dl_ch_estimates_ext[aatx * 2 + aarx][start_point];
            length_mod8 = length & 7;

            if(length_mod8 == 0)
            {
                length2 = length >> 3;

                for(ii = 0; ii < length2; ii++)
                {
                    avg128D = _mm_add_epi32(avg128D, _mm_srai_epi32(_mm_madd_epi16(dl_ch128[0], dl_ch128[0]), x));
                    avg128D = _mm_add_epi32(avg128D, _mm_srai_epi32(_mm_madd_epi16(dl_ch128[1], dl_ch128[1]), x));
                    dl_ch128 += 2;
                }
            }
            else
            {
                printf("Channel level: Received number of subcarriers is not multiple of 4, \n"
                       "need to adapt the code!\n");
            }

            avg[aatx * n_rx + aarx] = (((int32_t *)&avg128D)[0] +
                                       ((int32_t *)&avg128D)[1] +
                                       ((int32_t *)&avg128D)[2] +
                                       ((int32_t *)&avg128D)[3]) / y;
            //printf("Channel level [%d]: %d\n",aatx*n_rx + aarx, avg[aatx*n_rx + aarx]);
        }

    _mm_empty();
    _m_empty();
    /* FIXME This part needs to be adapted like the one above */
#elif defined(__arm__)
    short rb;
    unsigned char aatx, aarx, nre = 12, symbol_mod;
    int32x4_t avg128D;
    int16x4_t *dl_ch128;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            //clear average level
            avg128D = vdupq_n_s32(0);
            // 5 is always a symbol with no pilots for both normal and extended prefix
            dl_ch128 = (int16x4_t *)&dl_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                //  printf("rb %d : ",rb);
                //  print_shorts("ch",&dl_ch128[0]);
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[0], dl_ch128[0]));
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[1], dl_ch128[1]));
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[2], dl_ch128[2]));
                avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[3], dl_ch128[3]));

                if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
                {
                    dl_ch128 += 4;
                }
                else
                {
                    avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[4], dl_ch128[4]));
                    avg128D = vqaddq_s32(avg128D, vmull_s16(dl_ch128[5], dl_ch128[5]));
                    dl_ch128 += 6;
                }
            }

            if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
            {
                nre = 8;
            }
            else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB == 1))
            {
                nre = 10;
            }
            else
            {
                nre = 12;
            }

            avg[aatx * frame_parms->nb_antennas_rx + aarx] = (((int32_t *)&avg128D)[0] +
                    ((int32_t *)&avg128D)[1] +
                    ((int32_t *)&avg128D)[2] +
                    ((int32_t *)&avg128D)[3]) / (nb_rb * nre);
            //printf("Channel level : %d\n",avg[aatx*(frame_parms->nb_antennas_rx-1) + aarx]);
        }

#endif
}

void dlsch_channel_level_median(int **dl_ch_estimates_ext,
                                int32_t *median,
                                int n_tx,
                                int n_rx,
                                int length,
                                int start_point)
{
#if defined(__x86_64__)||defined(__i386__)
    short ii;
    int aatx, aarx;
    int length2;
    int max = 0, min = 0;
    int norm_pack;
    __m128i *dl_ch128, norm128D;

    for(aatx = 0; aatx < n_tx; aatx++)
    {
        for(aarx = 0; aarx < n_rx; aarx++)
        {
            max = 0;
            min = 0;
            norm128D = _mm_setzero_si128();
            dl_ch128 = (__m128i *)&dl_ch_estimates_ext[aatx * 2 + aarx][start_point];
            length2 = length >> 2;

            for(ii = 0; ii < length2; ii++)
            {
                norm128D = _mm_srai_epi32(_mm_madd_epi16(dl_ch128[0], dl_ch128[0]), 1);
                //print_ints("norm128D",&norm128D[0]);
                norm_pack = ((int32_t *)&norm128D)[0] +
                            ((int32_t *)&norm128D)[1] +
                            ((int32_t *)&norm128D)[2] +
                            ((int32_t *)&norm128D)[3];

                if(norm_pack > max)
                {
                    max = norm_pack;
                }

                if(norm_pack < min)
                {
                    min = norm_pack;
                }

                dl_ch128 += 1;
            }

            median[aatx * n_rx + aarx]  = (max + min) >> 1;
            // printf("Channel level  median [%d]: %d\n",aatx*n_rx + aarx, median[aatx*n_rx + aarx]);
        }
    }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
    short rb;
    unsigned char aatx, aarx, nre = 12, symbol_mod;
    int32x4_t norm128D;
    int16x4_t *dl_ch128;

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
    {
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            max = 0;
            min = 0;
            norm128D = vdupq_n_s32(0);
            dl_ch128 = (int16x4_t *)&dl_ch_estimates_ext[aatx * n_rx + aarx][start_point];
            length_mod8 = length & 3;
            length2 = length >> 2;

            for(ii = 0; ii < length2; ii++)
            {
                norm128D = vshrq_n_u32(vmull_s16(dl_ch128[0], dl_ch128[0]), 1);
                norm_pack = ((int32_t *)&norm128D)[0] +
                            ((int32_t *)&norm128D)[1] +
                            ((int32_t *)&norm128D)[2] +
                            ((int32_t *)&norm128D)[3];

                if(norm_pack > max)
                {
                    max = norm_pack;
                }

                if(norm_pack < min)
                {
                    min = norm_pack;
                }

                dl_ch128 += 1;
            }

            median[aatx * n_rx + aarx]  = (max + min) >> 1;
            //printf("Channel level  median [%d]: %d\n",aatx*n_rx + aarx, median[aatx*n_rx + aarx]);
        }
    }

#endif
}

void mmse_processing_oai(LTE_UE_PDSCH *pdsch_vars,
                         LTE_DL_FRAME_PARMS *frame_parms,
                         PHY_MEASUREMENTS *measurements,
                         unsigned char first_symbol_flag,
                         MIMO_mode_t mimo_mode,
                         unsigned short mmse_flag,
                         int noise_power,
                         unsigned char symbol,
                         unsigned short nb_rb)
{
    int **rxdataF_ext           = pdsch_vars->rxdataF_ext;
    int **dl_ch_estimates_ext   = pdsch_vars->dl_ch_estimates_ext;
    unsigned char *pmi_ext      = pdsch_vars->pmi_ext;
    int avg_00[frame_parms->nb_antenna_ports_eNB * frame_parms->nb_antennas_rx];
    int avg_01[frame_parms->nb_antenna_ports_eNB * frame_parms->nb_antennas_rx];
    int symbol_mod, length, start_point, nre;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
    {
        nre = 8;
    }
    else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB == 1))
    {
        nre = 10;
    }
    else
    {
        nre = 12;
    }

    length  = nre * nb_rb;
    start_point = symbol * nb_rb * 12;
    mmse_processing_core(rxdataF_ext,
                         dl_ch_estimates_ext,
                         noise_power,
                         frame_parms->nb_antenna_ports_eNB,
                         frame_parms->nb_antennas_rx,
                         length,
                         start_point);

    /*  dlsch_channel_aver_band(dl_ch_estimates_ext,
                            frame_parms,
                            chan_avg,
                            symbol,
                            nb_rb);

        for (aatx=0; aatx<frame_parms->nb_antenna_ports_eNB; aatx++)
        for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++) {
         H[aatx*frame_parms->nb_antennas_rx + aarx] = (float)(chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].r/(32768.0)) + I*(float)(chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i/(32768.0));
        // printf("H [%d] = (%f, %f) \n", aatx*frame_parms->nb_antennas_rx + aarx, creal(H[aatx*frame_parms->nb_antennas_rx + aarx]), cimag(H[aatx*frame_parms->nb_antennas_rx + aarx]));
        }*/

    if(first_symbol_flag == 1)
    {
        dlsch_channel_level_TM34(dl_ch_estimates_ext,
                                 frame_parms,
                                 pmi_ext,
                                 avg_00,
                                 avg_01,
                                 symbol,
                                 nb_rb,
                                 mmse_flag,
                                 mimo_mode);
        avg_00[0] = (log2_approx(avg_00[0]) / 2) + dlsch_demod_shift + 4; // + 2 ;//+ 4;
        avg_01[0] = (log2_approx(avg_01[0]) / 2) + dlsch_demod_shift + 4; // + 2 ;//+ 4;
        pdsch_vars->log2_maxh0 = cmax(avg_00[0], 0);
        pdsch_vars->log2_maxh1 = cmax(avg_01[0], 0);
    }
}

void mmse_processing_core(int32_t **rxdataF_ext,
                          int32_t **dl_ch_estimates_ext,
                          int noise_power,
                          int n_tx,
                          int n_rx,
                          int length,
                          int start_point)
{
    int aatx, aarx, re;
    float imag;
    float real;
    float complex **W_MMSE = malloc(n_tx * n_rx * sizeof(float complex *));

    for(int j = 0; j < n_tx * n_rx; j++)
    {
        W_MMSE[j] = malloc(sizeof(float complex) * length);
    }

    float complex *H =  malloc(n_tx * n_rx * sizeof(float complex));
    float complex *W_MMSE_re =  malloc(n_tx * n_rx * sizeof(float complex));
    float complex **dl_ch_estimates_ext_flcpx = malloc(n_tx * n_rx * sizeof(float complex *));

    for(int j = 0; j < n_tx * n_rx; j++)
    {
        dl_ch_estimates_ext_flcpx[j] = malloc(sizeof(float complex) * length);
    }

    float complex **rxdataF_ext_flcpx = malloc(n_rx * sizeof(float complex *));

    for(int j = 0; j < n_rx; j++)
    {
        rxdataF_ext_flcpx[j] = malloc(sizeof(float complex) * length);
    }

    chan_est_to_float(dl_ch_estimates_ext,
                      dl_ch_estimates_ext_flcpx,
                      n_tx,
                      n_rx,
                      length,
                      start_point);

    for(re = 0; re < length; re++)
    {
        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                imag = cimag(dl_ch_estimates_ext_flcpx[aatx * n_rx + aarx][re]);
                real = creal(dl_ch_estimates_ext_flcpx[aatx * n_rx + aarx][re]);
                H[aatx * n_rx + aarx] = real + I * imag;
            }
        }

        compute_MMSE(H, n_tx, noise_power, W_MMSE_re);

        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                W_MMSE[aatx * n_rx + aarx][re] = W_MMSE_re[aatx * n_rx + aarx];
            }
        }
    }

    rxdataF_to_float(rxdataF_ext,
                     rxdataF_ext_flcpx,
                     n_rx,
                     length,
                     start_point);
    mult_mmse_rxdataF(W_MMSE,
                      rxdataF_ext_flcpx,
                      n_tx,
                      n_rx,
                      length,
                      start_point);
    mult_mmse_chan_est(W_MMSE,
                       dl_ch_estimates_ext_flcpx,
                       n_tx,
                       n_rx,
                       length,
                       start_point);
    float_to_rxdataF(rxdataF_ext,
                     rxdataF_ext_flcpx,
                     n_tx,
                     n_rx,
                     length,
                     start_point);
    float_to_chan_est(dl_ch_estimates_ext,
                      dl_ch_estimates_ext_flcpx,
                      n_tx,
                      n_rx,
                      length,
                      start_point);
    free(W_MMSE);
    free(H);
    free(W_MMSE_re);
    free(dl_ch_estimates_ext_flcpx);
    free(rxdataF_ext_flcpx);
}

/*THIS FUNCTION TAKES FLOAT_POINT INPUT. SHOULD NOT BE USED WITH OAI*/
void mmse_processing_core_flp(float complex **rxdataF_ext_flcpx,
                              float complex **H,
                              int32_t **rxdataF_ext,
                              int32_t **dl_ch_estimates_ext,
                              float noise_power,
                              int n_tx,
                              int n_rx,
                              int length,
                              int start_point)
{
    int aatx, aarx, re;
    float max = 0;
    float one_over_max = 0;
    float complex **W_MMSE = malloc(n_tx * n_rx * sizeof(float complex *));

    for(int j = 0; j < n_tx * n_rx; j++)
    {
        W_MMSE[j] = malloc(sizeof(float complex) * length);
    }

    float complex *H_re =  malloc(n_tx * n_rx * sizeof(float complex));
    float complex *W_MMSE_re =  malloc(n_tx * n_rx * sizeof(float complex));

    for(re = 0; re < length; re++)
    {
        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                H_re[aatx * n_rx + aarx] = H[aatx * n_rx + aarx][re];
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf(" H_re[%d]= (%f + i%f)\n", aatx * n_rx + aarx, creal(H_re[aatx * n_rx + aarx]), cimag(H_re[aatx * n_rx + aarx]));
                }

#endif
            }
        }

        compute_MMSE(H_re, n_tx, noise_power, W_MMSE_re);

        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                W_MMSE[aatx * n_rx + aarx][re] = W_MMSE_re[aatx * n_rx + aarx];

                if(fabs(creal(W_MMSE_re[aatx * n_rx + aarx])) > max)
                {
                    max = fabs(creal(W_MMSE_re[aatx * n_rx + aarx]));
                }

                if(fabs(cimag(W_MMSE_re[aatx * n_rx + aarx])) > max)
                {
                    max = fabs(cimag(W_MMSE_re[aatx * n_rx + aarx]));
                }
            }
        }
    }

    one_over_max = 1.0 / max;

    for(re = 0; re < length; re++)
        for(aatx = 0; aatx < n_tx; aatx++)
            for(aarx = 0; aarx < n_rx; aarx++)
            {
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf(" W_MMSE[%d] = (%f + i%f)\n", aatx * n_rx + aarx, creal(W_MMSE[aatx * n_rx + aarx][re]), cimag(W_MMSE[aatx * n_rx + aarx][re]));
                }

#endif
                W_MMSE[aatx * n_rx + aarx][re] = one_over_max * W_MMSE[aatx * n_rx + aarx][re];
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf(" AFTER NORM W_MMSE[%d] = (%f + i%f), max = %f \n", aatx * n_rx + aarx, creal(W_MMSE[aatx * n_rx + aarx][re]), cimag(W_MMSE[aatx * n_rx + aarx][re]), max);
                }

#endif
            }

    mult_mmse_rxdataF(W_MMSE,
                      rxdataF_ext_flcpx,
                      n_tx,
                      n_rx,
                      length,
                      start_point);
    mult_mmse_chan_est(W_MMSE,
                       H,
                       n_tx,
                       n_rx,
                       length,
                       start_point);
    float_to_rxdataF(rxdataF_ext,
                     rxdataF_ext_flcpx,
                     n_tx,
                     n_rx,
                     length,
                     start_point);
    float_to_chan_est(dl_ch_estimates_ext,
                      H,
                      n_tx,
                      n_rx,
                      length,
                      start_point);
    free(H_re);
    free(W_MMSE);
    free(W_MMSE_re);
}

void dlsch_channel_aver_band(int **dl_ch_estimates_ext,
                             LTE_DL_FRAME_PARMS *frame_parms,
                             struct complex32 *chan_avg,
                             unsigned char symbol,
                             unsigned short nb_rb)
{
#if defined(__x86_64__)||defined(__i386__)
    short rb;
    unsigned char aatx, aarx, nre = 12, symbol_mod;
    __m128i *dl_ch128, avg128D;
    int32_t chan_est_avg[4];
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
    {
        nre = 8;
    }
    else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB == 1))
    {
        nre = 10;
    }
    else
    {
        nre = 12;
    }

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
    {
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            dl_ch128 = (__m128i *)&dl_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];
            avg128D = _mm_setzero_si128();
            //  print_shorts("avg128D 1",&avg128D);

            for(rb = 0; rb < nb_rb; rb++)
            {
                /*  printf("symbol %d, ant %d, nre*nrb %d, rb %d \n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, nb_rb*nre, rb);
                    print_shorts("aver dl_ch128",&dl_ch128[0]);
                    print_shorts("aver dl_ch128",&dl_ch128[1]);
                    print_shorts("aver dl_ch128",&dl_ch128[2]);
                    avg128D = _mm_add_epi16(avg128D, dl_ch128[0]);*/
                //print_shorts("avg128D 2",&avg128D);
                avg128D = _mm_add_epi16(avg128D, dl_ch128[1]);
                //  print_shorts("avg128D 3",&avg128D);

                if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
                {
                    dl_ch128 += 2;
                }
                else
                {
                    avg128D = _mm_add_epi16(avg128D, dl_ch128[2]);
                    //  print_shorts("avg128D 4",&avg128D);
                    dl_ch128 += 3;
                }
            }

            chan_avg[aatx * frame_parms->nb_antennas_rx + aarx].r = (((int16_t *)&avg128D)[0] +
                    ((int16_t *)&avg128D)[2] +
                    ((int16_t *)&avg128D)[4] +
                    ((int16_t *)&avg128D)[6]) / (nb_rb * nre);
            //  printf("symb %d chan_avg re [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].r);
            chan_avg[aatx * frame_parms->nb_antennas_rx + aarx].i = (((int16_t *)&avg128D)[1] +
                    ((int16_t *)&avg128D)[3] +
                    ((int16_t *)&avg128D)[5] +
                    ((int16_t *)&avg128D)[7]) / (nb_rb * nre);
            //  printf("symb %d chan_avg im [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i);
            //printf("symb %d chan_avg im [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_avg[aatx*frame_parms->nb_antennas_rx + aarx].i);
            chan_est_avg[aatx * frame_parms->nb_antennas_rx + aarx] = (((int32_t)chan_avg[aatx * frame_parms->nb_antennas_rx + aarx].i) << 16) | (((int32_t)chan_avg[aatx * frame_parms->nb_antennas_rx + aarx].r) & 0xffff);
            //printf("symb %d chan_est_avg [%d] = %d\n", symbol, aatx*frame_parms->nb_antennas_rx + aarx, chan_est_avg[aatx*frame_parms->nb_antennas_rx + aarx]);
            dl_ch128 = (__m128i *)&dl_ch_estimates_ext[aatx * frame_parms->nb_antennas_rx + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                dl_ch128[0] = _mm_set1_epi32(chan_est_avg[aatx * frame_parms->nb_antennas_rx + aarx]);
                dl_ch128[1] = _mm_set1_epi32(chan_est_avg[aatx * frame_parms->nb_antennas_rx + aarx]);

                if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
                {
                    dl_ch128 += 2;
                }
                else
                {
                    dl_ch128[2] = _mm_set1_epi32(chan_est_avg[aatx * frame_parms->nb_antennas_rx + aarx]);
                    dl_ch128 += 3;
                }
            }
        }
    }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
#endif
}

void rxdataF_to_float(int32_t **rxdataF_ext,
                      float complex **rxdataF_f,
                      int n_rx,
                      int length,
                      int start_point)
{
    short re;
    int aarx;
    int16_t imag;
    int16_t real;

    for(aarx = 0; aarx < n_rx; aarx++)
    {
        for(re = 0; re < length; re++)
        {
            imag = (int16_t)(rxdataF_ext[aarx][start_point + re] >> 16);
            real = (int16_t)(rxdataF_ext[aarx][start_point + re] & 0xffff);
            rxdataF_f[aarx][re] = (float)(real / (32768.0)) + I * (float)(imag / (32768.0));
#ifdef DEBUG_MMSE

            if(re == 0)
            {
                printf("rxdataF_to_float: aarx = %d, real= %d, imag = %d\n", aarx, real, imag);
                //printf("rxdataF_to_float: rxdataF_ext[%d][%d] = %d\n", aarx, start_point + re, rxdataF_ext[aarx][start_point + re]);
                //printf("rxdataF_to_float: ant %d, re = %d, rxdataF_f real = %f, rxdataF_f imag = %f \n", aarx, re, creal(rxdataF_f[aarx][re]), cimag(rxdataF_f[aarx][re]));
            }

#endif
        }
    }
}

void chan_est_to_float(int32_t **dl_ch_estimates_ext,
                       float complex **dl_ch_estimates_ext_f,
                       int n_tx,
                       int n_rx,
                       int length,
                       int start_point)
{
    short re;
    int aatx, aarx;
    int16_t imag;
    int16_t real;

    for(aatx = 0; aatx < n_tx; aatx++)
    {
        for(aarx = 0; aarx < n_rx; aarx++)
        {
            for(re = 0; re < length; re++)
            {
                imag = (int16_t)(dl_ch_estimates_ext[aatx * n_rx + aarx][start_point + re] >> 16);
                real = (int16_t)(dl_ch_estimates_ext[aatx * n_rx + aarx][start_point + re] & 0xffff);
                dl_ch_estimates_ext_f[aatx * n_rx + aarx][re] = (float)(real / (32768.0)) + I * (float)(imag / (32768.0));
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf("ant %d, re = %d, real = %d, imag = %d \n", aatx * n_rx + aarx, re, real, imag);
                    printf("ant %d, re = %d, real = %f, imag = %f \n", aatx * n_rx + aarx, re, creal(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]), cimag(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]));
                }

#endif
            }
        }
    }
}

void float_to_chan_est(int32_t **dl_ch_estimates_ext,
                       float complex **dl_ch_estimates_ext_f,
                       int n_tx,
                       int n_rx,
                       int length,
                       int start_point)
{
    short re;
    int aarx, aatx;
    int16_t imag;
    int16_t real;

    for(aatx = 0; aatx < n_tx; aatx++)
    {
        for(aarx = 0; aarx < n_rx; aarx++)
        {
            for(re = 0; re < length; re++)
            {
                if(cimag(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]) < -1)
                {
                    imag = 0x8000;
                }
                else if(cimag(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]) >= 1)
                {
                    imag = 0x7FFF;
                }
                else
                {
                    imag = cimag(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]) * 32768;
                }

                if(creal(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]) < -1)
                {
                    real = 0x8000;
                }
                else if(creal(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]) >= 1)
                {
                    real = 0x7FFF;
                }
                else
                {
                    real = creal(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]) * 32768;
                }

                dl_ch_estimates_ext[aatx * n_rx + aarx][start_point + re] = (((int32_t)imag) << 16) | ((int32_t)real & 0xffff);
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf(" float_to_chan_est: chan est real = %f, chan est imag = %f\n", creal(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]), cimag(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]));
                    printf("float_to_chan_est: real fixed = %d, imag fixed = %d\n", real, imag);
                    printf("float_to_chan_est: ant %d, re = %d, dl_ch_estimates_ext = %d \n", aatx * n_rx + aarx, re,  dl_ch_estimates_ext[aatx * n_rx + aarx][start_point + re]);
                }

#endif
            }
        }
    }
}

void float_to_rxdataF(int32_t **rxdataF_ext,
                      float complex **rxdataF_f,
                      int n_tx,
                      int n_rx,
                      int length,
                      int start_point)
{
    short re;
    int aarx;
    int16_t imag;
    int16_t real;

    for(aarx = 0; aarx < n_rx; aarx++)
    {
        for(re = 0; re < length; re++)
        {
            if(cimag(rxdataF_f[aarx][re]) < -1)
            {
                imag = 0x8000;
            }
            else if(cimag(rxdataF_f[aarx][re]) >= 1)
            {
                imag = 0x7FFF;
            }
            else
            {
                imag = cimag(rxdataF_f[aarx][re]) * 32768;
            }

            if(creal(rxdataF_f[aarx][re]) < -1)
            {
                real = 0x8000;
            }
            else if(creal(rxdataF_f[aarx][re]) >= 1)
            {
                real = 0x7FFF;
            }
            else
            {
                real = creal(rxdataF_f[aarx][re]) * 32768;
            }

            rxdataF_ext[aarx][start_point + re] = (((int32_t)imag) << 16) | (((int32_t)real) & 0xffff);
#ifdef DEBUG_MMSE

            if(re == 0)
            {
                printf(" float_to_rxdataF: real = %f, imag = %f\n", creal(rxdataF_f[aarx][re]), cimag(rxdataF_f[aarx][re]));
                printf("float_to_rxdataF: real fixed = %d, imag fixed = %d\n", real, imag);
                printf("float_to_rxdataF: ant %d, re = %d, rxdataF_ext = %d \n", aarx, re,  rxdataF_ext[aarx][start_point + re]);
            }

#endif
        }
    }
}

void mult_mmse_rxdataF(float complex **Wmmse,
                       float complex **rxdataF_ext_f,
                       int n_tx,
                       int n_rx,
                       int length,
                       int start_point)
{
    short re;
    int aarx, aatx;
    float complex *rxdata_re =  malloc(n_rx * sizeof(float complex));
    float complex *rxdata_mmse_re =  malloc(n_rx * sizeof(float complex));
    float complex *Wmmse_re =  malloc(n_tx * n_rx * sizeof(float complex));

    for(re = 0; re < length; re++)
    {
        for(aarx = 0; aarx < n_rx; aarx++)
        {
            rxdata_re[aarx] = rxdataF_ext_f[aarx][re];
#ifdef DEBUG_MMSE

            if(re == 0)
            {
                printf("mult_mmse_rxdataF before: rxdata_re[%d] = (%f, %f)\n", aarx, creal(rxdata_re[aarx]), cimag(rxdata_re[aarx]));
            }

#endif
        }

        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                Wmmse_re[aatx * n_rx + aarx] = Wmmse[aatx * n_rx + aarx][re];
            }
        }

        mutl_matrix_matrix_col_based(Wmmse_re, rxdata_re, n_rx, n_tx, n_rx, 1, rxdata_mmse_re);

        for(aarx = 0; aarx < n_rx; aarx++)
        {
            rxdataF_ext_f[aarx][re] = rxdata_mmse_re[aarx];
#ifdef DEBUG_MMSE

            if(re == 0)
            {
                printf("mult_mmse_rxdataF after: rxdataF_ext_f[%d] = (%f, %f)\n", aarx, creal(rxdataF_ext_f[aarx][re]), cimag(rxdataF_ext_f[aarx][re]));
            }

#endif
        }
    }

    free(rxdata_re);
    free(rxdata_mmse_re);
    free(Wmmse_re);
}

void mult_mmse_chan_est(float complex **Wmmse,
                        float complex **dl_ch_estimates_ext_f,
                        int n_tx,
                        int n_rx,
                        int length,
                        int start_point)
{
    short re;
    int aarx, aatx;
    float complex *chan_est_re =  malloc(n_tx * n_rx * sizeof(float complex));
    float complex *chan_est_mmse_re =  malloc(n_tx * n_rx * sizeof(float complex));
    float complex *Wmmse_re =  malloc(n_tx * n_rx * sizeof(float complex));

    for(re = 0; re < length; re++)
    {
        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                chan_est_re[aatx * n_rx + aarx] = dl_ch_estimates_ext_f[aatx * n_rx + aarx][re];
                Wmmse_re[aatx * n_rx + aarx] = Wmmse[aatx * n_rx + aarx][re];
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf("mult_mmse_chan_est: chan_est_re[%d] = (%f, %f)\n", aatx * n_rx + aarx, creal(chan_est_re[aatx * n_rx + aarx]), cimag(chan_est_re[aatx * n_rx + aarx]));
                }

#endif
            }
        }

        mutl_matrix_matrix_col_based(Wmmse_re, chan_est_re, n_rx, n_tx, n_rx, n_tx, chan_est_mmse_re);

        for(aatx = 0; aatx < n_tx; aatx++)
        {
            for(aarx = 0; aarx < n_rx; aarx++)
            {
                dl_ch_estimates_ext_f[aatx * n_rx + aarx][re] = chan_est_mmse_re[aatx * n_rx + aarx];
#ifdef DEBUG_MMSE

                if(re == 0)
                {
                    printf("mult_mmse_chan_est: dl_ch_estimates_ext_f[%d][%d] = (%f, %f)\n", aatx * n_rx + aarx, re, creal(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]), cimag(dl_ch_estimates_ext_f[aatx * n_rx + aarx][re]));
                }

#endif
            }
        }
    }

    free(Wmmse_re);
    free(chan_est_re);
    free(chan_est_mmse_re);
}

//compute average channel_level of effective (precoded) channel
void dlsch_channel_level_TM34(int **dl_ch_estimates_ext,
                              LTE_DL_FRAME_PARMS *frame_parms,
                              unsigned char *pmi_ext,
                              int *avg_0,
                              int *avg_1,
                              uint8_t symbol,
                              unsigned short nb_rb,
                              unsigned int mmse_flag,
                              MIMO_mode_t mimo_mode)
{
#if defined(__x86_64__)||defined(__i386__)
    short rb;
    unsigned char aarx, nre = 12, symbol_mod;
    __m128i *dl_ch0_128, *dl_ch1_128, dl_ch0_128_tmp, dl_ch1_128_tmp, avg_0_128D, avg_1_128D;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;
    //clear average level
    // avg_0_128D = _mm_setzero_si128();
    // avg_1_128D = _mm_setzero_si128();
    avg_0[0] = 0;
    avg_0[1] = 0;
    avg_1[0] = 0;
    avg_1[1] = 0;
    // 5 is always a symbol with no pilots for both normal and extended prefix

    if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
    {
        nre = 8;
    }
    else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB == 1))
    {
        nre = 10;
    }
    else
    {
        nre = 12;
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128 = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128 = (__m128i *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];
        avg_0_128D = _mm_setzero_si128();
        avg_1_128D = _mm_setzero_si128();

        for(rb = 0; rb < nb_rb; rb++)
        {
            // printf("rb %d : \n",rb);
            //print_shorts("ch0\n",&dl_ch0_128[0]);
            //print_shorts("ch1\n",&dl_ch1_128[0]);
            dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[0]);
            dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[0]);

            if(mmse_flag == 0)
            {
                if(mimo_mode == LARGE_CDD)
                {
                    prec2A_TM3_128(&dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODING1)
                {
                    prec2A_TM4_128(0, &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODINGj)
                {
                    prec2A_TM4_128(1, &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
                else if(mimo_mode == DUALSTREAM_PUSCH_PRECODING)
                {
                    prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
            }

            //      mmtmpD0 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
            avg_0_128D = _mm_add_epi32(avg_0_128D, _mm_madd_epi16(dl_ch0_128_tmp, dl_ch0_128_tmp));
            avg_1_128D = _mm_add_epi32(avg_1_128D, _mm_madd_epi16(dl_ch1_128_tmp, dl_ch1_128_tmp));
            dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[1]);
            dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[1]);

            if(mmse_flag == 0)
            {
                if(mimo_mode == LARGE_CDD)
                {
                    prec2A_TM3_128(&dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODING1)
                {
                    prec2A_TM4_128(0, &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
                else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODINGj)
                {
                    prec2A_TM4_128(1, &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
                else if(mimo_mode == DUALSTREAM_PUSCH_PRECODING)
                {
                    prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                }
            }

            //      mmtmpD1 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
            avg_0_128D = _mm_add_epi32(avg_0_128D, _mm_madd_epi16(dl_ch0_128_tmp, dl_ch0_128_tmp));
            avg_1_128D = _mm_add_epi32(avg_1_128D, _mm_madd_epi16(dl_ch1_128_tmp, dl_ch1_128_tmp));

            if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
            {
                dl_ch0_128 += 2;
                dl_ch1_128 += 2;
            }
            else
            {
                dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[2]);
                dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[2]);

                if(mmse_flag == 0)
                {
                    if(mimo_mode == LARGE_CDD)
                    {
                        prec2A_TM3_128(&dl_ch0_128_tmp, &dl_ch1_128_tmp);
                    }
                    else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODING1)
                    {
                        prec2A_TM4_128(0, &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                    }
                    else if(mimo_mode == DUALSTREAM_UNIFORM_PRECODINGj)
                    {
                        prec2A_TM4_128(1, &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                    }
                    else if(mimo_mode == DUALSTREAM_PUSCH_PRECODING)
                    {
                        prec2A_TM4_128(pmi_ext[rb], &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                    }
                }

                //      mmtmpD2 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
                avg_1_128D = _mm_add_epi32(avg_1_128D, _mm_madd_epi16(dl_ch1_128_tmp, dl_ch1_128_tmp));
                avg_0_128D = _mm_add_epi32(avg_0_128D, _mm_madd_epi16(dl_ch0_128_tmp, dl_ch0_128_tmp));
                dl_ch0_128 += 3;
                dl_ch1_128 += 3;
            }
        }

        avg_0[aarx] = (((int *)&avg_0_128D)[0]) / (nb_rb * nre) +
                      (((int *)&avg_0_128D)[1]) / (nb_rb * nre) +
                      (((int *)&avg_0_128D)[2]) / (nb_rb * nre) +
                      (((int *)&avg_0_128D)[3]) / (nb_rb * nre);
        //  printf("From Chan_level aver stream 0 %d =%d\n", aarx, avg_0[aarx]);
        avg_1[aarx] = (((int *)&avg_1_128D)[0]) / (nb_rb * nre) +
                      (((int *)&avg_1_128D)[1]) / (nb_rb * nre) +
                      (((int *)&avg_1_128D)[2]) / (nb_rb * nre) +
                      (((int *)&avg_1_128D)[3]) / (nb_rb * nre);
        //    printf("From Chan_level aver stream 1 %d =%d\n", aarx, avg_1[aarx]);
    }

    //avg_0[0] = max(avg_0[0],avg_0[1]);
    //avg_1[0] = max(avg_1[0],avg_1[1]);
    //avg_0[0]= max(avg_0[0], avg_1[0]);
    avg_0[0] = avg_0[0] + avg_0[1];
    // printf("From Chan_level aver stream 0 final =%d\n", avg_0[0]);
    avg_1[0] = avg_1[0] + avg_1[1];
    // printf("From Chan_level aver stream 1 final =%d\n", avg_1[0]);
    avg_0[0] = min(avg_0[0], avg_1[0]);
    avg_1[0] = avg_0[0];
    _mm_empty();
    _m_empty();
#elif defined(__arm__)
#endif
}

//compute average channel_level of effective (precoded) channel
void dlsch_channel_level_TM56(int **dl_ch_estimates_ext,
                              LTE_DL_FRAME_PARMS *frame_parms,
                              unsigned char *pmi_ext,
                              int *avg,
                              uint8_t symbol,
                              unsigned short nb_rb)
{
#if defined(__x86_64__)||defined(__i386__)
    short rb;
    unsigned char aarx, nre = 12, symbol_mod;
    __m128i *dl_ch0_128, *dl_ch1_128, dl_ch0_128_tmp, dl_ch1_128_tmp, avg128D;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;
    //clear average level
    avg128D = _mm_setzero_si128();
    avg[0] = 0;
    avg[1] = 0;
    // 5 is always a symbol with no pilots for both normal and extended prefix

    if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
    {
        nre = 8;
    }
    else if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB == 1))
    {
        nre = 10;
    }
    else
    {
        nre = 12;
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        dl_ch0_128 = (__m128i *)&dl_ch_estimates_ext[aarx][symbol * frame_parms->N_RB_DL * 12];
        dl_ch1_128 = (__m128i *)&dl_ch_estimates_ext[2 + aarx][symbol * frame_parms->N_RB_DL * 12];

        for(rb = 0; rb < nb_rb; rb++)
        {
            dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[0]);
            dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[0]);
            prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128_tmp, &dl_ch1_128_tmp);
            //      mmtmpD0 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
            avg128D = _mm_add_epi32(avg128D, _mm_madd_epi16(dl_ch0_128_tmp, dl_ch0_128_tmp));
            dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[1]);
            dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[1]);
            prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128_tmp, &dl_ch1_128_tmp);
            //      mmtmpD1 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
            avg128D = _mm_add_epi32(avg128D, _mm_madd_epi16(dl_ch0_128_tmp, dl_ch0_128_tmp));

            if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
            {
                dl_ch0_128 += 2;
                dl_ch1_128 += 2;
            }
            else
            {
                dl_ch0_128_tmp = _mm_load_si128(&dl_ch0_128[2]);
                dl_ch1_128_tmp = _mm_load_si128(&dl_ch1_128[2]);
                prec2A_TM56_128(pmi_ext[rb], &dl_ch0_128_tmp, &dl_ch1_128_tmp);
                //      mmtmpD2 = _mm_madd_epi16(dl_ch0_128_tmp,dl_ch0_128_tmp);
                avg128D = _mm_add_epi32(avg128D, _mm_madd_epi16(dl_ch0_128_tmp, dl_ch0_128_tmp));
                dl_ch0_128 += 3;
                dl_ch1_128 += 3;
            }
        }

        avg[aarx] = (((int *)&avg128D)[0]) / (nb_rb * nre) +
                    (((int *)&avg128D)[1]) / (nb_rb * nre) +
                    (((int *)&avg128D)[2]) / (nb_rb * nre) +
                    (((int *)&avg128D)[3]) / (nb_rb * nre);
    }

    // choose maximum of the 2 effective channels
    avg[0] = cmax(avg[0], avg[1]);
    _mm_empty();
    _m_empty();
#elif defined(__arm__)
#endif
}

//compute average channel_level for TM7
void dlsch_channel_level_TM7(int **dl_bf_ch_estimates_ext,
                             LTE_DL_FRAME_PARMS *frame_parms,
                             int *avg,
                             uint8_t symbol,
                             unsigned short nb_rb)
{
#if defined(__x86_64__)||defined(__i386__)
    short rb;
    unsigned char aatx, aarx, nre = 12, symbol_mod;
    __m128i *dl_ch128, avg128D;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;

    for(aatx = 0; aatx < frame_parms->nb_antenna_ports_eNB; aatx++)
        for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
        {
            //clear average level
            avg128D = _mm_setzero_si128();
            // 5 is always a symbol with no pilots for both normal and extended prefix
            dl_ch128 = (__m128i *)&dl_bf_ch_estimates_ext[(aatx << 1) + aarx][symbol * frame_parms->N_RB_DL * 12];

            for(rb = 0; rb < nb_rb; rb++)
            {
                //  printf("rb %d : ",rb);
                //  print_shorts("ch",&dl_ch128[0]);
                avg128D = _mm_add_epi32(avg128D, _mm_madd_epi16(dl_ch128[0], dl_ch128[0]));
                avg128D = _mm_add_epi32(avg128D, _mm_madd_epi16(dl_ch128[1], dl_ch128[1]));

                if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))) && (frame_parms->nb_antenna_ports_eNB != 1))
                {
                    dl_ch128 += 2;
                }
                else
                {
                    avg128D = _mm_add_epi32(avg128D, _mm_madd_epi16(dl_ch128[2], dl_ch128[2]));
                    dl_ch128 += 3;
                }

                /*
                    if (rb==0) {
                    print_shorts("dl_ch128",&dl_ch128[0]);
                    print_shorts("dl_ch128",&dl_ch128[1]);
                    print_shorts("dl_ch128",&dl_ch128[2]);
                    }
                */
            }

            if(((symbol_mod == 0) || (symbol_mod == (frame_parms->Ncp - 1))))
            {
                nre = 10;
            }
            else if((frame_parms->Ncp == 0) && (symbol == 3 || symbol == 6 || symbol == 9 || symbol == 12))
            {
                nre = 9;
            }
            else if((frame_parms->Ncp == 1) && (symbol == 4 || symbol == 7 || symbol == 9))
            {
                nre = 8;
            }
            else
            {
                nre = 12;
            }

            avg[(aatx << 1) + aarx] = (((int *)&avg128D)[0] +
                                       ((int *)&avg128D)[1] +
                                       ((int *)&avg128D)[2] +
                                       ((int *)&avg128D)[3]) / (nb_rb * nre);
            //            printf("Channel level : %d\n",avg[(aatx<<1)+aarx]);
        }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
#endif
}
//#define ONE_OVER_2_Q15 16384
void dlsch_alamouti(LTE_DL_FRAME_PARMS *frame_parms,
                    int **rxdataF_comp,
                    int **dl_ch_mag,
                    int **dl_ch_magb,
                    unsigned char symbol,
                    unsigned short nb_rb)
{
#if defined(__x86_64__)||defined(__i386__)
    short *rxF0, *rxF1;
    __m128i *ch_mag0, *ch_mag1, *ch_mag0b, *ch_mag1b, *rxF0_128;
    unsigned char rb, re;
    int jj = (symbol * frame_parms->N_RB_DL * 12);
    uint8_t symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;
    uint8_t pilots = ((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp))) ? 1 : 0;
    rxF0_128 = (__m128i *) &rxdataF_comp[0][jj];
    //amp = _mm_set1_epi16(ONE_OVER_2_Q15);
    //    printf("Doing alamouti!\n");
    rxF0     = (short *)&rxdataF_comp[0][jj]; //tx antenna 0  h0*y
    rxF1     = (short *)&rxdataF_comp[2][jj]; //tx antenna 1  h1*y
    ch_mag0 = (__m128i *)&dl_ch_mag[0][jj];
    ch_mag1 = (__m128i *)&dl_ch_mag[2][jj];
    ch_mag0b = (__m128i *)&dl_ch_magb[0][jj];
    ch_mag1b = (__m128i *)&dl_ch_magb[2][jj];

    for(rb = 0; rb < nb_rb; rb++)
    {
        for(re = 0; re < ((pilots == 0) ? 12 : 8); re += 2)
        {
            // Alamouti RX combining
            //      printf("Alamouti: symbol %d, rb %d, re %d: rxF0 (%d,%d,%d,%d), rxF1 (%d,%d,%d,%d)\n",symbol,rb,re,rxF0[0],rxF0[1],rxF0[2],rxF0[3],rxF1[0],rxF1[1],rxF1[2],rxF1[3]);
            rxF0[0] = rxF0[0] + rxF1[2];
            rxF0[1] = rxF0[1] - rxF1[3];
            rxF0[2] = rxF0[2] - rxF1[0];
            rxF0[3] = rxF0[3] + rxF1[1];
            //      printf("Alamouti: rxF0 after (%d,%d,%d,%d)\n",rxF0[0],rxF0[1],rxF0[2],rxF0[3]);
            rxF0 += 4;
            rxF1 += 4;
        }

        // compute levels for 16QAM or 64 QAM llr unit
        ch_mag0[0] = _mm_adds_epi16(ch_mag0[0], ch_mag1[0]);
        ch_mag0[1] = _mm_adds_epi16(ch_mag0[1], ch_mag1[1]);
        ch_mag0b[0] = _mm_adds_epi16(ch_mag0b[0], ch_mag1b[0]);
        ch_mag0b[1] = _mm_adds_epi16(ch_mag0b[1], ch_mag1b[1]);

        // account for 1/sqrt(2) scaling at transmission
        //ch_mag0[0] = _mm_srai_epi16(ch_mag0[0],1);
        //ch_mag0[1] = _mm_srai_epi16(ch_mag0[1],1);
        //ch_mag0b[0] = _mm_srai_epi16(ch_mag0b[0],1);
        //ch_mag0b[1] = _mm_srai_epi16(ch_mag0b[1],1);

        //rxF0_128[0] = _mm_mulhi_epi16(rxF0_128[0],amp);
        //rxF0_128[0] = _mm_slli_epi16(rxF0_128[0],1);
        //rxF0_128[1] = _mm_mulhi_epi16(rxF0_128[1],amp);
        //rxF0_128[1] = _mm_slli_epi16(rxF0_128[1],1);

        //rxF0_128[0] = _mm_srai_epi16(rxF0_128[0],1);
        //rxF0_128[1] = _mm_srai_epi16(rxF0_128[1],1);

        if(pilots == 0)
        {
            ch_mag0[2] = _mm_adds_epi16(ch_mag0[2], ch_mag1[2]);
            ch_mag0b[2] = _mm_adds_epi16(ch_mag0b[2], ch_mag1b[2]);
            //ch_mag0[2] = _mm_srai_epi16(ch_mag0[2],1);
            //ch_mag0b[2] = _mm_srai_epi16(ch_mag0b[2],1);
            //rxF0_128[2] = _mm_mulhi_epi16(rxF0_128[2],amp);
            //rxF0_128[2] = _mm_slli_epi16(rxF0_128[2],1);
            //rxF0_128[2] = _mm_srai_epi16(rxF0_128[2],1);
            ch_mag0 += 3;
            ch_mag1 += 3;
            ch_mag0b += 3;
            ch_mag1b += 3;
            rxF0_128 += 3;
        }
        else
        {
            ch_mag0 += 2;
            ch_mag1 += 2;
            ch_mag0b += 2;
            ch_mag1b += 2;
            rxF0_128 += 2;
        }
    }

    _mm_empty();
    _m_empty();
#elif defined(__arm__)
#endif
}

//==============================================================================================
// Extraction functions
//==============================================================================================

unsigned short dlsch_extract_rbs_single(int **rxdataF,
                                        int **dl_ch_estimates,
                                        int **rxdataF_ext,
                                        int **dl_ch_estimates_ext,
                                        unsigned short pmi,
                                        unsigned char *pmi_ext,
                                        unsigned int *rb_alloc,
                                        unsigned char symbol,
                                        unsigned char subframe,
                                        uint32_t high_speed_flag,
                                        LTE_DL_FRAME_PARMS *frame_parms)
{
    unsigned short rb, nb_rb = 0;
    unsigned char rb_alloc_ind;
    unsigned char i, aarx, l, nsymb, skip_half = 0, sss_symb, pss_symb = 0;
    int *dl_ch0, *dl_ch0_ext, *rxF, *rxF_ext;
    unsigned char symbol_mod, pilots = 0, j = 0, poffset = 0;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;
    pilots = ((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp))) ? 1 : 0;
    l = symbol;
    nsymb = (frame_parms->Ncp == NORMAL) ? 14 : 12;

    if(frame_parms->frame_type == TDD)     // TDD
    {
        sss_symb = nsymb - 1;
        pss_symb = 2;
    }
    else
    {
        sss_symb = (nsymb >> 1) - 2;
        pss_symb = (nsymb >> 1) - 1;
    }

    if(symbol_mod == (4 - frame_parms->Ncp))
    {
        poffset = 3;
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        if(high_speed_flag == 1)
        {
            dl_ch0     = &dl_ch_estimates[aarx][5 + (symbol * (frame_parms->ofdm_symbol_size))];
        }
        else
        {
            dl_ch0     = &dl_ch_estimates[aarx][5];
        }

        dl_ch0_ext = &dl_ch_estimates_ext[aarx][symbol * (frame_parms->N_RB_DL * 12)];
        rxF_ext   = &rxdataF_ext[aarx][symbol * (frame_parms->N_RB_DL * 12)];
        rxF       = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol * (frame_parms->ofdm_symbol_size)))];

        if((frame_parms->N_RB_DL & 1) == 0) // even number of RBs
            for(rb = 0; rb < frame_parms->N_RB_DL; rb++)
            {
                if(rb < 32)
                {
                    rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
                }
                else if(rb < 64)
                {
                    rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
                }
                else if(rb < 96)
                {
                    rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
                }
                else if(rb < 100)
                {
                    rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
                }
                else
                {
                    rb_alloc_ind = 0;
                }

                if(rb_alloc_ind == 1)
                {
                    nb_rb++;
                }

                // For second half of RBs skip DC carrier
                if(rb == (frame_parms->N_RB_DL >> 1))
                {
                    rxF       = &rxdataF[aarx][(1 + (symbol * (frame_parms->ofdm_symbol_size)))];
                    //dl_ch0++;
                }

                // PBCH
                if((subframe == 0) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= nsymb >> 1) && (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                }

                if(frame_parms->frame_type == FDD)
                {
                    //PSS
                    if(((subframe == 0) || (subframe == 5)) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }
                }

                if((frame_parms->frame_type == TDD) &&
                        (subframe == 6)) //TDD Subframe 6
                {
                    if((rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }
                }

                if(rb_alloc_ind == 1)
                {
                    *pmi_ext = (pmi >> ((rb >> 2) << 1)) & 3;
                    memcpy(dl_ch0_ext, dl_ch0, 12 * sizeof(int));

                    /*
                        printf("rb %d\n",rb);
                        for (i=0;i<12;i++)
                        printf("(%d %d)",((short *)dl_ch0)[i<<1],((short*)dl_ch0)[1+(i<<1)]);
                        printf("\n");
                    */
                    if(pilots == 0)
                    {
                        for(i = 0; i < 12; i++)
                        {
                            rxF_ext[i] = rxF[i];
                            /*
                                printf("%d : (%d,%d)\n",(rxF+i-&rxdataF[aarx][( (symbol*(frame_parms->ofdm_symbol_size)))]),
                                ((short*)&rxF[i])[0],((short*)&rxF[i])[1]);*/
                        }

                        dl_ch0_ext += 12;
                        rxF_ext += 12;
                    }
                    else
                    {
                        j = 0;

                        for(i = 0; i < 12; i++)
                        {
                            if((i != (frame_parms->nushift + poffset)) &&
                                    (i != ((frame_parms->nushift + poffset + 6) % 12)))
                            {
                                rxF_ext[j] = rxF[i];
                                //            printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j]));
                                dl_ch0_ext[j++] = dl_ch0[i];
                            }
                        }

                        dl_ch0_ext += 10;
                        rxF_ext += 10;
                    }
                }

                dl_ch0 += 12;
                rxF += 12;
            }
        else     // Odd number of RBs
        {
            for(rb = 0; rb < frame_parms->N_RB_DL >> 1; rb++)
            {
#ifdef DEBUG_DLSCH_DEMOD
                printf("dlch_ext %u\n", dl_ch0_ext - &dl_ch_estimates_ext[aarx][0]);
#endif
                skip_half = 0;

                if(rb < 32)
                {
                    rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
                }
                else if(rb < 64)
                {
                    rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
                }
                else if(rb < 96)
                {
                    rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
                }
                else if(rb < 100)
                {
                    rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
                }
                else
                {
                    rb_alloc_ind = 0;
                }

                if(rb_alloc_ind == 1)
                {
                    nb_rb++;
                }

                // PBCH
                if((subframe == 0) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                }

                //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3
                if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 1;
                }
                else if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 2;
                }

                //SSS

                if(((subframe == 0) || (subframe == 5)) &&
                        (rb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (rb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) &&
                        (rb == ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (l == sss_symb))
                {
                    skip_half = 1;
                }
                else if(((subframe == 0) || (subframe == 5)) &&
                        (rb == ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l == sss_symb))
                {
                    skip_half = 2;
                }

                //PSS in subframe 0/5 if FDD
                if(frame_parms->frame_type == FDD)     //FDD
                {
                    if(((subframe == 0) || (subframe == 5)) &&
                            (rb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (rb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if((frame_parms->frame_type == TDD) &&
                        (subframe == 6)) //TDD Subframe 6
                {
                    if((rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if((rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if((rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if(rb_alloc_ind == 1)
                {
#ifdef DEBUG_DLSCH_DEMOD
                    printf("rb %d/symbol %d (skip_half %d)\n", rb, l, skip_half);
#endif

                    if(pilots == 0)
                    {
                        //      printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        if(skip_half == 1)
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else if(skip_half == 2)
                        {
                            memcpy(dl_ch0_ext, dl_ch0 + 6, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[(i + 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 12 * sizeof(int));

                            for(i = 0; i < 12; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 12;
                            rxF_ext += 12;
                        }
                    }
                    else
                    {
                        //      printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        j = 0;

                        if(skip_half == 1)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }

                            rxF_ext += 5;
                            dl_ch0_ext += 5;
                        }
                        else if(skip_half == 2)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[(i + 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i + 6];
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else
                        {
                            for(i = 0; i < 12; i++)
                            {
                                if((i != (frame_parms->nushift + poffset)) &&
                                        (i != ((frame_parms->nushift + poffset + 6) % 12)))
                                {
                                    rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }

                            dl_ch0_ext += 10;
                            rxF_ext += 10;
                        }
                    }
                }

                dl_ch0 += 12;
                rxF += 12;
            } // first half loop

            // Do middle RB (around DC)
            if(rb < 32)
            {
                rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
            }
            else if(rb < 64)
            {
                rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
            }
            else if(rb < 96)
            {
                rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
            }
            else if(rb < 100)
            {
                rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
            }
            else
            {
                rb_alloc_ind = 0;
            }

            if(rb_alloc_ind == 1)
            {
                nb_rb++;
            }

            // PBCH

            if((subframe == 0) &&
                    (l >= (nsymb >> 1)) &&
                    (l < ((nsymb >> 1) + 4)))
            {
                rb_alloc_ind = 0;
            }

            //SSS
            if(((subframe == 0) || (subframe == 5)) && (l == sss_symb))
            {
                rb_alloc_ind = 0;
            }

            if(frame_parms->frame_type == FDD)
            {
                //PSS
                if(((subframe == 0) || (subframe == 5)) && (l == pss_symb))
                {
                    rb_alloc_ind = 0;
                }
            }

            //PSS
            if((frame_parms->frame_type == TDD) &&
                    (subframe == 6) &&
                    (l == pss_symb))
            {
                rb_alloc_ind = 0;
            }

            //  printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]);
            //      printf("DC rb %d (%p)\n",rb,rxF);
            if(rb_alloc_ind == 1)
            {
#ifdef DEBUG_DLSCH_DEMOD
                printf("rb %d/symbol %d (skip_half %d)\n", rb, l, skip_half);
#endif

                if(pilots == 0)
                {
                    for(i = 0; i < 6; i++)
                    {
                        dl_ch0_ext[i] = dl_ch0[i];
                        rxF_ext[i] = rxF[i];
                    }

                    rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];

                    for(; i < 12; i++)
                    {
                        dl_ch0_ext[i] = dl_ch0[i];
                        rxF_ext[i] = rxF[(1 + i - 6)];
                    }

                    dl_ch0_ext += 12;
                    rxF_ext += 12;
                }
                else     // pilots==1
                {
                    j = 0;

                    for(i = 0; i < 6; i++)
                    {
                        if(i != ((frame_parms->nushift + poffset) % 6))
                        {
                            dl_ch0_ext[j] = dl_ch0[i];
                            rxF_ext[j++] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                            printf("**extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j - 1], *(1 + (short *)&rxF_ext[j - 1]));
#endif
                        }
                    }

                    rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];

                    for(; i < 12; i++)
                    {
                        if(i != ((frame_parms->nushift + 6 + poffset) % 12))
                        {
                            dl_ch0_ext[j] = dl_ch0[i];
                            rxF_ext[j++] = rxF[(1 + i - 6)];
#ifdef DEBUG_DLSCH_DEMOD
                            printf("**extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j - 1], *(1 + (short *)&rxF_ext[j - 1]));
#endif
                        }
                    }

                    dl_ch0_ext += 10;
                    rxF_ext += 10;
                } // symbol_mod==0
            } // rballoc==1
            else
            {
                rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];
            }

            dl_ch0 += 12;
            rxF += 7;
            rb++;

            for(; rb < frame_parms->N_RB_DL; rb++)
            {
                //      printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]);
                //      printf("rb %d (%p)\n",rb,rxF);
                skip_half = 0;

                if(rb < 32)
                {
                    rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
                }
                else if(rb < 64)
                {
                    rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
                }
                else if(rb < 96)
                {
                    rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
                }
                else if(rb < 100)
                {
                    rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
                }
                else
                {
                    rb_alloc_ind = 0;
                }

                if(rb_alloc_ind == 1)
                {
                    nb_rb++;
                }

                // PBCH
                if((subframe == 0) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= nsymb >> 1) && (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                }

                //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3
                if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 1;
                }
                else if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 2;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == sss_symb))
                {
                    skip_half = 1;
                }
                else if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
                {
                    skip_half = 2;
                }

                if(frame_parms->frame_type == FDD)
                {
                    //PSS
                    if(((subframe == 0) || (subframe == 5)) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    //PSS

                    if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if((frame_parms->frame_type == TDD) &&
                        (subframe == 6)) //TDD Subframe 6
                {
                    if((rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if((rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if((rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if(rb_alloc_ind == 1)
                {
#ifdef DEBUG_DLSCH_DEMOD
                    printf("rb %d/symbol %d (skip_half %d)\n", rb, l, skip_half);
#endif

                    /*
                        printf("rb %d\n",rb);
                        for (i=0;i<12;i++)
                        printf("(%d %d)",((short *)dl_ch0)[i<<1],((short*)dl_ch0)[1+(i<<1)]);
                        printf("\n");
                    */
                    if(pilots == 0)
                    {
                        //      printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        if(skip_half == 1)
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else if(skip_half == 2)
                        {
                            memcpy(dl_ch0_ext, dl_ch0 + 6, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[(i + 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 12 * sizeof(int));

                            for(i = 0; i < 12; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 12;
                            rxF_ext += 12;
                        }
                    }
                    else
                    {
                        //      printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        j = 0;

                        if(skip_half == 1)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else if(skip_half == 2)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[(i + 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i + 6];
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else
                        {
                            for(i = 0; i < 12; i++)
                            {
                                if((i != (frame_parms->nushift + poffset)) &&
                                        (i != ((frame_parms->nushift + poffset + 6) % 12)))
                                {
                                    rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }

                            dl_ch0_ext += 10;
                            rxF_ext += 10;
                        }
                    } // pilots=0
                }

                dl_ch0 += 12;
                rxF += 12;
            }
        }
    }

    return(nb_rb / frame_parms->nb_antennas_rx);
}

unsigned short dlsch_extract_rbs_dual(int **rxdataF,
                                      int **dl_ch_estimates,
                                      int **rxdataF_ext,
                                      int **dl_ch_estimates_ext,
                                      unsigned short pmi,
                                      unsigned char *pmi_ext,
                                      unsigned int *rb_alloc,
                                      unsigned char symbol,
                                      unsigned char subframe,
                                      uint32_t high_speed_flag,
                                      LTE_DL_FRAME_PARMS *frame_parms,
                                      MIMO_mode_t mimo_mode)
{
    int prb, nb_rb = 0;
    int prb_off, prb_off2;
    int rb_alloc_ind, skip_half = 0, sss_symb, pss_symb = 0, nsymb, l;
    int i, aarx;
    int32_t *dl_ch0, *dl_ch0p, *dl_ch0_ext, *dl_ch1, *dl_ch1p, *dl_ch1_ext, *rxF, *rxF_ext;
    int symbol_mod, pilots = 0, j = 0;
    unsigned char *pmi_loc;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;
    //  printf("extract_rbs: symbol_mod %d\n",symbol_mod);

    if((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp)))
    {
        pilots = 1;
    }

    nsymb = (frame_parms->Ncp == NORMAL) ? 14 : 12;
    l = symbol;

    if(frame_parms->frame_type == TDD)     // TDD
    {
        sss_symb = nsymb - 1;
        pss_symb = 2;
    }
    else
    {
        sss_symb = (nsymb >> 1) - 2;
        pss_symb = (nsymb >> 1) - 1;
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        if(high_speed_flag == 1)
        {
            dl_ch0     = &dl_ch_estimates[aarx][5 + (symbol * (frame_parms->ofdm_symbol_size))];
            dl_ch1     = &dl_ch_estimates[2 + aarx][5 + (symbol * (frame_parms->ofdm_symbol_size))];
        }
        else
        {
            dl_ch0     = &dl_ch_estimates[aarx][5];
            dl_ch1     = &dl_ch_estimates[2 + aarx][5];
        }

        pmi_loc = pmi_ext;
        // pointers to extracted RX signals and channel estimates
        rxF_ext    = &rxdataF_ext[aarx][symbol * (frame_parms->N_RB_DL * 12)];
        dl_ch0_ext = &dl_ch_estimates_ext[aarx][symbol * (frame_parms->N_RB_DL * 12)];
        dl_ch1_ext = &dl_ch_estimates_ext[2 + aarx][symbol * (frame_parms->N_RB_DL * 12)];

        for(prb = 0; prb < frame_parms->N_RB_DL; prb++)
        {
            skip_half = 0;

            if(prb < 32)
            {
                rb_alloc_ind = (rb_alloc[0] >> prb) & 1;
            }
            else if(prb < 64)
            {
                rb_alloc_ind = (rb_alloc[1] >> (prb - 32)) & 1;
            }
            else if(prb < 96)
            {
                rb_alloc_ind = (rb_alloc[2] >> (prb - 64)) & 1;
            }
            else if(prb < 100)
            {
                rb_alloc_ind = (rb_alloc[3] >> (prb - 96)) & 1;
            }
            else
            {
                rb_alloc_ind = 0;
            }

            if(rb_alloc_ind == 1)
            {
                nb_rb++;
            }

            if((frame_parms->N_RB_DL & 1) == 0)   // even number of RBs
            {

                // PBCH
                if((subframe == 0) &&
                        (prb >= ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l >= (nsymb >> 1)) &&
                        (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                    //    printf("symbol %d / rb %d: skipping PBCH REs\n",symbol,prb);
                }

                //SSS

                if(((subframe == 0) || (subframe == 5)) &&
                        (prb >= ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                    //    printf("symbol %d / rb %d: skipping SSS REs\n",symbol,prb);
                }

                //PSS in subframe 0/5 if FDD
                if(frame_parms->frame_type == FDD)     //FDD
                {
                    if(((subframe == 0) || (subframe == 5)) &&
                            (prb >= ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                        //    printf("symbol %d / rb %d: skipping PSS REs\n",symbol,prb);
                    }
                }

                if((frame_parms->frame_type == TDD) &&
                        (subframe == 6)) //TDD Subframe 6
                {
                    if((prb >= ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }
                }

                if(rb_alloc_ind == 1)               // PRB is allocated
                {
                    prb_off      = 12 * prb;
                    prb_off2     = 1 + (12 * (prb - (frame_parms->N_RB_DL >> 1)));
                    dl_ch0p    = dl_ch0 + (12 * prb);
                    dl_ch1p    = dl_ch1 + (12 * prb);

                    if(prb < (frame_parms->N_RB_DL >> 1))
                    {
                        rxF      = &rxdataF[aarx][prb_off +
                                                  frame_parms->first_carrier_offset +
                                                  (symbol * (frame_parms->ofdm_symbol_size))];
                    }
                    else
                    {
                        rxF      = &rxdataF[aarx][prb_off2 +
                                                  (symbol * (frame_parms->ofdm_symbol_size))];
                    }

                    /*
                        if (mimo_mode <= PUSCH_PRECODING1)
                        pmi_loc = (pmi>>((prb>>2)<<1))&3;
                        else
                        pmi_loc=(pmi>>prb)&1;*/
                    *pmi_loc = get_pmi(frame_parms->N_RB_DL, mimo_mode, pmi, prb);
                    pmi_loc++;

                    if(pilots == 0)
                    {
                        memcpy(dl_ch0_ext, dl_ch0p, 12 * sizeof(int));
                        memcpy(dl_ch1_ext, dl_ch1p, 12 * sizeof(int));
                        memcpy(rxF_ext, rxF, 12 * sizeof(int));
                        dl_ch0_ext += 12;
                        dl_ch1_ext += 12;
                        rxF_ext    += 12;
                    }
                    else     // pilots==1
                    {
                        j = 0;

                        for(i = 0; i < 12; i++)
                        {
                            if((i != frame_parms->nushift) &&
                                    (i != frame_parms->nushift + 3) &&
                                    (i != frame_parms->nushift + 6) &&
                                    (i != ((frame_parms->nushift + 9) % 12)))
                            {
                                rxF_ext[j] = rxF[i];
                                //        printf("extract rb %d, re %d => (%d,%d)\n",rb,i,*(short *)&rxF_ext[j],*(1+(short*)&rxF_ext[j]));
                                dl_ch0_ext[j] = dl_ch0p[i];
                                dl_ch1_ext[j++] = dl_ch1p[i];
                            }
                        }

                        dl_ch0_ext += 8;
                        dl_ch1_ext += 8;
                        rxF_ext += 8;
                    } // pilots==1
                }
            }
            else      // Odd number of RBs
            {

                // PBCH
                if((subframe == 0) &&
                        (prb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l >= (nsymb >> 1)) &&
                        (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                    //    printf("symbol %d / rb %d: skipping PBCH REs\n",symbol,prb);
                }

                //SSS

                if(((subframe == 0) || (subframe == 5)) &&
                        (prb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                    //    printf("symbol %d / rb %d: skipping SSS REs\n",symbol,prb);
                }

                //PSS in subframe 0/5 if FDD
                if(frame_parms->frame_type == FDD)     //FDD
                {
                    if(((subframe == 0) || (subframe == 5)) &&
                            (prb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                        //    printf("symbol %d / rb %d: skipping PSS REs\n",symbol,prb);
                    }
                }

                if((frame_parms->frame_type == TDD) &&
                        ((subframe == 1) || (subframe == 6))) //TDD Subframe 1-6
                {
                    if((prb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (prb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }
                }

                if(rb_alloc_ind == 1)
                {
                    skip_half = 0;

                    //Check if we have to drop half a PRB due to PSS/SSS/PBCH
                    // skip_half == 0 means full PRB
                    // skip_half == 1 means first half is used (leftmost half-PRB from PSS/SSS/PBCH)
                    // skip_half == 2 means second half is used (rightmost half-PRB from PSS/SSS/PBCH)
                    //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3
                    if((subframe == 0) &&
                            (prb == ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (l >= (nsymb >> 1)) &&
                            (l < ((nsymb >> 1) + 4)))
                    {
                        skip_half = 1;
                    }
                    else if((subframe == 0) &&
                            (prb == ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l >= (nsymb >> 1)) &&
                            (l < ((nsymb >> 1) + 4)))
                    {
                        skip_half = 2;
                    }

                    //SSS
                    if(((subframe == 0) || (subframe == 5)) &&
                            (prb == ((frame_parms->N_RB_DL >> 1) - 3)) &&
                            (l == sss_symb))
                    {
                        skip_half = 1;
                    }
                    else if(((subframe == 0) || (subframe == 5)) &&
                            (prb == ((frame_parms->N_RB_DL >> 1) + 3)) &&
                            (l == sss_symb))
                    {
                        skip_half = 2;
                    }

                    //PSS Subframe 0,5
                    if(((frame_parms->frame_type == FDD) &&
                            (((subframe == 0) || (subframe == 5)))) || //FDD Subframes 0,5
                            ((frame_parms->frame_type == TDD) &&
                             (((subframe == 1) || (subframe == 6))))) //TDD Subframes 1,6
                    {
                        if((prb == ((frame_parms->N_RB_DL >> 1) - 3)) &&
                                (l == pss_symb))
                        {
                            skip_half = 1;
                        }
                        else if((prb == ((frame_parms->N_RB_DL >> 1) + 3)) &&
                                (l == pss_symb))
                        {
                            skip_half = 2;
                        }
                    }

                    prb_off      = 12 * prb;
                    prb_off2     = 7 + (12 * (prb - (frame_parms->N_RB_DL >> 1) - 1));
                    dl_ch0p      = dl_ch0 + (12 * prb);
                    dl_ch1p      = dl_ch1 + (12 * prb);

                    if(prb <= (frame_parms->N_RB_DL >> 1))
                    {
                        rxF      = &rxdataF[aarx][prb_off +
                                                  frame_parms->first_carrier_offset +
                                                  (symbol * (frame_parms->ofdm_symbol_size))];
                    }
                    else
                    {
                        rxF      = &rxdataF[aarx][prb_off2 +
                                                  (symbol * (frame_parms->ofdm_symbol_size))];
                    }

#ifdef DEBUG_DLSCH_DEMOD
                    printf("symbol %d / rb %d: alloc %d skip_half %d (rxF %p, rxF_ext %p) prb_off (%d,%d)\n", symbol, prb, rb_alloc_ind, skip_half, rxF, rxF_ext, prb_off, prb_off2);
#endif
                    /*  if (mimo_mode <= PUSCH_PRECODING1)
                        pmi_loc = (pmi>>((prb>>2)<<1))&3;
                        else
                        pmi_loc=(pmi>>prb)&1;
                        // printf("symbol_mod %d (pilots %d) rb %d, sb %d, pmi %d (pmi_loc %p,rxF %p, ch00 %p, ch01 %p, rxF_ext %p dl_ch0_ext %p dl_ch1_ext %p)\n",symbol_mod,pilots,prb,prb>>2,*pmi_loc,pmi_loc,rxF,dl_ch0, dl_ch1, rxF_ext,dl_ch0_ext,dl_ch1_ext);
                    */
                    *pmi_loc = get_pmi(frame_parms->N_RB_DL, mimo_mode, pmi, prb);
                    pmi_loc++;

                    if(prb != (frame_parms->N_RB_DL >> 1))  // This PRB is not around DC
                    {
                        if(pilots == 0)
                        {
                            if(skip_half == 1)
                            {
                                memcpy(dl_ch0_ext, dl_ch0p, 6 * sizeof(int32_t));
                                memcpy(dl_ch1_ext, dl_ch1p, 6 * sizeof(int32_t));
                                memcpy(rxF_ext, rxF, 6 * sizeof(int32_t));
#ifdef DEBUG_DLSCH_DEMOD

                                for(i = 0; i < 6; i++)
                                {
                                    printf("extract rb %d, re %d => (%d,%d)\n", prb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
                                }

#endif
                                dl_ch0_ext += 6;
                                dl_ch1_ext += 6;
                                rxF_ext += 6;
                            }
                            else if(skip_half == 2)
                            {
                                memcpy(dl_ch0_ext, dl_ch0p + 6, 6 * sizeof(int32_t));
                                memcpy(dl_ch1_ext, dl_ch1p + 6, 6 * sizeof(int32_t));
                                memcpy(rxF_ext, rxF + 6, 6 * sizeof(int32_t));
#ifdef DEBUG_DLSCH_DEMOD

                                for(i = 0; i < 6; i++)
                                {
                                    printf("extract rb %d, re %d => (%d,%d)\n", prb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
                                }

#endif
                                dl_ch0_ext += 6;
                                dl_ch1_ext += 6;
                                rxF_ext += 6;
                            }
                            else      // skip_half==0
                            {
                                memcpy(dl_ch0_ext, dl_ch0p, 12 * sizeof(int32_t));
                                memcpy(dl_ch1_ext, dl_ch1p, 12 * sizeof(int32_t));
                                memcpy(rxF_ext, rxF, 12 * sizeof(int32_t));
#ifdef DEBUG_DLSCH_DEMOD

                                for(i = 0; i < 12; i++)
                                {
                                    printf("extract rb %d, re %d => (%d,%d)\n", prb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
                                }

#endif
                                dl_ch0_ext += 12;
                                dl_ch1_ext += 12;
                                rxF_ext += 12;
                            }
                        }
                        else     // pilots=1
                        {
                            j = 0;

                            if(skip_half == 1)
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if((i != frame_parms->nushift) &&
                                            (i != ((frame_parms->nushift + 3) % 6)))
                                    {
                                        rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("(pilots,skip1)extract rb %d, re %d (%d)=> (%d,%d)\n", prb, i, j, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                        dl_ch0_ext[j] = dl_ch0p[i];
                                        dl_ch1_ext[j++] = dl_ch1p[i];
                                    }
                                }

                                dl_ch0_ext += 4;
                                dl_ch1_ext += 4;
                                rxF_ext += 4;
                            }
                            else if(skip_half == 2)
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if((i != frame_parms->nushift) &&
                                            (i != ((frame_parms->nushift + 3) % 6)))
                                    {
                                        rxF_ext[j] = rxF[(i + 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("(pilots,skip2)extract rb %d, re %d (%d) => (%d,%d)\n", prb, i, j, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                        dl_ch0_ext[j] = dl_ch0p[i + 6];
                                        dl_ch1_ext[j++] = dl_ch1p[i + 6];
                                    }
                                }

                                dl_ch0_ext += 4;
                                dl_ch1_ext += 4;
                                rxF_ext += 4;
                            }
                            else     //skip_half==0
                            {
                                for(i = 0; i < 12; i++)
                                {
                                    if((i != frame_parms->nushift) &&
                                            (i != frame_parms->nushift + 3) &&
                                            (i != frame_parms->nushift + 6) &&
                                            (i != ((frame_parms->nushift + 9) % 12)))
                                    {
                                        rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("(pilots)extract rb %d, re %d => (%d,%d)\n", prb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                        dl_ch0_ext[j]  = dl_ch0p[i];
                                        dl_ch1_ext[j++] = dl_ch1p[i];
                                    }
                                }

                                dl_ch0_ext += 8;
                                dl_ch1_ext += 8;
                                rxF_ext += 8;
                            } //skip_half==0
                        } //pilots==1
                    }
                    else           // Do middle RB (around DC)
                    {
                        if(pilots == 0)
                        {
                            memcpy(dl_ch0_ext, dl_ch0p, 6 * sizeof(int32_t));
                            memcpy(dl_ch1_ext, dl_ch1p, 6 * sizeof(int32_t));
                            memcpy(rxF_ext, rxF, 6 * sizeof(int32_t));
#ifdef DEBUG_DLSCH_DEMOD

                            for(i = 0; i < 6; i++)
                            {
                                printf("extract rb %d, re %d => (%d,%d)\n", prb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
                            }

#endif
                            rxF_ext += 6;
                            dl_ch0_ext += 6;
                            dl_ch1_ext += 6;
                            dl_ch0p += 6;
                            dl_ch1p += 6;
                            rxF       = &rxdataF[aarx][1 + ((symbol * (frame_parms->ofdm_symbol_size)))];
                            memcpy(dl_ch0_ext, dl_ch0p, 6 * sizeof(int32_t));
                            memcpy(dl_ch1_ext, dl_ch1p, 6 * sizeof(int32_t));
                            memcpy(rxF_ext, rxF, 6 * sizeof(int32_t));
#ifdef DEBUG_DLSCH_DEMOD

                            for(i = 0; i < 6; i++)
                            {
                                printf("extract rb %d, re %d => (%d,%d)\n", prb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
                            }

#endif
                            rxF_ext += 6;
                            dl_ch0_ext += 6;
                            dl_ch1_ext += 6;
                        }
                        else     // pilots==1
                        {
                            j = 0;

                            for(i = 0; i < 6; i++)
                            {
                                if((i != frame_parms->nushift) &&
                                        (i != ((frame_parms->nushift + 3) % 6)))
                                {
                                    dl_ch0_ext[j] = dl_ch0p[i];
                                    dl_ch1_ext[j] = dl_ch1p[i];
                                    rxF_ext[j++] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("(pilots)extract rb %d, re %d (%d) => (%d,%d)\n", prb, i, j, *(short *)&rxF[i], *(1 + (short *)&rxF[i]));
#endif
                                }
                            }

                            rxF       = &rxdataF[aarx][1 + symbol * (frame_parms->ofdm_symbol_size)];

                            for(; i < 12; i++)
                            {
                                if((i != ((frame_parms->nushift + 6) % 12)) &&
                                        (i != ((frame_parms->nushift + 9) % 12)))
                                {
                                    dl_ch0_ext[j] = dl_ch0p[i];
                                    dl_ch1_ext[j] = dl_ch1p[i];
                                    rxF_ext[j++] = rxF[i - 6];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("(pilots)extract rb %d, re %d (%d) => (%d,%d)\n", prb, i, j, *(short *)&rxF[1 + i - 6], *(1 + (short *)&rxF[1 + i - 6]));
#endif
                                }
                            }

                            dl_ch0_ext += 8;
                            dl_ch1_ext += 8;
                            rxF_ext += 8;
                        } //pilots==1
                    }  // if Middle PRB
                } // if odd PRB
            } // if rballoc==1
        } // for prb
    } // for aarx

    return(nb_rb / frame_parms->nb_antennas_rx);
}

unsigned short dlsch_extract_rbs_TM7(int **rxdataF,
                                     int **dl_bf_ch_estimates,
                                     int **rxdataF_ext,
                                     int **dl_bf_ch_estimates_ext,
                                     unsigned int *rb_alloc,
                                     unsigned char symbol,
                                     unsigned char subframe,
                                     uint32_t high_speed_flag,
                                     LTE_DL_FRAME_PARMS *frame_parms)
{
    unsigned short rb, nb_rb = 0;
    unsigned char rb_alloc_ind;
    unsigned char i, aarx, l, nsymb, skip_half = 0, sss_symb, pss_symb = 0;
    int *dl_ch0, *dl_ch0_ext, *rxF, *rxF_ext;
    unsigned char symbol_mod, pilots = 0, uespec_pilots = 0, j = 0, poffset = 0, uespec_poffset = 0;
    int8_t uespec_nushift = frame_parms->Nid_cell % 3;
    symbol_mod = (symbol >= (7 - frame_parms->Ncp)) ? symbol - (7 - frame_parms->Ncp) : symbol;
    pilots = ((symbol_mod == 0) || (symbol_mod == (4 - frame_parms->Ncp))) ? 1 : 0;
    l = symbol;
    nsymb = (frame_parms->Ncp == NORMAL) ? 14 : 12;

    if(frame_parms->Ncp == 0)
    {
        if(symbol == 3 || symbol == 6 || symbol == 9 || symbol == 12)
        {
            uespec_pilots = 1;
        }
    }
    else
    {
        if(symbol == 4 || symbol == 7 || symbol == 10)
        {
            uespec_pilots = 1;
        }
    }

    if(frame_parms->frame_type == TDD)   // TDD
    {
        sss_symb = nsymb - 1;
        pss_symb = 2;
    }
    else
    {
        sss_symb = (nsymb >> 1) - 2;
        pss_symb = (nsymb >> 1) - 1;
    }

    if(symbol_mod == (4 - frame_parms->Ncp))
    {
        poffset = 3;
    }

    if((frame_parms->Ncp == 0 && (symbol == 6 || symbol == 12)) || (frame_parms->Ncp == 1 && symbol == 7))
    {
        uespec_poffset = 2;
    }

    for(aarx = 0; aarx < frame_parms->nb_antennas_rx; aarx++)
    {
        if(high_speed_flag == 1)
        {
            dl_ch0     = &dl_bf_ch_estimates[aarx][symbol * (frame_parms->ofdm_symbol_size)];
        }
        else
        {
            dl_ch0     = &dl_bf_ch_estimates[aarx][0];
        }

        dl_ch0_ext = &dl_bf_ch_estimates_ext[aarx][symbol * (frame_parms->N_RB_DL * 12)];
        rxF_ext    = &rxdataF_ext[aarx][symbol * (frame_parms->N_RB_DL * 12)];
        rxF        = &rxdataF[aarx][(frame_parms->first_carrier_offset + (symbol * (frame_parms->ofdm_symbol_size)))];

        if((frame_parms->N_RB_DL & 1) == 0) // even number of RBs
            for(rb = 0; rb < frame_parms->N_RB_DL; rb++)
            {
                if(rb < 32)
                {
                    rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
                }
                else if(rb < 64)
                {
                    rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
                }
                else if(rb < 96)
                {
                    rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
                }
                else if(rb < 100)
                {
                    rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
                }
                else
                {
                    rb_alloc_ind = 0;
                }

                if(rb_alloc_ind == 1)
                {
                    nb_rb++;
                }

                // For second half of RBs skip DC carrier
                if(rb == (frame_parms->N_RB_DL >> 1))
                {
                    rxF       = &rxdataF[aarx][(1 + (symbol * (frame_parms->ofdm_symbol_size)))];
                    //dl_ch0++;
                }

                // PBCH
                if((subframe == 0) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= nsymb >> 1) && (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                }

                if(frame_parms->frame_type == FDD)
                {
                    //PSS
                    if(((subframe == 0) || (subframe == 5)) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }
                }

                if((frame_parms->frame_type == TDD) &&
                        (subframe == 6)) //TDD Subframe 6
                {
                    if((rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }
                }

                if(rb_alloc_ind == 1)
                {
                    /*
                        printf("rb %d\n",rb);
                        for (i=0;i<12;i++)
                        printf("(%d %d)",((short *)dl_ch0)[i<<1],((short*)dl_ch0)[1+(i<<1)]);
                        printf("\n");
                    */
                    if(pilots == 0 && uespec_pilots == 0)
                    {
                        memcpy(dl_ch0_ext, dl_ch0, 12 * sizeof(int));

                        for(i = 0; i < 12; i++)
                        {
                            rxF_ext[i] = rxF[i];
                        }

                        dl_ch0_ext += 12;
                        rxF_ext += 12;
                    }
                    else if(pilots == 1 && uespec_pilots == 0)
                    {
                        j = 0;

                        for(i = 0; i < 12; i++)
                        {
                            if((i != (frame_parms->nushift + poffset)) &&
                                    (i != ((frame_parms->nushift + poffset + 6) % 12)))
                            {
                                rxF_ext[j] = rxF[i];
                                dl_ch0_ext[j++] = dl_ch0[i];
                            }
                        }

                        dl_ch0_ext += 10;
                        rxF_ext += 10;
                    }
                    else if(pilots == 0 && uespec_pilots == 1)
                    {
                        j = 0;

                        for(i = 0; i < 12; i++)
                        {
                            if(frame_parms->Ncp == 0)
                            {
                                if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                {
                                    rxF_ext[j] = rxF[i];
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }
                            else
                            {
                                if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                {
                                    rxF_ext[j] = rxF[i];
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }
                        }

                        dl_ch0_ext += 9 - frame_parms->Ncp;
                        rxF_ext += 9 - frame_parms->Ncp;
                    }
                    else
                    {
                        LOG_E(PHY, "dlsch_extract_rbs_TM7(dl_demodulation.c):pilot or ue spec pilot detection error\n");
                        exit(-1);
                    }
                }

                dl_ch0 += 12;
                rxF += 12;
            }
        else     // Odd number of RBs
        {
            for(rb = 0; rb < frame_parms->N_RB_DL >> 1; rb++)
            {
                skip_half = 0;

                if(rb < 32)
                {
                    rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
                }
                else if(rb < 64)
                {
                    rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
                }
                else if(rb < 96)
                {
                    rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
                }
                else if(rb < 100)
                {
                    rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
                }
                else
                {
                    rb_alloc_ind = 0;
                }

                if(rb_alloc_ind == 1)
                {
                    nb_rb++;
                }

                // PBCH
                if((subframe == 0) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                }

                //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3
                if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 1;
                }
                else if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 2;
                }

                //SSS

                if(((subframe == 0) || (subframe == 5)) &&
                        (rb > ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (rb < ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) &&
                        (rb == ((frame_parms->N_RB_DL >> 1) - 3)) &&
                        (l == sss_symb))
                {
                    skip_half = 1;
                }
                else if(((subframe == 0) || (subframe == 5)) &&
                        (rb == ((frame_parms->N_RB_DL >> 1) + 3)) &&
                        (l == sss_symb))
                {
                    skip_half = 2;
                }

                //PSS in subframe 0/5 if FDD
                if(frame_parms->frame_type == FDD)     //FDD
                {
                    if(((subframe == 0) || (subframe == 5)) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if((frame_parms->frame_type == TDD) && ((subframe == 1) || (subframe == 6))) //TDD Subframe 1 and 6
                {
                    if((rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if((rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if((rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if(rb_alloc_ind == 1)
                {
#ifdef DEBUG_DLSCH_DEMOD
                    printf("rb %d/symbol %d pilots %d, uespec_pilots %d, (skip_half %d)\n", rb, l, pilots, uespec_pilots, skip_half);
#endif

                    if(pilots == 0 && uespec_pilots == 0)
                    {
                        //printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        if(skip_half == 1)
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else if(skip_half == 2)
                        {
                            memcpy(dl_ch0_ext, dl_ch0 + 6, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[(i + 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 12 * sizeof(int));

                            for(i = 0; i < 12; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract symbol %d rb %d, re %d => (%d,%d)\n", symbol, rb, i, *(short *)&rxF[i], *(1 + (short *)&rxF[i]));
#endif
                            }

                            dl_ch0_ext += 12;
                            rxF_ext += 12;
                        }
                    }
                    else if(pilots == 1 && uespec_pilots == 0)
                    {
                        // printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        j = 0;

                        if(skip_half == 1)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[i];
                                    dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else if(skip_half == 2)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[(i + 6)];
                                    dl_ch0_ext[j++] = dl_ch0[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else
                        {
                            for(i = 0; i < 12; i++)
                            {
                                if((i != (frame_parms->nushift + poffset)) &&
                                        (i != ((frame_parms->nushift + poffset + 6) % 12)))
                                {
                                    rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }

                            dl_ch0_ext += 10;
                            rxF_ext += 10;
                        }
                    }
                    else if(pilots == 0 && uespec_pilots == 1)
                    {
                        //printf("Extracting with uespec pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        j = 0;

                        if(skip_half == 1)
                        {
                            if(frame_parms->Ncp == 0)
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 6 - (uespec_nushift + uespec_poffset < 6) - (uespec_nushift + uespec_poffset + 4 < 6) - ((uespec_nushift + uespec_poffset + 8) % 12 < 6);
                                rxF_ext += 6 - (uespec_nushift + uespec_poffset < 6) - (uespec_nushift + uespec_poffset + 4 < 6) - ((uespec_nushift + uespec_poffset + 8) % 12 < 6);
                            }
                            else
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 4;
                                rxF_ext += 4;
                            }
                        }
                        else if(skip_half == 2)
                        {
                            if(frame_parms->Ncp == 0)
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                    {
                                        rxF_ext[j] = rxF[(i + 6)];
                                        dl_ch0_ext[j++] = dl_ch0[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 6 - (uespec_nushift + uespec_poffset > 6) - (uespec_nushift + uespec_poffset + 4 > 6) - ((uespec_nushift + uespec_poffset + 8) % 12 > 6);
                                rxF_ext += 6 - (uespec_nushift + uespec_poffset > 6) - (uespec_nushift + uespec_poffset + 4 > 6) - ((uespec_nushift + uespec_poffset + 8) % 12 > 6);
                            }
                            else
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                    {
                                        rxF_ext[j] = rxF[(i + 6)];
                                        dl_ch0_ext[j++] = dl_ch0[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 4;
                                rxF_ext += 4;
                            }
                        }
                        else
                        {
                            for(i = 0; i < 12; i++)
                            {
                                if(frame_parms->Ncp == 0)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract symbol %d, rb %d, re %d, j %d => (%d,%d)\n",
                                               symbol, rb, i, j - 1, *(short *)&dl_ch0[j], *(1 + (short *)&dl_ch0[i]));
#endif
                                    }
                                }
                                else
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }
                            }

                            dl_ch0_ext += 9 - frame_parms->Ncp;
                            rxF_ext += 9 - frame_parms->Ncp;
                        }
                    }
                    else
                    {
                        LOG_E(PHY, "dlsch_extract_rbs_TM7(dl_demodulation.c):pilot or ue spec pilot detection error\n");
                        exit(-1);
                    }
                }

                dl_ch0 += 12;
                rxF += 12;
            } // first half loop

            // Do middle RB (around DC)
            if(rb < 32)
            {
                rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
            }
            else if(rb < 64)
            {
                rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
            }
            else if(rb < 96)
            {
                rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
            }
            else if(rb < 100)
            {
                rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
            }
            else
            {
                rb_alloc_ind = 0;
            }

            if(rb_alloc_ind == 1)
            {
                nb_rb++;
            }

            // PBCH
            if((subframe == 0) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
            {
                rb_alloc_ind = 0;
            }

            //SSS
            if(((subframe == 0) || (subframe == 5)) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
            {
                rb_alloc_ind = 0;
            }

            if(frame_parms->frame_type == FDD)
            {
                //PSS
                if(((subframe == 0) || (subframe == 5)) && (rb >= ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                {
                    rb_alloc_ind = 0;
                }
            }

            if((frame_parms->frame_type == TDD) && ((subframe == 1) || (subframe == 6)))
            {
                //PSS
                if((rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                {
                    rb_alloc_ind = 0;
                }
            }

            //printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]);
            //printf("DC rb %d (%p)\n",rb,rxF);
            if(rb_alloc_ind == 1)
            {
                //printf("rb %d/symbol %d (skip_half %d)\n",rb,l,skip_half);
                if(pilots == 0 && uespec_pilots == 0)
                {
                    for(i = 0; i < 6; i++)
                    {
                        dl_ch0_ext[i] = dl_ch0[i];
                        rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                    }

                    rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];

                    for(; i < 12; i++)
                    {
                        dl_ch0_ext[i] = dl_ch0[i];
                        rxF_ext[i] = rxF[(1 + i - 6)];
#ifdef DEBUG_DLSCH_DEMOD
                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                    }

                    dl_ch0_ext += 12;
                    rxF_ext += 12;
                }
                else if(pilots == 1 && uespec_pilots == 0) // pilots==1
                {
                    j = 0;

                    for(i = 0; i < 6; i++)
                    {
                        if(i != ((frame_parms->nushift + poffset) % 6))
                        {
                            dl_ch0_ext[j] = dl_ch0[i];
                            rxF_ext[j++] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                            printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                        }
                    }

                    rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];

                    for(; i < 12; i++)
                    {
                        if(i != ((frame_parms->nushift + 6 + poffset) % 12))
                        {
                            dl_ch0_ext[j] = dl_ch0[i];
                            rxF_ext[j++] = rxF[(1 + i - 6)];
#ifdef DEBUG_DLSCH_DEMOD
                            printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                        }
                    }

                    dl_ch0_ext += 10;
                    rxF_ext += 10;
                }
                else if(pilots == 0 && uespec_pilots == 1)
                {
                    j = 0;

                    for(i = 0; i < 6; i++)
                    {
                        if(frame_parms->Ncp == 0)
                        {
                            if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                            {
                                dl_ch0_ext[j] = dl_ch0[i];
                                rxF_ext[j++] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }
                        }
                        else
                        {
                            if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                            {
                                dl_ch0_ext[j] = dl_ch0[i];
                                rxF_ext[j++] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }
                        }
                    }

                    rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];

                    for(; i < 12; i++)
                    {
                        if(frame_parms->Ncp == 0)
                        {
                            if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                            {
                                dl_ch0_ext[j] = dl_ch0[i];
                                rxF_ext[j++] = rxF[(1 + i - 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }
                        }
                        else
                        {
                            if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                            {
                                dl_ch0_ext[j] = dl_ch0[i];
                                rxF_ext[j++] = rxF[(1 + i - 6)];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }
                        }
                    }

                    dl_ch0_ext += 9 - frame_parms->Ncp;
                    rxF_ext += 9 - frame_parms->Ncp;
                }// symbol_mod==0
            } // rballoc==1
            else
            {
                rxF       = &rxdataF[aarx][((symbol * (frame_parms->ofdm_symbol_size)))];
            }

            dl_ch0 += 12;
            rxF += 7;
            rb++;

            for(; rb < frame_parms->N_RB_DL; rb++)
            {
                //  printf("dlch_ext %d\n",dl_ch0_ext-&dl_ch_estimates_ext[aarx][0]);
                //  printf("rb %d (%p)\n",rb,rxF);
                skip_half = 0;

                if(rb < 32)
                {
                    rb_alloc_ind = (rb_alloc[0] >> rb) & 1;
                }
                else if(rb < 64)
                {
                    rb_alloc_ind = (rb_alloc[1] >> (rb - 32)) & 1;
                }
                else if(rb < 96)
                {
                    rb_alloc_ind = (rb_alloc[2] >> (rb - 64)) & 1;
                }
                else if(rb < 100)
                {
                    rb_alloc_ind = (rb_alloc[3] >> (rb - 96)) & 1;
                }
                else
                {
                    rb_alloc_ind = 0;
                }

                if(rb_alloc_ind == 1)
                {
                    nb_rb++;
                }

                // PBCH
                if((subframe == 0) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= nsymb >> 1) && (l < ((nsymb >> 1) + 4)))
                {
                    rb_alloc_ind = 0;
                }

                //PBCH subframe 0, symbols nsymb>>1 ... nsymb>>1 + 3
                if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 1;
                }
                else if((subframe == 0) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l >= (nsymb >> 1)) && (l < ((nsymb >> 1) + 4)))
                {
                    skip_half = 2;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
                {
                    rb_alloc_ind = 0;
                }

                //SSS
                if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == sss_symb))
                {
                    skip_half = 1;
                }
                else if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == sss_symb))
                {
                    skip_half = 2;
                }

                //PSS
                if(frame_parms->frame_type == FDD)
                {
                    if(((subframe == 0) || (subframe == 5)) && (rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if(((subframe == 0) || (subframe == 5)) && (rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if((frame_parms->frame_type == TDD) && ((subframe == 1) || (subframe == 6))) //TDD Subframe 1 and 6
                {
                    if((rb > ((frame_parms->N_RB_DL >> 1) - 3)) && (rb < ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        rb_alloc_ind = 0;
                    }

                    if((rb == ((frame_parms->N_RB_DL >> 1) - 3)) && (l == pss_symb))
                    {
                        skip_half = 1;
                    }
                    else if((rb == ((frame_parms->N_RB_DL >> 1) + 3)) && (l == pss_symb))
                    {
                        skip_half = 2;
                    }
                }

                if(rb_alloc_ind == 1)
                {
#ifdef DEBUG_DLSCH_DEMOD
                    printf("rb %d/symbol %d (skip_half %d)\n", rb, l, skip_half);
#endif

                    /*
                        printf("rb %d\n",rb);
                        for (i=0;i<12;i++)
                        printf("(%d %d)",((short *)dl_ch0)[i<<1],((short*)dl_ch0)[1+(i<<1)]);
                        printf("\n");
                    */
                    if(pilots == 0 && uespec_pilots == 0)
                    {
                        //printf("Extracting w/o pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        if(skip_half == 1)
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else if(skip_half == 2)
                        {
                            memcpy(dl_ch0_ext, dl_ch0 + 6, 6 * sizeof(int));

                            for(i = 0; i < 6; i++)
                            {
                                rxF_ext[i] = rxF[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 6;
                            rxF_ext += 6;
                        }
                        else
                        {
                            memcpy(dl_ch0_ext, dl_ch0, 12 * sizeof(int));
                            //printf("symbol %d, extract rb %d, => (%d,%d)\n",symbol,rb,*(short *)&dl_ch0[j],*(1+(short*)&dl_ch0[i]));

                            for(i = 0; i < 12; i++)
                            {
                                rxF_ext[i] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                            }

                            dl_ch0_ext += 12;
                            rxF_ext += 12;
                        }
                    }
                    else if(pilots == 1 && uespec_pilots == 0)
                    {
                        //printf("Extracting with pilots (symbol %d, rb %d, skip_half %d)\n",l,rb,skip_half);
                        j = 0;

                        if(skip_half == 1)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[i];
                                    dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else if(skip_half == 2)
                        {
                            for(i = 0; i < 6; i++)
                            {
                                if(i != ((frame_parms->nushift + poffset) % 6))
                                {
                                    rxF_ext[j] = rxF[(i + 6)];
                                    dl_ch0_ext[j++] = dl_ch0[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                }
                            }

                            dl_ch0_ext += 5;
                            rxF_ext += 5;
                        }
                        else
                        {
                            for(i = 0; i < 12; i++)
                            {
                                if((i != (frame_parms->nushift + poffset)) &&
                                        (i != ((frame_parms->nushift + poffset + 6) % 12)))
                                {
                                    rxF_ext[j] = rxF[i];
#ifdef DEBUG_DLSCH_DEMOD
                                    printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[j], *(1 + (short *)&rxF_ext[j]));
#endif
                                    dl_ch0_ext[j++] = dl_ch0[i];
                                }
                            }

                            dl_ch0_ext += 10;
                            rxF_ext += 10;
                        }
                    }
                    else if(pilots == 0 && uespec_pilots == 1)
                    {
                        j = 0;

                        if(skip_half == 1)
                        {
                            if(frame_parms->Ncp == 0)
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 6 - (uespec_nushift + uespec_poffset < 6) - (uespec_nushift + uespec_poffset + 4 < 6) - ((uespec_nushift + uespec_poffset + 8) % 12 < 6);
                                rxF_ext += 6 - (uespec_nushift + uespec_poffset < 6) - (uespec_nushift + uespec_poffset + 4 < 6) - ((uespec_nushift + uespec_poffset + 8) % 12 < 6);
                            }
                            else
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 4;
                                rxF_ext += 4;
                            }
                        }
                        else if(skip_half == 2)
                        {
                            if(frame_parms->Ncp == 0)
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                    {
                                        rxF_ext[j] = rxF[i + 6];
                                        dl_ch0_ext[j++] = dl_ch0[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 6 - (uespec_nushift + uespec_poffset > 6) - (uespec_nushift + uespec_poffset + 4 > 6) - ((uespec_nushift + uespec_poffset + 8) % 12 > 6);
                                rxF_ext += 6 - (uespec_nushift + uespec_poffset > 6) - (uespec_nushift + uespec_poffset + 4 > 6) - ((uespec_nushift + uespec_poffset + 8) % 12 > 6);
                            }
                            else
                            {
                                for(i = 0; i < 6; i++)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                    {
                                        rxF_ext[j] = rxF[(i + 6)];
                                        dl_ch0_ext[j++] = dl_ch0[i + 6];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }

                                dl_ch0_ext += 4;
                                rxF_ext += 4;
                            }
                        }
                        else
                        {
                            for(i = 0; i < 12; i++)
                            {
                                if(frame_parms->Ncp == 0)
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 4 && i != (uespec_nushift + uespec_poffset + 8) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }
                                else
                                {
                                    if(i != uespec_nushift + uespec_poffset && i != uespec_nushift + uespec_poffset + 3 && i != uespec_nushift + uespec_poffset + 6 && i != (uespec_nushift + uespec_poffset + 9) % 12)
                                    {
                                        rxF_ext[j] = rxF[i];
                                        dl_ch0_ext[j++] = dl_ch0[i];
#ifdef DEBUG_DLSCH_DEMOD
                                        printf("extract rb %d, re %d => (%d,%d)\n", rb, i, *(short *)&rxF_ext[i], *(1 + (short *)&rxF_ext[i]));
#endif
                                    }
                                }
                            }

                            dl_ch0_ext += 9 - frame_parms->Ncp;
                            rxF_ext += 9 - frame_parms->Ncp;
                        }
                    }// pilots=0
                }

                dl_ch0 += 12;
                rxF += 12;
            }
        }
    }

    _mm_empty();
    _m_empty();
    return(nb_rb / frame_parms->nb_antennas_rx);
}

//==============================================================================================

void dump_dlsch2(PHY_VARS_UE *ue, uint8_t eNB_id, uint8_t subframe, unsigned int *coded_bits_per_codeword, int round,  unsigned char harq_pid)
{
#define NSYMB  ((ue->frame_parms.Ncp == 0) ? 14 : 12)
    char fname[32], vname[32];
    sprintf(fname, "dlsch%d_rxF_r%d_ext0.m", eNB_id, round);
    sprintf(vname, "dl%d_rxF_r%d_ext0", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->rxdataF_ext[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);

    if(ue->frame_parms.nb_antennas_rx > 1)
    {
        sprintf(fname, "dlsch%d_rxF_r%d_ext1.m", eNB_id, round);
        sprintf(vname, "dl%d_rxF_r%d_ext1", eNB_id, round);
        LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->rxdataF_ext[1],
              12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    }

    sprintf(fname, "dlsch%d_ch_r%d_ext00.m", eNB_id, round);
    sprintf(vname, "dl%d_ch_r%d_ext00", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_estimates_ext[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);

    if(ue->transmission_mode[eNB_id] == 7)
    {
        sprintf(fname, "dlsch%d_bf_ch_r%d.m", eNB_id, round);
        sprintf(vname, "dl%d_bf_ch_r%d", eNB_id, round);
        LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_bf_ch_estimates[0], 512 * NSYMB, 1, 1);
        //LOG_M(fname,vname,phy_vars_ue->lte_ue_pdsch_vars[eNB_id]->dl_bf_ch_estimates[0],512,1,1);
        sprintf(fname, "dlsch%d_bf_ch_r%d_ext00.m", eNB_id, round);
        sprintf(vname, "dl%d_bf_ch_r%d_ext00", eNB_id, round);
        LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_bf_ch_estimates_ext[0],
              12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    }

    if(ue->frame_parms.nb_antennas_rx == 2)
    {
        sprintf(fname, "dlsch%d_ch_r%d_ext01.m", eNB_id, round);
        sprintf(vname, "dl%d_ch_r%d_ext01", eNB_id, round);
        LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_estimates_ext[1],
              12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    }

    if(ue->frame_parms.nb_antenna_ports_eNB == 2)
    {
        sprintf(fname, "dlsch%d_ch_r%d_ext10.m", eNB_id, round);
        sprintf(vname, "dl%d_ch_r%d_ext10", eNB_id, round);
        LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_estimates_ext[2],
              12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);

        if(ue->frame_parms.nb_antennas_rx == 2)
        {
            sprintf(fname, "dlsch%d_ch_r%d_ext11.m", eNB_id, round);
            sprintf(vname, "dl%d_ch_r%d_ext11", eNB_id, round);
            LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_estimates_ext[3],
                  12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
        }
    }

    sprintf(fname, "dlsch%d_rxF_r%d_uespec0.m", eNB_id, round);
    sprintf(vname, "dl%d_rxF_r%d_uespec0", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->rxdataF_uespec_pilots[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    /*
        LOG_M("dlsch%d_ch_ext01.m","dl01_ch0_ext",pdsch_vars[eNB_id]->dl_ch_estimates_ext[1],12*N_RB_DL*NSYMB,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,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,1,1);
    */
    sprintf(fname, "dlsch%d_r%d_rho.m", eNB_id, round);
    sprintf(vname, "dl_rho_r%d_%d", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_rho_ext[harq_pid][round][0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    sprintf(fname, "dlsch%d_r%d_rho2.m", eNB_id, round);
    sprintf(vname, "dl_rho2_r%d_%d", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_rho2_ext[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    sprintf(fname, "dlsch%d_rxF_r%d_comp0.m", eNB_id, round);
    sprintf(vname, "dl%d_rxF_r%d_comp0", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->rxdataF_comp0[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);

    if(ue->frame_parms.nb_antenna_ports_eNB == 2)
    {
        sprintf(fname, "dlsch%d_rxF_r%d_comp1.m", eNB_id, round);
        sprintf(vname, "dl%d_rxF_r%d_comp1", eNB_id, round);
        LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->rxdataF_comp1[harq_pid][round][0],
              12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    }

    sprintf(fname, "dlsch%d_rxF_r%d_llr.m", eNB_id, round);
    sprintf(vname, "dl%d_r%d_llr", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->llr[0], coded_bits_per_codeword[0], 1, 0);
    sprintf(fname, "dlsch%d_r%d_mag1.m", eNB_id, round);
    sprintf(vname, "dl%d_r%d_mag1", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_mag0[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
    sprintf(fname, "dlsch%d_r%d_mag2.m", eNB_id, round);
    sprintf(vname, "dl%d_r%d_mag2", eNB_id, round);
    LOG_M(fname, vname, ue->pdsch_vars[ue->current_thread_id[subframe]][eNB_id]->dl_ch_magb0[0],
          12 * (ue->frame_parms.N_RB_DL)*NSYMB, 1, 1);
}