int lte_est_freq_offset(int **dl_ch_estimates, LTE_DL_FRAME_PARMS *frame_parms, int l, int* freq_offset) { int ch_offset, omega, dl_ch_shift; struct complex16 *omega_cpx; double phase_offset; int freq_offset_est; unsigned char aa; s16 *dl_ch,*dl_ch_prev; static int first_run = 1; int coef = 1<<10; int ncoef = 32767 - coef; ch_offset = (l*(frame_parms->ofdm_symbol_size)); if ((l!=0) && (l!=(4-frame_parms->Ncp))) { msg("lte_est_freq_offset: l (%d) must be 0 or %d\n",l,4-frame_parms->Ncp); return(-1); } phase_offset = 0.0; // for (aa=0;aa<frame_parms->nb_antennas_rx*frame_parms->nb_antennas_tx;aa++) { for (aa=0;aa<1;aa++) { dl_ch = (s16 *)&dl_ch_estimates[aa][12+ch_offset]; dl_ch_shift = 4+(log2_approx(dl_channel_level(dl_ch,frame_parms))/2); // printf("dl_ch_shift: %d\n",dl_ch_shift); if (ch_offset == 0) dl_ch_prev = (s16 *)&dl_ch_estimates[aa][12+(4-frame_parms->Ncp)*(frame_parms->ofdm_symbol_size)]; else dl_ch_prev = (s16 *)&dl_ch_estimates[aa][12+0]; // calculate omega = angle(conj(dl_ch)*dl_ch_prev)) // printf("Computing freq_offset\n"); omega = dot_product(dl_ch,dl_ch_prev,(frame_parms->N_RB_DL/2 - 1)*12,dl_ch_shift); //omega = dot_product(dl_ch,dl_ch_prev,frame_parms->ofdm_symbol_size,15); omega_cpx = (struct complex16*) ω // printf("omega (%d,%d)\n",omega_cpx->r,omega_cpx->i); dl_ch = (s16 *)&dl_ch_estimates[aa][(((frame_parms->N_RB_DL/2) + 1)*12) + ch_offset]; if (ch_offset == 0) dl_ch_prev = (s16 *)&dl_ch_estimates[aa][(((frame_parms->N_RB_DL/2) + 1)*12)+(4-frame_parms->Ncp)*(frame_parms->ofdm_symbol_size)]; else dl_ch_prev = (s16 *)&dl_ch_estimates[aa][((frame_parms->N_RB_DL/2) + 1)*12]; // calculate omega = angle(conj(dl_ch)*dl_ch_prev)) omega = dot_product(dl_ch,dl_ch_prev,((frame_parms->N_RB_DL/2) - 1)*12,dl_ch_shift); omega_cpx->r += ((struct complex16*) &omega)->r; omega_cpx->i += ((struct complex16*) &omega)->i; // phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); phase_offset += atan2((double)omega_cpx->i,(double)omega_cpx->r); // printf("omega (%d,%d) -> %f\n",omega_cpx->r,omega_cpx->i,phase_offset); } // phase_offset /= (frame_parms->nb_antennas_rx*frame_parms->nb_antennas_tx); freq_offset_est = (int) (phase_offset/(2*M_PI)/2.5e-4); //2.5e-4 is the time between pilot symbols // printf("symbol %d : freq_offset_est %d\n",l,freq_offset_est); // update freq_offset with phase_offset using a moving average filter if (first_run == 1) { *freq_offset = freq_offset_est; first_run = 0; } else *freq_offset = ((freq_offset_est * coef) + (*freq_offset * ncoef)) >> 15; //#ifdef DEBUG_PHY // msg("l=%d, phase_offset = %f (%d,%d), freq_offset_est = %d Hz, freq_offset_filt = %d \n",l,phase_offset,omega_cpx->r,omega_cpx->i,freq_offset_est,*freq_offset); /* for (i=0;i<150;i++) msg("i %d : %d,%d <=> %d,%d\n",i,dl_ch[2*i],dl_ch[(2*i)+1],dl_ch_prev[2*i],dl_ch_prev[(2*i)+1]); */ //#endif return(0); }
void rx_ulsch(LTE_eNB_COMMON *eNB_common_vars, LTE_eNB_ULSCH *eNB_ulsch_vars, LTE_DL_FRAME_PARMS *frame_parms, unsigned int subframe, unsigned char eNB_id, // this is the effective sector id LTE_eNB_ULSCH_t *ulsch, u8 cooperation_flag) { unsigned int l,i; int avgs; unsigned char log2_maxh,aarx; int avgs_0,avgs_1; unsigned log2_maxh_0,log2_maxh_1; // unsigned char harq_pid = ( ulsch->RRCConnRequest_flag== 0) ? subframe2harq_pid_tdd(frame_parms->tdd_config,subframe) : 0; unsigned char harq_pid = subframe2harq_pid(frame_parms,subframe); unsigned char Qm = get_Qm(ulsch->harq_processes[harq_pid]->mcs); unsigned short rx_power_correction; #ifdef DEBUG_ULSCH debug_msg("rx_ulsch: eNB_id %d, harq_pid %d, nb_rb %d first_rb %d, cooperation %d\n",eNB_id,harq_pid,ulsch->harq_processes[harq_pid]->nb_rb,ulsch->harq_processes[harq_pid]->first_rb, cooperation_flag); #endif //DEBUG_ULSCH if ( (frame_parms->ofdm_symbol_size == 128) || (frame_parms->ofdm_symbol_size == 512) ) rx_power_correction = 2; else rx_power_correction = 1; for (l=0;l<frame_parms->symbols_per_tti-1;l++) { #ifdef DEBUG_ULSCH msg("rx_ulsch : symbol %d (first_rb %d,nb_rb %d), rxdataF %p, rxdataF_ext %p\n",l, ulsch->harq_processes[harq_pid]->first_rb, ulsch->harq_processes[harq_pid]->nb_rb, eNB_common_vars->rxdataF[eNB_id], eNB_ulsch_vars->rxdataF_ext[eNB_id]); #endif //DEBUG_ULSCH ulsch_extract_rbs_single(eNB_common_vars->rxdataF[eNB_id], eNB_ulsch_vars->rxdataF_ext[eNB_id], ulsch->harq_processes[harq_pid]->first_rb, ulsch->harq_processes[harq_pid]->nb_rb, l%(frame_parms->symbols_per_tti/2), l/(frame_parms->symbols_per_tti/2), frame_parms); lte_ul_channel_estimation(eNB_ulsch_vars->drs_ch_estimates[eNB_id], eNB_ulsch_vars->drs_ch_estimates_time[eNB_id], eNB_ulsch_vars->drs_ch_estimates_0[eNB_id], eNB_ulsch_vars->drs_ch_estimates_1[eNB_id], eNB_ulsch_vars->rxdataF_ext[eNB_id], frame_parms, l%(frame_parms->symbols_per_tti/2), l/(frame_parms->symbols_per_tti/2), ulsch->harq_processes[harq_pid]->nb_rb, ulsch->cyclicShift, cooperation_flag); ulsch_correct_ext(eNB_ulsch_vars->rxdataF_ext[eNB_id], eNB_ulsch_vars->rxdataF_ext2[eNB_id], l, frame_parms, ulsch->harq_processes[harq_pid]->nb_rb); if(cooperation_flag == 2) { for (i=0;i<frame_parms->nb_antennas_rx;i++){ eNB_ulsch_vars->ulsch_power_0[i] = signal_energy_nodc(eNB_ulsch_vars->drs_ch_estimates_0[eNB_id][i], ulsch->harq_processes[harq_pid]->nb_rb*12)*rx_power_correction; eNB_ulsch_vars->ulsch_power_1[i] = signal_energy_nodc(eNB_ulsch_vars->drs_ch_estimates_1[eNB_id][i], ulsch->harq_processes[harq_pid]->nb_rb*12)*rx_power_correction; } } else { for (i=0;i<frame_parms->nb_antennas_rx;i++) eNB_ulsch_vars->ulsch_power[i] = signal_energy_nodc(eNB_ulsch_vars->drs_ch_estimates[eNB_id][i], ulsch->harq_processes[harq_pid]->nb_rb*12)*rx_power_correction; } } if(cooperation_flag == 2) { ulsch_channel_level(eNB_ulsch_vars->drs_ch_estimates_0[eNB_id], frame_parms, avgU_0, ulsch->harq_processes[harq_pid]->nb_rb); // msg("[ULSCH] avg_0[0] %d\n",avgU_0[0]); avgs_0 = 0; for (aarx=0;aarx<frame_parms->nb_antennas_rx;aarx++) avgs_0 = cmax(avgs_0,avgU_0[(aarx<<1)]); log2_maxh_0 = 4+(log2_approx(avgs_0)/2); #ifdef DEBUG_ULSCH msg("[ULSCH] log2_maxh_0 = %d (%d,%d)\n",log2_maxh_0,avgU_0[0],avgs_0); #endif ulsch_channel_level(eNB_ulsch_vars->drs_ch_estimates_1[eNB_id], frame_parms, avgU_1, ulsch->harq_processes[harq_pid]->nb_rb); // msg("[ULSCH] avg_1[0] %d\n",avgU_1[0]); avgs_1 = 0; for (aarx=0;aarx<frame_parms->nb_antennas_rx;aarx++) avgs_1 = cmax(avgs_1,avgU_1[(aarx<<1)]); log2_maxh_1 = 4+(log2_approx(avgs_1)/2); #ifdef DEBUG_ULSCH msg("[ULSCH] log2_maxh_1 = %d (%d,%d)\n",log2_maxh_1,avgU_1[0],avgs_1); #endif } else { ulsch_channel_level(eNB_ulsch_vars->drs_ch_estimates[eNB_id], frame_parms, avgU, ulsch->harq_processes[harq_pid]->nb_rb); // msg("[ULSCH] avg[0] %d\n",avgU[0]); avgs = 0; for (aarx=0;aarx<frame_parms->nb_antennas_rx;aarx++) avgs = cmax(avgs,avgU[(aarx<<1)]); log2_maxh = 2+(log2_approx(avgs)/2); #ifdef DEBUG_ULSCH msg("[ULSCH] log2_maxh = %d (%d,%d)\n",log2_maxh,avgU[0],avgs); #endif } for (l=0;l<frame_parms->symbols_per_tti-1;l++) { if (((frame_parms->Ncp == 0) && ((l==3) || (l==10)))|| // skip pilots ((frame_parms->Ncp == 1) && ((l==2) || (l==8)))) { l++; } if(cooperation_flag == 2) { ulsch_channel_compensation_alamouti(eNB_ulsch_vars->rxdataF_ext2[eNB_id], eNB_ulsch_vars->drs_ch_estimates_0[eNB_id], eNB_ulsch_vars->drs_ch_estimates_1[eNB_id], eNB_ulsch_vars->ul_ch_mag_0[eNB_id], eNB_ulsch_vars->ul_ch_magb_0[eNB_id], eNB_ulsch_vars->ul_ch_mag_1[eNB_id], eNB_ulsch_vars->ul_ch_magb_1[eNB_id], eNB_ulsch_vars->rxdataF_comp_0[eNB_id], eNB_ulsch_vars->rxdataF_comp_1[eNB_id], frame_parms, l, Qm, ulsch->harq_processes[harq_pid]->nb_rb, log2_maxh_0, log2_maxh_1); // log2_maxh+I0_shift ulsch_alamouti(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id], eNB_ulsch_vars->rxdataF_comp_0[eNB_id], eNB_ulsch_vars->rxdataF_comp_1[eNB_id], eNB_ulsch_vars->ul_ch_mag[eNB_id], eNB_ulsch_vars->ul_ch_magb[eNB_id], eNB_ulsch_vars->ul_ch_mag_0[eNB_id], eNB_ulsch_vars->ul_ch_magb_0[eNB_id], eNB_ulsch_vars->ul_ch_mag_1[eNB_id], eNB_ulsch_vars->ul_ch_magb_1[eNB_id], l, ulsch->harq_processes[harq_pid]->nb_rb); } else { ulsch_channel_compensation(eNB_ulsch_vars->rxdataF_ext2[eNB_id], eNB_ulsch_vars->drs_ch_estimates[eNB_id], eNB_ulsch_vars->ul_ch_mag[eNB_id], eNB_ulsch_vars->ul_ch_magb[eNB_id], eNB_ulsch_vars->rxdataF_comp[eNB_id], frame_parms, l, Qm, ulsch->harq_processes[harq_pid]->nb_rb, log2_maxh); // log2_maxh+I0_shift } if (frame_parms->nb_antennas_rx > 1) ulsch_detection_mrc(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id], eNB_ulsch_vars->ul_ch_mag[eNB_id], eNB_ulsch_vars->ul_ch_magb[eNB_id], l, ulsch->harq_processes[harq_pid]->nb_rb); #ifndef OFDMA_ULSCH freq_equalization(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id], eNB_ulsch_vars->ul_ch_mag[eNB_id], eNB_ulsch_vars->ul_ch_magb[eNB_id], l, ulsch->harq_processes[harq_pid]->nb_rb*12, Qm); #endif } #ifndef OFDMA_ULSCH //#ifdef DEBUG_ULSCH // Inverse-Transform equalized outputs // msg("Doing IDFTs\n"); lte_idft(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id][0], ulsch->harq_processes[harq_pid]->nb_rb*12); // msg("Done\n"); //#endif //DEBUG_ULSCH #endif for (l=0;l<frame_parms->symbols_per_tti-1;l++) { if (((frame_parms->Ncp == 0) && ((l==3) || (l==10)))|| // skip pilots ((frame_parms->Ncp == 1) && ((l==2) || (l==8)))) { l++; } switch (Qm) { case 2 : ulsch_qpsk_llr(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id], eNB_ulsch_vars->llr, l, ulsch->harq_processes[harq_pid]->nb_rb); break; case 4 : ulsch_16qam_llr(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id], eNB_ulsch_vars->llr, eNB_ulsch_vars->ul_ch_mag[eNB_id], l,ulsch->harq_processes[harq_pid]->nb_rb); break; case 6 : ulsch_64qam_llr(frame_parms, eNB_ulsch_vars->rxdataF_comp[eNB_id], eNB_ulsch_vars->llr, eNB_ulsch_vars->ul_ch_mag[eNB_id], eNB_ulsch_vars->ul_ch_magb[eNB_id], l,ulsch->harq_processes[harq_pid]->nb_rb); break; default: #ifdef DEBUG_ULSCH msg("ulsch_demodulation.c (rx_ulsch): Unknown Qm!!!!\n"); #endif //DEBUG_ULSCH break; } } }