Skip to content

Commit a0ebf93

Browse files
committed
sched: computation of PUCCH multiplexing regions
1 parent c220d4d commit a0ebf93

File tree

3 files changed

+192
-29
lines changed

3 files changed

+192
-29
lines changed

lib/scheduler/pucch_scheduling/pucch_collision_manager.cpp

Lines changed: 92 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "srsran/ran/pucch/pucch_mapping.h"
1616
#include "srsran/ran/resource_allocation/ofdm_symbol_range.h"
1717
#include "srsran/ran/resource_allocation/rb_interval.h"
18+
#include <algorithm>
1819

1920
using namespace srsran;
2021

@@ -133,8 +134,44 @@ struct resource_info {
133134
}
134135
};
135136

137+
/// \brief Represents a multiplexing region of PUCCH resources.
138+
/// Contains parameters that all resources in the region have in common.
139+
struct mux_region {
140+
/// Time-frequency grants of the region.
141+
time_freq_grants grants;
142+
/// PUCCH format of the region.
143+
pucch_format format;
144+
145+
/// Check if a a given resource belongs to this multiplexing region.
146+
bool does_resource_belong(const resource_info& res) const { return res.format == format and res.grants == grants; }
147+
};
148+
136149
} // namespace
137150

151+
/// Collects all PUCCH resources (common + dedicated) from the cell configuration.
152+
static static_vector<resource_info, pucch_collision_manager::max_nof_cell_resources>
153+
get_all_resources(const cell_configuration& cell_cfg)
154+
{
155+
// Get the parameter N_bwp_size, which is the Initial UL BWP size in PRBs, as per TS 38.213, Section 9.2.1.
156+
const unsigned size_ul_bwp = cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.length();
157+
158+
// Get PUCCH common resource config from Table 9.2.1-1, TS 38.213.
159+
const pucch_default_resource common_default_res = get_pucch_default_resource(
160+
cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->pucch_resource_common, size_ul_bwp);
161+
162+
// Collect all resources (common + dedicated).
163+
static_vector<resource_info, pucch_collision_manager::max_nof_cell_resources> all_resources;
164+
for (unsigned r_pucch = 0; r_pucch != pucch_collision_manager::nof_common_res; ++r_pucch) {
165+
all_resources.push_back(resource_info(common_default_res, r_pucch, size_ul_bwp));
166+
}
167+
for (const auto& res : cell_cfg.ded_pucch_resources) {
168+
all_resources.push_back(resource_info(res));
169+
}
170+
171+
return all_resources;
172+
}
173+
174+
/// Checks if two PUCCH resources collide.
138175
static bool do_resources_collide(const resource_info& res1, const resource_info& res2)
139176
{
140177
if (not res1.grants.overlaps(res2.grants)) {
@@ -160,6 +197,7 @@ static bool do_resources_collide(const resource_info& res1, const resource_info&
160197
pucch_collision_manager::pucch_collision_manager(const cell_configuration& cell_cfg_) :
161198
cell_cfg(cell_cfg_),
162199
collision_matrix(compute_collisions(cell_cfg)),
200+
mux_matrix(compute_mux_regions(cell_cfg)),
163201
slots_ctx({bounded_bitset<max_nof_cell_resources>(nof_common_res + cell_cfg.ded_pucch_resources.size())})
164202
{
165203
}
@@ -272,33 +310,19 @@ void pucch_collision_manager::free_ded(slot_point sl, unsigned cell_res_id)
272310
pucch_collision_manager::collision_matrix_t
273311
pucch_collision_manager::compute_collisions(const cell_configuration& cell_cfg)
274312
{
275-
collision_matrix_t matrix(
276-
nof_common_res + cell_cfg.ded_pucch_resources.size(),
277-
bounded_bitset<max_nof_cell_resources>(nof_common_res + cell_cfg.ded_pucch_resources.size()));
278-
279-
// Get the parameter N_bwp_size, which is the Initial UL BWP size in PRBs, as per TS 38.213, Section 9.2.1.
280-
const unsigned size_ul_bwp = cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.length();
281-
282-
// Get PUCCH common resource config from Table 9.2.1-1, TS 38.213.
283-
const pucch_default_resource common_default_res = get_pucch_default_resource(
284-
cell_cfg.ul_cfg_common.init_ul_bwp.pucch_cfg_common->pucch_resource_common, size_ul_bwp);
313+
const unsigned nof_res = nof_common_res + cell_cfg.ded_pucch_resources.size();
314+
collision_matrix_t matrix(nof_res, bounded_bitset<max_nof_cell_resources>(nof_res));
285315

286316
// Collect all resources (common + dedicated).
287-
static_vector<resource_info, max_nof_cell_resources> all_resources;
288-
for (unsigned r_pucch = 0; r_pucch != nof_common_res; ++r_pucch) {
289-
all_resources.push_back(resource_info(common_default_res, r_pucch, size_ul_bwp));
290-
}
291-
for (const auto& res : cell_cfg.ded_pucch_resources) {
292-
all_resources.push_back(resource_info(res));
293-
}
317+
static_vector<resource_info, max_nof_cell_resources> all_resources = get_all_resources(cell_cfg);
294318

295319
// Precompute the collision matrix.
296-
for (size_t i = 0; i != all_resources.size(); ++i) {
320+
for (size_t i = 0; i != nof_res; ++i) {
297321
// A resource always collides with itself.
298322
matrix[i].set(i);
299323

300324
// Note: The collision matrix is symmetric.
301-
for (size_t j = i + 1; j != all_resources.size(); ++j) {
325+
for (size_t j = i + 1; j != nof_res; ++j) {
302326
if (do_resources_collide(all_resources[i], all_resources[j])) {
303327
matrix[i].set(j);
304328
matrix[j].set(i);
@@ -308,3 +332,52 @@ pucch_collision_manager::compute_collisions(const cell_configuration& cell_cfg)
308332

309333
return matrix;
310334
}
335+
336+
pucch_collision_manager::mux_regions_matrix_t
337+
pucch_collision_manager::compute_mux_regions(const cell_configuration& cell_cfg)
338+
{
339+
unsigned nof_res = nof_common_res + cell_cfg.ded_pucch_resources.size();
340+
mux_regions_matrix_t mux_regions;
341+
342+
// Collect all resources (common + dedicated).
343+
static_vector<resource_info, max_nof_cell_resources> all_resources = get_all_resources(cell_cfg);
344+
345+
// Helper structure to keep track of multiplexing regions and their members.
346+
struct region_record {
347+
mux_region region;
348+
bounded_bitset<max_nof_cell_resources> members;
349+
};
350+
static_vector<region_record, max_nof_cell_resources> tmp_regions;
351+
352+
for (size_t i = 0; i != nof_res; ++i) {
353+
const auto& res = all_resources[i];
354+
355+
// Find if the resource belongs to an existing multiplexing region.
356+
auto* region_it = std::find_if(tmp_regions.begin(), tmp_regions.end(), [&res](const region_record& record) {
357+
return record.region.does_resource_belong(res);
358+
});
359+
360+
if (region_it == tmp_regions.end()) {
361+
// If the multiplexing region does not exist yet, create it.
362+
region_it = &tmp_regions.emplace_back(region_record{mux_region{
363+
.grants = res.grants,
364+
.format = res.format,
365+
},
366+
bounded_bitset<max_nof_cell_resources>(nof_res)});
367+
}
368+
369+
// Add the resource to the multiplexing region.
370+
region_it->members.set(i);
371+
}
372+
373+
// Return only multiplexing regions with more than one resource.
374+
for (const auto& record : tmp_regions) {
375+
if (record.members.count() < 2) {
376+
continue;
377+
}
378+
379+
mux_regions.push_back(record.members);
380+
}
381+
382+
return mux_regions;
383+
}

lib/scheduler/pucch_scheduling/pucch_collision_manager.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ namespace srsran {
2626
class pucch_collision_manager
2727
{
2828
public:
29+
/// Maximum number of common PUCCH resources managed by the collision manager.
30+
static constexpr unsigned nof_common_res = pucch_constants::MAX_NOF_CELL_COMMON_PUCCH_RESOURCES;
31+
/// Maximum number of PUCCH resources managed by the collision manager (common + dedicated).
32+
static constexpr unsigned max_nof_cell_resources = nof_common_res + pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES;
33+
2934
/// Bounded integer representing a common PUCCH resource index (r_pucch).
3035
using r_pucch_t = bounded_integer<unsigned, 0, 15>;
3136

@@ -40,6 +45,9 @@ class pucch_collision_manager
4045
/// Checks if a common PUCCH resource collides with a dedicated PUCCH resource.
4146
bool check_common_to_ded_collision(r_pucch_t r_pucch, unsigned cell_res_id) const;
4247

48+
/// Returns the number of multiplexing regions defined in the cell configuration.
49+
unsigned nof_mux_regions() const { return mux_matrix.size(); }
50+
4351
/// \brief Checks if a common PUCCH resource can be allocated at a given slot.
4452
/// A resource can be allocated if it is not in use and it does not collide with any other resource already allocated
4553
/// at the same slot.
@@ -63,20 +71,24 @@ class pucch_collision_manager
6371
void free_ded(slot_point sl, unsigned cell_res_id);
6472

6573
private:
66-
static constexpr unsigned nof_common_res = pucch_constants::MAX_NOF_CELL_COMMON_PUCCH_RESOURCES;
67-
static constexpr unsigned max_nof_cell_resources = nof_common_res + pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES;
68-
69-
// Collision matrix indicating which resources collide with each other.
70-
// C[i][j] = 1 if resource i collides with resource j, 0 otherwise.
74+
/// \brief Collision matrix indicating which resources collide with each other.
75+
/// - C[i][j] = 1 if resource i collides with resource j, 0 otherwise.
7176
using collision_matrix_t = static_vector<bounded_bitset<max_nof_cell_resources>, max_nof_cell_resources>;
77+
/// \brief Matrix of multiplexing regions indicating which resources can be multiplexed together.
78+
/// - Each row represents a multiplexing region.
79+
/// - M[i][j] = 1 if resource j belongs to multiplexing region i, 0 otherwise.
80+
/// \remark Multiplexing regions with only one resource (i.e., non-multiplexed resources) are not represented in this
81+
/// matrix. Therefore, we can have a maximum of $max_nof_cell_resources / 2$ rows.
82+
using mux_regions_matrix_t = static_vector<bounded_bitset<max_nof_cell_resources>, max_nof_cell_resources / 2>;
7283

73-
const cell_configuration& cell_cfg;
74-
const collision_matrix_t collision_matrix;
84+
const cell_configuration& cell_cfg;
85+
const collision_matrix_t collision_matrix;
86+
const mux_regions_matrix_t mux_matrix;
7587

7688
/// Allocation context for a specific slot.
7789
struct slot_context {
7890
/// Bitset representing the current usage state of all PUCCH resources (common and dedicated) in this slot.
79-
/// S[i] = 1 if resource i is in use, 0 otherwise.
91+
/// - S[i] = 1 if resource i is in use, 0 otherwise.
8092
bounded_bitset<max_nof_cell_resources> current_state;
8193
};
8294

@@ -88,6 +100,9 @@ class pucch_collision_manager
88100

89101
/// Computes the collision matrix for all PUCCH resources in the cell configuration.
90102
static collision_matrix_t compute_collisions(const cell_configuration& cell_cfg);
103+
104+
/// Computes the multiplexing matrix for all PUCCH resources in the cell configuration.
105+
static mux_regions_matrix_t compute_mux_regions(const cell_configuration& cell_cfg);
91106
};
92107

93108
} // namespace srsran

tests/unittests/scheduler/uci_and_pucch/pucch_collision_manager_test.cpp

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919

2020
using namespace srsran;
2121

22-
static cell_configuration make_test_cell_configuration(const std::vector<pucch_resource>& ded_res)
22+
static cell_configuration make_test_cell_configuration(const std::vector<pucch_resource>& ded_res = {},
23+
unsigned pucch_resource_common = 11)
2324
{
2425
const auto expert_cfg = config_helpers::make_default_scheduler_expert_config();
2526
auto sched_req = sched_config_helper::make_default_sched_cell_configuration_request();
2627
sched_req.ded_pucch_resources = ded_res;
28+
sched_req.ul_cfg_common.init_ul_bwp.pucch_cfg_common.value().pucch_resource_common = pucch_resource_common;
2729
return cell_configuration{expert_cfg, sched_req};
2830
}
2931

@@ -50,7 +52,7 @@ static cell_configuration make_test_cell_configuration(const std::vector<pucch_r
5052
// |---------|--------|----------------|------------------|------------------|
5153
TEST(pucch_collision_manager_test, common_resources_dont_collide_with_each_other)
5254
{
53-
const auto cell_cfg = make_test_cell_configuration({});
55+
const auto cell_cfg = make_test_cell_configuration();
5456
pucch_collision_manager col_manager(cell_cfg);
5557

5658
slot_point sl(cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.scs, 0);
@@ -202,3 +204,76 @@ TEST(pucch_collision_manager_test, f4_multiplexed_resources_dont_collide)
202204
}
203205
}
204206
}
207+
208+
TEST(pucch_collision_manager_test, check_mux_regions_count_for_common_resources)
209+
{
210+
static constexpr std::array<unsigned, 16> nof_expected_mux_regions = {
211+
8, // 2 CS
212+
6, // 3 CS, resources distributed in regions as 3-3-2-3-3-2
213+
6, // 3 CS, resources distributed in regions as 3-3-2-3-3-2
214+
8, // 2 CS
215+
4, // 4 CS
216+
4, // 4 CS
217+
4, // 4 CS
218+
8, // 2 CS
219+
4, // 4 CS
220+
4, // 4 CS
221+
4, // 4 CS
222+
8, // 2 CS
223+
4, // 4 CS
224+
4, // 4 CS
225+
4, // 4 CS
226+
4, // 4 CS
227+
};
228+
for (unsigned pucch_resource_common = 0; pucch_resource_common != 16; ++pucch_resource_common) {
229+
const auto cell_cfg = make_test_cell_configuration({}, pucch_resource_common);
230+
pucch_collision_manager col_manager(cell_cfg);
231+
232+
ASSERT_EQ(nof_expected_mux_regions[pucch_resource_common], col_manager.nof_mux_regions());
233+
}
234+
}
235+
236+
TEST(pucch_collision_manager_test, handles_max_dedicated_resources_with_unique_regions)
237+
{
238+
auto cell_cfg = make_test_cell_configuration();
239+
240+
std::vector<pucch_resource> ded_res_list;
241+
ded_res_list.reserve(pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES);
242+
243+
// Generate a list with the maximum number of dedicated PUCCH resources in a way that all resources belongs to a
244+
// different multiplexing region.
245+
for (unsigned sym = 0, prb = 0; ded_res_list.size() != pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES;) {
246+
const unsigned res_idx = ded_res_list.size();
247+
ded_res_list.push_back(pucch_resource{
248+
.res_id = {res_idx, res_idx},
249+
.starting_prb = prb,
250+
.second_hop_prb = std::nullopt,
251+
.nof_symbols = 1,
252+
.starting_sym_idx = static_cast<uint8_t>(sym),
253+
.format = pucch_format::FORMAT_2,
254+
.format_params = pucch_format_2_3_cfg{.nof_prbs = 1},
255+
});
256+
257+
// By using different starting symbols and PRBs for each resource, we ensure that all resources have unique
258+
// time-frequency allocations, and thus belong to different multiplexing regions.
259+
// Using Format 2 ensures they are not multiplexed with the common resources either.
260+
++sym;
261+
if (sym == NOF_OFDM_SYM_PER_SLOT_NORMAL_CP) {
262+
sym = 0;
263+
++prb;
264+
if (prb == cell_cfg.ul_cfg_common.init_ul_bwp.generic_params.crbs.length()) {
265+
// No more PRBs available. This should not happen.
266+
break;
267+
}
268+
}
269+
}
270+
ASSERT_EQ(ded_res_list.size(), pucch_constants::MAX_NOF_CELL_PUCCH_RESOURCES)
271+
<< "Failed to create the maximum number of dedicated PUCCH resources for the test";
272+
273+
// Overwrite the cell configuration with the dedicated resources.
274+
cell_cfg.ded_pucch_resources = ded_res_list;
275+
pucch_collision_manager col_manager(cell_cfg);
276+
277+
// Only the multiplexing regions of the common resources should be present.
278+
EXPECT_EQ(8U, col_manager.nof_mux_regions());
279+
}

0 commit comments

Comments
 (0)