/******************************************************************************* OpenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAirInterface is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenAirInterface.The full GNU General Public License is included in this distribution in the file called "COPYING". If not, see . Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@eurecom.fr Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE *******************************************************************************/ /*!\brief Phase error compensation*/ /// /// Accomplishes the phase error compensation for CHBCH and SCH channels /// #ifndef USER_MODE #define __NO_VERSION__ //#include "from_grlib_softregs.h" #else #include #include #include #endif #include "PHY/defs.h" #include "PHY/extern.h" #include "SCHED/extern.h" #include "defs.h" #include "extern.h" #include "mmintrin.h" #ifndef USER_MODE #define openair_get_mbox() (*(unsigned int *)mbox) #endif //USER_MODE static __m64 perror64 __attribute__ ((aligned(16))); static __m64 Rsymb_conj64 __attribute__ ((aligned(16))); int phy_phase_compensation_top (unsigned int pilot_type, unsigned int initial_pilot, unsigned int last_pilot, int ignore_prefix) { #ifdef PC_TARGET // i - pilot index // i2 - I have no idea // aa - receive antenna index unsigned short i, i2, aa; // Temporary buffer or similar int *input; // Our SCH indices unsigned int pilot_offset, sch_index; unsigned char frequency_reuse_ind = 1; unsigned char log2_avg,log2_perror_amp; struct complex16 perror, *Rchsch, *Rsymb, *Rsch; __m64 *Rchsch64, *Rsch64; register __m64 mm0, mm1; int ind, ind64; int chr, chi; int rx_energy[NB_ANTENNAS_RX]; unsigned char *chbch_pdu; unsigned int chbch_size; unsigned int time_in, time_out; unsigned int number_of_pilots = last_pilot - initial_pilot; #ifdef USER_MODE char fname[40], vname[40]; #endif //USER_MODE #ifdef DEBUG_PHY msg ("[openair][PHY][CODING] Correction of phase error\n"); #endif // DEBUG_PHY for (aa = 0; aa < NB_ANTENNAS_RX; aa++) { // Lets check to see if the phase compensation is done over the CHBCH or SCH if (pilot_type == 0) // Were working with the CHBCH { for (i = 0; i < NUMBER_OF_CHBCH_SYMBOLS; i++) { // Review this code... It is NOT WORKING!!! #ifndef USER_MODE if (openair_daq_vars.mode == openair_NOT_SYNCHED) { input = &PHY_vars->rx_vars[aa]. RX_DMA_BUFFER[(PHY_vars->rx_vars[0].offset + ((i + SYMBOL_OFFSET_CHBCH) << LOG2_NUMBER_OF_OFDM_CARRIERS) + (i + 1 + SYMBOL_OFFSET_CHBCH) * CYCLIC_PREFIX_LENGTH) % FRAME_LENGTH_SAMPLES]; } else { #ifdef HW_PREFIX_REMOVAL input = &PHY_vars->rx_vars[aa]. RX_DMA_BUFFER[((i + SYMBOL_OFFSET_CHBCH) << LOG2_NUMBER_OF_OFDM_CARRIERS)]; #else input = &PHY_vars->rx_vars[aa]. RX_DMA_BUFFER[((i + SYMBOL_OFFSET_CHBCH) << LOG2_NUMBER_OF_OFDM_CARRIERS) + (i + SYMBOL_OFFSET_CHBCH + 1) * CYCLIC_PREFIX_LENGTH]; #endif //HW_PREFIX_REMOVAL } #else //USER_MODE input = &PHY_vars->rx_vars[aa]. RX_DMA_BUFFER[(PHY_vars->rx_vars[0].offset + ((i + SYMBOL_OFFSET_CHBCH) << LOG2_NUMBER_OF_OFDM_CARRIERS) + (i + 1 + SYMBOL_OFFSET_CHBCH) * CYCLIC_PREFIX_LENGTH) % FRAME_LENGTH_SAMPLES]; #endif //USER_MODE // msg("[openair][PHY][CHBCH %d] frame %d: Decoding -> FFT %d\n",frequency_reuse_ind,frame,i); // dump_chbch_pilots (0); fft ((short *) &input[0], (short *) &PHY_vars->chbch_data[frequency_reuse_ind]. rx_sig_f[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], (short *) twiddle_fft, rev, LOG2_NUMBER_OF_OFDM_CARRIERS, 3, 0); // Phase error compensation // dump_chbch_pilots (0); if (NUMBER_OF_CHBCH_PILOTS) { perror.r = 0; perror.i = 0; Rchsch = (struct complex16 *) &PHY_vars-> chsch_data[frequency_reuse_ind].rx_sig_f[aa][0]; Rsymb = (struct complex16 *) &PHY_vars-> chbch_data[frequency_reuse_ind]. rx_sig_f[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)]; Rchsch64 = (__m64 *) & PHY_vars-> chsch_data[frequency_reuse_ind].rx_sig_f[aa][0]; // inner product of received CHSCH in pilot positions and received symbol mm1 = _m_pxor (mm1, mm1); for (i2 = 0; i2 < NUMBER_OF_CHBCH_PILOTS; i2++) { ind = PHY_vars->chbch_data[frequency_reuse_ind]. pilot_indices[i2] << 1; ind64 = PHY_vars->chbch_data[frequency_reuse_ind]. pilot_indices[i2]; #ifdef DEBUG_PHY #ifdef USER_MODE msg ("[OPENAIR][PHY][CHBCH DEMOD]Ant %d symbol %d (%p), pilot %d (%d): RX p (%d,%d), RX s (%d,%d)\n", aa, i, Rsymb, i2, ind64, Rchsch[ind].r, Rchsch[ind].i, Rsymb[ind].r, Rsymb[ind].i); #endif /* USER_MODE */ #endif /* DEBUG_PHY */ // perror.r += ( ((Rchsch[ind].r*Rsymb[ind].r)>>PERROR_SHIFT) + ((Rchsch[ind].i*Rsymb[ind].i)>>PERROR_SHIFT) ); // perror.i += ( ((Rchsch[ind].i*Rsymb[ind].r)>>PERROR_SHIFT) - ((Rchsch[ind].r*Rsymb[ind].i)>>PERROR_SHIFT) ); // MMX version ((short *) &Rsymb_conj64)[0] = Rsymb[ind].r; ((short *) &Rsymb_conj64)[1] = Rsymb[ind].i; ((short *) &Rsymb_conj64)[2] = -Rsymb[ind].i; ((short *) &Rsymb_conj64)[3] = Rsymb[ind].r; mm0 = _mm_madd_pi16 (Rchsch64[ind64], Rsymb_conj64); mm1 = _mm_add_pi32 (mm0, mm1); } perror64 = _mm_srai_pi32 (mm1, PERROR_SHIFT + LOG2_NUMBER_OF_CHBCH_PILOTS); perror.r = ((short *) &perror64)[0]; perror.i = ((short *) &perror64)[2]; // base shift for rotation on amplitude first OFDM symbol only (might be better to compute the max over the CHBCH if ((aa == 0) && (i == 0)) { log2_perror_amp = log2_approx ((unsigned int) ((int) perror. r * perror.r + (int) perror. i * perror. i)) >> 1; } // Apply rotation rotate_cpx_vector ((short *) Rsymb, (short *) &perror, (short *) Rsymb, NUMBER_OF_OFDM_CARRIERS, log2_perror_amp, 0); #ifdef DEBUG_PHY #ifdef USER_MODE msg ("[OPENAIR][PHY][CHBCH DEMOD] Ant %d : symbol %d, perror = (%d,%d) , approx amp %d\n", aa, i, perror.r, perror.i, log2_perror_amp); #endif //USER_MODE #endif //DEBUG_PHY } } } else // Were working with the SCH { // Foreach PILOT SCH for (pilot_offset = initial_pilot; pilot_offset <= last_pilot; pilot_offset++) { // Set the absolute pilot index wrt the frame: sch_index = EMOS_SCH_INDEX; for (i = 0; i < NUMBER_OF_SCH_SYMBOLS; i++) { if (ignore_prefix == 1) { input = &PHY_vars->rx_vars[aa].RX_DMA_BUFFER[(i + pilot_offset) << (LOG2_NUMBER_OF_OFDM_CARRIERS)]; } else { input = &PHY_vars->rx_vars[aa].RX_DMA_BUFFER[((i + pilot_offset) << (LOG2_NUMBER_OF_OFDM_CARRIERS)) + (i + 1 + pilot_offset) * CYCLIC_PREFIX_LENGTH]; } fft ((short *) &input[0], (short *) &PHY_vars->sch_data[sch_index].rx_sig_f[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], (short *) twiddle_fft, rev, LOG2_NUMBER_OF_OFDM_CARRIERS, 3, 0); perror.r = 0; perror.i = 0; // Reference SCH Rsch = (struct complex16 *) &PHY_vars->sch_data[sch_index].rx_sig_f[aa][initial_pilot]; Rsch64 = (__m64 *) & PHY_vars->chsch_data[sch_index].rx_sig_f[aa][initial_pilot]; //IN MMX format // SCH to be de-rotated Rsymb = (struct complex16 *) &PHY_vars->sch_data[sch_index].rx_sig_f[aa][pilot_offset << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)]; // inner product of received CHSCH in pilot positions and received symbol mm1 = _m_pxor (mm1, mm1); for (i2 = 0; i2 < NUMBER_OF_OFDM_CARRIERS; i2++) { // Indices ind = i2 << 1; ind64 = i2; #ifdef DEBUG_PHY #ifdef USER_MODE msg ("[OPENAIR][PHY][CHBCH DEMOD]Ant %d symbol %d (%p), pilot %d (%d): RX p (%d,%d), RX s (%d,%d)\n", aa, i, Rsymb, i2, ind64, Rchsch[ind].r, Rchsch[ind].i, Rsymb[ind].r, Rsymb[ind].i); #endif /* USER_MODE */ #endif /* DEBUG_PHY */ // perror.r += ( ((Rchsch[ind].r*Rsymb[ind].r)>>PERROR_SHIFT) + ((Rchsch[ind].i*Rsymb[ind].i)>>PERROR_SHIFT) ); // perror.i += ( ((Rchsch[ind].i*Rsymb[ind].r)>>PERROR_SHIFT) - ((Rchsch[ind].r*Rsymb[ind].i)>>PERROR_SHIFT) ); // MMX version // Initializing the vector for complex mult ((short *) &Rsymb_conj64)[0] = Rsymb[ind].r; ((short *) &Rsymb_conj64)[1] = Rsymb[ind].i; ((short *) &Rsymb_conj64)[2] = -Rsymb[ind].i; ((short *) &Rsymb_conj64)[3] = Rsymb[ind].r; mm0 = _mm_madd_pi16 (Rchsch64[ind64], Rsymb_conj64); mm1 = _mm_add_pi32 (mm0, mm1); } // this is a bitwise shift perror64 = _mm_srai_pi32 (mm1, PERROR_SHIFT + LOG2_NUMBER_OF_OFDM_CARRIERS); perror.r = ((short *) &perror64)[0]; perror.i = ((short *) &perror64)[2]; // base shift for rotation on amplitude first OFDM symbol only (might be better to compute the max over the CHBCH if ((aa == 0) && (i == 0)) { // For normalization in the followinf routine log2_perror_amp = log2_approx((unsigned int) ((int) perror.r * perror.r + (int)perror.i * perror.i)) >> 1; } // Apply rotation rotate_cpx_vector ((short *) Rsymb, (short *) &perror, (short *) Rsymb, NUMBER_OF_OFDM_CARRIERS, log2_perror_amp, 0); #ifdef DEBUG_PHY #ifdef USER_MODE msg ("[OPENAIR][PHY][CHBCH DEMOD] Ant %d : symbol %d, perror = (%d,%d) , approx amp %d\n", aa, i, perror.r, perror.i, log2_perror_amp); #endif //USER_MODE #endif //DEBUG_PHY } phy_channel_estimation ((short *) &PHY_vars-> sch_data[sch_index]. rx_sig_f[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], (short *) &PHY_vars-> sch_data[sch_index]. channel[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], (short *) &PHY_vars-> sch_data[sch_index]. channel_f[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], (short *) &PHY_vars-> sch_data[sch_index]. channel_matched_filter_f[aa][i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], (short *) &PHY_vars->sch_data[0]. SCH_conj_f[i << (1 + LOG2_NUMBER_OF_OFDM_CARRIERS)], 15, //LOG2_SCH_RX_F_AMP, (NB_ANTENNAS_RX == 1) ? 1 : 0); #ifdef USER_MODE #ifdef DEBUG_PHY sprintf (fname, "sch%d_channelF%d.m", sch_index, aa); sprintf (vname, "sch%d_chanF%d", sch_index, aa); write_output (fname, vname, (short *) &PHY_vars->sch_data[sch_index]. channel_f[aa][0], 2 * NUMBER_OF_OFDM_CARRIERS, 2, 1); sprintf (fname, "sch%d_channel%d.m", sch_index, aa); sprintf (vname, "sch%d_chan%d", sch_index, aa); write_output (fname, vname, (short *) &PHY_vars->sch_data[sch_index]. channel[aa][0], 2 * NUMBER_OF_OFDM_CARRIERS, 2, 1); #endif // DEBUG_PHY #endif // USER_MODE } } } #endif //PC_TARGET } void phy_phase_compensation (short *ref_sch, short *tgt_sch, short *out_sym, int ignore_prefix, int aa, struct complex16 *perror_out) { struct complex16 perror, *Rsymb, *Rsch; struct complex32 perror32; __m64 perror64, Rsymb_conj64, Rsch64; __m64 Rsymb64[NUMBER_OF_OFDM_CARRIERS]; __m64 *tgt_sch64 = (__m64 *)tgt_sch; register __m64 mm0, mm1, mm2; int i,i2; unsigned char log2_avg,log2_perror_amp; int ind, ind64; perror.r = 0; perror.i = 0; perror32.r = 0; perror32.i = 0; // Reference SCH Rsch = (struct complex16 *) ref_sch; // SCH to be de-rotated Rsymb = (struct complex16 *) tgt_sch; // The following code copies the data from *tgt_sch to *Rsymb64 and // converts it into the following format: | Re0 Im0 Re0 Im0 || Re1 Im1 Re1 Im1 | i2=0; for(i=0;i<((NUMBER_OF_OFDM_CARRIERS)>>1);i++) // reverse 2 complex samples at a time => does the loop size>>1 times { mm0 = tgt_sch64[i]; mm1 = mm0; mm2 = mm0; mm1 = _m_punpckldq(mm1,mm0); mm2 = _m_punpckhdq(mm2,mm0); Rsymb64[i2++]=mm1; // get the output index (reverse bit ordering index) Rsymb64[i2++]=mm2; } // inner product of received CHSCH in pilot positions and received symbol mm1 = _m_pxor (mm1, mm1); for (i = 0; i < NUMBER_OF_OFDM_CARRIERS; i++) { // Indices ind = i; //ind64 = i; // Pure C version // perror32.r += ( (((int)Rsch[ind].r*(int)Rsymb[ind].r) >> PERROR_SHIFT) + (((int)Rsch[ind].i*(int)Rsymb[ind].i) >> PERROR_SHIFT) ); // perror32.i += ( (((int)Rsch[ind].i*(int)Rsymb[ind].r) >> PERROR_SHIFT) - (((int)Rsch[ind].r*(int)Rsymb[ind].i) >> PERROR_SHIFT) ); // MMX version ((short *) &Rsch64)[0] = Rsch[ind].r; ((short *) &Rsch64)[1] = Rsch[ind].i; ((short *) &Rsch64)[2] = Rsch[ind].r; ((short *) &Rsch64)[3] = Rsch[ind].i; // Initializing the vector for complex mult ((short *) &Rsymb_conj64)[0] = Rsymb[ind].r; ((short *) &Rsymb_conj64)[1] = Rsymb[ind].i; ((short *) &Rsymb_conj64)[2] = -Rsymb[ind].i; ((short *) &Rsymb_conj64)[3] = Rsymb[ind].r; //Complex multiplication 16 -> 32 bits mm0 = _mm_madd_pi16 (Rsch64, Rsymb_conj64); mm1 = _mm_add_pi32 (mm0, mm1); } // Believe me... this is a bitwise shift! (bringing back to 16 bits) perror64 = _mm_srai_pi32 (mm1, PERROR_SHIFT + LOG2_NUMBER_OF_OFDM_CARRIERS); perror.r = ((short *) &perror64)[0]; perror.i = ((short *) &perror64)[2]; // perror.r = (short)(perror32.r >> LOG2_NUMBER_OF_OFDM_CARRIERS); // perror.i = (short)(perror32.i >> LOG2_NUMBER_OF_OFDM_CARRIERS); // base shift for rotation on amplitude first OFDM symbol only (might be better to compute the max over the CHBCH) // if (aa == 0) // { // For normalization in the following routine log2_perror_amp = log2_approx((unsigned int) ((int)(perror.r * perror.r) + (int)(perror.i * perror.i))) >> 1; // } *perror_out = perror; // Apply rotation rotate_cpx_vector ((short *) Rsymb64, (short *) &perror, (short *) out_sym, NUMBER_OF_OFDM_CARRIERS, log2_perror_amp,0); }