diff --git a/lib/include/srsran/common/band_helper.h b/lib/include/srsran/common/band_helper.h index 8112ba66c..575d3ea53 100644 --- a/lib/include/srsran/common/band_helper.h +++ b/lib/include/srsran/common/band_helper.h @@ -13,6 +13,7 @@ #ifndef SRSRAN_BAND_HELPER_H #define SRSRAN_BAND_HELPER_H +#include "srsran/phy/common/phy_common_nr.h" #include #include #include @@ -44,8 +45,77 @@ public: // For bands with 2 possible raster offsets, delta_f_raster needs to be specified std::vector get_bands_nr(uint32_t nr_arfcn, delta_f_raster_t delta_f_raster = DEFAULT); + /** + * @brief Get the lowest band that includes a given Downlink frequency in Hz + * @param dl_freq_Hz Given frequency in Hz + * @return The band number if the frequency is bounded in a band, UINT16_MAX otherwise + */ + uint16_t get_band_from_dl_freq_Hz(double dl_freq_Hz); + + /** + * @brief Selects the SSB pattern case according to the band number and subcarrier spacing + * @remark Described by TS 38.101-1 Table 5.4.3.3-1: Applicable SS raster entries per operating band + * @param band NR Band number + * @param scs SSB Subcarrier spacing + * @return The SSB pattern case if band and subcarrier spacing match, SRSRAN_SSB_PATTERN_INVALID otherwise + */ + srsran_ssb_patern_t get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs); + + /** + * @brief gets the NR band duplex mode + * @param band Given band + * @return A valid SRSRAN_DUPLEX_MODE if the band is valid, SRSRAN_DUPLEX_MODE_INVALID otherwise + */ + srsran_duplex_mode_t get_duplex_mode(uint16_t band); + private: - // Table 5.4.2.1-1 + // Elements of TS 38.101-1 Table 5.2-1: NR operating bands in FR1 + struct nr_operating_band { + uint16_t band; + uint32_t F_UL_low; // in MHz + uint32_t F_UL_high; // in MHz + uint32_t F_DL_low; // in MHz + uint32_t F_DL_high; // in MHz + srsran_duplex_mode_t duplex_mode; + }; + static const uint32_t nof_nr_operating_band_fr1 = 32; + static constexpr std::array nr_operating_bands_fr1 = {{ + // clang-format off + {1, 1920, 1080, 2110, 2170, SRSRAN_DUPLEX_MODE_FDD}, + {2, 1850, 1810, 1930, 1990, SRSRAN_DUPLEX_MODE_FDD}, + {3, 1710, 1785, 1805, 1880, SRSRAN_DUPLEX_MODE_FDD}, + {5, 824, 849, 869, 894, SRSRAN_DUPLEX_MODE_FDD}, + {7, 2500, 2570, 2620, 2690, SRSRAN_DUPLEX_MODE_FDD}, + {8, 880, 915, 925, 960, SRSRAN_DUPLEX_MODE_FDD}, + {12, 699, 716, 729, 746, SRSRAN_DUPLEX_MODE_FDD}, + {20, 832, 862, 791, 821, SRSRAN_DUPLEX_MODE_FDD}, + {25, 1850, 1915, 1930, 1995, SRSRAN_DUPLEX_MODE_FDD}, + {28, 703, 748, 758, 803, SRSRAN_DUPLEX_MODE_FDD}, + {34, 2010, 2025, 2010, 2025, SRSRAN_DUPLEX_MODE_TDD}, + {38, 2570, 2620, 2570, 2620, SRSRAN_DUPLEX_MODE_TDD}, + {39, 1880, 1920, 1880, 1920, SRSRAN_DUPLEX_MODE_TDD}, + {40, 2300, 2400, 2300, 2400, SRSRAN_DUPLEX_MODE_TDD}, + {41, 2496, 2690, 2496, 2690, SRSRAN_DUPLEX_MODE_TDD}, + {50, 1432, 1517, 1432, 1517, SRSRAN_DUPLEX_MODE_TDD}, + {51, 1427, 1432, 1427, 1432, SRSRAN_DUPLEX_MODE_TDD}, + {66, 1710, 1780, 2110, 2200, SRSRAN_DUPLEX_MODE_FDD}, + {70, 1695, 1710, 1995, 2020, SRSRAN_DUPLEX_MODE_FDD}, + {71, 663, 698, 617, 652, SRSRAN_DUPLEX_MODE_FDD}, + {74, 1427, 1470, 1475, 1518, SRSRAN_DUPLEX_MODE_FDD}, + {75, 0, 0, 1432, 1517, SRSRAN_DUPLEX_MODE_SDL}, + {76, 0, 0, 1427, 1432, SRSRAN_DUPLEX_MODE_SDL}, + {77, 3300, 4200, 3300, 4200, SRSRAN_DUPLEX_MODE_TDD}, + {78, 3300, 3800, 3300, 3800, SRSRAN_DUPLEX_MODE_TDD}, + {79, 4400, 5000, 4400, 5000, SRSRAN_DUPLEX_MODE_TDD}, + {80, 1710, 1785, 0, 0, SRSRAN_DUPLEX_MODE_SUL}, + {81, 880, 915, 0, 0, SRSRAN_DUPLEX_MODE_SUL}, + {82, 832, 862, 0, 0, SRSRAN_DUPLEX_MODE_SUL}, + {83, 703, 748, 0, 0, SRSRAN_DUPLEX_MODE_SUL}, + {84, 1920, 1980, 0, 0, SRSRAN_DUPLEX_MODE_SUL}, + {86, 1710, 1780, 0, 0, SRSRAN_DUPLEX_MODE_SUL} + // clang-format on + }}; + struct nr_raster_params { double delta_F_global_kHz; double F_REF_Offs_MHz; @@ -140,7 +210,7 @@ private: // clang-format on }}; - static const uint32_t nof_nr_bands_fr2 = 36; + static const uint32_t nof_nr_bands_fr2 = 8; static constexpr std::array nr_band_table_fr2 = {{ {257, KHZ_60, 2054166, 1, 2104165, 2054166, 1, 2104165}, {257, KHZ_120, 2054167, 2, 2104165, 2054167, 20, 2104165}, @@ -154,6 +224,48 @@ private: {261, KHZ_60, 2070833, 1, 2084999, 2070833, 1, 2084999}, {261, KHZ_120, 2070833, 2, 2084999, 2070833, 2, 2084999} }}; + +// Elements of TS 38.101-1 Table 5.4.3.3-1 : Applicable SS raster entries per operating band + struct nr_band_ss_raster { + uint16_t band; + srsran_subcarrier_spacing_t scs; + srsran_ssb_patern_t pattern; + uint32_t gscn_first; + uint32_t gscn_step; + uint32_t gscn_last; + }; + static const uint32_t nof_nr_band_ss_raster = 29; + static constexpr std::array nr_band_ss_raster_table = {{ + {1, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 5279, 1, 5419}, + {2, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 4829, 1, 4969}, + {3, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 4517, 1, 4693}, + {5, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 2177, 1, 2230}, + {5, srsran_subcarrier_spacing_30kHz, SRSRAN_SSB_PATTERN_B, 2183, 1, 2224}, + {7, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 6554, 1, 6718}, + {8, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 2318, 1, 2395}, + {12, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 1828, 1, 1858}, + {20, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 1982, 1, 2047}, + {25, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 4829, 1, 4981}, + {28, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 1901, 1, 2002}, + {34, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 5030, 1, 5056}, + {38, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 6431, 1, 6544}, + {39, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 4706, 1, 4795}, + {40, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 5756, 1, 5995}, + {41, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 6246, 3, 6717}, + {41, srsran_subcarrier_spacing_30kHz, SRSRAN_SSB_PATTERN_C, 6252, 3, 6714}, + {50, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 3584, 1, 3787}, + {51, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 3572, 1, 3574}, + {66, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 5279, 1, 5494}, + {66, srsran_subcarrier_spacing_30kHz, SRSRAN_SSB_PATTERN_B, 5285, 1, 5488}, + {70, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 4993, 1, 5044}, + {71, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 1547, 1, 1624}, + {74, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 3692, 1, 3790}, + {75, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 3584, 1, 3787}, + {76, srsran_subcarrier_spacing_15kHz, SRSRAN_SSB_PATTERN_A, 3572, 1, 3574}, + {77, srsran_subcarrier_spacing_30kHz, SRSRAN_SSB_PATTERN_C, 7711, 1, 8329}, + {78, srsran_subcarrier_spacing_30kHz, SRSRAN_SSB_PATTERN_C, 7711, 1, 8051}, + {79, srsran_subcarrier_spacing_30kHz, SRSRAN_SSB_PATTERN_C, 8480, 16, 8880}, + }}; }; } // namespace srsran diff --git a/lib/include/srsran/phy/common/phy_common_nr.h b/lib/include/srsran/phy/common/phy_common_nr.h index 089098859..6b12a9dff 100644 --- a/lib/include/srsran/phy/common/phy_common_nr.h +++ b/lib/include/srsran/phy/common/phy_common_nr.h @@ -328,8 +328,26 @@ typedef enum SRSRAN_API { srsran_subcarrier_spacing_60kHz, srsran_subcarrier_spacing_120kHz, srsran_subcarrier_spacing_240kHz, + srsran_subcarrier_spacing_invalid } srsran_subcarrier_spacing_t; +typedef enum SRSRAN_API { + SRSRAN_SSB_PATTERN_A = 0, // FR1, 15 kHz SCS + SRSRAN_SSB_PATTERN_B, // FR1, 30 kHz SCS + SRSRAN_SSB_PATTERN_C, // FR1, 30 kHz SCS + SRSRAN_SSB_PATTERN_D, // FR2, 120 kHz SCS + SRSRAN_SSB_PATTERN_E, // FR2, 240 kHz SCS + SRSRAN_SSB_PATTERN_INVALID, +} srsran_ssb_patern_t; + +typedef enum SRSRAN_API { + SRSRAN_DUPLEX_MODE_FDD = 0, // Paired + SRSRAN_DUPLEX_MODE_TDD, // Unpaired + SRSRAN_DUPLEX_MODE_SDL, // Supplementary DownLink + SRSRAN_DUPLEX_MODE_SUL, // Supplementary UpLink + SRSRAN_DUPLEX_MODE_INVALID +} srsran_duplex_mode_t; + /** * @brief NR carrier parameters. It is a combination of fixed cell and bandwidth-part (BWP) */ diff --git a/lib/src/common/band_helper.cc b/lib/src/common/band_helper.cc index 820b8fcb7..70a51f4c3 100644 --- a/lib/src/common/band_helper.cc +++ b/lib/src/common/band_helper.cc @@ -19,6 +19,10 @@ namespace srsran { constexpr std::array srsran_band_helper::nr_band_table_fr1; constexpr std::array srsran_band_helper::nr_fr_params; +constexpr std::array + srsran_band_helper::nr_operating_bands_fr1; +constexpr std::array + srsran_band_helper::nr_band_ss_raster_table; // Formula in 5.4.2.1 double srsran_band_helper::nr_arfcn_to_freq(uint32_t nr_arfcn) @@ -51,6 +55,55 @@ std::vector srsran_band_helper::get_bands_nr(uint32_t return bands; } +uint16_t srsran_band_helper::get_band_from_dl_freq_Hz(double freq) +{ + uint32_t freq_MHz = (uint32_t)round(freq / 1e6); + for (const nr_operating_band& band : nr_operating_bands_fr1) { + if (freq_MHz >= band.F_DL_low and freq_MHz <= band.F_DL_high) { + return band.band; + } + } + return UINT16_MAX; +} + +srsran_ssb_patern_t srsran_band_helper::get_ssb_pattern(uint16_t band, srsran_subcarrier_spacing_t scs) +{ + // Look for the given band and SCS + for (const nr_band_ss_raster& ss_raster : nr_band_ss_raster_table) { + // Check if band and SCS match! + if (ss_raster.band == band && ss_raster.scs == scs) { + return ss_raster.pattern; + } + + // As bands are in ascending order, do not waste more time if the current band is bigger + if (ss_raster.band > band) { + return SRSRAN_SSB_PATTERN_INVALID; + } + } + + // Band is out of range, so consider invalid + return SRSRAN_SSB_PATTERN_INVALID; +} + +srsran_duplex_mode_t srsran_band_helper::get_duplex_mode(uint16_t band) +{ + // Look for the given band + for (const nr_operating_band& b : nr_operating_bands_fr1) { + // Check if band and SCS match! + if (b.band == band) { + return b.duplex_mode; + } + + // As bands are in ascending order, do not waste more time if the current band is bigger + if (b.band > band) { + return SRSRAN_DUPLEX_MODE_INVALID; + } + } + + // Band is out of range, so consider invalid + return SRSRAN_DUPLEX_MODE_INVALID; +} + srsran_band_helper::nr_raster_params srsran_band_helper::get_raster_params(uint32_t nr_arfcn) { for (auto& fr : nr_fr_params) {