even if 2 codewords are currently not supported and not tested, the way UE handled the possibility of having 2 codewords was messy, in between support and non-support the intention of this MR is to cleanup the code more than extend the support Signed-off-by: Francesco Mani <email@francescomani.it>
534 lines
21 KiB
C
534 lines
21 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
/*!
|
|
* \brief Routines for initial UE synchronization procedure (PSS,SSS,PBCH and frame format detection)
|
|
*/
|
|
#include "PHY/defs_nr_UE.h"
|
|
#include "PHY/MODULATION/modulation_UE.h"
|
|
#include "nr_transport_proto_ue.h"
|
|
#include "PHY/NR_UE_ESTIMATION/nr_estimation.h"
|
|
#include "SCHED_NR_UE/defs.h"
|
|
#include "common/utils/nr/nr_common.h"
|
|
|
|
#include "common_lib.h"
|
|
#include <math.h>
|
|
|
|
#include "PHY/NR_REFSIG/pss_nr.h"
|
|
#include "PHY/NR_REFSIG/sss_nr.h"
|
|
#include "PHY/NR_REFSIG/nr_refsig.h"
|
|
#include "PHY/TOOLS/tools_defs.h"
|
|
#include "nr-uesoftmodem.h"
|
|
|
|
//#define DEBUG_INITIAL_SYNCH
|
|
#define DUMP_PBCH_CH_ESTIMATES 0
|
|
|
|
// structure used for multiple SSB detection
|
|
typedef struct NR_UE_SSB {
|
|
uint i_ssb; // i_ssb between 0 and 7 (it corresponds to ssb_index only for Lmax=4,8)
|
|
uint n_hf; // n_hf = 0,1 for Lmax =4 or n_hf = 0 for Lmax =8,64
|
|
double metric; // metric to order SSB hypothesis
|
|
} NR_UE_SSB;
|
|
|
|
static int ssb_sort(const void *a, const void *b)
|
|
{
|
|
return ((NR_UE_SSB *)b)->metric - ((NR_UE_SSB *)a)->metric;
|
|
}
|
|
|
|
static bool nr_pbch_detection(const UE_nr_rxtx_proc_t *proc,
|
|
const NR_DL_FRAME_PARMS *frame_parms,
|
|
int Nid_cell,
|
|
int pbch_initial_symbol,
|
|
int ssb_start_subcarrier,
|
|
int *half_frame_bit,
|
|
int *ssb_index,
|
|
int *symbol_offset,
|
|
fapiPbch_t *result,
|
|
const c16_t rxdataF[][frame_parms->samples_per_slot_wCP])
|
|
{
|
|
const int N_L = (frame_parms->Lmax == 4) ? 4 : 8;
|
|
const int N_hf = (frame_parms->Lmax == 4) ? 2 : 1;
|
|
NR_UE_SSB best_ssb[N_L * N_hf];
|
|
NR_UE_SSB *current_ssb = best_ssb;
|
|
// loops over possible pbch dmrs cases to retrieve best estimated i_ssb (and n_hf for Lmax=4) for multiple ssb detection
|
|
for (int hf = 0; hf < N_hf; hf++) {
|
|
for (int l = 0; l < N_L; l++) {
|
|
// computing correlation between received DMRS symbols and transmitted sequence for current i_ssb and n_hf
|
|
cd_t cumul = {0};
|
|
for (int i = pbch_initial_symbol; i < pbch_initial_symbol + 3; i++) {
|
|
c32_t meas = nr_pbch_dmrs_correlation(frame_parms,
|
|
i,
|
|
i - pbch_initial_symbol,
|
|
Nid_cell,
|
|
ssb_start_subcarrier,
|
|
nr_gold_pbch(frame_parms->Lmax, Nid_cell, hf, l),
|
|
rxdataF);
|
|
csum(cumul, cumul, meas);
|
|
}
|
|
*current_ssb = (NR_UE_SSB){.i_ssb = l, .n_hf = hf, .metric = squaredMod(cumul)};
|
|
current_ssb++;
|
|
}
|
|
}
|
|
qsort(best_ssb, N_L * N_hf, sizeof(NR_UE_SSB), ssb_sort);
|
|
|
|
const int nb_ant = frame_parms->nb_antennas_rx;
|
|
for (NR_UE_SSB *ssb = best_ssb; ssb < best_ssb + N_L * N_hf; ssb++) {
|
|
// computing channel estimation for selected best ssb
|
|
const int estimateSz = frame_parms->symbols_per_slot * frame_parms->ofdm_symbol_size;
|
|
__attribute__((aligned(32))) c16_t dl_ch_estimates[nb_ant][estimateSz];
|
|
__attribute__((aligned(32))) c16_t dl_ch_estimates_time[nb_ant][frame_parms->ofdm_symbol_size];
|
|
|
|
for(int i=pbch_initial_symbol; i<pbch_initial_symbol+3;i++)
|
|
nr_pbch_channel_estimation(frame_parms,
|
|
NULL,
|
|
estimateSz,
|
|
dl_ch_estimates,
|
|
dl_ch_estimates_time,
|
|
proc,
|
|
i,
|
|
i - pbch_initial_symbol,
|
|
ssb->i_ssb,
|
|
ssb->n_hf,
|
|
ssb_start_subcarrier,
|
|
rxdataF,
|
|
false,
|
|
Nid_cell);
|
|
|
|
if (0
|
|
== nr_rx_pbch(NULL,
|
|
proc,
|
|
false,
|
|
estimateSz,
|
|
dl_ch_estimates,
|
|
frame_parms,
|
|
ssb->i_ssb,
|
|
ssb_start_subcarrier,
|
|
Nid_cell,
|
|
result,
|
|
half_frame_bit,
|
|
ssb_index,
|
|
symbol_offset,
|
|
frame_parms->samples_per_frame_wCP,
|
|
rxdataF)) {
|
|
if (DUMP_PBCH_CH_ESTIMATES) {
|
|
write_output("pbch_ch_estimates.m", "pbch_ch_estimates", dl_ch_estimates, nb_ant * estimateSz, 1, 1);
|
|
write_output("pbch_ch_estimates_time.m",
|
|
"pbch_ch_estimates_time",
|
|
dl_ch_estimates_time,
|
|
nb_ant * frame_parms->ofdm_symbol_size,
|
|
1,
|
|
1);
|
|
}
|
|
LOG_A(PHY, "Initial sync: pbch decoded sucessfully, ssb index %d\n", *ssb_index);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
LOG_W(PHY, "Initial sync: pbch not decoded, ssb index %d\n", frame_parms->ssb_index);
|
|
return false;
|
|
}
|
|
|
|
static void compensate_freq_offset(c16_t **x, const NR_DL_FRAME_PARMS *fp, const int offset, const int sn)
|
|
{
|
|
double s_time = 1 / (1.0e3 * fp->samples_per_subframe); // sampling time
|
|
double off_angle = -2 * M_PI * s_time * (offset); // offset rotation angle compensation per sample
|
|
|
|
for (int n = sn * fp->samples_per_frame; n < (sn + 1) * fp->samples_per_frame; n++) {
|
|
for (int ar = 0; ar < fp->nb_antennas_rx; ar++) {
|
|
const double re = x[ar][n].r;
|
|
const double im = x[ar][n].i;
|
|
x[ar][n].r = (short)(round(re * cos(n * off_angle) - im * sin(n * off_angle)));
|
|
x[ar][n].i = (short)(round(re * sin(n * off_angle) + im * cos(n * off_angle)));
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Common SSB search function used by both initial sync and neighbor cell search
|
|
*/
|
|
bool nr_search_ssb_common(nr_ssb_search_params_t *params)
|
|
{
|
|
const NR_DL_FRAME_PARMS *fp = params->frame_parms;
|
|
|
|
const uint32_t pssTime_sz = fp->ofdm_symbol_size;
|
|
c16_t(*pssTime)[pssTime_sz] = (c16_t(*)[pssTime_sz])params->pssTime;
|
|
|
|
// Perform PSS search
|
|
int nid2 = -1;
|
|
int freq_offset_pss = 0;
|
|
int pss_peak = 0;
|
|
int pss_avg = 0;
|
|
const int sync_pos = pss_synchro_nr((const c16_t **)params->rxdata,
|
|
fp,
|
|
pssTime,
|
|
params->search_frame_id,
|
|
params->fo_flag,
|
|
params->target_nid_cell,
|
|
&nid2,
|
|
&freq_offset_pss,
|
|
&pss_peak,
|
|
&pss_avg);
|
|
|
|
if (params->pss_peak)
|
|
*params->pss_peak = pss_peak;
|
|
if (params->pss_avg)
|
|
*params->pss_avg = pss_avg;
|
|
if (params->freq_offset_pss)
|
|
*params->freq_offset_pss = freq_offset_pss;
|
|
|
|
if (sync_pos < fp->nb_prefix_samples || nid2 < 0) {
|
|
return false;
|
|
}
|
|
|
|
const int ssb_offset = sync_pos - fp->nb_prefix_samples;
|
|
if (params->ssb_offset)
|
|
*params->ssb_offset = ssb_offset;
|
|
|
|
#ifdef DEBUG_INITIAL_SYNCH
|
|
LOG_I(PHY, "Initial sync : Estimated PSS position %d, Nid2 %d, ssb offset %d\n", sync_pos, nid2, ssb_offset);
|
|
#endif
|
|
|
|
// Check that SSB fits within buffer
|
|
if (ssb_offset + NR_N_SYMBOLS_SSB * (fp->ofdm_symbol_size + fp->nb_prefix_samples) >= params->rxdata_size) {
|
|
LOG_D(PHY,
|
|
"SSB extends beyond buffer boundary (sync_pos %d, ssb_offset %d, buffer_size %d)\n",
|
|
sync_pos,
|
|
ssb_offset,
|
|
params->rxdata_size);
|
|
return false;
|
|
}
|
|
|
|
// Apply frequency offset compensation if requested
|
|
if (params->apply_freq_offset && freq_offset_pss != 0) {
|
|
compensate_freq_offset(params->rxdata, fp, freq_offset_pss, params->search_frame_id);
|
|
}
|
|
|
|
// Extract SSB symbols to frequency domain
|
|
// Symbol ordering: 0=PSS, 1=PBCH, 2=SSS, 3=PBCH
|
|
const uint32_t rxdataF_sz = fp->samples_per_slot_wCP;
|
|
c16_t(*rxdataF)[rxdataF_sz] = (c16_t(*)[rxdataF_sz])params->rxdataF;
|
|
const int sample_offset = params->search_frame_id * fp->samples_per_frame + ssb_offset;
|
|
for (int i = 0; i < NR_N_SYMBOLS_SSB; i++) {
|
|
nr_slot_fep(NULL, fp, 0, i, rxdataF, link_type_dl, sample_offset, (c16_t **)params->rxdata);
|
|
}
|
|
|
|
// Perform SSS detection
|
|
int detected_nid_cell = -1;
|
|
int32_t sss_metric = 0;
|
|
uint8_t sss_phase = 0;
|
|
int freq_offset_sss = 0;
|
|
|
|
bool sss_detected = rx_sss_nr(fp,
|
|
nid2,
|
|
params->target_nid_cell,
|
|
freq_offset_pss,
|
|
params->ssb_start_subcarrier,
|
|
&detected_nid_cell,
|
|
&sss_metric,
|
|
&sss_phase,
|
|
&freq_offset_sss,
|
|
rxdataF);
|
|
|
|
if (params->sss_metric)
|
|
*params->sss_metric = sss_metric;
|
|
if (params->sss_phase)
|
|
*params->sss_phase = sss_phase;
|
|
if (params->freq_offset_sss)
|
|
*params->freq_offset_sss = freq_offset_sss;
|
|
|
|
if (!sss_detected || detected_nid_cell < 0) {
|
|
return false;
|
|
}
|
|
|
|
// Check if we should exclude the serving cell
|
|
if (params->exclude_nid_cell >= 0 && detected_nid_cell == params->exclude_nid_cell) {
|
|
return false;
|
|
}
|
|
|
|
if (params->detected_nid_cell)
|
|
*params->detected_nid_cell = detected_nid_cell;
|
|
|
|
return true;
|
|
}
|
|
|
|
void nr_scan_ssb(void *arg)
|
|
{
|
|
/* Initial synchronisation
|
|
*
|
|
* 1 radio frame = 10 ms
|
|
* <--------------------------------------------------------------------------->
|
|
* -----------------------------------------------------------------------------
|
|
* | Received UE data buffer |
|
|
* ----------------------------------------------------------------------------
|
|
* --------------------------
|
|
* <-------------->| pss | pbch | sss | pbch |
|
|
* --------------------------
|
|
* sync_pos SS/PBCH block
|
|
*/
|
|
|
|
nr_ue_ssb_scan_t *ssbInfo = (nr_ue_ssb_scan_t *)arg;
|
|
c16_t **rxdata = ssbInfo->rxdata;
|
|
const NR_DL_FRAME_PARMS *fp = ssbInfo->fp;
|
|
|
|
// Generate PSS time signal for this GSCN.
|
|
__attribute__((aligned(32))) c16_t pssTime[NUMBER_PSS_SEQUENCE][fp->ofdm_symbol_size];
|
|
const int pss_sequence = get_softmodem_params()->sl_mode == 0 ? NUMBER_PSS_SEQUENCE : NUMBER_PSS_SEQUENCE_SL;
|
|
for (int nid2 = 0; nid2 < pss_sequence; nid2++)
|
|
generate_pss_nr_time(fp, nid2, ssbInfo->gscnInfo.ssbFirstSC, pssTime[nid2]);
|
|
|
|
const uint32_t rxdataF_sz = fp->samples_per_slot_wCP;
|
|
__attribute__((aligned(32))) c16_t rxdataF[fp->nb_antennas_rx][rxdataF_sz];
|
|
|
|
// initial sync performed on two successive frames, if pbch passes on first frame, no need to process second frame
|
|
// only one frame is used for simulation tools
|
|
for (int frame_id = 0; frame_id < ssbInfo->nFrames && !ssbInfo->syncRes.cell_detected; frame_id++) {
|
|
if (ssbInfo->freqOffset)
|
|
compensate_freq_offset(rxdata, fp, ssbInfo->freqOffset, frame_id);
|
|
|
|
int detected_nid_cell = -1;
|
|
int ssb_offset = 0;
|
|
int freq_offset_pss = 0;
|
|
int freq_offset_sss = 0;
|
|
int32_t sss_metric = 0;
|
|
uint8_t sss_phase = 0;
|
|
|
|
nr_ssb_search_params_t search_params = {
|
|
.frame_parms = fp,
|
|
.rxdata = rxdata,
|
|
.rxdata_size = fp->samples_per_frame,
|
|
.ssb_start_subcarrier = ssbInfo->gscnInfo.ssbFirstSC,
|
|
.target_nid_cell = ssbInfo->targetNidCell,
|
|
.exclude_nid_cell = -1, // No exclusion for initial sync
|
|
.apply_freq_offset = ssbInfo->foFlag,
|
|
.search_frame_id = frame_id,
|
|
.fo_flag = ssbInfo->foFlag,
|
|
.rxdataF = rxdataF,
|
|
.pssTime = pssTime,
|
|
.detected_nid_cell = &detected_nid_cell,
|
|
.ssb_offset = &ssb_offset,
|
|
.sss_metric = &sss_metric,
|
|
.freq_offset_pss = &freq_offset_pss,
|
|
.freq_offset_sss = &freq_offset_sss,
|
|
.sss_phase = &sss_phase,
|
|
.pss_peak = &ssbInfo->pssCorrPeakPower,
|
|
.pss_avg = &ssbInfo->pssCorrAvgPower,
|
|
};
|
|
|
|
ssbInfo->syncRes.frame_id = frame_id;
|
|
ssbInfo->syncRes.cell_detected = nr_search_ssb_common(&search_params);
|
|
|
|
if (!ssbInfo->syncRes.cell_detected) {
|
|
continue;
|
|
}
|
|
|
|
ssbInfo->ssbOffset = ssb_offset;
|
|
ssbInfo->nidCell = detected_nid_cell;
|
|
|
|
#ifdef DEBUG_INITIAL_SYNCH
|
|
LOG_I(PHY,
|
|
"TDD Normal prefix: sss detection result; %d, CellId %d metric %d, phase %d, measured offset %d\n",
|
|
ssbInfo->syncRes.cell_detected,
|
|
ssbInfo->nidCell,
|
|
sss_metric,
|
|
sss_phase,
|
|
ssbInfo->syncRes.rx_offset);
|
|
#endif
|
|
ssbInfo->freqOffset += freq_offset_pss + freq_offset_sss;
|
|
|
|
if (ssbInfo->syncRes.cell_detected) { // we got sss channel
|
|
ssbInfo->syncRes.cell_detected = nr_pbch_detection(ssbInfo->proc,
|
|
ssbInfo->fp,
|
|
ssbInfo->nidCell,
|
|
1,
|
|
ssbInfo->gscnInfo.ssbFirstSC,
|
|
&ssbInfo->halfFrameBit,
|
|
&ssbInfo->ssbIndex,
|
|
&ssbInfo->symbolOffset,
|
|
&ssbInfo->pbchResult,
|
|
rxdataF); // start pbch detection at first symbol after pss
|
|
if (ssbInfo->syncRes.cell_detected) {
|
|
uint32_t rsrp_avg = nr_ue_calculate_ssb_rsrp(ssbInfo->fp, rxdataF, 0, ssbInfo->gscnInfo.ssbFirstSC);
|
|
int rsrp_db_per_re = 10 * log10(rsrp_avg);
|
|
ssbInfo->adjust_rxgain = TARGET_RX_POWER - rsrp_db_per_re;
|
|
LOG_I(PHY, "pbch rx ok. rsrp:%d dB/RE, adjust_rxgain:%d dB\n", rsrp_db_per_re, ssbInfo->adjust_rxgain);
|
|
}
|
|
}
|
|
}
|
|
|
|
completed_task_ans(ssbInfo->ans);
|
|
}
|
|
|
|
nr_initial_sync_t nr_initial_sync(UE_nr_rxtx_proc_t *proc,
|
|
PHY_VARS_NR_UE *ue,
|
|
int n_frames,
|
|
nr_gscn_info_t gscnInfo[MAX_GSCN_BAND],
|
|
int numGscn)
|
|
{
|
|
NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
|
|
|
|
// Perform SSB scanning in parallel. One GSCN per thread.
|
|
LOG_I(NR_PHY,
|
|
"Starting cell search with center freq: %ld, bandwidth: %d. Scanning for %d number of GSCN.\n",
|
|
fp->dl_CarrierFreq,
|
|
fp->N_RB_DL,
|
|
numGscn);
|
|
DevAssert(numGscn);
|
|
task_ans_t ans;
|
|
init_task_ans(&ans, numGscn);
|
|
nr_ue_ssb_scan_t ssb_info[numGscn];
|
|
for (int s = 0; s < numGscn; s++) {
|
|
nr_ue_ssb_scan_t *ssbInfo = &ssb_info[s];
|
|
*ssbInfo = (nr_ue_ssb_scan_t){.gscnInfo = gscnInfo[s],
|
|
.fp = &ue->frame_parms,
|
|
.proc = proc,
|
|
.syncRes.cell_detected = false,
|
|
.nFrames = n_frames,
|
|
.foFlag = ue->UE_fo_compensation,
|
|
.freqOffset = ue->initial_fo,
|
|
.targetNidCell = ue->target_Nid_cell};
|
|
ssbInfo->rxdata = malloc16_clear(fp->nb_antennas_rx * sizeof(c16_t *));
|
|
for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
|
|
ssbInfo->rxdata[ant] = malloc16(sizeof(c16_t) * (fp->samples_per_frame * 2 + fp->ofdm_symbol_size));
|
|
memcpy(ssbInfo->rxdata[ant], ue->common_vars.rxdata[ant], sizeof(c16_t) * fp->samples_per_frame * 2);
|
|
memset(ssbInfo->rxdata[ant] + fp->samples_per_frame * 2, 0, fp->ofdm_symbol_size * sizeof(c16_t));
|
|
}
|
|
LOG_I(NR_PHY,
|
|
"Scanning GSCN: %d, with SSB offset: %d, SSB Freq: %lf\n",
|
|
ssbInfo->gscnInfo.gscn,
|
|
ssbInfo->gscnInfo.ssbFirstSC,
|
|
ssbInfo->gscnInfo.ssRef);
|
|
ssbInfo->ans = &ans;
|
|
task_t t = {.func = nr_scan_ssb, .args = ssbInfo};
|
|
pushTpool(&get_nrUE_params()->Tpool, t);
|
|
}
|
|
|
|
// Collect the scan results
|
|
nr_ue_ssb_scan_t *res = NULL;
|
|
join_task_ans(&ans);
|
|
for (int i = 0; i < numGscn; i++) {
|
|
nr_ue_ssb_scan_t *ssbInfo = &ssb_info[i];
|
|
if (ssbInfo->syncRes.cell_detected) {
|
|
LOG_I(NR_PHY,
|
|
"Cell Detected with GSCN: %d, SSB SC offset: %d, SSB Ref: %lf, PSS Corr peak: %d dB, PSS Corr Average: %d\n",
|
|
ssbInfo->gscnInfo.gscn,
|
|
ssbInfo->gscnInfo.ssbFirstSC,
|
|
ssbInfo->gscnInfo.ssRef,
|
|
ssbInfo->pssCorrPeakPower,
|
|
ssbInfo->pssCorrAvgPower);
|
|
// take the first cell detected
|
|
if (!res)
|
|
res = ssbInfo;
|
|
}
|
|
for (int ant = 0; ant < fp->nb_antennas_rx; ant++) {
|
|
free(ssbInfo->rxdata[ant]);
|
|
}
|
|
free(ssbInfo->rxdata);
|
|
ssbInfo->rxdata = NULL;
|
|
}
|
|
|
|
// Set globals based on detected cell
|
|
if (res) {
|
|
fp->Nid_cell = res->nidCell;
|
|
fp->ssb_start_subcarrier = res->gscnInfo.ssbFirstSC;
|
|
fp->half_frame_bit = res->halfFrameBit;
|
|
fp->ssb_index = res->ssbIndex;
|
|
ue->symbol_offset = res->symbolOffset;
|
|
ue->common_vars.freq_offset = res->freqOffset;
|
|
ue->adjust_rxgain = res->adjust_rxgain;
|
|
}
|
|
|
|
// In initial sync, we indicate PBCH to MAC after the scan is complete.
|
|
nr_downlink_indication_t dl_indication;
|
|
fapi_nr_rx_indication_t rx_ind = {0};
|
|
uint16_t number_pdus = 1;
|
|
nr_fill_dl_indication(&dl_indication, NULL, &rx_ind, proc, ue, NULL);
|
|
nr_fill_rx_indication(&rx_ind,
|
|
FAPI_NR_RX_PDU_TYPE_SSB,
|
|
ue,
|
|
0,
|
|
0,
|
|
NULL,
|
|
number_pdus,
|
|
proc,
|
|
res ? (void *)&res->pbchResult : NULL,
|
|
NULL);
|
|
|
|
if (ue->if_inst && ue->if_inst->dl_indication)
|
|
ue->if_inst->dl_indication(&dl_indication);
|
|
|
|
LOG_D(PHY, "nr_initial sync ue RB_DL %d\n", fp->N_RB_DL);
|
|
|
|
if (res) {
|
|
// digital compensation of FFO for SSB symbols
|
|
if (res->freqOffset && ue->UE_fo_compensation) {
|
|
// In SA we need to perform frequency offset correction until the end of buffer because we need to decode SIB1
|
|
// and we do not know yet in which slot it goes.
|
|
compensate_freq_offset(ue->common_vars.rxdata, fp, res->freqOffset, res->syncRes.frame_id);
|
|
}
|
|
// sync at symbol ue->symbol_offset
|
|
// computing the offset wrt the beginning of the frame
|
|
int mu = fp->numerology_index;
|
|
// number of symbols with different prefix length
|
|
// every 7*(1<<mu) symbols there is a different prefix length (38.211 5.3.1)
|
|
int n_symb_prefix0 = (res->symbolOffset / (7 * (1 << mu))) + 1;
|
|
const int sync_pos_frame = n_symb_prefix0 * (fp->ofdm_symbol_size + fp->nb_prefix_samples0)
|
|
+ (res->symbolOffset - n_symb_prefix0) * (fp->ofdm_symbol_size + fp->nb_prefix_samples);
|
|
// for a correct computation of frame number to sync with the one decoded at MIB we need to take into account in which of
|
|
// the n_frames we got sync
|
|
ue->init_sync_frame = n_frames - 1 - res->syncRes.frame_id;
|
|
|
|
// we also need to take into account the shift by samples_per_frame in case the if is true
|
|
if (res->ssbOffset < sync_pos_frame) {
|
|
res->syncRes.rx_offset = fp->samples_per_frame - sync_pos_frame + res->ssbOffset;
|
|
ue->init_sync_frame += 1;
|
|
} else
|
|
res->syncRes.rx_offset = res->ssbOffset - sync_pos_frame;
|
|
}
|
|
|
|
if (res) {
|
|
LOG_I(PHY, "[UE%d] In synch, rx_offset %d samples\n", ue->Mod_id, res->syncRes.rx_offset);
|
|
LOG_I(PHY, "[UE %d] Measured Carrier Frequency offset %d Hz\n", ue->Mod_id, res->freqOffset);
|
|
} else {
|
|
#ifdef DEBUG_INITIAL_SYNC
|
|
LOG_I(PHY,"[UE%d] Initial sync : PBCH not ok\n",ue->Mod_id);
|
|
LOG_I(PHY, "[UE%d] Initial sync : Estimated PSS position %d, Nid2 %d\n", ue->Mod_id, sync_pos, ue->common_vars.nid2);
|
|
LOG_I(PHY,"[UE%d] Initial sync : Estimated Nid_cell %d, Frame_type %d\n",ue->Mod_id,
|
|
fp->Nid_cell,fp->frame_type);
|
|
#endif
|
|
}
|
|
|
|
// gain control
|
|
if (!res) { // we are not synched, so we cannot use rssi measurement (which is based on channel estimates)
|
|
int rx_power = 0;
|
|
|
|
// do a measurement on the best guess of the PSS
|
|
// for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
|
|
// rx_power += signal_energy(&ue->common_vars.rxdata[aarx][sync_pos2],
|
|
// frame_parms->ofdm_symbol_size+frame_parms->nb_prefix_samples);
|
|
|
|
/*
|
|
// do a measurement on the full frame
|
|
for (aarx=0; aarx<frame_parms->nb_antennas_rx; aarx++)
|
|
rx_power += signal_energy(&ue->common_vars.rxdata[aarx][0],
|
|
frame_parms->samples_per_subframe*10);
|
|
*/
|
|
|
|
// we might add a low-pass filter here later
|
|
ue->measurements.rx_power_avg[0] = rx_power / fp->nb_antennas_rx;
|
|
|
|
ue->measurements.rx_power_avg_dB[0] = dB_fixed(ue->measurements.rx_power_avg[0]);
|
|
|
|
#ifdef DEBUG_INITIAL_SYNCH
|
|
LOG_I(PHY, "[UE%d] Initial sync failed : Estimated power: %d dB\n", ue->Mod_id, ue->measurements.rx_power_avg_dB[0]);
|
|
#endif
|
|
} else {
|
|
LOG_A(PHY, "Initial sync successful, PCI: %d\n", fp->Nid_cell);
|
|
}
|
|
// exit_fun("debug exit");
|
|
if (res)
|
|
return res->syncRes;
|
|
else
|
|
return (nr_initial_sync_t){.cell_detected = false};
|
|
}
|