/******************************************************************************* Eurecom OpenAirInterface Copyright(c) 1999 - 2011 Eurecom This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. The full GNU General Public License is included in this distribution in the file called "COPYING". Contact Information Openair Admin: openair_admin@eurecom.fr Openair Tech : openair_tech@eurecom.fr Forums : http://forums.eurecom.fsr/openairinterface Address : Eurecom, 2229, route des crĂȘtes, 06560 Valbonne Sophia Antipolis, France *******************************************************************************/ /*! \file PHY/LTE_TRANSPORT/ulsch_modulation.c * \brief Top-level routines for generating PUSCH physical channel from 36.211 V8.6 2009-03 * \author R. Knopp, F. Kaltenberger, A. Bhamri * \date 2011 * \version 0.1 * \company Eurecom * \email: knopp@eurecom.fr,florian.kaltenberger@eurecom.fr,ankit.bhamri@eurecom.fr * \note * \warning */ #include "PHY/defs.h" #include "PHY/extern.h" #include "PHY/CODING/defs.h" #include "PHY/CODING/extern.h" #include "PHY/LTE_TRANSPORT/defs.h" #include "defs.h" #include "UTIL/LOG/vcd_signal_dumper.h" //#define OFDMA_ULSCH //#define DEBUG_ULSCH_MODULATION __m128i dft_in128[4][1200],dft_in128[4][1200],dft_out128[4][1200],dft_out128[4][1200]; #ifndef OFDMA_ULSCH void dft_lte(mod_sym_t *z,mod_sym_t *d, int32_t Msc_PUSCH, uint8_t Nsymb) { uint32_t *dft_in0=(uint32_t*)dft_in128[0],*dft_out0=(uint32_t*)dft_out128[0]; uint32_t *dft_in1=(uint32_t*)dft_in128[1],*dft_out1=(uint32_t*)dft_out128[1]; uint32_t *dft_in2=(uint32_t*)dft_in128[2],*dft_out2=(uint32_t*)dft_out128[2]; // uint32_t *dft_in3=(uint32_t*)dft_in128[3],*dft_out3=(uint32_t*)dft_out128[3]; uint32_t *d0,*d1,*d2,*d3,*d4,*d5,*d6,*d7,*d8,*d9,*d10,*d11; uint32_t *z0,*z1,*z2,*z3,*z4,*z5,*z6,*z7,*z8,*z9,*z10,*z11; uint32_t i,ip; __m128i norm128; // msg("Doing lte_dft for Msc_PUSCH %d\n",Msc_PUSCH); d0 = (uint32_t *)d; d1 = d0+Msc_PUSCH; d2 = d1+Msc_PUSCH; d3 = d2+Msc_PUSCH; d4 = d3+Msc_PUSCH; d5 = d4+Msc_PUSCH; d6 = d5+Msc_PUSCH; d7 = d6+Msc_PUSCH; d8 = d7+Msc_PUSCH; d9 = d8+Msc_PUSCH; d10 = d9+Msc_PUSCH; d11 = d10+Msc_PUSCH; // msg("symbol 0 (d0 %p, d %p)\n",d0,d); for (i=0,ip=0;itdd_config,subframe); uint8_t harq_pid = subframe2harq_pid(frame_parms,((subframe==0)?1:0)+frame,subframe); uint8_t Q_m; mod_sym_t *txptr; uint32_t symbol_offset; uint16_t first_rb; uint16_t nb_rb; int G; uint32_t x1, x2, s=0; uint8_t c; // x1 is set in lte_gold_generic x2 = (ulsch->rnti<<14) + (subframe<<9) + frame_parms->Nid_cell; //this is c_init in 36.211 Sec 6.3.1 if (!ulsch) { msg("ulsch_modulation.c: Null ulsch\n"); return; } if (harq_pid > 7) { msg("ulsch_modulation.c: Illegal harq_pid %d\n",harq_pid); return; } first_rb = ulsch->harq_processes[harq_pid]->first_rb; nb_rb = ulsch->harq_processes[harq_pid]->nb_rb; if (nb_rb == 0) { msg("ulsch_modulation.c: Illegal nb_rb %d\n",nb_rb); return; } if (first_rb >25 ) { msg("ulsch_modulation.c: Illegal first_rb %d\n",first_rb); return; } vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_MODULATION, VCD_FUNCTION_IN); Q_m = get_Qm_ul(ulsch->harq_processes[harq_pid]->mcs); G = (int)ulsch->harq_processes[harq_pid]->nb_rb * (12 * Q_m) * (ulsch->Nsymb_pusch); // Mapping nsymb = (frame_parms->Ncp==0) ? 14:12; Msc_PUSCH = ulsch->harq_processes[harq_pid]->nb_rb*12; #ifdef DEBUG_ULSCH_MODULATION msg("ulsch_modulation.c: Doing modulation (rnti %x,x2 %x) for G=%d bits, harq_pid %d , nb_rb %d, Q_m %d, Nsymb_pusch %d (nsymb %d), subframe %d\n", ulsch->rnti,x2,G,harq_pid,ulsch->harq_processes[harq_pid]->nb_rb,Q_m, ulsch->Nsymb_pusch,nsymb,subframe); #endif // scrambling (Note the placeholding bits are handled in ulsch_coding.c directly!) //msg("ulsch bits: "); s = lte_gold_generic(&x1, &x2, 1); k=0; //printf("G %d\n",G); for (i=0;i<(1+(G>>5));i++) { for (j=0;j<32;j++,k++) { c = (uint8_t)((s>>j)&1); if (ulsch->h[k] == PUSCH_x) { // msg("i %d: PUSCH_x\n",i); ulsch->b_tilde[k] = 1; } else if (ulsch->h[k] == PUSCH_y) { // msg("i %d: PUSCH_y\n",i); ulsch->b_tilde[k] = ulsch->b_tilde[k-1]; } else { ulsch->b_tilde[k] = (ulsch->h[k]+c)&1; // msg("i %d : %d (h %d c %d)\n", (i<<5)+j,ulsch->b_tilde[k],ulsch->h[k],c); } } s = lte_gold_generic(&x1, &x2, 0); } //msg("\n"); gain_lin_QPSK = (short)((amp*ONE_OVER_SQRT2_Q15)>>15); // Modulation Msymb = G/Q_m; if(ulsch->cooperation_flag == 2) // For Distributed Alamouti Scheme in Collabrative Communication { for (i=0,j=Q_m;id[i])[0] = (ulsch->b_tilde[j] == 1) ? (gain_lin_QPSK) : -gain_lin_QPSK; ((int16_t*)&ulsch->d[i])[1] = (ulsch->b_tilde[j+1] == 1)? (-gain_lin_QPSK) : gain_lin_QPSK; // if (id[i],((int16_t*)&ulsch->d[i])[0],((int16_t*)&ulsch->d[i])[1]); // UE1, x0* ((int16_t*)&ulsch->d[i+1])[0] = (ulsch->b_tilde[j-2] == 1) ? (-gain_lin_QPSK) : gain_lin_QPSK; ((int16_t*)&ulsch->d[i+1])[1] = (ulsch->b_tilde[j-1] == 1)? (gain_lin_QPSK) : -gain_lin_QPSK; break; case 4: //UE1,-x1* qam16_table_offset_re = 0; qam16_table_offset_im = 0; if (ulsch->b_tilde[j] == 1) qam16_table_offset_re+=2; if (ulsch->b_tilde[j+1] == 1) qam16_table_offset_im+=2; if (ulsch->b_tilde[j+2] == 1) qam16_table_offset_re+=1; if (ulsch->b_tilde[j+3] == 1) qam16_table_offset_im+=1; ((int16_t*)&ulsch->d[i])[0]=-(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); ((int16_t*)&ulsch->d[i])[1]=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); //UE1,x0* qam16_table_offset_re = 0; qam16_table_offset_im = 0; if (ulsch->b_tilde[j-4] == 1) qam16_table_offset_re+=2; if (ulsch->b_tilde[j-3] == 1) qam16_table_offset_im+=2; if (ulsch->b_tilde[j-2] == 1) qam16_table_offset_re+=1; if (ulsch->b_tilde[j-1] == 1) qam16_table_offset_im+=1; // ((int16_t*)&ulsch->d[i+1])[0]=-(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); // ((int16_t*)&ulsch->d[i+1])[1]=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); ((int16_t*)&ulsch->d[i+1])[0]=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); ((int16_t*)&ulsch->d[i+1])[1]=-(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); break; case 6: //UE1,-x1*FPGA_UE qam64_table_offset_re = 0; qam64_table_offset_im = 0; if (ulsch->b_tilde[j] == 1) qam64_table_offset_re+=4; if (ulsch->b_tilde[j+1] == 1) qam64_table_offset_im+=4; if (ulsch->b_tilde[j+2] == 1) qam64_table_offset_re+=2; if (ulsch->b_tilde[j+3] == 1) qam64_table_offset_im+=2; if (ulsch->b_tilde[j+4] == 1) qam64_table_offset_re+=1; if (ulsch->b_tilde[j+5] == 1) qam64_table_offset_im+=1; ((int16_t*)&ulsch->d[i])[0]=-(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); ((int16_t*)&ulsch->d[i])[1]=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); //UE1,x0* qam64_table_offset_re = 0; qam64_table_offset_im = 0; if (ulsch->b_tilde[j-6] == 1) qam64_table_offset_re+=4; if (ulsch->b_tilde[j-5] == 1) qam64_table_offset_im+=4; if (ulsch->b_tilde[j-4] == 1) qam64_table_offset_re+=2; if (ulsch->b_tilde[j-3] == 1) qam64_table_offset_im+=2; if (ulsch->b_tilde[j-2] == 1) qam64_table_offset_re+=1; if (ulsch->b_tilde[j-1] == 1) qam64_table_offset_im+=1; ((int16_t*)&ulsch->d[i+1])[0]=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); ((int16_t*)&ulsch->d[i+1])[1]=-(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; }//switch }//for }//cooperation_flag == 2 else { for (i=0,j=0;id[i])[0] = (ulsch->b_tilde[j] == 1) ? (-gain_lin_QPSK) : gain_lin_QPSK; ((int16_t*)&ulsch->d[i])[1] = (ulsch->b_tilde[j+1] == 1)? (-gain_lin_QPSK) : gain_lin_QPSK; // if (id[i],((int16_t*)&ulsch->d[i])[0],((int16_t*)&ulsch->d[i])[1]); break; case 4: qam16_table_offset_re = 0; qam16_table_offset_im = 0; if (ulsch->b_tilde[j] == 1) qam16_table_offset_re+=2; if (ulsch->b_tilde[j+1] == 1) qam16_table_offset_im+=2; if (ulsch->b_tilde[j+2] == 1) qam16_table_offset_re+=1; if (ulsch->b_tilde[j+3] == 1) qam16_table_offset_im+=1; ((int16_t*)&ulsch->d[i])[0]=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_re])>>15); ((int16_t*)&ulsch->d[i])[1]=(int16_t)(((int32_t)amp*qam16_table[qam16_table_offset_im])>>15); // msg("input(16qam) %d (%p): %d,%d\n", i,&ulsch->d[i],((int16_t*)&ulsch->d[i])[0],((int16_t*)&ulsch->d[i])[1]); break; case 6: qam64_table_offset_re = 0; qam64_table_offset_im = 0; if (ulsch->b_tilde[j] == 1) qam64_table_offset_re+=4; if (ulsch->b_tilde[j+1] == 1) qam64_table_offset_im+=4; if (ulsch->b_tilde[j+2] == 1) qam64_table_offset_re+=2; if (ulsch->b_tilde[j+3] == 1) qam64_table_offset_im+=2; if (ulsch->b_tilde[j+4] == 1) qam64_table_offset_re+=1; if (ulsch->b_tilde[j+5] == 1) qam64_table_offset_im+=1; ((int16_t*)&ulsch->d[i])[0]=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_re])>>15); ((int16_t*)&ulsch->d[i])[1]=(int16_t)(((int32_t)amp*qam64_table[qam64_table_offset_im])>>15); break; } } }// normal symbols // Transform Precoding #ifdef OFDMA_ULSCH for (i=0;iz[i] = ulsch->d[i]; } #else dft_lte(ulsch->z,ulsch->d,Msc_PUSCH,ulsch->Nsymb_pusch); #endif #ifdef OFDMA_ULSCH re_offset0 = frame_parms->first_carrier_offset + (ulsch->harq_processes[harq_pid]->first_rb*12); if (re_offset0>frame_parms->ofdm_symbol_size) { re_offset0 -= frame_parms->ofdm_symbol_size; // re_offset0++; } // msg("re_offset0 %d\n",re_offset0); for (j=0,l=0;l<(nsymb-ulsch->srs_active);l++) { re_offset = re_offset0; symbol_offset = (int)frame_parms->ofdm_symbol_size*(l+(subframe*nsymb)); #ifdef DEBUG_ULSCH_MODULATION msg("symbol %d (subframe %d): symbol_offset %d\n",l,subframe,symbol_offset); #endif txptr = &txdataF[0][symbol_offset]; if (((frame_parms->Ncp == 0) && ((l==3) || (l==10)))|| ((frame_parms->Ncp == 1) && ((l==2) || (l==8)))) { } // Skip reference symbols else { // msg("copying %d REs\n",Msc_PUSCH); for (i=0;iz[j],((int16_t*)&ulsch->z[j])[0],((int16_t*)&ulsch->z[j])[1]); #endif txptr[re_offset++] = ulsch->z[j]; if (re_offset==frame_parms->ofdm_symbol_size) re_offset = 0; } } } # else // OFDMA_ULSCH = 0 re_offset0 = frame_parms->first_carrier_offset + (ulsch->harq_processes[harq_pid]->first_rb*12); if (re_offset0>frame_parms->ofdm_symbol_size) { re_offset0 -= frame_parms->ofdm_symbol_size; // re_offset0++; } // msg("re_offset0 %d\n",re_offset0); // printf("txdataF %p\n",&txdataF[0][0]); for (j=0,l=0;l<(nsymb-ulsch->srs_active);l++) { re_offset = re_offset0; symbol_offset = (uint32_t)frame_parms->ofdm_symbol_size*(l+(subframe*nsymb)); #ifdef DEBUG_ULSCH_MODULATION msg("ulsch_mod (OFDMA) symbol %d (subframe %d): symbol_offset %d\n",l,subframe,symbol_offset); #endif txptr = &txdataF[0][symbol_offset]; if (((frame_parms->Ncp == 0) && ((l==3) || (l==10)))|| ((frame_parms->Ncp == 1) && ((l==2) || (l==8)))) { } // Skip reference symbols else { // msg("copying %d REs\n",Msc_PUSCH); for (i=0;i %p\n", re_offset,&ulsch->z[j],((int16_t*)&ulsch->z[j])[0],((int16_t*)&ulsch->z[j])[1],&txptr[re_offset]); #endif //DEBUG_ULSCH_MODULATION txptr[re_offset++] = ulsch->z[j]; if (re_offset==frame_parms->ofdm_symbol_size) re_offset = 0; } } } #endif vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_ULSCH_MODULATION, VCD_FUNCTION_OUT); }