1515using namespace srsran ;
1616using namespace srs_du ;
1717
18+ // Helper that computes the SRS bandwidth parameter \f$C_{SRS}\f$ based on the number of UL RBs.
1819static std::optional<unsigned > compute_srs_bw_param (unsigned nof_ul_rbs)
1920{
20- // Iterate over Table 6.4.1.4.3-1, TS 38.211, and find the first \f$C_{SRS}\f$ value that provides the
21- // greatest \f$m_{SRS,0}\f$ such that it is less than or equal to number of UL RBs.
21+ // Iterate over Table 6.4.1.4.3-1, TS 38.211, and find the minimum \f$C_{SRS}\f$ value that maximizes \f$m_{SRS,0}\f$
22+ // under the constraint \f$m_{SRS,0}\f$ <= UL RBs.
2223
2324 // As per Table 6.4.1.4.3-1, TS 38.211, the maximum value of \f$C_{SRS}\f$ is 63.
2425 constexpr unsigned max_non_valid_c_srs = 64 ;
25- constexpr uint8_t b_srs_0 = 0 ;
26- for (uint8_t c_srs = 0 ; c_srs != max_non_valid_c_srs; c_srs++) {
26+ // As per Table 6.4.1.4.3-1, TS 38.211, we do not consider frequency hopping.
27+ constexpr uint8_t b_srs_0 = 0 ;
28+ // Defines the pair of C_SRS and m_SRS values.
29+ using pair_c_srs_m_srs = std::pair<unsigned , unsigned >;
30+ std::optional<pair_c_srs_m_srs> candidate_c_srs = std::nullopt ;
31+ for (uint8_t c_srs = 0 ; c_srs != max_non_valid_c_srs; ++c_srs) {
2732 auto srs_params = srs_configuration_get (c_srs, b_srs_0);
28- srsran_assert (srs_params.has_value (), " The SRS is not valid" );
2933
30- if (c_srs == 0 and srs_params.value (). m_srs > nof_ul_rbs ) {
31- srsran_assertion_failure (" C_SRS is not compatible with the number of UL RBs " );
34+ if (not srs_params.has_value () ) {
35+ srsran_assertion_failure (" C_SRS is not compatible with the current BW configuration " );
3236 return std::nullopt ;
3337 }
34- if (srs_params.value ().m_srs == nof_ul_rbs) {
35- return c_srs;
38+
39+ // If there is no candidate C_SRS value, we set the first valid C_SRS value as the candidate.
40+ if (not candidate_c_srs.has_value ()) {
41+ candidate_c_srs = pair_c_srs_m_srs{c_srs, srs_params.value ().m_srs };
42+ }
43+ // NOTE: the condition srs_params.value().m_srs > candidate_c_srs->second is used to find the minimum C_SRS value
44+ // that maximizes m_SRS.
45+ else if (srs_params.value ().m_srs <= nof_ul_rbs and srs_params.value ().m_srs > candidate_c_srs->second ) {
46+ candidate_c_srs = pair_c_srs_m_srs{c_srs, srs_params.value ().m_srs };
3647 }
48+ // If we reach this point, no need to keep looking for a valid C_SRS value.
3749 if (srs_params.value ().m_srs > nof_ul_rbs) {
38- return c_srs - 1 ;
50+ break ;
3951 }
4052 }
41- return max_non_valid_c_srs - 1 ;
53+ return candidate_c_srs. value (). first ;
4254}
4355
4456// Helper that returns the frequency shift value for the SRS; the value is computed in such a way that the SRS resources
@@ -62,53 +74,48 @@ static bool is_ul_slot(unsigned offset, const tdd_ul_dl_config_common& tdd_cfg)
6274
6375static bool is_partually_ul_slot (unsigned offset, const tdd_ul_dl_config_common& tdd_cfg)
6476{
65- const unsigned slot_index = offset % (NOF_SUBFRAMES_PER_FRAME * get_nof_slots_per_subframe (tdd_cfg.ref_scs ));
66- return srsran::get_active_tdd_ul_symbols (tdd_cfg, slot_index, cyclic_prefix::NORMAL).length () != 0 and
67- srsran::get_active_tdd_dl_symbols (tdd_cfg, slot_index, cyclic_prefix::NORMAL).length () !=
68- NOF_OFDM_SYM_PER_SLOT_NORMAL_CP;
77+ const unsigned slot_index = offset % (NOF_SUBFRAMES_PER_FRAME * get_nof_slots_per_subframe (tdd_cfg.ref_scs ));
78+ const unsigned nof_symbols = srsran::get_active_tdd_ul_symbols (tdd_cfg, slot_index, cyclic_prefix::NORMAL).length ();
79+ return nof_symbols != 0 and nof_symbols != NOF_OFDM_SYM_PER_SLOT_NORMAL_CP;
6980}
7081
71- static bool srs_config_validator (const du_cell_config& cell_cfg)
82+ // Helper that updates the starting SRS config with user-defined parameters.
83+ static srs_config build_default_srs_cfg (const du_cell_config& default_cell_cfg)
7284{
73- if (not cell_cfg.ue_ded_serv_cell_cfg .ul_config .has_value ()) {
74- return false ;
75- }
76-
77- if (cell_cfg.ue_ded_serv_cell_cfg .ul_config .value ().init_ul_bwp .srs_cfg .has_value ()) {
78- return false ;
79- }
85+ srsran_assert (default_cell_cfg.ue_ded_serv_cell_cfg .ul_config .has_value () and
86+ default_cell_cfg.ue_ded_serv_cell_cfg .ul_config .value ().init_ul_bwp .srs_cfg .has_value (),
87+ " DU cell config is not valid" );
8088
81- const auto & srs_cfg = cell_cfg. ue_ded_serv_cell_cfg . ul_config . value (). init_ul_bwp . srs_cfg . value ();
82- if (srs_cfg.srs_res_set_list . size () != 1 ) {
83- return false ;
89+ // If the DU is not configured for periodic SRS, we don't need to update the SRS configuration.
90+ if (not default_cell_cfg. srs_cfg .srs_period . has_value () ) {
91+ return default_cell_cfg. ue_ded_serv_cell_cfg . ul_config . value (). init_ul_bwp . srs_cfg . value () ;
8492 }
8593
86- if (not std::holds_alternative<srs_config::srs_resource_set::periodic_resource_type>(
87- srs_cfg.srs_res_set_list .front ().res_type )) {
88- return false ;
89- }
90-
91- if (srs_cfg.srs_res_set_list .front ().srs_res_id_list .size () != 1 or
92- srs_cfg.srs_res_set_list .front ().srs_res_id_list .front () != static_cast <srs_config::srs_res_id>(0U )) {
93- return false ;
94- }
94+ auto srs_cfg = default_cell_cfg.ue_ded_serv_cell_cfg .ul_config .value ().init_ul_bwp .srs_cfg .value ();
9595
96- if (srs_cfg.srs_res_list .size () != 1 or
97- srs_cfg.srs_res_list .front ().id .ue_res_id != static_cast <srs_config::srs_res_id>(0U )) {
98- return false ;
99- }
96+ srsran_assert (srs_cfg.srs_res_list .size () == 1 and srs_cfg.srs_res_set_list .size () == 1 ,
97+ " The SRS resource list and the SRS resource set list are expected to have a single element" );
10098
101- if (srs_cfg.srs_res_list .front ().res_type != srs_resource_type::periodic) {
102- return false ;
103- }
99+ srs_config::srs_resource& res = srs_cfg.srs_res_list .back ();
100+ res.res_type = srs_resource_type::periodic;
101+ // Set offset to 0. The offset will be updated later on, when the UE is allocated the SRS resources.
102+ res.periodicity_and_offset .emplace (
103+ srs_config::srs_periodicity_and_offset{.period = default_cell_cfg.srs_cfg .srs_period .value (), .offset = 0 });
104+ // Set the SRS resource ID to 0, as there is only 1 SRS resource per UE.
105+ res.id .ue_res_id = static_cast <srs_config::srs_res_id>(0U );
104106
105- if (not srs_cfg.srs_res_list .front ().periodicity_and_offset .has_value ()) {
106- return false ;
107- }
107+ srs_config::srs_resource_set& res_set = srs_cfg.srs_res_set_list .back ();
108+ res_set.res_type .emplace <srs_config::srs_resource_set::periodic_resource_type>(
109+ srs_config::srs_resource_set::periodic_resource_type{});
110+ // Set the SRS resource set ID to 0, as there is only 1 SRS resource set per UE.
111+ res_set.id = static_cast <srs_config::srs_res_set_id>(0U );
108112
109- return true ;
113+ return srs_cfg ;
110114}
111115
116+ du_srs_policy_max_ul_th::cell_context::cell_context (const du_cell_config& cfg) :
117+ cell_cfg(cfg), default_srs_cfg(build_default_srs_cfg(cfg)){};
118+
112119du_srs_policy_max_ul_th::du_srs_policy_max_ul_th (span<const du_cell_config> cell_cfg_list_) :
113120 cells(cell_cfg_list_.begin(), cell_cfg_list_.end())
114121{
@@ -117,7 +124,6 @@ du_srs_policy_max_ul_th::du_srs_policy_max_ul_th(span<const du_cell_config> cell
117124 continue ;
118125 }
119126
120- srsran_assert (srs_config_validator (cell.cell_cfg ), " The SRS configuration is not valid" );
121127 std::optional<unsigned > c_srs =
122128 compute_srs_bw_param (cell.cell_cfg .ul_cfg_common .init_ul_bwp .generic_params .crbs .length ()).value ();
123129 srsran_assert (c_srs.has_value (), " SRS parameters didn't provide a valid C_SRS value" );
@@ -130,19 +136,30 @@ du_srs_policy_max_ul_th::du_srs_policy_max_ul_th(span<const du_cell_config> cell
130136 // TODO: evaluate whether we need to consider the case of multiple cells.
131137 cell.cell_srs_res_list = generate_cell_srs_list (cell.cell_cfg );
132138
133- const unsigned srs_period_slots = static_cast <unsigned >(cell.cell_cfg .srs_cfg .srs_period .value ());
139+ const auto srs_period_slots = static_cast <unsigned >(cell.cell_cfg .srs_cfg .srs_period .value ());
134140 cell.slot_resource_cnt .reserve (srs_period_slots);
141+ cell.srs_res_offset_free_list .reserve (du_srs_policy_max_ul_th::cell_context::max_nof_srs_res);
135142
136143 for (unsigned offset = 0 ; offset != srs_period_slots; ++offset) {
144+ // We don't generate more than the maximum number of SRS resources per cell.
145+ if (cell.srs_res_offset_free_list .size () >= du_srs_policy_max_ul_th::cell_context::max_nof_srs_res) {
146+ break ;
147+ }
148+
137149 unsigned offset_res_cnt = 0U ;
150+ // Verify whether the offset maps to a partially- or fully-UL slot.
151+ if (cell_cfg_list_[0 ].tdd_ul_dl_cfg_common .has_value () and
152+ not is_ul_slot (offset, cell_cfg_list_[0 ].tdd_ul_dl_cfg_common .value ())) {
153+ cell.slot_resource_cnt .emplace_back (0U , offset_res_cnt);
154+ continue ;
155+ }
156+
138157 for (auto & res : cell.cell_srs_res_list ) {
139- // Handle TDD and FDD configurations separately, as we treat partially-UL slots differently from fully-UL slots.
158+ // Handle TDD and FDD configurations separately, as we treat partially-UL slots differently from
159+ // fully-UL slots.
140160 if (cell_cfg_list_[0 ].tdd_ul_dl_cfg_common .has_value ()) {
141- // Verify whether the offset maps to a partially- or fully-UL slot.
142- if (not is_ul_slot (offset, cell_cfg_list_[0 ].tdd_ul_dl_cfg_common .value ())) {
143- continue ;
144- }
145- // For partially-UL slots, we need to check if the SRS can be placed in the UL symbols of the slot.
161+ // For partially-UL slots, we need to check if the SRS can be placed in the UL symbols of the
162+ // slot.
146163 if (is_partually_ul_slot (offset, cell_cfg_list_[0 ].tdd_ul_dl_cfg_common .value ())) {
147164 // TODO: Fix check for pattern 2.
148165 if (res.symbols .start () < NOF_OFDM_SYM_PER_SLOT_NORMAL_CP -
@@ -184,12 +201,10 @@ bool du_srs_policy_max_ul_th::alloc_resources(cell_group_config& cell_grp_cfg)
184201 return true ;
185202 }
186203
187- // The UE SRS configuration is taken from a base configuration, saved in the GNB. The details that are UE specific
188- // will be added later on in this function.
204+ // The UE SRS configuration is taken from a base configuration, saved in the GNB. The details that are
205+ // UE specific will be added later on in this function.
189206 cell_grp_cfg.cells [0 ].serv_cell_cfg .ul_config ->init_ul_bwp .srs_cfg .emplace (
190- cells[cell_grp_cfg.cells [0 ].serv_cell_cfg .cell_index ]
191- .cell_cfg .ue_ded_serv_cell_cfg .ul_config .value ()
192- .init_ul_bwp .srs_cfg .value ());
207+ cells[cell_grp_cfg.cells [0 ].serv_cell_cfg .cell_index ].default_srs_cfg );
193208 srs_config& ue_srs_cfg = cell_grp_cfg.cells [0 ].serv_cell_cfg .ul_config ->init_ul_bwp .srs_cfg .value ();
194209 auto & free_srs_list = cells[cell_grp_cfg.cells [0 ].serv_cell_cfg .cell_index ].srs_res_offset_free_list ;
195210
@@ -220,14 +235,20 @@ bool du_srs_policy_max_ul_th::alloc_resources(cell_group_config& cell_grp_cfg)
220235 only_ue_srs_res.id .cell_res_id = du_res.cell_res_id ;
221236 only_ue_srs_res.id .ue_res_id = static_cast <srs_config::srs_res_id>(0U );
222237 only_ue_srs_res.periodicity_and_offset .value ().offset = srs_offset;
238+ only_ue_srs_res.tx_comb .size = cells[0 ].cell_cfg .srs_cfg .tx_comb ;
223239 only_ue_srs_res.tx_comb .tx_comb_offset = du_res.tx_comb_offset .to_uint ();
240+ only_ue_srs_res.tx_comb .tx_comb_cyclic_shift = du_res.cs ;
224241 only_ue_srs_res.freq_domain_pos = du_res.freq_dom_position ;
225242 only_ue_srs_res.res_mapping .start_pos = NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - du_res.symbols .start () - 1 ;
226243 only_ue_srs_res.res_mapping .nof_symb = static_cast <srs_nof_symbols>(du_res.symbols .length ());
227244 only_ue_srs_res.sequence_id = du_res.sequence_id ;
228245
229246 // Update the SRS configuration with the parameters that are common to the cell.
230247 only_ue_srs_res.freq_hop .c_srs = cells[cell_grp_cfg.cells [0 ].serv_cell_cfg .cell_index ].srs_common_params .c_srs ;
248+ // We assume that the frequency hopping is disabled and that the SRS occupies all possible RBs within the BWP. Refer
249+ // to Section 6.4.1.4.3, TS 38.211.
250+ only_ue_srs_res.freq_hop .b_srs = 0U ;
251+ only_ue_srs_res.freq_hop .b_hop = 0U ;
231252 only_ue_srs_res.freq_domain_shift =
232253 cells[cell_grp_cfg.cells [0 ].serv_cell_cfg .cell_index ].srs_common_params .freq_shift ;
233254
@@ -249,7 +270,8 @@ du_srs_policy_max_ul_th::cell_context::find_optimal_ue_srs_resource()
249270 // The weights assigned here can be set to any value, as long as:
250271 // - symbol_weight_base is greater than 0;
251272 // - reuse_slot_discount less than symbol_weight_base;
252- // - max_weight is > symbol_weight_base * (srs_builder_params::max_nof_symbols / srs_builder_params::nof_symbols).
273+ // - max_weight is > symbol_weight_base * (srs_builder_params::max_nof_symbols /
274+ // srs_builder_params::nof_symbols).
253275 static constexpr unsigned max_weight = 100U ;
254276 static constexpr unsigned symbol_weight_base = 10U ;
255277
@@ -270,8 +292,9 @@ du_srs_policy_max_ul_th::cell_context::find_optimal_ue_srs_resource()
270292 const unsigned symb_weight =
271293 (NOF_OFDM_SYM_PER_SLOT_NORMAL_CP - srs_res_cfg_it->symbols .start ()) * symbol_weight_base;
272294
273- // We consider a discount if the offset is already used but not full; this way, we give an incentive to the SRS
274- // resources not to be allocated on a new slot, to avoid taking PUSCH symbols on a new slot.
295+ // We consider a discount if the offset is already used but not full; this way, we give an incentive
296+ // to the SRS resources not to be allocated on a new slot, to avoid taking PUSCH symbols on a new
297+ // slot.
275298 const unsigned reuse_slot_discount = offset_used_not_full (srs_res.second ) ? symbol_weight_base / 2U : 0U ;
276299
277300 return symb_weight - reuse_slot_discount;
@@ -299,7 +322,7 @@ void du_srs_policy_max_ul_th::dealloc_resources(cell_group_config& cell_grp_cfg)
299322
300323 for (const auto & srs_res : ue_srs_cfg.srs_res_list ) {
301324 const unsigned offset_to_deallocate = srs_res.periodicity_and_offset .value ().offset ;
302- free_srs_list.push_back ({ srs_res.id .cell_res_id , offset_to_deallocate} );
325+ free_srs_list.emplace_back ( srs_res.id .cell_res_id , offset_to_deallocate);
303326
304327 // Update the used_not_full slot vector.
305328 srsran_assert (cells[0 ].slot_resource_cnt [offset_to_deallocate].first != 0 , " The offset is expected to be non-zero" );
0 commit comments