Increase SSB detection frequency range

master
Xavier Arteaga 3 years ago committed by Xavier Arteaga
parent d4fd4c8350
commit 5b744bb6c5

@ -615,7 +615,11 @@ int srsran_ssb_add(srsran_ssb_t* q, uint32_t N_id, const srsran_pbch_msg_nr_t* m
return SRSRAN_SUCCESS;
}
static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, uint32_t t_offset, cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
static int ssb_demodulate(srsran_ssb_t* q,
const cf_t* in,
uint32_t t_offset,
float coarse_cfo_hz,
cf_t ssb_grid[SRSRAN_SSB_NOF_RE])
{
const cf_t* in_ptr = &in[t_offset];
for (uint32_t l = 0; l < SRSRAN_SSB_DURATION_NSYMB; l++) {
@ -623,11 +627,16 @@ static int ssb_demodulate(srsran_ssb_t* q, const cf_t* in, uint32_t t_offset, cf
in_ptr += SRSRAN_FLOOR(q->cp_sz, 2);
// Copy FFT window in temporal time domain buffer
srsran_vec_cf_copy(q->tmp_time, in_ptr, q->symbol_sz);
if (isnormal(coarse_cfo_hz)) {
srsran_vec_apply_cfo(in_ptr, (float)(-coarse_cfo_hz / q->cfg.srate_hz), q->tmp_time, q->symbol_sz);
} else {
srsran_vec_cf_copy(q->tmp_time, in_ptr, q->symbol_sz);
}
in_ptr += q->symbol_sz + SRSRAN_CEIL(q->cp_sz, 2);
// Phase compensation
cf_t phase_compensation = (cf_t)cexp(-I * 2.0 * M_PI * q->cfg.center_freq_hz * (double)t_offset / q->cfg.srate_hz);
cf_t phase_compensation =
(cf_t)cexp(-I * 2.0 * M_PI * (q->cfg.center_freq_hz - coarse_cfo_hz) * (double)t_offset / q->cfg.srate_hz);
t_offset += q->symbol_sz + q->cp_sz;
// Convert to frequency domain
@ -750,18 +759,60 @@ ssb_measure(srsran_ssb_t* q, const cf_t ssb_grid[SRSRAN_SSB_NOF_RE], uint32_t N_
return SRSRAN_SUCCESS;
}
static int
ssb_pss_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, uint32_t* found_N_id_2, uint32_t* found_delay)
static void ssb_vec_prod_conj_circ_shift(const cf_t* a, const cf_t* b, cf_t* c, uint32_t n, int shift)
{
uint32_t offset = (uint32_t)abs(shift);
// Avoid negative number of samples
if (offset > n) {
srsran_vec_cf_zero(c, n);
return;
}
// Shift is negative
if (shift < 0) {
srsran_vec_prod_conj_ccc(&a[offset], &b[0], &c[0], n - offset);
srsran_vec_prod_conj_ccc(&a[0], &b[n - offset], &c[n - offset], offset);
return;
}
// Shift is positive
if (shift > 0) {
srsran_vec_prod_conj_ccc(&a[0], &b[offset], &c[0], n - offset);
srsran_vec_prod_conj_ccc(&a[n - offset], &b[0], &c[n - offset], offset);
return;
}
// Shift is zero
srsran_vec_prod_conj_ccc(a, b, c, n);
}
static int ssb_pss_search(srsran_ssb_t* q,
const cf_t* in,
uint32_t nof_samples,
uint32_t* found_N_id_2,
uint32_t* found_delay,
float* coarse_cfo_hz)
{
// verify it is initialised
if (q->corr_sz == 0) {
return SRSRAN_ERROR;
}
// Calculate correlation CFO coarse precision
double coarse_cfo_ref_hz = (q->cfg.srate_hz / q->corr_sz);
// Calculate shift integer range to detect the signal with a maximum CFO equal to the SSB subcarrier spacing
int shift_range = (int)ceil(SRSRAN_SUBC_SPACING_NR(q->cfg.scs) / coarse_cfo_ref_hz);
// Calculate the coarse shift increment for half of the subcarrier spacing
int shift_coarse_inc = shift_range / 2;
// Correlation best sequence
float best_corr = 0;
uint32_t best_delay = 0;
uint32_t best_N_id_2 = 0;
int best_shift = 0;
// Delay in correlation window
uint32_t t_offset = 0;
@ -787,39 +838,70 @@ ssb_pss_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, uint32_t*
// Try each N_id_2 sequence
for (uint32_t N_id_2 = 0; N_id_2 < SRSRAN_NOF_NID_2_NR; N_id_2++) {
// Actual correlation in frequency domain
srsran_vec_prod_conj_ccc(q->tmp_freq, q->pss_seq[N_id_2], q->tmp_corr, q->corr_sz);
// Steer coarse frequency offset
for (int shift = -shift_range; shift <= shift_range; shift += shift_coarse_inc) {
// Actual correlation in frequency domain
ssb_vec_prod_conj_circ_shift(q->tmp_freq, q->pss_seq[N_id_2], q->tmp_corr, q->corr_sz, shift);
// Convert to time domain
srsran_dft_run_guru_c(&q->ifft_corr);
// Find maximum
uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window);
// Average power, skip window if value is invalid (0.0, nan or inf)
float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz);
if (!isnormal(avg_pwr_corr)) {
continue;
}
// Normalise correlation
float corr = SRSRAN_CSQABS(q->tmp_time[peak_idx]) / avg_pwr_corr / sqrtf(SRSRAN_PSS_NR_LEN);
// Update if the correlation is better than the current best
if (best_corr < corr) {
best_corr = corr;
best_delay = peak_idx + t_offset;
best_N_id_2 = N_id_2;
best_shift = shift;
}
}
}
// Convert to time domain
srsran_dft_run_guru_c(&q->ifft_corr);
// Advance time
t_offset += q->corr_window;
}
// Find maximum
uint32_t peak_idx = srsran_vec_max_abs_ci(q->tmp_time, q->corr_window);
// From the best sequence correlate in frequency domain
{
// Reset best correlation
best_corr = 0.0f;
// Average power, skip window if value is invalid (0.0, nan or inf)
float avg_pwr_corr = srsran_vec_avg_power_cf(&q->tmp_time[peak_idx], q->symbol_sz);
if (!isnormal(avg_pwr_corr)) {
continue;
}
// Copy the amount of samples
srsran_vec_cf_copy(q->tmp_time, &in[best_delay], q->corr_sz);
// Normalise correlation
float corr = SRSRAN_CSQABS(q->tmp_time[peak_idx]) / avg_pwr_corr / sqrtf(SRSRAN_PSS_NR_LEN);
// Convert to frequency domain
srsran_dft_run_guru_c(&q->fft_corr);
for (int shift = -shift_range; shift <= shift_range; shift++) {
// Actual correlation in frequency domain
ssb_vec_prod_conj_circ_shift(q->tmp_freq, q->pss_seq[best_N_id_2], q->tmp_corr, q->corr_sz, shift);
// Calculate correlation assuming the peak is in the first sample
float corr = SRSRAN_CSQABS(srsran_vec_acc_cc(q->tmp_corr, q->corr_sz));
// Update if the correlation is better than the current best
if (best_corr < corr) {
best_corr = corr;
best_delay = peak_idx + t_offset;
best_N_id_2 = N_id_2;
best_corr = corr;
best_shift = shift;
}
}
// Advance time
t_offset += q->corr_window;
}
// Save findings
*found_delay = best_delay;
*found_N_id_2 = best_N_id_2;
*found_delay = best_delay;
*found_N_id_2 = best_N_id_2;
*coarse_cfo_hz = -(float)best_shift * coarse_cfo_ref_hz;
return SRSRAN_SUCCESS;
}
@ -848,9 +930,10 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
nof_samples -= (q->symbol_sz + q->cp_sz) * SRSRAN_SSB_DURATION_NSYMB;
// Search for PSS in time domain
uint32_t N_id_2 = 0;
uint32_t t_offset = 0;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset) < SRSRAN_SUCCESS) {
uint32_t N_id_2 = 0;
uint32_t t_offset = 0;
float coarse_cfo_hz = 0.0f;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset, &coarse_cfo_hz) < SRSRAN_SUCCESS) {
ERROR("Error searching for N_id_2");
return SRSRAN_ERROR;
}
@ -864,7 +947,7 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
// Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, t_offset, ssb_grid) < SRSRAN_SUCCESS) {
if (ssb_demodulate(q, in, t_offset, coarse_cfo_hz, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating");
return SRSRAN_ERROR;
}
@ -888,6 +971,7 @@ int srsran_ssb_csi_search(srsran_ssb_t* q,
// Add delay to measure
meas->delay_us += (float)(1e6 * t_offset / q->cfg.srate_hz);
meas->cfo_hz -= coarse_cfo_hz;
return SRSRAN_SUCCESS;
}
@ -916,7 +1000,7 @@ int srsran_ssb_csi_measure(srsran_ssb_t* q,
// Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, (uint32_t)t_offset, ssb_grid) < SRSRAN_SUCCESS) {
if (ssb_demodulate(q, in, (uint32_t)t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating");
return SRSRAN_ERROR;
}
@ -1045,7 +1129,7 @@ int srsran_ssb_decode_pbch(srsran_ssb_t* q,
// Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, (uint32_t)t_offset, ssb_grid) < SRSRAN_SUCCESS) {
if (ssb_demodulate(q, in, (uint32_t)t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating");
return SRSRAN_ERROR;
}
@ -1074,9 +1158,10 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
}
// Search for PSS in time domain
uint32_t N_id_2 = 0;
uint32_t t_offset = 0;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset) < SRSRAN_SUCCESS) {
uint32_t N_id_2 = 0;
uint32_t t_offset = 0;
float coarse_cfo_hz = 0.0f;
if (ssb_pss_search(q, in, nof_samples, &N_id_2, &t_offset, &coarse_cfo_hz) < SRSRAN_SUCCESS) {
ERROR("Error searching for N_id_2");
return SRSRAN_ERROR;
}
@ -1090,7 +1175,7 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
// Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, in, t_offset, ssb_grid) < SRSRAN_SUCCESS) {
if (ssb_demodulate(q, in, t_offset, coarse_cfo_hz, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating");
return SRSRAN_ERROR;
}
@ -1132,6 +1217,7 @@ int srsran_ssb_search(srsran_ssb_t* q, const cf_t* in, uint32_t nof_samples, srs
res->t_offset = t_offset;
res->pbch_msg = pbch_msg;
res->measurements = measurements;
res->measurements.cfo_hz += coarse_cfo_hz;
return SRSRAN_SUCCESS;
}
@ -1241,7 +1327,7 @@ int srsran_ssb_find(srsran_ssb_t* q,
// Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, q->sf_buffer, t_offset, ssb_grid) < SRSRAN_SUCCESS) {
if (ssb_demodulate(q, q->sf_buffer, t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating");
return SRSRAN_ERROR;
}
@ -1301,7 +1387,7 @@ int srsran_ssb_track(srsran_ssb_t* q,
// Demodulate
cf_t ssb_grid[SRSRAN_SSB_NOF_RE] = {};
if (ssb_demodulate(q, sf_buffer, t_offset, ssb_grid) < SRSRAN_SUCCESS) {
if (ssb_demodulate(q, sf_buffer, t_offset, 0.0f, ssb_grid) < SRSRAN_SUCCESS) {
ERROR("Error demodulating");
return SRSRAN_ERROR;
}

Loading…
Cancel
Save