diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c index 73f4f89241..f7811cb204 100644 --- a/common/utils/nr/nr_common.c +++ b/common/utils/nr/nr_common.c @@ -755,11 +755,25 @@ void SLIV2SL(int SLIV,int *S,int *L) { } } -int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA) +int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs) { - uint32_t absolute_diff = (absoluteFrequencySSB - absoluteFrequencyPointA); - const int scaling_5khz = absoluteFrequencyPointA < 600000 ? 3 : 1; - return ((absolute_diff / scaling_5khz) % 24); + // for FR1 k_SSB expressed in terms of 15kHz SCS + // for FR2 k_SSB expressed in terms of the subcarrier spacing provided by the higher-layer parameter subCarrierSpacingCommon + // absoluteFrequencySSB and absoluteFrequencyPointA are ARFCN + // NR-ARFCN delta frequency is 5kHz if f < 3 GHz, 15kHz for other FR1 freq and 60kHz for FR2 + const uint32_t absolute_diff = absoluteFrequencySSB - absoluteFrequencyPointA; + int scaling = 1; + if (absoluteFrequencyPointA < 600000) // correspond to 3GHz + scaling = 3; + if (scs > 2) // FR2 + scaling <<= (scs - 2); + int sco_limit = scs == 1 ? 24 : 12; + int subcarrier_offset = (absolute_diff / scaling) % sco_limit; + // 30kHz is the only case where k_SSB is expressed in terms of a different SCS (15kHz) + // the assertion is to avoid having an offset of half a subcarrier + if (scs == 1) + AssertFatal(subcarrier_offset % 2 == 0, "ssb offset %d invalid for scs %d\n", subcarrier_offset, scs); + return subcarrier_offset; } uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, @@ -767,16 +781,16 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, int ssbSubcarrierSpacing, int frequency_range) { + // offset to pointA is expressed in terms of 15kHz SCS for FR1 and 60kHz for FR2 + // only difference wrt NR-ARFCN is delta frequency 5kHz if f < 3 GHz for ARFCN uint32_t absolute_diff = (absoluteFrequencySSB - absoluteFrequencyPointA); const int scaling_5khz = absoluteFrequencyPointA < 600000 ? 3 : 1; - int sco = get_ssb_subcarrier_offset(absoluteFrequencySSB, absoluteFrequencyPointA); - const int scs_scaling = frequency_range == FR2 ? 1 << (ssbSubcarrierSpacing - 2) : 1 << ssbSubcarrierSpacing; - const int scaled_abs_diff = absolute_diff / scaling_5khz; - const int ssb_offset_point_a = - (scaled_abs_diff - sco) / 12 - - 10 * scs_scaling; // absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total - AssertFatal(ssb_offset_point_a % scs_scaling == 0, "PRB offset %d can create frequency offset\n", ssb_offset_point_a); - AssertFatal(sco % scs_scaling == 0, "ssb offset %d can create frequency offset\n", sco); + const int scaling = frequency_range == FR2 ? 1 << (ssbSubcarrierSpacing - 2) : 1 << ssbSubcarrierSpacing; + const int scaled_abs_diff = absolute_diff / (scaling_5khz * scaling); + // absoluteFrequencySSB is the central frequency of SSB which is made by 20RBs in total + const int ssb_offset_point_a = ((scaled_abs_diff / 12) - 10) * scaling; + // Offset to point A needs to be divisible by scaling + AssertFatal(ssb_offset_point_a % scaling == 0, "PRB offset %d not valid for scs %d\n", ssb_offset_point_a, ssbSubcarrierSpacing); return ssb_offset_point_a; } diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h index 671f232928..3082691f1b 100644 --- a/common/utils/nr/nr_common.h +++ b/common/utils/nr/nr_common.h @@ -202,7 +202,7 @@ uint32_t get_ssb_offset_to_pointA(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int ssbSubcarrierSpacing, int frequency_range); -int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA); +int get_ssb_subcarrier_offset(uint32_t absoluteFrequencySSB, uint32_t absoluteFrequencyPointA, int scs); int get_delay_idx(int delay, int max_delay_comp); void freq2time(uint16_t ofdm_symbol_size, diff --git a/openair1/PHY/INIT/nr_parms.c b/openair1/PHY/INIT/nr_parms.c index d9289401ad..02141f4ff3 100644 --- a/openair1/PHY/INIT/nr_parms.c +++ b/openair1/PHY/INIT/nr_parms.c @@ -347,10 +347,12 @@ int nr_init_frame_parms_ue(NR_DL_FRAME_PARMS *fp, fp->freq_range = (fp->dl_CarrierFreq < 6e9)? nr_FR1 : nr_FR2; uint8_t sco = 0; - if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset<24)) || - ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset<12)) ) { + if (((fp->freq_range == nr_FR1) && (config->ssb_table.ssb_subcarrier_offset < 24)) || + ((fp->freq_range == nr_FR2) && (config->ssb_table.ssb_subcarrier_offset < 12))) { if (fp->freq_range == nr_FR1) sco = config->ssb_table.ssb_subcarrier_offset>>config->ssb_config.scs_common; + else + sco = config->ssb_table.ssb_subcarrier_offset; } fp->ssb_start_subcarrier = (12 * config->ssb_table.ssb_offset_point_a + sco); diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index b989a5c1c6..270441a6dd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -639,7 +639,8 @@ static void config_common(gNB_MAC_INST *nrmac, nr_pdsch_AntennaPorts_t pdsch_Ant cfg->num_tlv++; cfg->ssb_table.ssb_subcarrier_offset.value = get_ssb_subcarrier_offset(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, + *scc->ssbSubcarrierSpacing); AssertFatal(cfg->ssb_table.ssb_subcarrier_offset.value < 16, "cannot handle ssb_subcarrier_offset %d resulting from Point A %ld SSB %ld: please increase dl_absoluteFrequencyPointA " diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c index 56d5843048..d85bedf79e 100644 --- a/openair2/RRC/NR/nr_rrc_config.c +++ b/openair2/RRC/NR/nr_rrc_config.c @@ -1768,7 +1768,8 @@ NR_BCCH_BCH_Message_t *get_new_MIB_NR(const NR_ServingCellConfigCommon_t *scc) int ssb_subcarrier_offset = 31; // default value for NSA if (get_softmodem_params()->sa) { ssb_subcarrier_offset = get_ssb_subcarrier_offset(*scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencySSB, - scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA); + scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA, + *scc->ssbSubcarrierSpacing); } mib->message.choice.mib->ssb_SubcarrierOffset = ssb_subcarrier_offset & 15;