Skip to content

Commit d4bb5f3

Browse files
frankistcodebot
authored andcommitted
sched: derive PRACH config index based on provided TDD pattern
1 parent d71be37 commit d4bb5f3

File tree

10 files changed

+212
-69
lines changed

10 files changed

+212
-69
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
*
3+
* Copyright 2021-2023 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#pragma once
12+
13+
#include "rach_config_common.h"
14+
#include "srsran/adt/expected.h"
15+
#include "srsran/adt/interval.h"
16+
17+
namespace srsran {
18+
19+
struct tdd_ul_dl_config_common;
20+
21+
namespace prach_helper {
22+
23+
/// \brief Finds whether a PRACH config index fits in the provided TDD pattern.
24+
/// \return In case of failure, returns the range of PRACH slots that did not fit in the TDD pattern. If the PRACH
25+
/// configuration is invalid, an empty interval of slots is returned.
26+
error_type<interval<uint8_t>> prach_fits_in_tdd_pattern(subcarrier_spacing pusch_scs,
27+
bool cp_extended,
28+
uint8_t prach_cfg_idx,
29+
const tdd_ul_dl_config_common& tdd_cfg);
30+
31+
/// \brief Finds a PRACH configuration index that ensures that PRACH falls in an TDD UL slot.
32+
optional<uint8_t>
33+
find_valid_prach_config_index(subcarrier_spacing pusch_scs, bool cp_extended, const tdd_ul_dl_config_common& tdd_cfg);
34+
35+
} // namespace prach_helper
36+
} // namespace srsran
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
*
3+
* Copyright 2021-2023 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#pragma once
12+
13+
#include "restricted_set_config.h"
14+
#include "srsran/adt/bounded_integer.h"
15+
#include "srsran/adt/optional.h"
16+
#include "srsran/ran/subcarrier_spacing.h"
17+
18+
namespace srsran {
19+
20+
/// \remark See TS 38.331, RACH-ConfigGeneric.
21+
struct rach_config_generic {
22+
/// Values: {0,...,255}.
23+
uint8_t prach_config_index;
24+
/// Msg2 RAR window length in #slots. Network configures a value < 10msec. Values: (1, 2, 4, 8, 10, 20, 40, 80).
25+
unsigned ra_resp_window;
26+
/// Number of PRACH occasions FDMed in one time instance as per TS38.211, clause 6.3.3.2.
27+
unsigned msg1_fdm;
28+
/// Offset of lowest PRACH transmission occasion in frequency domain respective to PRB 0,
29+
/// as per TS38.211, clause 6.3.3.2. Possible values: {0,...,MAX_NOF_PRB - 1}.
30+
unsigned msg1_frequency_start;
31+
/// Zero-correlation zone configuration number as per TS38.331 "zeroCorrelationZoneConfig", used to derive N_{CS}.
32+
uint16_t zero_correlation_zone_config;
33+
/// \brief \c preambleReceivedTargetPower, part of \c RACH-ConfigGeneric, TS 38.311.
34+
/// Target power level at the network receiver side, in dBm. Only values multiple of 2 are valid.
35+
bounded_integer<int, -202, -60> preamble_rx_target_pw;
36+
};
37+
38+
/// Used to specify the cell-specific random-access parameters as per TS 38.331, "RACH-ConfigCommon".
39+
struct rach_config_common {
40+
rach_config_generic rach_cfg_generic;
41+
/// Total number of prambles used for contention based and contention free RA. Values: (1..64).
42+
optional<unsigned> total_nof_ra_preambles;
43+
/// PRACH Root Sequence Index can be of 2 types, as per \c prach-RootSequenceIndex, \c RACH-ConfigCommon, TS 38.331.
44+
/// We use \c true for l839, while \c false for l139.
45+
bool is_prach_root_seq_index_l839;
46+
/// PRACH root sequence index. Values: (1..839).
47+
/// \remark See TS 38.211, clause 6.3.3.1.
48+
unsigned prach_root_seq_index;
49+
/// \brief Subcarrier spacing of PRACH as per TS38.331, "RACH-ConfigCommon". If invalid, the UE applies the SCS as
50+
/// derived from the prach-ConfigurationIndex in RACH-ConfigGeneric as per TS38.211 Tables 6.3.3.1-[1-3].
51+
subcarrier_spacing msg1_scs;
52+
restricted_set_config restricted_set;
53+
/// Enables the transform precoder for Msg3 transmission according to clause 6.1.3 of TS 38.214.
54+
bool msg3_transform_precoder;
55+
};
56+
57+
} // namespace srsran

include/srsran/scheduler/config/bwp_configuration.h

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "srsran/ran/pcch/pcch_configuration.h"
2020
#include "srsran/ran/pdcch/coreset.h"
2121
#include "srsran/ran/pdcch/search_space.h"
22+
#include "srsran/ran/prach/rach_config_common.h"
2223
#include "srsran/ran/prach/restricted_set_config.h"
2324
#include "srsran/ran/pucch/pucch_configuration.h"
2425
#include "srsran/ran/resource_block.h"
@@ -106,43 +107,6 @@ struct bwp_downlink_common {
106107
pdsch_config_common pdsch_common;
107108
};
108109

109-
/// \remark See TS 38.331, RACH-ConfigGeneric.
110-
struct rach_config_generic {
111-
/// Values: {0,...,255}.
112-
uint8_t prach_config_index;
113-
/// Msg2 RAR window length in #slots. Network configures a value < 10msec. Values: (1, 2, 4, 8, 10, 20, 40, 80).
114-
unsigned ra_resp_window;
115-
/// Number of PRACH occasions FDMed in one time instance as per TS38.211, clause 6.3.3.2.
116-
unsigned msg1_fdm;
117-
/// Offset of lowest PRACH transmission occasion in frequency domain respective to PRB 0,
118-
/// as per TS38.211, clause 6.3.3.2. Possible values: {0,...,MAX_NOF_PRB - 1}.
119-
unsigned msg1_frequency_start;
120-
/// Zero-correlation zone configuration number as per TS38.331 "zeroCorrelationZoneConfig", used to derive N_{CS}.
121-
uint16_t zero_correlation_zone_config;
122-
/// \brief \c preambleReceivedTargetPower, part of \c RACH-ConfigGeneric, TS 38.311.
123-
/// Target power level at the network receiver side, in dBm. Only values multiple of 2 are valid.
124-
bounded_integer<int, -202, -60> preamble_rx_target_pw;
125-
};
126-
127-
/// Used to specify the cell-specific random-access parameters as per TS 38.331, "RACH-ConfigCommon".
128-
struct rach_config_common {
129-
rach_config_generic rach_cfg_generic;
130-
/// Total number of prambles used for contention based and contention free RA. Values: (1..64).
131-
optional<unsigned> total_nof_ra_preambles;
132-
/// PRACH Root Sequence Index can be of 2 types, as per \c prach-RootSequenceIndex, \c RACH-ConfigCommon, TS 38.331.
133-
/// We use \c true for l839, while \c false for l139.
134-
bool is_prach_root_seq_index_l839;
135-
/// PRACH root sequence index. Values: (1..839).
136-
/// \remark See TS 38.211, clause 6.3.3.1.
137-
unsigned prach_root_seq_index;
138-
/// \brief Subcarrier spacing of PRACH as per TS38.331, "RACH-ConfigCommon". If invalid, the UE applies the SCS as
139-
/// derived from the prach-ConfigurationIndex in RACH-ConfigGeneric as per TS38.211 Tables 6.3.3.1-[1-3].
140-
subcarrier_spacing msg1_scs;
141-
restricted_set_config restricted_set;
142-
/// Enables the transform precoder for Msg3 transmission according to clause 6.1.3 of TS 38.214.
143-
bool msg3_transform_precoder;
144-
};
145-
146110
struct pusch_time_domain_resource_allocation {
147111
/// Values: (0..32).
148112
unsigned k2;

lib/ran/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ add_library(srsran_ran
2424
prach/prach_cyclic_shifts.cpp
2525
prach/prach_frequency_mapping.cpp
2626
prach/prach_preamble_information.cpp
27+
prach/prach_helper.cpp
2728
precoding/precoding_codebooks.cpp
2829
pusch/pusch_mcs.cpp
2930
pusch/pusch_uci_beta_offset.cpp

lib/ran/prach/prach_helper.cpp

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
*
3+
* Copyright 2021-2023 Software Radio Systems Limited
4+
*
5+
* By using this file, you agree to the terms and conditions set
6+
* forth in the LICENSE file which can be found at the top level of
7+
* the distribution.
8+
*
9+
*/
10+
11+
#include "srsran/ran/prach/prach_helper.h"
12+
#include "srsran/ran/prach/prach_configuration.h"
13+
#include "srsran/ran/prach/prach_preamble_information.h"
14+
#include "srsran/ran/tdd_ul_dl_config.h"
15+
16+
using namespace srsran;
17+
18+
error_type<interval<uint8_t>> srsran::prach_helper::prach_fits_in_tdd_pattern(subcarrier_spacing pusch_scs,
19+
bool cp_extended,
20+
uint8_t prach_cfg_idx,
21+
const tdd_ul_dl_config_common& tdd_cfg)
22+
{
23+
const unsigned symbols_per_slot = cp_extended ? NOF_OFDM_SYM_PER_SLOT_EXTENDED_CP : NOF_OFDM_SYM_PER_SLOT_NORMAL_CP;
24+
const unsigned nof_slots_per_subframe = get_nof_slots_per_subframe(pusch_scs);
25+
26+
const prach_configuration prach_cfg = prach_configuration_get(frequency_range::FR1, duplex_mode::TDD, prach_cfg_idx);
27+
if (prach_cfg.format == prach_format_type::invalid) {
28+
return interval<uint8_t>{};
29+
}
30+
const prach_symbols_slots_duration dur = get_prach_duration_info(prach_cfg, pusch_scs);
31+
32+
// For each subframe with PRACH, check if all slots are UL.
33+
for (uint8_t subframe_index : prach_cfg.subframe) {
34+
// There are configuration for which the PRACH starts in an odd slot within the subframe
35+
// (for numerologies > mu(SCS 15kHz)); the addition of start_slot_pusch_scs compensate for this.
36+
uint8_t start_slot_index = subframe_index * nof_slots_per_subframe + dur.start_slot_pusch_scs;
37+
for (uint8_t prach_slot_idx = 0; prach_slot_idx != dur.prach_length_slots; ++prach_slot_idx) {
38+
uint8_t slot_index = start_slot_index + prach_slot_idx;
39+
ofdm_symbol_range active_ul_symbols = get_active_tdd_ul_symbols(tdd_cfg, slot_index, cp_extended);
40+
41+
// Note: For now, PRACH in special slots is not supported.
42+
if (active_ul_symbols.length() != symbols_per_slot) {
43+
// No UL symbols exist in this slot.
44+
return interval<uint8_t>{start_slot_index, start_slot_index + dur.prach_length_slots};
45+
}
46+
}
47+
}
48+
49+
return {};
50+
}
51+
52+
optional<uint8_t> srsran::prach_helper::find_valid_prach_config_index(subcarrier_spacing pusch_scs,
53+
bool cp_extended,
54+
const tdd_ul_dl_config_common& tdd_cfg)
55+
{
56+
static constexpr size_t NOF_PRACH_CONFIG_INDEXES = 256;
57+
58+
// Iterate over different PRACH configuration indexes until a valid one is found.
59+
for (unsigned prach_cfg_idx = 0; prach_cfg_idx != NOF_PRACH_CONFIG_INDEXES; ++prach_cfg_idx) {
60+
if (prach_fits_in_tdd_pattern(pusch_scs, cp_extended, prach_cfg_idx, tdd_cfg).has_value()) {
61+
return prach_cfg_idx;
62+
}
63+
}
64+
return nullopt;
65+
}

lib/ran/tdd_ul_dl_config.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ nof_active_symbols(const tdd_ul_dl_config_common& cfg, unsigned slot_index, bool
3939
}
4040

4141
// UL case.
42-
const unsigned ul_pattern_start = period_slots - pattern->nof_ul_slots;
42+
const unsigned ul_pattern_start = pattern->dl_ul_tx_period_nof_slots - pattern->nof_ul_slots;
4343
if (slot_idx_period >= ul_pattern_start) {
4444
return cp_extended ? NOF_OFDM_SYM_PER_SLOT_EXTENDED_CP : NOF_OFDM_SYM_PER_SLOT_NORMAL_CP;
45-
} else if (slot_idx_period == ul_pattern_start - 1) {
45+
}
46+
if (slot_idx_period == ul_pattern_start - 1) {
4647
return pattern->nof_ul_symbols;
4748
}
4849
return 0;

lib/scheduler/config/scheduler_cell_config_validator.cpp

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "srsran/ran/duplex_mode.h"
1515
#include "srsran/ran/prach/prach_configuration.h"
1616
#include "srsran/ran/prach/prach_frequency_mapping.h"
17+
#include "srsran/ran/prach/prach_helper.h"
1718
#include "srsran/ran/prach/prach_preamble_information.h"
1819
#include "srsran/scheduler/sched_consts.h"
1920

@@ -61,28 +62,26 @@ static error_type<std::string> validate_rach_cfg_common(const sched_cell_configu
6162
rach_cfg_cmn.rach_cfg_generic.prach_config_index);
6263
VERIFY(prach_cfg.format < prach_format_type::invalid, "Invalid PRACH format");
6364

64-
subcarrier_spacing pusch_scs = msg.ul_cfg_common.init_ul_bwp.generic_params.scs;
65-
prach_symbols_slots_duration prach_duration_info = get_prach_duration_info(prach_cfg, pusch_scs);
66-
prach_subcarrier_spacing prach_scs = is_long_preamble(prach_cfg.format)
67-
? get_prach_preamble_long_info(prach_cfg.format).scs
68-
: to_ra_subcarrier_spacing(pusch_scs);
65+
subcarrier_spacing pusch_scs = msg.ul_cfg_common.init_ul_bwp.generic_params.scs;
66+
prach_subcarrier_spacing prach_scs = is_long_preamble(prach_cfg.format)
67+
? get_prach_preamble_long_info(prach_cfg.format).scs
68+
: to_ra_subcarrier_spacing(pusch_scs);
6969

7070
// Check if the PRACH preambles fall into UL slots
7171
if (msg.tdd_ul_dl_cfg_common.has_value()) {
7272
const cell_configuration cell_cfg{msg};
73-
// For each subframe with PRACH, check if all slots are UL.
74-
for (unsigned subframe_idx : prach_cfg.subframe) {
75-
// There are configuration for which the PRACH starts in an odd slot within the subframe
76-
// (for numerologies > mu(SCS 15kHz)); the addition of start_slot_pusch_scs compensate for this.
77-
const unsigned start_slot_idx =
78-
subframe_idx * (1U << to_numerology_value(pusch_scs)) + prach_duration_info.start_slot_pusch_scs;
79-
for (unsigned sl = 0; sl < prach_duration_info.prach_length_slots; ++sl) {
80-
VERIFY(
81-
cell_cfg.is_fully_ul_enabled(slot_point{to_numerology_value(pusch_scs), sl + start_slot_idx}),
82-
"PRACH configuration index {} not supported with current TDD pattern. Slot indexes used for PRACH {} fall "
83-
"outside TDD UL slots",
84-
rach_cfg_cmn.rach_cfg_generic.prach_config_index,
85-
interval<unsigned>{start_slot_idx, start_slot_idx + prach_duration_info.prach_length_slots});
73+
74+
auto ret = prach_helper::prach_fits_in_tdd_pattern(pusch_scs,
75+
msg.ul_cfg_common.init_ul_bwp.generic_params.cp_extended,
76+
rach_cfg_cmn.rach_cfg_generic.prach_config_index,
77+
*msg.tdd_ul_dl_cfg_common);
78+
if (ret.is_error()) {
79+
std::string s = fmt::format("PRACH configuration index {} not supported with current TDD pattern.",
80+
rach_cfg_cmn.rach_cfg_generic.prach_config_index);
81+
if (ret.error().empty()) {
82+
return s + fmt::format(" Cause: PRACH configuration is not valid");
83+
} else {
84+
return s + fmt::format(" Cause: Slot indexes used for PRACH {} fall outside TDD UL slots", ret.error());
8685
}
8786
}
8887
}

tests/unittests/scheduler/scheduler_tdd_test.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "test_utils/indication_generators.h"
1616
#include "test_utils/result_test_helpers.h"
1717
#include "test_utils/scheduler_test_bench.h"
18+
#include "srsran/ran/prach/prach_helper.h"
1819
#include <gtest/gtest.h>
1920

2021
using namespace srsran;
@@ -49,6 +50,13 @@ class base_scheduler_tdd_tester : public scheduler_test_bench
4950
// TDD params.
5051
sched_cfg.tdd_ul_dl_cfg_common = tdd_cfg;
5152

53+
// RACH config
54+
optional<uint8_t> chosen_prach_cfg_idx =
55+
prach_helper::find_valid_prach_config_index(sched_cfg.ul_cfg_common.init_ul_bwp.generic_params.scs,
56+
sched_cfg.ul_cfg_common.init_ul_bwp.generic_params.cp_extended,
57+
*sched_cfg.tdd_ul_dl_cfg_common);
58+
sched_cfg.ul_cfg_common.init_ul_bwp.rach_cfg_common->rach_cfg_generic.prach_config_index = *chosen_prach_cfg_idx;
59+
5260
return sched_cfg;
5361
}());
5462

@@ -68,13 +76,13 @@ class base_scheduler_tdd_tester : public scheduler_test_bench
6876

6977
using test_params = tdd_ul_dl_config_common;
7078

71-
class scheduler_tdd_tester : public base_scheduler_tdd_tester, public ::testing::TestWithParam<test_params>
79+
class scheduler_dl_tdd_tester : public base_scheduler_tdd_tester, public ::testing::TestWithParam<test_params>
7280
{
7381
public:
74-
scheduler_tdd_tester() : base_scheduler_tdd_tester(GetParam()) {}
82+
scheduler_dl_tdd_tester() : base_scheduler_tdd_tester(GetParam()) {}
7583
};
7684

77-
TEST_P(scheduler_tdd_tester, all_dl_slots_are_scheduled)
85+
TEST_P(scheduler_dl_tdd_tester, all_dl_slots_are_scheduled)
7886
{
7987
// Enqueue enough bytes for continuous DL tx.
8088
dl_buffer_state_indication_message dl_buf_st{ue_idx, ue_drb_lcid, 10000000};
@@ -83,7 +91,6 @@ TEST_P(scheduler_tdd_tester, all_dl_slots_are_scheduled)
8391
const unsigned MAX_COUNT = 1000;
8492
for (unsigned count = 0; count != MAX_COUNT; ++count) {
8593
this->run_slot();
86-
ASSERT_TRUE(this->last_sched_res->success);
8794

8895
// For every DL slot.
8996
// Note: Skip special slots in test for now.
@@ -105,7 +112,13 @@ TEST_P(scheduler_tdd_tester, all_dl_slots_are_scheduled)
105112
}
106113
}
107114

108-
TEST_P(scheduler_tdd_tester, all_ul_slots_are_scheduled)
115+
class scheduler_ul_tdd_tester : public base_scheduler_tdd_tester, public ::testing::TestWithParam<test_params>
116+
{
117+
public:
118+
scheduler_ul_tdd_tester() : base_scheduler_tdd_tester(GetParam()) {}
119+
};
120+
121+
TEST_P(scheduler_ul_tdd_tester, all_ul_slots_are_scheduled)
109122
{
110123
// Enqueue enough bytes for continuous UL tx.
111124
ul_bsr_indication_message bsr{
@@ -120,7 +133,6 @@ TEST_P(scheduler_tdd_tester, all_ul_slots_are_scheduled)
120133
const unsigned MAX_COUNT = 1000;
121134
for (unsigned count = 0; count != MAX_COUNT; ++count) {
122135
this->run_slot();
123-
ASSERT_TRUE(this->last_sched_res->success);
124136

125137
// For every UL slot.
126138
// Note: Skip special slots in test for now.
@@ -146,13 +158,21 @@ TEST_P(scheduler_tdd_tester, all_ul_slots_are_scheduled)
146158

147159
INSTANTIATE_TEST_SUITE_P(
148160
scheduler_tdd_test,
149-
scheduler_tdd_tester,
161+
scheduler_dl_tdd_tester,
150162
testing::Values(
151163
// clang-format off
152164
// test_params{ref_scs, pattern1={slot_period, DL_slots, DL_symbols, UL_slots, UL_symbols}, pattern2={...}}
153165
test_params{subcarrier_spacing::kHz30, {10, 6, 4, 3, 4}, nullopt}));
154-
// Note: Not working because some PDSCHs fail due to insufficient PUCCH resources.
155-
//test_params{subcarrier_spacing::kHz30, {10, 7, 4, 2, 4}, nullopt},
156-
// Note: Not working because PRACH configuration needs to be adjusted.
157-
//test_params{subcarrier_spacing::kHz30, {6, 3, 4, 2, 4}, tdd_ul_dl_pattern{4, 4, 0, 0, 0}}));
166+
// TODO: Support more TDD patterns.
167+
// clang-format on
168+
169+
INSTANTIATE_TEST_SUITE_P(
170+
scheduler_tdd_test,
171+
scheduler_ul_tdd_tester,
172+
testing::Values(
173+
// clang-format off
174+
// test_params{ref_scs, pattern1={slot_period, DL_slots, DL_symbols, UL_slots, UL_symbols}, pattern2={...}}
175+
test_params{subcarrier_spacing::kHz30, {10, 6, 4, 3, 4}, nullopt},
176+
test_params{subcarrier_spacing::kHz30, {10, 7, 4, 2, 4}, nullopt},
177+
test_params{subcarrier_spacing::kHz30, {6, 3, 4, 2, 4}, tdd_ul_dl_pattern{4, 4, 0, 0, 0}}));
158178
// clang-format on

tests/unittests/scheduler/test_utils/scheduler_test_bench.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ class scheduler_test_bench
7575
srsran_assert(cell_cfg_list.size() > cell_idx, "Invalid cellId={}", cell_idx);
7676
logger.set_context(next_slot.sfn(), next_slot.slot_index());
7777
last_sched_res = &sched->slot_indication(next_slot, cell_idx);
78-
srsran_assert(last_sched_res->success, "No scheduler output was provided");
7978
test_scheduler_result_consistency(cell_cfg_list[cell_idx], next_slot, *last_sched_res);
8079
++next_slot;
8180
}

0 commit comments

Comments
 (0)