working version of FFO estimation
This commit is contained in:
@@ -137,7 +137,8 @@ int set_pss_nr(int ofdm_symbol_size);
|
|||||||
int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int rate_change);
|
int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int rate_change);
|
||||||
int pss_search_time_nr(int **rxdata, ///rx data in time domain
|
int pss_search_time_nr(int **rxdata, ///rx data in time domain
|
||||||
NR_DL_FRAME_PARMS *frame_parms,
|
NR_DL_FRAME_PARMS *frame_parms,
|
||||||
int *eNB_id);
|
int *eNB_id,
|
||||||
|
int *f_off);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
|
|||||||
@@ -244,7 +244,8 @@ int nr_initial_sync(PHY_VARS_NR_UE *ue, runmode_t mode)
|
|||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consider this is a false detection if the offset is > 1000 Hz */
|
/* Consider this is a false detection if the offset is > 1000 Hz
|
||||||
|
Not to be used now that offest estimation is in place
|
||||||
if( (abs(ue->common_vars.freq_offset) > 150) && (ret == 0) )
|
if( (abs(ue->common_vars.freq_offset) > 150) && (ret == 0) )
|
||||||
{
|
{
|
||||||
ret=-1;
|
ret=-1;
|
||||||
@@ -253,7 +254,7 @@ int nr_initial_sync(PHY_VARS_NR_UE *ue, runmode_t mode)
|
|||||||
#else
|
#else
|
||||||
LOG_E(HW, "Ignore MIB with high freq offset [%d Hz] estimation \n",ue->common_vars.freq_offset);
|
LOG_E(HW, "Ignore MIB with high freq offset [%d Hz] estimation \n",ue->common_vars.freq_offset);
|
||||||
#endif
|
#endif
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (ret==0) { // PBCH found so indicate sync to higher layers and configure frame parameters
|
if (ret==0) { // PBCH found so indicate sync to higher layers and configure frame parameters
|
||||||
|
|
||||||
|
|||||||
@@ -706,7 +706,9 @@ int pss_synchro_nr(PHY_VARS_NR_UE *PHY_vars_UE, int rate_change)
|
|||||||
|
|
||||||
synchro_position = pss_search_time_nr(rxdata,
|
synchro_position = pss_search_time_nr(rxdata,
|
||||||
frame_parms,
|
frame_parms,
|
||||||
(int *)&PHY_vars_UE->common_vars.eNb_id);
|
(int *)&PHY_vars_UE->common_vars.eNb_id,
|
||||||
|
(int *)&PHY_vars_UE->common_vars.freq_offset);
|
||||||
|
|
||||||
|
|
||||||
#if TEST_SYNCHRO_TIMING_PSS
|
#if TEST_SYNCHRO_TIMING_PSS
|
||||||
|
|
||||||
@@ -815,11 +817,12 @@ static inline double angle64(int64_t x)
|
|||||||
|
|
||||||
int pss_search_time_nr(int **rxdata, ///rx data in time domain
|
int pss_search_time_nr(int **rxdata, ///rx data in time domain
|
||||||
NR_DL_FRAME_PARMS *frame_parms,
|
NR_DL_FRAME_PARMS *frame_parms,
|
||||||
int *eNB_id)
|
int *eNB_id,
|
||||||
|
int *f_off)
|
||||||
{
|
{
|
||||||
unsigned int n, ar, peak_position, pss_source;
|
unsigned int n, ar, peak_position, pss_source;
|
||||||
int64_t peak_value;
|
int64_t peak_value;
|
||||||
int64_t result;
|
int64_t result,result1,result2;
|
||||||
int64_t avg[NUMBER_PSS_SEQUENCE];
|
int64_t avg[NUMBER_PSS_SEQUENCE];
|
||||||
double ffo_est;
|
double ffo_est;
|
||||||
|
|
||||||
@@ -842,7 +845,6 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain
|
|||||||
maxval = max(maxval,-primary_synchro_time_nr[1][i]);
|
maxval = max(maxval,-primary_synchro_time_nr[1][i]);
|
||||||
maxval = max(maxval,primary_synchro_time_nr[2][i]);
|
maxval = max(maxval,primary_synchro_time_nr[2][i]);
|
||||||
maxval = max(maxval,-primary_synchro_time_nr[2][i]);
|
maxval = max(maxval,-primary_synchro_time_nr[2][i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
int shift = log2_approx(maxval);//*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2);
|
int shift = log2_approx(maxval);//*(frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples)*2);
|
||||||
|
|
||||||
@@ -877,27 +879,58 @@ int pss_search_time_nr(int **rxdata, ///rx data in time domain
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate the absolute value of sync_corr[n] */
|
/* calculate the absolute value of sync_corr[n] */
|
||||||
avg[pss_index]+=pss_corr_ue[pss_index][n];
|
avg[pss_index]+=pss_corr_ue[pss_index][n];
|
||||||
if (pss_corr_ue[pss_index][n] > peak_value) {
|
if (pss_corr_ue[pss_index][n] > peak_value) {
|
||||||
peak_value = pss_corr_ue[pss_index][n];
|
peak_value = pss_corr_ue[pss_index][n];
|
||||||
peak_position = n;
|
peak_position = n;
|
||||||
pss_source = pss_index;
|
pss_source = pss_index;
|
||||||
ffo_est = angle64(result)/M_PI;
|
|
||||||
|
|
||||||
//#ifdef DEBUG_PSS_NR
|
#ifdef DEBUG_PSS_NR
|
||||||
printf("pss_index %d: n %6d peak_value %15llu ffo %lf\n", pss_index, n, (unsigned long long)pss_corr_ue[pss_index][n],ffo_est);
|
printf("pss_index %d: n %6d peak_value %15llu\n", pss_index, n, (unsigned long long)pss_corr_ue[pss_index][n]);
|
||||||
//#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fractional frequency offser computation according to Cross-correlation Synchronization Algorithm Using PSS
|
||||||
|
// Shoujun Huang, Yongtao Su, Ying He and Shan Tang, "Joint time and frequency offset estimation in LTE downlink," 7th International Conference on Communications and Networking in China, 2012.
|
||||||
|
|
||||||
|
// Computing cross-correlation at peak on half the symbol size for first half of data
|
||||||
|
result1 = dot_product64((short*)primary_synchro_time_nr[pss_source],
|
||||||
|
(short*) &(rxdata[0][peak_position]),
|
||||||
|
frame_parms->ofdm_symbol_size>>1,
|
||||||
|
shift);
|
||||||
|
// Computing cross-correlation at peak on half the symbol size for data shifted by half symbol size
|
||||||
|
// as it is real and complex it is necessary to shift by a value equal to symbol size to obtain such shift
|
||||||
|
result2 = dot_product64((short*)primary_synchro_time_nr[pss_source]+(frame_parms->ofdm_symbol_size),
|
||||||
|
(short*) &(rxdata[0][peak_position])+(frame_parms->ofdm_symbol_size),
|
||||||
|
frame_parms->ofdm_symbol_size>>1,
|
||||||
|
shift);
|
||||||
|
|
||||||
|
int64_t re1,re2,im1,im2;
|
||||||
|
re1=((int*) &result1)[0];
|
||||||
|
re2=((int*) &result2)[0];
|
||||||
|
im1=((int*) &result1)[1];
|
||||||
|
im2=((int*) &result2)[1];
|
||||||
|
|
||||||
|
// estimation of fractional frequency offset: angle[(result1)'*(result2)]/pi
|
||||||
|
ffo_est=atan2(re1*im2-re2*im1,re1*re2+im1*im2)/M_PI;
|
||||||
|
|
||||||
|
#ifdef DBG_PSS_NR
|
||||||
|
printf("ffo %lf\n",ffo_est);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// computing absolute value of frequency offset
|
||||||
|
*f_off = ffo_est*frame_parms->subcarrier_spacing;
|
||||||
|
|
||||||
for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) avg[pss_index]/=(length/4);
|
for (int pss_index = 0; pss_index < NUMBER_PSS_SEQUENCE; pss_index++) avg[pss_index]/=(length/4);
|
||||||
|
|
||||||
*eNB_id = pss_source;
|
*eNB_id = pss_source;
|
||||||
|
|
||||||
LOG_I(PHY,"[UE] nr_synchro_time: Sync source = %d, Peak found at pos %d, val = %llu (%d dB) avg %d dB\n", pss_source, peak_position, (unsigned long long)peak_value, dB_fixed64(peak_value),dB_fixed64(avg[pss_source]));
|
LOG_I(PHY,"[UE] nr_synchro_time: Sync source = %d, Peak found at pos %d, val = %llu (%d dB) avg %d dB, ffo %lf\n", pss_source, peak_position, (unsigned long long)peak_value, dB_fixed64(peak_value),dB_fixed64(avg[pss_source]),ffo_est);
|
||||||
|
|
||||||
if (peak_value < 5*avg[pss_source])
|
if (peak_value < 5*avg[pss_source])
|
||||||
return(-1);
|
return(-1);
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
* contact@openairinterface.org
|
* contact@openairinterface.org
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "tools_defs.h"
|
#include "tools_defs.h"
|
||||||
#include "PHY/sse_intrin.h"
|
#include "PHY/sse_intrin.h"
|
||||||
|
|
||||||
|
|||||||
@@ -139,20 +139,20 @@ void nr_common_signal_procedures (PHY_VARS_gNB *gNB,int frame, int subframe) {
|
|||||||
LOG_D(PHY,"SS TX: frame %d, subframe %d, start_symbol %d\n",frame,subframe, ssb_start_symbol);
|
LOG_D(PHY,"SS TX: frame %d, subframe %d, start_symbol %d\n",frame,subframe, ssb_start_symbol);
|
||||||
|
|
||||||
nr_generate_pss(gNB->d_pss, txdataF, AMP, ssb_start_symbol, cfg, fp);
|
nr_generate_pss(gNB->d_pss, txdataF, AMP, ssb_start_symbol, cfg, fp);
|
||||||
nr_generate_sss(gNB->d_sss, txdataF, AMP_OVER_2, ssb_start_symbol, cfg, fp);
|
nr_generate_sss(gNB->d_sss, txdataF, AMP, ssb_start_symbol, cfg, fp);
|
||||||
|
|
||||||
if (!(frame&7)){
|
if (!(frame&7)){
|
||||||
LOG_D(PHY,"%d.%d : pbch_configured %d\n",frame,subframe,gNB->pbch_configured);
|
LOG_D(PHY,"%d.%d : pbch_configured %d\n",frame,subframe,gNB->pbch_configured);
|
||||||
if (gNB->pbch_configured != 1)return;
|
if (gNB->pbch_configured != 1)return;
|
||||||
gNB->pbch_configured = 0;
|
gNB->pbch_configured = 0;
|
||||||
}
|
}
|
||||||
nr_generate_pbch_dmrs(gNB->nr_gold_pbch_dmrs[n_hf][ssb_index],txdataF, AMP_OVER_2, ssb_start_symbol, cfg, fp);
|
nr_generate_pbch_dmrs(gNB->nr_gold_pbch_dmrs[n_hf][ssb_index],txdataF, AMP, ssb_start_symbol, cfg, fp);
|
||||||
nr_generate_pbch(&gNB->pbch,
|
nr_generate_pbch(&gNB->pbch,
|
||||||
gNB->nrPolar_params,
|
gNB->nrPolar_params,
|
||||||
pbch_pdu,
|
pbch_pdu,
|
||||||
gNB->nr_pbch_interleaver,
|
gNB->nr_pbch_interleaver,
|
||||||
txdataF,
|
txdataF,
|
||||||
AMP_OVER_2,
|
AMP,
|
||||||
ssb_start_symbol,
|
ssb_start_symbol,
|
||||||
n_hf,Lmax,ssb_index,
|
n_hf,Lmax,ssb_index,
|
||||||
frame, cfg, fp);
|
frame, cfg, fp);
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
double pbch_sinr;
|
double pbch_sinr;
|
||||||
int pbch_tx_ant;
|
int pbch_tx_ant;
|
||||||
int N_RB_DL=106,mu=1;
|
int N_RB_DL=273,mu=1;
|
||||||
|
|
||||||
unsigned char frame_type = 0;
|
unsigned char frame_type = 0;
|
||||||
unsigned char pbch_phase = 0;
|
unsigned char pbch_phase = 0;
|
||||||
@@ -538,7 +538,6 @@ int main(int argc, char **argv)
|
|||||||
sigma2_dB = 10*log10((double)txlev)-SNR;
|
sigma2_dB = 10*log10((double)txlev)-SNR;
|
||||||
sigma2 = pow(10,sigma2_dB/10);
|
sigma2 = pow(10,sigma2_dB/10);
|
||||||
// printf("sigma2 %f (%f dB)\n",sigma2,sigma2_dB);
|
// printf("sigma2 %f (%f dB)\n",sigma2,sigma2_dB);
|
||||||
|
|
||||||
if(eps!=0.0)
|
if(eps!=0.0)
|
||||||
rf_rx(r_re, // real part of txdata
|
rf_rx(r_re, // real part of txdata
|
||||||
r_im, // imag part of txdata
|
r_im, // imag part of txdata
|
||||||
|
|||||||
@@ -444,6 +444,7 @@ static void *UE_thread_synch(void *arg) {
|
|||||||
|
|
||||||
//write_output("txdata_sym.m", "txdata_sym", UE->common_vars.rxdata[0], (10*UE->frame_parms.samples_per_subframe), 1, 1);
|
//write_output("txdata_sym.m", "txdata_sym", UE->common_vars.rxdata[0], (10*UE->frame_parms.samples_per_subframe), 1, 1);
|
||||||
|
|
||||||
|
freq_offset = UE->common_vars.freq_offset; // frequency offset computed with pss in initial sync
|
||||||
hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_subframe;
|
hw_slot_offset = (UE->rx_offset<<1) / UE->frame_parms.samples_per_subframe;
|
||||||
printf("Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %u, UL %u), UE_scan_carrier %d\n",
|
printf("Got synch: hw_slot_offset %d, carrier off %d Hz, rxgain %d (DL %u, UL %u), UE_scan_carrier %d\n",
|
||||||
hw_slot_offset,
|
hw_slot_offset,
|
||||||
@@ -459,13 +460,13 @@ static void *UE_thread_synch(void *arg) {
|
|||||||
openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
|
openair0_cfg[UE->rf_map.card].rx_gain[UE->rf_map.chain+i] = UE->rx_total_gain_dB;//-USRP_GAIN_OFFSET;
|
||||||
if (UE->UE_scan_carrier == 1) {
|
if (UE->UE_scan_carrier == 1) {
|
||||||
if (freq_offset >= 0)
|
if (freq_offset >= 0)
|
||||||
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] += abs(UE->common_vars.freq_offset);
|
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] += abs(freq_offset);
|
||||||
else
|
else
|
||||||
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] -= abs(UE->common_vars.freq_offset);
|
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i] -= abs(freq_offset);
|
||||||
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
|
openair0_cfg[UE->rf_map.card].tx_freq[UE->rf_map.chain+i] =
|
||||||
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i]+uplink_frequency_offset[CC_id][i];
|
openair0_cfg[UE->rf_map.card].rx_freq[UE->rf_map.chain+i]+uplink_frequency_offset[CC_id][i];
|
||||||
downlink_frequency[CC_id][i] = openair0_cfg[CC_id].rx_freq[i];
|
downlink_frequency[CC_id][i] = openair0_cfg[CC_id].rx_freq[i];
|
||||||
freq_offset=0;
|
//freq_offset=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user